feat(analysis): tabella per-anno (PnL/DD) versioni migliorate + portafoglio
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user