Files
Adriano 0e47956f7a refactor: riorganizzazione script — Strategy ABC, folder strategies/waste/analysis
- src/strategies/base.py: Strategy ABC con Signal, BacktestResult, YearlyStats
- src/strategies/indicators.py: keltner_ratio, detect_squeezes, ema, atr, rv, corr
- scripts/strategies/: SQ01-SQ04 (squeeze puro/filtri), ML01 (squeeze+GBM)
- scripts/waste/: W01-W22 script scartati + REF originali
- scripts/analysis/: compare, best_yearly, final_report, paper_status
- CLAUDE.md aggiornato con nuova struttura e tabella strategie

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 23:01:36 +02:00

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()