fix(dashboard): PnL totale dal ledger, non init hardcoded 2000

La KPI "PnL totale" sottraeva un capitale iniziale fisso di 2000 (retaggio
testnet) -> sul micro-test mainnet da 500 mostrava -1499 (-74.95%) invece di
+0.95 (+0.19%). Nuovo helper _ledger_pnl(): legge pnl_total dall'ultima riga
di equity.jsonl (il ledger lo scrive come equity-initial_capital) e ne deriva
l'iniziale -> la dashboard combacia col ledger per costruzione, qualunque sia
il capitale (500 mainnet / 2000 testnet), niente piu' valori fissi da
aggiornare a mano. Fallback: primo punto equity, poi l'equity stessa.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-18 09:48:33 +00:00
parent 3b60289cbd
commit c8b956ab56
+26 -4
View File
@@ -139,6 +139,28 @@ def _equity_curve(max_pts: int = 400) -> list[dict]:
return [{"t": r["ts"], "equity": r["equity"], "dd": r.get("dd", 0.0)} for r in rows] return [{"t": r["ts"], "equity": r["equity"], "dd": r.get("dd", 0.0)} for r in rows]
def _ledger_pnl(equity: float) -> tuple[float, float]:
"""(pnl_total, capitale iniziale) dal ledger — MAI hardcoded. La equity.jsonl scrive
`pnl_total = equity initial_capital` ad ogni tick → e' la fonte di verita' (il
micro-test mainnet parte da 500, il testnet partiva da 2000; lo status non persiste
l'iniziale). Da pnl_total derivo l'iniziale (equity pnl_total) cosi' la dashboard
combacia col ledger per costruzione. Fallback: primo punto equity, poi l'equity stessa."""
f = LEDGER / "equity.jsonl"
if f.exists():
lines = [l for l in f.read_text().splitlines() if l.strip()]
if lines:
try:
last = json.loads(lines[-1])
if last.get("pnl_total") is not None:
pt = float(last["pnl_total"])
return pt, equity - pt
init = float(json.loads(lines[0]).get("equity", equity))
return equity - init, init
except Exception:
pass
return 0.0, equity
def _worker_trades(wid: str) -> tuple[float, int, int, list[dict]]: def _worker_trades(wid: str) -> tuple[float, int, int, list[dict]]:
"""(pnl realizzato, n_chiusi, n_win, lista CLOSE) dal trades.jsonl.""" """(pnl realizzato, n_chiusi, n_win, lista CLOSE) dal trades.jsonl."""
f = PAPER / wid / "trades.jsonl" f = PAPER / wid / "trades.jsonl"
@@ -175,7 +197,7 @@ def build_state() -> dict:
led = json.loads((LEDGER / "status.json").read_text()) if (LEDGER / "status.json").exists() else {} led = json.loads((LEDGER / "status.json").read_text()) if (LEDGER / "status.json").exists() else {}
curve = _equity_curve() curve = _equity_curve()
equity = led.get("equity", curve[-1]["equity"] if curve else 0.0) equity = led.get("equity", curve[-1]["equity"] if curve else 0.0)
init_cap = 2000.0 pnl_total, init_cap = _ledger_pnl(equity) # dal ledger, NON hardcoded (500 mainnet / 2000 testnet)
strategies, active, closed = [], [], [] strategies, active, closed = [], [], []
paper_strategies, paper_closed = [], [] paper_strategies, paper_closed = [], []
open_assets: set[str] = set() open_assets: set[str] = set()
@@ -306,9 +328,9 @@ def build_state() -> dict:
"ts": now.isoformat(), "ts": now.isoformat(),
"version": _app_version(), "version": _app_version(),
"portfolio": { "portfolio": {
"equity": round(equity, 2), "init": init_cap, "equity": round(equity, 2), "init": round(init_cap, 2),
"pnl_total": round(equity - init_cap, 2), "pnl_total": round(pnl_total, 2),
"pnl_pct": round((equity / init_cap - 1) * 100, 2), "pnl_pct": round((pnl_total / init_cap * 100) if init_cap else 0.0, 2),
"dd": led.get("max_dd", 0.0), "peak": led.get("peak", equity), "dd": led.get("max_dd", 0.0), "peak": led.get("peak", equity),
"last_rebalance": led.get("last_rebalance", ""), "last_rebalance": led.get("last_rebalance", ""),
"curve": curve, "curve": curve,