#!/usr/bin/env python3
"""
Blend a VRP equity curve with a put-write strategy equity curve on the same $100k base.

The blend formula (equal-capital weighted):

    combined_equity(t) = capital + (1 - w) × VRP_PnL(t) + w × PW_PnL(t)

where ``VRP_PnL(t) = vrp_equity(t) - capital`` and ``PW_PnL(t) = pw_equity(t) - capital``.
At ``w=0.5`` each strategy receives half the starting capital and contributes half the PnL.

VRP equity source: any CSV with a date index and a column selectable via ``--vrp-col``
(default: ``eq_vrp_only`` — matches ``portfolio_vrp_plus_vxx.py`` output).

Put-write equity source: ``run_lit_putwrite_stack_sids.py --out-equity-csv``.

Example::

    # 1. Export S055 daily equity (fast):
    cd /Users/robzingale/trading_bot && PYTHONUNBUFFERED=1 .venv/bin/python \\
      RenTech/strategy_stack/run_lit_putwrite_stack_sids.py \\
      --sids S055 --start 2016-01-04 --end 2026-04-02 --capital 100000 \\
      --out-equity-csv RenTech/data/logs/s055_equity_daily.csv \\
      2>&1 | tee RenTech/data/logs/s055_equity_export_run.log

    # 2. Blend with original VRP (50/50):
    cd /Users/robzingale/trading_bot && .venv/bin/python \\
      RenTech/strategy_stack/combine_vrp_putwrite.py \\
      --vrp-csv RenTech/data/logs/portfolio_opt_10dd_sharpe_fullvrp.csv \\
      --vrp-col eq_vrp_only \\
      --pw-csv RenTech/data/logs/s055_equity_daily.csv \\
      --pw-col S055 \\
      --pw-frac 0.5 \\
      --capital 100000 \\
      --out-csv RenTech/data/logs/vrp_s055_blend_equity.csv
"""
from __future__ import annotations

import argparse
import math
import sys
from pathlib import Path

_REPO = Path(__file__).resolve().parents[2]
if str(_REPO) not in sys.path:
    sys.path.insert(0, str(_REPO))

import numpy as np
import pandas as pd


def _sharpe(eq: pd.Series) -> float:
    r = eq.pct_change().replace([np.inf, -np.inf], np.nan).fillna(0.0)
    std = float(r.std(ddof=1))
    if std < 1e-12:
        return 0.0
    return float(r.mean()) / std * math.sqrt(252)


def _max_dd(eq: pd.Series) -> tuple[float, float]:
    """Returns (max_dd_usd, max_dd_pct) — both negative."""
    peak = eq.cummax()
    dd = eq - peak
    dd_pct = dd / peak
    return float(dd.min()), float(dd_pct.min())


def _cagr(eq: pd.Series, years: float) -> float:
    if years <= 0:
        return 0.0
    return (float(eq.iloc[-1]) / float(eq.iloc[0])) ** (1.0 / years) - 1.0


def _metrics(eq: pd.Series, label: str, capital: float) -> None:
    end = float(eq.iloc[-1])
    ret_pct = (end / capital - 1.0) * 100.0
    first = pd.Timestamp(eq.index[0])
    last = pd.Timestamp(eq.index[-1])
    years = (last - first).days / 365.25
    cagr = _cagr(eq, years) * 100.0
    sh = _sharpe(eq)
    dd_usd, dd_pct = _max_dd(eq)
    calmar = cagr / abs(dd_pct * 100.0) if dd_pct != 0 else float("nan")
    print(
        f"{label:<30}  end ${end:>10,.0f}  ret {ret_pct:>7.1f}%  "
        f"CAGR {cagr:>5.2f}%  Sharpe {sh:>5.2f}  "
        f"MaxDD {dd_pct*100:>6.2f}%  Calmar {calmar:>5.2f}"
    )


