@@ -47,10 +47,19 @@ def build_semiconductor_rotation_indicators_from_history(
4747 soxl_history : Iterable [float ] | pd .Series ,
4848 soxx_history : Iterable [float ] | pd .Series ,
4949 trend_ma_window : int = 140 ,
50+ dynamic_rsi_quantile_window : int = 252 ,
51+ dynamic_rsi_quantile : float = 0.90 ,
52+ dynamic_rsi_floor : float = 70.0 ,
5053) -> dict [str , dict [str , float ]]:
5154 window = int (trend_ma_window )
5255 if window <= 0 :
5356 raise ValueError ("trend_ma_window must be positive" )
57+ rsi_quantile_window = int (dynamic_rsi_quantile_window )
58+ if rsi_quantile_window <= 0 :
59+ raise ValueError ("dynamic_rsi_quantile_window must be positive" )
60+ rsi_quantile = float (dynamic_rsi_quantile )
61+ if not 0.0 < rsi_quantile < 1.0 :
62+ raise ValueError ("dynamic_rsi_quantile must be between 0 and 1" )
5463
5564 soxl_close = _normalize_numeric_history (soxl_history , label = "SOXL" )
5665 soxx_close = _normalize_numeric_history (soxx_history , label = "SOXX" )
@@ -61,7 +70,26 @@ def build_semiconductor_rotation_indicators_from_history(
6170 soxx_ma_trend = float (soxx_close .rolling (window ).mean ().iloc [- 1 ])
6271 soxx_ma20 = float (soxx_close .rolling (20 ).mean ().iloc [- 1 ])
6372 soxx_ma20_slope = float (soxx_close .rolling (20 ).mean ().diff ().iloc [- 1 ])
64- soxx_rsi14 = float (_compute_rsi (soxx_close , window = 14 ).iloc [- 1 ])
73+ soxx_rsi_history = _compute_rsi (soxx_close , window = 14 )
74+ soxx_rsi14 = float (soxx_rsi_history .iloc [- 1 ])
75+ rsi_threshold_history = (
76+ soxx_rsi_history .rolling (
77+ rsi_quantile_window ,
78+ min_periods = min (rsi_quantile_window , max (60 , min (rsi_quantile_window , 126 ) // 2 )),
79+ )
80+ .quantile (rsi_quantile )
81+ .shift (1 )
82+ )
83+ soxx_dynamic_rsi_threshold = float (
84+ max (
85+ float (dynamic_rsi_floor ),
86+ (
87+ rsi_threshold_history .iloc [- 1 ]
88+ if pd .notna (rsi_threshold_history .iloc [- 1 ])
89+ else float (dynamic_rsi_floor )
90+ ),
91+ )
92+ )
6593 soxx_bb_mid = float (soxx_close .rolling (20 ).mean ().iloc [- 1 ])
6694 soxx_bb_std = float (soxx_close .rolling (20 ).std (ddof = 0 ).iloc [- 1 ])
6795 return {
@@ -75,6 +103,7 @@ def build_semiconductor_rotation_indicators_from_history(
75103 "ma20" : soxx_ma20 ,
76104 "ma20_slope" : soxx_ma20_slope ,
77105 "rsi14" : soxx_rsi14 ,
106+ "rsi14_dynamic_threshold" : soxx_dynamic_rsi_threshold ,
78107 "bb_mid" : soxx_bb_mid ,
79108 "bb_upper" : soxx_bb_mid + 2.0 * soxx_bb_std ,
80109 "bb_lower" : soxx_bb_mid - 2.0 * soxx_bb_std ,
@@ -87,12 +116,18 @@ def build_semiconductor_rotation_inputs_from_history(
87116 soxl_history : Iterable [float ] | pd .Series ,
88117 soxx_history : Iterable [float ] | pd .Series ,
89118 trend_ma_window : int = 140 ,
119+ dynamic_rsi_quantile_window : int = 252 ,
120+ dynamic_rsi_quantile : float = 0.90 ,
121+ dynamic_rsi_floor : float = 70.0 ,
90122) -> dict [str , dict [str , dict [str , float ]]]:
91123 return {
92124 "derived_indicators" : build_semiconductor_rotation_indicators_from_history (
93125 soxl_history = soxl_history ,
94126 soxx_history = soxx_history ,
95127 trend_ma_window = trend_ma_window ,
128+ dynamic_rsi_quantile_window = dynamic_rsi_quantile_window ,
129+ dynamic_rsi_quantile = dynamic_rsi_quantile ,
130+ dynamic_rsi_floor = dynamic_rsi_floor ,
96131 )
97132 }
98133
0 commit comments