1b099bb47b
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
"""Tabella per-anno (PnL% e DD% intra-anno) delle versioni MIGLIORATE:
|
|
ROT02 (dual-momentum), le 3 sleeve e il PORTAFOGLIO combinato.
|
|
Tutto NETTO. Riusa gli engine di honest_improve / honest_improve2.
|
|
"""
|
|
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_improve2 import ( # noqa: E402
|
|
dip_market_gated, _daily_equity, _norm, _tr_basket_daily, _rot_daily_equity,
|
|
)
|
|
|
|
|
|
def _year_dd(eq: pd.Series) -> dict[int, float]:
|
|
out = {}
|
|
for y, g in eq.groupby(eq.index.year):
|
|
peak = g.iloc[0]; dd = 0.0
|
|
for v in g:
|
|
peak = max(peak, v); dd = max(dd, (peak - v) / peak if peak > 0 else 0.0)
|
|
out[int(y)] = dd * 100
|
|
return out
|
|
|
|
|
|
def _year_pnl(eq: pd.Series) -> dict[int, float]:
|
|
out = {}
|
|
for y, g in eq.groupby(eq.index.year):
|
|
out[int(y)] = (g.iloc[-1] / g.iloc[0] - 1) * 100
|
|
return out
|
|
|
|
|
|
def table(name, eq):
|
|
eq = _norm(eq)
|
|
dd = _year_dd(eq); pnl = _year_pnl(eq)
|
|
print(f"\n {name}")
|
|
print(f" {'Anno':>6s}{'PnL%':>9s}{'DD%':>7s}")
|
|
print(" " + "-" * 22)
|
|
for y in sorted(pnl):
|
|
print(f" {y:>6d}{pnl[y]:>+9.0f}{dd[y]:>7.0f}")
|
|
tot = (eq.iloc[-1] / eq.iloc[0] - 1) * 100
|
|
print(f" {'TOT':>6s}{tot:>+9.0f}{_year_dd(eq) and max(_year_dd(eq).values()):>7.0f}(max anno)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print(" RISULTATI PER ANNO — versioni migliorate (NETTO)")
|
|
print("=" * 60)
|
|
|
|
# ROT02 dal 2020 (dati paniere)
|
|
idx_rot = pd.date_range("2020-09-01", "2026-05-26", freq="1D", tz="UTC")
|
|
eq_rot = _rot_daily_equity(idx_rot)
|
|
table("ROT02 — dual-momentum rotation (1d)", eq_rot)
|
|
|
|
# sleeve + portafoglio dal 2021
|
|
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)
|
|
eq_dip = _norm(_daily_equity(d["eq_ts"], d["eq_v"], idx))
|
|
eq_tr = _norm(_tr_basket_daily(["BNB", "BTC", "DOGE", "SOL", "XRP"], idx))
|
|
eq_r2 = _norm(_rot_daily_equity(idx))
|
|
table("Sleeve DIP01 — BTC (1h)", eq_dip)
|
|
table("Sleeve TR01 — basket (4h)", eq_tr)
|
|
table("Sleeve ROT02 (1d)", eq_r2)
|
|
|
|
drets = pd.DataFrame({"DIP": eq_dip.pct_change().fillna(0),
|
|
"TR": eq_tr.pct_change().fillna(0),
|
|
"ROT": eq_r2.pct_change().fillna(0)})
|
|
combo = (1 + drets.mean(axis=1)).cumprod()
|
|
table("PORTAFOGLIO equal-weight (daily rebal)", combo)
|