Explicación detallada de la estrategia de órdenes pendientes de BitMEX

El autor:La bondad, Creado: 2019-01-16 15:28:13, Actualizado: 2019-01-22 14:16:48

BitMEX se ha convertido en la plataforma de elección para el comercio de apalancamiento de criptomonedas, pero sus restricciones de comercio de API son estrictas y hacen que los operadores automáticos se sientan muy confundidos.

Las características de BitMEX

La ventaja más significativa es que la liquidez de negociación es muy activa, especialmente el contrato perpetuo de Bitcoin, el monto de la transacción por minuto a menudo excede de un millón o incluso diez millones de dólares estadounidenses; BitMEX tiene la política de pago de comisiones pendientes de negociación, aunque no es mucho, pero atrajo a un gran número de operaciones de mercado, lo que hizo que la profundidad del precio sea muy rica. el último precio de compra y venta a menudo tienen más de un millón de dólares en orden pendiente; debido a este punto, el precio de la transacción a menudo fluctúa alrededor de la unidad mínima de cambio de $ 0.50.

2.Límite de frecuencia de la API de BitMEX

La frecuencia de solicitud de la API REST está limitada a 300 veces cada 5 minutos, casi igual a 1 vez por segundo, este límite se puede decir que es muy estricto en comparación con otras plataformas de negociación. Después de que se supere el límite, se le pedirá Rate limit exceeded. Si continúa excediendo el límite, la IP puede ser desactivada durante una hora. Múltiples deshabilitaciones en un corto tiempo darán lugar a una semana de desactivación. Para cada solicitud de API, BitMEX devolverá los datos de encabezado, los datos de encabezado se utilizan para ver el número actual de solicitudes restantes. De hecho, si se utiliza correctamente la API, no excederá el límite de frecuencia y generalmente no necesita ser revisado.

3.Utilizar websocket para obtener la cotización del mercado

La API REST de BitMEX es más restrictiva. La recomendación oficial es usar más el protocolo websocket y empujar más tipos de datos que el intercambio promedio. Preste atención a los siguientes puntos para un uso específico:

Se estima que hay demasiados cambios de profundidad y hay omisiones en el empuje, pero en general, debido a la excelente fluidez, se puede suscribir a ticker o trades. El pedido de detalles de empuje falta mucho y es casi indisponible. Hay un retraso significativo en el envío de la información de la cuenta, preferiblemente utilizando la API REST. Cuando la volatilidad del mercado es demasiado grande, el retraso de empuje alcanzará unos segundos. El siguiente código utiliza el protocolo websocket para obtener información de mercado y cuenta en tiempo real, principalmente para estrategias de creación de mercado.

var ticker  = {price:0, buy:0, sell:0, time:0} //Ticker information, the latest price, "buy one" price, "sell one" price, update time
//Account information, respectively, position, buying and selling price, buying and selling quantity, position status, order Id
var info = {position:0, buyPrice:0, sellPrice:0, buyAmount:0, sellAmount:0, buyState:0, sellState:0, buyId:0, sellId:0}
var buyListId = []//Global variables, pre-emptive buying id list, will described below
var sellListId = []
var APIKEY = 'your api id' //Need to fill in the BitMEX API ID here. Note that it is not a key, which is required for websocket protocol authentication.
var expires = parseInt(Date.now() / 1000) + 10
var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey}}")//The secretkey will be automatically replaced at the bottom level and does not need to be filled in.
var bitmexClient = Dial("wss://www.bitmex.com/realtime", 60)
var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})//Authentication information, otherwise you cannot subscribe to the account
bitmexClient.write(auth)
bitmexClient.write('{"op": "subscribe", "args": ["position","execution","trade:XBTUSD"]}')//Subscribed to positions, order execution and perpetual contract real-time transaction
while(true){
    var data = bitmexClient.read()
    if(data){
        bitmexData = JSON.parse(data)
        if('table' in bitmexData && bitmexData.table == 'trade'){
            data = bitmexData.data
            ticker.price = parseFloat(data[data.length-1].price)//The latest transaction price, will push multiple transactions at a time, take one will be ok
            //You can get the "buy one" and "sell one" price according to the direction of the latest transaction, without subscribing to the depth.
            if(data[data.length-1].side == 'Buy'){
                ticker.sell = parseFloat(data[data.length-1].price)
                ticker.buy = parseFloat(data[data.length-1].price)-0.5
            }else{
                ticker.buy = parseFloat(data[data.length-1].price)
                ticker.sell = parseFloat(data[data.length-1].price)+0.5
            }
            ticker.time =  new Date(data[data.length-1].timestamp);//Update time, can be used to determine the delay
        }
    }else if(bitmexData.table == 'position'){
        var position = parseInt(bitmexData.data[0].currentQty)  
        if(position != info.position){
            Log('Position change: ', position, info.position, '#FF0000@')//Position change Log, and pushed to WeChat, remove @ means Do not push
            info.position = position  
        }
        info.position  = parseInt(bitmexData.data[0].currentQty)  
    }
}

