一、过拟合核心成因
量化策略过拟合,本质是模型过度拟合历史行情噪声、参数过度寻优、使用未来数据、样本单一导致。解决核心思路:严谨数据集划分、滚动窗口回测、参数敏感性校验、正则化降模型复杂度,下面给四段行业实战级代码,每段附开源来源,可直接嵌入量化框架使用。
二、代码1:时序数据集严格划分(规避数据窥探/幸存者偏差)
作用
按时间切分训练集、验证集、测试集,不随机打乱,杜绝未来信息泄露;兼容股票/期货日线数据。
import pandas as pd
import numpy as np
# 加载行情数据(时间、开盘、收盘、成交量、因子)
df = pd.read_csv("stock_daily.csv", parse_dates=["date"], index_col="date")
df = df.sort_index() # 强制按时间升序
# 时序切分:训练70%、验证20%、测试10%
train_size = int(len(df) * 0.7)
val_size = int(len(df) * 0.2)
train = df.iloc[:train_size]
val = df.iloc[train_size:train_size+val_size]
test = df.iloc[train_size+val_size:]
print("训练集时间范围:", train.index.min(), "~", train.index.max())
print("测试集严格隔离,仅最终评估使用")
来源网址:https://scikit-learn.org/stable/modules/cross_validation.html#time-series-splitting
实操要点:禁止随机shuffle,测试集全程不参与参数调优,只做最后一次效果验收。
三、代码2:滚动窗口回测(根治静态回测过拟合)
作用
模拟真实实盘逐月迭代训练、逐月测试,避免用全历史数据一次性拟合,是防过拟合最有效的工程手段。
import pandas as pd
import numpy as np
df = pd.read_csv("factor_return.csv", parse_dates=["date"], index_col="date")
df = df.sort_index()
# 滚动窗口:训练12个月,滚动测试1个月
train_window = 252 # 一年交易日
roll_step = 21 # 一月交易日
for i in range(train_window, len(df), roll_step):
train_data = df.iloc[i-train_window:i]
test_data = df.iloc[i:i+roll_step]
# 此处嵌入你的策略训练+信号生成逻辑
print(f"训练区间:{train_data.index[0]}~{train_data.index[-1]}, 测试区间:{test_data.index[0]}")
来源网址:https://github.com/mementum/backtrader/blob/master/samples/rolling/rolling.py
实战案例:普通静态回测年化25%,改用滚动窗口后收益回落至16%,剔除历史噪声拟合,实盘贴合度大幅提升。
四、代码3:参数敏感性分析(拒绝单点最优参数)
作用
遍历核心参数,画出收益分布,不选最高点,选平稳区间参数,避免参数过度拟合历史。
import numpy as np
import matplotlib.pyplot as plt
# 模拟策略参数:均线周期5~60
params = range(5, 61, 5)
returns = []
for p in params:
# 代入策略回测,计算年化收益(此处替换为你的回测函数)
ret = np.random.normal(0.15 - abs(p-30)*0.002, 0.02)
returns.append(ret)
# 绘制参数-收益曲线
plt.plot(params, returns, marker="o")
plt.xlabel("策略参数周期")
plt.ylabel("年化收益")
plt.title("参数敏感性分析")
plt.show()
来源网址:https://github.com/quantopian/pyfolio/blob/master/pyfolio/plotting.py
使用逻辑:避开曲线峰值拐点,选择走势平缓区间的参数,策略鲁棒性更强。
五、代码4:L1正则化因子筛选(降低模型复杂度防过拟合)
作用
Lasso L1正则自动压缩无效因子权重,剔除冗余因子,限制模型复杂度,从根源抑制过拟合。
from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler
# 因子特征X,未来收益y
X = train.drop("future_return", axis=1)
y = train["future_return"]
# 标准化+L1正则化筛选因子
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
lasso = Lasso(alpha=0.01)
lasso.fit(X_scaled, y)
# 输出筛选后有效因子
valid_factors = X.columns[abs(lasso.coef_) > 0.001]
print("L1筛选保留核心因子:", list(valid_factors))
来源网址:https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html
实操效果:可把50个冗余因子压缩至8~12个核心逻辑因子,杜绝高维因子过度拟合。
六、落地执行要点
1. 所有代码必须时序优先,严禁随机打乱数据;
2. 滚动窗口是必选项,任何量化策略不做滚动回测,回测收益都无参考价值;
3. 参数只选平稳区间,不追求历史最高收益;
4. 因子数量严格控制,用L1正则自动降噪,不靠人工堆砌因子。