欢迎光临
我们一直在努力

Momentum:CMO(钱德动量震荡指标)技术指标详解

Momentum:CMO(钱德动量震荡指标)技术指标详解

一、CMO的定义

CMO(Chande Momentum Oscillator,钱德动量震荡指标) 是由著名技术分析师Tushar Chande于1994年在《The New Technical Trader》一书中正式提出的一种动量技术指标。

核心思想

CMO的核心设计理念是捕捉Chande所说的"纯动量"(Pure Momentum)。与许多传统动量指标不同,CMO在计算过程中同时使用上涨日和下跌日的数据,通过比较一段时间内累计涨幅与累计跌幅的比率,来量化市场的净动量。

CMO的核心特征

特征说明
数值范围 严格限定在-100到+100之间
对称性 围绕零轴上下对称,直观反映多空力量对比
零轴分界 CMO > 0表示上涨动量占优,CMO < 0表示下跌动量占优
开发者 Tushar Chande(1994年)
默认周期 14或20周期

CMO与RSI的对比

CMO与RSI在计算思想上密切相关但又各有特色:

对比维度CMORSI
数值范围 -100 到 +100(零轴居中) 0 到 100
计算平滑 使用未平滑数据(可后续平滑) 使用Wilder平滑
上下阈值 +50 / -50 70 / 30
核心优势 更直接地测量净动量 更广泛的市场认可

二、CMO的计算方法

1. 核心公式

CMO的标准计算公式为:
CMO=Su−SdSu+Sd×100
\\mathrm{CMO} = \\frac{S_u – S_d}{S_u + S_d} \\times 100
CMO=Su​+Sd​Su​−Sd​​×100

其中:

  • SuS_uSu​:指定周期内上涨日(当日收盘 > 前日收盘)的收盘价差之和
  • SdS_dSd​:指定周期内下跌日(当日收盘 < 前日收盘)的收盘价差绝对值和

2. 详细计算步骤

步骤一:计算每日价格变化

对于每个周期 ttt,计算当日收盘价与前一日收盘价的差值:

ΔPt=Closet−Closet−1\\Delta P_t = \\mathrm{Close}_t−\\mathrm{Close}_{t−1}ΔPt​=Closet​−Closet−1​

步骤二:分离上涨值和下跌值

  • 上涨值:Ut=max⁡⁡(ΔPt,0)U_t = \\max ⁡(\\Delta P_t,0)Ut​=max⁡(ΔPt​,0)
  • 下跌值:Dt=∣min⁡⁡(ΔPt,0)∣D_t = |\\min ⁡(\\Delta P_t,0)|Dt​=∣min⁡(ΔPt​,0)∣

步骤三:计算周期总和

设周期为 NNN(默认14或20):

Su=∑i=t−N+1tUiSd=∑i=t−N+1tDi
S_u = \\sum_{i=t-N+1}^t U_i \\\\
S_d = \\sum_{i=t-N+1}^t D_i \\\\
Su​=i=t−N+1∑t​Ui​Sd​=i=t−N+1∑t​Di​

步骤四:计算CMO值
CMO=Su−SdSu+Sd×100
\\mathrm{CMO} = \\frac{S_u – S_d}{S_u + S_d} \\times 100
CMO=Su​+Sd​Su​−Sd​​×100

  • 当 Su=SdS_u=S_dSu​=Sd​ 时,CMO = 0(多空平衡)
  • 当 Sd=0S_d=0Sd​=0 时,CMO = +100(极端超买)
  • 当 Su=0S_u=0Su​=0 时,CMO = -100(极端超卖)

3. CMO的等价变形公式

CMO也可以表示为:

CMO=(2SuSu+Sd−1)×100
\\mathrm{CMO} = \\left(\\frac{2S_u}{S_u + S_d} – 1 \\right) \\times 100
CMO=(Su​+Sd​2Su​​−1)×100

这种变形清楚地显示了CMO与上涨占比的关系。

4. 参数说明

参数默认值说明
length 14 CMO计算周期(Chande建议20,多数平台默认14)
scalar 100 放大倍数,将结果转换为-100到+100范围
drift 1 价格变化步长

5. 计算示例

假设某股票最近7个交易日数据(N=5):

