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>
81 lines
3.3 KiB
Python
81 lines
3.3 KiB
Python
"""Tabella unica consolidata: PnL% NETTO per anno, tutte le strategie a confronto.
|
|
Colonne: DIP01(BTC) · TR01(basket) · ROT01(base) · ROT02(dual-mom) · PORTAFOGLIO.
|
|
Ultima riga: TOT e DD full-period.
|
|
"""
|
|
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 available_assets, FEE_RT
|
|
from scripts.analysis.honest_improve import _dd
|
|
from scripts.analysis.honest_improve2 import (
|
|
dip_market_gated, _daily_equity, _norm, _tr_basket_daily,
|
|
)
|
|
from scripts.analysis.honest_rotation import build_panel
|
|
|
|
LEV, POS = 3.0, 0.15
|
|
|
|
|
|
def rot_daily(idx, regime_n=0, lookback=60, top_k=2, gross=0.45):
|
|
"""equity giornaliera della rotazione, con/senza overlay dual-momentum."""
|
|
panel = build_panel(available_assets(), "1d")
|
|
cols = list(panel.columns); P = panel.values; T, N = P.shape
|
|
rets = np.zeros_like(P); rets[1:] = P[1:] / P[:-1] - 1
|
|
btc = P[:, cols.index("BTC")]
|
|
bma = pd.Series(btc).rolling(max(regime_n, 2)).mean().values
|
|
use_reg = regime_n and regime_n > 1
|
|
cap = 1000.0; w = np.zeros(N); tl, cl = [], []
|
|
start = max(lookback + 1, regime_n + 1 if use_reg else 0)
|
|
for i in range(start, T - 1):
|
|
risk_on = (btc[i] > bma[i]) if (use_reg and not np.isnan(bma[i])) else True
|
|
mom = P[i] / P[i - lookback] - 1; order = np.argsort(mom)[::-1]
|
|
chosen = [j for j in order if mom[j] > 0][:top_k] if risk_on else []
|
|
nw = np.zeros(N)
|
|
for j in chosen:
|
|
nw[j] = gross / len(chosen)
|
|
cap -= cap * np.abs(nw - w).sum() * (FEE_RT / 2); w = nw
|
|
cap = max(cap * (1 + float(np.dot(w, rets[i + 1]))), 10.0)
|
|
tl.append(panel.index[i]); cl.append(cap)
|
|
return _norm(_daily_equity(tl, cl, idx))
|
|
|
|
|
|
def year_pnl(eq):
|
|
return {int(y): (g.iloc[-1] / g.iloc[0] - 1) * 100 for y, g in _norm(eq).groupby(eq.index.year)}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
idx = pd.date_range("2021-01-01", "2026-05-26", freq="1D", tz="UTC")
|
|
d = dip_market_gated("BTC", market_n=0, return_equity=True)
|
|
cols = {
|
|
"DIP01(BTC)": _norm(_daily_equity(d["eq_ts"], d["eq_v"], idx)),
|
|
"TR01(bskt)": _norm(_tr_basket_daily(["BNB", "BTC", "DOGE", "SOL", "XRP"], idx)),
|
|
"ROT01": rot_daily(idx, regime_n=0),
|
|
"ROT02": rot_daily(idx, regime_n=100),
|
|
}
|
|
drets = pd.DataFrame({k: v.pct_change().fillna(0) for k, v in {
|
|
"DIP01(BTC)": cols["DIP01(BTC)"], "TR01(bskt)": cols["TR01(bskt)"], "ROT02": cols["ROT02"]
|
|
}.items()})
|
|
cols["PORTAF."] = (1 + drets.mean(axis=1)).cumprod()
|
|
|
|
names = list(cols)
|
|
py = {n: year_pnl(cols[n]) for n in names}
|
|
years = sorted({y for n in names for y in py[n]})
|
|
|
|
print("=" * 78)
|
|
print(" PnL% NETTO PER ANNO — confronto strategie (leva 3x, fee 0.10% RT)")
|
|
print("=" * 78)
|
|
print(f" {'Anno':>6s}" + "".join(f"{n:>12s}" for n in names))
|
|
print(" " + "-" * 72)
|
|
for y in years:
|
|
print(f" {y:>6d}" + "".join(f"{py[n].get(y, float('nan')):>+12.0f}" if y in py[n] else f"{'-':>12s}" for n in names))
|
|
print(" " + "-" * 72)
|
|
print(f" {'TOT%':>6s}" + "".join(f"{(cols[n].iloc[-1]/cols[n].iloc[0]-1)*100:>+12.0f}" for n in names))
|
|
print(f" {'DDfull':>6s}" + "".join(f"{_dd(cols[n].values):>12.0f}" for n in names))
|