Loading ...

传统模型跨期套利策略(传统商品期货)

Author: 小小梦, Created: 2021-08-19 14:26:22, Updated: 2021-08-26 09:01:18

传统模型跨期套利策略(传统商品期货)

跨期套利

跨期套利是期货套利交易的一种,是对于同一商品但不同交割月份之间正常价格差距出现异常变化时,可以进行对冲交易而获利的一种交易方式,或者说策略。跨期套利又可分为牛市套利和熊市套利两种形式。可以做多差价,也可以做空差价。

那么怎么判断不合理的价差?

合理价差的运用在正向市场中有效,在正向市场中,以相邻月份为例,远月比近月的价格高出的部分主要是持有成本(大部分情况下,期货市场呈现正向市场,但是也有例外的情况,有些品种的远期合约要低于近期合约,主要是近期合约受现货影响较大,远期合约受产业发展、需求预期等因素影响)。持有期间的成本又可以大致分为交割成本(运输费、持仓费等)和时间成本(等值的现金流收益),交割成本以仓储费和交易费为主,我们可以把他们看作一个常量整体,而时间成本就是资金流的时间价值。如果同一个标的资产的不同交割月份的两个期货合约之间的价差,和我们计算的理论值偏离过大,我们可以认为出现了不合理价差,也同时出现了交易机会。

传统持有成本模型中,我们可以通过无风险利率(取十年国债收益率)来计算合理的远期合约价值(不考虑交易成本),公式为:

远期合约价值的计算公式
Flater = Fearly *(1 + Rf * month / 12)

其中Flater为远期合约合理价值,Fearly为近期合约最新价,Rf为无风险利率,month为远近期货合约之间的时间差,month / 12用来转化年化利率为持有期间利率。

策略交易逻辑

基于以上思路来设计开仓平仓条件。

  • 对于开仓 当实际差价正向偏离计算出的理论差价一定数值时(作为参数具体设置)做空差价即多近期合约,空远期合约。当差价反向偏离理论差价时,做多差价,即空近期合约,多远期合约。
  • 对于平仓 当持有对冲仓位时,差价回归到一定程度(作为参数具体设置)平仓获利。

在FMZ平台使用Javascript语言实现策略源码:(FMZ支持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 += "未连接|"
        }        
    }
}


回测测试

img

img

img

策略源码: https://www.fmz.com/strategy/308930


More