
    pjF                       U d Z ddlmZ ddlZddlZddlmZm	Z	m
Z
mZmZmZmZmZmZmZmZmZmZmZmZmZ drdZdd	 	 	 	 	 	 	 	 	 dsdZdtd	Zdud
ZdudZdudZdudZdudZdudZ dudZ!dudZ"dudZ#dudZ$dudZ%dudZ&dudZ'dudZ(dudZ)dudZ*dudZ+dudZ,dudZ-dudZ.dudZ/dudZ0dud Z1dud!Z2dvd"Z3dud#Z4dvd$Z5dud%Z6	 	 	 	 	 	 	 	 dwd&Z7dud'Z8dxd(Z9dxd)Z:dxd*Z;dud+Z<dud,Z=dud-Z>dud.Z?dud/Z@dud0ZAi d1ed2ed3ed4ed5ed6ed7ed8ed9e d:e!d;e"d<eAd=ed>ed?e$d@edAe#i dBe%dCe&dDe'dEedFe(dGedHe)dIe*dJe+dKe,dLe-dMe.dNe/dOe0dPe1dQedRei dSe3dTe2dUe8dVe4dWe5dXe6dYe7dZe?d[e9d\e:d]e;d^e<d_e>d`e=dae@dbdZBdceCdd<   dydeZDeDeBdb<   dfZEdgeCdh<   diZFdgeCdj<   eEeFdkZGdleCdm<   	 	 	 	 	 	 	 	 dzdnZH	 	 	 	 	 	 	 	 d{doZI	 	 	 	 	 	 d|dpZJ	 	 	 	 	 	 d|dqZKy)}z
Rule-based QuantifiedStrategies-style ETF sleeves for ranking / research.

Each function returns a daily return series aligned to ``spy.index`` (cash = 0).
    )annotationsN)_ibs_mom_12m_mr_state_machine_overnight_one_night_rsi_spy_close_to_closedual_momentum_spy_tltmr_ibs_sma200mr_rsi2_sma200overnight_3downovernight_5d_lowovernight_close_to_openrotation_spy_tlt_gldseasonality_opex_weekseasonality_turn_of_monthseasonality_turnaround_tuesdayc                8    t        |       j                  |d      S )N        )r	   where)spymasks     H/opt/rentech/trading_bot/RenTech/strategy_stack/qs_systematic_library.py_c2c_on_maskr       s    s#))$44    F)cash_if_all_negc          	     *   t        j                  | |       j                  j                  d      }t        j                  d| t              }|j                  |      D ]  \  }}|j                  d   }|D 	ci c]  }	|	t        ||	   j                  |           }
}	t        d |
j                         D              st        |j                               d   }n8|rt        |
j                               dk  rd}nt        |
|
j                        }|j                  D ]  }||j                  |<     t        j                  d|       }| D ]?  }|j                  |   }|dk7  st        ||   j                  |         |j                  |<   A |S c c}	w )	NindexMcash)r   dtyper   c              3  F   K   | ]  }t        j                  |        y wN)npisfinite).0vs     r   	<genexpr>z$_month_start_pick.<locals>.<genexpr>0   s     9a2;;q>9s   !)keyr   )pdSeriesdt	to_periodobjectgroupbyr   floatlocallvalueslistkeysmaxget)idxscoresretsr   monthchoice_datesd0kvalspickdoutcs                  r   _month_start_pickrG   $   s\    IIc%((2237EYYvS7FMM%( 
!5[[^5;<5r*++<<94;;=99&q)DT[[]!3q!8Dt*D 	!A FJJqM	!
! ))Cs
#C /JJqM;tAw{{1~.CGGAJ/ J =s   7#Fc                    t        j                  | |d      }t        j                  ||t         j                  j	                  d      z   d      }t        |      dk\  r|d   S |d   S )	N   )yearr<   dayr   zW-FRI)freq      )r+   	Timestamp
date_rangeoffsetsMonthEndlen)rJ   r<   rD   fridayss       r   _third_fridayrV   @   sX    
$e3AmmAq2::#6#6q#99HGW*71:;;r   c                    t        j                  | j                  | j                        j                  j	                  d      }||j                  d      k7  }t        | |      S )Nr   r    rI   r+   r,   r   r-   r.   shiftr   )r   _kwmfirsts       r   seasonality_first_day_monthr]   I   sI    
		#))399-00::3?AOEU##r   c                    t        j                  | j                  | j                        j                  j	                  d      }||j                  d      k7  }t        | |      S )Nr   r    rO   rX   )r   rZ   r[   lasts       r   seasonality_last_day_monthr`   O   sJ    
		#))399-00::3?ADT""r   c                   t               }| j                  j                  d      j                         D ]?  }|j	                  t        |j                  |j                        j                                A t        j                  | j                  D cg c]  }|j                         |v  c}| j                        }t        | |      S c c}w )Nr    r   )setr   r.   uniqueaddrV   rJ   r<   	normalizer+   r,   r   )r   rZ   daysperrD   r   s         r   seasonality_opex_fridayrh   U   s    !eDyy""3'..0 Asxx3==?@A99SYY?akkmt+?syyQDT"" @s   Cc                \    | j                   j                  }|dk\  |dk  z  }t        | |      S )u(   Long Nov–Apr (Hirsch best six months).      )r   r<   r   )r   rZ   r[   r   s       r   seasonality_sell_in_mayrl   ]   s.    		AGQDT""r   c                   | j                   }t        j                  d|      }t        t	        |j
                              D ]  }||j
                  |k(  |j                  dk(  z     }||j
                  |k(  |j                  dk(  z     }t        |      dk\  r|dd D ]  }d|j                  |<    t        |      d	k\  s}|dd	 D ]  }d|j                  |<     t        | |      S )