日期收盘价与前日差价上涨值 UtU_tUt​下跌值 DtD_tDt​
Day1 100 — — —
Day2 102 +2 2 0
Day3 105 +3 3 0
Day4 103 -2 0 2
Day5 107 +4 4 0
Day6 106 -1 0 1
Day7 108 +2 2 0

计算过程(以Day7为例,取最近5个有效变化:Day3-Day7):

  • 周期内上涨和 Su=3+4+2=9S_u = 3 + 4 + 2 = 9Su​=3+4+2=9(Day3、Day5、Day7)
  • 周期内下跌和 Sd=2+1=3S_d = 2 + 1 = 3Sd​=2+1=3(Day4、Day6)
  • CMO = 100×(9−3)/(9+3)=100×6/12=50100 × (9 – 3) / (9 + 3) = 100 × 6 / 12 = 50100×(9−3)/(9+3)=100×6/12=50

该CMO值为50,处于超买阈值(+50)线上,提示市场可能过热。

三、CMO的使用方法

1. 超买超卖判断——最核心用法

这是CMO指标最经典的应用方法。Tushar Chande将+50量化为超买水平,-50为超卖水平。

CMO区间市场状态操作建议
CMO > +50 超买区 上涨动量过热,可能出现回调,考虑减仓或做空
CMO < -50 超卖区 下跌动量过度,可能出现反弹,考虑建仓或平空
+50 > CMO > 0 偏多区 上涨动量占优,但未过热,可顺势持仓
0 > CMO > -50 偏空区 下跌动量占优,但未过度,谨慎操作

逻辑解释:当CMO达到+50时,上涨日总涨幅是下跌日总跌幅的三倍(因为(3-1)/(3+1)=0.5);当CMO达到-50时,下跌日总跌幅是上涨日总涨幅的三倍。

阈值调整建议:

市场类型推荐阈值原因
稳定市场(股票) +50 / -50 标准配置
高波动市场(加密货币) +60 / -60 或更高 波动大,需要更高阈值过滤噪音

2. 零轴穿越

CMO围绕零轴波动,零轴是多空力量的分界线:

信号类型触发条件含义操作建议
看涨穿越 CMO从下方上穿零轴 上涨动量开始压倒下跌动量 考虑建立多头仓位
看跌穿越 CMO从上方下穿零轴 下跌动量开始压倒上涨动量 考虑平仓或建立空头

适用场景:零轴穿越在趋势市场中效果最佳,在震荡市场中可能产生较多假信号。

3. 背离信号——反转预警

与其他动量指标一样,CMO与价格走势的背离是重要的反转预警信号:

背离类型价格表现CMO表现信号含义
顶背离 价格创出新高 CMO未能创出新高(形成更低高点) 上涨动能衰竭,可能见顶
底背离 价格创出新低 CMO未能创出新低(形成更高低点) 下跌动能减弱,可能见底

实战提示:背离信号在CMO处于极端区域(±50外)时可靠性更高。

4. 趋势强度判断

CMO的绝对值大小可以反映趋势强度:

CMO绝对值趋势强度市场含义
高值(>50) 强趋势 动量强烈,趋势健康但需警惕反转
中值(20-50) 中等趋势 动量明显,趋势可靠
低值(<20) 弱趋势/盘整 动量不足,市场可能处于横盘状态

5. 配合移动平均线触发线

Chande建议可以给CMO增加一条触发线(Trigger Line)来产生更明确的买卖信号:

触发线设置信号操作
CMO上穿其9周期MA 买入信号 动量开始增强
CMO下穿其9周期MA 卖出信号 动量开始减弱

6. 参数优化建议

CMO的计算周期可以根据交易风格调整:

交易风格推荐周期特点
短线/日内交易 9 反应灵敏,信号较多但噪声增加
波段交易(标准) 14 标准配置,平衡可靠性与灵敏度
中长线交易 20-25 更平滑,信号较少但更可靠

7. 多指标配合策略

CMO不应单独使用,建议与其他指标配合:

配合指标作用具体用法
移动平均线 确认趋势方向 CMO零轴穿越方向与MA趋势一致时信号更可靠
支撑/阻力位 确认关键位置 CMO超卖信号出现在关键支撑位时胜率更高
K线形态 确认入场时机 CMO信号配合反转K线形态(锤子线、吞没形态)确认

