
    pjS)                    (   U d Z ddlmZ ddlZddlmZ ddlZddlZ	ddddddddddddddddZ
ded	<   	 d	 	 	 	 	 	 	 	 	 dd
Z	 	 	 	 	 	 ddZddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 	 	 ddZdd	 	 	 	 	 	 	 	 	 	 	 ddZy)u9  
UnifiedMarginTracker — daily combined-margin estimate for the Best Ideas portfolio.

Aggregates margin estimates from each sleeve, scaled by fund_weights × fund_scale.
Reports combined utilisation and applies a dynamic scale cap when projected margin
would exceed ``margin_cap_frac`` (default 0.85) of the running NAV.

Sleeve margin sources
---------------------
* ``spy_theta``     — actual margin from ``evaluate_theta_margin``
                      column: ``margin_total_usd``
* ``vxx_regime``    — VXX regime stack daily CSV
                      column: ``margin_total_usd`` (added 2026-06)
* ``vxx_long_call`` — long OTM calls, paid premium → zero margin required
* ``macro_aw``      — from per-trade ``margin_reserved_usd`` (added 2026-06)
                      reconstructed as daily open-position margin
* ``tactical_aw``   — Tactical AW daily CSV column ``margin_usd`` (added 2026-06)
* ``tsmom``         — TSMOM daily CSV column ``margin_usd`` (added 2026-06)
* ``orb_zarattini``  — Zarattini 5m ORB daily CSV column ``margin_usd`` (added 2026-07)
    )annotationsN)Pathmargin_total_usd
margin_usd)	spy_theta
vxx_regimetactical_awtsmomorb_zarattinivol_edge	ls_equityvxx_long_callmacro_aw
equity_dipsector_momentumride_rocketsma_slope_topnma_slope_inversema_slope_intradayzdict[str, str]_MARGIN_COLc                p   | j                         s'|rt        j                  d|      S t        d|        t        j                  | dg      }t        j
                  |d         j                  j                         |d<   |j                  d      }||j                  vrR|r?t        j                  d| d| j                   dd	
       t        j                  d|      S t        d| d|        ||   j                  |      j                         j!                  d      j#                  t$              S )z>Load a single margin column from a CSV and reindex to ``idx``.        indexzMargin CSV not found: dateparse_dateszColumn 'z	' not in zV; margin set to 0 for this sleeve. Re-run the sleeve backtest to populate this column.   
stacklevel)is_filepdSeriesFileNotFoundErrorread_csvto_datetimedt	normalize	set_indexcolumnswarningswarnnameKeyErrorreindexffillfillnaastypefloat)pathcolidxfallback_zerodfs        I/opt/rentech/trading_bot/RenTech/strategy_stack/unified_margin_tracker.py_load_margin_colr:   6   s    <<>99S,,"8 ?@@	Tx	0B6
+..88:BvJ	f	B
"**MM3%y 4F F
 99S,,#iv677c7??3%%'..s3::5AA    c                   | j                         st        j                  d|      S t        j                  | ddg      }t        j                  |d         j
                  j                         |d<   t        j                  |d         j
                  j                         |d<   d|j                  vr.t        j                  dd	       t        j                  d|      S t        j                  d|      }|j                         D ]  \  }}t        |j                  dd      xs d      }|dk(  r+t        j                  |d         }t        j                  |d         }t        j                  |      st        j                  |      r|j                         }|j                         }|||k\  ||k  z     }	|j                  |	xx   |z  cc<    |S )
u   Reconstruct per-day open Macro AW margin from the trade log.

    For each business day, sum ``margin_reserved_usd`` for all trades where
    ``entry_date ≤ day < exit_date`` (position still open).
    r   r   
