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 实现方法
待续...