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>
69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
"""SQ01 — Squeeze Breakout Base.
|
|
|
|
Strategia strutturale: rileva compressione di volatilità (Bollinger dentro
|
|
Keltner Channel) e segue la direzione del breakout al rilascio.
|
|
|
|
IN:
|
|
- OHLCV DataFrame (da load_data)
|
|
- Parametri: bb_window (14), sq_threshold (0.8), min_squeeze_dur (5)
|
|
|
|
OUT:
|
|
- Lista di Signal con direzione breakout (+1/-1)
|
|
- BacktestResult con equity, yearly breakdown, metriche
|
|
|
|
Risultati tipici:
|
|
BTC 15m: 76.7% acc, 4062 trades, DD 6.7%, €9.32/day
|
|
ETH 15m: 76.4% acc, 2948 trades, DD 6.2%, €10.31/day
|
|
"""
|
|
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 SqueezeBase(Strategy):
|
|
name = "SQ01_squeeze_base"
|
|
description = "Squeeze breakout puro — segui direzione al rilascio"
|
|
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
|
|
n = len(c)
|
|
|
|
bb_w = params.get("bb_window", 14)
|
|
sq_thr = params.get("sq_threshold", 0.8)
|
|
min_dur = params.get("min_dur", 5)
|
|
|
|
kcr = keltner_ratio(c, h, l, bb_w)
|
|
events = detect_squeezes(c, h, l, kcr, sq_thr, min_dur)
|
|
|
|
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
|
|
signals.append(Signal(
|
|
idx=i,
|
|
direction=1 if first_ret > 0 else -1,
|
|
entry_price=c[i - 1],
|
|
metadata={"dur": ev["dur"], "kcr": ev["kcr_at_release"]},
|
|
))
|
|
return signals
|
|
|
|
|
|
if __name__ == "__main__":
|
|
strategy = SqueezeBase()
|
|
strategy.report()
|