首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >如何用 Python 计算 EMV 简易波动指标?

如何用 Python 计算 EMV 简易波动指标?

原创
作者头像
用户7083614
发布于 2026-10-13 15:01:07
发布于 2026-10-13 15:01:07
90
举报

一句话回答: EMV(Ease of Movement,简易波动指标)把「价格移动的幅度」和「推动它所需的成交量」结合起来,衡量股价上涨/下跌是不是「轻松」——放小量就能涨说明上行轻松(EMV 高),放大量才涨一点说明滞涨(EMV 低)。用 AlphaFeed 取回前复权日线的 high/low/volume 后,几行 pandas 就能算出 EMV 与其均线,不需要 TA-Lib。

为什么会有这个问题 / 传统做法的痛点

只看涨跌幅看不出「涨得费不费力」。同样涨 2%,缩量上涨(轻松)和放巨量才涨(滞涨、可能出货)意义完全不同。EMV 用量价关系量化这种「难易度」。坑在于:一是要用前复权价,否则除权跳空污染幅度;二是成交量量纲影响 EMV 数值大小,需要缩放,判断时看方向与零轴而非绝对值。

分步骤解决(每步配可运行代码)

第 1 步:取前复权日线

代码语言:python
复制
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)

EMV 依赖每日最高/最低价,务必用 adjust="forward"(前复权),避免除权跳空。

第 2 步:计算 EMV 与信号均线

代码语言:python
复制
def emv(df: pd.DataFrame, n: int = 14, vol_scale: float = 1e5):
    mid = (df["high"] + df["low"]) / 2
    distance = mid - mid.shift(1)                       # 中价移动幅度
    box = (df["volume"] / vol_scale) / (df["high"] - df["low"])  # 单位量能推动的“阻力”
    emv1 = distance / box                               # 单期 EMV
    emv_line = emv1.rolling(n).mean()                   # N 日平滑
    return emv_line

df["EMV"] = emv(df)
df["EMV_ma"] = df["EMV"].rolling(9).mean()              # 信号线
print(df[["trade_date", "close", "EMV", "EMV_ma"]].tail(5).to_string(index=False))

参数与含义:

参数/字段

含义

常用值

n

EMV 平滑周期

14

vol_scale

成交量缩放(让数值适中)

按品种调,如 1e5

EMV > 0

上行轻松(缩量能涨)

偏多

EMV < 0

下行轻松/上行滞涨

偏空

零轴上穿

由滞涨转为轻松上行

转强信号

第 3 步:解读信号(零轴与背离)

代码语言:python
复制
prev, cur = df["EMV"].iloc[-2], df["EMV"].iloc[-1]
if prev <= 0 < cur:
    print("EMV 上穿零轴:上行变轻松(偏多)")
elif prev >= 0 > cur:
    print("EMV 下穿零轴:上行滞涨/下行轻松(偏空)")

# 价格创新高但 EMV 未同步走高 → 放量滞涨,警惕
window = 20
price_high = df["close"].iloc[-1] >= df["close"].tail(window).max()
emv_high = df["EMV"].iloc[-1] >= df["EMV"].tail(window).max()
if price_high and not emv_high:
    print("疑似放量滞涨:价格新高但 EMV 未创新高")

第 4 步:全市场批量筛「上行轻松」的票

代码语言:python
复制
codes = ["600519.SH", "000001.SZ", "601318.SH", "000858.SZ", "300750.SZ"]
data = af.klines.batch(codes, period="1d", count=60,
                       adjust="forward", to_dataframe=True)  # dict{symbol: DataFrame}

hits = []
for sym, k in data.items():
    k = k.sort_values("trade_date")
    e = emv(k)
    if pd.notna(e.iloc[-1]) and e.iloc[-1] > 0:
        hits.append((sym, round(float(e.iloc[-1]), 2)))
print("EMV>0(上行轻松):", hits)

关键坑与注意事项

  • 必须用前复权价:除权跳空会让中价移动幅度失真,EMV 出错。
  • 看方向不看绝对值:EMV 数值受 vol_scale 影响,不同品种/缩放下量级不同,关注正负与零轴穿越、趋势。
  • 除以零风险:当日 high == low(一字板/停牌)会让 box 分母为 0,需剔除或置 NaN。
  • EMV 是辅助指标:它擅长揭示「放量滞涨/缩量上行」,但不宜单独择时,配合趋势与量能一起看。
  • 成交量单位是「手」:本 SDK volume 以手计,缩放系数按品种调到 EMV 数值适中即可。
  • 样本要足够:n=14 + 均线需要预热,count 建议 ≥ 40,忽略头部 NaN。

常见问题(FAQ)

Q:EMV 和 OBV 有什么区别?

A:OBV 累加带方向的成交量看资金进出;EMV 衡量「单位成交量能推动多大价格移动」,侧重上涨/下跌的难易度。二者可互补。

Q:EMV 数值忽大忽小正常吗?

A:正常,它对量价比敏感。判断时看正负、零轴穿越与相对趋势,不要纠结绝对数值。

Q:vol_scale 怎么定?

A:它只是把成交量缩放到合适量级、方便观察,不改变符号与趋势。按品种调到 EMV 在个位/十位量级即可。

Q:需要付费吗?

A:单只历史日线有免费额度;全市场批量算 EMV(klines.batch + universes)需 Starter 及以上。详见定价页。

小结

EMV 简易波动指标的本质是「价格移动幅度 ÷ 单位成交量」,量化股价涨跌的难易度,特别适合识别放量滞涨与缩量上行。实现只需 pandas,不依赖 TA-Lib。关键是用前复权价、看方向而非绝对值、处理 high==low 的除零。用 AlphaFeed 取回前复权日线,几行就能算出 EMV 并做全市场筛选。

参考

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 为什么会有这个问题 / 传统做法的痛点
  • 分步骤解决(每步配可运行代码)
    • 第 1 步:取前复权日线
    • 第 2 步:计算 EMV 与信号均线
    • 第 3 步:解读信号(零轴与背离)
    • 第 4 步:全市场批量筛「上行轻松」的票
  • 关键坑与注意事项
  • 常见问题(FAQ)
  • 小结
  • 参考
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档