博客Blog /

让 Pine Script 警报不重绘、不重复的三个习惯

把 Pine Script 策略接到自动下单之前,我会先检查三件事。它们和策略好不好无关,只和“信号是否可靠”有关。

1. 只在 K 线收盘后发信号

盘中价格还在变动,条件可能这一秒成立、下一秒又不成立。如果警报在盘中触发,你可能已经下了单,图表上的信号却消失了。

最简单的办法,是在条件里加上 barstate.isconfirmed,或者在 alert() 里使用收盘频率:

//@version=6
indicator("Close-only alert", overlay = true)

longCond = ta.crossover(ta.sma(close, 10), ta.sma(close, 30))

if longCond and barstate.isconfirmed
    alert("long signal", alert.freq_once_per_bar_close)

代价是信号会晚到一根 K 线收盘,但换来的是:图表上看到的信号,就是实际发出去的信号。

2. 跨周期取数,只用已经收盘的数据

在 1 小时图上引用日线数据时,很多人会写 request.security(syminfo.tickerid, "D", close)。在历史回测中,这可能会用到当天还没收盘的日线价格,回测结果因此偏好看。

常用的不重绘写法,是取前一根已经收盘的值,并配合 lookahead_on:

dailyClose = request.security(syminfo.tickerid, "D", close[1], lookahead = barmerge.lookahead_on)

这样回测和实盘拿到的都是同一个、已经确定的数字。

3. 每个信号带一个唯一编号

TradingView 的 webhook 偶尔会失败,网络重试也可能让同一条消息到达两次。执行端如果没有办法分辨,就可能重复下单。

我的做法是在消息里加上“品种 + 方向 + K 线时间”组成的编号:

signalId(side) => syminfo.ticker + "-" + side + "-" + str.tostring(time)

服务器收到消息后先查这个编号:没见过就执行,见过就丢弃并记录。之后每天对账,也用同一个编号把信号和券商订单对上。

小结

这三个习惯不会让策略更赚钱,但能让你相信:系统做的,就是你写的。下周我会写服务器端如何处理去重和断线。

本文仅讨论代码写法,不构成投资建议。