
    pj<                    f   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e      ej,                  vr"ej,                  j/                  d ee             ddlmZ dd	lmZ dd
lmZ ed   Zedz  dz  dz  Zedz  Z dZ! ed       G d d             Z"d dZ#	 	 	 	 	 	 	 	 	 	 d!dZ$d"dZ%	 	 	 	 	 	 	 	 	 	 d#dZ&	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d$dZ'd%dZ(d&dZ)	 	 	 	 	 	 	 	 	 	 	 	 d'dZ*d(dZ+d)dZ,e-dk(  r e,        yy)*u  
Volatility Edge VIX ETN sleeve (Zarattini / Mele / Aziz, SSRN 5316487).

Implements Strategies 2–4 on short-vol (SVXY/SVIX) and long-vol (VIXY) ETNs:
  * ``evrp`` — short when expected VRP > 0 (20% allocation)
  * ``evrp_boc`` — eVRP + VIX vs VIX3M term structure (Strategy 3)
  * ``evrp_boc_sizing`` — Strategy 4, size = VIX/100
  * ``evrp_boc_sizing_v200`` — Strategy 4 with VIX/200 (conservative)

Signals use daily SPY/VIX/VIX3M closes (paper: 3:45 PM ET + MOC). Rebalance when
target weight drifts > ``rebalance_threshold``; ``tcost_bps`` per traded notional.

Example::

    cd /Users/robzingale/trading_bot && PYTHONUNBUFFERED=1 \
      .venv/bin/python RenTech/strategy_stack/run_volatility_edge_etn.py \
      --variant evrp_boc --start 2016-01-04 --end 2026-04-02 --capital 100000

    # Strategy 3 vs 4 (VIX/200) comparison table
    cd /Users/robzingale/trading_bot && PYTHONUNBUFFERED=1 \
      .venv/bin/python RenTech/strategy_stack/run_volatility_edge_etn.py --compare-s3-s4
    )annotationsN)	dataclass)Path)Literal   )
DataLoader)_load_vix3m_series)load_spy_vix_from_yfinance)evrpevrp_bocevrp_boc_sizingevrp_boc_sizing_v200passiveRenTechdatalogsvolatility_edge_etn)r   r   T)frozenc                  ~    e Zd ZU dZded<   dZded<   dZded	<   d
Zded<   dZded<   dZ	ded<   dZ
ded<   dZded<   y)VolEdgeConfigr   Variantvariant
   intrv_lookback{Gz?floatrebalance_threshold      @	tcost_bpsSVXYstrshort_tickerVIXYlong_tickerSVIXshort_stitch_tickerz
2022-03-30stitch_dateN)__name__
__module____qualname__r   __annotations__r   r   r    r#   r%   r'   r(        J/opt/rentech/trading_bot/RenTech/strategy_stack/run_volatility_edge_etn.pyr   r   ;   sT    !GW!K!%%IuL#K%%#K#r.   r   c                X   t               }|j                         t        j                  d      z
  j	                  d      }|j                         t        j                  d      z   j	                  d      }|j                  | ||      }|j                  rt        d|        |d   j                  t              }t        j                  |j                        j                  d       |_        |j                  |      j                         j!                         j#                  d      S )	N   days%Y-%m-%d   )startendzNo daily data for close        )r   minpd	Timedeltastrftimemaxfetch_dailyemptyRuntimeErrorastyper   to_datetimeindextz_localizereindexffill
pct_changefillna)tickerrD   loaderr6   r7   dfr8   s          r/   _daily_returnsrM   G   s    \FYY[2<<R00:::FE99;1--
7
7

CC			F%S		9B	xx/x899wKu%E..-99$?EK==%%'224;;C@@r.   c                   t        ||       }|| j                         k  r|j                  d      S t        ||       }|j                         }|j                  | |k\     |j                  | |k\  <   |j                  d      S )z4SVXY pre-SVIX inception, SVIX after (short-vol leg).ret_short_vol)rM   r:   renamecopyloc)rD   primarystitch	stitch_onr_prir_stouts          r/   _stitched_short_returnsrY   S   st     7E*EEIIK||O,,&%(D
**,C"&((5I+=">CGGEY::o&&r.   c                .   ||k  rt        d      S | j                  ||z
  dz   |dz    }|j                         j                         }t	        |      |dz
  k  rt        d      S t        |j                  d      t        j                  d      z  dz        S )Nnan   ddof     o@      Y@)r   ilocrH   dropnalenstdmathsqrt)	spy_closeilookbackwindowretss        r/   _erv30rl   d   s    8|U|^^AL1,q1u5F%%'D