z,Last 5 trading days of Dec + first 2 of Jan.Fr      rI      NTrN   )
r   r+   r,   sortedrb   rJ   r<   rT   r2   r   )r   rZ   r9   r   ydecjanrD   s           r   seasonality_turn_of_yearru   d   s    
))C99U#&DCM" #388q=SYY"_56388q=SYY!^45s8q=X #"#s8q=!W #"## T""r   c                v   t        |       }t        j                  d| j                        }t	        dt        |             D ]d  }| j                  |   j                  dk(  s | j                  |dz
     j                  dk(  s@|j                  |dz
     dk  sVd|j                  |<   f |j                  |d      S )z'Long Monday when prior Friday was down.Fr   rI   r   rk   Tr   )	r	   r+   r,   r   rangerT   	dayofweekilocr   )r   rZ   c2csigis        r   seasonality_monday_reversalr}   t   s    
c
"C
))E
+C1c#h #99Q<!!Q&399QU+;+E+E+JxxA""# 99S#r   c                H    t        | | j                  j                  dk(        S )NrN   r   r   rx   r   rZ   s     r   seasonality_wednesdayr          SYY00A566r   c                H    t        | | j                  j                  dk(        S )Nrk   r   r   s     r   seasonality_fridayr      r   r   c                n    | d   | d   j                  dd      j                         k  }t        | |      S )Nclose
   min_periods)rollingminr   )r   rZ   r[   s      r   overnight_10d_lowr      s:    GG,,RR,@DDFFAQ''r   c                d    t        |       }|dk  |j                  d      dk  z  }t        | |      S )Nr   rI   )r	   rY   r   )r   rZ   rz   r[   s       r   overnight_2downr      s4    
c
"C	qSYYq\A%&AQ''r   c                6    t        |       }t        | |dk        S )Ng{Gz)r	   r   )r   rZ   rz   s      r   overnight_large_downr      s    
c
"CS5[11r   c                   | d   | d   j                  d      z  dz
  }t        j                  d| j                        }t	        dt        |             D ]  }| j                  |   j                  dk(  s | j                  |dz
     j                  dk(  s@t        j                  |j                  |         rt        |j                  |         nd|j                  |<    |S )	u   Fri close → Mon open.openr   rI         ?r   r   r   rk   )rY   r+   r,   r   rw   rT   rx   r%   r&   ry   r1   )r   rZ   ocrE   r|   s        r   overnight_weekendr      s    	Vs7|))!,	,s	2B
))Csyy
)C1c#h P99Q<!!Q&399QU+;+E+E+J/1{{2771:/F%
+CCHHQKP Jr   c                Z    | d   | d   j                  d      z  dz
  }t        | |dk        S )Nr   r   rI   r   g~jth)rY   r   r   rZ   gaps      r   overnight_gap_downr      s5    