4. Habilidades para ordenar

BitMEX recomienda oficialmente el uso de ordenes masivos y modificación de pedidos para realizar pedidos. ordenes masivos se pueden ejecutar más rápido debido a la auditoría en tiempo real de BitMEX, la comprobación de riesgos, el cálculo de márgenes y la puesta en marcha. Por lo tanto, la frecuencia de los pedidos masivos se calcula como una décima parte de la frecuencia normal. Además, nuestra operación de pedidos debe usar el método de ordenes masivos y modificación de pedidos para minimizar el uso de API. El estado de la orden de consulta también necesita consumir la API utilizando la frecuencia. Puede juzgar el estado de los pedidos de acuerdo con la posición de cambio o fallo del pedido de modificación.

El pedido en masa no limita la cantidad de pedido (no puede ser demasiado), de hecho, un solo pedido también puede usar la interfaz de pedido en masa. Debido a la operación de modificar el pedido, podemos "preordenar" algunos pedidos donde el precio se desvía mucho, estos pedidos no se ejecutarán, pero cuando necesitamos realizar un pedido, solo necesitamos modificar el precio y la cantidad del pedido realizado. cuando se produce un fallo en la modificación del pedido, también se puede usar como una señal para que se ejecute el pedido.

El código específico de aplicación es el siguiente:

