在国内期货市场中, 可以使用上期技术提供的CTP API接口进行组合合约的交易。组合合约又称为套利合约,是交易所制定的方便投资者进行套利交易的合约,由两个或更多单个合约组合而成。目前国内期货市场的组合合约分为跨期组合和跨品种组合合约两种,而且都只由两个买卖方向相反的合约组合而成,这两个合约称为组合合约的“两条腿”。本文只讨论两条腿都是期货合约的组合合约,而不包含两条腿中存在期权的组合合约。
跨期组合合约指两个单腿合约属于同一个品种,交割月份不同的合约。近月(指交割时间更早)合约是第一腿, 远月(指交割时间更迟)合约是第二腿。如玉米2409合约-玉米2501合约。
跨品种组合合约指两个单腿合约属于不同品种,交割月份相同的合约,两个品种具有关联性,而且合约乘数相同,例如玉米-玉米淀粉,黄豆一号-豆粕。
目前,国内期货交易所中,郑州商品交易所(郑商所),大连商品交易所(大商所),以及广州期货交易所(郑商所)这三家交易所上市了组合合约。
组合合约的合约代码规则如下:
郑商所跨期组合 | SPD 第一腿&第二腿 例如: SPD TA411&TA501 |
郑商所跨品种组合 | IPS 第一腿&第二腿 例如: IPS CF501&CY501 |
大商所/广期所 跨期组合 | SP 第一腿&第二腿 例如: SP m2501&m2505 |
大商所/广期所 跨品种组合 | SPC 第一腿&第二腿 例如: SPC a2505&m2505 |
可以看到,组合合约的代码与普通合约迥然不同,有空格,‘&’等符号,处理时需要留意。
组合合约的合约信息也可以通过查询合约(ReqQryInstrument)来查询得到,合约信息数据结构为CThostFtdcInstrumentField,组合合约部分字段的值与普通合约有所区别,以SPC a2101&a2105为例:
合约代码 (InstrumentID) | SPC a2101&a2105 | a2105 |
产品代码 (ProductID) | SPC a&a | a |
产品类型 (ProductClass) | THOST_FTDC_PC_Combination | THOST_FTDC_PC_Futures |
合约数量乘数 (VolumeMultiple) | 0 | 10 |
最小变动价位 (PriceTick) | 1.0 | 1.0 |
到期日 (ExpireDate) | (空) | 20210524 |
交割年份 (DeliveryYear) | 0 | 2021 |
交割月份 (DeliveryMonth) | 0 | 5 |
可以通过ProductClass值是否等于THOST_FTDC_PC_Combination来判断合约是否为组合合约。
如果你使用的CTP API版本不低于v6.5.1,那么还可以通过查分类合约的方法ReqQryClassifiedInstrument来直接查询获取组合合约,只需在通过上述这个新增的接口查询时指定分类类型 ClassType 为 THOST_FTDC_INS_COMB即可。
我们可以使用CTP的行情API订阅组合合约。
与普通合约不一样的是,CTP推送的组合合约行情中,最新价、成交量等值为1.7976931348623157e+308,这是double类型数的上限值,即CTP中的无效数据,一些交易软件中显示的组合合约最新价等数据是由两个单腿合约的行情合成得来。我们也可以使用相同的方法,来自行合成出组合合约行情中缺失的最新价等数据。
一般而言,CTP推送的组合合约的行情的频次是比较低的,即使是最活跃的组合合约,也很难做到像期货主力合约一样在每个切片时间都有行情快照推送,因此组合合约自身的行情参考价值不太大。
先复习一下:组合交易是指对两个(或多个)合约进行买卖,买卖价格、买卖数量间保持相应关系的交易策略,能起到锁定价格风险、避免单腿风险等作用。在交易所端实现组合交易,相比在客户端(例如两腿分别委托),优势是能保证在两个(或多个)合约上同时成交,从而实现降低滑点等目的。
组合合约的报单和报单通知与普通合约基本一样,需要注意的有以下几点:组合合约的报单不支持市价单(可能是因为行情中最新价是无效的);买入组合合约,等于买入第一腿合约,同时卖出第二腿合约;而卖出组合合约,等于卖出第一腿合约,同时买入第二腿合约。
两个单腿的开平方向相同, 即都等于报单的开平方向。但如果指定了为题为互换单(报单时IsSwapOrder设为1), 则第一腿的开平方向与组合合约相同, 而第二腿合约的开平方向与第一腿(及组合合约)的开平方向相反, 如下图所示。
是否互换 | 组合买卖方向 | 组合开平仓方式 | 组合合约 | A 合约 | B 合约 |
否 | 买入 | 开仓 | SP A&B | 买开 | 卖开 |
否 | 买入 | 平仓 | SP A&B | 买平 | 卖平 |
否 | 卖出 | 开仓 | SP A&B | 卖开 | 买开 |
否 | 卖出 | 平仓 | SP A&B | 卖平 | 买平 |
是 | 买入 | 开仓 | SP A&B | 买开 | 卖平 |
是 | 买入 | 平仓 | SP A&B | 买平 | 卖开 |
是 | 卖出 | 开仓 | SP A&B | 卖开 | 买平 |
是 | 卖出 | 平仓 | SP A&B | 卖平 | 买开 |
因此,如果是要做近远月合约的移仓换月,则可以使用互换来报单组合合约。
组合合约成交时,两腿会保证同时成交,即收到两条腿的合约的成交通知(OnRtnTrade),例如,下单A&B组合合约1手,成交时,收到A合约的成交1手的成交通知和B合约的成交1手的成交通知(但两条腿的成交通知的推送顺序不固定),二者的成交价格之差,等于或优于A&B的报单价格。组合合约成交时,也可能有部分成交的情况产生,但两腿合约一直是同等数量的同步成交。下面的例子是下单某组合合约产生的成交通知的情况(按时间顺序排列):
11:00:00 | 下单买入A&B合约100手,报单价格为-10元。 |
11:00:45 | A于1000元成交50手。 |
11:00:45 | B于1010元成交20手。 |
11:00:45 | B于1010元成交30手。 |
11:01:00 | A于999元成交10手。 |
11:01:00 | B于1010元成交10手。 |
11:04:07 | B于1012元成交40手。 |
11:04:07 | A于1000元成交40手。 |
组合合约的成交通知中,成交类型(TradeType)的值为THOST_FTDC_TRDT_CombinationDerived(组合衍生成交),可以据此判断成交是否是组合合约报单产生成交。
下面是组合合约持仓和持仓明细的计算规则,年代久远,出处已不可考...
组合合约开仓后,持仓查询中生成3条记录,即组合合约持仓记录和两条分腿合约的持仓记录。其中,近期合约的多空方向与组合合约一致,远期合约的多空方向与组合合约相反。
对于组合合约的持仓记录,它只计算上日持仓、今日持仓、总持仓、开仓量、保证金等字段,组合合约的平仓量、平仓盈亏、持仓成本、持仓盈亏、手续费此类信息都在其分腿合约中计算。
对于分腿合约的持仓记录,其上日持仓、今日持仓、总持仓、开仓量、平仓量计算的都是单一合约和组合合约形成的持仓的总合,如要区分其中单一合约和组合合约分别形成的持仓数量,必须查询持仓明细。分腿合约的保证金字段只计算其单一合约持仓的保证金,其组合合约持仓的保证金存放在组合合约持仓记录的保证金字段中。但开仓成本、开仓均价、持仓成本、持仓均价、持仓盈亏、平仓金额、平仓盈亏、手续费这类字段是计算所有持仓的,包括组合合约形成的持仓。
组合合约平仓按先“单一后组合,先开先平”的原则。即组合合约平仓时,先平它的单一合约头寸,使用哪一手的单一合约持仓按先开先平的原则;如果单一合约头寸不足平仓量的话,再平它的组合合约头寸,具体平仓时也是按先开先平的原则。如果平仓时用到了组合合约的持仓头寸,则需有一个打散的动作,即在自身分腿的组合持仓头寸中减少持仓量,增加平仓量;相应减少组合合约记录持仓的持仓量;减少另一条分腿的组合合约持仓头寸,衍生出一个单一合约持仓,持仓量为平组合仓的平仓量部分,该持仓记录的撮合编号与原组合合约的撮合编号一致,开仓时间也与原组合合约的开仓时间一致。
组合合约的平仓包含以下几种情况:
例如:合约A有单一持仓4手,组合合约AB的组合持仓2手。
合约B有单一持仓3手,组合合约AB的组合持仓2手。
组合合约AB有2手持仓
现平合约A持仓5手,过程中,合约A的单一持仓4手全部平仓,还差一手,于是将AB组合持仓打散,平1手组合合约。因为AB的组合持仓被打散了1手,所以,组合合约AB的持仓减少1手。相应的,合约B的AB组合持仓也减少1手,衍生出1手B的单一持仓。
即,结果为:
合约A有单一持仓0手,组合合约AB的组合持仓1手。
合约B有单一持仓4手,组合合约AB的组合持仓1手。
组合合约AB有1手持仓
例如:合约A有单一持仓0手,组合合约AB的组合持仓1手。
合约B有单一持仓3手,组合合约AB的组合持仓1手,组合合约BC的组合持仓7手 ,其中AB组合持仓先开仓,BC组合持仓后开仓
合约C有单一持仓0手,组合合约BC的组合持仓7手
组合合约AB有1手持仓
组合合约BC有7手持仓
现平合约B5手,过程中,合约B的单一持仓3手全部平仓,然后需要用到组合持仓,组合持仓中AB先开仓,所以先平,将AB的组合持仓打散,平1手。这时,组合合约AB的持仓也减少1手;合约A的AB组合持仓同时减少1手,衍生出1手单一合约。接着,再将合约B的BC组合持仓打散,平1手。与此同时,组合合约BC的持仓减少1手;合约C的BC组合持仓减少1手,衍生出1手单一持仓。
即,结果为:
合约A有单一持仓1手,组合合约AB的组合持仓0手。
合约B有单一持仓0手,组合合约AB的组合持仓0手,组合合约BC的组合持仓6手
合约C有单一持仓1手,组合合约BC的组合持仓6手
组合合约AB有0手持仓
组合合约BC有6手持仓
例如:合约A有单一持仓0手,组合合约AB的组合持仓4手。
合约B有单一持仓1手,组合合约AB的组合持仓4手,其中,组合持仓先开仓
组合合约AB有4手持仓
现平组合合约AB3手,过程中,合约A因为没有单一持仓,所以,当分腿A的成交回报到达时将AB组合持仓打散3手,平组合持仓3手,减少组合持仓,增加组合持仓的平仓量。组合合约AB的持仓相应减少3手。合约B的AB组合持仓同时也被打散,减少了3手,并衍生出了3手单一持仓。当分腿B的成交回报到达时,平合约B所用的持仓头寸是它刚从组合合约衍生出来的3手单一持仓,因为这3手单一持仓的开仓时间与组合持仓一致,比原来的1手单一持仓早,所以,先平这3手。
即,结果为:
合约A有单一持仓0手,组合合约AB的组合持仓1手。
合约B有单一持仓1手(这1手是原来的1手单一持仓而不是组合持仓衍生出的单一持仓),组合合约AB的组合持仓1手。
组合合约AB有1手持仓
例如:合约A有单一持仓1手,组合合约AB的组合持仓2手。
合约B有单一持仓0手,组合合约AB的组合持仓2手,组合合约BC的组合持仓3手 ,其中BC组合持仓先开仓,AB组合持仓后开仓
合约C有单一持仓1手,组合合约BC的组合持仓3手
组合合约AB有2手持仓
组合合约BC有3手持仓
现平组合合约AB1手。过程中,分腿A有1手单一持仓,所以,平仓时使用的是单一持仓。分腿B没有单一持仓,但它的组合持仓中BC是先开仓的,所以打散BC组合持仓1手,平仓。因为BC组合持仓被打散1手,所以,组合合约BC持仓减少1手;合约C的BC组合持仓减少1手,衍生出1手单一合约。
即,结果是:
合约A有单一持仓0手,组合合约AB的组合持仓2手。
合约B有单一持仓0手,组合合约AB的组合持仓2手,组合合约BC的组合持仓2手
合约C有单一持仓2手,组合合约BC的组合持仓2手
组合合约AB有2手持仓
组合合约BC有2手持仓
例如:合约A有单一持仓2手,组合合约AB的组合持仓0手。
合约B有单一持仓1手,组合合约AB的组合持仓0手。
组合合约AB有0手持仓
现平组合合约AB1手。虽然组合合约AB没有持仓,但它的2个分腿都有持仓,所以可以平仓。分腿合约A和B都是使用他们的单一持仓来平仓
即,结果为:
合约A有单一持仓1手,组合合约AB的组合持仓0手。
合约B有单一持仓0手,组合合约AB的组合持仓0手。
组合合约AB有0手持仓
例如:合约A有单一持仓0手,组合合约AB的组合持仓2手。
合约B有单一持仓0手,组合合约AB的组合持仓2手,组合合约BC的组合持仓2手 ,其中AB组合持仓先开仓,BC组合持仓后开仓
合约C有单一持仓2手,组合合约BC的组合持仓2手
组合合约AB有2手持仓
组合合约BC有2手持仓
现平组合合约BC3手,过程中,当分腿B的成交回报到达时,由于B没有单一持仓,所以它用组合持仓来平仓,其中,组合AB先开仓,所以现将AB持仓打散,平2手。这时,组合合约AB的持仓相应减少2手,合约A的组合AB持仓减少2手,衍生出2手的单一持仓。然后再平合约B的BC组合持仓1手,同时将组合合约BC的持仓减少1手,合约C的BC组合持仓减少1手,同时衍生出1手单一持仓。当分腿C的成交回报到达时,合约C正好有3手单一持仓,全部平仓。
即,结果为:
合约A有单一持仓2手,组合合约AB的组合持仓0手。
合约B有单一持仓0手,组合合约AB的组合持仓0手,组合合约BC的组合持仓1手 ,其中AB组合持仓先开仓,BC组合持仓后开仓
合约C有单一持仓0手,组合合约BC的组合持仓1手
组合合约AB有0手持仓
组合合约BC有1手持仓
组合合约的冻结在组合合约持仓记录的多头冻结(LongFrozen)/空头冻结(ShortFrozen)、两个分腿合约的组合多头冻结(CombLongFrozen)/组合空头冻结(CombShortFrozen)字段上能显示出来。
例如:多头开仓冻结,组合合约记录的多头冻结(LongFrozen)字段增加,近期合约分腿的组合多头冻结(CombLongFrozen)增加,远期合约分腿的组合空头冻结(CombShortFrozen)增加。
多头平仓冻结,组合合约记录的空头冻结(ShortFrozen)字段增加,可平数量减少;近期合约分腿的组合空头冻结(CombShortFrozen)增加;远期合约分腿的组合多头冻结(CombLongFrozen)增加。
可能有一些难懂,如果有读不明白的,可以在文后的讨论中留言,笔者会尽量解答。
CTP API查询持仓(汇总)时,组合合约相关的持仓会有3条持仓记录返回,即组合合约持仓,和两个单腿合约的持仓。其中,组合合约持仓基本只有保证金(UseMargin)和各个持仓数量(Position, YdPosition, LongFrozen等)等数据是有用的,两个单腿合约的持仓的保证金都是0,组合成交形成的持仓(CombPosition)表示合约持仓中有多少手是组合合约成交产生的。组合持仓一般有保证金优惠,具体减免情况可以查看交易所规则。
CTP API查询持仓明细时,持仓明细的成交类型(TradeType, 它也是持仓明细的key之一)字段即为开仓成交的成交类型,因此可以通过此字段来判断持仓明细是否是组合合约衍生成交产生的。不过,组合合约平仓时更新持仓明细较为复杂(甚至可能产生平仓时凭空增加一条持仓明细记录的情况),如果要正确维护组合合约的持仓明细,需要搞懂上面的持仓明细规则才行。
另外, 还有额外的专门查询组合合约成交衍生产生的持仓明细的接口:ReqQryInvestorPositionCombineDetail,其响应函数是OnRspQryInvestorPositionCombineDetail,数据结构是CThostFtdcInvestorPositionCombineDetailField。
TIPS 1:使用组合合约平仓时,交易系统判断的是两个对应买卖方向的单腿的合约的可用持仓数量是否足够,而并不是组合合约持仓数量。因此,即使用户没有组合合约持仓,也可以通过组合合约的方式来平掉两个单腿的持仓。
例如,小明有A的多头持仓10手,有B的空头持仓7手,二者都不是通过组合合约开仓产生的,则他若下单卖出平仓A&B,仍最多可以卖出平仓7手。
TIPS 2: 组合合约的交易,手续费没有优惠。手续费是在成交时收取的,组合合约衍生的成交的手续费计算规则和普通合约的相同。