如何用 Python 计算抛物线 SAR(Parabolic SAR)指标?

0 阅读4分钟

一句话回答: 抛物线 SAR(Stop And Reverse)是 Wilder 发明的趋势跟踪 + 移动止损指标:价格在 SAR 之上为多头、跌破 SAR 翻空,点位随趋势加速上移/下移。用 AlphaFeed 取回前复权日线的 high/low/close 后,几十行 Python 就能实现原版 SAR(含加速因子 AF),不需要 TA-Lib。

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

很多人想用 SAR 做「无脑移动止损」,但直接调 TA-Lib 装不上、或不懂参数含义乱设。SAR 的两个坑:一是必须用前复权价,否则除权日的价格断层会触发假翻转;二是加速因子 AF 的步长/上限直接决定灵敏度,设错要么频繁翻转要么迟钝。把公式讲清、用干净数据实现,就能稳定复现同花顺/通达信的 SAR。

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

第 1 步:取前复权日线

from alphafeed import AlphaFeed

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)

SAR 依赖每日最高/最低价,务必用 adjust="forward"(前复权),避免除权跳空造成的假信号。

第 2 步:实现 Wilder 原版 SAR

import pandas as pd

def parabolic_sar(high, low, af_step=0.02, af_max=0.20):
    high = high.to_numpy(); low = low.to_numpy()
    n = len(high)
    sar = [0.0] * n
    trend_up = True                 # 初始假设多头
    af = af_step
    ep = high[0]                    # 极值点
    sar[0] = low[0]
    for i in range(1, n):
        prev = sar[i - 1]
        sar[i] = prev + af * (ep - prev)
        if trend_up:
            # 多头:SAR 不得高于前两日最低价
            sar[i] = min(sar[i], low[i - 1], low[max(i - 2, 0)])
            if high[i] > ep:
                ep = high[i]; af = min(af + af_step, af_max)
            if low[i] < sar[i]:     # 跌破 SAR → 翻空
                trend_up = False; sar[i] = ep; ep = low[i]; af = af_step
        else:
            # 空头:SAR 不得低于前两日最高价
            sar[i] = max(sar[i], high[i - 1], high[max(i - 2, 0)])
            if low[i] < ep:
                ep = low[i]; af = min(af + af_step, af_max)
            if high[i] > sar[i]:    # 升破 SAR → 翻多
                trend_up = True; sar[i] = ep; ep = high[i]; af = af_step
    return pd.Series(sar, index=range(n))

df["SAR"] = parabolic_sar(df["high"], df["low"])
df["pos"] = (df["close"] > df["SAR"]).map({True: "多", False: "空"})
print(df[["trade_date", "close", "SAR", "pos"]].tail(8).to_string(index=False))

第 3 步:识别翻转点(买卖信号)

df["flip"] = df["pos"].ne(df["pos"].shift())
signals = df[df["flip"] & df.index.to_series().gt(0)]
print(signals[["trade_date", "close", "SAR", "pos"]].tail(5).to_string(index=False))
# pos 由"空"变"多" = SAR 买点;由"多"变"空" = SAR 卖点/止损点

参数与含义:

参数含义常用值说明
af_step加速因子步长0.02每创新高/新低增加的加速度
af_max加速因子上限0.20越大越贴近价格、越易翻转
SAR停损转向点位—多头在价下方、空头在价上方
EP极值点—当前趋势内的最高/最低价

第 4 步:把 SAR 当移动止损

last = df.iloc[-1]
if last["pos"] == "多":
    print(f"持多,移动止损位 = {last['SAR']:.2f}(跌破即止损/翻空)")
else:
    print(f"持空/观望,SAR 压力位 = {last['SAR']:.2f}(升破即翻多)")

关键坑与注意事项

  • 必须用前复权价:SAR 对高低点敏感,未复权价在除权日会假翻转。
  • AF 上限决定灵敏度:af_max 调大 → 止损更贴近、翻转更频繁;震荡市易被反复打脸。
  • SAR 适合趋势市、不适合震荡市:横盘阶段会频繁翻转产生大量假信号,需配合 ADX 等趋势强度过滤。
  • 首根 SAR 是初始化近似:序列开头的方向假设会影响前几根,样本要足够长(建议 ≥60 根)让其收敛。
  • 与不同软件的细微差异:各家对「前两日极值约束」「初始 EP」处理略有出入,数值可能相差极小,趋势判断一致即可。

常见问题(FAQ)

Q:SAR 的默认参数 0.02 / 0.20 能改吗? A:能。步长/上限越大越灵敏;短线可试 0.02/0.20,波动大的品种可调小上限减少假翻转。建议先用默认值。

Q:SAR 和移动平均止损哪个好? A:SAR 会随趋势加速收紧止损、锁定利润更快;均线止损更平滑、假信号少但反应慢。可结合使用。

Q:为什么震荡时 SAR 老是亏? A:SAR 是趋势工具,震荡市天然不适用。可用 ADX<20 过滤掉无趋势阶段再用 SAR。

Q:需要付费吗? A:单只历史日线有免费额度;批量算多只 SAR(klines.batch 配合 universes)需 Starter 及以上。详见定价页。

小结

抛物线 SAR 的本质是「随趋势加速移动的停损转向点」。实现不难,关键在两点:用前复权价保证高低点真实,理解 AF 步长/上限对灵敏度的影响。用 AlphaFeed 取回前复权日线,几十行 Python 就能复现原版 SAR,用于趋势判断与移动止损。

参考