function cancelAll(){ var ref = false; for(var e in exchanges){ while(true){ var n = 0; var my_orders = _C(exchanges[e].GetOrders); for(var order1 in my_orders){ ref = true; e.CancelOrder(my_orders[order1].Id); n += 1; } if(n==0){ break; } } } return ref; } function main(){ if(exchanges.length != 2){ throw("Only two exchanges are supported"); } LogReset(); LogProfitReset(); cancelAll(); var initStocks = 0.0; var initBalance = 0.0; var minAmount = 0.1; var lastTradeTime = 0; var lastTradeErrExchange = ''; var accountsCache = []; var hedgeNum = [0, 0]; var names = []; var baseCurrency = exchange.GetCurrency(); for(var e in exchanges){ if(exchanges[e].GetCurrency() != baseCurrency){ throw("It has to be the same currency to hedge:"+baseCurrency); } names.push(exchanges[e].GetName()); var account = _C(exchanges[e].GetAccount); accountsCache.push(account); initStocks += account.Stocks; initBalance += account.Balance; } if(baseCurrency == "BTC"){ minAmount = 0.01 } else { minAmount = 0.1 } Log("all balance:", _N(initBalance), "all stocks", _N(initStocks)) while(true){ if(accountsCache.length <= 0){ for(var e in exchanges){ var account1 = _C(exchanges[e].GetAccount); accountsCache.push(account1); } } Sleep(LoopInterval); cmd = GetCommand(); if(cmd){ Log("CMD", cmd); var arr = cmd.split(":"); if(arr[0]=="A->B"){ MinSpreadA = parseFloat(arr[1]); } else if(arr[0]=="B->A"){ MinSpreadB = parseFloat(arr[1]); } } var depthA = exchanges[0].GetDepth(); if (!depthA){ continue; } var depthB = exchanges[1].GetDepth(); if (!depthB){ continue; } var time = new Date(); if(lastTradeTime > 0 && time.getTime() - lastTradeTime > BalanceTime){ var needUpdate = cancelAll(); if (!needUpdate){ for(var account2 in accountsCache){ if(accountsCache[account2].FrozenBalance >= 0.1 || accountsCache[account2].FrozenStocks >= 0.001){ needUpdate = true; break; } } } if (needUpdate){ for(var k in exchanges){ account3 = _C(exchanges[k].GetAccount); accountsCache.push(account3); } } var nowStocks = 0.0; var nowBalance = 0.0; for(var account4 in accountsCache){ nowBalance += accountsCache[account4].Balance; nowStocks += accountsCache[account4].Stocks; } var diff = _N(nowStocks-initStocks, 5); var isReverse; if(Math.abs(diff) < minAmount){ LogProfit(_N(nowBalance-initBalance, 3), "all balance", _N(nowBalance), "all stocks", _N(nowStocks), "stock offset:", diff); lastTradeTime = 0; } else if(diff > minAmount){ isReverse = depthA.Bids[0].Price < depthB.Bids[0].Price; } else if(-diff > minAmount){ isReverse = depthA.Asks[0].Price > depthB.Asks[0].Price; } if(isReverse != null){ var depths = [depthA, depthB]; var opAmount; var kk; if(isReverse){ kk = [1, 0]; } else{ kk = [0, 1]; } for(var pos in kk){ if(diff > minAmount){ opAmount = Math.min(diff, accountsCache[pos].Stocks, depths[pos].Bids[0].Amount + depths[pos].Bids[1].Amount); diff = -opAmount; if(opAmount >= minAmount){ exchanges[pos].Sell(depths[pos].Bids[1].Price, opAmount); } } else if(-diff >= minAmount){ opAmount = Math.min(-diff, _N(accountsCache[pos].Balance / depths[pos].Asks[1].Price, 3), depths[pos].Asks[0].Amount + depths[pos].Asks[1].Amount); diff += opAmount; if (opAmount >= minAmount){ exchanges[pos].Buy(depths[pos].Asks[1].Price, opAmount); } } } if (opAmount != undefined){ var time1 = new Date(); lastTradeTime = time1.getTime(); accountsCache = []; } } continue; } var diffA = _N(depthA.Bids[0].Price - depthB.Asks[0].Price, 3) var diffB = _N(depthB.Bids[0].Price - depthA.Asks[0].Price, 3) LogStatus(JSON.stringify({type: 'table', title: 'status', cols: ['name', 'money', 'frozenmoney', 'stock', 'frozenstock', 'buyone', 'sellone', 'threshold', 'offset', 'num of times'], rows: [[names[0], accountsCache[0].Balance, accountsCache[0].FrozenBalance, accountsCache[0].Stocks, accountsCache[0].FrozenStocks, depthA.Bids[0].Price, depthA.Asks[0].Price, MinSpreadA, diffA, hedgeNum[0]], [names[1], accountsCache[1].Balance, accountsCache[1].FrozenBalance, accountsCache[1].Stocks, accountsCache[1].FrozenStocks, depthB.Bids[0].Price, depthB.Asks[0].Price, MinSpreadB, diffB, hedgeNum[0]]]})); HPos = 0; if (diffA >= MinSpreadA){ orderH = depthA.Bids[0]; orderL = depthB.Asks[0]; exchangeH = 0; exchangeL = 1; accountH = accountsCache[0]; accountL = accountsCache[1]; } else if (diffB >= MinSpreadB){ HPos = 1; orderH = depthB.Bids[0]; orderL = depthA.Asks[0]; exchangeH = 1; exchangeL = 0; accountH = accountsCache[1]; accountL = accountsCache[0]; } else{ continue; } var opPrice = _N((orderH.Price + orderL.Price) / 2.0, 2); var opAmount = Math.min(MaxAmount, orderH.Amount, orderL.Amount, accountH.Stocks, _N(accountL.Balance / opPrice, 3)); if(opAmount >= minAmount){ var tasks = [[exchangeH, "H"], [exchangeL, "L"]]; if(lastTradeErrExchange == "L"){ tasks.reverse(); } lastTradeErrExchange = ""; for(var task in tasks){ if(tasks[task][1] == "H"){ var id = exchanges[tasks[task][0]].Sell(opPrice, opAmount); if(id == undefined){ lastTradeErrExchange = tasks[task][1]; break; } } if(tasks[task][1] == "L"){ var id = exchanges[tasks[task][0]].Buy(opPrice, opAmount); if(id == undefined){ lastTradeErrExchange = tasks[task][1]; break; } } } var time = new Date(); lastTradeTime = time.getTime(); accountsCache = [] hedgeNum[HPos] += 1 } } }
dyhhu 这个如果如果不平衡了,是不是就需要调整差价,趋向于做平衡的方向调整差价
bijiasuo 测试没效益的?是不是那差价要改动的?
7meter 已改正
m0606 17行那儿返回ref写成ret了