CTP开发爬坑指北(三) 聚看点

2023-05-14 14:14:24 来源:哔哩哔哩

众所周知,天下大坑共一石,CTP独占八斗。进行CTP开发时,里面需要注意的地方比较多。今天给大家聊一聊CTP中暗藏的一些坑,让新手避开陷阱。

CTP开发中有很多需要注意的小细节,稍有不慎就会出问题,不然,轻则表现与预期不符,重则程序崩溃影响策略盈利。本系列将容易遇到的坑列出来,以供开发时参考,如有疑义之处,欢迎指正。

01


【资料图】

成交通知OnRtnTrade中的开平标志是怎样的?

成交通知里的开平方向标志OffsetFlag,与其对应的报单里的开平方向CombOffsetFlag[0],其实并不是完全相等的。

对于上期所和能源中心,成交与报单的开平方向,是相同的。而对大商所、郑商所和中金所,如果是开仓,则成交通知中的开平标志也是开仓THOST_FTDC_OF_Open ('0');如果是平仓,则无论你报单时使用的开平方向是什么(平今,平昨等),成交通知中的开平方向都是THOST_FTDC_OF_Close ('1')。

值得一提的是,SimNow环境(怎么又是你?)中,成交中的开平标志的设置是遵循上期所的规则的,即成交随着报单的开平标志来,例如大商所合约,报单如果开平方向填平今,那么即使这笔订单实际上是平掉了昨仓,成交里面的开平标志也会是平今,这是隐藏的一个小坑。

02

如何区分订单撤单时,是自己发起撤单还是被交易所拒单而导致的?

CTP中订单被撤单时,报单通知OnRtnOrder中的报单状态OrderStatus是已撤单THOST_FTDC_OST_Canceled ('5')。那么,如何区分订单到底是因为自己发出了撤单请求而撤的单,还是被交易所拒单而撤单的呢?

注:已撤单时可能有其他的报单状态OrderStatus,如THOST_FTDC_OST_PartTradedNotQueueing,这种情况下可认为都是自己发起撤单导致的。

第一种法子,是判断报单编号OrderSysID是否为空。如果不为空即已经产生了报单编号,说明这笔订单此前进入了交易所撮合队列中,所以此次撤单是被自己撤的单。否则是被交易所拒单了,或者订单还没有进入交易所就被你自己撤掉了。

第二种法子,是判断操作用户代码ActiveUserID是否为空。如果是自己发起的撤单,则ActiveUserID为你的账户名,否则它为空。

第三种法子,是判断报单提交状态OrderSubmitStatus。如果是自己发起的撤单,则撤单时OrderSubmitStatus为"已经接受"THOST_FTDC_OSS_Accepted ('3'),否则为"报单已经被拒绝"THOST_FTDC_OSS_InsertRejected ('4')。

03

订阅合约却收到了退订的响应?

如果行情API中,订阅合约(Subscribe*)却收到了退订(UnSubscribe*)的响应,则可能是你的行情API错误的连接到了交易前置地址上。

另一个可能是,你使用的头文件和库文件(dll, so等)它们各自的版本不一样,例如头文件的版本是6.3.15而库文件的版本是6.3.19。

04

API在断开连接时崩溃了?

低版本的CTP API在频繁与前置断连时确实有极低可能崩掉,不过高版本(since 6.3.19)的API,已经修复了这个问题了,所以换用较高版本的API即可解决问题。

也可以通过,进入非交易时间段则将API释放掉,临近交易时间时再创建API实例,从而避免这个问题。

另外,崩掉也有可能是你的程序编写有问题,例如在断开连接的响应OnFrontDisconnected()中,调用 Release()释放了API。正确的做法是,如果要释放API,需要在别的线程中进行,而不能在SPI函数中直接执行释放操作,而且,创建与释放API实例,最好是在同一个线程中。

05

结算单中为什么有乱码?

通过CTP的交易API的请求查询投资者结算结果ReqQrySettlementInfo接口,可以查询账户的结算单,结算单内容通过OnRspQrySettlementInfo接口返回。如果没有处理好,结算单中可能会有乱码。

首先需要知道,CTP中的字符串,都是使用GBK系的编码,不能使用UTF8等编码来解码,因此如果是在linux系统中查询结算单并显示,则可能由于终端编码等是UTF8不是GBK编码而显示为乱码,这个可以修改终端等使用的编码或者在程序中转换编码来解决。

其次,结算单内容较长,而OnRspQrySettlementInfo中的数据结构长度是可能不够存储结算单的,因此一般是分成多条来返回的。而连续的两条响应的结算内容正文Content 的衔接的地方,则会有编码处理的问题。响应中的结算内容,其实是char数组,因此,可能正好遇到有中文字符在两条响应交界处而被拆分的情况,所以,如果是每次收到一条查询结算单响应,就把它解码显示出来,遇到这种情况是就无法解析最后一个被拆成两半的中文字符了,乱码就在所难免了。

因此正确的处理方法是,用一个大的字符数组,汇总拼接存储各条响应中的结算内容字符。当收到全部的查询结算内容响应时,将这个字符数组进行解码,这时得到的就不会有乱码了。

如果用的是python等转换后的其他语言的API,则需要用类似的思路,用byte数组而非string数据结构来对应接受C++中的结算单内容字段,然后汇总拼接各个响应里面的结算单。

///请求查询投资者结算结果响应void OnRspQrySettlementInfo(CThostFtdcSettlementInfoField *pSettlementInfo, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)

{

static char settlement[MAX_LEN] = { 0 };

static int tempIndex = 0;

strncpy(settlement + tempIndex, pSettlementInfo->Content, sizeof(pSettlementInfo->Content) - 1);

tempIndex += sizeof(pSettlementInfo->Content) - 1;

if(bIsLast)

//完成生成结算单,显示结算

std::cout << settlement << std::endl;

}

}

关键词:

X 广告
公司
X 广告

Copyright   2015-2022 亚太快递网版权所有  备案号:沪ICP备2020036824号-11   联系邮箱: 562 66 29@qq.com