@@ -175,49 +175,52 @@ def main() -> None:
175175 # ------------------------------------------------------------------
176176 _step ("Step 5 / 5 — Synthetic factor" )
177177
178- _info (f"Effective alphas: { effective_alphas } " )
179- #_info(f"Using ALL factors for OLS combination")
180- _info (f"Rolling window = { COMBINE_WINDOW } trading days | orthogonalize = True" )
181-
182- # Use cross-sectional percentile rank of forward_return as the OLS
183- # regression target. This removes the market-wide daily move (beta)
184- # from the label, so the model learns relative stock selection ability
185- # rather than fitting to the overall market direction.
186- target_flat = target_df .reset_index ()[["trade_date" , "ts_code" , "forward_return" ]]
187- target_cs_rank = target_flat .copy ()
188- target_cs_rank ["forward_return" ] = target_cs_rank .groupby ("trade_date" )[
189- "forward_return"
190- ].rank (pct = True )
191- _info (" OLS target: cross-sectional pct-rank of forward_return (per trade_date)" )
192-
193- synth_df = rolling_linear_combine (
194- factors_df [['trade_date' , 'ts_code' , * effective_alphas ]],
195- target_cs_rank ,
196- factor_cols = effective_alphas ,
197- window = COMBINE_WINDOW ,
198- orthogonalize = True ,
199- forward_days = FORWARD_DAYS ,
200- )
201- _ok (f"Synthetic factor : { synth_df .shape [0 ]:>7,} rows "
202- f"(dates: { synth_df ['trade_date' ].nunique ()} )" )
203-
204- ic_series = calc_ic (synth_df , target_df )
205-
206- metrics = calc_ic_metrics (ic_series )
207- _info (f" IC Mean : { metrics ['ic_mean' ]:>+.4f} " )
208- _info (f" IC Std : { metrics ['ic_std' ]:>.4f} " )
209- _info (f" ICIR : { metrics ['icir' ]:>+.4f} " )
210-
211- save_path = PLOTS_DIR / f"synthetic_factor_ic.png"
212- plot_ic (ic_series , factor_name = "synthetic_factor" , show = SHOW_PLOTS , save_path = save_path )
213- _info (f" IC chart saved." )
214-
215- bt_synth = LayeredBacktester (synth_df , target_df , forward_days = FORWARD_DAYS , plots_dir = PLOTS_DIR )
216- perf_synth = bt_synth .run_backtest ()
217- _info (" Backtest metrics (synthetic factor):" )
218- _p (perf_synth .to_string ())
219- bt_synth .plot (show = SHOW_PLOTS )
220- _info (" Synthetic backtest plot saved." )
178+ if len (effective_alphas ) == 0 :
179+ _info ("No effective alphas found. Rolling OLS skipped." )
180+ else :
181+ _info (f"Effective alphas: { effective_alphas } " )
182+ #_info(f"Using ALL factors for OLS combination")
183+ _info (f"Rolling window = { COMBINE_WINDOW } trading days | orthogonalize = True" )
184+
185+ # Use cross-sectional percentile rank of forward_return as the OLS
186+ # regression target. This removes the market-wide daily move (beta)
187+ # from the label, so the model learns relative stock selection ability
188+ # rather than fitting to the overall market direction.
189+ target_flat = target_df .reset_index ()[["trade_date" , "ts_code" , "forward_return" ]]
190+ target_cs_rank = target_flat .copy ()
191+ target_cs_rank ["forward_return" ] = target_cs_rank .groupby ("trade_date" )[
192+ "forward_return"
193+ ].rank (pct = True )
194+ _info (" OLS target: cross-sectional pct-rank of forward_return (per trade_date)" )
195+
196+ synth_df = rolling_linear_combine (
197+ factors_df [['trade_date' , 'ts_code' , * effective_alphas ]],
198+ target_cs_rank ,
199+ factor_cols = effective_alphas ,
200+ window = COMBINE_WINDOW ,
201+ orthogonalize = True ,
202+ forward_days = FORWARD_DAYS ,
203+ )
204+ _ok (f"Synthetic factor : { synth_df .shape [0 ]:>7,} rows "
205+ f"(dates: { synth_df ['trade_date' ].nunique ()} )" )
206+
207+ ic_series = calc_ic (synth_df , target_df )
208+
209+ metrics = calc_ic_metrics (ic_series )
210+ _info (f" IC Mean : { metrics ['ic_mean' ]:>+.4f} " )
211+ _info (f" IC Std : { metrics ['ic_std' ]:>.4f} " )
212+ _info (f" ICIR : { metrics ['icir' ]:>+.4f} " )
213+
214+ save_path = PLOTS_DIR / f"synthetic_factor_ic.png"
215+ plot_ic (ic_series , factor_name = "synthetic_factor" , show = SHOW_PLOTS , save_path = save_path )
216+ _info (f" IC chart saved." )
217+
218+ bt_synth = LayeredBacktester (synth_df , target_df , forward_days = FORWARD_DAYS , plots_dir = PLOTS_DIR )
219+ perf_synth = bt_synth .run_backtest ()
220+ _info (" Backtest metrics (synthetic factor):" )
221+ _p (perf_synth .to_string ())
222+ bt_synth .plot (show = SHOW_PLOTS )
223+ _info (" Synthetic backtest plot saved." )
221224
222225 _p (f"\n { '=' * 62 } " )
223226 _p (" Phase 2 factor analysis complete." )
0 commit comments