Explicação detalhada da estratégia de ordens pendentes da BitMEX

Autora:Bem-estar, Criado: 2019-01-16 15:28:13, Atualizado: 2019-01-22 14:16:48

O BitMEX tornou-se a plataforma de escolha para a negociação de alavancagem de criptomoedas, mas suas restrições de negociação de API são rigorosas e fazem com que os comerciantes automáticos se sintam muito confusos.

1. Características do BitMEX

A vantagem mais significativa é que a liquidez de negociação é muito ativa, especialmente o contrato perpétuo do Bitcoin, o valor da transação por minuto muitas vezes excede um milhão ou até dez milhões de dólares americanos; As ordens pendentes do BitMEX possuem a política de comissão de retorno, embora não seja muito, mas atraíram um grande número de negociações de mercado, o que fez a profundidade do preço muito rica. O preço de compra e venda mais recente geralmente tem mais de um milhão de dólares em ordens pendentes; por causa deste ponto, o preço da transação muitas vezes flutua em torno da unidade de mudança mínima de US $ 0,50.

2.Limite de frequência BitMEX API

A frequência de solicitação da API REST é limitada a 300 vezes a cada 5 minutos, quase igual a 1 vez por segundo, esse limite pode ser dito ser muito rigoroso em comparação com outras plataformas de negociação. Após o limite ser excedido, Rate limit exceeded será solicitado. Se você continuar excedendo o limite, o IP pode ser desativado por uma hora. Múltiplas desativações em um curto período de tempo resultarão em uma semana de desativação. Para cada solicitação de API, o BitMEX retornará os dados de cabeçalho, os dados de cabeçalho são usados para ver o número atual de solicitações restantes.

3.Utilize o websocket para obter a cotação do mercado

A API REST do BitMEX é mais restritiva. A recomendação oficial é usar mais o protocolo websocket e empurrar mais tipos de dados do que o intercâmbio médio. Preste atenção aos seguintes pontos para uso específico:

Se o tempo de inserção de dados de profundidade for muito longo, haverá um erro, que não corresponde à profundidade real. O pedido de detalhes falta muito e é quase indisponível. Há um atraso significativo na transferência de informações da conta, de preferência usando a API REST. Quando a volatilidade do mercado é muito grande, o atraso de push chegará a alguns segundos. O código a seguir utiliza o protocolo websocket para obter informações de mercado e de conta em tempo real, principalmente para estratégias de criação 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 dar ordens

O BitMEX recomenda oficialmente o uso de encomenda em massa e modificação de ordem para fazer pedidos. encomenda em massa pode ser executada mais rapidamente devido à auditoria em tempo real, verificação de riscos, cálculo de margem e comissionamento do BitMEX. Portanto, a frequência da encomenda em massa é calculada como um décimo da frequência normal. Além disso, nossa operação de ordem deve usar o método de encomenda em massa e modificação de ordem para minimizar o uso da API. O status da ordem de consulta também precisa consumir a API usando a frequência. Pode julgar o status da ordem de acordo com a posição de mudança ou falha da ordem de modificação.

O pedido em massa não limita a quantidade de pedido (não pode ser demais), na verdade, uma única ordem também pode usar a interface de pedido em massa. Devido à operação de modificação da ordem, podemos "pré-ordenar" algumas ordens onde o preço desvia muito, essas ordens não serão executadas, mas quando precisamos colocar um pedido, só precisamos modificar o preço e a quantidade da ordem colocada. quando a modificação da ordem ocorre falha, também pode ser usada como um sinal para a ordem ser executada.

O código específico de aplicação é o seguinte:

// 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. Outros

O servidor do BitMEX está no servidor da Amazon em Dublin, Irlanda. O ping do servidor é inferior a 1ms quando você escolhe um servidor de nuvem AWS em Dublin, mas quando ainda há um atraso no empurrão, o problema de sobrecarga não pode ser resolvido. Além disso, quando a conta é conectada, o agente do servidor não pode ser localizado nos Estados Unidos e em outros lugares onde não permitem negociações de criptomoedas. Devido ao regulamento, a conta será banida.

O código neste artigo foi modificado a partir da minha estratégia pessoal e não é garantido para ser completamente correto para referência.


Mais.

gmgphilO conector WS produz um erro: ReferenceError: identificador 'data' não definido em...

Ervas daninhasUm erro de código, problema resolvido.