A股量化选股因子模型实战:从基础构建到过拟合避免(2024最佳实践)

1次阅读
没有评论

共计 2330 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

一、为什么你的因子模型总在实盘失效?

最近和几个做量化的朋友聊天,发现大家普遍遇到这样的问题:回测时年化收益动辄 30%+ 的因子组合,实盘跑起来连指数都跑不赢。这其实就是典型的过拟合现象——我们的模型在历史数据上表现太好,到了真实市场就原形毕露。

A 股市场的特殊挑战

  • 政策市特征明显:比如 2023 年的中特估行情,传统估值因子集体失效
  • 波动率显著高于成熟市场:创业板指单日±3% 的波动已成常态
  • 市场结构快速变化:注册制实施后小市值因子有效性明显下降

A 股量化选股因子模型实战:从基础构建到过拟合避免(2024 最佳实践)
(示意图:样本内完美曲线 vs 样本外的灾难性表现)

二、从零搭建稳健因子库

基础因子代码实现(Python 示例)

# 使用聚宽 API 获取基础数据
import jqdatasdk
jqdatasdk.auth('你的账号', '你的密码')

def get_market_cap(stocks, date):
    """市值因子(对数化处理)"""
    q = query(
        valuation.code,
        valuation.market_cap
    ).filter(valuation.code.in_(stocks)
    )
    df = get_fundamentals(q, date=date)
    df['log_mcap'] = np.log(df['market_cap'])
    return df.set_index('code')['log_mcap']

def momentum_factor(stocks, end_date, lookback=21):
    """20 日动量因子(避免使用未来数据)"""
    start_date = end_date - pd.Timedelta(days=lookback+5)
    prices = get_price(stocks, start_date, end_date, '1d', ['close'], skip_paused=True)
    returns = prices['close'].iloc[-20:].pct_change().mean()
    return returns.dropna()

必备的数据预处理

  1. 极值处理:A 股常有涨跌停导致的异常值
def winsorize(series, sigma=3):
    """3sigma 去极值"""
    mean, std = series.mean(), series.std()
    return series.clip(mean - sigma*std, mean + sigma*std)
  1. 标准化:使不同量纲因子可比
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
factors_scaled = scaler.fit_transform(factors_df)

三、过拟合防御实战技巧

正则化实战:LASSO 回归

from sklearn.linear_model import LassoCV

# 5 折交叉验证自动选择 alpha
lasso = LassoCV(cv=5, alphas=np.logspace(-3, 1, 50))
lasso.fit(X_train, y_train)

# 查看因子权重
pd.Series(lasso.coef_, index=X_train.columns)

时间序列交叉验证

from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)

for train_idx, test_idx in tscv.split(X):
    X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
    y_train, y_test = y.iloc[train_idx], y.iloc[test_idx]
    # 训练和评估代码...

四、2024 年 A 股特有陷阱

北向资金因子构建要点

  • 使用 持仓变化比例 而非绝对金额
  • 注意沪深股通名单的月度调整
  • 避免与市值因子高度相关
def north_money_factor(stocks, date):
    """北向资金净流入占比因子"""
    q = query(
        valuation.code,
        valuation.market_cap,
        north_money.net_pct_main
    ).filter(valuation.code.in_(stocks)
    )
    df = get_fundamentals(q, date=date)
    return df.set_index('code')['net_pct_main']

注册制下的特殊处理

  • 次新股因子需要特殊处理(上市满 60 天再纳入)
  • 涨跌幅限制差异(科创板 / 创业板 20%)

五、验证体系搭建

Walk-Forward 回测框架

  1. 按季度滚动训练模型
  2. 使用未来一个季度数据测试
  3. 累计所有样本外结果

关键评价指标

  • IC(信息系数):因子与下期收益的相关系数,>0.03 算有效
  • IR(信息比率):IC 均值 /IC 标准差,>1.5 说明稳定性好
def calculate_ic(factor, next_ret):
    """计算 Rank IC"""
    return factor.rank(pct=True).corr(next_ret.rank(pct=True))

附:因子研究 Checklist

  • [] 所有因子避免使用未来函数
  • [] 完成 3sigma 去极值处理
  • [] 测试过不同市场环境(牛市 / 熊市 / 震荡市)
  • [] 样本外测试周期≥3 年
  • [] IC 值在不同时间段保持稳定
  • [] 因子间相关性 <0.7

最后分享一个血泪教训:去年我有个动量因子在 2019-2021 年回测表现极好,但实盘后发现它只在流动性宽松期有效。现在我的标准流程是必须单独测试 2015 股灾、2018 贸易战等极端行情下的表现。量化没有圣杯,与诸君共勉!

正文完
 0
评论(没有评论)