
    pje                    p   d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ ddlZddlZ e
e      j%                         j&                  d   Zedz  d	z  d
z  Zedz  Z ee      ej0                  vr"ej0                  j3                  d ee             ddlmZmZmZ d1d2dZd3dZd3dZ d4dZ!d4dZ"d5dZ# ed       G d d             Z$ddddddddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d6dZ%ddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d7dZ&d8dZ'dddddddddddddddddddddd dd!d"	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d9d#Z(ddd$dddddddddddddddddddd%dd!d&	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d:d'Z)ddd(d(d(d)ddddddddddddddddddd*	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d;d+Z*d<d,Z+d=d-Z,d>d.Z-d/ Z.e/d0k(  r e.        yy)?u  
Combine the **VRP regime** book (+ IV overlays) with the **VXX contango**
sleeve (90 % bear call credit spread + 10 % long OTM call) and report
portfolio-level metrics with vs. without the VXX sleeve.

**Percentage allocation “backtest”** (no Theta re-run): load realized trades from JSONLs and
merge daily PnL with ``--allocation-json`` pointing at ``optimize_overlay_risk_fracs.py`` output
(``portfolio_vrp_plus_vxx_cli_snippet`` fractions × ``--total-capital``). That is the same merge
model the optimizer uses; sleeves are **fractions of the account**, then converted to USD
risk budgets internally for scaling vs each JSONL’s ref risk.

**One account, one starting equity** (``--total-capital``, default 100k): every equity curve
starts at that number. **IV overlays and VXX** are scaled by **broker risk budget** (max loss for
credit structures, debit paid for long premium): ``sleeve_pnl × (your_risk_usd / ref_risk_usd)``.
Reference risk per sleeve defaults to the **median** ``broker_risk_usd`` in each JSONL (or
inferred for legacy rows). Override with ``--put-risk-ref`` / ``--overlay-ref`` / ``--vxx-ref``.
VRP still uses ``capital_vrp / vrp_ref``. Per-trade VRP risk lives inside ``VRPBacktester``.

Active sleeves: VRP main, OTM put, straddle, risk reversal, VXX bear call,
VXX long call.

Calendar spread is **excluded** — drop-one-out analysis (Apr 2026) showed it
lost -$10.5K with Sharpe -5.61 and removing it improved portfolio Sharpe by
+0.069.  Do not re-add without fresh evidence of profitability.

Example::

    python RenTech/strategy_stack/portfolio_vrp_plus_vxx.py \
      --total-capital 100000 --capital-vxx-pct 0.024 --vxx-bear-pct 90 --vxx-call-pct 10

    # Same as --capital-put 2000 on a 100k book:
    python RenTech/strategy_stack/portfolio_vrp_plus_vxx.py \
      --total-capital 100000 --capital-put-pct 0.02

Or from Python / after ``vrp_backtest_theta.py``::

    from RenTech.strategy_stack.portfolio_vrp_plus_vxx import execute_portfolio_merge
    execute_portfolio_merge(
        vrp_trades=Path("RenTech/data/logs/vrp_low_dd_ov2_vxxbundle_vrp_trades.jsonl"),
        total_portfolio_capital=100_000,
    )

Overlay JSONLs (defaults under ``RenTech/data/logs/``): ``stress_longvol_otm_put.jsonl``,
``stress_longvol_straddle.jsonl``, ``risk_reversal.jsonl`` from ``backtest_iv_stress_long_vol.py`` /
``backtest_iv_calendar_risk_reversal.py``; VXX: ``vxx_portfolio_bear_call.jsonl`` and
``vxx_portfolio_long_call.jsonl`` from ``optimize_vxx_portfolio.py`` / ``backtest_vxx_bear_call_contango.py``
and ``explore_vxx_decay_strategies.py`` (see those scripts for exact flags).

**Optimize sleeve risk budgets:** :func:`optimize_sleeve_notionals` (or CLI ``--optimize-sleeves``)
searches overlay + VXX **broker risk budgets (USD)** with an optional sum cap and a **soft** max-drawdown target,
maximizing ``Calmar + sharpe_weight * Sharpe`` with VRP scale fixed to the account.

**Sharpe-only allocation:** :func:`optimize_portfolio_sharpe` (or CLI ``--optimize-sharpe``) searches
put/straddle/RR/VXX as **fractions of** ``--total-capital`` to maximize **Sharpe** on the merged book,
with optional sum cap (``--sharpe-sum-cap-pct``) and optional **hard** max drawdown cap
(``--sharpe-max-dd-pct``, default 10%% peak-to-trough; use ``0`` to disable).
Mutually exclusive with ``--optimize-sleeves``.
    )annotationsN)	dataclass)Path)Any   RenTechdatalogsz)vrp_low_dd_ov2_vxxbundle_vrp_trades.jsonl)_load_jsonl_pnl_series_from_trades_require_jsonlc                4    t        |       }t        |d|      S )N	exit_date)exit_keypnl_key)r   r   )pathr   tradess      I/opt/rentech/trading_bot/RenTech/strategy_stack/portfolio_vrp_plus_vxx.py	_load_pnlr   S   s    F"6KQQ    c           
        | j                  d      }|'t        |      }t        j                  |      r|dkD  r|S t	        | j                  dd            }|dv r.t        t        t        | j                  dd                  d      S t        | j                  dd            }t        | j                  d	d
            }d}|dk\  rt        |d      S t        t        |      d|z  |z  z   d      S )z^Max loss / debit (USD) for one overlay position; legacy JSONL when ``broker_risk_usd`` absent.broker_risk_usdr   	structure )otm_putstraddleentry_premium      ?entry_net_premium	spy_entryi        Y@皙?getfloatmathisfinitestrmaxabs)tradevxstenspycms          r   _infer_broker_risk_overlayr2   X   s    		#$A}!H==AH	UYY{B'	(B	$$3uUYY:;<cBB	uyy,a0	1B
		+s+
,C	B	Qw2s|s2wb(#..r   c                   | j                  d      }|'t        |      }t        j                  |      r|dkD  r|S t	        | j                  dd            }|dk(  r)| j                  d      t        t        | d         d      S t        | j                  dd            }|d	k(  s|dk  r!t        |dk7  rt        |      d      S d
d      S |dk(  ryt        t        |      d      S )Nr   r   strategyr   	bear_callmax_lossr   entry_credit_or_debit	long_callg     b@g      t@g      i@r#   )r+   r,   r-   secs        r   _infer_broker_risk_vxxr;   j   s    		#$A}!H==AHEIIj"%&AKEIIj1=5z*+S11	uyy0!4	5BK26bAg3r7#665#66Ks2wr   c                   | j                         syt        |       }|sy|D cg c]
  } ||       }}|D cg c]   }t        j                  |      s|dkD  s|" }}|rt	        t        j                  |            S dS c c}w c c}w )Nr   r   )is_filer   r&   r'   r%   npmedian)r   infer_fnr   tvalsr,   s         r   _median_risk_usdrC   {   s{    <<>F!'(AHQK(D(:!t}}Q/AEA:D:%)54!2s2 ):s   BBBBc                <   | j                         syt        |       }|syt        d |D              }g }|D ]  }|j                  d      }|Gt	        j
                  t        |            r)t        |      dkD  r|j                  t        |             ]t         ||            }t	        j
                  |      s|dkD  s|j                  |        |sy|rt        t        t        |            d      S t        t        t        j                  |            d      S )uB  
    Reference USD for scaling an overlay/VXX sleeve to ``capital_*``.

    If **every** row has ``broker_risk_usd > 0``, use **sum** of those values (total capital
    deployed in the log — correct when contracts vary per trade). Otherwise fall back to the
    **median** of inferred per-trade risk (legacy JSONL).
    r   c              3     K   | ]M  }|j                  d       duxr4 t        j                  t        |d                xr t        |d          dkD   O yw)r   Nr   )r$   r&   r'   r%   ).0rA   s     r   	<genexpr>z5_overlay_sleeve_risk_reference_usd.<locals>.<genexpr>   sb        	
 , 	,MM%"3 456	,!%&'!+	,s   AAr   r   )r=   r   allr$   r&   r'   r%   appendr)   sumr>   r?   )r   r@   r   
