使用套利合约进行对冲优点是双向开仓速度快, 滑点少, 策略实盘测试通过.
function Hedge(q, e, initAccount, symbol, hedgeSpread, coverSpread, rHedgeSpread, rCoverSpread) { var self = {} self.q = q self.initAccount = initAccount self.status = 0 self.symbol = symbol self.e = e self.isBusy = false self.hedgeSpread = hedgeSpread self.coverSpread = coverSpread self.rHedgeSpread = rHedgeSpread self.rCoverSpread = rCoverSpread self.insDetail = null; self.opAmount = OpAmount var arr = symbol.split('&'); if (arr.length != 2) { throw "合约名称必须是套利合约"; } self.pairA = arr[0].replace('SPD ', '').replace('SP ', ''); self.pairB = arr[1]; self.reset = function() { self.isBusy = false; self.status = 0; } self.init = function() { LogStatus("正在尝试恢复仓位"); var positions = _C(exchange.GetPosition); for (var i = 0; i < positions.length; i++) { if (positions[i].ContractType == self.symbol) { self.status = (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) ? 1 : 2; break; } } Log("恢复状态成功, 当前状态为: ", ["闲置", "多仓", "空仓"][self.status]); LogStatus("Running"); } self.poll = function() { if (self.isBusy || (!exchange.IO("status")) || (!$.IsTrading(self.symbol))) { Sleep(1000); return } var insDetail = exchange.SetContractType(self.symbol) if (!insDetail) { Sleep(1000); return } if (self.insDetail == null) { self.insDetail = insDetail; Log("合约", insDetail.InstrumentName, "一手", insDetail.VolumeMultiple, "份, 最大下单量", insDetail.MaxLimitOrderVolume); } var ticker = exchange.GetTicker() if (!ticker) { Sleep(1000); return } // _D()是内置时间格式化函数, 不传参就是取当前时间, 可以传时间戳 LogStatus(_D(), self.pairA, "卖", self.pairB, "买", ticker.Sell, " -- ", self.pairA, "买", self.pairB, "卖", ticker.Buy) var action = 0; // 1: A sell B buy 2: A buy B sell if (self.status == 0) { if (ticker.Buy >= self.hedgeSpread) { Log("开仓 ", self.pairA, "卖", self.pairB, "买", ticker.Buy, '#ff0000') action = 2 } else if (ticker.Sell <= self.rHedgeSpread) { Log("开仓 ", self.pairA, "买", self.pairB, "卖", ticker.Sell, '#ff0000') action = 1 } } else if (self.status == 2 && ticker.Sell <= self.coverSpread) { Log("平仓", self.pairA, "买", self.pairB, "卖", ticker.Sell, '#ff0000') action = 2 } else if (self.status == 1 && ticker.Buy >= self.rCoverSpread) { Log("平仓", self.pairA, "卖", self.pairB, "买",ticker.Buy, '#ff0000') action = 1 } if (action == 0) { return } self.isBusy = true var taskDirection = ""; if (action == 1) { taskDirection = self.status == 0 ? "buy" : "closebuy"; } else if (action == 2) { taskDirection = self.status == 0 ? "sell" : "closesell"; } self.q.pushTask(self.e, self.symbol, taskDirection, self.opAmount, function(task, ret) { self.isBusy = false if (task.action == "sell") { self.status = 2 } else if (task.action == "buy") { self.status = 1 } else { self.status = 0 var account = _C(exchange.GetAccount) LogProfit(account.Balance - self.initAccount.Balance, account) } }) } return self } function main() { if (IsVirtual()) { throw "回测不支持套利合约, 请用模拟盘或者实盘测试" } SetErrorFilter("ready|login|timeout") Log("正在与交易服务器连接...") while (!exchange.IO("status")) Sleep(1000); Log("与交易服务器连接成功") var initAccount = _C(exchange.GetAccount) Log(initAccount) var n = 0 var q = $.NewTaskQueue(function(task, ret) { Log(task.desc, ret ? "成功" : "失败", ret) }) if (Reset) { LogReset() LogProfitReset() } if (CoverAll) { Log("开始平掉所有残余仓位..."); $.NewPositionManager().CoverAll(); Log("操作完成"); } var t = Hedge(q, exchanges[0], initAccount, Symbol, HedgeSpread, CoverSpread, RHedgeSpread, RCoverSpread) if (AutoRestore) { t.init(); } while (true) { var cmd = GetCommand(); if (cmd == 'CoverALL') { Log("开始平掉仓位..."); $.NewPositionManager().CoverAll(); t.reset(); } q.poll() t.poll() } }