1. CtaTemplate模版的成员trading是指示策略是否处于交易状态

1.1 CtaTemplate模版的成员trading的定义

class CtaTemplate(ABC):
    """"""

    author = ""
    parameters = []
    variables = []

    def __init__(
        self,
        cta_engine: Any,
        strategy_name: str,
        vt_symbol: str,
        setting: dict,
    ):
        """"""
        self.cta_engine = cta_engine
        self.strategy_name = strategy_name
        self.vt_symbol = vt_symbol

        self.inited = False
        self.trading = False       # 策略是否处于交易状态
        self.pos = 0

    ... ... 其他略去

你会发现self.trading除了初始化时赋值为False之外,并没有在CtaTemplate的任何其他地方被修改赋值。

1.2 CtaTemplate模版的成员trading是由CtaEngine来维护的

我们的CTA策略都是从CtaTemplate模版扩展而来。当我们的CTA策略被实例化为运行策略时,self.trading就被缓冲到以CTA策略实例名称为文件名的json文件中。之后随着CTA策略被初始化、启动、停止,self.trading的状态在False和True之间做相应的变化,并调用put_event()函数写入json文件,调用sync_data()函数从json文件中读出。这两个函数中都是调用了self.cta_engine的功能。

    def put_event(self):
        """
        Put an strategy data event for ui update.
        """
        if self.inited:
            self.cta_engine.put_strategy_event(self)
    def sync_data(self):
        """
        Sync strategy variables value into disk storage.
        """
        if self.trading:
            self.cta_engine.sync_strategy_data(self)

1.3 CtaEngine的put_strategy_event()函数

    def put_strategy_event(self, strategy: CtaTemplate):
        """
        Put an event to update strategy status.
        """
        data = strategy.get_data()                                       # 策略的变量,包含的trading
        event = Event(EVENT_CTA_STRATEGY, data)
        self.event_engine.put(event)                                   # 发送消息EVENT_CTA_STRATEGY给订阅者,通知策略变量变化了

1.4 CtaEngine的sync_strategy_data()函数

    def sync_strategy_data(self, strategy: CtaTemplate):
        """
        Sync strategy data into json file.
        """
        data = strategy.get_variables()

        # 下面的两句把inited和trading都剔除了
        data.pop("inited")      # Strategy status (inited, trading) should not be synced.
        data.pop("trading")    

        self.strategy_data[strategy.strategy_name] = data
        save_json(self.data_filename, self.strategy_data)   # 把其他策略变量写入json文件

2. CtaTemplate模版的成员trading不能告诉策略当前交易合约否处于交易状态

由上面的代码分析发现,策略的trading并没有考虑交易合约是否可以处在交易状态。
策略的trading是会影响到策略的委托行为的,下面是CtaTemplate的send_order()函数:

    def send_order(
        self,
        direction: Direction,
        offset: Offset,
        price: float,
        volume: float,
        stop: bool = False,
        lock: bool = False,
        net: bool = False
    ):
        """
        Send a new order.
        """
        if self.trading:                                                    # 只要self.trading==True就可以委托
            vt_orderids = self.cta_engine.send_order(
                self, direction, offset, price, volume, stop, lock, net
            )
            return vt_orderids
        else:
            return []

实际使用中会发现策略可能会在休市或者非交易时间,因为收到的错误数据而误动作,导致出现委托无法得到回应或者是拒单。
其原因也是因为作为委托条件的self.trading并没有考虑委托时刻,交易合约是否可以处在交易状态!

3. 怎么解决这个问题?

3.1 开放CTP网关接口的合约品种交易状态推送接口函数

合约品种交易状态推送接口函数是onRtnInstrumentStatus()。
具体方法我已经在再谈集合竞价 里详细地讨论过了,文章很长,希望有耐心看完,这里就不再赘述。

注:其他网关接口也应该类似。

3.2 委托执行条件 = 合约交易状态 + self.trading

3.2.1 合约有哪些交易状态

/////////////////////////////////////////////////////////////////////////
///TFtdcInstrumentStatusType是一个合约交易状态类型
/////////////////////////////////////////////////////////////////////////
///开盘前
#define THOST_FTDC_IS_BeforeTrading '0'
///非交易
#define THOST_FTDC_IS_NoTrading '1'
///连续交易
#define THOST_FTDC_IS_Continous '2'
///集合竞价报单
#define THOST_FTDC_IS_AuctionOrdering '3'
///集合竞价价格平衡
#define THOST_FTDC_IS_AuctionBalance '4'
///集合竞价撮合
#define THOST_FTDC_IS_AuctionMatch '5'
///收盘
#define THOST_FTDC_IS_Closed '6'

typedef char TThostFtdcInstrumentStatusType;

只有在交易合约在“连续交易”和 “集合竞价报单”这两种状态下,同时交易者也启动了策略(trading==True)情况下,策略才可以执行委托。
也就是说 :委托执行条件 = 合约交易状态 + self.trading。

3.2.3 实现方法

待续...