很多CTP API初学者遇到的一个头疼的事情,就是持仓和持仓明细的查询。这里简单介绍一下这二者的查询的处理,希望对大家有所帮助。
首先讲一下啥是持仓,以及啥是持仓明细。
CTP里的持仓明细,则是由开仓成交产生的逐笔持仓数据,而持仓,实际是持仓明细按合约、买卖方向、持仓日期类型等汇总而成的持仓数据,可能把它叫"持仓汇总"会更贴切。
举个例子来方便大家理解:
假设在沪深300指数六月(IF2406)和九月(IF2409)合约上初始时没有持仓。今天(2024年3月28日)陆续在这两个合约上分别报入了一个委托,而且这两个委托都是开仓20手,并且都成交了。订单和成交流水如下:
合约代码 | 订单编号 | 方向 | 报单价格/元 | 成交编号 | 成交数量/手 | 成交价格/元 |
IF2406 | 00001 | 买入/开仓 | 3500 | T10000 | 20 | 3500 |
IF2409 | 00002 | 卖出/开仓 | 3450 | T10086 | 8 | 3450.2 |
T10099 | 12 | 3450.4 |
则最终账户里有3笔持仓明细,如下所示:
持仓明细序号 | 合约代码 | 持仓明细买卖方向 | 开仓成交编号 | 开仓日期 | 开仓成交价格/元 | 数量/手 |
1 | IF2406 | 买入 | T10000 | 20240328 | 3500 | 20 |
2 | IF2409 | 卖出 | T10086 | 20240328 | 3450.2 | 8 |
3 | IF2409 | 卖出 | T10099 | 20240328 | 3450.4 | 12 |
最终有2笔持仓,如下所示:
持仓序号 | 合约代码 | 持仓方向 | 持仓日期类型 | 持仓均价/元 | 数量/手 |
1 | IF2406 | 多头 | 今仓 | 3500 | 20 |
2 | IF2409 | 空头 | 今仓 | 3450.32 | 20 |
聪明的你可能已经猜到了,在同一个账户里,持仓和持仓明细的KEY是什么。
持仓明细的KEY是以下字段的组合:
- 买卖方向(Direction)
- 开仓日期(OpenDate)
- 开仓成交编号(TradeID)
-
成交类型(TradeType)
- 成交类型一般是组合衍生的成交或普通成交,如果不涉及组合套利合约的交易,一般都是普通成交。
-
投机套保标志(HedgeFlag)
- 投机套保标志分为投机和套保(套期保值)等,投机持仓和套保持仓是互相独立的,当然,普通投资者订单一般都是投机标志。
对于不涉及套期保值和组合合约交易的大部分投资者来说,可以忽略HedgeFlag和TradeType字段.如果不考虑自成交的情况,可以忽略Direction字段。同时,由于CTP中不同的交易日的成交编号有可能重复(不能扔掉开仓日期),因此对单个账户的持仓明细的key可以简化为:
开仓日期(OpenDate) + 开仓成交编号(TradeID)
开发者可以根据此KEY,来区分及储存持仓明细。
持仓的KEY是以下字段的组合:
- 持仓多空方向(PosiDirection)
- 持仓日期类型(PositionDate)
- 投机套保标志(HedgeFlag)
目前,上期所(SHFE)和能源中心(INE)这两个交易所是区分今仓和昨仓(历史仓),因此它们的持仓在持仓日期类型(PositionDate)上有区分(即THOST_FTDC_PSD_Today今仓和THOST_FTDC_PSD_History昨仓)。其他交易所则不区分,持仓日期类型的值无多大意义,一般值都是THOST_FTDC_PSD_Today(今仓)。
在上面的例子里,由于是中金所合约的持仓,所以查询得到的这两条持仓记录中的持仓日期类型都是THOST_FTDC_PSD_Today(今仓),即使是(当天结算后)到了第二天的交易日,这两个持仓(已经变成了昨仓)它们的持仓日期类型仍然还是THOST_FTDC_PSD_Today(今仓)。
如果你动手能力够强,可以自行由持仓明细合成出持仓汇总来。
查询持仓明细
CTP查询持仓明细的请求函数是:
int ReqQryInvestorPositionDetail
(CThostFtdcQryInvestorPositionDetailField*pQryInvestorPositionDetail, int nRequestID);
返回值:
0,代表成功。
-1,表示网络连接失败;
-2,表示未处理请求超过许可数;
-3,表示每秒发送请求数超过许可数。
查询持仓明细的响应函数是:
void OnRspQryInvestorPositionDetail
(CThostFtdcInvestorPositionDetailField* pInvestorPositionDetail,
CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
用户可以根据交易所代码和合约代码等来查询持仓明细。下面是一个示例:
void CCTPTrade::QueryPositionDetail(const std::string& contract)
{
CThostFtdcQryInvestorPositionDetailField req = { 0 };
::strcpy(req.BrokerID, m_BrokerID.c_str());
::strcpy(req.InvestorID, m_userID.c_str());
::strcpy(req.InstrumentID, contract.c_str());
::strcpy(req.ExchangeID, "");
int ret = m_pAPI->ReqQryInvestorPositionDetail(&req, ++m_requestId);
if (ret != 0) {
std::cerr << "Query position detail failed!" << std::endl;
return;
}
}
和其他查询类似, 查询持仓明细受到查询流控的影响, 在途查询仅能有一笔, 同时有两次查询时间间隔的限制(一般为间隔1秒)。用户可以通过一些字段来对查询范围做出限制,如可以不填BrokerID和Investor, 若如此做, 则为默认查询登录的此账户的持仓明细. 查询时, 可以不填InstrumentID合约代码或ExchangeID交易所代码, 若如此做, 则为InstrumentID或ExchangeID不做限制, 即查询满足其他条件的任意合约或任意交易所的合约的持仓明细。
举个例子:
1. InstrumentID填"IF2409",其他填为空,则查询账户中的所有的IF2409合约的持仓明细,在上面的例子中,会查询返回2条记录。
2. ExchangeID填"DCE",其他填为空,则查询账户中的所有的DCE交易所(大商所)的合约的持仓明细,在上面的例子中,会查询返回0条记录。
查询持仓明细的响应OnRspQryInvestorPositionDetail中:
- 若有多条满足条件的持仓明细,则分成多次返回,最后一条的记录bIsLast值为true。
- 若没有任何满足条件的持仓明细,则仅返回一次(空的记录),其bIsLast值为true,且pInvestorPositionDetail参数为空指针。
在上面的例子里,如果不限制查询的条件则能查询到3条持仓明细记录,返回第3条记录时,bIslast值为true。
需要提到的是,有时候会查询得到持仓数量为0的持仓明细记录,这表明这个持仓明细在今天已经被完全平仓了。盘后结算时,已全部平仓的持仓明细将被清除,第二天就无法再查询到了。
查询持仓
CTP查询持仓的请求函数是:
int ReqQryInvestorPosition
(CThostFtdcQryInvestorPositionField *pQryInvestorPosition, int nRequestID);
返回值:
0,代表成功。
-1,表示网络连接失败;
-2,表示未处理请求超过许可数;
-3,表示每秒发送请求数超过许可数。
查询持仓的响应函数是:
void OnRspQryInvestorPosition
(CThostFtdcInvestorPositionField *pInvestorPosition,
CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
用户可以根据交易所代码和合约代码等来查询持仓。下面是一个示例:
void CCTPTrade::QueryPosition(const std::string& contract)
{
CThostFtdcQryInvestorPositionField req = { 0 };
::strcpy(req.BrokerID, m_BrokerID.c_str());
::strcpy(req.InvestorID, m_userID.c_str());
::strcpy(req.InstrumentID, contract.c_str());
::strcpy(req.ExchangeID, "");
int ret = m_pAPI->ReqQryInvestorPosition(&req, ++m_requestId);
if (ret != 0) {
std::cerr << "Query position failed!" << std::endl;
return;
}
}
查询持仓和查询持仓明细的方法类似,这里不做赘述。
CThostFtdcInvestorPositionField 持仓数据结构部分字段的说明:
Position: 表示当前持仓数量(手数)
TodayPosition: 表示今日新开仓数量,也就是当前持仓数量里的今仓的数量
YdPosition: 表示昨日收盘时持仓数量(≠ 当前的昨仓数量, 静态, 日间不随着开平仓而变化)
YdStrikeFrozen: 该字段是给个股期权用的, 期货期权里一直保持为0
OpenVolume: 当日累计开仓量,一天之内只会增加不会减少
CloseVolume: 当日累计平仓量,一天之内只会增加不会减少
OpenAmount: 当日开仓成交的成交额,一天之内只会增加不会减少
CloseAmount: 当日平仓成交的成交额,一天之内只会增加不会减少
LongFrozen: 多头冻结. 未成交的买入委托(含开仓和平仓)的未成交数量
ShortFrozen: 空头冻结. 未成交的卖出委托(含开仓和平仓)的未成交数量
OpenCost: 开仓成本, 等于汇总的各笔持仓明细的开仓成本的和
PositionCost: 持仓成本, 等于汇总的各笔持仓明细的持仓成本的和
FrozenMargin: 冻结的保证金, 开仓未成交的委托占用的冻结的保证金
PositionProfit: (当日的)(逐日盯市)持仓盈亏. 期权没有持仓盈亏, 为0.
CloseProfit: (当日的)(逐日盯市)平仓盈亏. 期权没有平仓盈亏, 为0.
例如, CF101的多头持仓4手, 平仓掉1手, 则这笔平仓成交产生的平仓盈亏会计入到剩下的这3手的CF101多头持仓记录中。
持仓字段中没有当前昨仓数量, 开仓均价, 持仓均价, 可用持仓(即可平持仓)数量等字段, 它们需要我们自己来算:
当前的昨仓数量 = Position - TodayPosition
开仓均价 = OpenCost / (Position * 合约乘数)
持仓均价 = PositionCost / (Position * 合约乘数)
可用数量:
可用数量(对于多头持仓) = Position - ShortFrozen - CombShortFrozen
可用数量(对于空头持仓) = Position - LongFrozen - CombLongFrozen
和持仓明细类似,有时候会查询得到持仓数量为0的持仓记录,这表明这个持仓在今天已经被完全平仓了,或者今天曾有过开仓报单但报单还没有成交过。当然,这种持仓中的平仓盈亏(CloseProfit)和平仓量(CloseVolume)等数据可能是有数值(而非0)的。盘后结算时,已全部平仓的持仓将被清除,第二天就无法再查询到了。文章来源:https://www.toymoban.com/news/detail-850562.html
如果有更多想要了解的,欢迎加入QQ交流群 736174420,一起讨论交流CTP API的使用!文章来源地址https://www.toymoban.com/news/detail-850562.html
到了这里,关于CTP查询持仓和持仓明细的那些事儿的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!