
用 Python 揭秘均值回归策略:你的收益从何而来?
2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含 500 篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!
在量化交易的世界里,大多数策略都在追逐强势——买入上涨最猛的,卖出跌得最惨的。但有没有想过,真正的机会可能藏在一个"安静的信号"里?
今天给大家分享一篇来自 Kryptera 的有趣实战:OSDI Fade 策略。它在 AMCR(安姆科包装)上跑了近 14 年的历史数据,最终以 119% 的总收益跑赢了买入持有策略(77.8%)。更有意思的是,它的入场逻辑完全反直觉——在动量变弱时买入,在趋势真正走软时卖出。
对于正在学习 Python 的同学来说,这是一个非常好的学习案例:涉及数据获取、技术指标计算、信号生成、回测框架使用等完整流程。
这个策略用了两个经典技术指标,但搭配方式很"不对称":
简单来说:用均值回归的方式入场,用趋势确认的方式出场。
import pandas as pd
import numpy as np
import yfinance as yf
import vectorbt as vbt
# 下载 AMCR 的日线数据
symbol = "AMCR"
start_date = "2000-01-01"
end_date = "2026-01-01"
interval = "1d"
# 使用 yfinance 下载历史价格数据
df = yf.download(symbol, start=start_date, end=end_date, interval=interval)
df.to_csv("AMCR_clean.csv", index=False)# OsMA 参数设置(经典 MACD 参数)
OSMA_FAST = 12 # 快速 EMA 周期
OSMA_SHIFT = 5 # 对比的回看周期
OSMA_SIGNAL = 9 # 信号线周期
OSMA_SLOW = 26 # 慢速 EMA 周期
def calculate_macd_osma(df, fast=OSMA_FAST, slow=OSMA_SLOW, signal_period=OSMA_SIGNAL):
"""
计算 MACD 、信号线以及 OsMA(MACD - Signal)
"""
df = df.copy()
# 计算快慢 EMA
df['EMA_fast'] = df['Close'].ewm(span=fast, adjust=False).mean()
df['EMA_slow'] = df['Close'].ewm(span=slow, adjust=False).mean()
# MACD 主线
df['MACD'] = df['EMA_fast'] - df['EMA_slow']
# 信号线
df['Signal'] = df['MACD'].ewm(span=signal_period, adjust=False).mean()
# OsMA 柱状图
df['OSMA'] = df['MACD'] - df['Signal']
return df
def osma_falling(df, shift=OSMA_SHIFT):
# 判断 OsMA 是否比 5 根 K 线前更低(即动量在减弱)
df = calculate_macd_osma(df)
return df['OSMA'] < df['OSMA'].shift(shift)DI_PERIOD = 14 # DMI 系统周期
DI_SHIFT_1 = 5 # 第一段回看
DI_SHIFT_2 = 10 # 第二段回看
def calculate_di(df, period=DI_PERIOD):
"""
计算 DI+ 和 DI- 方向指标
"""
df = df.copy()
# 真实波幅 TR
df['H-L'] = df['High'] - df['Low']
df['H-PC'] = abs(df['High'] - df['Close'].shift(1))
df['L-PC'] = abs(df['Low'] - df['Close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1)
# 计算 +DM 和 -DM
df['+DM'] = np.where((df['High'] - df['High'].shift(1)) > (df['Low'].shift(1) - df['Low']),
np.maximum(df['High'] - df['High'].shift(1), 0), 0)
df['-DM'] = np.where((df['Low'].shift(1) - df['Low']) > (df['High'] - df['High'].shift(1)),
np.maximum(df['Low'].shift(1) - df['Low'], 0), 0)
# Wilder 平滑处理
df['TR_smooth'] = df['TR'].rolling(period).sum()
df['+DM_smooth'] = df['+DM'].rolling(period).sum()
df['-DM_smooth'] = df['-DM'].rolling(period).sum()
# 计算 DI+ 和 DI-
df['DI+'] = 100 * (df['+DM_smooth'] / df['TR_smooth'])
df['DI-'] = 100 * (df['-DM_smooth'] / df['TR_smooth'])
return df
def di_plus_change_direction_downward(df, shift_1=DI_SHIFT_1, shift_2=DI_SHIFT_2):
# 判断 DI+ 是否连续两段下降(趋势走软确认)
df = calculate_di(df)
return (df['DI+'].shift(shift_1) < df['DI+'].shift(shift_2)) & \
(df['DI+'] < df['DI+'].shift(shift_1))# 生成入场和出场条件
df["OSMA_Falling"] = osma_falling(df)
df["DI+_Change_Direction_Downward"] = di_plus_change_direction_downward(df)
# 组合信号
df['entry_signal'] = df[['OSMA_Falling']].all(axis=1)
df['exit_signal'] = df[['DI+_Change_Direction_Downward']].all(axis=1)
# 信号向后平移一根 K 线(避免未来函数)
shift_entries = df['entry_signal'].shift(1).astype(bool).fillna(False).to_numpy()
shift_exits = df['exit_signal'].shift(1).astype(bool).fillna(False).to_numpy()
# 使用 vectorbt 进行回测
pf = vbt.Portfolio.from_signals(
close=df['Open'], # 以开盘价成交
entries=shift_entries,
exits=shift_exits,
init_cash=100_000, # 初始资金 10 万美元
fees=0.001, # 千一手续费
slippage=0.002, # 千二滑点
freq='1d'
)
# 输出绩效和图表
print(pf.stats())
pf.plot().show()在 2012-05-15 到 2025-12-31 的回测区间内:
几个关键观察:
AMCR 是一家包装公司,属于低波动、区间震荡型标的。这种股票的动量波动不剧烈,均值回归特性明显——所以"动量疲软即入场"的反直觉逻辑才会有效。
警告:同样的参数用在高波动的科技股上,结果可能完全不同。这也是量化策略的共识——没有放之四海而皆准的参数。
这篇文章给 Python 学习者带来三点启发:
真正的量化优势,往往不在喧嚣的信号里,而在安静的问题中——"动量是否正在疲软?"——每天问一次,耐心等答案。
风险提示:本文仅用于学习交流,不构成投资建议。任何交易系统在实盘前都应进行充分的研究和压力测试。
2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:
星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!
好文推荐
1. 用 Python 打造股票预测系统:Transformer 模型教程(一)
2. 用 Python 打造股票预测系统:Transformer 模型教程(二)
3. 用 Python 打造股票预测系统:Transformer 模型教程(三)
4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)
6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用
9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解
好书推荐