documentedrB   rA   r,   r-   s           r   "_overlay_sleeve_risk_reference_usdrL      s     <<>F  	 J D EE#$=T]]584qAKKa!hqk"A}}QAEA 5T#S))uRYYt_%s++r   c                (    || j                         z   S )N)cumsum)pnlcapitals     r   _equity_from_pnlrQ      s    SZZ\!!r   T)frozenc                      e Zd ZU dZded<   ded<   ded<   ded<   ded<   ded	<   ded
<   ded<   ded<   ded<   ded<   ded<   ded<   ded<   y)PortfolioPnLBasiszhVRP uses ``B_v = pnl/vrp_ref``. Overlays/VXX use **raw** daily $ PnL scaled by ``risk_budget/risk_ref``.zpd.DatetimeIndexindexr%   eq0vrp_refput_risk_refstraddle_risk_refrr_risk_refvxx_bear_risk_refvxx_call_risk_ref	pd.SeriesB_vB_pB_sB_rB_vbB_vcN)__name__
__module____qualname____doc____annotations__ r   r   rT   rT      sQ    r	JN	N	N	N	N
O
Or   rT        j@)rW   rX   rY   rZ   overlay_refr[   r\   vxx_ref
put_tradesstraddle_tradesrisk_reversal_tradesvxx_bear_tradesvxx_call_tradestotal_portfolio_capitalc                "   |	xs	 t         dz  }	|
xs	 t         dz  }
|xs	 t         dz  }|xs	 t         dz  }|xs	 t         dz  }| j                         j                         }|j                         st	        d|       t        |	t              }t        |
t              }t        |t              }t        |t              }t        |t              }dfd} |||      } |||      } |||      }dfd} |||      } |||      }t        |d	
      }|	j                         rt        |	      nt        j                  t              }|
j                         rt        |
      nt        j                  t              }|j                         rt        |      nt        j                  t              }|j                         rt        |      nt        j                  t              } |j                         rt        |      nt        j                  t              }!|j                  }"|||| |!fD ]*  }#|#j                  r|"j                  |#j                        }", |"j                         }"t!        |"      dkD  r2|"d   t        j"                  d      z
  }$|$|"vr|"j%                  d|$      }"t'        t        |      d      }%|j)                  |"d      |%z  }&|j)                  |"d      }'|j)                  |"d      }(|j)                  |"d      })| j)                  |"d      }*|!j)                  |"d      }+t+        |"t        |      t        |      t        |      t        |      t        |      t        |      t        |      |&|'|(|)|*|+      S )a  
    Load JSONLs once; overlay/VXX daily PnL is **raw dollars** from the reference backtest.
    Risk refs default to **sum** of ``broker_risk_usd`` per file when every row documents it
    (dynamic contracts / 1:1 sizing); otherwise **median** of inferred per-trade risk (legacy).
    ``overlay_ref`` (if set) overrides put, straddle, and RR refs. ``vxx_ref`` overrides both VXX legs.
    stress_longvol_otm_put.jsonlstress_longvol_straddle.jsonlrisk_reversal.jsonlvxx_portfolio_bear_call.jsonlvxx_portfolio_long_call.jsonlzVRP trades JSONL not found: c                    | t        t        |       d      S t        t              d      S t        t        |      d      S Nr   r)   r%   )explicitmedrk   s     r   _or_ovz(load_portfolio_pnl_basis.<locals>._or_ov   sC    uX,,"u[)3//5:s##r   c                    | t        t        |       d      S t        t              d      S t        t        |      d      S rz   r{   )r|   r}   rl   s     r   _vxx_legz*load_portfolio_pnl_basis.<locals>._vxx_leg   sB    uX,,uW~s++5:s##r   pnl_usd)r   )dtyper      )daysr   )
fill_value)rU   rV   rW   rX   rY   rZ   r[   r\   r^   r_   r`   ra   rb   rc   )r|   float | Noner}   r%   returnr%   )LOGS
expanduserresolver=   FileNotFoundErrorrL   r2   r;   r   pdSeriesr%   rU   emptyunionsort_valueslen	Timedeltainsertr)   reindexrT   ),
vrp_tradesrW   rX   rY   rZ   rk   r[   r\   rl   rm   rn   ro   rp   rq   rr   vrp_pathm_putm_strm_rrm_vbm_vcr~   prsrrrr   vbrvcrvrp_pnlput_pnlstr_pnlrr_pnlvxx_bear_pnlvxx_call_pnlall_idxr9   t_padrfr^   r_   r`   ra   rb   rc   s,        `  `                                   r   load_portfolio_pnl_basisr      s9   0 F'E EJ%Q$1P*PO/QD;P4P%Q$1P*PO%Q$1P*PO$$&..0H">xj IJJ.z;UVE.@Z[E-.BD^_D-o?UVD-o?UVD$ 
e	$B	!5	)B	T	"B$ $d
+C
$d
+C)4G'1'9'9';i
#QVAWG,;,C,C,Ei(299[`KaG0D0L0L0NY+,TVT]T]diTjF1@1H1H1J9_-PRPYPY`ePfL1@1H1H1J9_-PRPYPY`ePfLmmGwlC -wwmmAGG,G- !!#G
7|a
R\\q11nnQ.G	U7^S	!B
//'a/
02
5C
//'a/
0C
//'a/
0C
..Q.
/CA6DA6D)*g2Y)"I** r        V@      $@)vxx_bear_pctvxx_call_pctc                  |t        |      n| j                  }t        |      t        |      t        |      }}
}	t        |      }||dz  z  }||dz  z  }t        | j                  d      t        | j                  d      t        | j
                  d      }}}t        | j                  d      t        | j                  d      }}|| j                  z  |	|z  | j                  z  z   |
