【量化进阶】突破 Beta 干扰:如何用 Python  QuantDash 构建“波动率加权动量(Risk-Adjusted Momentum)”多资产选股模型? 在多因子选股和动量轮动策略Momentum Rotation的开发中大部分开发者使用的最基础因子是原始累计收益率Raw Momentum然而在实际运行组合策略时这种纯价格幅度的动量算法存在一个致命的工程缺陷它对高 Beta高波动的标的具有极强的选择偏好。在牛市或强趋势行情中像英伟达NVDA.US这类高波动股票的累计涨幅会天然、无条件地碾压可口可乐等低波动但走势极稳的防御性标的。但在市场风格切换或高位剧烈震荡期这些高波动标的的高额累计收益往往伴随着极大的回撤隐患。为了剔除资产自身波动率的干扰发掘走势最稳健、最具持续性的“真强趋势股”量化业界通常会使用波动率加权动量Risk-Adjusted Momentum也称风险调整后动量。本文将带你手把手使用 Python、Pandas 和QuantDash多市场行情服务构建这套工业级多资产动量特征提取流水线。1. 数学原理为什么“风险调整后动量”更优秀我们要构建的风险调整后动量Risk-Adjusted Momentum其本质是在原始收益率的基础上除以资产在同一时间段内的年化波动率Standard Deviation of Daily Returns。1.1 核心公式对于任意资产 i 在过去 N 个交易日内1.日收益率Daily Return2.年化波动率Annualized Volatilit​​​​3.风险调整后动量因子Risk-Adjusted Momentum Score1.2 数学直觉这个指标的数学形态与**夏普比率Sharpe Ratio**非常相似。如果两只股票在过去 60 天内都涨了 20%股票 A每天波澜不惊天天微涨日收益率标准差极小 σ 低。股票 B中间经历了大涨大跌、多次腰斩和暴涨日收益率标准差极大 σ 高。在原始动量眼中A 和 B 是一样的得分都是 20%。在风险调整后动量眼中A 的得分会远高于 B。因为 A 的上涨过程具有极高的一致性与低回撤特征更适合大资金进行平滑配置。2. 完整实战代码我们使用最新的QuantDash SDK一键拉取跨中美港三大市场的 4 只核心资产腾讯控股、贵州茅台、苹果公司、英伟达最近 100 根前复权日 K 线并利用 Pandas 向量化计算它们的双轨动量得分并进行横截面排序Cross-Sectional Ranking。import os import pandas as pd import numpy as np from quantdash import QuantDash # # 1. 客户端初始化 # QUANTDASH_API_KEY os.getenv(QUANTDASH_API_KEY, your_api_key_here) qd QuantDash(api_keyQUANTDASH_API_KEY) def calculate_risk_adjusted_momentum(symbol, count100): 通过 QuantDash 提取单只标的前复权K线计算原始动量与风险调整后动量 try: # 获取标准前复权 K 线确保数据连续性 df qd.klines.get( symbolsymbol, period1d, countcount, adjustforward, to_dataframeTrue ) except Exception as e: print(f[!] 抓取标的 [{symbol}] 数据失败: {e}) return None if df is None or df.empty: return None # 规整字段名 df.columns [col.lower() for col in df.columns] df df.sort_values(bytrade_date, ascendingTrue).reset_index(dropTrue) # 1. 计算每日收益率 df[daily_return] df[close].pct_change() # 2. 计算累计原始收益率 (Raw Momentum) # 以整个区间 (从 count 天前到最新一天) 的变动百分比作为动量测度 raw_momentum (df[close].iloc[-1] - df[close].iloc[0]) / df[close].iloc[0] # 3. 计算年化波动率 (252个交易日) # 引入 1e-9 极小值防止分母为 0 溢出 daily_vol df[daily_return].std(ddof1) annualized_vol daily_vol * np.sqrt(252) 1e-9 # 4. 计算风险调整后动量 risk_adj_momentum raw_momentum / annualized_vol return { symbol: symbol, raw_momentum: raw_momentum, annualized_vol: annualized_vol, risk_adj_momentum: risk_adj_momentum } def build_momentum_leaderboard(symbols, count100): 对多资产组合进行横截面动量因子排序 results [] for symbol in symbols: res calculate_risk_adjusted_momentum(symbol, countcount) if res: results.append(res) if not results: print([!] 未能成功计算任何标的的动量因子。) return pd.DataFrame() # 构建横截面 DataFrame leaderboard pd.DataFrame(results) # 计算两种动量指标在组合内的排名 (数值越大排名越靠前) leaderboard[raw_rank] leaderboard[raw_momentum].rank(ascendingFalse, methodmin).astype(int) leaderboard[risk_adj_rank] leaderboard[risk_adj_momentum].rank(ascendingFalse, methodmin).astype(int) # 整理列顺序输出 leaderboard leaderboard.sort_values(byrisk_adj_rank, ascendingTrue).reset_index(dropTrue) return leaderboard if __name__ __main__: # 我们选择一个涵盖 A股、港股、美股的主流大类资产测试池 asset_pool [600519.SH, 00700.HK, AAPL.US, NVDA.US] # 设定因子的时间窗口为 100 个交易日 lookback_window 100 print(f[] 正在拉取全球资产池最新 K 线并执行动量模型解构...) leaderboard_df build_momentum_leaderboard(asset_pool, countlookback_window) if not leaderboard_df.empty: # 格式化输出百分比 leaderboard_df[raw_momentum] leaderboard_df[raw_momentum].map(lambda x: f{x*100:.2f}%) leaderboard_df[annualized_vol] leaderboard_df[annualized_vol].map(lambda x: f{x*100:.2f}%) leaderboard_df[risk_adj_momentum] leaderboard_df[risk_adj_momentum].map(lambda x: f{x:.4f}) print(\n *85) print( 跨市场全球核心资产多维动量因子看板 (横截面排序)) print(*85) print(leaderboard_df[[symbol, raw_momentum, raw_rank, annualized_vol, risk_adj_momentum, risk_adj_rank]]) print(*85)3. 运行结果与控制台输出[] 正在拉取全球资产池最新 K 线并执行动量模型解构... 跨市场全球核心资产多维动量因子看板 (横截面排序) symbol raw_momentum raw_rank annualized_vol risk_adj_momentum risk_adj_rank 0 AAPL.US 26.26% 1 26.46% 0.9927 1 1 NVDA.US 14.88% 2 38.23% 0.3892 2 2 600519.SH -7.77% 3 23.34% -0.3328 3 3 00700.HK -15.12% 4 40.80% -0.3705 4 4. 生产环境下的多因子量化实操规范如果你打算将波动率加权动量Risk-Adjusted Momentum应用到实盘轮动基金或指数增强策略中需要遵守以下三条核心指导原则4.1 窗口跨度的自适应匹配Lookback Window短期动量如 20 日、30 日对市场短期情绪和催化剂反应极快但容易频繁产生虚假突破信号。中长期动量如 60 日、120 日、250 日趋势过滤效果极佳。学术界和华尔街大类资产轮动策略中最常采用60日一季度和120日半年作为动量测量区间。4.2 波动率计算的“时间不一致性”防护在计算波动率时如果标的含有长期停牌、涨跌停限制如 A股 10% 限制或者流动性真空时Pandas 的 .std() 会出现虚假低波动。解决策略对于发生过长时间停牌或成交量极度萎缩的交易日不应直接填 0 计入标准差应当采用自适应过滤法剔除无量交易日或者使用帕克Parkinson高低价波动率算法来替代简单的收盘价标准差从而还原真实的波动率。4.3 换仓缓冲带设计Turnover Buffer动量策略的换手率Turnover通常偏高。如果在月末调仓时第 2 名和第 3 名的动量得分仅相差 0.001 导致频繁调换会产生大量的交易手续费Commission和滑点Slippage损耗。缓冲带机制只有当非持仓标的的动量排名显著超越持仓标的例如前两名自动买入但只有当持仓标的跌出前 4 名时才触发平仓换仓才执行交易以此压低摩擦成本。5. 三步开启你的多因子研发克隆完整的多因子轮动回测系统前往官方 GitHub 获取本策略在历史大类资产 ETF如黄金、美债、沪深300上的完整轮动回测源码https://github.com/quantdash-net/QuantDash 欢迎 Star 支持我们的开源工作。申请无积分门槛的 API 密钥即刻注册标准账户解锁跨市场高精度前复权行情调用特权https://quantdash.net/。查阅标准化因子开发手册学习如何通过 QuantDash API 极速提取截面数据与多标的行情对齐https://docs.quantdash.net/。(重要声明本文中所展示的波动率折算模型、因子计算公式以及 Python 数据分析过程仅作为量化技术与特征工程的学术探讨。历史表现不预测未来任何内容均不构成针对具体标的的投资策略与买卖建议。)