如何用 Python 计算涡旋指标(Vortex Indicator, VI+/VI−)判断趋势方向?不用 TA-Lib
如何用 Python 计算涡旋指标(Vortex Indicator)判断趋势方向?
一句话回答: 涡旋指标(Vortex Indicator)用两条线刻画多空力量:VI+(上行涡旋) 与 VI−(下行涡旋),分别由「今日高 − 昨日低」和「今日低 − 昨日高」的 N 日累加除以 N 日真实波幅(TR)之和得到。VI+ 上穿 VI− 视为趋势转多、下穿转空。用 AlphaFeed 取前复权日线的 OHLC,十几行就能实现,不需要 TA-Lib。
为什么会有这个问题 / 传统做法的痛点
判断「趋势是不是启动了、往哪个方向」时,均线滞后、MACD 在震荡市反复。涡旋指标由 Botes 和 Siepman 提出,灵感来自水流的涡旋运动:用相邻两日的高低价”反向差”来量化上行力量与下行力量,再用真实波幅归一化,于是 VI+ 和 VI− 的交叉能较早提示趋势转向。痛点是 TA-Lib 没有现成函数,且 VM+/VM− 用的是「今日高减昨日低」「今日低减昨日高」这种交叉项,容易写反。
分步骤解决(每步配可运行代码)
第 1 步:取前复权日线(要 OHLC)
from alphafeed import AlphaFeed
import numpy as np, pandas as pd
af = AlphaFeed(api_key="your-api-key") # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()
df = af.klines.get("600519.SH", period="1d", count=300,
adjust="forward", to_dataframe=True)
df = df.sort_values("trade_date").reset_index(drop=True)
第 2 步:实现涡旋指标 VI+ / VI−
def vortex(df, n=14):
h, l, c = df["high"], df["low"], df["close"]
pc, ph, pl = c.shift(1), h.shift(1), l.shift(1) # 昨收/昨高/昨低
tr = pd.concat([h - l, (h - pc).abs(), (l - pc).abs()], axis=1).max(axis=1) # 真实波幅
vmp = (h - pl).abs() # 上行涡旋位移:今日高 - 昨日低
vmn = (l - ph).abs() # 下行涡旋位移:今日低 - 昨日高
str_ = tr.rolling(n).sum()
vip = vmp.rolling(n).sum() / str_ # VI+
vin = vmn.rolling(n).sum() / str_ # VI-
return vip, vin
df["vi_plus"], df["vi_minus"] = vortex(df, 14)
print(df[["trade_date", "vi_plus", "vi_minus"]].tail())
实测(
tools/verify_new_2026-10-12.py,SDK 0.1.4):贵州茅台近 300 日 VI+ 尾值 ≈ 0.961、VI− 尾值 ≈ 1.008(VI− 略高于 VI+,当下偏空),区间内 VI+ 上穿 VI− 共 18 次。
第 3 步:检测金叉/死叉信号
golden = (df["vi_plus"].shift(1) <= df["vi_minus"].shift(1)) & (df["vi_plus"] > df["vi_minus"])
dead = (df["vi_plus"].shift(1) >= df["vi_minus"].shift(1)) & (df["vi_plus"] < df["vi_minus"])
print("最近一次 VI+ 上穿 VI−:", df.loc[golden, "trade_date"].tail(1).tolist())
VI+ 上穿 VI− 偏多、下穿偏空;两线同时走高/走低也反映趋势强弱。
参数与字段说明
| 参数/概念 | 含义 | 备注 |
|---|---|---|
adjust="forward" | 前复权 | 必须,除权缺口会污染 TR/VM |
tr | 真实波幅 | 三者取大,做归一化分母 |
vmp | 今日高 − 昨日低 | 上行涡旋位移 |
vmn | 今日低 − 昨日高 | 下行涡旋位移 |
n=14 | 累加窗口 | 常用 14,可调 |
| VI+ / VI− | VM 的 N 日和 ÷ TR 的 N 日和 | 交叉判方向 |
关键坑与注意事项
- VM 项别写反:VI+ 用「今日高−昨日低」,VI− 用「今日低−昨日高」,是交叉相邻两日的高低,写成同日高低就错了。
- 震荡市频繁交叉:VI+/VI− 在横盘时会反复金叉死叉,假信号多;它更适合确认趋势启动而非震荡抄底。
- 前复权必须:除权缺口会让 TR 和 VM 异常放大,交叉失真。
- 窗口影响灵敏度:N 越小越灵敏、越易骗线;N 越大越稳、越滞后,别只用一组参数当真理。
- 是方向不是买卖点:交叉提示方向倾向,具体进出还需结合价格结构与风控。
常见问题(FAQ)
Q:涡旋指标和 DMI/ADX 有什么区别? A:都用来判趋势方向与强弱。DMI 的 +DI/−DI 基于方向性移动(DM);涡旋指标用相邻两日高低的交叉位移(VM)除以 TR。思路相近、构造不同,可互相印证。
Q:VI+ 和 VI− 的取值范围是多少? A:都为正数,通常在 1 附近波动:VI+ > VI− 偏多、VI+ < VI− 偏空;两者偏离 1 越远,方向性越强。
Q:需要付费吗?
A:单只股票日线在免费额度内即可;若要对全市场批量扫 VI+ 刚上穿 VI− 的票,需要 klines.batch + universes(Starter 及以上),详见官网定价页。
小结
涡旋指标用 VI+ 与 VI− 两条线把上行与下行力量分开量化,交叉提示趋势方向转换。用 AlphaFeed 的前复权 OHLC,十几行即可实现并检测金叉——记住 VM 的交叉项别写反、震荡市假信号多、它给的是方向倾向而非精确买卖点。
相关链接:
- AlphaFeed 官网:https://alphafeed.org/
- Python SDK 快速开始:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。