4y8a<U|q!DIIe$44u<==r.   c                   t        j                  |      r*t        j                  |      rt        j                  |      sy||k  }||kD  }| dk(  ry| dk(  r	|dkD  rdS dS d}| dk(  rd}| d	k(  r|dkD  r|ry|dk  r|ry
|dk  r|ryyt        dt        d||z              }|dkD  r|r|dfS |dk  r	|rd|z  dfS |dk  r|rd|fS y)zJReturn (weight_short_vol, weight_long_vol) as fractions of sleeve capital.)r9   r9   r   )皙?r9   r   r   r`   r   g      i@r   )皙?r9   )r9   rn   r9         ?g      ?)re   isfiniter>   r:   )r   r   vixvix3mcontangobackwardation
sizing_divvix_fracs           r/   target_weightsrx   n   s     MM$DMM#$64==;OU{H%KM)&"Qh{6J6J((
*!81919 3Cz!123HaxH}qyXX~s""qy]H}r.   c                z   t        |       }d}	d}
g }t        |      D ]  }| |   }t        |j                  |         t	        |||j
                        z
  }t        |j                  |t        |j                  |         t        |j                  |               \  }}t        |j                  |         }t        |j                  |         }|	|z  |
|z  z   }d}d}t        |	|z
        |j                  kD  st        |
|z
        |j                  kD  r9t        ||	z
        t        ||
z
        z   }||j                  dz  |z  z  }||}
}	d}n?|	d|z   z  |
d|z   z  z   t        dd|	z
  |
z
        z   }|dkD  r|	d|z   z  |z  }	|
d|z   z  |z  }
|j                  |j                  d      ||t        |j                  |         t        |j                  |         |||	|
||d	        t        j                  |      }t        j                   |d
         |d
<   |d   j#                  t              }t        |      }||z  }|d|z   j%                         z  }||d<   ||d<   ||d   |d   z   z  dz  |d<   t'        |||      }|j)                  |j                  d|j                  |j                  |j*                   d|j,                   d|j.                   |j0                  t3        |d   j5                               t7        d|d   dkD  j9                         z  d      t7        d|d   dkD  j9                         z  d      t        t        j                  ||j;                  |       j=                         j?                  d      d      jA                         jC                         j                  d         d
       ||fS )Nr9   )r   r   rr   rs   Fg     @Trp   -q=r4   )date	daily_retr   rr   rs   target_w_shorttarget_w_longw_shortw_long
rebalancedturnoverr{   r|   daily_pnl_usd
equity_usdr   r   333333?
margin_usdz Zarattini-Mele-Aziz SSRN 5316487z -> z from r   r`   gMbP?r\   )vspy)r   r\   )
r   paperr   r    short_vol_proxylong_vol_proxyn_rebalancespct_days_shortpct_days_longcorr_spy)"rc   ranger   ra   rl   r   rx   r   absr   r    r>   appendr=   r;   	DataFramerC   rB   cumprod_metricsupdater#   r'   r(   r%   r   sumroundmeanrF   rH   rI   rb   corr)idxrg   rr   rs   	ret_shortret_longcapitalcfgnr   r   rowsrh   dtr   t_shortt_longr_sr_lport_retr   r   grossdailyrcappnleqmetas                                r/   run_volatility_edge_backtestr      s    	CAGFD1X -
VSXXa[!F9a$II(KKchhqk"

1&	
 INN1%&HMM!$%S=6C</
'!"S%<%<<6F?#c&=&==7W,-FVO0DDH1X==H%vVGJ sSy)FcCi,@@3sCRYM\bLbCccEu}!S3Y/%739-5J/%SXXa[)uzz!}-")!'" ($	
?-
^ LLENN5=1E&Mk!!%(A
.C
c'C	a  "	"B E/E,i 05? BCdJE,BQDKK{{7#&#:#:"%"2"2!348O8O7PPVWZWfWfVgh!ool 3 7 7 9:#EU9-=-E,K,K,M$MqQ"5E(Oe,C+I+I+K#KQO1Y->->s-C-N-N-P-W-WX[-\]^d	
& $;r.   c           
     `   t        |      }|dz  }t        | j                  d         }||z  dz
  }|dkD  r||z  d|z  z  dz
  n
t        d      }|dkD  rt        |j                  d            n
t        d      }|dkD  r2t        |j	                         |z  t        j                  d      z        nd	}	t        | | j                         z  dz
  j                               }
|||d
z  |d
z  |	|
d
z  t        j                  |      r|t        j                  d      z  d
z  |dS t        d      |dS )Nr_   rp   r   r[   r\   r]   rz   r9   r`   )capital_usdending_equity_usdtotal_return_pctcagr_pctsharpemax_drawdown_pctvol_ann_pct
n_sessions)
rc   r   ra   rd   r   re   rf   cummaxr:   rq   )r   r   r   r   yearsr7   totcagrsdr   dds              r/   r   r      s(   AAIE

C
)c/C16C#I3;'#-eD!"Qquu!u}	E%LB8:U
U1668b=499U#334F	RYY[ 3&++-	.B %K5LJ8<b8IrDIIe,,u4	 	 PUUZ|	 	r.   c                   t        j                  |       t        j                  d      z
  j                  d      }t        j                  |      t        j                  d      z   j                  d      }t	        ||      }t        j
                  |j                        j                  d       |_        |j                  |j                  t        j                  |       k\  |j                  t        j                  |      k  z     }t        |      dk  rt        dt        |       d|  d|       t        |      }t        ||j                  |j                  t        j                  |j                        	      }t        |j                   |      }	t        j"                  |d
   j%                  |      j'                  t(              |d   j%                  |      j'                  t(              |j%                  |      j'                  t(              ||	d|      }
|
j+                  g d      }
t        j,                  |
j                        |
fS )Ni  r2   r4      d   zToo few sessions (z) for     → )rS   rT   rU   r8   	vix_close)rg   rr   rs   rO   ret_long_volrD   )rg   rr   rs   )subset)r;   	Timestampr<   r=   r
   rC   rD   rE   rc   
