refactor: Simplify variable names and improve readability in metrics and lifecycle modules
CI / lint-test-build (push) Failing after 11s
CI / lint-test-build (push) Failing after 11s
This commit is contained in:
+97
-88
@@ -86,7 +86,7 @@ def _dashboard_overview(request: Request) -> dict[str, object]:
|
|||||||
ORDER BY started_at DESC
|
ORDER BY started_at DESC
|
||||||
LIMIT 5
|
LIMIT 5
|
||||||
""").fetchall()
|
""").fetchall()
|
||||||
pnl_total_row = conn.execute("""
|
rpnl = conn.execute("""
|
||||||
SELECT COALESCE(SUM(COALESCE(realized_pnl, 0)), 0)
|
SELECT COALESCE(SUM(COALESCE(realized_pnl, 0)), 0)
|
||||||
FROM trades
|
FROM trades
|
||||||
""").fetchone()
|
""").fetchone()
|
||||||
@@ -131,7 +131,7 @@ def _dashboard_overview(request: Request) -> dict[str, object]:
|
|||||||
"total_value": total_value,
|
"total_value": total_value,
|
||||||
"open_trade_count": len(open_trade_rows),
|
"open_trade_count": len(open_trade_rows),
|
||||||
"open_trades": open_trade_rows,
|
"open_trades": open_trade_rows,
|
||||||
"realized_pnl_total": f"{float(pnl_total_row[0]):.2f} USD" if pnl_total_row else "—",
|
"realized_pnl_total": f"{float(rpnl[0]):.2f} USD" if rpnl else "—",
|
||||||
"opportunities": opportunity_rows,
|
"opportunities": opportunity_rows,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,21 +146,23 @@ def _dashboard_charts(request: Request) -> dict[str, object]:
|
|||||||
LIMIT 10
|
LIMIT 10
|
||||||
""").fetchall()
|
""").fetchall()
|
||||||
|
|
||||||
chart_rows = list(reversed(opportunity_rows))
|
cr = list(reversed(opportunity_rows))
|
||||||
labels = [
|
labels = []
|
||||||
row[0].isoformat() if isinstance(row[0], datetime) else f"opportunity-{index + 1}"
|
for index, row in enumerate(cr):
|
||||||
for index, row in enumerate(chart_rows)
|
if isinstance(row[0], datetime):
|
||||||
]
|
labels.append(row[0].isoformat())
|
||||||
net_pct_values = [float(row[2]) if row[2] is not None else 0.0 for row in chart_rows]
|
else:
|
||||||
est_profit_values = [float(row[3]) if row[3] is not None else 0.0 for row in chart_rows]
|
labels.append(f"opportunity-{index + 1}")
|
||||||
cycles = [str(row[1]) for row in chart_rows]
|
np = [float(row[2]) if row[2] is not None else 0.0 for row in cr]
|
||||||
|
ep = [float(row[3]) if row[3] is not None else 0.0 for row in cr]
|
||||||
|
cycles = [str(row[1]) for row in cr]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"labels": labels,
|
"labels": labels,
|
||||||
"net_pct_values": net_pct_values,
|
"net_pct_values": np,
|
||||||
"est_profit_values": est_profit_values,
|
"est_profit_values": ep,
|
||||||
"cycles": cycles,
|
"cycles": cycles,
|
||||||
"has_chart_data": bool(chart_rows),
|
"has_chart_data": bool(cr),
|
||||||
"generated_at": datetime.now(UTC).isoformat(),
|
"generated_at": datetime.now(UTC).isoformat(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,13 +188,17 @@ def _record_audit(
|
|||||||
if repository is None:
|
if repository is None:
|
||||||
return
|
return
|
||||||
correlation_id = request.headers.get("x-request-id")
|
correlation_id = request.headers.get("x-request-id")
|
||||||
|
if payload is not None:
|
||||||
|
ret_pl = {str(key): payload[key] for key in payload}
|
||||||
|
else:
|
||||||
|
ret_pl = None
|
||||||
repository.insert(
|
repository.insert(
|
||||||
AuditRecord(
|
AuditRecord(
|
||||||
occurred_at=datetime.now(UTC),
|
occurred_at=datetime.now(UTC),
|
||||||
actor=actor,
|
actor=actor,
|
||||||
event_type=event_type,
|
event_type=event_type,
|
||||||
decision=decision,
|
decision=decision,
|
||||||
payload=None if payload is None else {str(key): payload[key] for key in payload},
|
payload=ret_pl,
|
||||||
correlation_id=correlation_id,
|
correlation_id=correlation_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -254,8 +260,8 @@ def _alert_status_snapshot(request: Request) -> dict[str, object]:
|
|||||||
|
|
||||||
|
|
||||||
def _dashboard_controls(request: Request) -> dict[str, object]:
|
def _dashboard_controls(request: Request) -> dict[str, object]:
|
||||||
controls = _dashboard_controls_state(request)
|
ctl = _dashboard_controls_state(request)
|
||||||
settings = request.app.state.settings
|
rs = request.app.state.settings
|
||||||
alert_status = _alert_status_snapshot(request)
|
alert_status = _alert_status_snapshot(request)
|
||||||
last_event = alert_status.get("last_event")
|
last_event = alert_status.get("last_event")
|
||||||
last_event_title = "—"
|
last_event_title = "—"
|
||||||
@@ -264,44 +270,47 @@ def _dashboard_controls(request: Request) -> dict[str, object]:
|
|||||||
if isinstance(title_value, str):
|
if isinstance(title_value, str):
|
||||||
last_event_title = title_value
|
last_event_title = title_value
|
||||||
|
|
||||||
configured_channels = alert_status.get("configured_channels")
|
cc = alert_status.get("configured_channels")
|
||||||
channels_display = "—"
|
cd = "—"
|
||||||
if isinstance(configured_channels, list) and configured_channels:
|
if isinstance(cc, list) and cc:
|
||||||
channels_display = ", ".join(str(channel) for channel in configured_channels)
|
cd = ", ".join(str(channel) for channel in cc)
|
||||||
|
|
||||||
dedup_seconds_raw = alert_status.get("dedup_seconds", 0.0)
|
ddsr = alert_status.get("dedup_seconds", 0.0)
|
||||||
dedup_seconds = float(dedup_seconds_raw) if isinstance(dedup_seconds_raw, int | float) else 0.0
|
dds = float(ddsr) if isinstance(ddsr, int | float) else 0.0
|
||||||
tradable_pairs_display = (
|
tpd = ", ".join(ctl.tradable_pairs) if ctl.tradable_pairs else "All"
|
||||||
", ".join(controls.tradable_pairs) if controls.tradable_pairs else "All"
|
max_trade_capital_usd = (
|
||||||
|
f"{float(rs.max_trade_capital_usd):.2f} USD"
|
||||||
|
if rs.max_trade_capital_usd is not None
|
||||||
|
else "—"
|
||||||
)
|
)
|
||||||
|
max_trade_capital_usd_value = (
|
||||||
|
f"{float(rs.max_trade_capital_usd):.2f}" if rs.max_trade_capital_usd is not None else ""
|
||||||
|
)
|
||||||
|
max_concurrent_trades = (
|
||||||
|
str(rs.max_concurrent_trades) if rs.max_concurrent_trades is not None else "—"
|
||||||
|
)
|
||||||
|
max_concurrent_trades_value = (
|
||||||
|
str(rs.max_concurrent_trades) if rs.max_concurrent_trades is not None else ""
|
||||||
|
)
|
||||||
|
alerts_last_channel_results = [
|
||||||
|
str(item) for item in cast(list[object], alert_status.get("last_channel_results", []))
|
||||||
|
]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"execution_status": "running" if controls.is_running else "stopped",
|
"execution_status": "running" if ctl.is_running else "stopped",
|
||||||
"kill_switch_status": "active" if controls.kill_switch.is_active else "inactive",
|
"kill_switch_status": "active" if ctl.kill_switch.is_active else "inactive",
|
||||||
"kill_switch_reason": controls.kill_switch.reason or "—",
|
"kill_switch_reason": ctl.kill_switch.reason or "—",
|
||||||
"paper_trading_mode": "enabled" if settings.paper_trading_mode else "disabled",
|
"paper_trading_mode": "enabled" if rs.paper_trading_mode else "disabled",
|
||||||
"trade_capital_usd": f"{float(settings.trade_capital_usd):.2f} USD",
|
"trade_capital_usd": f"{float(rs.trade_capital_usd):.2f} USD",
|
||||||
"trade_capital_usd_value": f"{float(settings.trade_capital_usd):.2f}",
|
"trade_capital_usd_value": f"{float(rs.trade_capital_usd):.2f}",
|
||||||
"max_trade_capital_usd": (
|
"max_trade_capital_usd": max_trade_capital_usd,
|
||||||
"—"
|
"max_trade_capital_usd_value": max_trade_capital_usd_value,
|
||||||
if settings.max_trade_capital_usd is None
|
"max_concurrent_trades": max_concurrent_trades,
|
||||||
else f"{float(settings.max_trade_capital_usd):.2f} USD"
|
"max_concurrent_trades_value": max_concurrent_trades_value,
|
||||||
),
|
|
||||||
"max_trade_capital_usd_value": (
|
|
||||||
""
|
|
||||||
if settings.max_trade_capital_usd is None
|
|
||||||
else f"{float(settings.max_trade_capital_usd):.2f}"
|
|
||||||
),
|
|
||||||
"max_concurrent_trades": (
|
|
||||||
"—" if settings.max_concurrent_trades is None else str(settings.max_concurrent_trades)
|
|
||||||
),
|
|
||||||
"max_concurrent_trades_value": (
|
|
||||||
"" if settings.max_concurrent_trades is None else str(settings.max_concurrent_trades)
|
|
||||||
),
|
|
||||||
"alerts_enabled": "enabled" if bool(alert_status.get("enabled", False)) else "disabled",
|
"alerts_enabled": "enabled" if bool(alert_status.get("enabled", False)) else "disabled",
|
||||||
"alerts_channels": channels_display,
|
"alerts_channels": cd,
|
||||||
"alerts_min_severity": str(alert_status.get("min_severity", "—")),
|
"alerts_min_severity": str(alert_status.get("min_severity", "—")),
|
||||||
"alerts_dedup_seconds": f"{dedup_seconds:.0f}",
|
"alerts_dedup_seconds": f"{dds:.0f}",
|
||||||
"alerts_last_result": str(alert_status.get("last_result", "unavailable")),
|
"alerts_last_result": str(alert_status.get("last_result", "unavailable")),
|
||||||
"alerts_last_attempted_at": str(alert_status.get("last_attempted_at") or "—"),
|
"alerts_last_attempted_at": str(alert_status.get("last_attempted_at") or "—"),
|
||||||
"alerts_last_success_at": str(alert_status.get("last_success_at") or "—"),
|
"alerts_last_success_at": str(alert_status.get("last_success_at") or "—"),
|
||||||
@@ -310,12 +319,12 @@ def _dashboard_controls(request: Request) -> dict[str, object]:
|
|||||||
"alerts_last_channel_results": [
|
"alerts_last_channel_results": [
|
||||||
str(item) for item in cast(list[object], alert_status.get("last_channel_results", []))
|
str(item) for item in cast(list[object], alert_status.get("last_channel_results", []))
|
||||||
],
|
],
|
||||||
"tradable_pairs_display": tradable_pairs_display,
|
"tradable_pairs_display": tpd,
|
||||||
"tradable_pairs_value": ", ".join(controls.tradable_pairs),
|
"tradable_pairs_value": ", ".join(ctl.tradable_pairs),
|
||||||
"strategy_mode": controls.strategy_mode,
|
"strategy_mode": ctl.strategy_mode,
|
||||||
"strategy_profit_threshold": f"{controls.strategy_profit_threshold:.6f}",
|
"strategy_profit_threshold": f"{ctl.strategy_profit_threshold:.6f}",
|
||||||
"strategy_max_depth_levels": str(controls.strategy_max_depth_levels),
|
"strategy_max_depth_levels": str(ctl.strategy_max_depth_levels),
|
||||||
"updated_at": controls.updated_at.isoformat(),
|
"updated_at": ctl.updated_at.isoformat(),
|
||||||
"start_endpoint": "/dashboard/control/start",
|
"start_endpoint": "/dashboard/control/start",
|
||||||
"stop_endpoint": "/dashboard/control/stop",
|
"stop_endpoint": "/dashboard/control/stop",
|
||||||
"kill_switch_endpoint": "/dashboard/control/kill-switch",
|
"kill_switch_endpoint": "/dashboard/control/kill-switch",
|
||||||
@@ -519,34 +528,38 @@ async def dashboard_control_kill_switch(request: Request) -> HTMLResponse:
|
|||||||
|
|
||||||
@router.post("/dashboard/control/config", response_class=HTMLResponse)
|
@router.post("/dashboard/control/config", response_class=HTMLResponse)
|
||||||
async def dashboard_control_config(request: Request) -> HTMLResponse:
|
async def dashboard_control_config(request: Request) -> HTMLResponse:
|
||||||
controls = _dashboard_controls_state(request)
|
ctl = _dashboard_controls_state(request)
|
||||||
settings = request.app.state.settings
|
rs = request.app.state.settings
|
||||||
form = _parse_form_body(await request.body())
|
form = _parse_form_body(await request.body())
|
||||||
|
|
||||||
if "trade_capital_usd" in form and form["trade_capital_usd"]:
|
if "trade_capital_usd" in form and form["trade_capital_usd"]:
|
||||||
settings.trade_capital_usd = float(form["trade_capital_usd"])
|
rs.trade_capital_usd = float(form["trade_capital_usd"])
|
||||||
if "max_trade_capital_usd" in form:
|
if "max_trade_capital_usd" in form:
|
||||||
max_trade_capital_value = form["max_trade_capital_usd"].strip()
|
mtcv = form["max_trade_capital_usd"].strip()
|
||||||
settings.max_trade_capital_usd = (
|
rs.max_trade_capital_usd = float(mtcv) if mtcv else None
|
||||||
float(max_trade_capital_value) if max_trade_capital_value else None
|
|
||||||
)
|
|
||||||
if "max_concurrent_trades" in form:
|
if "max_concurrent_trades" in form:
|
||||||
max_concurrent_value = form["max_concurrent_trades"].strip()
|
mcv = form["max_concurrent_trades"].strip()
|
||||||
settings.max_concurrent_trades = int(max_concurrent_value) if max_concurrent_value else None
|
rs.max_concurrent_trades = int(mcv) if mcv else None
|
||||||
|
|
||||||
controls.tradable_pairs = _parse_comma_separated_list(form.get("tradable_pairs"))
|
form_pairs = form.get("tradable_pairs")
|
||||||
|
ctl.tradable_pairs = _parse_comma_separated_list(form_pairs)
|
||||||
if "strategy_mode" in form and form["strategy_mode"].strip():
|
if "strategy_mode" in form and form["strategy_mode"].strip():
|
||||||
strategy_mode = form["strategy_mode"].strip().lower()
|
strategy_mode = form["strategy_mode"].strip().lower()
|
||||||
if strategy_mode not in {"incremental", "paper", "live"}:
|
if strategy_mode not in {"incremental", "paper", "live"}:
|
||||||
raise ValueError("strategy_mode must be one of: incremental, paper, live")
|
e = "strategy_mode must be one of: incremental, paper, live"
|
||||||
controls.strategy_mode = strategy_mode
|
raise ValueError(e)
|
||||||
if "strategy_profit_threshold" in form and form["strategy_profit_threshold"].strip():
|
ctl.strategy_mode = strategy_mode
|
||||||
controls.strategy_profit_threshold = float(form["strategy_profit_threshold"])
|
if "strategy_profit_threshold" in form:
|
||||||
if "strategy_max_depth_levels" in form and form["strategy_max_depth_levels"].strip():
|
if form["strategy_profit_threshold"].strip():
|
||||||
controls.strategy_max_depth_levels = int(form["strategy_max_depth_levels"])
|
spt = float(form["strategy_profit_threshold"])
|
||||||
|
ctl.strategy_profit_threshold = spt
|
||||||
|
if "strategy_max_depth_levels" in form:
|
||||||
|
if form["strategy_max_depth_levels"].strip():
|
||||||
|
smdl = int(form["strategy_max_depth_levels"])
|
||||||
|
ctl.strategy_max_depth_levels = smdl
|
||||||
|
|
||||||
settings.paper_trading_mode = _form_bool(form.get("paper_trading_mode"))
|
rs.paper_trading_mode = _form_bool(form.get("paper_trading_mode"))
|
||||||
controls.mark_updated()
|
ctl.mark_updated()
|
||||||
|
|
||||||
notifier = _alert_notifier(request)
|
notifier = _alert_notifier(request)
|
||||||
if notifier is not None:
|
if notifier is not None:
|
||||||
@@ -556,18 +569,14 @@ async def dashboard_control_config(request: Request) -> HTMLResponse:
|
|||||||
title="Runtime config updated",
|
title="Runtime config updated",
|
||||||
message="Dashboard control updated runtime risk and execution settings.",
|
message="Dashboard control updated runtime risk and execution settings.",
|
||||||
details={
|
details={
|
||||||
"trade_capital_usd": f"{settings.trade_capital_usd}",
|
"trade_capital_usd": f"{rs.trade_capital_usd}",
|
||||||
"max_trade_capital_usd": (
|
"max_trade_capital_usd": (
|
||||||
"none"
|
"none" if rs.max_trade_capital_usd is None else f"{rs.max_trade_capital_usd}"
|
||||||
if settings.max_trade_capital_usd is None
|
|
||||||
else f"{settings.max_trade_capital_usd}"
|
|
||||||
),
|
),
|
||||||
"max_concurrent_trades": (
|
"max_concurrent_trades": (
|
||||||
"none"
|
"none" if rs.max_concurrent_trades is None else f"{rs.max_concurrent_trades}"
|
||||||
if settings.max_concurrent_trades is None
|
|
||||||
else f"{settings.max_concurrent_trades}"
|
|
||||||
),
|
),
|
||||||
"paper_trading_mode": "true" if settings.paper_trading_mode else "false",
|
"paper_trading_mode": "true" if rs.paper_trading_mode else "false",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
_record_audit(
|
_record_audit(
|
||||||
@@ -576,14 +585,14 @@ async def dashboard_control_config(request: Request) -> HTMLResponse:
|
|||||||
event_type="dashboard.control.config",
|
event_type="dashboard.control.config",
|
||||||
decision="approved",
|
decision="approved",
|
||||||
payload={
|
payload={
|
||||||
"trade_capital_usd": settings.trade_capital_usd,
|
"trade_capital_usd": rs.trade_capital_usd,
|
||||||
"max_trade_capital_usd": settings.max_trade_capital_usd,
|
"max_trade_capital_usd": rs.max_trade_capital_usd,
|
||||||
"max_concurrent_trades": settings.max_concurrent_trades,
|
"max_concurrent_trades": rs.max_concurrent_trades,
|
||||||
"paper_trading_mode": settings.paper_trading_mode,
|
"paper_trading_mode": rs.paper_trading_mode,
|
||||||
"tradable_pairs": controls.tradable_pairs,
|
"tradable_pairs": ctl.tradable_pairs,
|
||||||
"strategy_mode": controls.strategy_mode,
|
"strategy_mode": ctl.strategy_mode,
|
||||||
"strategy_profit_threshold": controls.strategy_profit_threshold,
|
"strategy_profit_threshold": ctl.strategy_profit_threshold,
|
||||||
"strategy_max_depth_levels": controls.strategy_max_depth_levels,
|
"strategy_max_depth_levels": ctl.strategy_max_depth_levels,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+25
-57
@@ -24,7 +24,7 @@ class MetricsCalculator:
|
|||||||
|
|
||||||
def compute(self) -> PerformanceMetrics:
|
def compute(self) -> PerformanceMetrics:
|
||||||
with self._store.connect() as conn:
|
with self._store.connect() as conn:
|
||||||
trade_metrics = conn.execute("""
|
tm = conn.execute("""
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(SUM(COALESCE(realized_pnl, 0)), 0) AS realized_pnl_usd,
|
COALESCE(SUM(COALESCE(realized_pnl, 0)), 0) AS realized_pnl_usd,
|
||||||
COUNT(*) AS total_trades,
|
COUNT(*) AS total_trades,
|
||||||
@@ -46,7 +46,7 @@ class MetricsCalculator:
|
|||||||
WHERE finished_at IS NOT NULL
|
WHERE finished_at IS NOT NULL
|
||||||
""").fetchone()
|
""").fetchone()
|
||||||
|
|
||||||
opportunity_metrics = conn.execute("""
|
om = conn.execute("""
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) AS opportunity_count,
|
COUNT(*) AS opportunity_count,
|
||||||
MIN(detected_at) AS first_detected_at,
|
MIN(detected_at) AS first_detected_at,
|
||||||
@@ -54,79 +54,47 @@ class MetricsCalculator:
|
|||||||
FROM opportunities
|
FROM opportunities
|
||||||
""").fetchone()
|
""").fetchone()
|
||||||
|
|
||||||
fill_metrics = conn.execute("""
|
fm = conn.execute("""
|
||||||
SELECT AVG(filled_volume / volume) AS fill_rate
|
SELECT AVG(filled_volume / volume) AS fill_rate
|
||||||
FROM orders
|
FROM orders
|
||||||
WHERE volume > 0 AND filled_volume IS NOT NULL
|
WHERE volume > 0 AND filled_volume IS NOT NULL
|
||||||
""").fetchone()
|
""").fetchone()
|
||||||
|
|
||||||
realized_pnl_usd = (
|
r_pnl_usd = float(tm[0]) if tm and tm[0] is not None else 0.0
|
||||||
float(trade_metrics[0]) if trade_metrics and trade_metrics[0] is not None else 0.0
|
tt = int(tm[1]) if tm and tm[1] is not None else 0
|
||||||
)
|
wt = int(tm[2]) if tm and tm[2] is not None else 0
|
||||||
total_trades = (
|
wr = wt / tt if tt > 0 else None
|
||||||
int(trade_metrics[1]) if trade_metrics and trade_metrics[1] is not None else 0
|
|
||||||
)
|
|
||||||
winning_trades = (
|
|
||||||
int(trade_metrics[2]) if trade_metrics and trade_metrics[2] is not None else 0
|
|
||||||
)
|
|
||||||
win_rate = winning_trades / total_trades if total_trades > 0 else None
|
|
||||||
|
|
||||||
avg_trade_duration_seconds = (
|
atd = float(tm[3]) if tm and tm[3] is not None else None
|
||||||
float(trade_metrics[3]) if trade_metrics and trade_metrics[3] is not None else None
|
|
||||||
)
|
|
||||||
|
|
||||||
opportunity_count = (
|
oc = int(om[0]) if om is not None and om[0] is not None else 0
|
||||||
int(opportunity_metrics[0])
|
fo = om[1] if om is not None and isinstance(om[1], datetime) else None
|
||||||
if opportunity_metrics is not None and opportunity_metrics[0] is not None
|
lo = om[2] if om is not None and isinstance(om[2], datetime) else None
|
||||||
else 0
|
|
||||||
)
|
|
||||||
first_detected_at = (
|
|
||||||
opportunity_metrics[1]
|
|
||||||
if opportunity_metrics is not None and isinstance(opportunity_metrics[1], datetime)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
last_detected_at = (
|
|
||||||
opportunity_metrics[2]
|
|
||||||
if opportunity_metrics is not None and isinstance(opportunity_metrics[2], datetime)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
opportunities_per_minute: float | None
|
opportunities_per_minute: float | None
|
||||||
if (
|
if oc >= 2 and fo is not None and lo is not None:
|
||||||
opportunity_count >= 2
|
span_seconds = (lo - fo).total_seconds()
|
||||||
and first_detected_at is not None
|
|
||||||
and last_detected_at is not None
|
|
||||||
):
|
|
||||||
span_seconds = (last_detected_at - first_detected_at).total_seconds()
|
|
||||||
opportunities_per_minute = (
|
opportunities_per_minute = (
|
||||||
opportunity_count / (span_seconds / 60.0)
|
oc / (span_seconds / 60.0) if span_seconds > 0.0 else float(oc)
|
||||||
if span_seconds > 0.0
|
|
||||||
else float(opportunity_count)
|
|
||||||
)
|
)
|
||||||
elif opportunity_count == 1:
|
elif oc == 1:
|
||||||
opportunities_per_minute = 60.0
|
opportunities_per_minute = 60.0
|
||||||
else:
|
else:
|
||||||
opportunities_per_minute = None
|
opportunities_per_minute = None
|
||||||
|
|
||||||
fill_rate = float(fill_metrics[0]) if fill_metrics and fill_metrics[0] is not None else None
|
fill_rate = float(fm[0]) if fm and fm[0] is not None else None
|
||||||
|
|
||||||
latency_p50_seconds = (
|
lp50 = float(tm[4]) if tm and tm[4] is not None else None
|
||||||
float(trade_metrics[4]) if trade_metrics and trade_metrics[4] is not None else None
|
lp95 = float(tm[5]) if tm and tm[5] is not None else None
|
||||||
)
|
lp99 = float(tm[6]) if tm and tm[6] is not None else None
|
||||||
latency_p95_seconds = (
|
|
||||||
float(trade_metrics[5]) if trade_metrics and trade_metrics[5] is not None else None
|
|
||||||
)
|
|
||||||
latency_p99_seconds = (
|
|
||||||
float(trade_metrics[6]) if trade_metrics and trade_metrics[6] is not None else None
|
|
||||||
)
|
|
||||||
|
|
||||||
return PerformanceMetrics(
|
return PerformanceMetrics(
|
||||||
realized_pnl_usd=realized_pnl_usd,
|
realized_pnl_usd=r_pnl_usd,
|
||||||
win_rate=win_rate,
|
win_rate=wr,
|
||||||
avg_trade_duration_seconds=avg_trade_duration_seconds,
|
avg_trade_duration_seconds=atd,
|
||||||
opportunities_per_minute=opportunities_per_minute,
|
opportunities_per_minute=opportunities_per_minute,
|
||||||
fill_rate=fill_rate,
|
fill_rate=fill_rate,
|
||||||
latency_p50_seconds=latency_p50_seconds,
|
latency_p50_seconds=lp50,
|
||||||
latency_p95_seconds=latency_p95_seconds,
|
latency_p95_seconds=lp95,
|
||||||
latency_p99_seconds=latency_p99_seconds,
|
latency_p99_seconds=lp99,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -127,31 +127,32 @@ def persist_runtime_snapshot(app: FastAPI, *, note: str | None = None) -> Runtim
|
|||||||
|
|
||||||
|
|
||||||
async def restore_runtime_state(app: FastAPI) -> RuntimeRecoveryReport:
|
async def restore_runtime_state(app: FastAPI) -> RuntimeRecoveryReport:
|
||||||
controls = _controls(app)
|
ctl = _controls(app)
|
||||||
store = _store(app)
|
store = _store(app)
|
||||||
runtime_repository = _runtime_repository(app)
|
repo = _runtime_repository(app)
|
||||||
|
|
||||||
restored_from_snapshot = False
|
restored_from_snapshot = False
|
||||||
snapshot_at: str | None = None
|
snapshot_at: str | None = None
|
||||||
|
|
||||||
latest = runtime_repository.latest() if runtime_repository is not None else None
|
latest = repo.latest() if repo is not None else None
|
||||||
if latest is not None:
|
if latest is not None:
|
||||||
restored_from_snapshot = True
|
restored_from_snapshot = True
|
||||||
snapshot_at = latest.snapshot_at.isoformat()
|
snapshot_at = latest.snapshot_at.isoformat()
|
||||||
controls.is_running = latest.is_running
|
ctl.is_running = latest.is_running
|
||||||
if latest.kill_switch_active:
|
if latest.kill_switch_active:
|
||||||
controls.kill_switch.activate(reason=latest.kill_switch_reason or "recovered")
|
r = latest.kill_switch_reason or "recovered"
|
||||||
|
ctl.kill_switch.activate(reason=r)
|
||||||
else:
|
else:
|
||||||
controls.kill_switch.deactivate()
|
ctl.kill_switch.deactivate()
|
||||||
controls.mark_updated()
|
ctl.mark_updated()
|
||||||
|
|
||||||
open_trades = _open_trade_count(store)
|
open_trades = _open_trade_count(store)
|
||||||
restart_guard_active = False
|
restart_guard_active = False
|
||||||
if open_trades > 0:
|
if open_trades > 0:
|
||||||
controls.is_running = False
|
ctl.is_running = False
|
||||||
if not controls.kill_switch.is_active:
|
if not ctl.kill_switch.is_active:
|
||||||
controls.kill_switch.activate(reason="recovery_open_trades_detected")
|
ctl.kill_switch.activate(reason="recovery_open_trades_detected")
|
||||||
controls.mark_updated()
|
ctl.mark_updated()
|
||||||
restart_guard_active = True
|
restart_guard_active = True
|
||||||
|
|
||||||
report = RuntimeRecoveryReport(
|
report = RuntimeRecoveryReport(
|
||||||
|
|||||||
Reference in New Issue
Block a user