|z  | j                  z  z   ||z  | j                  z  z   ||z  | j                  z  z   ||z  | j                  z  z   }| j                  |j                         z   S )z>Full book: VRP + IV overlays + VXX, starting at ``basis.eq0``.r!   -q=)r%   rV   r)   rX   rY   rZ   r[   r\   r^   r_   r`   ra   rb   rc   rN   )basiscapital_vrpcapital_putcapital_straddlecapital_risk_reversalcapital_vxxr   r   vrp_numcpcscrcvxxbearcallr   r   r   r   r   dailys                        r   merged_full_equityr   *  sQ    %0$;eK G{#U+;%<eDY>ZBBD<%'(D<%'(DU''/U5L5Le1TVYZ_ZkZkmrVsBB5**E2C8O8OQV4WC%))7eii
	 7eii
	  7eii
	  #:
#		$
 #:
#	$ 
 99u||~%%r   c                     t        | d          S )zePositive number, e.g. 8.91 for 8.91 % peak-to-trough (``_metrics_block`` stores negative max_dd_pct).
max_dd_pctr%   )metricss    r   max_drawdown_pct_magnituder   H  s    ',''((r         ?P   F)rr   r   max_dd_limit_pctadditional_notionals_capmax_single_sleevesharpe_weightr   r   rW   rk   rX   rY   rZ   rl   r[   r\   rm   rn   ro   rp   rq   maxiterseedpolishc                 *+ ddl m}m} t        | |	||||
|||||||||      *|t	        |      n*j
                  +t	        |      }d|fd|fd|fd|fg}d}|)t	        |      } |t        j                  d      d|      f}t        j                  j                  |      }d"*+fd}  || |||||dd	
      }!t	        |!j                  d         t	        |!j                  d         t	        |!j                  d         t	        |!j                  d         f\  }"}#}$}%t        *+|"|#|$|%      }&t        |&d      }'t        |'      }(|(dz   k  })i d|)d+d|"d|#d|$d|%d|"|#z   |$z   |%z   d|(d|'d   d|'d   d|'d   d|'d   d|'d   d|&d|'d   |'d   z  z   dt        |!j                        d t!        |!j"                        d!t%        |!j&                        iS )#u  
    Search non‑negative **risk budgets** (USD) for **put / straddle / risk‑reversal / VXX** (VXX split by bear/call %)
    while **VRP scale** stays fixed at ``capital_vrp`` or ``total_portfolio_capital``.

    **Capital:** starting equity is always ``total_portfolio_capital`` (same as merge). Optional
    ``additional_notionals_cap`` requires ``capital_put + capital_straddle + capital_risk_reversal
    + capital_vxx <= cap`` — a combined **risk budget** (max loss / debit USD), not VRP.

    **Objective:** maximize ``Calmar + sharpe_weight * Sharpe`` on the **full** merged equity curve.
    **Feasibility:** solutions with max drawdown **above** ``max_dd_limit_pct`` (peak‑to‑trough %) are
    heavily penalized (soft constraint); the best reported point may be infeasible if the limit is
    too tight — check ``feasible`` and ``max_drawdown_pct`` in the result.

    Uses ``scipy.optimize.differential_evolution`` (non‑smooth OK). Install scipy if missing.
    r   )LinearConstraintdifferential_evolutionr   rW   rX   rY   rZ   rk   r[   r\   rl   rm   rn   ro   rp   rq   rr           ri   )r      c           
     H   t        | d         t        | d         t        | d         t        | d         f\  }}}}t        ||||      }t        |d      }t        |      }t        |d         t        |d         }	}|d	z   kD  rd
|z
  dz  dz  z   S ||	z  z   }
|
 S )Nr   r   r      r   r   r   r   r   r   r   r   calmarsharpe皙?g    .A     @)r%   r   _metrics_blockr   )r-   r   r   r   r   eqmdd_magr   r   scorer   r   r   r   r   r   s              r   	objectivez,optimize_sleeve_notionals.<locals>.objective  s     1;adU1Q4[%!+MBD"$%%	
 2r"+A.q{+U1X;-?$t++&#339C???//vr   r   deferredboundsconstraintsr   r   r   workersupdatingr   r   r   	optimizedr   feasiblecapital_vrp_scaler   r   r   r   sum_overlay_vxxmax_drawdown_pctr   r   cagr_pct
return_pct
end_equityequityobjective_scorescipy_successscipy_messagenitr-   
np.ndarrayr   r%   )scipy.optimizer   r   r   r%   rV   r>   onesrandomdefault_rngr-   r   r   r   boolsuccessr(   messageintr   ),r   rr   r   r   r   r   r   r   r   rW   rk   rX   rY   rZ   rl   r[   r\   rm   rn   ro   rp   rq   r   r   r   r   r   hir   r   caprngr   resr   r   r   r   eq_optm_optr   r   r   r   s,      `  ```                                 @@r   optimize_sleeve_notionalsr  M  s   V H$!+++'1'' 7E$ %0$;eK G	 	!BBi#rS"IRy9FK+,-RWWV_c37
 ))


%C ( !	C ceeAhsuuQx%a/5QTQVQVWXQY?[BB !!	F 6;/E'.F)D00HHW 	r 	B	
 	  	t 	27R<$. 	F 	%/ 	%/ 	E*% 	eL) 	eL) 	& 	5?]U8_-LL  	ckk*!" 	S[[)#$ 	s377|% r   ffffff?x   )rr   r   sum_risk_budget_pctmax_sleeve_pctr   fixed_vxx_fracfixed_straddle_fracr   r   rW   rk   rX   rY   rZ   rl   r[   r\   rm   rn   ro   rp   rq   r   r   r   c                 	789:;<= ddl m}m}m} t	        |      <d;|-t	        |      ;d;cxk  rdk  st        d       t        d      d:|-t	        |      :d:cxk  rdk  st        d       t        d      t        | |
||||||||||||<      9|t	        |      n9j                  =t	        |      }d*:;fd	};:d|fd|fg}d+:;fd
8n:;d|fd|fd|fg}d+;fd8n&:d|fd|fd|fg}d+:fd8nd|fd|fd|fd|fg}d+d8g } |Lt	        |      }! ||!      }"t        |      }#| j                   |t        j                  d|#f      d|"             t        j                  j                  |      }$|}%d}&d,89<=	fd7|%:d-7fd}'| j                   ||'t        j                   t	        |%      |&z                t        |       }(d-7fd}) ||)||(|$||dd      }* 8|*j                         \  }+},}-}.|+<z  |,<z  |-<z  |.<z  f\  }/}0}1}2t#        9=|/|0|1|2	      }3t%        |3d      }4t'        |4      }5d}6||5t	        |      |&z   k  }6i d|6d|5d|+d|,d|-d|.d|+|,z   |-z   |.z   d=d |/d!|0d"|1d#|2d$|4d$   d%|4d%   d&|4d&   d'|4d'   d(|4d(   |3t)        |*j*                        t-        |*j.                        t1        |*j2                        d)S ).u  
    Search **allocation fractions** ``put, straddle, RR, VXX`` (each in ``[0, max_sleeve_pct]``) of
    ``total_portfolio_capital`` to **maximize Sharpe** on the full merged equity curve (VRP scale fixed).

    Risk budgets in USD are ``fraction × total_portfolio_capital``. Optional
    ``sum_risk_budget_pct`` caps ``f_put + f_straddle + f_rr + f_vxx`` (e.g. 0.35 = 35%% of account).

    If ``fixed_vxx_frac`` is set (e.g. ``0.01`` for 1%% of book to VXX), the search is only over
    put / straddle / RR; VXX is held fixed and excluded from ``sum_risk_budget_pct`` unless you
    subtract ``fixed_vxx_frac`` from the cap yourself.

    If ``fixed_straddle_frac`` is set (often ``0.0`` when the straddle JSONL is empty / disabled),
    straddle allocation is fixed and the search is over the remaining sleeves only.

    If ``max_dd_limit_pct`` is set, the solver enforces **peak-to-trough max DD** ≤ that value (hard
    inequality via ``NonlinearConstraint``, with a small numerical tolerance on the bound).
    r   )r   NonlinearConstraintr   Nr   r   z fixed_vxx_frac must be in [0, 1]z%fixed_straddle_frac must be in [0, 1]r   c           	     \    | }|z  }|z  }|dk  rt        d|  d d d      |S )Nr   zIsum_risk_budget_pct must be >= fixed_straddle_frac + fixed_vxx_frac (cap=z, fs_fixed=z, fv_fixed=))
ValueError)cap_sumremfs_fixedfv_fixeds     r   _sum_cap_remainderz5optimize_portfolio_sharpe.<locals>._sum_cap_remainder-  s_    8OC8OC7yH:[
!M  
r   c                @    t        | d         t        | d         fS )Nr   r   r   )r-   r  r  s    r   _unpackz*optimize_portfolio_sharpe.<locals>._unpack>  s"    1;%!+x??r   c                X    t        | d         t        | d         t        | d         fS Nr   r   r   r   )r-   r  s    r   r  z*optimize_portfolio_sharpe.<locals>._unpackD  s*    1;adU1Q4[(BBr   c                X    t        | d         t        | d         t        | d         fS r  r   )r-   r  s    r   r  z*optimize_portfolio_sharpe.<locals>._unpackJ  s*    1;%!+uQqT{BBr   c                n    t        | d         t        | d         t        | d         t        | d         fS )Nr   r   r   r   r   r-   s    r   r  z*optimize_portfolio_sharpe.<locals>._unpackP  s1    1;adU1Q4[%!+EEr   r   r   c           
     t     |       \  }}}}t        	|z  |z  |z  |z  
      }t        |d      S )Nr   r   )r   r   )r-   fpfsfrfvr   r  r   tcr   r   r   s         r   _metrics_from_fracsz6optimize_portfolio_sharpe.<locals>._metrics_from_fracs^  sU     BBR"W"$r'R%%	
 b"%%r   c                n     |       }t        |      }t        j                  |      rt        |      S dS )N    eA)r   r&   r'   r%   )r-   r   dr"  s      r   _max_dd_pct_magz2optimize_portfolio_sharpe.<locals>._max_dd_pct_magn  s1    #A&A*1-A#}}Q/588S8r   c                b     |       }t        |d         }t        j                  |      sy| S )Nr   r$  )r%   r&   r'   )r-   r   r   r"  s      r   r   z,optimize_portfolio_sharpe.<locals>.objectivey  s1    "q{#}}V$wr   r   r   r   
sharpe_optTfeasible_ddr   put_fracstraddle_fracrr_fracvxx_fracsum_fracr   r   r   r   r   r   r   r   r   r   )r   r   r   r   )r  r%   r   r%   )r-   r   r   z!tuple[float, float, float, float])r-   r   r   dictr   )r   r   r  r   r%   r  r   rV   r   rI   r>   r   r   r   inftupler-   r   r   r   r   r   r(   r   r   r   )>r   rr   r   r  r  r   r	  r
  r   r   rW   rk   rX   rY   rZ   rl   r[   r\   rm   rn   ro   rp   rq   r   r   r   r   r  r   r   r  r   	cons_listr  r  n_dimr   dd_limdd_tolr&  r   r   r  r  r  r  r   r   r   r   r   r  r  r   r)  r"  r  r   r  r  r!  r   s>           ``                                             @@@@@@@r   optimize_portfolio_sharper6    s,   \ ]\	&	'B!H!(x&3&?@@ '?@@!H&,-x&3&DEE 'DEE$!+++'1'' "E$ %0$;eK G	~	B  4)c2Y'	@ 
	)c2Yb	2	C 
	)c2Yb	2	C )c2Yb	C9=	F I&+, )F)"''1e**=sCHI
))


%CFF& & 	9
 	"&&%-&:PQ	
 	"K !	C SUU^NBBBwRb"r'9BB !!	F 6<0E'.FK#&6 7& @@{F 	B 		
 	2 	B 	BGbL2% 	W 	r 	B 	  	t 	%/ 	%/ 	E*%  	eL)!" 	eL)#$ ckk*S[[)377|+ r   r   g     L@)rr   r   r   r   r   r   r   r   rW   rk   rX   rY   rZ   rl   r[   r\   rm   rn   ro   rp   rq   out_csvprint_reportprint_vxx_sweepc                   |t        |      n
t        |      }|xs	 t        dz  }|xs	 t        dz  }|xs	 t        dz  }|xs	 t        dz  }|xs	 t        dz  }|	t        dz  }| j                         j                         }|rFt	        d       d	|fd
|fd|fd|fd|ffD ]'  \  }}|j                         rt	        d| d|        ) t        ||	||||
|||||||||      }|j                  }|j                  }t        |j                  d      t        |j                  d      t        |j                  d      }"}!} t        |j                  d      t        |j                  d      }$}#||j                  z  }%t        |      | z  |j                   z  }&t        |      |!z  |j"                  z  }'t        |      |"z  |j$                  z  }(t        |      })|)|dz  z  }*|)|dz  z  }+|*|#z  |j&                  z  },|+|$z  |j(                  z  }-||%j+                         z   }.||%|&z   |'z   |(z   j+                         z   }/||,|-z   j+                         z   }0||%|&z   |'z   |(z   |,z   |-z   j+                         z   }1t-        j.                  |.|/|0|1|%|&|'z   |(z   |,|-d|      }2|rt1        |.d      }3t1        |/d      }4t1        |0d      }5t1        |1d      }6|%|&|'z   |(z   |,|-d}7t-        j.                  |7      j3                         }8t	        dd        t	        d       t	        d        t	        dj5                  g d|dd |dd!|	dd"|dd#| dd$|dd#|!dd%|dd#|"dd&|dd'|d(d)|d(d*|*dd#|#dd+|+dd#|$d             |d,kD  r4t	        d-d|z  |z  d.d/d|z  |z  d.d0d|z  |z  d.d1d|z  |z  d.d2	       t	        d3|d,   j7                          d4|d5   j7                          d6t9        |       d7|3d8   d9d:	       t	        dd;        d<d=d>d?d@d>dAd@d>dBdCd>dDdEd>dFdGd>dHdEd>dIdCd>dJdGd>dKdE}9t	        |9       t	        d;        |3|4|5|6fD ]  }:|:dL   };t;        |;t<        t         f      rt?        j@                  |;      r|;dMdNndOdG}<t	        |:dP   d=d>|:dQ   dRd>|:dS   dRd>|:dT   dUd>|:dV   dWdX|< d>|:dY   dZd>|:d[   d\d>|:d]   dZdX|:d^   dZ        t	        d;        t	        d_       |6dY   |4dY   z
  }=|6d^   |4d^   z
  }>|6d]   |4d]   z
  }?|6dV   |4dV   z
  }@t?        j@                  |6dL         rAt?        j@                  |4dL         r)|6dL   |4dL   z
  }At	        d`|4dL   d9da|6dL   d9db|Adcdd       t	        de|4dY   d9d4|6dY   d9d6|=dfdg       t	        dh|4d^   d9d4|6d^   d9d6|>dcdg       t	        di|4d]   d9da|6d]   d9db|?dcdd       t	        dj|4dV   dkda|6dV   dkdb@dldd       t	        dm       t	        |8jC                  dn o             |r;|r8t	        dd        t	        dp       t	        d        t	        dqdGd>drdsd>dHdEd>dJdGd>dKdEd>dtdEdu       t	        dv        d}Bdw}CdxD ]  }D||Dz  }E|E|dz  z  }F|E|dz  z  }G|j&                  |F|#z  z  }H|j(                  |G|$z  z  }I|%|&z   |'z   |(z   |Hz   |Iz   }J||Jj+                         z   }Kt1        |Kdy|Ddz      }Ld}M|LdY   CkD  rLdY   }CD}BDd,k(  rd{}Mt	        Ed|d>Dd}d>LdY   dZd>|Ld]   dZdX|Ld^   dZd>|LdV   dWd~M         BBd,kD  rt	        dBdzd       t	        d        |j                         }|jD                  jG                  dd       |2jI                  |d       |rt	        d|        |2S )a/  
    Merge **VRP** (``pnl_usd`` on exit dates) with optional IV overlay JSONLs and VXX sleeve JSONLs.
    Missing overlay/VXX files contribute **zero** PnL (same as CLI defaults).

    All equity series start at ``total_portfolio_capital``. Overlay/VXX PnL scales as
    ``risk_budget / risk_ref`` (median ``broker_risk_usd`` per JSONL unless refs overridden).
    If ``capital_vrp`` is None, VRP PnL is scaled as ``total_portfolio_capital / vrp_ref``.

    Used by ``portfolio_vrp_plus_vxx.py`` CLI and ``vrp_backtest_theta.py --full-portfolio-report``.
    Nrt   ru   rv   rw   rx   portfolio_vrp_vxx_equity.csvu   Loading trade logs …zOTM put overlayzStress straddlezRisk reversalzVXX bear callzVXX long callz	  [skip] u   : file not found → r   r   r!   )eq_vrp_onlyeq_vrp_plus_overlayseq_vxx_sleeveeq_full_portfoliopnl_vrppnl_overlayspnl_vxx_bearpnl_vxx_call)rU   zVRP onlyzVRP + overlayszVXX sleeve onlyzFULL (VRP + overlays + VXX))VRPIV_overlaysVXX_bearVXX_call
