外观
四种动量计算方式详解
在 ETF 轮动等趋势跟踪策略中,动量是核心评分指标——它衡量的是一段时间内资产的上涨强度与趋势质量。次方量化平台提供四种动量计算方式,各有侧重,适用于不同的市场环境和策略诉求。
| 动量类型 | 计算复杂度 | 对趋势的刻画 | 抗噪能力 | 适用场景 |
|---|---|---|---|---|
| 简单动量 | ⭐ 低 | 只看涨跌幅 | 低 | 快速筛选、短线参考 |
| 斜率动量 | ⭐⭐ 中 | 趋势方向 + 稳定性 | 中 | 中长期趋势跟踪 |
| 加权斜率动量 | ⭐⭐ 中 | 偏重近期趋势 + 稳定性 | 中 | 短中期趋势跟踪 |
| RSRS 动量 | ⭐⭐⭐ 高 | 支撑/阻力弹性 + 标准化 | 高 | 择时精度要求高的策略 |
一、简单动量
核心思想
最直观的动量计算方式:用当前价格相对 N 天前价格的涨跌幅来衡量动量强弱。涨得越多,动量越强。
计算公式
简单动量 = (P_当前 - P_N天前) / P_N天前其中:
P_当前— 最新收盘价P_N天前— N 个周期前的收盘价(momentum_period参数控制)
计算步骤
第一步:取价格
python
current_price = df['close'].iloc[-1] # 最新收盘价
past_price = df['close'].iloc[-momentum_period] # N 天前收盘价第二步:计算涨跌幅
python
momentum = (current_price - past_price) / past_price第三步:保留 4 位小数
python
return int(momentum * 10000) / 10000特点分析
优点:
- 计算简单、直观,无需复杂数学
- 计算速度快,适合大规模标的快速排序
缺点:
- 仅看"起点"和"终点",忽略了中间走势
- 对极端值非常敏感:N 天前若恰好是某次暴跌低点,会虚高动量分数
- 无法区分"稳健上涨"和"大起大落后持平"
示例:
| 资产 | N天前价格 | 今日价格 | 简单动量 | 实际走势 |
|---|---|---|---|---|
| A | 100 | 130 | +30% | 稳定上涨 ✅ |
| B | 80 | 104 | +30% | 暴跌后缓慢反弹 ❌ |
两者得分相同,但 B 的实际走势远弱于 A。这正是简单动量的局限所在。
分时版(简单动量分时版)
与普通版的区别: 不再取 N 天前的收盘价,而是取 N 天前同一分钟时刻 M 的价格作为基准价,当前价格也同样取今日 M 时刻的价格。
计算公式
简单动量(分时版)= (P_今日M时刻 - P_N天前M时刻) / P_N天前M时刻其中:
P_今日M时刻— 今日 M 时间点(如 10:00)的分钟级价格,(实时动量计算工具取当前价格)P_N天前M时刻— N 个交易日前同一时间点 M 的分钟级价格
适用场景
- 策略在日内固定时点执行调仓(如每日 10:00、14:30 等)
- 希望避免使用收盘价,减少尾盘集中交易带来的滑点干扰
- 基于日内同一时刻的价格序列进行动量比较,保持时间口径一致
二、斜率动量
核心思想
通过对对数价格做线性回归,用回归斜率代表趋势方向与速度,再用 R² 衡量趋势稳定性,最终综合评分:
斜率动量得分 = 年化收益率 × R²相比简单动量,斜率动量同时考虑了趋势强度与趋势的可信度。
计算步骤
第一步:获取收盘价并做对数转换
python
close_prices = df['close'].values[-momentum_period:]
y = np.log(close_prices) # 对数价格
x = np.arange(len(y)) # 时间序列:[0, 1, 2, ..., N-1]为什么用对数?
- 对数收益率具有时间可加性,连续多日收益可以直接累加
- 更好地处理复利效应,价格变化更接近正态分布
第二步:等权线性回归
python
slope, intercept = np.polyfit(x, y, 1)对 N 个 (时间, 对数价格) 数据点拟合一条直线 y = slope × x + intercept。
slope(斜率):每个交易日的对数收益率intercept(截距):趋势线的起始位置
所有数据点权重相同,平等对待历史与近期数据。
第三步:将斜率年化
python
annualized_returns = math.exp(slope * 250) - 1slope × 250= 一年(250个交易日)的累计对数收益率exp(...) - 1= 将对数收益率转换为实际涨幅百分比
示例: 若 slope = 0.002(每天0.2%的对数增长),则年化收益率 = exp(0.5) − 1 ≈ 64.87%
第四步:计算 R²(趋势拟合优度)
python
y_pred = slope * x + intercept
ss_residual = np.sum((y - y_pred) ** 2) # 残差平方和
ss_total = np.sum((y - np.mean(y)) ** 2) # 总平方和
r_squared = 1 - (ss_residual / ss_total)R² 的含义:
- R² → 1:价格走势几乎完美贴合趋势线,趋势非常稳定
- R² → 0:价格走势杂乱,趋势线几乎没有解释力
第五步:综合评分
python
slope_momentum = annualized_returns * r_squared
return int(slope_momentum * 10000) / 10000示例对比:
| 资产 | 年化收益率 | R² | 斜率动量得分 | 说明 |
|---|---|---|---|---|
| A | 50% | 0.90 | 0.45 | 稳定上涨,信号可靠 ✅ |
| B | 80% | 0.40 | 0.32 | 高收益但走势混乱 |
| C | 20% | 0.95 | 0.19 | 趋势稳定但涨速慢 |
资产 A 综合得分最高,因为它兼具较高的收益率与趋势稳定性。
分时版(斜率动量分时版)
与普通版的区别: 不再使用过去 N 天的收盘价序列,而是取过去 N 个交易日中每天同一时间点 M 的分钟级价格,构成 N 个价格数据点后再做对数转换与线性回归。
计算步骤
第一步:获取每日 M 时刻价格并做对数转换
python
# 取过去 N 个交易日中每天 M 时刻(如 10:00)的价格
intraday_prices = [day_data.loc[M, 'price'] for day_data in last_N_days]
y = np.log(intraday_prices) # 对数转换
x = np.arange(len(y)) # 时间序列:[0, 1, 2, ..., N-1]后续步骤与普通斜率动量完全相同: 等权线性回归 → 斜率年化 → 计算 R² → 综合评分。
与普通斜率动量的对比
| 对比项 | 斜率动量(普通版) | 斜率动量(分时版) |
|---|---|---|
| 价格来源 | 每日收盘价 | 每日固定时刻 M 的分钟级价格 |
| 数据个数 | 过去 N 天的 N 个收盘价 | 过去 N 天中每天 M 时刻的 N 个价格 |
| 回归方式 | 等权线性回归 | 等权线性回归(完全相同) |
| 适用场景 | 收盘后调仓 | 日内固定时点调仓 |
适用场景
- 策略在日内固定时点(如每日开盘 30 分钟后)触发调仓信号
- 希望动量评分与实际成交时刻的价格口径保持一致,避免收盘价与调仓价之间的偏差
- 通过分时价格序列更精准地捕捉日内趋势的方向与稳定性
三、加权斜率动量
核心思想
与斜率动量完全相同,唯一的区别在于线性回归时为近期数据赋予更高权重,使动量评分更加偏重最近的价格走势。
权重:从 1 到 2 线性增长(最旧数据 → 最新数据)与斜率动量的区别
| 对比项 | 斜率动量 | 加权斜率动量 |
|---|---|---|
| 数据权重 | 所有时间点相同 | 近期权重是早期的 2 倍 |
| 趋势敏感性 | 中等 | 更高(对近期变化反应更快) |
| 抗噪能力 | 较强 | 略弱(更容易受近期波动影响) |
| 适用周期 | 中长期(60天以上) | 短中期(30天以内) |
计算步骤
第一步:构造权重序列
python
weights = np.linspace(1, 2, len(y))- 最旧数据的权重 = 1.0
- 最新数据的权重 = 2.0
- 中间数据线性插值
直觉理解: 对 60 天的回看窗口,第 1 天的影响力是第 60 天的一半,系统认为近期走势比远期走势更能代表当前动量。
第二步:加权线性回归
python
slope, intercept = np.polyfit(x, y, 1, w=weights)用带权重的最小二乘法拟合,近期数据对斜率的贡献更大。
第三步:年化收益率(与斜率动量相同)
python
annualized_returns = math.exp(slope * 250) - 1第四步:加权 R²
python
y_pred = slope * x + intercept
weights = np.linspace(1, 2, len(y))
ss_residual = np.sum(weights * (y - y_pred) ** 2)
ss_total = np.sum(weights * (y - np.mean(y)) ** 2)
r_squared = 1 - (ss_residual / ss_total)注意:R² 的计算也需要加权,确保评估标准与回归过程一致。
第五步:综合评分(与斜率动量相同)
python
slope_momentum = annualized_returns * r_squared分时版(加权斜率动量分时版)
与普通版的区别: 不再使用过去 N 天的收盘价序列,而是取过去 N 个交易日中每天同一时间点 M 的分钟级价格,构成 N 个价格数据点后再做对数转换与加权线性回归。
计算步骤
第一步:获取每日 M 时刻价格并做对数转换
python
# 取过去 N 个交易日中每天 M 时刻(如 10:00)的价格
intraday_prices = [day_data.loc[M, 'price'] for day_data in last_N_days]
y = np.log(intraday_prices) # 对数转换
x = np.arange(len(y)) # 时间序列:[0, 1, 2, ..., N-1]后续步骤与普通加权斜率动量完全相同: 构造线性权重序列 → 加权线性回归 → 斜率年化 → 计算加权 R² → 综合评分。
与普通加权斜率动量的对比
| 对比项 | 加权斜率动量(普通版) | 加权斜率动量(分时版) |
|---|---|---|
| 价格来源 | 每日收盘价 | 每日固定时刻 M 的分钟级价格 |
| 数据个数 | 过去 N 天的 N 个收盘价 | 过去 N 天中每天 M 时刻的 N 个价格 |
| 回归方式 | 加权线性回归(近期权重更高) | 加权线性回归(完全相同) |
| 适用场景 | 收盘后调仓 | 日内固定时点调仓 |
选择建议
- 短周期(≤ 30 天):建议使用加权斜率动量,能更快响应近期趋势转变
- 长周期(≥ 60 天):斜率动量更稳健,避免被短期波动误导
- 可以同时计算两种动量,构建多周期评分体系:
python
score_short = calculate_slope_momentum(df, 20, use_weighted_regression=True)
score_medium = calculate_slope_momentum(df, 60, use_weighted_regression=False)
final_score = 0.6 * score_short + 0.4 * score_medium四、RSRS 动量
核心思想
RSRS(Resistance Support Relative Strength,阻力支撑相对强度)是一种基于最高价与最低价之间关系的动量指标,并通过历史 Z-Score 标准化,使得跨标的、跨时期的比较更加客观。
详细原理参见:RSRS 指标详解
RSRS 动量得分 = 当期 RSRS 值相对过去历史分布的标准分(Z-Score)
计算步骤
第一步:确定所需数据长度
python
standardization_period = rsrs_period * 2
required_length = standardization_period + rsrs_periodRSRS 动量需要比其他动量更多的历史数据:
rsrs_period:计算单期 RSRS 值的回看窗口(即用于线性回归的天数)standardization_period:用于历史标准化的 RSRS 值个数(= rsrs_period × 2)required_length:总共所需的最少历史数据长度
第二步:计算每日 RSRS 值序列
对每个时间点 i,取过去 rsrs_period 天的数据做以下计算:
以最低价(Low)为自变量 X,最高价(High)为因变量 Y,进行线性回归:
python
mean_low = np.mean(window_low)
mean_high = np.mean(window_high)
cov = np.mean((window_low - mean_low) * (window_high - mean_high))
var_low = np.mean((window_low - mean_low) ** 2)
slope = cov / var_low # 回归斜率 β计算 R²:
python
ss_res = np.sum((window_high - (mean_high + slope * (window_low - mean_low))) ** 2)
ss_tot = np.sum((window_high - mean_high) ** 2)
r_squared = 1 - (ss_res / ss_tot)计算当日 RSRS 值(仅在通过质量过滤后赋值):
python
# 过滤极端斜率(排除异常市场)和低拟合度(排除无规律窗口)
if (slope_lower_limit <= slope <= slope_upper_limit) and (r_squared >= r_squared_threshold):
rsrs_values[i] = slope * r_squaredRSRS 原始值 = 斜率 × R²,同时考虑了支撑/阻力关系的强度与可信度。
第三步:取当前 RSRS 值
python
current_rsrs = rsrs_values[-1]若当前值为 NaN(数据不足或未通过质量过滤),则返回 0。
第四步:Z-Score 标准化
python
rsrs_for_std = rsrs_values[-(standardization_period + 1):-1] # 不含当前值
valid_rsrs = rsrs_for_std[~np.isnan(rsrs_for_std)]
mean_rsrs = np.mean(valid_rsrs)
std_rsrs = np.std(valid_rsrs)
standardized_rsrs = (current_rsrs - mean_rsrs) / std_rsrsZ-Score 的意义:
Z-Score = (当期 RSRS - 历史均值μ) / 历史标准差σ- Z > 0:当前趋势强度高于历史均值
- Z > 1.5:趋势处于历史极强水平,可能超买
- Z < −1.5:趋势处于历史极弱水平,可能超卖
- 标准化后的得分无量纲,可以直接跨标的比较
RSRS 动量的独特优势
- 微观结构视角:通过最高价与最低价的关系,刻画市场的支撑强度与上涨弹性,而非仅看收盘价
- 历史标准化:Z-Score 消除了不同标的之间的绝对值差异,使排名更公平
- 质量过滤:R² 阈值和斜率上下限自动剔除异常信号,避免噪音干扰
五、四种方式综合对比
计算复杂度与信息量
简单动量 → 只用两个价格点,信息量最少
斜率动量 → 用全周期收盘价做回归,信息量中等
加权斜率动量 → 同上,但偏重近期,时效性更强
RSRS 动量 → 用全周期最高/最低价 + 历史标准化,信息量最丰富适用场景速查
| 场景 | 推荐方式 |
|---|---|
| 快速筛选,计算量敏感 | 简单动量 |
| 中长期 ETF 轮动(60天以上) | 斜率动量 |
| 短中期 ETF 轮动(30天以内) | 加权斜率动量 |
| 对择时精度要求高的策略 | RSRS 动量 |
| 多因子组合评分 | 混合使用以上多种 |
信号稳定性对比
当市场出现短期剧烈震荡时,四种动量的表现:
- 简单动量:波动最剧烈,容易产生虚假信号
- 斜率动量:线性回归平滑了噪音,信号较稳定
- 加权斜率动量:近期敏感,对趋势转折反应更快,但震荡时也更容易误判
- RSRS 动量:Z-Score 标准化 + 质量过滤,综合稳定性最佳
六、总结
四种动量计算方式本质上是一个从简到繁、从粗到精的光谱:
- 简单动量:快,粗糙,适合初步排序
- 斜率动量:兼顾收益率与趋势稳定性,适合中长期策略
- 加权斜率动量:在斜率动量基础上偏重近期,适合短中期策略
- RSRS 动量:利用价格微观结构与历史标准化,适合对精度要求更高的策略
在实际应用中,可以将多种动量指标组合使用,构建更全面的资产评分体系,以应对不同的市场风格。