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>
88 lines
2.7 KiB
Python
88 lines
2.7 KiB
Python
"""SQ02 — Squeeze Breakout + Anti-Fakeout + Volume Confirmation.
|
||
|
||
Migliora SQ01 con due filtri:
|
||
1. Anti-fakeout: scarta breakout dove la candela ritraccia >60% del range
|
||
2. Volume confirm: volume al breakout deve essere >1.3× la media durante squeeze
|
||
|
||
IN:
|
||
- OHLCV DataFrame
|
||
- Parametri: bb_window (14), sq_threshold (0.8), retrace_limit (0.6),
|
||
vol_multiplier (1.3)
|
||
|
||
OUT:
|
||
- Lista di Signal filtrati
|
||
- BacktestResult
|
||
|
||
Risultati tipici:
|
||
BTC 15m: 79.7% acc, 1250 trades, DD 6.5%, €5.23/day — SOLIDO 9/9 anni
|
||
ETH 15m: 78.6% acc, 942 trades, DD 3.4%, €4.33/day
|
||
BTC 1h: 78.0% acc, 473 trades, DD 3.5%, Sharpe 6.57
|
||
"""
|
||
from __future__ import annotations
|
||
import sys
|
||
sys.path.insert(0, ".")
|
||
|
||
import numpy as np
|
||
import pandas as pd
|
||
|
||
from src.strategies.base import Strategy, Signal
|
||
from src.strategies.indicators import keltner_ratio, detect_squeezes
|
||
|
||
|
||
class SqueezeAntifakeVol(Strategy):
|
||
name = "SQ02_antifake_vol"
|
||
description = "Squeeze + antifakeout + volume confirmation"
|
||
default_assets = ["BTC", "ETH"]
|
||
default_timeframes = ["15m", "1h"]
|
||
|
||
def generate_signals(self, df: pd.DataFrame, ts: pd.DatetimeIndex,
|
||
**params) -> list[Signal]:
|
||
c = df["close"].values
|
||
h = df["high"].values
|
||
l = df["low"].values
|
||
v = df["volume"].values
|
||
n = len(c)
|
||
|
||
bb_w = params.get("bb_window", 14)
|
||
sq_thr = params.get("sq_threshold", 0.8)
|
||
retrace_limit = params.get("retrace_limit", 0.6)
|
||
vol_mult = params.get("vol_multiplier", 1.3)
|
||
|
||
kcr = keltner_ratio(c, h, l, bb_w)
|
||
events = detect_squeezes(c, h, l, kcr, sq_thr)
|
||
|
||
signals = []
|
||
for ev in events:
|
||
i = ev["idx"]
|
||
if i < 1 or i >= n:
|
||
continue
|
||
first_ret = (c[i] - c[i - 1]) / c[i - 1] if c[i - 1] > 0 else 0
|
||
if abs(first_ret) < 0.001:
|
||
continue
|
||
|
||
br = h[i] - l[i]
|
||
if br > 0:
|
||
if c[i] > c[i - 1]:
|
||
if (h[i] - c[i]) / br > retrace_limit:
|
||
continue
|
||
else:
|
||
if (c[i] - l[i]) / br > retrace_limit:
|
||
continue
|
||
|
||
avg_v = np.mean(v[ev["sq_start"]:i])
|
||
if avg_v > 0 and v[i] <= avg_v * vol_mult:
|
||
continue
|
||
|
||
signals.append(Signal(
|
||
idx=i,
|
||
direction=1 if first_ret > 0 else -1,
|
||
entry_price=c[i - 1],
|
||
metadata={"dur": ev["dur"], "vol_ratio": v[i] / avg_v if avg_v > 0 else 0},
|
||
))
|
||
return signals
|
||
|
||
|
||
if __name__ == "__main__":
|
||
strategy = SqueezeAntifakeVol()
|
||
strategy.report()
|