简单的跨期对冲, 抛砖引玉, 细节还需要处理, 轮训间隔可以缩小到1秒或者删除Sleep那行策略就可以随时响应价格变化
function Hedge(q, e, initAccount, symbolA, symbolB, hedgeSpread, coverSpread) { var self = {} self.q = q self.initAccount = initAccount self.status = 0 self.symbolA = symbolA self.symbolB = symbolB self.e = e self.isBusy = false self.hedgeSpread = hedgeSpread self.coverSpread = coverSpread self.opAmount = OpAmount self.poll = function() { if (self.isBusy || (!exchange.IO("status")) || (!$.IsTrading(self.symbolA))) { Sleep(1000); return } var insDetailA = exchange.SetContractType(self.symbolA) if (!insDetailA) { return } var tickerA = exchange.GetTicker() if (!tickerA) { return } var insDetailB = exchange.SetContractType(self.symbolB) if (!insDetailB) { return } var tickerB = exchange.GetTicker() if (!tickerB) { return } // _D()是内置时间格式化函数, 不传参就是取当前时间, 可以传时间戳 LogStatus(_D(), "A卖B买", _N(tickerA.Buy - tickerB.Sell), "A买B卖", _N(tickerA.Sell-tickerB.Buy)) var action = 0; // 1: A sell B buy 2: A buy B sell if (self.status == 0) { if ((tickerA.Buy - tickerB.Sell) > self.hedgeSpread) { Log("开仓 A卖B买", tickerA.Buy, tickerB.Sell, '#ff0000') action = 1 } else if ((tickerB.Buy - tickerA.Sell) > self.hedgeSpread) { Log("开仓 B卖A买", tickerB.Buy, tickerA.Sell, '#ff0000') action = 2 } } else if (self.status == 1 && (tickerA.Sell-tickerB.Buy) <= self.coverSpread) { Log("平仓 A买B卖", tickerA.Sell, tickerB.Buy, '#ff0000') action = 2 } else if (self.status == 2 && (tickerB.Sell-tickerA.Buy) <= self.coverSpread) { Log("平仓 B买A卖", tickerB.Sell, tickerA.Buy, '#ff0000') action = 1 } if (action == 0) { return } self.isBusy = true var tasks = [] if (action == 1) { tasks.push([self.symbolA, self.status == 0 ? "sell" : "closebuy"]) tasks.push([self.symbolB, self.status == 0 ? "buy" : "closesell"]) } else if (action == 2) { tasks.push([self.symbolA, self.status == 0 ? "buy" : "closesell"]) tasks.push([self.symbolB, self.status == 0 ? "sell" : "closebuy"]) } self.q.pushTask(self.e, tasks[0][0], tasks[0][1], self.opAmount, function(task, ret) { self.q.pushTask(self.e, tasks[1][0], tasks[1][1], 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() { 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 ? "成功" : "失败") }) if (CoverAll) { Log("开始平掉所有残余仓位..."); $.NewPositionManager().CoverAll(); Log("操作完成"); } var t = Hedge(q, exchanges[0], initAccount, SA, SB, HedgeSpread, CoverSpread) while (true) { q.poll() t.poll() } }template: strategy.tpl:40:21: executing "strategy.tpl" at <.api.GetStrategyListByName>: wrong number of args for GetStrategyListByName: want 7 got 6