import pandas as pd import numpy as np from typing import Dict, Any, Optional from sklearn.linear_model import Ridge, LogisticRegression class RawMomentumBaseline: """Baseline 1: Standard 20-day return cross-sectional ranking.""" def __init__(self, lookback_col: str = "mom_20d"): self.lookback_col = lookback_col def fit(self, df: pd.DataFrame, target_col: str): pass def predict(self, df: pd.DataFrame) -> pd.Series: if self.lookback_col in df.columns: return df[self.lookback_col].fillna(0.0) return df["adjusted_close"].pct_change(20).fillna(0.0) class VolAdjMomentumBaseline: """Baseline 2: Volatility-Adjusted Cross-Sectional Momentum (Return_20d / Vol_20d).""" def __init__(self, feature_col: str = "vol_adj_mom_20d"): self.feature_col = feature_col def fit(self, df: pd.DataFrame, target_col: str): pass def predict(self, df: pd.DataFrame) -> pd.Series: if self.feature_col in df.columns: return df[self.feature_col].fillna(0.0) return df["adjusted_close"].pct_change(20) / (df["adjusted_close"].pct_change(1).std() * np.sqrt(252) + 1e-6) class LinearRidgeModel: """Linear Model 1: Ridge Regression with L2 Regularization.""" def __init__(self, alpha: float = 1.0): self.alpha = alpha self.model = Ridge(alpha=alpha) def fit(self, df: pd.DataFrame, feature_cols: list, target_col: str): clean_df = df[feature_cols + [target_col]].dropna() if len(clean_df) > 10: self.model.fit(clean_df[feature_cols], clean_df[target_col]) def predict(self, df: pd.DataFrame, feature_cols: list) -> pd.Series: X = df[feature_cols].fillna(0.0) return pd.Series(self.model.predict(X), index=df.index) class LogisticClassificationModel: """Linear Model 2: L2 Regularized Logistic Regression for Top Quantile Classification.""" def __init__(self, C: float = 1.0): self.C = C self.model = LogisticRegression(C=C, max_iter=500) def fit(self, df: pd.DataFrame, feature_cols: list, target_col: str): clean_df = df[feature_cols + [target_col]].dropna() if len(clean_df) > 10: self.model.fit(clean_df[feature_cols], clean_df[target_col]) def predict(self, df: pd.DataFrame, feature_cols: list) -> pd.Series: X = df[feature_cols].fillna(0.0) probs = self.model.predict_proba(X)[:, 1] return pd.Series(probs, index=df.index)