你是否想过,如何运用简洁的技术指标逻辑,在长期市场波动中捕捉交易机会?今天,我们将深入剖析一个结合了CMO(钱德动量震荡指标)与QQE(量化定性估计指标)的超卖反转策略。该策略遵循一个朴素但有力的交易哲学:在市场出现极端恐慌情绪时入场,在上涨动量开始衰减时离场。下文将详细拆解其核心逻辑,并提供完整的Python实现代码,适合量化交易初学者入门实践。
策略核心逻辑
这个策略建立在一个清晰的二元框架之上:
- 入场时机:当市场恐慌情绪达到极致,出现非理性抛售时买入。
- 离场时机:当价格上涨的动能开始减弱、出现衰减迹象时卖出。
问题的关键在于,如何量化定义“恐慌”和“动量衰减”。这正是CMO和QQE两个技术指标发挥作用的舞台。
技术指标详解与实现
1. CMO:钱德动量震荡指标
CMO由Tushar Chande发明,是一个动量振荡器,其数值在-100到100之间波动。当CMO值跌破-50时,通常意味着市场的卖压已达到极端水平,可能处于超卖状态,这构成了我们的入场信号基础。
CMO_LEVEL_OVERSOLD = -50 # 超卖阈值
CMO_PERIOD = 14 # 计算周期
def chande_momentum_oscillator(df, period=CMO_PERIOD):
"""
计算钱德动量震荡指标(CMO)
参数:
df: 包含收盘价的 DataFrame
period: 计算周期,默认 14 天
返回:
添加了 CMO 列的 DataFrame
"""
diff = df['Close'].diff() # 计算价格变化
up = diff.clip(lower=0).rolling(period).sum() # 上涨幅度之和
down = (-diff.clip(upper=0)).rolling(period).sum() # 下跌幅度之和
df['CMO'] = 100 * (up - down) / (up + down) # CMO 公式
return df
def cmo_is_cross_below_oversold(df, level=CMO_LEVEL_OVERSOLD):
"""
判断 CMO 是否向下穿越超卖线
这个“穿越”的瞬间被视为恐慌达到顶点,生成潜在入场信号。
"""
df = chande_momentum_oscillator(df)
return (df['CMO'] < level) & (df['CMO'].shift(1) >= level)
2. QQE:量化定性估计指标
QQE可以理解为RSI指标的平滑版本,并结合了波动率调整。当QQE指标线(Value1)向下跌破50水平线时,表明当前的上涨动量正在消退,这作为我们离场的信号。
QQE_FACTOR = 4.236 # 波动率乘数
QQE_LEVEL = 50 # 动量阈值
QQE_PERIOD = 14 # RSI 周期
QQE_SMOOTH = 5 # 平滑周期
def calculate_qqe(df, rsi_period=QQE_PERIOD, smooth=QQE_SMOOTH, factor=QQE_FACTOR):
"""
计算 QQE 指标的两条线(Value1 和 Value2)
参数:
df: 包含收盘价的 DataFrame
rsi_period: RSI 计算周期
smooth: 平滑窗口
factor: ATR 波动率乘数
"""
df = df.copy()
# 计算 RSI
delta = df['Close'].diff()
up = delta.clip(lower=0)
down = -delta.clip(upper=0)
roll_up = up.ewm(alpha=1/rsi_period, adjust=False).mean()
roll_down = down.ewm(alpha=1/rsi_period, adjust=False).mean()
rsi = 100 - (100 / (1 + roll_up / roll_down))
# 平滑 RSI
rsi_ma = rsi.rolling(window=smooth).mean().fillna(method='bfill')
# 计算 RSI 的波动率(类似 ATR)
rsi_delta = rsi_ma.diff().abs().fillna(0)
atr_rsi = rsi_delta.ewm(alpha=1/smooth, adjust=False).mean()
# 计算 QQE 的两条线
value1 = rsi_ma.copy()
value2 = pd.Series(index=df.index, dtype=float)
value2.iloc[0] = value1.iloc[0]
for i in range(1, len(df)):
prev_trail = value2.iloc[i-1]
prev_value1 = value1.iloc[i-1]
atr = atr_rsi.iloc[i]
direction = 1 if prev_value1 > prev_trail else -1
value2.iloc[i] = prev_trail + direction * factor * atr
df['QQE_Value1'] = value1
df['QQE_Value2'] = value2
return df
def qqe_cross_below_level(df, level=QQE_LEVEL):
"""
判断 QQE Value1 是否向下穿越阈值线
这是离场的信号。
"""
df = calculate_qqe(df)
return (df['QQE_Value1'] < level) & (df['QQE_Value1'].shift(1) >= level)
完整策略回测代码
以下是完整的策略回测实现,我们使用高效的vectorbt库进行向量化回测。
import pandas as pd
import numpy as np
import yfinance as yf
import vectorbt as vbt
# -------------------------
# 下载历史数据
# -------------------------
symbol = “AVY“ # 示例股票:艾利丹尼森公司
start_date = “2000-01-01“
end_date = “2026-01-01“
interval = “1d“ # 日线数据
df = yf.download(symbol, start=start_date, end=end_date, interval=interval)
df.to_csv(“AVY_clean.csv“, index=False)
# -------------------------
# 生成交易信号
# -------------------------
# 入场信号:CMO向下穿越超卖线
df[“CMO_is_Cross_Below_Oversold“] = cmo_is_cross_below_oversold(df)
entry_conditions = [‘CMO_is_Cross_Below_Oversold‘]
df[‘entry_signal‘] = df[entry_conditions].all(axis=1)
# 离场信号:QQE Value1向下穿越50水平线
df[“QQE_Value1_CrossBelow_Level“] = qqe_cross_below_level(df)
exit_conditions = [‘QQE_Value1_CrossBelow_Level‘]
df[‘exit_signal‘] = df[exit_conditions].all(axis=1)
# -------------------------
# 执行回测
# -------------------------
# 信号延迟一天执行,以模拟更真实的交易场景
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()
pf = vbt.Portfolio.from_signals(
close=df[‘Open‘], # 使用次日开盘价成交
entries=shift_entries,
exits=shift_exits,
init_cash=100_000, # 初始资金 10 万美元
fees=0.001, # 手续费 0.1%
slippage=0.002, # 滑点 0.2%
freq=’1d’)
# -------------------------
# 输出回测统计结果
# -------------------------
print(pf.stats())
pf.plot().show()
回测结果分析
在2000年1月至2025年12月长达约25年的回测区间内,该策略表现如下关键指标(具体数值可能因数据源和细微参数差异略有浮动):
- 总收益率:约663%
- 最大回撤:约52%
- 总交易次数:69次
- 胜率:约66.67%
- 盈亏比:约2.08
作为对比,同期简单的买入持有(Buy and Hold)策略的最大回撤高达73%,远高于本策略的52%,体现了该策略在风险控制方面的潜在优势。
策略核心启示
- 逆向布局:当CMO指标揭示市场处于极端超卖(恐慌)状态时,往往是逆向投资者寻找机会的窗口。
- 动量跟踪离场:无需等到价格趋势完全反转,QQE指标发出的动量衰减信号有助于早期锁定利润,避免大幅回吐。
- 理性看待回撤:52%的最大回撤提醒我们,任何旨在获取超额收益的策略都需承担相应的波动风险。
- 数据驱动决策:25年间仅触发69次交易,结合超过66%的胜率和大于2的盈亏比,展示了系统化、纪律化交易的统计优势。
风险提示
- 历史回测业绩不代表未来表现,市场环境与规律可能发生变化。
- 本文内容仅用于量化交易技术交流与学习,不构成任何投资建议。
- 所有交易策略均存在风险,应用前请充分理解其逻辑并进行严格测试。
总结
本文详细阐述了一个基于CMO与QQE技术指标的超卖反转策略。其逻辑链条清晰:利用CMO捕捉市场极端恐慌带来的入场机会,借助QQE监控上涨动能的衰减以提示离场。长期的回测数据显示,该策略在控制最大回撤的同时,实现了显著的总收益累积。对于希望入门Python量化交易的朋友而言,这个案例提供了一个从指标理解、信号构建到vectorbt回测的完整实践路径。