z_===============================================================================================z6PORTFOLIO COMPARISON: VRP+Overlays vs VRP+Overlays+VXXr   z
Account start (all curves): $,.0fz  |  VRP PnL scale numerator $z	 vs ref $z:  |  IV overlay **risk budgets** (max loss / debit): put $z / ref $z, straddle $z, RR $z
  |  VXX $z (.0fz	% bear / u   % call) → bear $z, call $r   u`     (same sleeves as **fraction of account** — what you set with *-pct flags or merge JSON: put .3fz%, straddle z%, RR z%, VXX uc   %; dollar line above is that fraction × account, used to scale each overlay JSONL vs its ref risk)zDate range: u    → z  (z days; ~years.2fz yr CAGR horizon)u;  ─────────────────────────────────────────────────────────────────────────────────────────────────────────	Portfolioz<30 Startz>10EndReturnz>9zRet%z>7CAGRz>8SharpezMaxDD$zMaxDD%Calmarr   z>6.2f%n/alabelstart_capitalz>10,.0fr   total_returnz>+9,.0fr   z>6.1fz% r   z>7.2f
max_dd_usdz>9,.0fr   r   u1   
── IMPROVEMENT FROM ADDING VXX SLEEVE ──z  CAGR%:   u   % → z%  (z+.2fzpp)z  Sharpe:  +.3fr  z  Calmar:  z  MaxDD%:  z  Return%: .1fz+.1fu%   
── DAILY PNL CORRELATIONS ──c                
    | dS )Nr]  ri   r  s    r   <lambda>z)execute_portfolio_merge.<locals>.<lambda>j  s
    !D r   )float_formatu   VXX RISK-BUDGET SENSITIVITY — same account start; VRP + IV overlays unchanged; total VXX risk budget = fraction × account (split bear/call by %)zVXX$zVXX%z>6RetPctz  Notesu   ────────────────────────────────────────────────────────────g     8)
r   g{Gz?r   g{Gz?g?gQ?g333333?r"   r   g333333?zVXX=z.0%u   ← baseline (no VXX)z>8,.0fz>5.0%z%  u   
  ★ Best Sharpe at z VXX allocationT)parentsexist_okz%Y-%m-%d)date_formatu   
Daily equity CSV → )%r%   r   r   r   printr=   r   rU   rV   r)   rX   rY   rZ   r[   r\   r^   r_   r`   ra   rb   rc   rN   r   	DataFramer   corrjoindater   
isinstancer   r&   r'   	to_stringparentmkdirto_csv)Nr   rr   r   r   r   r   r   r   r   rW   rk   rX   rY   rZ   rl   r[   r\   rm   rn   ro   rp   rq   r7  r8  r9  r   r   rY  pr   r   rV   r   r   r   r   r   VPSRr   cap_vxx_bearcap_vxx_callVBVCr<  	eq_no_vxxr>  eq_with_vxxframem_vrpm_no_vxxm_vxxm_full	corr_datacorr_dfhdrr   cgcag_ssharpe_deltacalmar_deltadd_delta	ret_deltacagr_dbest_sharpe_allocbest_sharpe_valr-  vxx_capbear_capcall_capvxx_bvxx_c	combo_pnleq_combomcnotesN                                                                                 r   execute_portfolio_merger    sb   L %0$;eK G^A_GF'E EJ%Q$1P*PO/QD;P4P%Q$1P*PO%Q$1P*PO77$$&..0H&'
+023o.o.
 	CHE1 99;	%(=aSAB	C %!+++'1'' 7E" kkG
))CU''/U5L5Le1TVYZ_ZkZkmrVsBB5**E2C8O8OQV4WC%))A	{	b	 EII-A		 2	%2A	$	%	*eii7AD<%/0L<%/0L



	*B



	*B
"Kq1uqy1},,..I27**,,MQQ+b088::KLL&$-*!,EAI		
 E {J7!)-=>}.?@-JKa!eaiRUWX	,,y)..06(mFGl l- lc$Z l 8( l(/~l5>l?FtnlMDlDOPTCUlU]l^`ae]flgl *$/l 08l 9;4ylAl ).	l /7	l 8:$i	l@	l
  %l
 &(l
 )5S'9l
 :Cl
 DPPSBTl
Ul &d+l ,4l 58:l >Fl GSSWEXl Yal beei`jl	
 7{*S05\%JZBZ]`B`adAe f33c9#>gekFY\_F_`cEd ess 	71:??,-U72;3C3C3E2F GG~XeGnS%99JL	

 	9+3qQuSk8B-qPRSTU[\^T__`m1XbM8B-q"G 	 	c
5&1 	A:B&0c5\&Bt}}UWGXr%jNafgi`jEW:c"!Ao$6w#?q<QX@YYZ^$W-Qqu.ERwaPQRZP[\aObbc\?6*!AlOE+B"Qx[QVDWY	 	BCh'(8*<<h'(8*<<,'(<*@@<(8L+AA	==
+,x
?S1TJ'(:*>>Fhz237vfZ>PQT=UUYZ`aeYffij 	HX.s359I#8NcR^_cQddefgHX.s359I#8NcR^_cQddefgH\237vf\>RSV=WW[\dei[jjmnoH\237vf\>RSV=WW[\efj[kknop67g-BCD6(mQ	
 	1VBKq"Qxm1XbMQRS[\^R__fgh
  Q 	HHnG,"67H,"67HJJ(S.1EJJ(S.1EA	A-5IY--//HD#*?@BD(|o-"$X,$,!1}.6"!HU#31R\%4Hl#E*"R\%,@"\BRSXAYY\]a\bd#	, (->-B+,=c+B/RS  "GNN5	LLjL1'y12Lr   c                   | j                         j                  d      }t        | j                  d   | j                  d   z
        }t        | j                  d         t        | j                  d         }}|dkD  r||z  dz  nd}t        |j	                               }|j                         dkD  rt        |j                               nd}||z  t        j                  d      z  }	| j                         }
