audit+fix: anti-look-ahead audit, migrate deployable config to >=12h

- trackD_lookahead_audit.py: relabel test (left==right, no labeling leak) + execution-lag
  stress -> our trend pipeline is CLEAN (4h Sharpe 1.36 robust to +1 bar lag, label-invariant)
- ADOPT conservative conclusion: deploy at 12h (sub-12h: costs/overfit dominate, slight Sharpe
  bump unreliable). 12h: Sharpe 1.32, DD 13.3%, CAGR 16.2% ~ identical and robust
- trend_portfolio: DEPLOY_TF=12h, resample_tf(rule); paper trader + tests on 12h
- calendar research (NEGATIVE, both): trackF seasonality (spurious), trackG prior-levels
  (breakouts continue, fade dead; only long-drift survivor, redundant with TP01)
- gitignore data/paper_trend runtime state
This commit is contained in:
2026-06-19 21:13:57 +02:00
parent 7b34e11476
commit eac2aa1d00
10 changed files with 1162 additions and 38 deletions
+7 -6
View File
@@ -33,7 +33,8 @@ PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
from src.backtest.harness import load
from src.strategies.trend_portfolio import TrendPortfolio, CANONICAL, resample_4h, simple_returns
from src.strategies.trend_portfolio import (
TrendPortfolio, CANONICAL, resample_tf, DEPLOY_TF, simple_returns)
STATE_DIR = PROJECT_ROOT / "data" / "paper_trend"
STATE_FILE = STATE_DIR / "state.json"
@@ -43,8 +44,8 @@ WEIGHT = 0.5
INITIAL_CAPITAL = 2000.0
def build_4h() -> dict[str, pd.DataFrame]:
return {a: resample_4h(load(a, "1h")) for a in ASSETS}
def build_bars() -> dict[str, pd.DataFrame]:
return {a: resample_tf(load(a, "1h"), DEPLOY_TF) for a in ASSETS}
def load_state() -> dict | None:
@@ -144,10 +145,10 @@ def print_status(st: dict, dfs: dict):
ret = cap / st["initial_capital"] - 1
daily = (cap - st["initial_capital"]) / days if days > 0 else 0.0
print("=" * 72)
print(" PAPER TRADER — TP01 Trend Portfolio (PORT LF4h, 50/50 BTC+ETH, 4h)")
print(f" PAPER TRADER — TP01 Trend Portfolio (PORT LF{DEPLOY_TF}, 50/50 BTC+ETH)")
print("=" * 72)
print(f" start {start:%Y-%m-%d %H:%M} UTC")
print(f" last bar {last:%Y-%m-%d %H:%M} UTC ({days:.1f} giorni, {st['n_bars']} barre 4h)")
print(f" last bar {last:%Y-%m-%d %H:%M} UTC ({days:.1f} giorni, {st['n_bars']} barre {DEPLOY_TF})")
print(f" capitale {cap:,.2f} USDT (start {st['initial_capital']:,.0f})")
print(f" ritorno {ret*100:+.2f}% | €/giorno {daily:+.2f} | maxDD {st['max_dd']*100:.1f}%")
print(f" posizioni now { 'flat' if all(p==0 for p in st['positions'].values()) else '' }")
@@ -168,7 +169,7 @@ def print_status(st: dict, dfs: dict):
def main():
argv = sys.argv[1:]
dfs = build_4h()
dfs = build_bars()
if "--reset" in argv:
if STATE_FILE.exists():
STATE_FILE.unlink()