8. 注意事项与局限性

使用CMO前需了解以下要点:

局限性说明
震荡市假信号 在横盘整理市场中,CMO可能在零轴上下频繁穿越,产生大量假信号
强趋势中钝化 在强劲单边趋势中,CMO可能长时间停留在超买或超卖区域,过早反向操作会导致踏空
参数敏感性 不同周期参数会导致CMO表现差异较大,需要根据品种和交易风格优化
滞后性质 基于历史价格数据的计算本质上有滞后性,在快速反转行情中可能延迟反应
不能单独使用 建议结合趋势指标(如均线、ADX)过滤信号,避免在震荡市中追涨杀跌

四、使用pandas_ta计算CMO(附示例代码)

1. pandas_ta中的CMO函数

pandas_ta库内置了CMO指标的完整实现,函数位于momentum模块中。

2. 函数完整参数

pandas_ta.momentum.cmo(close, length=None, scalar=None, talib=None, drift=None, offset=None, **kwargs)

参数详解:

参数类型默认值说明
close pd.Series 必需 收盘价序列
length int 14 CMO计算周期
scalar float 100 放大倍数(转换为百分比)
talib bool True 若安装TA-Lib则使用其版本
drift int 1 价格变化步长
offset int 0 结果偏移周期数

返回值:pd.Series——CMO值序列(范围-100到+100)。

3. 示例代码

import pandas as pd
import pandas_ta as ta
import numpy as np
import matplotlib.pyplot as plt

# ========== 第一步:准备数据 ==========
np.random.seed(42)
dates = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')
n = len(dates)

# 生成带趋势和周期波动的价格序列
trend = np.linspace(0, 25, n)
cycle = np.sin(np.linspace(0, 6 * np.pi, n)) * 10
noise = np.random.randn(n) * 2
price_series = 100 + trend + cycle + noise

df = pd.DataFrame(index=dates)
df['close'] = price_series
df['high'] = df['close'] + np.abs(np.random.randn(n)) * 2 + 1
df['low'] = df['close'] – np.abs(np.random.randn(n)) * 2 – 1
df['volume'] = np.random.randint(1000000, 10000000, n)

print("=" * 60)
print("数据预览:")
print(df.head())
print("\\n" + "=" * 60 + "\\n")

# ========== 第二步:计算CMO(基础用法) ==========
# 使用默认参数 length=14
df['CMO'] = ta.cmo(df['close'])

print("CMO计算结果(最近10行):")
print(df[['close', 'CMO']].tail(10))
print("\\n" + "=" * 60 + "\\n")

# ========== 第三步:手动验证CMO计算 ==========
def manual_cmo(close, length=14):
"""手动计算CMO验证pandas_ta结果"""
# 计算价格变化
delta = close.diff()

# 分离上涨和下跌
gains = delta.clip(lower=0)
losses = –delta.clip(upper=0)

# 滚动求和
sum_gains = gains.rolling(window=length).sum()
sum_losses = losses.rolling(window=length).sum()

# 计算CMO
cmo = 100 * (sum_gains – sum_losses) / (sum_gains + sum_losses)
return cmo

df['CMO_manual'] = manual_cmo(df['close'])

# 验证一致性
diff = (df['CMO'] – df['CMO_manual']).abs().max()
print(f"pandas_ta与手动计算的最大差异:{diff:.10f}")
print("\\n" + "=" * 60 + "\\n")

# ========== 第四步:不同周期的CMO ==========
# 短线参数 (9)
df['CMO_9'] = ta.cmo(df['close'], length=9)

# 标准参数 (14)
df['CMO_14'] = ta.cmo(df['close'], length=14)

# 长线参数 (20)
df['CMO_20'] = ta.cmo(df['close'], length=20)

print("不同周期CMO对比(最近5行):")
print(df[['close', 'CMO_9', 'CMO_14', 'CMO_20']].tail())
print("\\n" + "=" * 60 + "\\n")

# ========== 第五步:生成超买超卖信号 ==========
OVERBOUGHT = 50
OVERSOLD = –50

df['signal'] = ''
df.loc[df['CMO'] > OVERBOUGHT, 'signal'] = '超买(考虑卖出)'
df.loc[df['CMO'] < OVERSOLD, 'signal'] = '超卖(考虑买入)'

