在商品期货交易中,跨期合约正套、反套是一种常见的套利方式。这种套利并不是无风险套利,在差价的单边方向持续扩大时,套利持仓是会处于浮亏状态的。不过只要套利仓位控制得当,还是很具有操作性、可行性。本次我们换一种策略类型,不再构建一个全自动的交易策略,而是实现一个可交互的半自动量化交易工具,以便更加方便的在商品期货交易中跨期套利。
开发平台使用优宽量化交易平台,本文重点是如何构建具有交互功能的半自动策略。 跨期套利这个是很简单的概念。
摘自百度知道
跨期套利正是通过观察期货各合约价差的波动,以赚取差价为目的,在同一期货品种的不同合约月份建立数量相等、方向相反的交易部位,并以对冲或交割方式结束交易的一种操作方式。正向市场时,价差为负,表现为远月升水,反向市场时,价差为正,表现为近月升水。一般来说,价差(绝对值)由持有成本(或持仓费)构成,即指为拥有或保留某种仓单或头寸而支付的仓储费、保险费和利息等费用。
策略框架如下代码:
function main(){
while(true){
if(exchange.IO("status")){ // 判断CTP协议连接状态。
LogStatus(_D(), "已经连接CTP !") // 开市时间,登录连接正常。
} else {
LogStatus(_D(), "未连接CTP !") // 未登录到交易前置机。
}
}
}
如果CTP协议连接正常后,接下来我们就是需要设置合约,然后获取行情。获取行情后,我们可以使用优宽量化交易平台封装好的「画线类库」画图,画出差价。
function main(){
while(true){
if(exchange.IO("status")){ // 判断CTP协议连接状态。
exchange.SetContractType("rb2001") // 设置远月合约
var tickerA = exchange.GetTicker() // 远月合约行情数据
exchange.SetContractType("rb1910") // 设置近月合约
var tickerB = exchange.GetTicker() // 近月合约行情数据
var diff = tickerA.Last - tickerB.Last
$.PlotLine("diff", diff)
LogStatus(_D(), "已经连接CTP !") // 开市时间,登录连接正常。
} else {
LogStatus(_D(), "未连接CTP !") // 未登录到交易前置机。
}
}
}
拿到了行情数据,计算差价,并且画图记录,让其简单反映出近期差价的波动状态。
使用「画线类库」的函数 $.PlotLine
在策略编辑页面可以直接给策略增加交互控件:
在策略代码中使用函数 GetCommand
函数捕获,上述策略控件触发后发送给机器人的命令。
捕获到命令后,对不同的命令做出不同的处理即可。
交易部分代码可以使用「商品期货交易类库」封装好的函数。首先,使用var q = $.NewTaskQueue()
生成交易控制对象 q(声明为全局变量)。
var cmd = GetCommand()
if (cmd) {
if (cmd == "plusHedge") {
q.pushTask(exchange, "rb2001", "sell", 1, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, "rb1910", "buy", 1, 123, function(task, ret) {
Log("q", task.desc, ret, task.arg)
})
}
})
} else if (cmd == "minusHedge") {
q.pushTask(exchange, "rb2001", "buy", 1, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, "rb1910", "sell", 1, 123, function(task, ret) {
Log("q", task.desc, ret, task.arg)
})
}
})
} else if (cmd == "coverPlus") {
q.pushTask(exchange, "rb2001", "closesell", 1, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, "rb1910", "closebuy", 1, 123, function(task, ret) {
Log("q", task.desc, ret, task.arg)
})
}
})
} else if (cmd == "coverMinus") {
q.pushTask(exchange, "rb2001", "closebuy", 1, function(task, ret) {
Log(task.desc, ret)
if (ret) {
q.pushTask(exchange, "rb1910", "closesell", 1, 123, function(task, ret) {
Log("q", task.desc, ret, task.arg)
})
}
})
}
}
q.poll()