t        | |
z
  j                               }t        | |
z
  |
j                  dt        j                        z  j                  d      j                               dz  }|dk7  rt        ||z        nd}| j                  }t        d      }t        d      }t        |      dk\  rgt        j                   |d         t        j                   |d         }}t#        ||z
  j$                  dz  d      }|dkD  r|dkD  r||z  d	|z  z  d	z
  d
z  }|t'        |d      t'        |d      t'        |d      t'        |d      t)        j*                  |      rt'        |d      n
t        d      t)        j*                  |      rt'        |d      n
t        d      t'        |	d      t'        |d      t'        |d      t'        |d      t'        |d      dS )Nr   rL  d   g&.>   nanr   g     v@r   r!   r   r   )rY  rZ  r   r[  r   r   rM  r   r\  r   r   	daily_vol)difffillnar%   ilocmeanstdr>   sqrtcummaxminreplacer  r*   rU   r   r   	Timestampr)   r   roundr&   r'   )r   rY  r   	total_rets0s1pct_retmnsdr   peakdd_absdd_pctr   idxr   years_samplet0t1s                      r   r   r     sM   GGIQEbggbkBGGAJ./I2771:bggbk 2B&(1fi"ns"!G	uzz|	B$yy{Quyy{	DB2g%F99;DBI??$%FR$Y$,,q"&&"99AA!DHHJKcQF(.!SV#$F
((CU|H<L
3x1}c!f%r||CG'<BBG>>F2D96b1fbcL&89C?5HHr1Bli+GQ'*.--*AE(A&uU|+/==+F|Q'ERWL"FA&FA&"2q\ r   c                J    |t        |      t        |      z  S t        |       S )z[If ``pct`` is set, return ``total_capital * pct`` (``pct`` is a fraction, e.g. 0.02 = 2%%).r   usdpcttotal_capitals      r   _risk_budget_from_pct_or_usdr    s%    
]#eCj00:r   c               &   t        |      }t        j                  |      r|dk  rt        d      t	        |       j                         j                         }t        j                  |j                  d            }t        |j                  d|      xs |      }|dkD  r||z  nd}|j                  d      }t        |t              r|ni }|j                  d      t        |j                  dd	      xs d	      }	t        |j                  d
d	      xs d	      }
t        |j                  dd	      xs d	      }t        |j                  dd	      xs d	      }t        |j                  dd      xs d      }t        |j                  dd      xs d      }||	z  ||
z  ||z  ||z  ||d}n<t        |j                  d      t              rx|d   rs|d   dfd}| |d      z  | |d      z  | |d      z  | |d      z  t        |j                  dd      xs d      t        |j                  dd      xs d      d}nt        |j                  d      t              rx|d   rs|d   dfd} |d      |z   |d      |z   |d      |z   |d      |z  t        |j                  dd      xs d      t        |j                  dd      xs d      d}nt        | d      |j                  d      }||t        |      z  |d<   |S )u  
    Load ``optimize_overlay_risk_fracs.py`` output and return kwargs for :func:`execute_portfolio_merge`.

    Reads **fractions of account** from ``portfolio_vrp_plus_vxx_cli_snippet`` or
    ``overlay_risk_fractions`` (maps to ``capital_put``, … as ``total_capital * frac``).
    If only ``overlay_risk_usd`` exists (``calmar-usd`` mode), scales those USD budgets by
    ``total_capital / json['total_capital']``.

    Optional ``capital_vrp_pct`` in the snippet sets ``capital_vrp`` (VRP PnL scale numerator).
    r   z-total_capital must be a positive finite floatzutf-8)encodingr  r   "portfolio_vrp_plus_vxx_cli_snippetcapital_put_pctr   capital_straddle_pctcapital_risk_reversal_pctcapital_vxx_pctr   r   r   r   )r   r   r   r   r   r   overlay_risk_fractionsc                D    j                  |       }|t        |      S dS Nr   r$   r%   )kr,   ovs     r   _fz.merge_capital_from_allocation_json.<locals>._f  s#    q	A }585#5r   stress_longvol_otm_putstress_longvol_straddlerisk_reversal
