212427ffa1
Ricerca onesta post-squeeze su 8 crypto (2018-2026), engine fee-aware con ingresso eseguibile a close[i], uscita TP/SL intrabar, OOS held-out, sweep fee. Lezione madre: shortare cripto perde OOS sistematicamente (campione net-bull) -> tutte le strategie robuste sono long-biased. Tre meccanismi distinti e complementari: - DIP01 dip-buy z-score reversion (long-only, 1h) robusto BTC/ETH/SOL - TR01 EMA 20/100 trend-following (long-only, 4h) robusto su 5/8 asset - ROT01 rotazione cross-sectional momentum sul paniere (1d) OOS +44%, param-insensitive Engine e validazione: scripts/analysis/honest_lab.py + honest_final.py (+ honest_candidates/diag/diag2/trend/rotation). Diario in docs/diary/. Onesto sull'obiettivo: €50/giorno su €1000 in pochi mesi non e' raggiungibile a rischio sano (~1825%/anno); edge reali 30-60% OOS pluriennale. Via realistica: portafoglio delle 3, leva moderata, crescita composta. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
2.5 KiB
Python
65 lines
2.5 KiB
Python
"""Diag2: long-MR sempre + short-MR SOLO in downtrend confermato (close<EMA_t).
|
|
Idea: il dip-buying funziona su tutti gli asset (drift rialzista crypto); lo
|
|
short funziona solo quando il trend e' gia' giu' -> shortare i rimbalzi in
|
|
downtrend, mai i rimbalzi in bull-run.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from scripts.analysis.honest_lab import ( # noqa: E402
|
|
atr, ema, get_df, simulate, oos_split, available_assets, FEE_RT,
|
|
)
|
|
|
|
|
|
def regime_mr(df, n=50, z_in=2.5, sl_atr=2.5, max_bars=24, trend_n=200,
|
|
allow_short=True):
|
|
"""Long su z<=-z_in SEMPRE. Short su z>=+z_in solo se close<EMA(trend_n)."""
|
|
c = df["close"].values
|
|
ma = pd.Series(c).rolling(n).mean().values
|
|
sd = pd.Series(c).rolling(n).std().values
|
|
a = atr(df, 14)
|
|
z = (c - ma) / np.where(sd == 0, np.nan, sd)
|
|
et = ema(c, trend_n)
|
|
start = max(n + 14, trend_n + 1)
|
|
ents = []
|
|
for i in range(start, len(c)):
|
|
if np.isnan(z[i]) or np.isnan(a[i]):
|
|
continue
|
|
if z[i] <= -z_in and z[i - 1] > -z_in:
|
|
ents.append({"i": i, "d": 1, "tp": ma[i], "sl": c[i] - sl_atr * a[i], "max_bars": max_bars})
|
|
elif allow_short and z[i] >= z_in and z[i - 1] < z_in and c[i] < et[i]:
|
|
ents.append({"i": i, "d": -1, "tp": ma[i], "sl": c[i] + sl_atr * a[i], "max_bars": max_bars})
|
|
return ents
|
|
|
|
|
|
def show(label, df, ents):
|
|
if len(ents) < 20:
|
|
print(f" {label:<30s} <20 trd"); return None
|
|
full = simulate(ents, df); _, oe = oos_split(ents, df); oos = simulate(oe, df)
|
|
print(f" {label:<30s}{full.trades:>6d}{full.win:>7.1f}{full.ret:>+9.0f}"
|
|
f"{oos.ret:>+9.0f}{full.dd:>6.0f}{f'{full.pos_years}/{full.n_years}':>8s}")
|
|
return full, oos
|
|
|
|
|
|
if __name__ == "__main__":
|
|
assets = available_assets()
|
|
print(f"DIAG2 — regime MR (long sempre + short in downtrend) fee {FEE_RT*100:.2f}% leva3x OOS30%")
|
|
surv = 0
|
|
for a in assets:
|
|
df = get_df(a, "1h")
|
|
print(f"\n === {a} 1h === {'Trd':>5s}{'Win%':>7s}{'FULL%':>8s}{'OOS%':>8s}{'DD%':>6s}{'AnniP':>8s}")
|
|
show("long-only", df, regime_mr(df, allow_short=False))
|
|
r = show("long + short@downtrend200", df, regime_mr(df, trend_n=200))
|
|
show("long + short@downtrend500", df, regime_mr(df, trend_n=500))
|
|
if r and r[0].ret > 0 and r[1].ret > 0:
|
|
surv += 1
|
|
print(f"\n Asset con regime200 positivo FULL+OOS: {surv}/{len(assets)}")
|