entry_date	exit_dater   margin_reserved_usdzhmacro_aw trades CSV has no 'margin_reserved_usd' column. Re-run macro_aw_options_portfolio.py to add it.r   r   )r!   r"   r#   r%   r&   r'   r(   r*   r+   r,   iterrowsr3   get	Timestampisnaloc)
trades_pathr6   tradesmargin_by_day_rowmentryexit_	days_opens
             r9   _macro_aw_daily_marginrN   P   s     yyC(([[<2MNF>>&*>?BBLLNF<..)<=@@JJLF;FNN2>	

 yyC((IIc-M//# *3#''/5<=8S./S-.775>RWWU^!!#+67	)$)$* r;   )equity_dip_dailyvol_edge_dailyls_equity_dailyorb_zarattini_dailyc               @   i }|D ]  }t         j                  |      }|dk(  rt        |d|       ||<   /|dk(  rt        |d|       ||<   E|dk(  rt        |d|       ||<   [|dk(  r.|
t        |
d|       ||<   st        j                  d|       ||<   |d	k(  rt        |d|       ||<   |d
k(  r.|t        |d|       ||<   t        j                  d|       ||<   |dk(  r/|	t        |	d|       ||<   t        j                  d|       ||<   |dk(  rt        j                  d|       ||<   ,|dk(  rt        ||       ||<   B|dv r6|j                  |d      }||z  }t        j                  |dz  |       ||<   |t        j                  d|       ||<    |S )zReturn ``{sleeve_key: daily_margin_usd_at_scale_1}`` for every active sleeve.

    The series are at scale=1 (unlevered); multiply by ``fund_scale`` to get
    the margin consumed by the levered position.
    r   r   r   r
   r   r   r   r   r	   r   r   r   r   )r   r   johansen_etfr   r   r   r   qs_actionable_etfg333333?)r   rA   r:   r"   r#   rN   )r6   active_sleeveslit_mtm_dailyvxx_regime_dailytsmom_dailytactical_aw_dailymacro_aw_trades_pathrO   rP   rQ   rR   fund_weights
fund_scalecapitalresultsleever5   wbase_notionals                      r9   build_sleeve_margin_maprc   w   s   0 $&F  47oof%[ -m=OQTUF6N|#-.>@RTWXF6Nw-k<MF6N&".!12E|UX!Yv!#3c!:v}$-.?sSF6Nz!)!1.,PS!Tv!#3c!:v{"*!1/<QT!Uv!#3c!:v&YYs#6F6Nz!34H#NF6N 
 
   -AKMYY}t';3GF6N  YYs#6F6Ni47l Mr;   c                  t        j                  |       }t        j                  d|       }|j                         D ]8  \  }}t	        |j                  |d            }||z  }	d| d}
|	|z  ||
<   ||	z   }: ||z  |d<   ||d<   |S )ux  Combine per-sleeve margins into a summary DataFrame.

    Each sleeve's standalone margin (computed at $100k notional) is scaled by:
    ``fund_weight × fund_scale`` because:
    * ``fund_weight`` is the fraction of NAV allocated to the sleeve, and
    * ``fund_scale`` is the overall leverage multiplier applied to the combined book.

    Columns returned:
    * ``margin_<sleeve>_usd``   — sleeve margin scaled by fund_weight × fund_scale
    * ``margin_combined_usd``   — total across all sleeves (at fund_weight × fund_scale)
    * ``margin_scale1_usd``     — total at scale=1 weighted by fund_weights (for gating)
    r   r   margin__usdmargin_combined_usdmargin_scale1_usd)r"   	DataFramer#   itemsr3   rA   )r6   sleeve_margin_mapr\   r]   outcombined_scale1r`   	margin_s1ra   margin_weighted_s1r5   s              r9   build_combined_marginrp      s    & ,,S
!Cii3/O.446 ?	,""63/0&]xt$%
2C),>>? "1:!=C.CJr;   g333333?)margin_cap_fracc                   ||z  }|j                  dt        j                        }||z  }|j                  |      }t        j                  ||j                  d            }| |z  }	|	|fS )u_  Apply a per-day dynamic scale cap so margin ≤ ``margin_cap_frac`` × prev_NAV.

    Parameters
    ----------
    port_ret_unscaled : daily portfolio return at scale=1 (normalized weights, no leverage)
    fund_scale : requested leverage multiplier
    margin_scale1 : combined margin at scale=1 per day
    nav : prior-day NAV (or starting capital on day 0)
    margin_cap_frac : max allowed margin / NAV (default 0.85 = 85%)

    Returns
    -------
    effective_ret : levered daily return, capped when margin would breach
    effective_scale : the scale actually applied each day (≤ fund_scale)
    r   )lower)replacenpnanr1   minimumclip)
port_ret_unscaledr]   margin_scale1navrq   
max_marginsafemax_scale_from_margineffective_scaleeffective_rets
             r9   apply_margin_capr      sv    . &J   bff-D&-188Djj-B-G-Gc-G-RSO%7M/))r;   )T)
r4   r   r5   strr6   pd.DatetimeIndexr7   boolreturn	pd.Series)rE   r   r6   r   r   r   )r6   r   rV   zset[str]rW   r   rX   r   rY   r   rZ   r   r[   r   rO   Path | NonerP   r   rQ   r   rR   r   r\   dict[str, float]r]   r3   r^   r3   r   dict[str, pd.Series])
r6   r   rk   r   r\   r   r]   r3   r   zpd.DataFrame)ry   r   r]   r3   rz   r   r{   r   rq   r3   r   ztuple[pd.Series, pd.Series])__doc__
__future__r   r+   pathlibr   numpyru   pandasr"   r   __annotations__r:   rN   rc   rp   r    r;   r9   <module>r      s  * #     '&  !  ^ . 	B
B	B 
B 	B
 B4$$	$ $b %)"&#''+P	P P
 P P P P P "P  P !P %P #P  !P" #P$ %Pf	+ #	
  P " *  * *  * 
	 *  * ! *r;   