SystemExitr	   rY   r#   r'   r(   rM   r%   r   rF   rB   r   rb   DatetimeIndex)r6   r7   r   yf_startyf_endspy_vixr   rs   r   r   panels              r/   load_signal_panelr     s   U#bll&<<FFzRHll3",,B"77AA*MF(6:GNN7==1==dCGM
--	",,u-	-'--2<<PSCT2TUC 3x#~-c#hZveWE#OPPs#E'  &&,,s/	I coos3HLL )11#6==eD;'//4;;EB]]3'..u5&$	
 	E LL =L>EEKK(%//r.   c                   t        | ||      \  }}t        ||d   |d   |d   |d   |d   ||      \  }}t        |d   j                               |d<   t        |d	   j                               |d
<   |j	                         j                         }	|	j                  r|	j                  d      }	|	j                  j                  dd       t        |	 d      }
t        |	 d      }|j                  |
d       |j                  t        j                  |d      dz   d       t        d|j                    d|d   dd|d   dd|d   dd |d!   d"d#|d$   dd%       t        d&|
 d%       |S )'Nrg   rr   rs   rO   r   )r   rg   rr   rs   r   r   r   r   r   r6   r   r7    T)parentsexist_ok
_daily.csvz
_meta.jsonFr   r   indent
utf-8encoding  z	: return r   +.1fz%  CAGR r   
%  Sharpe r   .2f  maxDD r   .1fu   %  ρ(SPY) r   flushu       → )r   r   r"   r{   
expanduserresolvesuffixwith_suffixparentmkdirr   to_csv
write_textjsondumpsprintr   )r6   r7   r   r   
out_prefixr   r   r   r   prefix
daily_path	meta_paths               r/   run_and_writer   1  s    #5#s3JC.$%LGn(~&	KE4 A&DMc"glln%DK""$,,.F}}##B'
MMt4
+,Jxz*+I	LL5L)D3d:WM	
S[[M4(:#;D"A BZ &jh0D E()#.k$z:J39O	Q 	 
HZL
!.Kr.   c                |   t        d|  d| dd       g }t        D ]E  }t        |      }t        j                  d| z  }t        | ||||      }|j                  |       G t        d	z  }|j                         rzt        d
d       t        j                  |dg      j                  d      j                         }	|	d   j                  t              j                         j!                  d      }
t        D ]  }t        j                  t        d| dz  dg      j                  d      }|d   j                  t              }dD ]  }d|z
  }||
j#                  |
j$                  j'                  |j$                              j!                  d      z  ||j#                  |
j$                  j'                  |j$                              j!                  d      z  z   }|d|z   j)                         z  }|j                         j!                  d      }|j+                         dkD  rBt        |j-                         |j+                  d      z  t/        j0                  d      z        nd}t        ||j3                         z  dz
  j5                               }t        |j6                  d   |z  dz
        dz  }t        d| d|dd|dd|dd |d!z  d"d#d         |j                  d$d%i       t        d&z  }|j9                  t;        j<                  |d'(      d)z   d*+       t        d,| d       y )-Nu#   
