From f6287fcd36d529077132627129b8f2751adbd81b Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Sat, 13 Jun 2026 21:25:17 +0000 Subject: [PATCH] feat(dashboard): area PAPER distinta con equity separata I 4 multi-asset (TR01/ROT02/TSM01/XS01, solo statistica fuori dal pool reale) ora in una zona dedicata con la PROPRIA equity (capitale nozionale + PnL cumulato del book paper) e tabella separata. La tabella/fam_pnl/closed dell'area principale diventano SOLO reali. Curva paper Chart.js (ocra), cliccabile -> stesso modal. Co-Authored-By: Claude Fable 5 --- src/live/dashboard.py | 68 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/src/live/dashboard.py b/src/live/dashboard.py index 127a53d..d11ff8d 100644 --- a/src/live/dashboard.py +++ b/src/live/dashboard.py @@ -177,6 +177,7 @@ def build_state() -> dict: equity = led.get("equity", curve[-1]["equity"] if curve else 0.0) init_cap = 2000.0 strategies, active, closed = [], [], [] + paper_strategies, paper_closed = [], [] open_assets: set[str] = set() dirs = sorted(list(PAPER.glob("*")) + list(STATS.glob("*"))) @@ -188,14 +189,14 @@ def build_state() -> dict: st = json.loads(sp.read_text()) paper_only = (d.parent.name == "portfolio_paper_stats") # multi-asset (no real exec) pnl, n, wins, closes = _worker_trades(wid) - closed.extend(closes) + (paper_closed if paper_only else closed).extend(closes) cap = st.get("capital", 0.0) rc = st.get("real_capital") # ritirata = status.json non aggiornato da >30min (non piu' tickato dal runner = # fuori dal config attivo, es. le fade 1h sostituite dal 15m). I paper/stats # tickano sempre -> mai ritirati. retired = (not paper_only) and _age_min(sp) > RETIRED_MIN - strategies.append({ + (paper_strategies if paper_only else strategies).append({ "id": _short(wid), "wid": wid, "family": _family_of(wid), "code": _code_of(wid), "capital": round(cap, 2), "real_capital": round(rc, 2) if rc is not None else None, "realized_pnl": round(pnl, 2), "n_trades": n, "wins": wins, @@ -240,11 +241,21 @@ def build_state() -> dict: a["to_tp_pct"] = round(abs(a["tp"] - mark) / mark * 100, 2) closed.sort(key=lambda c: c["ts"], reverse=True) - # aggregati per famiglia + # aggregati per famiglia (SOLO reali: il paper ha la sua area) fam_pnl: dict[str, float] = {} for s in strategies: fam_pnl[s["family"]] = fam_pnl.get(s["family"], 0.0) + s["realized_pnl"] + # --- area PAPER distinta: equity propria = capitale-base + PnL cumulato del book --- + paper_init = round(sum(s["capital"] - s["realized_pnl"] for s in paper_strategies), 2) + paper_closed.sort(key=lambda c: c["ts"]) + pcurve, acc = [], paper_init + for c in paper_closed: + acc += c["pnl"] or 0.0 + pcurve.append({"t": c["ts"], "equity": round(acc, 2)}) + paper_pnl = round(sum(s["realized_pnl"] for s in paper_strategies), 2) + paper_cap = round(sum(s["capital"] for s in paper_strategies), 2) + return { "ts": now.isoformat(), "version": _app_version(), @@ -263,6 +274,12 @@ def build_state() -> dict: "active": sorted(active, key=lambda a: a.get("unreal_eur", 0)), "closed": closed[:50], "n_active": len(active), + # area PAPER (multi-asset TR01/ROT02/TSM01/XS01: solo statistica, fuori dal pool reale) + "paper": { + "strategies": sorted(paper_strategies, key=lambda s: s["id"]), + "curve": pcurve, "init": paper_init, "equity": paper_cap, "pnl": paper_pnl, + "n": len(paper_strategies), + }, } @@ -369,7 +386,8 @@ HTML = r""" .ov.on{display:flex}.modal{background:var(--card);border:1px solid var(--bd);border-radius:12px;max-width:820px;width:94%;margin:40px 0;padding:20px} .modal h3{margin:0 0 4px}.x{float:right;cursor:pointer;color:var(--mut);font-size:20px;line-height:1} .btn{display:inline-block;background:#1f6feb;color:#fff;padding:7px 12px;border-radius:7px;text-decoration:none;font-size:13px;margin-top:10px} - canvas{width:100%!important;height:220px!important}#mchart{height:240px!important}#eq{height:300px!important} + canvas{width:100%!important;height:220px!important}#mchart{height:240px!important}#eq{height:300px!important}#peq{height:200px!important} + .paperzone{margin-top:22px;border:1px dashed #6e552233;border-radius:12px;padding:14px;background:linear-gradient(180deg,rgba(210,153,34,.05),transparent)} #eqcard{background:linear-gradient(180deg,#11161d,#0d1117)} .eqhead{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:6px} .eqhead .big{font-size:22px;font-weight:600}.eqhead .pc{font-size:13px} @@ -380,9 +398,18 @@ HTML = r"""

Equity

β€”
-

PnL per strategia (realizzato, netto fee)

+

PnL per strategia REALE (realizzato, netto fee)

Trade attivi β€” stato in tempo reale

Trade chiusi (ultimi 50)

+ +
+

πŸ“„ Area PAPER β€” multi-asset (solo statistica, fuori dal pool reale)

+
β€”
+
TR01 / ROT02 / TSM01 / XS01 girano con capitale nozionale fisso per valutarne l'edge in vista di un'esecuzione reale futura (bloccata dal capitale a €2k). Equity e PnL separati dal portafoglio reale.
+
+
+
+

Descrizioni strategie