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>
70 lines
2.7 KiB
Python
70 lines
2.7 KiB
Python
"""Re-validazione: il StrategyWorker REALE tradi MR01 con edge netto?
|
|
|
|
Guida il worker vero (generate_signals + nuova logica exit TP/SL/max_bars) su
|
|
finestre mobili di dati 1h storici, simulando il polling live. Conferma che
|
|
sulla finestra OOS l'edge netto (dopo fee 0.10% RT) sopravvive alla meccanica
|
|
del worker (exit su prezzo corrente, piu' conservativa del backtest high/low).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
import os
|
|
import sys
|
|
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 src.live.strategy_loader import load_strategy
|
|
from src.live.strategy_worker import StrategyWorker
|
|
|
|
OOS_FRAC = 0.30
|
|
WIN = 250 # barre per finestra di poll (warmup bb_window=50 + ATR)
|
|
|
|
|
|
def replay(asset: str, params: dict):
|
|
df = load_data(asset, "1h").reset_index(drop=True)
|
|
n = len(df)
|
|
split = int(n * (1 - OOS_FRAC))
|
|
strat = load_strategy("MR01_bollinger_fade")
|
|
w = StrategyWorker(strat, asset, "1h", capital=1000.0, position_size=0.15,
|
|
leverage=3.0, hold_bars=3, params=params,
|
|
data_dir=Path(f"/tmp/replay_{asset}"))
|
|
w._notify = lambda *a, **k: None
|
|
# stato pulito
|
|
for attr, val in dict(capital=1000.0, in_position=False, direction=0, entry_price=0,
|
|
bars_held=0, total_trades=0, total_wins=0, last_bar_ts=0,
|
|
tp=0.0, sl=0.0, max_bars=0).items():
|
|
setattr(w, attr, val)
|
|
|
|
start = max(split, WIN)
|
|
with contextlib.redirect_stdout(open(os.devnull, "w")):
|
|
for j in range(start, n):
|
|
w.tick(df.iloc[j - WIN + 1 : j + 1])
|
|
|
|
ret = (w.capital / 1000 - 1) * 100
|
|
acc = w.total_wins / w.total_trades * 100 if w.total_trades else 0.0
|
|
import pandas as pd
|
|
period = (f"{pd.to_datetime(df['timestamp'].iloc[start], unit='ms', utc=True).date()}"
|
|
f"->{pd.to_datetime(df['timestamp'].iloc[-1], unit='ms', utc=True).date()}")
|
|
return w.total_trades, acc, ret, w.capital, period
|
|
|
|
|
|
def main():
|
|
print("=" * 90)
|
|
print(" RE-VALIDAZIONE WORKER REALE su MR01 (OOS, fee 0.10% RT, leva 3x) — finestra poll 250b")
|
|
print("=" * 90)
|
|
params = dict(bb_window=50, k=2.5, sl_atr=2.0, max_bars=24)
|
|
print(f" {'Asset':>6s}{'Periodo OOS':>26s}{'Trade':>7s}{'Win%':>7s}{'Ret%':>9s}{'Cap€':>9s}")
|
|
print(" " + "-" * 80)
|
|
for asset in ["BTC", "ETH"]:
|
|
t, acc, ret, cap, period = replay(asset, params)
|
|
print(f" {asset:>6s}{period:>26s}{t:>7d}{acc:>7.1f}{ret:>+9.1f}{cap:>9.0f}")
|
|
print(" " + "-" * 80)
|
|
print(" Atteso: Ret% positivo (l'edge mean-reversion sopravvive alla meccanica del worker).")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|