一句话回答: EMV(Ease of Movement,简易波动指标)把「价格移动的幅度」和「推动它所需的成交量」结合起来,衡量股价上涨/下跌是不是「轻松」——放小量就能涨说明上行轻松(EMV 高),放大量才涨一点说明滞涨(EMV 低)。用 AlphaFeed 取回前复权日线的 high/low/volume 后,几行 pandas 就能算出 EMV 与其均线,不需要 TA-Lib。
只看涨跌幅看不出「涨得费不费力」。同样涨 2%,缩量上涨(轻松)和放巨量才涨(滞涨、可能出货)意义完全不同。EMV 用量价关系量化这种「难易度」。坑在于:一是要用前复权价,否则除权跳空污染幅度;二是成交量量纲影响 EMV 数值大小,需要缩放,判断时看方向与零轴而非绝对值。
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"(前复权),避免除权跳空。
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))参数与含义:
参数/字段 | 含义 | 常用值 |
|---|---|---|
| EMV 平滑周期 | 14 |
| 成交量缩放(让数值适中) | 按品种调,如 1e5 |
| 上行轻松(缩量能涨) | 偏多 |
| 下行轻松/上行滞涨 | 偏空 |
零轴上穿 | 由滞涨转为轻松上行 | 转强信号 |
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 未创新高")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)vol_scale 影响,不同品种/缩放下量级不同,关注正负与零轴穿越、趋势。high == low(一字板/停牌)会让 box 分母为 0,需剔除或置 NaN。volume 以手计,缩放系数按品种调到 EMV 数值适中即可。n=14 + 均线需要预热,count 建议 ≥ 40,忽略头部 NaN。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 删除。