老早以前开发的,JavaScript属于便学便开发,不喜忽喷, 有兴趣的可以在二次开发更新。 微信:fzqtdkj
var ContractTypeIdx =[] //合约类型 var MarginLevelIdx =[] //杠杆 var VarietiesIndx =[] //交易品种 var PriceCancelRatio =[]; //撤单比例 var Slide =[]; //滑动值 var CloseNarrowSpreadList =[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]; //同一方向平仓值 var curVarietiesIndex =[0,0,0,0,0,0,0,0,0,0,0,0]; //0 当前执行品种下标 1当前平台执行标记 var curPlatformIndex =[]; //用于标记当前哪两个平台在对比价差(比如说下标0、下标1的交易所相互对比) var ArbitrageSpreadList =[[],[],[],[],[],[],[],[],[],[],[],[]]; //套利价差 var ArbitrageAmountList =[[],[],[],[],[],[],[],[],[],[],[],[]]; //交易数量 var OrderInfoArry =[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]; //我的订单信息(主要记录订单类型与订单号) var CanCelOrderCheckTimer =[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; //撤销订单检测时间 var LastBarTime =[]; var DifferentHistory =[0,0,0,0,0] //价差历史 /////k线行情信息// var __lastDiff = 0; var cfg = { tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'}, title : { text : '差价分析图'}, rangeSelector: { buttons: [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}], selected: 0, inputEnabled: false }, xAxis: { type: 'datetime'}, yAxis : { plotLines : [{ value : 0.0, color : 'black', dashStyle : 'shortdash', width : 3, }, { value : NormalDiff, color : 'green', dashStyle : 'shortdash', width : 1, }, { value : HighDiff, color : 'red', dashStyle : 'shortdash', width : 1, },{ value : -NormalDiff, color : 'green', dashStyle : 'shortdash', width : 1, }, { value : -HighDiff, color : 'red', dashStyle : 'shortdash', width : 1, }] }, series : [{ name : '价差', data : [], tooltip: { valueDecimals: 2 } }] }; function _N(v, precision) { if (typeof(precision) != 'number') { precision = 4; } var d = parseFloat(v.toFixed(Math.max(10, precision+5))); s = d.toString().split("."); if (s.length < 2 || s[1].length <= precision) { return d; } var b = Math.pow(10, precision); return Math.floor(d*b)/b; } function GetTicker(e) { if (typeof(e) == 'undefined') { e = exchange; } var ticker; while (!(ticker = e.GetTicker())) { Sleep(Interval); } return ticker; } var curArbitrageInfo = //当前信息 [ { SpreadIndex:0, //价差下标 UsedAmount:0, //当前价差,已用数量 LastArbitrageType:0 //最后一次套利类型,若套利类型发生变种,则套利价差下标也需进行变动. }, { SpreadIndex:0, //价差下标 UsedAmount:0, //当前价差,已用数量 LastArbitrageType:0 //最后一次套利类型,若套利类型发生变种,则套利价差下标也需进行变动. }, { SpreadIndex:0, //价差下标 UsedAmount:0, //当前价差,已用数量 LastArbitrageType:0 //最后一次套利类型,若套利类型发生变种,则套利价差下标也需进行变动. }, { SpreadIndex:0, //价差下标 UsedAmount:0, //当前价差,已用数量 LastArbitrageType:0 //最后一次套利类型,若套利类型发生变种,则套利价差下标也需进行变动. }, ]; //数量转换 function CoinToSheetsAmount(curPrice,CoinAmount,ContractPrice) { var value =curPrice *CoinAmount / ContractPrice; if(value <1) { value =1; } return _N(value, 0); } //张数转换为数量 function SheetsToCoinAmount(curPrice,SheetsAmount,ContractPrice) { var value =SheetsAmount * ContractPrice/curPrice; // Log("SheetsAmount",SheetsAmount,"ContractPrice",ContractPrice,"curPrice",curPrice); return _N(value, 3); } //PD_LONG 多头仓位 PD_SHORT 空头仓位 function GetPosition(Index,posType) { var positions = _C(exchanges[Index].GetPosition); for (var i = 0; i < positions.length; i++) { if (positions[i].Type === posType) { return [positions[i].Price, positions[i].Amount]; } } return [0, 0]; } //获取交易所基础信息 function getExchangesBaseInfo() { var details = []; for (var i = 0; i < exchanges.length; i++) { //只获取当前对比的两个交易所.. var account =null; var ticker =null; var LongPosition =null; var ShortPosition =null; var depth =null; if(exchanges[curPlatformIndex[i]].GetName() == 'Futures_OKCoin' || exchanges[curPlatformIndex[i]].GetName() == 'Futures_HuobiDM') {//合约则获取持仓信息 LongPosition = GetPosition(curPlatformIndex[i],PD_LONG); ShortPosition = GetPosition(curPlatformIndex[i],PD_SHORT); } var accountTemp =exchanges[curPlatformIndex[i]].Go("GetAccount"); var tickerTemp =exchanges[curPlatformIndex[i]].Go("GetTicker"); var depthTemp =exchanges[curPlatformIndex[i]].Go("GetDepth"); ticker =tickerTemp.wait(); depth =depthTemp.wait(); account =accountTemp.wait(); if(ticker ==null ||depth ==null || account ==null) { //若数据获取失败了,则直接pass.. break; } details.push({account: account, ticker: ticker,depth: depth,LongPosition:LongPosition,ShortPosition:ShortPosition}); } return details; } //获取价格差 参数:现货下标,数据集,类型 function GetPriceDifferent(ExchangeInfo) { var Different =0; var Type =0; //正向计算获取价差 如果合约价格 >现货价格,则按 正的方式进行计算价差,否则按反的方式计算.. var curSpread =ArbitrageSpreadList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex]; var curUsedAmount =curArbitrageInfo[curVarietiesIndex[1]].UsedAmount; var curMaxArbitrageAmount =ArbitrageAmountList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex] ; var BuyAveragePrice =[0,0,0,0,0,0]; //买均价 var SellAveragePrice =[0,0,0,0,0,0]; //卖均价 for(var n =0;n<=BuyDepthIndex;n++) {//买价 BuyAveragePrice[0] +=ExchangeInfo[0].depth.Bids[n].Price; BuyAveragePrice[1] +=ExchangeInfo[1].depth.Bids[n].Price; } BuyAveragePrice[0] =BuyAveragePrice[0] /(BuyDepthIndex+1); //均价 BuyAveragePrice[1] =BuyAveragePrice[1] /(BuyDepthIndex+1); //均价 for(var n =0;n<=SellDepthIndex;n++) {//卖价 SellAveragePrice[0] +=ExchangeInfo[0].depth.Asks[n].Price; SellAveragePrice[1] +=ExchangeInfo[1].depth.Asks[n].Price; } SellAveragePrice[0] =SellAveragePrice[0] /(SellDepthIndex+1); //计算出均价 SellAveragePrice[1] =SellAveragePrice[1] /(SellDepthIndex+1); //计算出均价 if(BuyAveragePrice[0] >SellAveragePrice[1] ) { //交易所0开空 ,交易所1开多 Different =BuyAveragePrice[0] -SellAveragePrice[1]; Type =1; } else if(BuyAveragePrice[1] >SellAveragePrice[0]) { //交易所1开空 ,交易所0开多 Different =BuyAveragePrice[1] -SellAveragePrice[0]; Type =2; } if(ExchangeInfo[0].depth.Bids[0].Price <ExchangeInfo[0].depth.Bids[1].Price || ExchangeInfo[1].depth.Bids[0].Price <ExchangeInfo[1].depth.Bids[1].Price || ExchangeInfo[0].depth.Asks[0].Price >ExchangeInfo[0].depth.Asks[1].Price || ExchangeInfo[1].depth.Asks[0].Price >ExchangeInfo[1].depth.Asks[1].Price) { Type =0; Different =0; Log("平台抽风,价格排序不正确!!!!"); } return {TYPE:Type,DIFFERENT:Different}; //返回值 类型(正向期空现多 ==1 反向期多现空==2) ,价差 } //动态计算数量,依据盘口挂单数量多少进行最合适的数量 function CalcAmount(ExchangeInfo,Type) { var amount =0; var BuyTotalAmount =[0,0,0,0,0,0,0]; var SellTotalAmount =[0,0,0,0,0,0,0]; for(var n =0; n<=BuyDepthIndex;n++) { BuyTotalAmount[0] +=ExchangeInfo[0].depth.Bids[n].Amount; BuyTotalAmount[1] +=ExchangeInfo[1].depth.Bids[n].Amount; } for (var n =0;n <=SellDepthIndex;n++) { SellTotalAmount[0] +=ExchangeInfo[0].depth.Asks[n].Amount; SellTotalAmount[1] +=ExchangeInfo[1].depth.Asks[n].Amount; } if(Type ==1) { //交易所0开空 ,交易所1开多 amount =Math.min(BuyTotalAmount[0],SellTotalAmount[1]); //计算两个平台买卖深度最小值(取最小值进行下单,防止深度不足坑的很..) //取出深度最小的值但是深度最小值不能大于限定的下单张数 amount =Math.min(amount,ArbitrageAmountList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex]); } else if(Type ==2) {//交易所0开多,交易所1开空 amount =Math.min(SellTotalAmount[0],BuyTotalAmount[1]); //取出深度最小的值但是深度最小值不能大于限定的下单张数 amount =Math.min(amount,ArbitrageAmountList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex]); } else if(Type ==3) {// 0 平空 , 1 平多 amount =Math.min(SellTotalAmount[0],BuyTotalAmount[1]); //取出深度最小的值但是深度最小值不能大于限定的下单张数 var MinPostion = Math.min(ExchangeInfo[0].ShortPosition[1],ExchangeInfo[1].LongPosition[1]); //平仓,取数量最小一边的数量 amount =Math.min(amount,MinPostion); } else if(Type ==4) {//平 交易所0平多,交易所1平空 amount =Math.min(BuyTotalAmount[0],SellTotalAmount[1]); var MinPostion = Math.min(ExchangeInfo[0].LongPosition[1],ExchangeInfo[1].ShortPosition[1]); //平仓,取数量最小一边的数量 amount =Math.min(amount,MinPostion); } if(Type ==1 || Type ==2) {//只有是开仓类型时才进行这样的判断... //剩余数量(最大可开仓数量) var SurplusAmount =ArbitrageAmountList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex] -curArbitrageInfo[curVarietiesIndex[1]].UsedAmount; amount =amount >SurplusAmount?SurplusAmount:amount; amount =amount>0?amount:1; //默认为张数(这里加个三目,主要目的在于防止计算出数量为0的值..) } else if(Type ==3 || Type ==4) {//平仓修改后分批平仓后,平仓数量不能大于当前档位最大数量 //求出上一次开仓下标,若上一次开仓下标小于0,则强制归置为0 if(curArbitrageInfo[curVarietiesIndex[1]].UsedAmount ==0) {//若当前档位没有多余数量则直接取上一次开仓的数量进行平仓计算 var MinSpreadIndex =curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex -1 <=0?0:curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex -1; //最小价差下标 amount =Math.min(amount,ArbitrageAmountList[curVarietiesIndex[0]][MinSpreadIndex]); } else { //若当前档位有零散数量,则直接取以零散数量为主的数量 amount =Math.min(amount,curArbitrageInfo[curVarietiesIndex[1]].UsedAmount); } } return amount; //返回张数值.. } //开始套利函数 function OpenArbitrage(DifferentInfo,ExchangeInfo) { var TreadAmount = CalcAmount(ExchangeInfo,DifferentInfo.TYPE); var OrderIdA =null; var OrderIdB =null; var OrderAWait =null; var OrderBWait =null; if(DifferentInfo.TYPE ==1) { //交易所0开空 ,交易所1开多 while(OrderIdA ==null &&OrderIdB ==null) { if(OrderIdA ==null) { exchanges[curPlatformIndex[0]].SetDirection("sell"); //设置下单类型为做空 OrderAWait = exchanges[curPlatformIndex[0]].Go("Sell",MarketState ==true?-1:ExchangeInfo[0].depth.Bids[BuyDepthIndex].Price -Slide[curVarietiesIndex[0]],TreadAmount); //原始数量下单 } if(OrderIdB ==null) { exchanges[curPlatformIndex[1]].SetDirection("buy"); //设置下单类型为做多 OrderBWait = exchanges[curPlatformIndex[1]].Go("Buy",MarketState ==true?-1:ExchangeInfo[1].depth.Asks[SellDepthIndex].Price +Slide[curVarietiesIndex[0]], TreadAmount); //数量以转换 } OrderIdA = OrderAWait.wait(); OrderIdB = OrderBWait.wait(); if(MarketState !=true &&(OrderIdA ==null || OrderIdB ==null)){ ExchangeInfo = getExchangesBaseInfo(); //刷新数据(重新挂单) } } OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdA,Type:2}); //订单信息保存至容器 OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdB,Type:1}); //订单信息保存至容器 } else if(DifferentInfo.TYPE ==2) { //交易所0开多,交易所1开空 while(OrderIdA ==null &&OrderIdB ==null) { if(OrderIdA ==null) { exchanges[curPlatformIndex[0]].SetDirection("buy"); //设置下单类型为做多 OrderAWait =exchanges[curPlatformIndex[0]].Go("Buy",MarketState ==true?-1:ExchangeInfo[0].depth.Asks[SellDepthIndex].Price +Slide[curVarietiesIndex[0]], TreadAmount); //数量以转换 } if(OrderIdB ==null) { exchanges[curPlatformIndex[1]].SetDirection("sell"); //设置下单类型为做空 OrderBWait =exchanges[curPlatformIndex[1]].Go("Sell",MarketState ==true?-1:ExchangeInfo[1].depth.Bids[BuyDepthIndex].Price -Slide[curVarietiesIndex[0]],TreadAmount); //原始数量下单 } OrderIdA = OrderAWait.wait(); OrderIdB = OrderBWait.wait(); if(MarketState !=true &&(OrderIdA ==null || OrderIdB ==null)){ ExchangeInfo = getExchangesBaseInfo(); //刷新数据(重新挂单) } } OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdA,Type:1}); OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdB,Type:2}); } curArbitrageInfo[curVarietiesIndex[1]].UsedAmount +=TreadAmount; if(curArbitrageInfo[curVarietiesIndex[1]].UsedAmount >=ArbitrageAmountList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex]) { curArbitrageInfo[curVarietiesIndex[1]].UsedAmount =0; //下标最低值为0,小于0则强制归0 curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex =curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex++ >ArbitrageSpreadList[curVarietiesIndex[0]].length?curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex:curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex++; } //修改当前下标类型 curArbitrageInfo[curVarietiesIndex[1]].LastArbitrageType =DifferentInfo.TYPE; } //平仓 结束一轮套利 function CloseArbitrage(DifferentInfo,ExchangeInfo) { var TreadAmount = CalcAmount(ExchangeInfo,DifferentInfo.TYPE); var OrderIdA =null; var OrderIdB =null; var OrderAWait =null; var OrderBWait =null; if(TreadAmount >0) { if(DifferentInfo.TYPE ==3) { //平 交易所0开空 ,交易所1开多 // 平空 , 平多 while(OrderIdA ==null &&OrderIdB ==null) { if(OrderIdA ==null){ exchanges[curPlatformIndex[0]].SetDirection("closesell"); OrderAWait =exchanges[curPlatformIndex[0]].Go("Buy",MarketState ==true?-1:ExchangeInfo[0].depth.Asks[SellDepthIndex].Price +Slide[curVarietiesIndex[0]],TreadAmount); } if(OrderIdB ==null){ exchanges[curPlatformIndex[1]].SetDirection("closebuy"); OrderBWait =exchanges[curPlatformIndex[1]].Go("Sell",MarketState ==true?-1:ExchangeInfo[1].depth.Bids[BuyDepthIndex].Price -Slide[curVarietiesIndex[0]], TreadAmount); //卖出平多仓 } OrderIdA = OrderAWait.wait(); OrderIdB = OrderBWait.wait(); if(MarketState !=true &&(OrderIdA ==null || OrderIdB ==null)){ ExchangeInfo = getExchangesBaseInfo(); //刷新数据(重新挂单) } } OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdA,Type:4}); OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdB,Type:3}); } else if(DifferentInfo.TYPE ==4) {//平 交易所0平多,交易所1平空 while(OrderIdA ==null &&OrderIdB ==null) { if(OrderIdA ==null) { exchanges[curPlatformIndex[0]].SetDirection("closebuy"); OrderAWait =exchanges[curPlatformIndex[0]].Go("Sell",MarketState ==true?-1:ExchangeInfo[0].depth.Bids[BuyDepthIndex].Price -Slide[curVarietiesIndex[0]], TreadAmount); //卖出平多仓 } if(OrderIdB ==null) { exchanges[curPlatformIndex[1]].SetDirection("closesell"); OrderBWait =exchanges[curPlatformIndex[1]].Go("Buy",MarketState ==true?-1:ExchangeInfo[1].depth.Asks[SellDepthIndex].Price +Slide[curVarietiesIndex[0]],TreadAmount); } OrderIdA = OrderAWait.wait(); OrderIdB = OrderBWait.wait(); if(MarketState !=true &&(OrderIdA ==null || OrderIdB ==null)){ ExchangeInfo = getExchangesBaseInfo(); //刷新数据(重新挂单) } } OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdA,Type:3}); OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderIdB,Type:4}); } } else { Log("平仓失败,有一方可平仓数量小于0张!!!,类型:",DifferentInfo.TYPE); return; } curArbitrageInfo[curVarietiesIndex[1]].UsedAmount -=TreadAmount; if(curArbitrageInfo[curVarietiesIndex[1]].UsedAmount <=0) { curArbitrageInfo[curVarietiesIndex[1]].UsedAmount =0; //下标最低值为0,小于0则强制归0 curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex =curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex--<=0?0:curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex--; } } //合约价格撤单检测 function FuturePriceCancelCheck(Index,ExchangeInfo,CancelValue) { if(IsVirtual() ==true) {//若是模拟不用撤单功能.... return ; } var orders = exchanges[Index].GetOrders(); var Type =0; var OrderId =0; if(orders ==null ||orders.length <=0) {//没有未成交订单则直接返回.... return; } //主要目的用于修正类型(开多、开空、平多、平空) for(var l =0;l <OrderInfoArry[curVarietiesIndex[1]].length;l++) { for(var n =0;n <orders.length;n++) { if(orders[n].Id ==OrderInfoArry[curVarietiesIndex[1]][l].OrderId) { orders[n].Type =OrderInfoArry[curVarietiesIndex[1]][l].Type; break; } } } for(var n =0;n <orders.length;n++) { if(Math.abs(orders[n].Price - ExchangeInfo[Index].ticker.Last) >CancelValue) {//若超出指定值,则进行撤单,重新挂单.. if(exchanges[Index].CancelOrder(orders[n].Id) ==true) { Sleep(2000); //延时2秒,主要防止撤销订单后服务器无法及时响应.. var curOrderInfo =_C(exchanges[Index].GetOrder,orders[n].Id); if(curOrderInfo.Status !=ORDER_STATE_CANCELED || curOrderInfo.Status ==ORDER_STATE_CLOSED) { Log("撤销重新挂单,撤单失败,当前订单状态不为已撤单,返回...当前状态:",curOrderInfo.Status,"当前id",orders[n].Id); return false; } Log("撤单 类型,",orders[n].Type,"数量:",orders[n].Amount -orders[n].DealAmount,"交易所下标:",Index,"订单id:",orders[n].Id); if(orders[n].Type ==1) { exchanges[Index].SetDirection("buy"); //开多 OrderId =_C(exchanges[Index].Buy,MarketState ==true?-1:ExchangeInfo[Index].depth.Asks[SellDepthIndex].Price +Slide[curVarietiesIndex[0]],orders[n].Amount -orders[n].DealAmount); //原始数量下单 Type =1; break; } else if(orders[n].Type ==2) { exchanges[Index].SetDirection("sell"); //开空 OrderId =_C(exchanges[Index].Sell,MarketState ==true?-1:ExchangeInfo[Index].depth.Bids[BuyDepthIndex].Price -Slide[curVarietiesIndex[0]],orders[n].Amount -orders[n].DealAmount); //原始数量下单 Type =2; break; } else if(orders[n].Type ==3) { exchanges[Index].SetDirection("closebuy"); OrderId =_C(exchanges[Index].Sell,MarketState ==true?-1:ExchangeInfo[Index].depth.Bids[BuyDepthIndex].Price -Slide[curVarietiesIndex[0]], orders[n].Amount -orders[n].DealAmount); //卖出平多仓 Type =3; break; } else if(orders[n].Type ==4) { exchanges[Index].SetDirection("closesell"); OrderId =_C(exchanges[Index].Buy,MarketState ==true?-1:ExchangeInfo[Index].depth.Asks[SellDepthIndex].Price +Slide[curVarietiesIndex[0]],orders[n].Amount -orders[n].DealAmount); Type =4; break; } } } } if(Type !=0) //若数值不为空则将新订单信息push进去.. { OrderInfoArry[curVarietiesIndex[1]].push({OrderId:OrderId,Type:Type}); //撤单后新的挂单依旧push进去保存.. } return false; } //保存部分核心变量的值至本地 function SaveVarValue() { _G("curArbitrageInfo"+curVarietiesIndex[1].toString()+"LastArbitrageType", curArbitrageInfo[curVarietiesIndex[1]].LastArbitrageType); _G("curArbitrageInfo"+curVarietiesIndex[1].toString()+"SpreadIndex", curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex); _G("curArbitrageInfo"+curVarietiesIndex[1].toString()+"UsedAmount", curArbitrageInfo[curVarietiesIndex[1]].UsedAmount); } //读取本地内容 function ReadVarValue(n) { curArbitrageInfo[n].LastArbitrageType =_G("curArbitrageInfo"+n.toString()+"LastArbitrageType"); curArbitrageInfo[n].SpreadIndex =_G("curArbitrageInfo"+n.toString()+"SpreadIndex"); curArbitrageInfo[n].UsedAmount =_G("curArbitrageInfo"+n.toString()+"UsedAmount"); if(curArbitrageInfo[n].LastArbitrageType ==null || curArbitrageInfo[n].SpreadIndex ==null || curArbitrageInfo[n].UsedAmount ==null) {//若配置内容无数据,则直接将其归0 curArbitrageInfo[n].LastArbitrageType =0; curArbitrageInfo[n].SpreadIndex =0; curArbitrageInfo[n].UsedAmount =0; } Log("读取本地配置值:",curArbitrageInfo[n].LastArbitrageType,curArbitrageInfo[n].SpreadIndex,curArbitrageInfo[n].UsedAmount); } function onTick(exchanges) { var records =_C(exchanges[0].GetRecords,PERIOD_M1); //默认1小时 var ExchangeInfo = getExchangesBaseInfo(); //获取数据 if(ExchangeInfo.length <2 || records ==null || ExchangeInfo[0].account.Stocks ==0 || ExchangeInfo[1].account.Stocks ==0) { return;//若两个交易所有一个交易所无保证金或数据只有一个货币对,则直接pass } var DifferentInfo =GetPriceDifferent(ExchangeInfo); DifferentHistory[curVarietiesIndex[0]] =DifferentInfo.DIFFERENT; //记录不同品种价差记录,用于日志刷新... if(ExchangeInfo[0].ShortPosition[1] !=ExchangeInfo[1].LongPosition[1]|| ExchangeInfo[1].ShortPosition[1] !=ExchangeInfo[0].LongPosition[1]) { //若持仓数量不相等,则不进行任何开平仓操作,防止火币合约抽风,导致都是单边持仓..,这样最多只有一个价位单是单边,风险可控.. DifferentInfo.TYPE =-1; //没有任何类型,直接屏蔽... } var Bar = records[records.length - 1]; if (LastBarTime[curVarietiesIndex[0]] !== Bar.Time) { if(IsShowLog ==true) {//是否显示日志 Log("价差信息:",DifferentInfo," 持仓信息",ExchangeInfo[0].ShortPosition[1],ExchangeInfo[0].LongPosition[1], ExchangeInfo[1].ShortPosition[1],ExchangeInfo[1].LongPosition[1],"当前价差下标:",curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex,"当前已用数量:",curArbitrageInfo[curVarietiesIndex[1]].UsedAmount, "平台0价格:",ExchangeInfo[0].ticker.Last,"平台1价格:",ExchangeInfo[1].ticker.Last); } if(ExchangeInfo[0].ShortPosition[1] !=ExchangeInfo[1].LongPosition[1]|| ExchangeInfo[1].ShortPosition[1] !=ExchangeInfo[0].LongPosition[1]) { //若持仓数量不相等,则不进行任何开平仓操作,防止火币合约抽风,导致都是单边持仓.. DifferentInfo.TYPE =-1; //没有任何类型,直接屏蔽... } //图表.. var diff = ExchangeInfo[0].ticker.Last - ExchangeInfo[1].ticker.Last; var strLogStatus =""; for(var LogN =0;LogN <VarietiesCount;LogN++) { var TempLogStatus ="符号 : " +VarietiesIndx[LogN]+"差价:"+ DifferentHistory[LogN].toString()+"\r\n"; strLogStatus+=TempLogStatus; } strLogStatus+="\r\n说起爆仓我就想起了对冲,无风险对冲,有需要的老板可以联系,文体两开花,懂得自然懂!!\r\n 租用1888元/一月,3888元/季 微信:fzq250 "; LogStatus(strLogStatus); if (__lastDiff != 0) { if (Math.abs(Math.abs(diff) - Math.abs(__lastDiff)) > 200) { return; } } if(curVarietiesIndex[0] ==0) { cfg.yAxis.plotLines[0].value=diff; // cfg.subtitle={text:'当前价差:' + diff}; __chart.update([cfg,cfg]); __chart.add([0, [new Date().getTime(), diff]]); } else if(curVarietiesIndex[0] ==1) { cfg.yAxis.plotLines[1].value=diff; // cfg.subtitle={text:'当前价差:' + diff}; __chart.update([cfg,cfg]); __chart.add([1, [new Date().getTime(), diff]]); } SaveVarValue(); //定时保存值至本地 LastBarTime[curVarietiesIndex[0]] = Bar.Time; } if((curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex <=0 &&curArbitrageInfo[curVarietiesIndex[1]].UsedAmount <=0)|| (ExchangeInfo[0].ShortPosition[1]==0&&ExchangeInfo[0].LongPosition[1]==0&& ExchangeInfo[1].ShortPosition[1]==0&&ExchangeInfo[1].LongPosition[1]==0)) {//若当前价差下标与当前已用数量==0则重新初始化.. var PlatformAOrder =exchanges[curPlatformIndex[0]].GetOrders(); var PlatformBOrder =exchanges[curPlatformIndex[1]].GetOrders(); if(PlatformAOrder !=null&&PlatformBOrder !=null &&PlatformAOrder.length <=0 &&PlatformBOrder.length <=0 ) {//若两个平台都没有未成交订单并且又没有持仓订单,则订单数组可清空...,否则一旦清空有未成交订单则很麻烦.. curArbitrageInfo[curVarietiesIndex[1]].LastArbitrageType =0; curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex =0; curArbitrageInfo[curVarietiesIndex[1]].UsedAmount =0; OrderInfoArry[curVarietiesIndex[1]] =[]; //清空订单数组 } } //正向计算获取价差 如果合约价格 >现货价格,则按 正的方式进行计算价差,否则按反的方式计算.. var curOpenSpread =ArbitrageSpreadList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex]; var curUsedAmount =curArbitrageInfo[curVarietiesIndex[1]].UsedAmount; var curMaxArbitrageAmount =ArbitrageAmountList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex] ; var LastArbitrageType =curArbitrageInfo[curVarietiesIndex[1]].LastArbitrageType; //当前平仓价差值 var curCloseSpread =CloseNarrowSpreadList[curVarietiesIndex[0]][curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex]; if(curArbitrageInfo[curVarietiesIndex[1]].UsedAmount ==0) {//若当前档位没有多余数量则直接取上一次开仓的数量进行平仓计算 var MinSpreadIndex =curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex -1 <=0?0:curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex -1; //最小价差下标 curCloseSpread =CloseNarrowSpreadList[curVarietiesIndex[0]][MinSpreadIndex]; } if(curArbitrageInfo[curVarietiesIndex[1]].SpreadIndex <ArbitrageSpreadList[curVarietiesIndex[0]].length) { if(DifferentInfo.TYPE ==1 &&DifferentInfo.DIFFERENT >curOpenSpread &&curMaxArbitrageAmount >curUsedAmount) { //交易所0开空 ,交易所1开多 DifferentInfo.TYPE =1; OpenArbitrage(DifferentInfo,ExchangeInfo); } else if(DifferentInfo.TYPE ==2 &&DifferentInfo.DIFFERENT >curOpenSpread &&curMaxArbitrageAmount >curUsedAmount) {//交易所0开多,交易所1开空 DifferentInfo.TYPE =2; OpenArbitrage(DifferentInfo,ExchangeInfo); } } //平仓检测_剥离出去.. if(LastArbitrageType ==1 &&DifferentInfo.TYPE ==1 &&DifferentInfo.DIFFERENT <=curCloseSpread) {//平仓 平0空 平1多 DifferentInfo.TYPE =3; CloseArbitrage(DifferentInfo,ExchangeInfo); } else if(LastArbitrageType ==2 &&DifferentInfo.TYPE ==2 &&DifferentInfo.DIFFERENT <=curCloseSpread) {//平仓 平0多 平1空 DifferentInfo.TYPE =4; CloseArbitrage(DifferentInfo,ExchangeInfo); } //这里为交易所价差反转情况下平仓逻辑(A >B 现在为B<A 那么之前的开仓应平掉.) //这里不判断下标,只判断价差是否反转,反转则平.. if(DifferentInfo.TYPE ==1 && DifferentInfo.DIFFERENT >0 && ExchangeInfo[0].LongPosition[1]!=0 &&ExchangeInfo[1].ShortPosition[1]!=0) {//若类型==1并有相反方向开仓,则平掉 交易所0开多,交易所1开空 DifferentInfo.TYPE =4; CloseArbitrage(DifferentInfo,ExchangeInfo); Log("价差发生反转,平仓...",DifferentInfo.TYPE); } else if(DifferentInfo.TYPE ==2 && DifferentInfo.DIFFERENT >0 && ExchangeInfo[0].ShortPosition[1]!=0 &&ExchangeInfo[1].LongPosition[1]!=0) {//若类型==2 并有相反方向开仓,则平掉 交易所0开空 ,交易所1开多 DifferentInfo.TYPE =3; CloseArbitrage(DifferentInfo,ExchangeInfo); Log("价差发生反转,平仓...",DifferentInfo.TYPE); } if(CanCelOrderCheckTimer[curVarietiesIndex[1]]++ >3) { //每隔5秒检测一次撤单 FuturePriceCancelCheck(curPlatformIndex[0],ExchangeInfo,PriceCancelRatio[curVarietiesIndex[0]]/100*ExchangeInfo[0].ticker.Last); FuturePriceCancelCheck(curPlatformIndex[1],ExchangeInfo,PriceCancelRatio[curVarietiesIndex[0]]/100*ExchangeInfo[1].ticker.Last); CanCelOrderCheckTimer[curVarietiesIndex[1]] =0; //归0,重新计数 } set_command(); //设置交互信息 } function main() { Log("交易所0:",exchanges[0].GetName(),"符号:",exchanges[0].GetCurrency(),exchanges[0].GetAccount()); Log("交易所1:",exchanges[1].GetName(),"符号:",exchanges[1].GetCurrency(),exchanges[1].GetAccount()); __chart = Chart(cfg); var strContractTypeIdxArray =ContractTypeIdxString.split("|"); var strMarginLevelIdxArray =MarginLevelIdxString.split("|"); var strVarietiesArray =VarietiesString.split("|"); var strPriceCancelRatioArray =PriceCancelRatioString.split("|"); var strSlideArray =SlideString.split("|"); // var strCloseNarrowSpreadArray =CloseNarrowSpreadString.split("|"); var strArbitrageSpreadArrayA =ArbitrageSpreadString.split("#"); var strArbitrageAmountA =ArbitrageAmountString.split("#"); //#号拆分符号分割 for(var n =0;n<strArbitrageSpreadArrayA.length;n++) { //拆分套利价差 var strArbitrageSpreadArrayB =strArbitrageSpreadArrayA[n].split("|"); for(var l=0;l <strArbitrageSpreadArrayB.length;l++) { ArbitrageSpreadList[n][l] =parseFloat(strArbitrageSpreadArrayB[l]); } } for(var n =0;n<strArbitrageAmountA.length;n++) { //拆分交易数量 var strArbitrageAmountB =strArbitrageAmountA[n].split("|"); //|号拆分具体数据 for(var l=0;l <strArbitrageAmountB.length;l++) { ArbitrageAmountList[n][l] =parseFloat(strArbitrageAmountB[l]); } } var strCloseNarrowSpreadArray =CloseNarrowSpreadString.split("#"); for(var n =0;n<strCloseNarrowSpreadArray.length;n++) { //拆分平仓价差 var strCloseNarrowSpreadB =strCloseNarrowSpreadArray[n].split("|"); //|号拆分具体数据 for(var l=0;l <strCloseNarrowSpreadB.length;l++) { CloseNarrowSpreadList[n][l] =parseFloat(strCloseNarrowSpreadB[l]); Log("平仓价差:", CloseNarrowSpreadList[n][l] ); } } for(var n =0;n<2;n++) //最大数量为交易品种的数量 { ContractTypeIdx[n] =strContractTypeIdxArray[n]; MarginLevelIdx[n] =parseInt(strMarginLevelIdxArray[n]); VarietiesIndx[n] =strVarietiesArray[n]; PriceCancelRatio[n] =parseFloat(strPriceCancelRatioArray[n]); Slide[n] =parseFloat(strSlideArray[n]); } for(var n =0;n<exchanges.length;n++) { exchanges[n].SetPrecision(3, 1); exchanges[n].SetRate(1); exchanges[n].SetContractType(ContractTypeIdx[n]); exchanges[n].SetMarginLevel(MarginLevelIdx[n]); Log("交易所:",n,"当前合约类型:",ContractTypeIdx[n],"杠杆:",MarginLevelIdx[n]); } for(var a =0;a <exchanges.length;a++) { for(var b =a+1;b <exchanges.length;b++) { for(var n =0; n <VarietiesCount;n++) { ReadVarValue(a+b+n); //读取本地配置信息 } } } if(IsDeleteGloablConfig ==true) { //删除_G保留的配置信息 _G(null); // 删除所有全局变量 } while(true) { for(var a =0;a <exchanges.length;a++) { for(var b =a+1;b <exchanges.length;b++) { curPlatformIndex[0] =a; //交易所0 curPlatformIndex[1] =b; //交易所1 for(var n =0; n <VarietiesCount;n++) { curVarietiesIndex[0] =n; //当前执行下标,用于更换品种 curVarietiesIndex[1] =a+b+n; //当前交易所所与交易对标记0\1\2\3\4\5以此类推.. if(IsVirtual() ==false) {//实盘则进行符号切换 exchanges[curPlatformIndex[0]].IO("currency", VarietiesIndx[n]+"_USD"); //合约符号更改 exchanges[curPlatformIndex[1]].IO("currency", VarietiesIndx[n]+"_USD"); //现货符号更改 } onTick(exchanges); Sleep(1000); //延时1秒 } } } Sleep(LoopInterval * 1000); } } //获取动态参数(策略交互内容) function set_command() { var get_command = GetCommand();// GetCommand方法是获取参数方法,获取的参数是字符串形式 格式为 "参数名:参数值" 参见BotVS API文档 if (get_command != null) { if (get_command.indexOf("ModifyArbitrageSpread:") == 0) { //如果传入的参数名为A3(以“A3:”打头,即表明是A3参数) var AAA = (get_command.replace("ModifyArbitrageSpread:", "")); //赋值给策略里面的AAA(将打头字符串替换为空,剩下就是我们的参数值) var strArbitrageSpreadArrayA =AAA.split("#"); for(var n =0;n<strArbitrageSpreadArrayA.length;n++) { //拆分套利价差 var strArbitrageSpreadArrayB =strArbitrageSpreadArrayA[n].split("|"); for(var l=0;l <strArbitrageSpreadArrayB.length;l++) { ArbitrageSpreadList[n][l] =parseFloat(strArbitrageSpreadArrayB[l]); Log("新的值:",ArbitrageSpreadList[n][l]); } } } if (get_command.indexOf("ModifyArbitrageAmount:") == 0) { //如果传入的参数名为B3(以“B3:”打头,即表明是B3参数) var BBB = (get_command.replace("ModifyArbitrageAmount:", "")); //赋值给策略里面的BBB(将打头字符串替换为空,剩下就是我们的参数值) var strArbitrageAmountA =BBB.split("#"); //#号拆分符号分割 for(var n =0;n<strArbitrageAmountA.length;n++) { //拆分交易数量 var strArbitrageAmountB =strArbitrageAmountA[n].split("|"); //|号拆分具体数据 for(var l=0;l <strArbitrageAmountB.length;l++) { ArbitrageAmountList[n][l] =parseFloat(strArbitrageAmountB[l]); Log("新的值:",ArbitrageAmountList[n][l]); } } } if (get_command.indexOf("ModifyCloseNarrowSpread:") == 0) { //如果传入的参数名为B3(以“B3:”打头,即表明是B3参数) var CCC = (get_command.replace("ModifyCloseNarrowSpread:", "")); //赋值给策略里面的BBB(将打头字符串替换为空,剩下就是我们的参数值) var strCloseNarrowSpreadArray =CCC.split("#"); for(var n =0;n<strCloseNarrowSpreadArray.length;n++) { //拆分平仓价差 var strCloseNarrowSpreadB =strCloseNarrowSpreadArray[n].split("|"); //|号拆分具体数据 for(var l=0;l <strCloseNarrowSpreadB.length;l++) { CloseNarrowSpreadList[n][l] =parseFloat(strCloseNarrowSpreadB[l]); Log("新的值:", CloseNarrowSpreadList[n][l] ); } } } } }