"""EQ-GTAA01 — Trend difensivo MULTI-ASSET (GTAA) sull'universo ETF.

EQ-TREND01 ha mostrato che il trend long-flat su SPY taglia il DD (analogo TP01). La diversificazione
delle SORGENTI di trend (azioni US/tech/small + bond + oro + high-yield) di solito migliora il
rischio-aggiustato del trend mono-asset. Qui: ogni asset gestito col proprio trend long-flat
(TSMOM multi-orizzonte), equal-weight tra gli asset DISPONIBILI (la quota "off" o assente -> cash).

DATI: cache eqlib (ADJUSTED, nessun IB). Start diversi -> outer-join con peso rinormalizzato sugli
asset esistenti (come gli sleeve crypto). Finestra lunga: SPY/QQQ/IWM da ~2000; TLT(2016)/GLD(2004)/
HYG(2007) entrano dopo. Riporto anche la finestra 6-asset comune (2016+).

GIUDIZIO: vs SPY buy&hold, vs EW statico (isola il valore del TIMING di trend), vs SPY-trend mono;
Sharpe full/pre15/OOS + maxDD + plateau. Causale, netto fee.
"""
import sys
from pathlib import Path
import numpy as np, pandas as pd

ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "scripts" / "research"))
import eqlib
from eqlib import load_eq
from eq_sector_momentum import _sh, _cagr, _dd, EQ_HOLDOUT, spy_bh
from eq_spy_trend import tsmom_exposure, backtest, _series

ASSETS = ["SPY", "QQQ", "IWM", "TLT", "GLD", "HYG"]


def gated_returns(sym, horizons=(21, 63, 126, 252), fee_side=0.0002, target_vol=None, lev_cap=1.0):
    """Rendimenti netti daily di UN asset gestito col proprio trend long-flat (cash quando off)."""
    px = _series(sym)
    ex = tsmom_exposure(px, horizons=horizons, target_vol=target_vol, lev_cap=lev_cap)
    return backtest(px, ex, fee_side=fee_side)


def gtaa(assets=ASSETS, horizons=(21, 63, 126, 252), fee_side=0.0002, target_vol=None):
    """Portafoglio GTAA: media (equal-weight) dei rendimenti trend-gated sugli asset disponibili
    ogni giorno (outer-join). La quota di asset assenti/in-cash resta in cash."""
    cols = {a: gated_returns(a, horizons, fee_side, target_vol) for a in assets}
    R = pd.concat(cols, axis=1).sort_index()
    return R.mean(axis=1, skipna=True)   # EW sugli asset esistenti quel giorno


def ew_buyhold(assets=ASSETS):
    cols = {a: _series(a).pct_change() for a in assets}
    return pd.concat(cols, axis=1).sort_index().mean(axis=1, skipna=True)


def _row(name, r, common=None, bench=None):
    r = r.dropna() if common is None else r.reindex(common).fillna(0.0)
    h = r[r.index >= EQ_HOLDOUT]; ii = r[r.index < EQ_HOLDOUT]
    tim = float((r != 0).mean()) * 100
    extra = ""
    if bench is not None:
        J = pd.concat({"r": r, "b": bench}, axis=1, join="inner").dropna()
        extra = f"  corrSPY {J['r'].corr(J['b']):+.2f}"
    print(f"  {name:26} CAGR {_cagr(r.values, r.index)*100:>5.1f}%  Sh {_sh(r):>5.2f} "
          f"(pre15 {_sh(ii):>5.2f}|OOS {_sh(h):>5.2f})  maxDD {_dd(r.values)*100:>4.0f}%  inMkt {tim:>3.0f}%{extra}")


