Criptomoeda Futures Martingale-tipo de estratégia de design

Autora:Ninabadass, Criado: 2022-04-12 17:50:07, Atualizado: 2022-04-12 18:06:07

Criptomoeda Futures Martingale-tipo de estratégia de design

Recentemente, há muitas estratégias de tipo Martingale discutidas no grupo oficial da FMZ, e não há muitas estratégias de tipo Martingale de contratos de criptomoedas em nossa plataforma. Portanto, aproveitei esta oportunidade para projetar uma estratégia de tipo Martingale de futuros de criptomoedas simples. Por que é chamada de estratégia de tipo Martingale? Porque o risco potencial da estratégia Martingale não é de fato pequeno, não é necessário projetar de acordo com a estratégia Martingale. No entanto, esse tipo de estratégia ainda tem muitos riscos, e as configurações de parâmetros da estratégia de tipo Martingale estão intimamente relacionadas aos riscos, e os riscos não devem ser ignorados.

Neste artigo, explicamos principalmente e aprendemos com o design de estratégias de tipo Martingale.

Obtenção de capital total

O capital total é frequentemente usado ao projetar uma estratégia de futuros de criptomoedas, pois queremos calcular os lucros, especialmente quando precisamos calcular os lucros flutuantes.exchange.GetAccount()Na verdade, a maioria das plataformas de futuros de criptomoedas fornece os dados do patrimônio total, mas essa propriedade não é uniformemente empacotada na FMZ.

Portanto, projetamos separadamente funções para obter os dados de acordo com diferentes plataformas:

// OKEX V5 obtains the total equity 
function getTotalEquity_OKEX_V5() {
    var totalEquity = null 
    var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
    if (ret) {
        try {
            totalEquity = parseFloat(ret.data[0].details[0].eq)
        } catch(e) {
            Log("Fail to obtain the total equity of the account!")
            return null
        }
    }
    return totalEquity
}

// Binance Ftures 
function getTotalEquity_Binance() {
    var totalEquity = null 
    var ret = exchange.GetAccount()
    if (ret) {
        try {
            totalEquity = parseFloat(ret.Info.totalWalletBalance)
        } catch(e) {
            Log("Fail to obtain the total equity!")
            return null
        }
    }
    return totalEquity
}

OtotalEquityEntão nós escrevemos uma função como a entrada de invocação, e chamamos a função correspondente de acordo com o nome da plataforma.

function getTotalEquity() {
    var exName = exchange.GetName()
    if (exName == "Futures_OKCoin") {
        return getTotalEquity_OKEX_V5()
    } else if (exName == "Futures_Binance") {
        return getTotalEquity_Binance()
    } else {
        throw "Do not support the platform"
    }
}

Projetar várias funções auxiliares

Antes de projetar a função principal e a lógica principal, também precisamos projetar algumas funções auxiliares para preparação.

  • Cancelar todas as ordens pendentes

    function cancelAll() {
        while (1) {
            var orders = _C(exchange.GetOrders)
            if (orders.length == 0) {
                break
            }
            for (var i = 0 ; i < orders.length ; i++) {
                exchange.CancelOrder(orders[i].Id, orders[i])
                Sleep(500)
            }
            Sleep(500)
        }
    }
    

    Acredita-se que esta função seja familiar para aqueles que frequentemente leem o código de exemplo de estratégia no quadrado de estratégia FMZ, e muitas estratégias usaram o design semelhante.

  • Operação de colocação de ordens de futuros

    function trade(distance, price, amount) {
        var tradeFunc = null 
        if (distance == "buy") {
            tradeFunc = exchange.Buy
        } else if (distance == "sell") {
            tradeFunc = exchange.Sell
        } else if (distance == "closebuy") {
            tradeFunc = exchange.Sell
        } else {
            tradeFunc = exchange.Buy
        }
        exchange.SetDirection(distance)
        return tradeFunc(price, amount)
    }
    
    function openLong(price, amount) {
        return trade("buy", price, amount)
    }
    
    function openShort(price, amount) {
        return trade("sell", price, amount)
    }
    
    function coverLong(price, amount) {
        return trade("closebuy", price, amount)
    }
    
    function coverShort(price, amount) {
        return trade("closesell", price, amount)
    }
    

    Existem quatro direções para a negociação de futuros: posição longa aberta (openLong), posição curta aberta (openShort), posição longa fechada (coverLong) e posição curta fechada (coverShort). Portanto, projetamos quatro funções de ordem para corresponder a essas operações.

    Também projetamos uma função chamada:tradepara lidar com a operação quandodirection (distance), order price (price)eorder amount (amount)são especificados.

    As chamadas de funções de posições longas abertas (openLong), de posições curtas abertas (openShort), de posições longas fechadas (coverLong) e de posições curtas fechadas (coverShort) são finalmente completadas pelotradefunção, ou seja, de acordo com a direção especificada, preço e montante, colocar ordens nas plataformas de futuros.

Função principal

