معاہدہ ہیجنگ _ ایک سے زیادہ تھریڈ ورژن

مصنف:نشے میں چراغ کھینچ کر تلوار دیکھنا، تاریخ: 2019-01-10 21:53:37
ٹیگز:

جاوا اسکرپٹ ایک ایسا سافٹ ویئر ہے جس میں بہت ساری چیزیں شامل ہیں جو آپ کو اپنی مرضی کے مطابق کرنے کی اجازت دیتی ہیں۔دلچسپ ہے کہ دوسری بار اپ ڈیٹ تیار کیا جا سکتا ہے۔


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] );
               }
            }  
         }         
         
     }
 }



مزید