quant_test / factor_engine /neutralization.py
lucky-loster's picture
Upload folder using huggingface_hub
590a501 verified
Raw
History Blame Contribute Delete
1.45 kB
"""Factor neutralization (industry / market cap) via cross-sectional regression."""
from __future__ import annotations
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
def neutralize_factor(
factor: pd.Series,
exposures: pd.DataFrame,
date_level: str = "datetime",
) -> pd.Series:
"""
Neutralize factor against exposure columns (e.g. industry dummies, log market cap).
Expects MultiIndex (instrument, datetime) or a panel with date column.
"""
if isinstance(factor.index, pd.MultiIndex):
df = factor.to_frame("factor").join(exposures, how="left")
neutralized = []
for dt, group in df.groupby(level=date_level):
y = group["factor"].values
x = group[exposures.columns].fillna(0).values
if len(y) < x.shape[1] + 2:
neutralized.append(group["factor"])
continue
reg = LinearRegression().fit(x, y)
resid = y - reg.predict(x)
neutralized.append(pd.Series(resid, index=group.index))
return pd.concat(neutralized).sort_index()
raise NotImplementedError("neutralize_factor currently supports MultiIndex panels only")
def zscore_by_date(factor: pd.Series, date_level: str = "datetime") -> pd.Series:
def _z(x):
return (x - x.mean()) / (x.std() + 1e-8)
return factor.groupby(level=date_level, group_keys=False).apply(_z)