
用 Python 揭秘均值回归策略:你的收益从何而来?
2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含 500 篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!
每个交易者都有自己的「直觉」:某只股票该涨了,某个形态要出现反转了……但当你把感性剥离,让纯数学来交易,会发生什么?
更要命的是,大多数人做策略回测时都会犯一个致命错误 —— 用全部历史数据训练模型,再用同一段历史去验证。模型「偷看」了未来,回测结果漂亮得不真实,一上实盘就原形毕露。这就是著名的 look-ahead bias(前视偏差)。
今天这篇文章,我们用 Python 搭建一个 走查法(Walk-Forward)仿真引擎,让 Kernel Regression、SVR、Ridge Regression 这 3 个回归模型在 NVIDIA(NVDA)的真实周线数据上「同台竞技」,看看哪个才是真金不怕火炼。
结果可能会颠覆你的认知:最简单的 Ridge 线性回归,反而打败了机器学习味十足的 SVR。
走查法的核心,是模拟真实交易场景:模型只能看到「当下之前」的数据,绝不允许偷看未来。具体步骤如下:
这套「训练 — 预测 — 揭晓」的循环,是目前公认最诚实的策略验证方式。
为了让对比公平,引擎使用 固定 1 股 的仓位逻辑:
单笔 ROI 公式:
其中 Direction 在做多时为 +1,做空时为 -1。
整体策略 ROI:
import yfinance as yf
import pandas as pd
# 从 Yahoo Finance 拉取 NVDA 日线数据
raw_df = yf.download("NVDA", start="2024-01-01", end="2026-06-25")
daily_df = raw_df[['Close']].ffill().dropna()
# 重采样为每周五收盘价,共 125 根周线
df = daily_df.resample('W-FRI').last().dropna()import numpy as np
WINDOW_SIZE = 24 # 训练窗口 24 周
for t in range(WINDOW_SIZE, len(df) - 1):
# 训练样本:截至 t-1 的 24 周历史
history_df = df.iloc[t - WINDOW_SIZE : t]
current_price = history_df['Close'].iloc[-1]
# 样本外目标:1 周后的真实收盘价(预测时不可见)
next_close = df['Close'].iloc[t]
realized_move = next_close - current_price
# 准备训练数据
X_train = np.arange(len(history_df)).reshape(-1, 1)
y_train = history_df['Close'].values
next_idx = np.array([[len(history_df)]])关键点:
realized_move是在预测之后才计算的,模型在预测时绝看不到它。
import statsmodels.api as sm
from sklearn.svm import SVR
from sklearn.linear_model import Ridge
# 模型 1:核回归(非参数,Nadaraya-Watson)
kernel_model = sm.nonparametric.KernelReg(
endog=y_train, exog=X_train, var_type='c', bw=[4.0])
kernel_pred, _ = kernel_model.fit(next_idx)
# 模型 2:支持向量回归(RBF 核技巧,捕捉非线性)
svr_model = SVR(kernel='rbf', C=1e3, gamma=0.05)
svr_model.fit(X_train, y_train)
svr_pred = svr_model.predict(next_idx)[0]
# 模型 3:岭回归(带 L2 正则的线性模型)
ridge_model = Ridge(alpha=10.0)
ridge_model.fit(X_train, y_train)
ridge_pred = ridge_model.predict(next_idx)[0]# 用样本内 RMSE 作为模型不确定性的代理
rmse_val = np.sqrt(np.mean((y_train - model.predict(X_train)) ** 2))
# 信号阈值:模型自身误差的 1.5 倍
noise_threshold = rmse_val * 1.5
projected_move = pred_val - current_price
# 只有当预测幅度 > 噪声阈值时才交易
signal_valid = abs(projected_move) >= noise_threshold
# 计算单笔 ROI(信号无效则为 0)
trade_roi = (realized_move * direction / current_price) * 100 \
if signal_valid else 0巧妙之处:拟合越差的模型(高 RMSE)会自动给自己设更高的门槛,相当于「自我打分」。
经过 125 周 NVDA 真实数据的洗礼,3 个模型成绩如下:
| Ridge(线性) | 29 | 48.28% | +$37.20 | +24.85% |
发现了吗?
SVR 的 RBF 核太「敏感」:它在 24 周里硬是要找出复杂曲线,结果不断被反转打脸,每周都在 LONG/SHORT 之间反复横跳,胜率仅 38%。
NVDA 在 2025 年走出了一波明显的上升趋势,Ridge 的「直线假设」恰好踩中节奏。在 9—10 月那段从 187 的行情里,它连续多周给出 LONG 信号,吃到了主升浪。
日期:2025-04-18 | 方向:SHORT | 入场:$110.90 | 出场:$101.47 | ROI:+8.51%Kernel 在 2024 年中段震荡市几乎不开仓(信号不过闸门),2025 年 4 月却精准捕捉到一次下跌,单笔赚回 +8.51%。
这套走查法仿真引擎的真正价值,不是「告诉你哪个模型最好」,而是 给你一把诚实的尺子。代码完全模块化,你只需要换一个股票代码、换一个日期区间,就能在任何标的上做属于自己的「模型对决」。
下次再有人吹自己的策略 ROI 多高,先问一句:「你是走查法测的吗?」
想动手实战?把训练窗口从 24 周改成 12 周或 36 周试试,看看 Ridge 的趋势跟随能力是否会变得更稳。
2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:
星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!
好文推荐
1. 用 Python 打造股票预测系统:Transformer 模型教程(一)
2. 用 Python 打造股票预测系统:Transformer 模型教程(二)
3. 用 Python 打造股票预测系统:Transformer 模型教程(三)
4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)
6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用
9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解
好书推荐