feat(live): REAL-TRUTH ledger — capital aggiornato dal PnL dei fill reali, sim ridotto a diagnostica

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-10 12:23:52 +00:00
parent d2948d582b
commit cc39c36c08
7 changed files with 337 additions and 20 deletions
+13 -5
View File
@@ -57,18 +57,21 @@ def pos_for_spec(sid: str, global_ps: float, family_overrides: dict[str, float],
def build_worker_for(spec: SleeveSpec, alloc_capital: float, leverage: float,
data_dir: Path = DATA_DIR, position_size: float = 0.15,
executor=None, exec_instrument: str | None = None,
pairs_executor=None, exec_instruments: dict | None = None):
pairs_executor=None, exec_instruments: dict | None = None,
real_truth: bool = False):
"""Costruisce il worker esecutore per uno sleeve con capitale = quota allocata.
executor/exec_instrument: per i fade single-leg, StrategyWorker affianca al fill sim
un ordine REALE (shadow). pairs_executor/exec_instruments: idem per i PairsWorker
(esecuzione reale a 2 gambe)."""
(esecuzione reale a 2 gambe). real_truth: il ledger `capital` si aggiorna col PnL
dei FILL REALI (sim ridotto a diagnostica) — inerte senza executor."""
if spec.kind == "pairs":
return PairsWorker(
asset_a=spec.a, asset_b=spec.b, tf=spec.tf, params=spec.params,
capital=alloc_capital, position_size=position_size, leverage=leverage,
fee_rt=0.001, name="PR01_pairs_reversion", data_dir=data_dir,
executor=pairs_executor, exec_instruments=exec_instruments,
real_truth=real_truth,
)
if spec.kind == "basket":
pr = spec.params
@@ -110,7 +113,7 @@ def build_worker_for(spec: SleeveSpec, alloc_capital: float, leverage: float,
return StrategyWorker(
strategy=strategy, asset=spec.asset, tf=spec.tf, capital=alloc_capital,
position_size=position_size, leverage=leverage, params=spec.params, data_dir=data_dir,
executor=executor, exec_instrument=exec_instrument,
executor=executor, exec_instrument=exec_instrument, real_truth=real_truth,
)
@@ -277,6 +280,9 @@ def run(config_path: str = "portfolios.yml"):
exec_sleeves = set(_exec_cfg.get("sleeves", []))
exec_instr = _exec_cfg.get("instruments", {}) or {}
pairs_exec_enabled = bool(_exec_cfg.get("pairs_enabled")) # esecuzione reale 2 gambe
# REAL-TRUTH (2026-06-10): il capitale degli sleeve eseguiti si aggiorna col PnL
# dei fill reali (sim = diagnostica). Default False: va acceso esplicitamente in yml.
real_truth = bool(_exec_cfg.get("real_truth", False))
executor = None
pairs_executor = None
if exec_enabled:
@@ -285,7 +291,8 @@ def run(config_path: str = "portfolios.yml"):
# disaster-bracket on-book (~-30%): assicurazione outage sui fade reali
executor.disaster_sl_pct = float(_exec_cfg.get("disaster_sl_pct", 0.30) or 0) or None
print(f"[runner] ESECUZIONE REALE attiva (shadow) — sleeve={sorted(exec_sleeves)} "
f"strumenti={exec_instr} disaster_sl={executor.disaster_sl_pct}")
f"strumenti={exec_instr} disaster_sl={executor.disaster_sl_pct} "
f"real_truth={real_truth}")
if pairs_exec_enabled:
from src.live.execution import PairsExecutionClient
pairs_executor = PairsExecutionClient(leg=executor)
@@ -318,7 +325,8 @@ def run(config_path: str = "portfolios.yml"):
workers[s.sid] = build_worker_for(s, alloc[s.sid], p.leverage,
position_size=pos_for_spec(s.sid, position_size, ps_family, s.params.get("position_size")),
executor=ex, exec_instrument=inst,
pairs_executor=pex, exec_instruments=pinst)
pairs_executor=pex, exec_instruments=pinst,
real_truth=real_truth)
if ps_family:
print(f"[runner] position_size globale={position_size} override famiglia={ps_family}")