VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 25
声望: 0

新手,想请教在vnpy_ctastrategy策略中,如果获取当前的未成交挂单?
策略很简单,在开市时发出一个限价委托,为了避免重复报单,发出委托之前,获取下当前有哪些挂单,如果有未成交的挂单,则不再重复报单。
查看了cta_strategy的源代码,还是有些看不懂,是不是要注册OmsEngine才可以实现这个功能?

Member
avatar
加入于:
帖子: 5020
声望: 303

防止重复挂单可参考https://www.vnpy.com/forum/topic/1830-jin-tian-vnpychu-cuo-liao-tong-yi-barnei-cheng-jiao-liang-ci

Member
avatar
加入于:
帖子: 25
声望: 0

谢谢回复。
此前学习过此贴,也采用了类似的方法,但在运行策略时,仍然遇到了问题。
策略很简单,在压力位做空,支撑位做多,每次只交易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)
Member
avatar
加入于:
帖子: 5020
声望: 303

CtaEngine有orderid_strategy_map和strategy_orderid_map。
不知道这是不是你的完整代码了,如果是的话,你的都没有self.orderids成交后删除的逻辑,但你的self.active_orders成交后就会删除对应缓存,那这样在self.active_orders当然找不到删除后的order了。

Member
avatar
加入于:
帖子: 25
声望: 0

是的,这已经是完整的代码了。

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回报数据,由此造成了以上的问题吗?

Member
avatar
加入于:
帖子: 5020
声望: 303

分开推送的。具体请自行打印排查了。
如果参考2楼的帖子中建议的self.vt_orderids.extend(vt_orderids)那种写法,应该在尚未收到委托变化回报之前,都不会挂新的委托出去

Member
avatar
加入于:
帖子: 25
声望: 0

好的,谢谢xiaohe

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】