# 超买超卖区域回穿信号(信号可靠性更高)
df['cross_below_overbought'] = (df['CMO'].shift(1) > OVERBOUGHT) & (df['CMO'] <= OVERBOUGHT)
df['cross_above_oversold'] = (df['CMO'].shift(1) < OVERSOLD) & (df['CMO'] >= OVERSOLD)

df['trade_signal'] = ''
df.loc[df['cross_below_overbought'], 'trade_signal'] = '卖出信号(退出超买区)'
df.loc[df['cross_above_oversold'], 'trade_signal'] = '买入信号(退出超卖区)'

print("超买超卖信号统计:")
print(f"超买信号数量:{(df['CMO'] > OVERBOUGHT).sum()}")
print(f"超卖信号数量:{(df['CMO'] < OVERSOLD).sum()}")

print("\\n退出超买/超卖区信号(最近10个):")
exit_signals = df[df['trade_signal'] != ''].tail(10)
if not exit_signals.empty:
print(exit_signals[['close', 'CMO', 'trade_signal']])
print("\\n" + "=" * 60 + "\\n")

# ========== 第六步:零轴穿越信号 ==========
df['CMO_above_zero'] = df['CMO'] > 0
df['cross_above_zero'] = (df['CMO_above_zero'] == True) & (df['CMO_above_zero'].shift(1) == False)
df['cross_below_zero'] = (df['CMO_above_zero'] == False) & (df['CMO_above_zero'].shift(1) == True)

print("零轴穿越信号(最近10个):")
zero_cross = df[df['cross_above_zero'] | df['cross_below_zero']].tail(10)
if not zero_cross.empty:
for idx, row in zero_cross.iterrows():
signal_type = "上穿零轴(买入)" if row['cross_above_zero'] else "下穿零轴(卖出)"
print(f"{idx.date()} – {signal_type} – CMO: {row['CMO']:.2f}")
print("\\n" + "=" * 60 + "\\n")

# ========== 第七步:背离检测(简化版) ==========
# 计算20日价格变化和CMO变化
df['price_change_20d'] = df['close'].diff(20)
df['cmo_change_20d'] = df['CMO'].diff(20)

# 检测潜在背离
df['potential_bearish_div'] = (df['price_change_20d'] > 0) & (df['cmo_change_20d'] < 0)
df['potential_bullish_div'] = (df['price_change_20d'] < 0) & (df['cmo_change_20d'] > 0)

print("潜在背离信号统计(20日尺度):")
print(f"潜在顶背离(价格涨CMO跌)数量:{df['potential_bearish_div'].sum()}")
print(f"潜在底背离(价格跌CMO涨)数量:{df['potential_bullish_div'].sum()}")
print("注:完整背离需结合局部高/低点分析,此处为简化方向对比")
print("\\n" + "=" * 60 + "\\n")

# ========== 第八步:添加触发线(Signal Line) ==========
# Chande推荐的9周期MA作为触发线
df['CMO_signal'] = ta.sma(df['CMO'], length=9)
df['signal_cross_above'] = (df['CMO'] > df['CMO_signal']) & (df['CMO'].shift(1) <= df['CMO_signal'].shift(1))
df['signal_cross_below'] = (df['CMO'] < df['CMO_signal']) & (df['CMO'].shift(1) >= df['CMO_signal'].shift(1))

print("CMO与触发线交叉信号统计:")
print(f"CMO上穿触发线数量:{df['signal_cross_above'].sum()}")
print(f"CMO下穿触发线数量:{df['signal_cross_below'].sum()}")
print("\\n" + "=" * 60 + "\\n")

# ========== 第九步:策略回测(超买超卖反转策略) ==========
# 策略:CMO < -50 时买入,CMO > 50 时卖出
df['position'] = 0
in_position = False

for i in range(1, len(df)):
if not in_position and df['CMO'].iloc[i] < –50:
df.loc[df.index[i], 'position'] = 1
in_position = True
elif in_position and df['CMO'].iloc[i] > 50:
df.loc[df.index[i], 'position'] = 0
in_position = False
else:
df.loc[df.index[i], 'position'] = df['position'].iloc[i–1]

# 计算收益
df['returns'] = df['close'].pct_change()
df['strategy_returns'] = df['position'].shift(1) * df['returns']

