跨期套利是期货套利交易的一种,是对于同一商品但不同交割月份之间正常价格差距出现异常变化时,可以进行对冲交易而获利的一种交易方式,或者说策略。跨期套利又可分为牛市套利和熊市套利两种形式。可以做多差价,也可以做空差价。
那么怎么判断不合理的价差?
合理价差的运用在正向市场中有效,在正向市场中,以相邻月份为例,远月比近月的价格高出的部分主要是持有成本(大部分情况下,期货市场呈现正向市场,但是也有例外的情况,有些品种的远期合约要低于近期合约,主要是近期合约受现货影响较大,远期合约受产业发展、需求预期等因素影响)。持有期间的成本又可以大致分为交割成本(运输费、持仓费等)和时间成本(等值的现金流收益),交割成本以仓储费和交易费为主,我们可以把他们看作一个常量整体,而时间成本就是资金流的时间价值。如果同一个标的资产的不同交割月份的两个期货合约之间的价差,和我们计算的理论值偏离过大,我们可以认为出现了不合理价差,也同时出现了交易机会。
传统持有成本模型中,我们可以通过无风险利率(取十年国债收益率)来计算合理的远期合约价值(不考虑交易成本),公式为:
远期合约价值的计算公式
Flater = Fearly *(1 + Rf * month / 12)
其中Flater
为远期合约合理价值,Fearly
为近期合约最新价,Rf
为无风险利率,month
为远近期货合约之间的时间差,month / 12
用来转化年化利率为持有期间利率。
基于以上思路来设计开仓平仓条件。
在优宽平台使用Javascript语言实现策略源码:(优宽支持C++/Python/Javascript/麦语言/可视化模块)
/*backtest
start: 2021-02-01 09:00:00
end: 2021-04-01 15:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
*/
// 全局变量
var interest_rate = 1 + rate * diffMonth / 12 // 远近合约月份之间的利率系数理论值
var q = $.NewTaskQueue() // 创建商品期货交易类库模版类库中的交易对象
var p = $.NewPositionManager()
function main() {
var lastPlotTS = 0
var strState = ""
while (true) {
Sleep(interval)
LogStatus(_D(), strState)
strState = ""
if (exchange.IO("status")) {
if (!$.IsTrading(symbolNear) || !$.IsTrading(symbolFar)) {
strState += "不在交易时间|"
continue
}
// 获取近期行情数据
var infoNear = exchange.SetContractType(symbolNear)
if (!infoNear) {
strState += "订阅" + symbolNear + "合约失败|"
continue
}
var tickerNear = exchange.GetTicker()
// 获取远期行情数据
var infoFar = exchange.SetContractType(symbolFar)
if (!infoFar) {
strState += "订阅" + symbolFar + "合约失败|"
continue
}
var tickerFar = exchange.GetTicker()
if (!tickerNear || !tickerFar) {
strState += "行情获取失败|"
continue
}
// 更新持仓
var nearSymbolHold = 0
var farSymbolHold = 0
var pos = _C(exchange.GetPosition)
for (var i = 0 ; i < pos.length ; i++) {
if (pos[i].ContractType == symbolNear) {
nearSymbolHold += pos[i].Amount
} else if (pos[i].ContractType == symbolFar) {
farSymbolHold += pos[i].Amount
}
}
// theory_price 理论远期合约价格
var theory_price = tickerNear.Last * interest_rate
// theory 近期实际价格和远期理论价格的价差
var theory = tickerNear.Last - theory_price
// 近期合约和远期合约实际价差
var real = tickerNear.Last - tickerFar.Last
// 触发下线
var floor = theory - openDiff
// 触发上线
var cap = theory + openDiff
// 平仓线
var close_low = theory - coverDiff
var close_high = theory + coverDiff
// 判断触发条件
if (nearSymbolHold == 0 && farSymbolHold == 0 && real < floor) { // 买近卖远
Log("买近卖远,real:", real, "floor:", floor, "#FF0000")
q.pushTask(exchange, symbolNear, "buy", amount, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, symbolFar, "sell", amount, function(task, ret) {
Log(task.desc, ret)
})
}
})
} else if (nearSymbolHold == 0 && farSymbolHold == 0 && real > cap) { // 卖近买远
Log("卖近买远,real:", real, "floor:", floor, "#CD32CD")
q.pushTask(exchange, symbolNear, "sell", amount, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, symbolFar, "buy", amount, function(task, ret) {
Log(task.desc, ret)
})
}
})
} else if ((nearSymbolHold != 0 || farSymbolHold != 0) && real > close_low && real < close_high) { // 当差价进入设置的非套利区间,平仓
// coverall
Log("平仓,real:", real, "close_low:", close_low, "close_high:", close_high)
q.pushTask(exchange, symbolNear, "coverall", -1, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, symbolFar, "coverall", -1, function(task, ret) {
Log(task.desc, ret)
})
}
})
}
q.poll()
strState += "已链接|"
if (new Date().getTime() - lastPlotTS > 1000 * 60 * 60) {
$.PlotLine("floor", floor)
$.PlotLine("cap", cap)
$.PlotLine("close_low", close_low)
$.PlotLine("close_high", close_high)
$.PlotLine("real", real)
lastPlotTS = new Date().getTime()
}
} else {
strState += "未连接|"
}
}
}