def main():
    print("=" * 100)
    print("  EQ-GTAA01 — Trend difensivo MULTI-ASSET (GTAA)")
    print("=" * 100)
    spy = spy_bh()
    g = gtaa()                          # outer-join, finestra lunga
    gl = g.dropna()
    print(f"  finestra lunga (outer-join) {gl.index[0].date()}..{gl.index[-1].date()} ({len(gl)}g)  OOS {EQ_HOLDOUT.date()}+\n")

    print("  --- BASELINE & confronti (finestra lunga) ---")
    cl = gl.index
    _row("SPY buy&hold", spy.reindex(cl).fillna(0))
    _row("EW statico (no trend)", ew_buyhold().reindex(cl).fillna(0), bench=spy.reindex(cl).fillna(0))
    _row("SPY-trend mono (TREND01)", backtest(_series("SPY"), tsmom_exposure(_series("SPY"))).reindex(cl).fillna(0), bench=spy.reindex(cl).fillna(0))
    print("\n  --- GTAA (multi-asset trend) ---")
    _row("GTAA lf", gl, bench=spy.reindex(cl).fillna(0))
    _row("GTAA lf vt12%", gtaa(target_vol=0.12).reindex(cl).fillna(0), bench=spy.reindex(cl).fillna(0))

    # finestra 6-asset comune (tutti gli ETF esistono): 2016+
    tlt0 = _series("TLT").index[0]
    c6 = gl.index[gl.index >= tlt0]
    print(f"\n  --- finestra 6-asset comune ({c6[0].date()}+) ---")
    _row("SPY buy&hold (6a win)", spy.reindex(c6).fillna(0))
    _row("GTAA lf (6a win)", g.reindex(c6).fillna(0), bench=spy.reindex(c6).fillna(0))
    _row("GTAA lf vt12 (6a win)", gtaa(target_vol=0.12).reindex(c6).fillna(0), bench=spy.reindex(c6).fillna(0))

    # MARGINALE vs SPY
    print("\n  --- MARGINALE vs SPY (GTAA lf, finestra lunga) ---")
    J = pd.concat({"spy": spy, "c": gl}, axis=1, join="inner").dropna(); JH = J[J.index >= EQ_HOLDOUT]
    print(f"    corr full {J['spy'].corr(J['c']):+.3f} | OOS {JH['spy'].corr(JH['c']):+.3f}")
    for wt in (0.5, 1.0):
        bf = _sh((1-wt)*J['spy']+wt*J['c'])-_sh(J['spy']); bh = _sh((1-wt)*JH['spy']+wt*JH['c'])-_sh(JH['spy'])
        lbl = "100% GTAA" if wt == 1.0 else "50/50 SPY/GTAA"
        print(f"    {lbl:16}: uplift Sharpe FULL {bf:+.3f}  OOS {bh:+.3f}")
    print("    DD nei bear (GTAA vs SPY):")
    for lo, hi, lbl in [("2000-03-01","2002-12-31","dot-com"),("2007-10-01","2009-06-30","GFC"),
                        ("2020-02-01","2020-04-30","COVID"),("2022-01-01","2022-12-31","2022")]:
        seg=lambda s: _dd(s.reindex(cl).fillna(0)[(cl>=pd.Timestamp(lo,tz='UTC'))&(cl<=pd.Timestamp(hi,tz='UTC'))].values)*100
        print(f"      {lbl:8} GTAA {seg(gl):.0f}%  | SPY {seg(spy):.0f}%")

    print("\n  --- PLATEAU (Sharpe FULL/pre15/OOS, DD, CAGR) GTAA lf, finestra lunga ---")
    print(f"    {'horizons':22} {'FULL':>6} {'pre15':>6} {'OOS':>6} {'DD%':>5} {'CAGR%':>6}")
    for hz in [(63,126,252),(21,63,126,252),(126,252),(252,)]:
        r = gtaa(horizons=hz).reindex(cl).fillna(0); h=r[r.index>=EQ_HOLDOUT]; ii=r[r.index<EQ_HOLDOUT]
        print(f"    {'x'.join(map(str,hz)):22} {_sh(r):>6.2f} {_sh(ii):>6.2f} {_sh(h):>6.2f} {_dd(r.values)*100:>5.0f} {_cagr(r.values,r.index)*100:>6.1f}")


if __name__ == "__main__":
    main()
