14522262e6
Reset del progetto su fondamenta verificate dopo la scoperta che l'intera libreria "validata OOS" era artefatto di feed contaminato (print fantasma del feed Cerbero TESTNET + storico Binance/USDT). - Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE 50-82% barre flat; XRP/BNB non certificabili). - Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST con segnale residuo, da ri-validare in isolamento. - Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio, runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/ portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/ (preservati, non cancellati). Diario consolidato in un unico documento. - Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal + src/backtest/engine + load_data; tool dati certificati (rebuild_history, certify_feed, audit_feed, multi_source_check). - Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
91 lines
4.1 KiB
Python
91 lines
4.1 KiB
Python
"""VALIDA GridWorker — forward-tracking == backtest grid_mtm (gate obbligatorio del progetto).
|
|
|
|
Il GridWorker (sim/paper) bootstrappa la storia FULL (start fisso) e mappa il capitale forward
|
|
dal deploy: capital = initial * eq[-1]/base_norm. Proprieta' da validare:
|
|
[A] LOGICA: la griglia sul feed full == backtest (stesso n_trades/win).
|
|
[B] FORWARD: deployato a T0 (bootstrap up to T0), dopo aver ticcato fino a T1 il capitale
|
|
e' initial * eq_full(T1)/eq_full(T0) — cioe' il ritorno della griglia DA T0 (causale).
|
|
[C] RESUME: reistanziato (rilegge base_norm da status.json) -> stesso capitale.
|
|
Config = la finale del re-gate pulito: BTC 1h range1.5 rd0.20 ru0.06 L6 sl0.10 tp0.03.
|
|
|
|
uv run python scripts/analysis/validate_grid_worker.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from src.data.downloader import load_data
|
|
from scripts.analysis.grid_game_gate import grid_mtm
|
|
from scripts.analysis.ladder_search import regime_mask
|
|
from src.live.grid_worker import GridWorker
|
|
|
|
CFG = dict(tf="1h", range_down=0.20, range_up=0.06, levels=6,
|
|
sl_buf=0.10, tp_buf=0.03, max_bars=720, regime="range", trend_max=1.5)
|
|
ASSET, INIT, POS, LEV, FEE = "BTC", 1000.0, 0.15, 3.0, 0.0005
|
|
|
|
|
|
def _eq_last(df, mask):
|
|
cfg_bt = {k: v for k, v in CFG.items() if k not in ("regime", "trend_max")}
|
|
eqd, st = grid_mtm(ASSET, **cfg_bt, pos=POS, lev=LEV, fee_side=FEE, deploy_mask=mask, df=df)
|
|
return float(eqd.iloc[-1]), st
|
|
|
|
|
|
def main():
|
|
df = load_data(ASSET, "1h")
|
|
n = len(df)
|
|
nboot = n - 400 # deploy a T0 = nboot, poi 400 barre forward
|
|
mask_full = regime_mask(ASSET, "1h", trend_max=CFG["trend_max"])
|
|
|
|
F, st_full = _eq_last(df, mask_full) # eq full @ T1 (== backtest)
|
|
B, _ = _eq_last(df.iloc[:nboot].reset_index(drop=True), mask_full[:nboot]) # eq @ T0 (causale)
|
|
expected = INIT * F / B
|
|
print(f"[backtest] eq@T0={B:.4f} eq@T1={F:.4f} -> capitale forward atteso {expected:,.2f} "
|
|
f"(trades full {st_full['trades']}, win {st_full['win']:.1f}%)")
|
|
|
|
wd = Path(tempfile.mkdtemp(prefix="gridval_"))
|
|
try:
|
|
boot = df.iloc[:nboot].reset_index(drop=True)
|
|
w = GridWorker("GRID_BTC", ASSET, CFG, INIT, wd, leverage=LEV,
|
|
position_size=POS, fee_side=FEE, hist=boot)
|
|
# [A] logica: tick col feed full -> n_trades come backtest
|
|
w.tick(df)
|
|
dA = abs(w.n_trades - st_full["trades"])
|
|
print(f"[A] logica n_trades worker {w.n_trades} vs backtest {st_full['trades']} "
|
|
f"{'OK' if dA == 0 else 'MISMATCH'}")
|
|
|
|
# [B] forward: deploy a T0 (base), poi fino a T1
|
|
wd2 = Path(tempfile.mkdtemp(prefix="gridval_fwd_"))
|
|
wf = GridWorker("GRID_BTC", ASSET, CFG, INIT, wd2, leverage=LEV,
|
|
position_size=POS, fee_side=FEE, hist=boot)
|
|
wf.tick(boot) # deploy: base_norm=B, capital=initial
|
|
cap0 = wf.capital
|
|
wf.tick(df.iloc[:n - 200].reset_index(drop=True))
|
|
wf.tick(df) # fino a T1
|
|
dB = abs(wf.capital - expected)
|
|
print(f"[B] forward: cap@deploy {cap0:,.2f} (atteso {INIT:,.0f}) cap@T1 {wf.capital:,.2f} "
|
|
f"(atteso {expected:,.2f}) delta {dB:.4f} {'OK' if dB < 0.05 else 'MISMATCH'}")
|
|
|
|
# [C] resume
|
|
wr = GridWorker("GRID_BTC", ASSET, CFG, INIT, wd2, leverage=LEV,
|
|
position_size=POS, fee_side=FEE, hist=boot)
|
|
wr.tick(df)
|
|
dC = abs(wr.capital - wf.capital)
|
|
print(f"[C] resume cap {wr.capital:,.2f} delta {dC:.4f} "
|
|
f"{'OK' if dC < 0.05 else 'MISMATCH'} (base_norm persistito)")
|
|
|
|
ok = dA == 0 and dB < 0.05 and dC < 0.05
|
|
print(f"\n{'VALIDAZIONE OK: GridWorker forward-tracking == backtest' if ok else 'VALIDAZIONE FALLITA'}")
|
|
shutil.rmtree(wd2, ignore_errors=True)
|
|
finally:
|
|
shutil.rmtree(wd, ignore_errors=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|