=== Volatility Edge standalone · r   z ===Tr   )r   volatility_edge_etn_r6   r7   r   r   r   zstock_only_tactical70_plus_stock_only_plus_equity_dip_plus_sector_momentum_plus_tactical_aw_plus_tsmom_plus_fund_plus_nav_q_mtm_daily.csvz9
=== Stock-only + Vol Edge blends (static weight add) ===r{   )parse_datesequity_mtm_usdr9   r   r|   )ro   g      ?r   rp   r   r\   r]      r   r`   r   z @ z.0%z vol: return r   r   r   r   r   r   %notez4blend uses existing stock_only_tactical70 fund dailyz&volatility_edge_etn_compare_s3_s4.jsonr   r   r   r   r   z
Wrote )r   COMPARE_VARIANTSr   DEFAULT_OUT_PREFIXr   r   r   LOGSis_filer;   read_csv	set_index
sort_indexrB   r   rH   rI   rF   rD   unionr   rd   r   re   rf   r   r:   ra   r   r   r   )r6   r7   r   resultsr   r   rX   r   
stock_pathsdfsretvdfvretvwwblendr   r   shr   r   out_jsons                         r/   compare_s3_s4r  Z  s   	0uSE
FdSG# G, '',@	*JJ5c7X[\t	 	IJ JRVWkk*6(;EEfMXXZ#$++E2==?FFsK' 	G++-gYjAAPVxi  {#**51D) "HDLL)9)9$**)EFMMcRRUWZ^ZfZfJJ$$TZZ0[&+V  e4466MMO**3/IJSTU1668aeeem3diinDEZ]B,s2779:BGGBK'1C785@	RHM#d:bQTXU]^`ad^deh]iijk	& 	 VWX>>H

715<wO	HXJ
t,r.   c                    t        j                  t        j                  d      d         } | j	                  dd       | j	                  dd       | j	                  d	t
        d
       | j	                  ddg d       | j	                  dt
        d       | j	                  dt
        d       | j	                  dt        t               | j	                  ddd       | j	                  ddd       | j                         }|j                  rHt        t        |j                        t        |j                        t        |j                               y |j                  rg d}n|j                  g}|D ]  }t!        |t        |j"                        t        |j$                              }|j&                  }t)        |      dkD  s|dk7  r2|j&                  j*                  |j&                  j,                   d| z  }t/        t        |j                        t        |j                        t        |j                        ||         y )!Nz

r   )descriptionz--startz
2016-01-04)defaultz--endz
2026-06-18z	--capitalg     j@)typer  z	--variantr   )r   r   r   r   r   )r  choicesz--rebalance-thresholdr   z--tcost-bpsr   z--out-prefixz--compare-s3-s4
store_truez@Run Strategy 3 vs Strategy 4 (VIX/200) and write comparison JSON)actionhelpz--all-variantsz9Run evrp, evrp_boc, evrp_boc_sizing, evrp_boc_sizing_v200)r6   r7   r   )r   r   r   r   )r   r   r    r\   _r   )argparseArgumentParser__doc__splitadd_argumentr   r   r   
parse_argsr  r"   r6   r7   r   all_variantsr   r   r   r    r   rc   r   namer   )apargsvariantsr   r   r   s         r/   mainr#    s   		 	 W]]6-B1-E	FBOOI|O4OOG\O2OOKeYO?OO
  
 OO+%OFOOMsO;OON7IOJOOO  
 OOH  
 ==?DC

OTXXdllH[\ RLL> 
 %d&>&> ?DNN+

 x=1: 5__++1E1E0Fay.QQFdjj/DHH$,,'	

r.   __main__)rJ   r"   rD   pd.DatetimeIndexreturn	pd.Series)
rD   r%  rS   r"   rT   r"   rU   zpd.Timestampr&  r'  )rg   r'  rh   r   ri   r   r&  r   )
r   r   r   r   rr   r   rs   r   r&  ztuple[float, float])r   r%  rg   r'  rr   r'  rs   r'  r   r'  r   r'  r   r   r   r   r&  ztuple[pd.DataFrame, dict])r   r'  r   r   r   r'  r&  dict)r6   r"   r7   r"   r   r   r&  z%tuple[pd.DatetimeIndex, pd.DataFrame])r6   r"   r7   r"   r   r   r   r   r   r   r&  r(  )r6   r"   r7   r"   r   r   r&  None)r&  r)  ).r  
__future__r   r  r   re   sysdataclassesr   pathlibr   typingr   numpynppandasr;   __file__r   r   _REPOr"   pathinsert"RenTech.strategy_stack.data_loaderr   6RenTech.strategy_stack.spx_regime_state_space.featuresr	   %RenTech.strategy_stack.vrp_backtesterr
   r   r   r   r   r   rM   rY   rl   rx   r   r   r   r   r  r#  r)   r-   r.   r/   <module>r9     s  . #    
 !    X ((+u:SXXHHOOAs5z" 9 U L
 y6!F*11 7  $$ $ $	A'' ' 	'
 ' '">)) ) 
	)
 ) )X]	] ] 
	]
 ] ] ] ] 
] ]@*0D&& 
& 	&
 
& & 
&R)-X8
v zF r.   