新手,想请教在vnpy_ctastrategy策略中,如果获取当前的未成交挂单?
策略很简单,在开市时发出一个限价委托,为了避免重复报单,发出委托之前,获取下当前有哪些挂单,如果有未成交的挂单,则不再重复报单。
查看了cta_strategy的源代码,还是有些看不懂,是不是要注册OmsEngine才可以实现这个功能?
新手,想请教在vnpy_ctastrategy策略中,如果获取当前的未成交挂单?
策略很简单,在开市时发出一个限价委托,为了避免重复报单,发出委托之前,获取下当前有哪些挂单,如果有未成交的挂单,则不再重复报单。
查看了cta_strategy的源代码,还是有些看不懂,是不是要注册OmsEngine才可以实现这个功能?
谢谢回复。
此前学习过此贴,也采用了类似的方法,但在运行策略时,仍然遇到了问题。
策略很简单,在压力位做空,支撑位做多,每次只交易1手。由于希望能较早成交,于是采取提前挂单,进入排队的方式。
策略启动后,在开仓又平仓了一手之后,代码就报错了,在这句”active_order = self.active_orders[self.orderids[0]] “ 报错KeyError。
反复查看代码逻辑,还是不清楚是哪里出了问题,所以希望每次挂单之前,直接通过底层代码,获取当前的有效订单,通过这种方法避免重复报单。
策略代码如下:
class SimpleStrategy(CtaTemplate):
price_up = 0.0 # 定义压力位
price_down = 0.0 # 定义支撑位
parameters = ["price_up", "price_down"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.active_orders = {}
# 计算压力与支持位的中间位置
self.mid_price = (self.price_down + self.price_up) / 2
def on_tick(self, tick: TickData):
if not self.pos:
if not self.active_orders:
# 最新价偏向压力位,则挂空单;最新价偏向支撑位,则挂多单
if tick.last_price > self.mid_price:
self.orderids = self.short(self.price_up, 1)
else:
self.orderids = self.buy(self.price_down, 1)
elif self.active_orders:
# 取出当前的未成交挂单
active_order = self.active_orders[self.orderids[0]]
# 若多单未成交且最新价偏向压力位,则撤销多单的挂单
if active_order.direction == Direction.LONG and tick.last_price >= self.mid_price:
self.cancel_order(self.orderids[0])
# 若空单未成交且最新价偏向支撑位,则撤销空单的挂单
elif active_order.direction == Direction.SHORT and tick.last_price < self.mid_price:
self.cancel_order(self.orderids[0])
def on_order(self, order: OrderData):
# 有效委托则放入字典,撤销、成交类型的无效委托则从字典中删除
if order.is_active():
self.active_orders[order.vt_orderid] = order
else:
del self.active_orders[order.vt_orderid]
def on_trade(self, trade: TradeData):
# 委托成交后,立即反向挂出平仓单
if trade.offset == Offset.OPEN:
if trade.direction == Direction.LONG:
self.sell(self.price_up, 1)
else:
self.cover(self.price_down, 1)
CtaEngine有orderid_strategy_map和strategy_orderid_map。
不知道这是不是你的完整代码了,如果是的话,你的都没有self.orderids成交后删除的逻辑,但你的self.active_orders成交后就会删除对应缓存,那这样在self.active_orders当然找不到删除后的order了。
是的,这已经是完整的代码了。
self.orderids用来记录挂单的订单号,我想如果有新的委托,这个变量就会被新的委托号覆盖,所以就没有进行删除操作。
并且挂单成交了之后,则有持仓,not self.pos则为假,那么就不会进入if not self.pos:之后的代码了。
只有当not self.pos为真,即没有持仓,才可能运行“active_order = self.active_orders[self.orderids[0]]”这行代码。
按照代码的规则,运行“active_order = self.active_orders[self.orderids[0]]”的前提是,无持仓且有挂单。
只要有挂单,on_order函数中,则会将挂单放入self.active_orders中,就不应该存在self.active_orders中找不到self.orderids的情况。
综上所述,会不会是这种情况导致?
即,平仓成交之后(亦没有持仓),on_order函数中未立即更新self.active_orders(此时字典中还存放了一个平仓挂单),
所以在on_tick函数中,就运行了“elif self.active_orders:”这行代码,而没有先运行“if not self.active_orders:”这行代码,
由于此前的开仓挂单已成交,被移除,此时字典存放的是未成交的平仓挂单,就导致找不到self.orderids
如果是这个原因的话,那就说明策略代码在平仓成交之后,先运行on_tick,再运行的on_order。这样理解对吗?
想到此处,则又有一个新的问题,TickData、OrderData、TradeData这三个数据从交易所传到策略时,是打包在一起的形式推送给策略,还是独立分开的形式推送给策略?
是因为分开独立传送的形式,造成了tick数据快于order、trade回报数据,由此造成了以上的问题吗?
分开推送的。具体请自行打印排查了。
如果参考2楼的帖子中建议的self.vt_orderids.extend(vt_orderids)那种写法,应该在尚未收到委托变化回报之前,都不会挂新的委托出去
好的,谢谢xiaohe