total_return_buyhold = (1 + df['returns']).prod() – 1
total_return_strategy = (1 + df['strategy_returns']).prod() – 1
win_rate = (df['strategy_returns'] > 0).sum() / (df['strategy_returns'] != 0).sum() if (df['strategy_returns'] != 0).sum() > 0 else 0

print("=" * 60)
print("策略绩效统计(CMO超买超卖反转策略回测):")
print(f"买入持有策略总收益率:{total_return_buyhold:.2%}")
print(f"CMO反转策略总收益率:{total_return_strategy:.2%}")
print(f"策略胜率:{win_rate:.2%}")
print("\\n注意:此为简化回测,仅供参考")
print("=" * 60 + "\\n")

# ========== 第十步:可视化 ==========
plt.figure(figsize=(14, 10))

# 子图1:价格走势
plt.subplot(2, 1, 1)
plt.plot(df.index[–150:], df['close'][–150:], label='Close Price',
linewidth=1.5, color='black')
plt.title('Price Chart (Last 150 days)', fontsize=14)
plt.ylabel('Price')
plt.legend()
plt.grid(True, alpha=0.3)

# 子图2:CMO指标(含超买超卖线)
plt.subplot(2, 1, 2)
plt.plot(df.index[–150:], df['CMO'][–150:], label='CMO (14)',
linewidth=1.5, color='blue')
plt.plot(df.index[–150:], df['CMO_signal'][–150:], label='Trigger Line (SMA 9)',
linewidth=1, color='orange', alpha=0.8)
plt.axhline(y=50, color='red', linestyle='–', linewidth=1, label='超买线 (+50)')
plt.axhline(y=0, color='gray', linestyle='-', linewidth=0.8, alpha=0.7, label='零轴')
plt.axhline(y=–50, color='green', linestyle='–', linewidth=1, label='超卖线 (-50)')

# 填充超买超卖区域
plt.fill_between(df.index[–150:], 50, 100, alpha=0.1, color='red', label='超买区')
plt.fill_between(df.index[–150:], –100, –50, alpha=0.1, color='green', label='超卖区')

plt.title('CMO (Chande Momentum Oscillator) – Overbought/Oversold Levels', fontsize=14)
plt.xlabel('Date')
plt.ylabel('CMO Value')
plt.ylim(–110, 110)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# ========== 第十一步:数据清洗提示 ==========
nan_count = df['CMO'].isna().sum()
print(f"\\nCMO初始NaN数量:{nan_count}")
print("原因:CMO需要至少length个周期的数据才能开始计算")
print("处理建议:df_clean = df.iloc[14:].copy()")

五、总结

CMO(钱德动量震荡指标)是一种直观且对称的动量衡量工具,其核心价值与定位如下:

维度特点
核心创新 同时使用上涨和下跌日数据,直接测量净动量
数值范围 严格限定在-100到+100之间,对称于零轴
三大核心信号 超买超卖(±50)、零轴穿越、顶底背离
与RSI关系 计算逻辑相似但更对称,+50/-50对应RSI的70/30
最佳应用场景 趋势确认、反转预警、动量强度判断
主要局限 震荡市假信号多、强趋势中可能钝化

实战使用三原则:

  • 超买超卖是核心:CMO最经典的应用是±50阈值的超买超卖判断,退出超买/超卖区的信号比进入时更可靠
  • 趋势市用零轴穿越,震荡市用极值反转:在趋势行情中跟随零轴穿越信号,在震荡行情中关注极端值附近的反弹机会
  • 配合趋势过滤提高胜率:将CMO与移动平均线、ADX等趋势指标配合使用,避免在震荡市中频繁交易
  • 最后提醒:CMO最大的特色在于其对称性——它用简洁的公式将多空力量对比直观地呈现在-100到+100之间。当CMO达到+50时,意味着上涨动量是下跌动量的三倍,这种量化的解释为交易者提供了清晰的决策参考。然而,正如Chande本人所强调的,CMO在强趋势市场中可能会长期停留在极端区域,因此建议将其与趋势确认工具结合使用,形成更完整的交易系统。

    赞(0)
    未经允许不得转载:171主机测评 » Momentum:CMO(钱德动量震荡指标)技术指标详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址