feat(research): FR01 Hurst-Calm Fade + analisi per-anno/mercato (ricerca 100 agenti)

Esito ricerca frattali x regime ARGO (171 agenti):
- FR01_hurst_calm_fade.py: vincitore = fade gateato da hurst<0.55 (anti-persistente) +
  dvol_pct<0.4 (DVOL bassa). OOS Sharpe 3.73 BTC, 6/6 anni positivi su BTC+ETH, corr bassa
  coi fade esistenti (MR01 +0.17/MR02 +0.08/MR07 -0.03) -> diversificatore non ridondante.
- fractal_argo_peryear.py: analisi per-anno/regime-mercato dei top candidati.
- diario 2026-06-02: verdetto completo. Finding chiave: prior ARGO 'VRP>0=range=fade' SMENTITO,
  l'edge robusto e' su VRP<0 + DVOL bassa.

Diversificatori, NON spodestano PORT06 (OOS Sharpe 8.19). Branch di ricerca.
Deploy bloccato da: verifica corr sul MASTER intero + wiring DVOL live nel runner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-02 07:22:10 +00:00
parent 5f229cd66e
commit 7005763517
3 changed files with 284 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import sys; sys.path.insert(0,".")
import numpy as np, pandas as pd
from scripts.analysis.regime_lab import load_features
from scripts.analysis.explore_lab import atr
FEE=0.001; LEV=3
def build(df, gate, k=2.5, sl_atr=2.0, mb=24, bb=50):
c=df['close'].values; a=atr(df,14)
ma=pd.Series(c).rolling(bb).mean().values; sd=pd.Series(c).rolling(bb).std().values
ent=[]
for i in range(bb+14,len(c)-1):
if np.isnan(sd[i]) or sd[i]==0 or np.isnan(a[i]): continue
if not gate(df,i): continue
if c[i]<ma[i]-k*sd[i]: d,sl=1,c[i]-sl_atr*a[i]
elif c[i]>ma[i]+k*sd[i]: d,sl=-1,c[i]+sl_atr*a[i]
else: continue
ent.append({'i':i,'d':d,'tp':ma[i],'sl':sl,'mb':mb})
return ent
def per_year(df, ent):
"""replay intrabar fedele (sl-first, tp, poi max_bars@close) -> per anno {n,ret%,win%}."""
h=df['high'].values; l=df['low'].values; c=df['close'].values
ts=pd.to_datetime(df['timestamp'],unit='ms',utc=True)
Y={}
last=-1
for e in ent:
i=e['i']
if i<=last: continue
d=e['d']; tp=e['tp']; sl=e['sl']; j=min(i+e['mb'],len(c)-1)
exit_p=c[j]
for t in range(i+1,j+1):
if d==1:
if l[t]<=sl: exit_p=sl; j=t; break
if h[t]>=tp: exit_p=tp; j=t; break
else:
if h[t]>=sl: exit_p=sl; j=t; break
if l[t]<=tp: exit_p=tp; j=t; break
ret=(exit_p-c[i])/c[i]*d*LEV - FEE*LEV
last=j; yr=ts.iloc[i].year
if yr not in Y: Y[yr]=[0,0.0,0]
Y[yr][0]+=1; Y[yr][1]+=ret*100; Y[yr][2]+= (ret>0)
return Y
# gate functions
def g_hurst_calm(df,i): return df['hurst'].iloc[i]<0.55 and not np.isnan(df['dvol_pct'].iloc[i]) and df['dvol_pct'].iloc[i]<0.40
def g_vrp_neg(df,i): return not np.isnan(df['vrp'].iloc[i]) and df['vrp'].iloc[i]<0
def g_hig_vrp(df,i):
hi=df['higuchi'].iloc[i]; return (not np.isnan(hi)) and hi>1.5 and (not np.isnan(df['vrp'].iloc[i])) and df['vrp'].iloc[i]<0
def g_none(df,i): return True
STRATS=[("HurstCalmFade (hurst<.55 & DVOL<p40)",g_hurst_calm),
("VRP<0 Fade (core driver)",g_vrp_neg),
("HigVRP Fade (Higuchi>1.5 & VRP<0)",g_hig_vrp),
("Fade NUDA (no gate, baseline)",g_none)]
# regime mercato BTC per anno (da BTC close annuale)
btc=load_features("BTC","1d")
bts=pd.to_datetime(btc['timestamp'],unit='ms',utc=True); bc=btc['close'].values
mkt={}
for yr in range(2021,2027):
m=(bts.dt.year==yr).values
if m.sum()>5:
r=(bc[m][-1]/bc[m][0]-1)*100
mkt[yr]=("BULL" if r>40 else "BEAR" if r<-30 else "RANGE", r)
for asset in ("BTC","ETH"):
df=load_features(asset,"1h")
print(f"\n{'='*78}\n {asset} 1h — performance per anno (somma ret% per-trade, netto leva3x+fee0.10%)\n{'='*78}")
print(f" {'Strategia':<40} " + " ".join(f"{y}" for y in range(2021,2027)))
for name,g in STRATS:
ent=build(df,g); Y=per_year(df,ent)
cells=[]
for y in range(2021,2027):
if y in Y and Y[y][0]>0:
cells.append(f"{Y[y][1]:+5.0f}")
else: cells.append(" . ")
print(f" {name:<40} " + " ".join(cells))
# riga trades/anno per la strategia principale
ent=build(df,g_hurst_calm); Y=per_year(df,ent)
tr=" ".join(f"{Y.get(y,[0])[0]:>5}" for y in range(2021,2027))
print(f" {'(HurstCalmFade trades/anno)':<40} {tr}")
print(f"\n REGIME MERCATO BTC per anno (ret% annuale prezzo):")
for y in range(2021,2027):
if y in mkt: print(f" {y}: {mkt[y][0]:6} ({mkt[y][1]:+.0f}%)")