// Cancel all orders and reset global variables
function cancelAll(){
    exchange.IO("api","DELETE","/api/v1/order/all","symbol=XBTUSD")//Call IO extension revocation
    info = {position:0, buyPrice:0, sellPrice:0, buyAmount:0, sellAmount:0, buyState:0, sellState:0, buyId:0, sellId:0}
    buyListId = []
    sellListId = []
}
//placing alternate order
function waitOrders(){
    var orders = []
    if(buyListId.length<4){
        //When the number of inspections is insufficient, place another "bulk"
        for(var i=0;i<7;i++){
            //Due to BitMEX restrictions, the price can not be excessively excessive, the order quantity can not be too small, and the "execInst" parameter guarantees that only the market making transaction can be executed.
            orders.push({symbol:'XBTUSD', side:'Buy', orderQty:100, price:ticker.buy-400+i, execInst:'ParticipateDoNotInitiate'})
        }
    }
    if(sellListId.length<4){
        for(var i=0;i<7;i++){
            orders.push({symbol:'XBTUSD', side:'Sell', orderQty:100, price:ticker.buy+400+i, execInst:'ParticipateDoNotInitiate'})
        }
    }
    if(orders.length>0){
        var param = "orders=" + JSON.stringify(orders);
        var ids = exchange.IO("api", "POST", "/api/v1/order/bulk", param);//Bulk orders submitted here
        for(var i=0;i<ids.length;i++){
            if(ids.side == 'Buy'){
                buyListId.push(ids.orderID)
            }else{
                sellListId.push(ids.orderID)
            }
        }
    }
}
//Modify order function
function amendOrders(order, direction, price, amount, id){
    var param = "orders=" + JSON.stringify(order);
    var ret = exchange.IO("api", "PUT", "/api/v1/order/bulk", param);//Modify one order at a time
    //Modification occurs error
    if(!ret){
        var err = GetLastError()
        //overloaded unmodified strategy, need to recycle the order id
        if(err.includes('The system is currently overloaded')){
            if(id){
                if(direction == 'buy'){
                    buyListId.push(id)
                }else{
                    sellListId.push(id)
                }
            }
            Sleep(1000)
            return
        }
        //Illegal order status, indicating that the order to be modified has been completely executed
        else if(err.includes('Invalid ordStatus')){
            Log(order, direction)
            if(direction == 'buy'){
                info.buyId = 0
                info.buyState = 0
                info.buyAmount = 0
                info.buyPrice = 0
            }else{
                info.sellId = 0
                info.sellState = 0
                info.sellAmount = 0
                info.sellPrice = 0
            }
            //Since the push is not timely, update the position with the "rest" protocol here.
            pos = _C(exchange.GetPosition)
            if(pos.length>0){
                info.position = pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount
            }else{
                info.position = 0
            }
        }
        //Unknown error cannot be modified, all orders are cancelled, reset once
        else if(err.includes('Invalid orderID')){
            cancelAll()
            Log('Invalid orderID,reset once')
        }
        //Exceed the frequency limit, you can continue to try after hibernation
        else if(err.includes('Rate limit exceeded')){
            Sleep(2000)
            return
        }
        //The account is banned, all orders are revoked, and sleep is awaiting recovery for a long time.
        else if(err.includes('403 Forbidden')){
            cancelAll()
            Log('403,reset once')
            Sleep(5*60*1000)
        }
    }else{
        //Modify order successfully
        if(direction == 'buy'){
            info.buyState = 1
            info.buyPrice = price
            info.buyAmount = amount
        }else{
            info.sellState = 1
            info.sellPrice = price
            info.sellAmount = amount
        }
    }
}
//0.5 price change
function fixSize(num){
    if(num>=_N(num,0)+0.75){
        num = _N(num,0)+1
    }else if(num>=_N(num,0)+0.5){
        num=_N(num,0)+0.5
    }else{
        num=_N(num,0)
    }
    return num
}
//Trading function
function trade(){
    waitOrders()//Check if you need a replacement order
    var buyPrice = fixSize(ticker.buy-5) //For demonstration purposes only, specific transactions should be written by yourself.
    var sellPrice = fixSize(ticker.sell+5)
    var buyAmount =  500
    var sellAmount = 500
    //Modify from an alternate order when there is no order
    if(info.buyState == 0  && buyListId.length > 0){
        info.buyId = buyListId.shift()
        amendOrders([{orderID:info.buyId, price:buyPrice, orderQty:buyAmount}],'buy', group, buyPrice, buyAmount, info.buyId)
    }
    if(info.sellState == 0 && sellListId.length > 0){
        info.sellId = sellListId.shift()
        amendOrders([{orderID: info.sellId, price:sellPrice, orderQty:sellAmount}],'sell', group, sellPrice, sellAmount, info.sellId )
    }
    //Existing orders need to change price
    if(buyPrice !=  info.buyPrice && info.buyState == 1){
        amendOrders([{orderID:info.buyId, price:buyPrice, orderQty:buyAmount}],'buy', group, buyPrice, buyAmount)
    }
    if(sellPrice != info.sellPrice && info.sellState == 1){
        amendOrders([{orderID:info.sellId, price:sellPrice, orderQty:sellAmount}],'sell', group, sellPrice, sellAmount)
    }
}

5. Otros

El servidor de BitMEX está en el servidor de Amazon en Dublín, Irlanda. El ping del servidor es de menos de 1 ms cuando se elige un servidor de nube AWS en Dublín, pero cuando todavía hay un retraso en el empuje, el problema de sobrecarga no se puede resolver. Además, cuando se inicia sesión en la cuenta, el agente del servidor no puede estar ubicado en los Estados Unidos y otros lugares donde no se permiten las transacciones de criptomonedas. Debido a la regulación, la cuenta será prohibida.

El código en este artículo ha sido modificado a partir de mi estrategia personal y no se garantiza que sea completamente correcto para referencia.


Más.

GmgphilEl conector WS produce un error: ReferenceError: identificador 'datos' no definido en...

Las hierbasUn error de código, el problema ha sido solucionado.