def main() -> None:
    ap = argparse.ArgumentParser(
        description="Blend VRP + put-write equity curves at configurable weight.",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    ap.add_argument(
        "--vrp-csv",
        type=Path,
        default=Path("RenTech/data/logs/portfolio_opt_10dd_sharpe_fullvrp.csv"),
        help="VRP equity CSV (date-indexed); use portfolio_opt_10dd_sharpe_fullvrp.csv for original VRP.",
    )
    ap.add_argument(
        "--vrp-col",
        type=str,
        default="eq_vrp_only",
        help="Column name in --vrp-csv to use as the VRP equity series.",
    )
    ap.add_argument(
        "--pw-csv",
        type=Path,
        default=Path("RenTech/data/logs/s055_equity_daily.csv"),
        help="Put-write equity CSV (output of run_lit_putwrite_stack_sids.py --out-equity-csv).",
    )
    ap.add_argument(
        "--pw-col",
        type=str,
        default="S055",
        help="Column name in --pw-csv to use as the put-write equity series.",
    )
    ap.add_argument(
        "--pw-frac",
        type=float,
        default=0.5,
        metavar="W",
        help="Weight given to put-write; VRP weight = 1 - W. E.g. 0.5 = equal split.",
    )
    ap.add_argument(
        "--capital",
        type=float,
        default=100_000.0,
        help="Starting capital (used to convert equity → PnL for blending).",
    )
    ap.add_argument(
        "--out-csv",
        type=Path,
        default=None,
        help="Write blended daily equity CSV here (optional).",
    )
    args = ap.parse_args()

    w = float(args.pw_frac)
    if not (0.0 <= w <= 1.0):
        print("ERROR: --pw-frac must be in [0, 1]", file=sys.stderr)
        sys.exit(1)
    cap = float(args.capital)

    # --- Load VRP equity ---
    vrp_path = args.vrp_csv.expanduser()
    if not vrp_path.is_file():
        print(f"ERROR: VRP CSV not found: {vrp_path}", file=sys.stderr)
        sys.exit(1)
    vrp_df = pd.read_csv(vrp_path, index_col=0, parse_dates=True)
    vrp_df.index = pd.to_datetime(vrp_df.index).normalize()
    if args.vrp_col not in vrp_df.columns:
        print(f"ERROR: column '{args.vrp_col}' not in {vrp_path}. Available: {list(vrp_df.columns)}", file=sys.stderr)
        sys.exit(1)
    vrp_eq = vrp_df[args.vrp_col].dropna().sort_index()

    # --- Load put-write equity ---
    pw_path = args.pw_csv.expanduser()
    if not pw_path.is_file():
        print(f"ERROR: Put-write CSV not found: {pw_path}", file=sys.stderr)
        sys.exit(1)
    pw_df = pd.read_csv(pw_path, index_col=0, parse_dates=True)
    pw_df.index = pd.to_datetime(pw_df.index).normalize()
    if args.pw_col not in pw_df.columns:
        print(f"ERROR: column '{args.pw_col}' not in {pw_path}. Available: {list(pw_df.columns)}", file=sys.stderr)
        sys.exit(1)
    pw_eq = pw_df[args.pw_col].dropna().sort_index()

    # --- Align on intersection ---
    idx = vrp_eq.index.intersection(pw_eq.index)
    if len(idx) < 10:
        print(f"ERROR: Only {len(idx)} overlapping dates between VRP and put-write series.", file=sys.stderr)
        sys.exit(1)
    vrp_eq = vrp_eq.reindex(idx)
    pw_eq = pw_eq.reindex(idx)

    # --- Blend: combined = cap + (1-w)*VRP_PnL + w*PW_PnL ---
    vrp_pnl = vrp_eq - cap
    pw_pnl = pw_eq - cap
    combined_eq = cap + (1.0 - w) * vrp_pnl + w * pw_pnl

    # --- Report ---
    print("=" * 90)
    print(
        f"VRP + S055 Blend  |  VRP weight {(1-w):.0%}  |  PW ({args.pw_col}) weight {w:.0%}  "
        f"|  capital ${cap:,.0f}"
    )
    print(f"Overlap window: {idx[0].date()} → {idx[-1].date()}  ({len(idx)} days)")
    print("=" * 90)
    print(f"{'Portfolio':<30}  {'End Equity':>12}  {'Return':>8}  {'CAGR':>7}  {'Sharpe':>7}  {'MaxDD':>8}  {'Calmar':>7}")
    print("-" * 90)
    _metrics(vrp_eq, f"VRP only ({args.vrp_col})", cap)
    _metrics(pw_eq, f"PW only ({args.pw_col})", cap)
    _metrics(combined_eq, f"Blend {(1-w):.0%} VRP + {w:.0%} {args.pw_col}", cap)
    print("=" * 90)

    # Daily PnL correlation
    vrp_r = vrp_eq.pct_change().fillna(0.0)
    pw_r = pw_eq.pct_change().fillna(0.0)
    corr = float(vrp_r.corr(pw_r))
    print(f"\nDaily return correlation (VRP vs {args.pw_col}): {corr:+.3f}")

    if args.out_csv is not None:
        out_path = args.out_csv.expanduser()
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_df = pd.DataFrame({
            args.vrp_col: vrp_eq,
            args.pw_col: pw_eq,
            f"blend_{(1-w):.0%}vrp_{w:.0%}pw": combined_eq,
        })
        out_df.index.name = "date"
        out_df.to_csv(out_path)
        print(f"\nEquity CSV → {out_path}")


if __name__ == "__main__":
    main()