f+G**1-
-
3CS6\22r   c                    t        | d   d      }| d   j                  dd      j                         }|dk  | d   |kD  z  }t        | ||dkD  d	      S )
Nr   rN      d   r      F   ro   max_holdr   r   meanr   )r   rZ   rsi2sma200entrys        r   mr_rsi2_sma200_looser      `    Ga D\!!#3!7<<>FBY3w<&01ES%Q??r   c                F    t        |       }|dk  }t        | ||dkD  d      S )N皙?g?rM   r   )r   r   )r   rZ   ibsr   s       r   mr_ibs_no_filterr      s)    
s)C#IES%sQ??r   c                &   | d   j                  dd      j                         }| d   | d   j                  dd      j                         k  }|| d   |kD  z  }| d   | d   j                  dd      j                         k\  }t	        | ||d      S )Nr   r   r   r   ro   r   )r   r   r   r7   r   )r   rZ   r   low5r   exit_sigs         r   mr_5day_low_sma200r      s    \!!#3!7<<>Fw<3w<//q/AEEGGDCL6)*E7|s7|33A13EIIKKHS%A>>r   c                    | d   j                  dd      j                         }t        |       }|dk  |j                  d      dk  z  | d   |kD  z  }t	        | ||dkD  d      S )	Nr   r   r   r   r   rI   rM   r   )r   r   r	   rY   r   )r   rZ   r   rz   r   s        r   mr_2day_low_sma200r      sl    \!!#3!7<<>F
c
"C1W1)*c'lV.CDES%q1==r   c                    t        | d   d      }| d   j                  dd      j                         }|dk  | d   |kD  z  }t        | ||dkD  d      S )	Nr   ro   r   r   r      2   r   r   )r   rZ   rsi5r   r   s        r   mr_rsi5_30_50r      r   r   c                x   | d   j                  dd      j                         }| d   j                  dd      j                         }d| d   |z
  z  ||z
  j                  dt        j
                        z  }| d   j                  dd      j                         }|d	k  | d   |kD  z  }t        | ||d
kD  d      S )Nlow   r   highr   r   r   r      P   ro   r   r   r   r7   replacer%   nanr   r   )r   rZ   lohirA   r   r   s          r   mr_stoch_sma200r      s    	U		BB		/	3	3	5B	V		RR		0	4	4	6Bs7|b !R"W$5$5a$@@A\!!#3!7<<>FVGv-.ES%R!<<r   c                x   | d   j                  dd      j                         }| d   j                  dd      j                         }d|| d   z
  z  ||z
  j                  dt        j
                        z  }| d   j                  dd	      j                         }|d
k  | d   |kD  z  }t        | ||dkD  d      S )Nr   r   r   r   ir   r   r   r   iiro   r   r   )r   rZ   r   r   wrr   r   s          r   mr_williams_r_sma200r      s    	U		BB		/	3	3	5B	V		RR		0	4	4	6B	c'l"	#rBw&7&7266&B	BB\!!#3!7<<>F#X#g,/0ES%cA>>r   c                    t        |       }|dkD  |j                  d      dkD  z  |j                  d      dkD  z  }| j                  |j                  d      j                  d      d      S )z5Fade 3 up days: short next day (negative SPY return).r   rI   rN   Fr   )r	   rY   r   fillna)r   rZ   rz   r{   s       r   mr_connors_3up_shortr      s_    
c
"C7syy|a'
(CIIaL1,<
=CD<<		!++E2C88r   c                F    t        |       }|dk  }t        | ||dkD  d      S )Ng{Gzr   rN   r   )r	   r   )r   rZ   rz   r   s       r   mr_large_drop_bouncer      s*    
c
"C%KES%q1==r   c                    | d   | d   z
  }||j                  dd      j                         k  }t        | |j                  d      j	                  d      ||j                  d      j                         kD  d      S )	Nr   r      r   rI   FrM   r   )r   r   r   rY   r   r   )r   rZ   rngnr7s       r   mr_nr7r      sp    
f+E

"C
QA.224
4CS#))A,"5"5e"<cCKKPQNDWDWDY>Ydeffr   c                @    t        | d         }|dkD  }t        | |      S )Nr   r   )r   r   )r   rZ   momr   s       r   momentum_12m_spy_cashr      s&    
3w<
 C7DT""r   c                   | j                   j                  |j                         }| j                  |df   |j                  |df   d}|j                         D ci c]%  \  }}||j	                         j                  d      ' }}}|j                         D ci c]  \  }}|t        |       }}}t        |||      S c c}}w c c}}w )Nr   )r   tltr   r   intersectionr2   items
pct_changer   r   rG   )	r   r   rZ   r9   panelsrA   r(   r;   momss	            r   rotation_spy_tltr      s    
))
 
 
+CWWS'\*3773<3HIF6<llnEdaAq||~$$S))EDE'-||~6tq!Ax{N6D6S$-- F6s   *CCc                n    | d   j                  dd      j                         }t        | | d   |kD        S )Nr   r   r   r   r   r   r   )r   rZ   smas      r   faber_200sma_spy_cashr     s:    
g,

s

4
9
9
;CS\C/00r   c                2   | j                   j                  |j                         }| j                  |df   j                  dd      j	                         }| j                  |df   j                         j                  d      }|j                  |df   j                         j                  d      }| j                  |df   |kD  }t        j                  d|      }|j                  |   |j                  |<   |j                  |    |j                  | <   |S )Nr   r   r   r   r   r   )	r   r   r2   r   r   r   r   r+   r,   )	r   r   rZ   r9   r   spy_rtlt_rlong_spyrE   s	            r   faber_200sma_spy_tltr   
  s    
))
 
 
+C
''#w,

'
'
'
=
B
B
DCGGCL!,,.55c:EGGCL!,,.55c:EwwsG|$s*H
))Cs
#C		(+CGGHH9-CGGXIJr   c                    | d   j                  dd      j                         }| d   j                  dd      j                         }t        | ||kD        S )Nr   r   (   r   r   r   r   )r   rZ   s50s200s       r   golden_cross_50_200r     sW    
g,

rr

2
7
7
9Cw<5::<DS4Z((r   c                   | j                   j                  |j                         j                  |j                         }| j                  |df   |j                  |df   |j                  |df   d}|j                         D ci c]%  \  }}||j	                         j                  d      ' }}}|j                         D ci c]  \  }}|t        |       }	}}t        ||	|      S c c}}w c c}}w )Nr   )r   xlpxlur   r   )
r   r   r   rZ   r9   r   rA   r(   r;   r   s
             r   rotation_defensive_xlp_xlur     s     ))
 
 
+
8
8
CCWWS'\*3773<3HQTQXQXY\^eYeQfgF6<llnEdaAq||~$$S))EDE'-||~6tq!Ax{N6D6S$-- F6s   *C+C1c                Z    | d   | d   j                  d      z  dz
  }t        | |dkD        S )Nr   ~   r   r   )rY   r   )r   rZ   r   s      r   momentum_6m_spy_cashr   &  s5    
g,W++C0
03
6CS1W%%r   c                    |d   j                  | j                        j                         }|j                         }|dkD  }t	        | |t        j                  d| j                        d      S )z5After VIX jumps >15% in a day, long SPY next session.r   g333333?Fr   rN   r   )reindexr   ffillr   r   r+   r,   )r   vixrZ   vcvchgr   s         r   vol_vix_spike_fader   .  sX    	W		cii	(	.	.	0B==?D4KES%5		)JUVWWr   c                x    |d   j                  | j                        j                         }t        | |dk        S )Nr      r   r   r   r   r   r   rZ   r   s       r   vol_vix_high_cashr   6  4    	W		cii	(	.	.	0BR"W%%r   c                x    |d   j                  | j                        j                         }t        | |dk        S )Nr   r   r   r   s       r   vol_vix_low_risk_onr   ;  r   r   c                j   | d   }|j                  dd      j                         }|j                  dd      j                         }d|z  |z  }||j                  dd      j                  d      k  }||d|z  z   kD  }|j	                  d      j                  d	      |z  }t        | |||k  d
      S )Nr   r   r   rN   r   <   r   rI   Fr   r   )r   r   stdquantilerY   r   r   )	r   rZ   rF   midr  widthsqueezebreakoutr   s	            r   vol_bollinger_squeezer  @  s    GA
))BB)
'
,
,
.C
))BB)
'
+
+
-CWOEemmCRm8AA#FFG3S= HMM!##E*X5ES%S2>>r   c                4   | d   | d   j                  d      k  | d   | d   j                  d      kD  z  }| d   | d   j                  d      kD  }|j                  d      j                  d      |z  }t        | || d   | d   j                  d      k  d      S )Nr   rI   r   r   Fro   r   )rY   r   r   )r   rZ   insidebrkr   s        r   pa_inside_day_breakoutr  N  s    &kCK--a00SZ#e*BRBRSTBU5UVF
g,V**1-
-CLLO""5)C/ES%WE
8H8H8K)KVWXXr   c                z    | d   | d   j                  d      z  dz
  }t        |        j                  |dkD  d      S )Nr   r   rI   r   g{Gzt?r   )rY   r	   r   r   s      r   pa_gap_up_fader  U  sC    
f+G**1-
-
3C %%,,S5[#>>r   c                t    | d   j                  dd      j                         }t        | | d   |dz  k\        S )Nr      r   r   g\(\?)r   r7   r   )r   rZ   r   s      r   pa_52w_high_momentumr  Z  s>    	W		cs		3	7	7	9BS\R$Y677r   c                Z    t        |       }t        |       }t        |       }||z   |z   dz  S )Ng      @)r   r   r   )r   rZ   abrF   s        r   combo_turn_tue_3down_ibsr  b  s3    &s+AAcAEAIr   c                    t        |       }t        |       }t        |       }|dk7  |dk7  z  |dk7  z  }t        |       }|j	                  |d      S )Nr   r   )r   r   r}   r	   r   )r   rZ   r  r  rF   activerz   s          r   combo_seasonality_stackr  i  sV    &s+A!#&A#C(A1fa AF+F
c
"C99VS!!r   S01_turnaround_tuesdayS02_turn_of_monthS03_first_day_monthS04_last_day_monthS05_opex_weekS06_opex_fridayS07_sell_in_mayS08_turn_of_yearS09_monday_reversalS10_wednesday
S11_fridayS12_seasonality_comboS13_overnight_close_openS14_overnight_3downS15_overnight_2downS16_overnight_5d_lowS17_overnight_10d_lowS18_overnight_large_downS19_overnight_weekendS20_overnight_gap_downS21_mr_rsi2_sma200S22_mr_rsi2_looseS23_mr_ibs_sma200S24_mr_ibs_nofilterS25_mr_5d_low_sma200S26_mr_2d_down_sma200S27_mr_rsi5_30_50S28_mr_stoch_sma200S29_mr_williams_rS30_mr_connors_3up_fadeS31_mr_large_drop
S32_mr_nr7S33_dual_momentum_spy_tltS34_rotation_spy_tlt_gldS35_rotation_spy_tltS36_momentum_12m_cashS37_momentum_6m_cashS38_faber_200sma_cashS39_faber_200sma_tltS40_golden_cross_50_200S41_rotation_xlp_xlu_spyS42_52w_high_momentumS43_vix_spike_fadeS44_vix_high_cashS45_vix_low_risk_onS46_bollinger_squeezeS47_gap_up_fadeS48_inside_day_breakoutS49_combo_tue_3down_ibsS50_qqq_rsi2_sma200zdict[str, object]SYSTEMATIC_STRATEGIESc                   t        |d   j                  | j                        j                         d      }|d   j                  | j                        j                         j	                  dd      j                         }|d   j                  | j                        j                         j                         j                  d      }|dk  |d   j                  | j                        j                         |kD  z  }t        j                  t        |       t              }d	}t        t        |             D ]o  }	|	r||	d
z
     nd}
|
r6|d
z  }t        |j                  |	d
z
     dkD        s|dkD  rd||	<   d	}Ad||	<   G|	d	kD  sMt        |j                  |	d
z
           sid||	<   d
}q |j                  t        j                   || j                        d      S )Nr   rN   r   r   r   r   r   )r"   r   rI   Fr   ro   Tr   )r   r   r   r   r   r   r   r   r%   zerosrT   boolrw   ry   r   r+   r,   )r   qqqrZ   r   r   qqq_rr   posholdr|   prevs              r   qqq_rsi2_sma200rT    s   G$$SYY/557;D\!!#)),224<<Sc<RWWYFL  +113>>@GGLEBY3w<//		:@@BVKLE
((3s84
(CD3s8_ s1q5zEAIDDIIa!e$r)*dQhAAUtEJJq1u-.CFD ;;ryyCII6<<r   )r  r&  r  r)  tuple[str, ...]QS_ACTIONABLE_4)r&  rI  r  r)  r-  r/  r  QS_ACTIONABLE_7)zactionable-4zactionable-7zdict[str, tuple[str, ...]]QS_ACTIONABLE_PRESETSc                    ddl }t        |    }|t        |       |j                  |      }i }dD ]  }||j                  v s||   ||<     ||d   fi |}|j                  |      j                  d      S )z8Run one registry sleeve; returns daily returns on *idx*.r   N)r   gldr   r   r   rO  r   r   )inspectrK  KeyError	signature
parametersr   r   )	sidr   r9   r[  fnr{   kwargsnamers	            r   run_systematic_strategyrd    s     	s	#B	zsm


B
CF: (3>>!!$<F4L( 	6%=#F#A99S>  %%r   c                    |D cg c]  }t        || |       }}t        j                  |d      j                  d      S c c}w )NrI   )axis)rd  r+   concatr   )r   r9   membersr_  partss        r   actionable_daily_returnrj    sH    
 CJJ3$S&#6JEJ99U#((a(00 Ks   Ac                $    t        | |t              S r$   )rj  rV  r   r9   s     r   actionable_4_daily_returnrm         #63@@r   c                $    t        | |t              S r$   )rj  rW  rl  s     r   actionable_7_daily_returnrp    rn  r   )r   pd.DataFramer   	pd.Seriesreturnrr  )
r9   pd.DatetimeIndexr:   dict[str, pd.Series]r;   ru  r   rN  rs  rr  )rJ   intr<   rv  rs  zpd.Timestamp)r   rq  rs  rr  )r   rq  r   rq  rs  rr  )r   rq  r   rq  r   rq  rs  rr  )r   rq  r   rq  rs  rr  )r   rq  rO  rq  rs  rr  )r_  strr   dict[str, pd.DataFrame]r9   rt  rs  rr  )r   rx  r9   rt  rh  rU  rs  rr  )r   rx  r9   rt  rs  rr  )L__doc__
__future__r   numpyr%   pandasr+   0RenTech.strategy_stack.run_qs_top_ideas_backtestr   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   rG   rV   r]   r`   rh   rl   ru   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  rK  __annotations__rT  rV  rW  rX  rd  rj  rm  rp   r   r   <module>r     s   #      (5 "	  
  8<$#### 77(
(2
3@@?>@=?9>g#.1
	).	.(./;..&X&
&
?Y?
8"9,<9, 29, 6	9,
 49, *9, .9, .9, 09, 69, *9, $9, 49,  79,  ?!9," ?#9,$ ,%9,& .'9,(  4)9,* .+9,, 0-9,0 .19,2 -39,4 59,6 +79,8 .99,: /;9,< =9,> ??9,@ -A9,B 3C9,D -E9,F &G9,J  !6K9,L  4M9,N ,O9,P 2Q9,R 0S9,T 2U9,V 0W9,X 2Y9,Z  :[9,\ 1]9,` ,a9,b *c9,d .e9,f 2g9,h ~i9,l 5m9,n 7o9,p 4q9, ( 9x=, 0? + ,$ $  $#5 1 &	&#& 
& 	&(1#1	1 1 	1A#A	A AA#A	A Ar   