A ideia da estratégia é muito simples; tomar o preço atual como a linha de base, e a partir de uma certa distância acima e abaixo da linha de base para colocar ordens de venda (short) e compras (long).

  • Trabalhos iniciais Para que possamos pendurar pedidos, precisamos de duas variáveis para registrar a ID do pedido.

    var buyOrderId = null
    var sellOrderId = null
    

    Em seguida, a opção de usar o bot simulado OKEX_V5 é projetada nos parâmetros da interface de estratégia, então algum processamento precisa ser feito no código:

    var exName = exchange.GetName()    
    // switch to OKEX V5 simulated bot 
    if (isSimulate && exName == "Futures_OKCoin") {
        exchange.IO("simulate", true)
    }
    

    A opção de redefinir todas as informações também é projetada nos parâmetros da estratégia, por isso, algum processamento precisa ser feito no código:

    if (isReset) {
        _G(null)
        LogReset(1)
        LogProfitReset()
        LogVacuum()
        Log("Reset all data", "#FF0000")
    }
    

    Nós só executamos contratos perpétuos, então aqui nós escrevemos em um loop infinito, e nós apenas definimos para contrato perpétuo.

    exchange.SetContractType("swap")
    

    Além disso, precisamos considerar os problemas de precisão do preço da ordem e do valor da ordem. Se a precisão não for definida corretamente, ela será perdida durante o processo de cálculo da estratégia.

    exchange.SetPrecision(pricePrecision, amountPrecision)
    Log("set percision", pricePrecision, amountPrecision)
    

    A função de recuperação de dados simples no projeto

    if (totalEq == -1 && !IsVirtual()) {
        var recoverTotalEq = _G("totalEq")
        if (!recoverTotalEq) {
            var currTotalEq = getTotalEquity()
            if (currTotalEq) {
                totalEq = currTotalEq
                _G("totalEq", currTotalEq)
            } else {
                throw "Fail to obtain the initial equity"
            }
        } else {
            totalEq = recoverTotalEq
        }
    }
    

    Se você quiser especificar o capital total inicial da conta ao executar a estratégia, você pode definir o parâmetrototalEqSe este parâmetro for definido em -1, a estratégia lerá os dados de patrimônio total armazenados. Se não houver dados de patrimônio total armazenados, o patrimônio total atualmente lido é usado como o patrimônio total inicial na estratégia em andamento. Mais tarde, se o patrimônio total aumentar, significa que ele ganhou lucro; se o patrimônio total diminuir, significa que há uma perda. Se os dados de patrimônio total forem lidos, use os dados para continuar a correr.

  • Lógica principal Após o trabalho inicial ser feito, chegamos finalmente à parte lógica principal da estratégia.

      while (1) {                                  // the main logic of the strategy is designed as an infinite loop
          var ticker = _C(exchange.GetTicker)      // read the current market information first, in which we mainly use the latest trading price
          var pos = _C(exchange.GetPosition)       // read the current position data 
          if (pos.length > 1) {                    // judge the position data; due to the strategy logic, it is unlikely to have long and short positions at the same time, so if there are long and short positions at the same time, an error will be thrown
              Log(pos)
              throw "concurrently with long and short positions"                  // raise an error, and stop the strategy 
          }
          // according to the status 
          if (pos.length == 0) {                    // according to the position status, make different operations; if pos.length == 0, it means currently no position
              // when there is no position yet, calculate the equity 
              if (!IsVirtual()) {
                  var currTotalEq = getTotalEquity()
                  if (currTotalEq) {
                      LogProfit(currTotalEq - totalEq, "Current total equity:", currTotalEq)
                  }
              }
    
              buyOrderId = openLong(ticker.Last - targetProfit, amount)       // pend buy order of open long position 
              sellOrderId = openShort(ticker.Last + targetProfit, amount)     // pend sell order of open short position
          } else if (pos[0].Type == PD_LONG) {   // there are long positions; pending position and amount are 
              var n = 1
              var price = ticker.Last
              buyOrderId = openLong(price - targetProfit * n, amount)
              sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
          } else if (pos[0].Type == PD_SHORT) {   // there are short positions; pending position and amount are different 
              var n = 1
              var price = ticker.Last
              buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
              sellOrderId = openShort(price + targetProfit * n, amount)
          }
    
          if (!sellOrderId || !buyOrderId) {   // if opending orders of one side fails, cancel all pending orders and try again 
              cancelAll()
              buyOrderId = null 
              sellOrderId = null
              continue
          } 
    
          while (1) {  // finish pending the order, and start to monitor the order
              var isFindBuyId = false 
              var isFindSellId = false
              var orders = _C(exchange.GetOrders)
              for (var i = 0 ; i < orders.length ; i++) {
                  if (buyOrderId == orders[i].Id) {
                      isFindBuyId = true 
                  }
                  if (sellOrderId == orders[i].Id) {
                      isFindSellId = true 
                  }               
              }
              if (!isFindSellId && !isFindBuyId) {    // both buy order and sell order are detected to be executed 
                  cancelAll()
                  break
              } else if (!isFindBuyId) {   // a buy order execution is detected 
                  Log("buy order executed")
                  cancelAll()
                  break
              } else if (!isFindSellId) {  // a sell order execution is detected 
                  Log("sell order executed")
                  cancelAll()
                  break
              }
              LogStatus(_D())
              Sleep(3000)
          }
          Sleep(500)
      }
    

A lógica e o desenho são completamente explicados.

Teste de retrocesso

Deixe a estratégia atravessar as cotações de mercado em 19 de maio de 2021.

img

img

Como podemos ver, a estratégia semelhante à estratégia Martingale ainda apresenta certos riscos.

Bot teste pode usar OKEX V5 simulado bot para executar

img

Endereço estratégico:https://www.fmz.com/strategy/294957

A estratégia é usada principalmente para estudo, por isso não operar a estratégia em um bot real!


Mais.