vxx_sleeveoverlay_risk_usdc                D    j                  |       }|t        |      S dS r  r  )r  r,   r  s     r   _uz.merge_capital_from_allocation_json.<locals>._u  s#    
A }585#5r   zx: expected 'portfolio_vrp_plus_vxx_cli_snippet' with capital_put_pct, or 'overlay_risk_fractions', or 'overlay_risk_usd'capital_vrp_pctr   )r  r(   r   r%   )r%   r&   r'   r  r   r   r   jsonloads	read_textr$   rk  r/  )r   r  r   rp  rawtc0scalesnipsnip_dput_pstr_prr_pvxx_pr   r   outr  r  vrp_pctr  r  s                      @@r   "merge_capital_from_allocation_jsonr    s    
C==HIIT
'')A
**Q[['[2
3C
-4
5CqC#IcE7778Dd+TFzz#$0fjj!2C8?C@fjj!7=DEVZZ ;SAHSIfjj!2C8?C@VZZ5=>VZZ5=>; #e%(4Z;  !
 
CGG45t	<E]A^)*	6
 $<!== #b)B&C C%(2o+>%>L!11!#''.$"?"G4H!#''.$"?"G4H
 
CGG./	63?Q;R$%	6
 67%? "#< = E%'%85%@l+e3!#''.$"?"G4H!#''.$"?"G4H
 c A A
 	

 jj*+G 5>1MJr   c                 B"   t        j                  d      } | j                  dt        dd       | j                  dt        d d       | j                  d	t        d d
       | j                  dt        d dd       | j                  dt        dd       | j                  dt        d dd       | j                  dt        dd       | j                  dt        d dd       | j                  dt        dd       | j                  dt        d dd       | j                  dt        dd       | j                  dt        d dd        | j                  d!t        d"d#       | j                  d$t        d%d&       | j                  d't        d()       | j                  d*t        d d+       | j                  d,t        d d-       | j                  d.t        d )       | j                  d/t        d )       | j                  d0t        d d1       | j                  d2t        d )       | j                  d3t        d )       | j                  d4t        t
        d5t
        j                   d6       | j                  d7t        t        d8z  )       | j                  d9t        t        d:z  )       | j                  d;t        t        d<z  )       | j                  d=t        t        d>z  )       | j                  d?t        t        d@z  )       | j                  dAt        t        dBz  )       | j                  dCdDdEF       | j                         }|j                  dGdDdHF       |j                  dIdDdJF       | j                  dKt        dLddM       | j                  dNt        dOddP       | j                  dQt        dRdSdT       | j                  dUt        d ddV       | j                  dWt        d ddX       | j                  dYt        dRdZ       | j                  d[t        dd\       | j                  d]t        d dd^       | j                  d_t        dOd`       | j                  dat        ddb       | j                  dct        d ddd       | j                  det        dfdg       | j                  dht        didj       | j                         }t        |j                        }|j                   g }|j                  |j                  d       |j                  |j                  d       |j                   |j                  d       |j"                  |j                  d       |j$                  |j                  d       |j&                  s|j(                  r|j                  dk       |rBt+        dldmj-                  |      z   t.        j0                  n       t/        j2                  do       |j4                  }|j$                  $|j                  |t        |j$                        z  }|j                  |j                  j7                         }|j9                         sAt+        dp|j;                          t.        j0                  n       t/        j2                  do       	 t=        ||q      }t        dt         }	t        |du         }
t        |dv         }t        |dw         }t        |dx         }t        |dy         }dz|v rt        |dz         }t+        d{       t+        d|       t+        d{       t+        d}|j;                                 t+        d~d|	z  |z  ddd|
z  |z  ddd|z  |z  ddd|z  |z  dd|dd|dd|dd       dz|v rt+        dt        |      dd       nt+        d|dd       t+        d       n*t        |jF                        }t        |jH                        }|j                  tK        |jL                  |j                  |      }	tK        |jN                  |j                  |      }
tK        |jP                  |j                   |      }tK        |jR                  |j"                  |      }|jT                  "t        |jT                        }|dik  rd n||z  }n'|jV                  dik  rd }nt        |jV                        }t        |jX                        }|jZ                  |t        |jZ                        z  }t]        |j^                  |j`                  |jb                  |jd                  |jf                  |jh                  |jj                        }|j&                  rt        |jl                        dik  rd nt        |jl                        }t        |jn                        dik  rd nt        |jn                        }tq        |jr                  fi d|j                  dz|d|dt        |jt                        d|d|jv                  d|jx                  dx|jF                  dy|jH                  d|jz                  d|j|                  d|j~                  d|j                  d|j                  d|j                  dt        |j                        dt        |j                        |}t        |j                        }t+        d       t+        d       t+        d{       |dn|dd}|dn|d   }d}|jv                  |dt        |jv                        dz  }|jx                  |dt        |jx                        dz  }t+        d| d| |        t+        d|d   dd|d   dd|d   dd|d   dd|d   d
       t+        d|dd|dt   dd|du   dd|dv   dd|dw   d
       |d   }t        j                  |      r|ddnd}t+        d|d   dd|d   dd|d   dd| d|d   dd|d   d       t+        d|d    dʝ       t+        d˫       t+        d|dd|d   dΛd|d   dΛd|d   dΛd|d   dΛd|jF                  dӛd|jH                  dӛd՝       t+        d       t        di d|jr                  d|j                  dz|dt|dt   du|du   dv|dv   dw|dw   dx|jF                  dy|jH                  d|jz                  d|j|                  d|j~                  d|j                  d|j                  d|j                  d|j                  ddٓddۓ| y |j(                  rt        |jr                  fi d|j                  dz|dt        |j                        d|d|dt        |j                        dx|jF                  dy|jH                  d|jz                  d|j|                  d|j~                  d|j                  d|j                  d|j                  dt        |j                        dt        |j                        |}t+        d       t+        d߫       t+        d{       t+        d|j                  dd|d           t+        d|dt   dd|du   dd|dv   dd|dw   d       t+        d|d   dd|d   d       |d   }t        j                  |      r|ddnd}t+        d|d   dd|d   dd|d   dd| d|d   dd|d   d       t+        d|j                   d|d   d       t+        d|d    dʝ       t+        d       t        di d|jr                  d|j                  dz|dt|dt   du|du   dv|dv   dw|dw   dx|jF                  dy|jH                  d|jz                  d|j|                  d|j~                  d|j                  d|j                  d|j                  d|j                  ddٓddۓ| y t        di d|jr                  d|j                  dz|dt	du
