如何用 Python 计算 ROC 变动率指标做动量分析?
**一句话回答:** ROC(Rate of Change,变动率)就是「当前价相对 N 日前价的涨跌幅百分比」,公式 `ROC = (close / close.shift(N) - 1) × 100`。用 AlphaFeed 取回**前复权日线**后,一行 pandas 就能算出 ROC,用来衡量动量强弱、识别零轴穿越与顶底背离,还能对全市场做动量排名——完全不需要 TA-Lib。 ## 为什么会有这个问题 / 传统做法的痛点 ROC 是最直观的动量指标:它直接回答「这只票 N 天涨了多少」。但两个坑常被忽略:一是**用未复权价**,遇到除权日 ROC 会出现虚假暴涨暴跌;二是把 ROC 当成孤立信号,忽略了它天生适合做**横截面动量排名**和**背离判断**。用一个稳定的数据源取回前复权价,这两点都能干净解决。 ## 分步骤解决(每步配可运行代码) ### 第 1 步:取前复权日线并计算 ROC ``` from alphafeed import AlphaFeed import pandas as pd af = AlphaFeed() # 读取 ALPHAFEED_API_KEY df = af.klines.get("600519.SH", period="1d", count=250, adjust="forward", to_dataframe=True) df = df.sort_values("trade_date").reset_index(drop=True) def roc(close: pd.Series, n: int = 12) -> pd.Series: return (close / close.shift(n) - 1.0) * 100.0 df["ROC12"] = roc(df["close"], 12) df["ROC25"] = roc(df["close"], 25) print(df[["trade_date", "close", "ROC12", "ROC25"]].tail(5).to_string(index=False)) ``` > 用 `adjust="forward"`(前复权)算 ROC,避免除权日的价格断层污染动量值。 ### 第 2 步:理解参数与信号 |参数/信号|含义|常用取值/解读| | --- | --- | --- | |N(回看周期)|与几日前比较|短线 6/12,中线 25/125| |ROC > 0|价格高于 N 日前|上行动量| |ROC = 0 > cur: print("ROC 下穿零轴:动量转弱") # 平滑 ROC 减少噪音(对 ROC 再做移动平均) df["ROC12_ma"] = df["ROC12"].rolling(6).mean() ``` ### 第 4 步:用 ROC 做全市场动量排名 ROC 天生适合横截面比较——同一 N 下,ROC 越高动量越强。批量取多只股票日线,算 N 日 ROC 后排名: ``` codes = ["600519.SH", "000001.SZ", "300750.SZ", "601318.SH", "000858.SZ"] data = af.klines.batch(codes, period="1d", count=60, adjust="forward", to_dataframe=True) # 返回 dict{symbol: DataFrame} rows = [] for sym, k in data.items(): k = k.sort_values("trade_date") r = (k["close"].iloc[-1] / k["close"].iloc[-21] - 1) * 100 # 20 日 ROC rows.append({"symbol": sym, "ROC20": round(float(r), 2)}) rank = pd.DataFrame(rows).sort_values("ROC20", ascending=False) print(rank.to_string(index=False)) ``` > 想扫全市场?把 `codes` 换成 `af.quotes.get(universes="CN_Stock")` 拿到的 `symbol` 列表,再分批 `klines.batch`(注意请求量,建议本地缓存)。 ### 第 5 步:粗判顶底背离 ``` # 价格创新高但 ROC 未创新高 → 顶背离(动量衰减) window = 20 price_high = df["close"].iloc[-1] >= df["close"].tail(window).max() roc_high = df["ROC12"].iloc[-1] >= df["ROC12"].tail(window).max() if price_high and not roc_high: print("疑似顶背离:价格新高但动量未同步") ``` ## 关键坑与注意事项 - **必须用前复权价**:未复权价在除权日会让 ROC 出现虚假跳变,动量信号失真。 - **N 太小噪音大、太大滞后重**:短线常用 6/12,中长线用 25/125;可对 ROC 再取移动平均降噪。 - **ROC 无上下界**:不同股票、不同波动率下 ROC 数值量级差异大,做横截面排名时同一 N 才可比。 - **背离仅供参考**:背离不是精确择时信号,需结合成交量、趋势与其它指标交叉验证。 - **数据不足会得到 NaN**:`count` 至少要大于 `N`,否则 `shift(N)` 前 N 行为 NaN。 - **ROC 与「N 日涨跌幅」等价**:本质就是区间收益率×100,别把它想得太复杂。 ## 常见问题(FAQ) **Q:ROC 和动量指标 MTM 有什么区别?** A:MTM(动量)用差值 `close - close.shift(N)`,ROC 用比值百分比 `(close/close.shift(N)-1)×100`。ROC 做跨股票比较更合适,因为它是无量纲的百分比。 **Q:ROC 和 RSI 都算动量,用哪个?** A:RSI 有 0~100 的有界区间、适合看超买超卖;ROC 无界、更适合看动量方向与横截面强弱排名。两者可互补。 **Q:为什么我算出来前面几行是 NaN?** A:ROC 需要 N 日前的价格,前 N 行没有可比基准,正常为 NaN;取数时把 `count` 设得比 `N` 大即可。 **Q:需要付费吗?** A:单只历史日线有免费额度;`klines.batch` 全市场动量排名(配合 `universes`)需 Starter 及以上。详见定价页。 ## 小结 ROC 变动率的本质是「N 日区间收益率」,计算只需一行 pandas,不必依赖 TA-Lib。关键是用前复权价保证动量真实、按需要选好 N,并善用它无量纲的特性做全市场动量排名与背离判断。用 AlphaFeed 取回前复权日线,从单股信号到全市场动量梯队都能几行搞定。 ## 参考 - AlphaFeed Python SDK 文档:[https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart](https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart)