当前位置:首页>python>当动量开始疲软:一个反直觉的 Python 量化策略实战

当动量开始疲软:一个反直觉的 Python 量化策略实战

  • 2026-09-09 15:56:36
当动量开始疲软:一个反直觉的 Python 量化策略实战

用 Python 揭秘均值回归策略:你的收益从何而来?

2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含 500 篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!

引言

在量化交易的世界里,大多数策略都在追逐强势——买入上涨最猛的,卖出跌得最惨的。但有没有想过,真正的机会可能藏在一个"安静的信号"里?

今天给大家分享一篇来自 Kryptera 的有趣实战:OSDI Fade 策略。它在 AMCR(安姆科包装)上跑了近 14 年的历史数据,最终以 119% 的总收益跑赢了买入持有策略(77.8%)。更有意思的是,它的入场逻辑完全反直觉——在动量变弱时买入,在趋势真正走软时卖出。

对于正在学习 Python 的同学来说,这是一个非常好的学习案例:涉及数据获取、技术指标计算、信号生成、回测框架使用等完整流程。

策略核心思想

这个策略用了两个经典技术指标,但搭配方式很"不对称":

  • • 入场信号:使用 OsMA(MACD 柱状图)。当 OsMA 相对 5 根 K 线前在下降时买入——也就是动量在"悄悄疲软"。
  • • 出场信号:使用 DI+(Wilder 的方向指标)。当 DI+ 连续两段时间下降时卖出——也就是上升趋势正式确认走软。

简单来说:用均值回归的方式入场,用趋势确认的方式出场。

代码实战

1. 数据获取

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)

2. 计算 OsMA 指标(入场信号)

# 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)

3. 计算 DI+ 指标(出场信号)

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))

4. 生成信号并回测

# 生成入场和出场条件
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 的回测区间内:

指标
OSDI Fade 策略
买入持有
总收益率
119%
77.8%
最大回撤
41%
48.5%
夏普比率
0.46
0.36
总交易次数
68
1
胜率
51%
—
盈亏比
1.35
—

几个关键观察:

  1. 1. 低频交易:14 年只有 68 笔交易,平均每年 5 笔,极度"佛系"。
  2. 2. 盈亏不对称:平均盈利 7.3%,平均亏损 4.8%,最好的单笔 +36.5%,最差 -14.9%。
  3. 3. 持仓时间不对称:平均盈利单持有 47 天,平均亏损单只持有 34 天——赚钱的单子拿得更久,这是健康的交易行为。
  4. 4. 回撤更小:相比买入持有的 48.5%,策略的 41% 回撤让持仓体验更舒适。

为什么这个策略能奏效?

AMCR 是一家包装公司,属于低波动、区间震荡型标的。这种股票的动量波动不剧烈,均值回归特性明显——所以"动量疲软即入场"的反直觉逻辑才会有效。

警告:同样的参数用在高波动的科技股上,结果可能完全不同。这也是量化策略的共识——没有放之四海而皆准的参数。

总结

这篇文章给 Python 学习者带来三点启发:

  1. 1. 技术指标不是孤立的:入场和出场可以用不同逻辑的指标组合,形成"不对称策略"。
  2. 2. vectorbt 是个好工具:用几行代码就能完成完整的信号回测,适合快速验证想法。
  3. 3. 不要盲目相信回测:14 年的历史数据也不能保证未来表现,必须结合 Walk-Forward 优化、多标的验证等稳健性测试。

真正的量化优势,往往不在喧嚣的信号里,而在安静的问题中——"动量是否正在疲软?"——每天问一次,耐心等答案。

风险提示:本文仅用于学习交流,不构成投资建议。任何交易系统在实盘前都应进行充分的研究和压力测试。

参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。

财经数据与量化投研知识社区

2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:

  1. 1. 双典系统赋能:获赠《财经数据宝典》与《量化投研宝典》完整文档,凝练多年实战经验,构建系统化知识框架;
  2. 2. 量化因子日更教程(2026重磅新增):每日更新「量化因子专题教程」,配套完整可运行代码与实战案例,深度拆解因子构建、回测与优化全流程;
  3. 3. 量化文章专题教程库:300+篇星球独有高质量教程式文章,系统覆盖策略开发、因子研究、风险管理等核心领域,内容基本每日更新,并配套精选学习资料与实战参考;
  4. 4. 量化投研实战课程:赠送《AKQuant-入门及实战》《PyBroker-入门及实战》视频课程,手把手教学,快速掌握量化策略开发技能;
  5. 5. 财经数据支持:定期更新国内外财经数据,为策略研发提供精准、可靠的数据基础;
  6. 6. 顶尖学者与行业专家分享:年度邀请学术界博士与业界资深专家开展前沿论文精讲与实战案例分享,不少于4场,直击研究前沿与产业实践;
    专家直连答疑:与核心开发者及领域专家实时互动,高效解决投研实战难题;
  7. 7. 专业社群与专属福利:加入高质量交流社群,获取课程折扣及更多独家资源。

星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐

最新文章

随机文章