dvdwdx|dy|d|jz                  d|j|                  d|j~                  d|j                  d|j                  d|j                  d|j                  ddٓd|j                   | y # t>        j@                  tB        tD        f$ rA}t+        dr| ds| t.        j0                  n       t/        j2                  do       Y d }~
gd }~ww xY w)Nz'VRP + overlays + VXX contango portfolio)descriptionz--total-capitalrj   zGStarting equity for every reported curve (single account; default 100k))typedefaulthelpz--allocation-jsonu   Run merged portfolio from optimize_overlay_risk_fracs.py output: sleeve fractions × --total-capital (incompatible with --capital-*-pct / --optimize-*).z--capital-vrpzGVRP PnL scale numerator vs --vrp-ref (default: same as --total-capital)z--capital-vrp-pctFRACuZ   VRP scale numerator = FRAC × --total-capital (e.g. 1.0); overrides --capital-vrp when set)r  r  metavarr  z--capital-puti'  zfPut overlay broker risk budget USD (max loss / debit); scaled vs ref (median broker_risk_usd in JSONL)z--capital-put-pctu_   Put risk budget = FRAC × --total-capital (e.g. 0.02 for 2%%); overrides --capital-put when setz--capital-straddlezStraddle sleeve risk budget USDz--capital-straddle-pctuU   Straddle risk budget = FRAC × --total-capital; overrides --capital-straddle when setz--capital-risk-reversalz$Risk-reversal sleeve risk budget USDz--capital-risk-reversal-pctuT   RR risk budget = FRAC × --total-capital; overrides --capital-risk-reversal when setz--capital-vxxi:  zETotal VXX sleeve broker risk budget USD (split bear/call by %% flags)z--capital-vxx-pctuQ   VXX total risk budget = FRAC × --total-capital; overrides --capital-vxx when setz--vxx-bear-pctZ   z7Percent of VXX capital to bear call (rest to long call)z--vxx-call-pct
   z#Percent of VXX capital to long callz	--vrp-refi )r  r  z--overlay-refzCOverride risk ref USD for all three IV overlays (put, straddle, RR)z--put-risk-refz!Override put overlay risk ref USDz--straddle-risk-refz--rr-risk-refz	--vxx-refzAOverride risk ref USD for both VXX JSONLs (bear call + long call)z--vxx-bear-risk-refz--vxx-call-risk-refz--vrp-tradesz"VRP closed trades JSONL (default: r  z--put-tradesrt   z--straddle-tradesru   z--risk-reversal-tradesrv   z--vxx-bear-tradesrw   z--vxx-call-tradesrx   z	--out-csvr;  z--no-vxx-sweep
store_truezASkip the VXX notional sensitivity table after the main comparison)actionr  z--optimize-sleeveszeSearch put/straddle/RR/VXX risk budgets (USD) to maximize Calmar + w*Sharpe with a max-DD soft targetz--optimize-sharpezbSearch sleeve allocation fractions (of --total-capital) to maximize Sharpe on the full merged bookz--sharpe-sum-cap-pctr  zeWith --optimize-sharpe, max sum of put+straddle+RR+VXX fractions (default 0.35); use 0 for no sum capz--sharpe-max-sleeve-pctr   zWWith --optimize-sharpe, upper bound per sleeve fraction (default 0.25 of total capital)z--sharpe-max-dd-pctr   PCTz[With --optimize-sharpe, hard cap on peak-to-trough max DD %% (default 10); use 0 to disablez--sharpe-fixed-vxx-pctzWith --optimize-sharpe, hold VXX sleeve at FRAC of --total-capital and optimize only IV sleeves (put/straddle/RR). --sharpe-sum-cap-pct then limits put+straddle+RR only (add this FRAC separately for total overlay+VXX).z--sharpe-fixed-straddle-pctzhWith --optimize-sharpe, hold straddle sleeve at FRAC (use 0 when straddle JSONL is disabled / zero PnL).z--max-dd-pctzWWith --optimize-sleeves, penalize paths whose max drawdown exceeds this %% (default 10)z--notionals-budgetz_With --optimize-sleeves, cap sum of risk budgets put+straddle+RR+VXX (default 100k); 0 = no capz--notionals-budget-pctut   With --optimize-sleeves, cap sum = FRAC × --total-capital; overrides --notionals-budget when set (0 still = no cap)z--sharpe-weightz3With --optimize-sleeves, objective += this * Sharpez--opt-max-sleevezKWith --optimize-sleeves, upper bound USD per searched sleeve (default 100k)z--opt-max-sleeve-pctun   With --optimize-sleeves, per-sleeve upper bound = FRAC × --total-capital; overrides --opt-max-sleeve when setz--opt-maxiterr   z5DE maxiter for --optimize-sleeves / --optimize-sharpez
--opt-seedr   z3RNG seed for --optimize-sleeves / --optimize-sharpez&--optimize-sharpe / --optimize-sleevesz2ERROR: --allocation-json cannot be combined with: z, )filer   z$ERROR: --allocation-json not found: )r  zERROR: --allocation-json z: r   r   r   r   r   r   r   zH========================================================================zIPORTFOLIO BACKTEST (merge model): sleeve sizes from % allocations in JSONz  JSON: z  put r!   z.4fz%  straddle z%  RR z%  VXX z% of $rI  z  | VXX split rJ  /z
 bear/callz  VRP PnL scale numerator $z (capital_vrp_pct from JSON)z- (default: full --total-capital vs --vrp-ref)zI========================================================================
r  )rk   rX   rY   rZ   rl   r[   r\   rr   r  r  r   r	  r
  rW   rm   rn   ro   rp   rq   r   r   zI
========================================================================zKSHARPE-OPTIMIZED ALLOCATION (fractions of --total-capital; VRP scale fixed)disabledr^  rW  rX  r)  r   z  |  fixed VXX frac: z.6fz  |  fixed straddle frac: z  DD cap (hard): z  |  feasible_dd: z  put_frac=r*  z  straddle_frac=r+  z
  rr_frac=r,  z  vxx_frac=r-  z  sum=r.  z	  USD @ $z: put=$z  straddle=$z  RR=$z  VXX=$r   rN  z	  Sharpe=r   rK  z	  Calmar=r   z
  max_dd%=r   z  CAGR=z  ret%=r   z%  end=$r   z  [r   ]z
  Re-run with:
zZ  .venv/bin/python RenTech/strategy_stack/portfolio_vrp_plus_vxx.py \
    --total-capital z \
    --capital-put-pct z.8fz \
    --capital-straddle-pct z# \
    --capital-risk-reversal-pct z \
    --capital-vxx-pct z \
    --vxx-bear-pct gz --vxx-call-pct z \
    --no-vxx-sweepr   r7  r8  Tr9  Fr   r   r   zEOPTIMIZED SLEEVE RISK BUDGETS (VRP scale fixed; single account start)u     Feasible (max DD ≤ z%): r   z  capital_put=z  capital_straddle=z  capital_risk_reversal=z  capital_vxx=z   sum(risk budgets overlay+VXX)=r   z  |  VRP scale numerator=r   z  max_dd_pct=z
