一句话回答: SAR(Stop And Reverse)天生是「翻转」信号——价格升破 SAR 做多、跌破 SAR 平仓(A 股无法裸做空,只做多头段)。用 AlphaFeed 取回前复权日线算 SAR,用「当日出信号、次日开盘成交」避免未来函数,扣手续费,几十行就能回测出收益、最大回撤与交易次数,并和买入持有对比检验它值不值。
SAR 常被当「移动止损 + 趋势跟踪」用,但「按 SAR 翻转做多做空到底赚不赚钱」要回测验证。两个常见错误:一是未来函数(当日出信号用当日收盘价成交,实际做不到);二是忽略 A 股限制与手续费(不能裸卖空、换手有成本)。正确做法:前复权价算 SAR、次日开盘成交、只做多头段、扣费、对比基准。
from alphafeed import AlphaFeed
import pandas as pd
af = AlphaFeed() # 读取 ALPHAFEED_API_KEY
df = af.klines.get("600519.SH", period="1d", count=500,
adjust="forward", to_dataframe=True)
df = df.sort_values("trade_date").reset_index(drop=True)
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[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]: trend_up = False; sar[i] = ep; ep = low[i]; af = af_step
else:
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]: 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"])# 收盘价在 SAR 上方=多头持有,下方=空仓(A 股不裸做空)
df["long"] = (df["close"] > df["SAR"]).astype(int)
df["position"] = df["long"].shift(1).fillna(0) # 当日信号,次日才持仓FEE = 0.0013 # 单边约 0.13%(佣金+印花税近似)
df["open_ret"] = df["open"].pct_change().shift(-1) # 持仓吃 t→t+1 开盘间收益
df["trade"] = df["position"].diff().abs().fillna(0) # 换手(建仓/平仓)
df["strat_ret"] = df["position"] * df["open_ret"].fillna(0) - df["trade"] * FEE
df["equity"] = (1 + df["strat_ret"]).cumprod()
df["bench"] = (1 + df["close"].pct_change().fillna(0)).cumprod() # 买入持有基准def stats(equity, rets):
total = equity.iloc[-1] - 1
cagr = equity.iloc[-1] ** (252 / len(equity)) - 1
dd = (equity / equity.cummax() - 1).min()
return total, cagr, dd
t_s, c_s, d_s = stats(df["equity"], df["strat_ret"])
t_b, c_b, d_b = stats(df["bench"], df["close"].pct_change())
trades = int(df["trade"].sum() // 2)
print(f"SAR策略 收益{t_s:.2%} 年化{c_s:.2%} 回撤{d_s:.2%} 交易{trades}次")
print(f"买入持有 收益{t_b:.2%} 年化{c_b:.2%} 回撤{d_b:.2%}")关键参数:
参数 | 含义 | 本文取值 |
|---|---|---|
| SAR 加速因子步长/上限 | 0.02 / 0.20 |
| 单边手续费 | 0.0013 |
成交时点 | 避免未来函数 | 次日开盘 |
方向 | A 股只做多头段 | 空仓代替做空 |
position.shift(1) 实现。Q:为什么不按当日收盘价成交?
A:当日收盘才算出信号,用当日收盘价成交是未来函数。用次日开盘价才真实可执行。
Q:SAR 翻空为什么不做空?
A:A 股个股无法裸做空(融券成本高、标的有限),所以翻空时用空仓代替,只赚多头段。
Q:SAR 策略一定跑赢买入持有吗?
A:不一定。趋势强的品种/区间 SAR 能控回撤,震荡市则因频繁交易而跑输。回测对比才有结论。
Q:需要付费吗?
A:单只历史日线有免费额度;多标的批量回测(klines.batch + universes)需 Starter 及以上。详见定价页。
SAR 翻转策略回测的关键在严谨性:前复权价算 SAR、次日开盘成交避免未来函数、A 股只做多头段、扣手续费、和买入持有对比。用 AlphaFeed 取回前复权日线,几十行 Python 就能客观检验这套经典趋势跟踪信号在具体品种上到底值不值。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。