最近在模拟盘测试海龟策略,对vnpy2.1.6版自带海龟策略的以下代码有所疑问:
def on_trade(self, trade: TradeData):
"""
Callback of new trade data update.
"""
if trade.direction == Direction.LONG:
self.long_entry = trade.price
self.long_stop = self.long_entry - 2 * self.atr_value
else:
self.short_entry = trade.price
self.short_stop = self.short_entry + 2 * self.atr_value
上面代码定义了收到成交回报时所做的处理,即有新的成交时,立即设置对应的止损价。
从逻辑上看,有两点存疑:
1.上述处理没有区分成交是开仓还是平仓。如果是开仓,则没有问题。但如果是平仓,实际上是不应该这这里设置止损价的。比方原有一个在5000价位开的多单,止损价原来设置的为4950。当价格跌到4950时,通过一个空单平仓了所开的多单。根据以上代码逻辑,这个时候会设置一个对应空单(就是在4950成交的平多单)的止损价。假设是50点的止损,那么这个止损单会设置在5000。那么当价格涨到5000时,会自动开一个买单(根据on_bar逻辑,假设pos不空时,会在on_bar里产生这个买单)。但实际上这个买单是不应该开的。
2.如果成交的是开仓,上述代码只是设置了止损价,并没有立刻生成对应的停损单,而是要等到下一根K线产生时,才会在on_bar里生成对应的停损单。假设策略的周期是日线,当天开了仓,则需要等到第二天才能生成停损单。如果当天发生了黑天鹅事件,那么损失会很可怕。所以在开仓完后,不光要生成止损价,而且需要立刻设置对应的停损单。
以上是在阅读代码以及测试策略所发现的两个问题,我对on_trade做了个修改:
def on_trade(self, trade: TradeData):
"""
Callback of new trade data update.
"""
# 只在开仓时设置止损价格
if not (trade.offset == Offset.OPEN):
return
# 如果有开仓,则立刻设置对应的止损单
if trade.direction == Direction.LONG:
self.long_entry = trade.price
self.long_stop = self.long_entry - 2 * self.atr_value
print("%s: 多单成交价格:long_entry = %.1f" % (self.vt_symbol, self.long_entry))
print("%s: 设置多单的止损价格:long_stop = %.1f" % (self.vt_symbol, self.long_stop))
# 计算多单的止损价
sell_price = max(self.long_stop, self.exit_down)
# 如果有多头仓位,则设置多单的止损单
print("long_stop = %d, self.exit_down = %d" % (self.long_stop, self.exit_down))
print("%s: in on_trade(), 设置多头止损单,sell_price:%.1f, vol:%d" % (
self.vt_symbol, sell_price, abs(trade.volume)))
self.sell(sell_price, abs(trade.volume), True)
elif trade.direction == Direction.SHORT:
self.short_entry = trade.price
self.short_stop = self.short_entry + 2 * self.atr_value
print("%s: 空单成交价格:short_entry = %.1f" % (self.vt_symbol, self.short_entry))
print("%s: 设置空单的止损价格:short_stop = %.1f" % (self.vt_symbol, self.short_stop))
# 计算空单的止损价
cover_price = min(self.short_stop, self.exit_up)
# 如果有空头仓位,则设置空单的止损单
print("short_stop = %d, self.exit_up = %d" % (self.short_stop, self.exit_up))
print("%s: in on_trade(), 设置空头止损单,cover_price:%.1f, vol:%d" % (
self.vt_symbol, cover_price, abs(trade.volume)))
self.cover(cover_price, abs(trade.volume), True)
上述代码大家也可以一起来做个检查,看看是否有不妥之处。