%  Calmar=z  objective (Calmar + z	*Sharpe)=r   ri   )MargparseArgumentParseradd_argumentr%   r   DEFAULT_VRP_TRADES_JSONLnamer   add_mutually_exclusive_groupr   
parse_argsr  allocation_jsonr  rI   r  r  r  r  optimize_sharpeoptimize_sleevesrf  ri  sysstderrexitr   r   r=   r   r  r  JSONDecodeErrorOSErrorr  r   r   r  r   r   r   r   notionals_budget_pctnotionals_budgetopt_max_sleeveopt_max_sleeve_pctr/  rk   rX   rY   rZ   rl   r[   r\   sharpe_sum_cap_pctsharpe_max_dd_pctr6  r   sharpe_max_sleeve_pctsharpe_fixed_vxx_pctsharpe_fixed_straddle_pctrW   rm   rn   ro   rp   rq   opt_maxiteropt_seedr&   r'   r  r7  r  r   r   no_vxx_sweep)ap_opt_grpargsr!  badcap_vrp_resolvedajallocecap_putcap_strcap_rrcap_vxxvxx_bear_effvxx_call_effrp  
budget_capr   _risk_ref_kwsharpe_sum_capsharpe_dd_caprtc2dd_notefeas_ddfv_note_cg_cgss                               r   mainr#    s   		 	 -V	WB OOV	   OON	   OOV	   OOi   OOu	   OOn   OO(uf:  <OO d   OO-E6?  AOO%c   OOT	   OO`   OO$5"R  TOO$5">  @ OOKeWO=OOR	   OO$5$EhOiOO)tODOOO%O>OOP	   OO)tODOO)tOD OO(12J2O2O1PPQR	   OONt>\7\O]OO'dDCb<bOcOO,4H]A]O^OO'd #BB  DOO'd #BB  DOOKdD;Y4YOZOOP   ..0Ht  
 q  
 OOt   OO!f   OOj   OO E   OO%w   OOf	   OOn	   OO  D   OO%E4N  POOZ	   OO}   OOO#r@wOxOOLsA<qOr==?D	t!!	"B'+JJ*+$$0JJ/0))5JJ45+JJ*++JJ*+4#8#8JJ?@DtyyQT~UZZ HHQK'''D,@,@,Hd&:&: ;;'!!,,.zz|8GcjjYHHQK	6rLE m,-012u456m,-U>23U>23E!$U=%9:hYZh'(UW_r)#.l57?R;OPS:T U&.2%c*'%'/B2Fs1K6RTUYQZ [',Al3-?zK	

 E!/6F0G/MMijk/4y8efgoT../T../#.  d&:&:"
 /%%4+D+DTV
 .**0N0N^`
 /  d&:&:"
   ,$++,!VTa
			!	#
4001
4../N*eD$;$;<<$$&&00$$0000L !&t'>'>!?1!D%PTPgPgJh %d&<&< = BdNdNdHe%OO
$($6$6
 )
 !/	

 !!;!;<
 +
  44
 !% > >
 **
 **
 LL
 
 !00
 "&!:!:
 !00
  !00!
" (()#
$ T]]#'
* D&&'o[\h - 5*mC=PPQ;R(0%a6F$$0.uT5N5N/OPS.TUUG))53E$:X:X4YZ]3^__G!'*<WIgYOPAjM#..>q?QRU>V W9c*+a
mC5HqQ[}]`Nac 	d	#d71]+;D*AaPbNcdhMi j./5WQ}=Md<SU 	V
m $c 2#c!}	!H+c*)AhK3DJqQcOdehNi jV71\?3"7x,PT?UW 	XAo&'q)*"###&s) ,%%&z]3$7 8**+O*<S)A B//0|C.@ A%%&z]3$7 8""&"3"3A!66FtGXGXYZF[ \!"		
 	o 	
	
$($6$6	
 )	
 -(		

 12	
 #$$;"<	
 -(	
 **	
 **	
 LL	
 	
 !00	
 "&!:!:	
 !00	
 !00	
  LL!	
" #	
$ "'	
* 
		%OO
$($6$6
 )
 #4??3	

 &0
 -
   2 23
 **
 **
 LL
 
 !00
 "&!:!:
 !00
 !00
  (()!
" T]]#%
( 	oUVh''<D:PQq/55HK]I^_cHd e''()@'A$&G~VWXeVfgkUln 	o03D1Ed0KKdefgze{  }A  eB  C  	D
m $c 2#c!}a 23C8
1X;sBSS\]^_g]hil\m nV71\?3"7x,PT?UW 	X&t'9'9&:)AFWDXY\C]^_Ao&'q)*o 	
	
$($6$6	
 )	
 -(		

 12	
 #$$;"<	
 -(	
 **	
 **	
 LL	
 	
 !00	
 "&!:!:	
 !00	
 !00	
  LL!	
" #	
$ "'	
, 	  	
	
$($6$6	
 )	
  		

 %	
 #)	
  	
 &	
 &	
 LL	
 	
 !00	
 "&!:!:	
 !00	
 !00	
  LL!	
" #	
$ !% 1 11'	
Q $$gz: 	-bTA37cjjIHHQKK	s   %AB? B?ADC6ADDAD__main__)	pnl_total)r   r   r   r(   r   r]   )r+   r/  r   r%   )r   r   r   r%   )rO   r]   rP   r%   r   r]   ) r   r   rW   r%   rX   r   rY   r   rZ   r   rk   r   r[   r   r\   r   rl   r   rm   Path | Nonern   r&  ro   r&  rp   r&  rq   r&  rr   r%   r   rT   )r   rT   r   r   r   r%   r   r%   r   r%   r   r%   r   r%   r   r%   r   r]   )r   r/  r   r%   )4r   r   rr   r%   r   r   r   r%   r   r   r   r%   r   r%   r   r%   r   r%   rW   r%   rk   r   rX   r   rY   r   rZ   r   rl   r   r[   r   r\   r   rm   r&  rn   r&  ro   r&  rp   r&  rq   r&  r   r   r   r   r   r   r   dict[str, Any])6r   r   rr   r%   r   r   r  r   r  r%   r   r   r	  r   r
  r   r   r%   r   r%   rW   r%   rk   r   rX   r   rY   r   rZ   r   rl   r   r[   r   r\   r   rm   r&  rn   r&  ro   r&  rp   r&  rq   r&  r   r   r   r   r   r   r   r'  )4r   r   rr   r%   r   r   r   r%   r   r%   r   r%   r   r%   r   r%   r   r%   rW   r%   rk   r   rX   r   rY   r   rZ   r   rl   r   r[   r   r\   r   rm   r&  rn   r&  ro   r&  rp   r&  rq   r&  r7  r&  r8  r   r9  r   r   zpd.DataFrame)r   r]   rY  r(   r   r/  )r  r%   r  r   r  r%   r   r%   )r   z
Path | strr  r%   r   zdict[str, float])0rg   
__future__r   r  r  r&   r  dataclassesr   pathlibr   typingr   numpyr>   pandasr   __file__r   rc  _REPOr   r  r(   r   r   /RenTech.strategy_stack.iv_mispricing_complementr   r   r   r   r2   r;   rC   rL   rQ   rT   r   r   r   r  r6  r  r   r  r  r#  rd   ri   r   r   <module>r1     s  9t #     !    X ((+y6!F*"MM u:SXXHHOOAs5z" 
R
/$"3 ,F" $  , !%&* $ $&*&* "#'(,#'#'%.!ff f 	f
 $f f f $f $f f f !f &f !f !f  #!f" #fb && & 	&
 & !& & & & &<) &/ $"-6( $!%&* $ &*&*"#'(,#'#'5MM #M 	M
 M +M M M M M M M M $M M  !M" $#M$ $%M& 'M( !)M* &+M, !-M. !/M0 1M2 3M4 5M6 7Mf &/ $(, %)#'(, $!%&* $ &*&*"#'(,#'#'7VV #V 	V
 &V V #V !V &V V V V V V $V  !V" #V$ $%V& $'V( )V* !+V, &-V. !/V0 !1V2 3V4 5V6 7V8 9Vx &/ $!&#+! $!%&* $ &*&*"#'(,#'#' 5cc #c 	c
 c c !c c c c c c c $c c  !c" $#c$ $%c& 'c( !)c* &+c, !-c. !/c0 1c2 3c4 5c6 7cL!HM`N
b zF r   