Diseño de estrategias de futuros de criptomonedas de tipo Martingale

El autor:No lo sé., Creado: 2022-04-12 17:50:07, Actualizado: 2022-04-12 18:06:07

Diseño de estrategias de futuros de criptomonedas de tipo Martingale

Recientemente, hay muchas estrategias de tipo Martingale discutidas en el grupo oficial de FMZ, y no hay muchas estrategias de tipo Martingale de contratos de criptomonedas en nuestra plataforma. Por lo tanto, aproveché esta oportunidad para diseñar una estrategia simple de tipo Martingale de futuros de criptomonedas. ¿Por qué se llama estrategia de tipo Martingale? Debido a que el riesgo potencial de la estrategia de Martingale no es pequeño, no es necesario diseñar de acuerdo con la estrategia de Martingale. Sin embargo, este tipo de estrategias todavía tienen muchos riesgos, y los parámetros de configuración de la estrategia de tipo Martingale están estrechamente relacionados con los riesgos, y los riesgos no deben ignorarse.

En este artículo, principalmente explicamos y aprendemos del diseño de estrategias de tipo Martingale.

Obtener el capital total

El capital total se utiliza a menudo al diseñar una estrategia de futuros de criptomonedas, ya que queremos calcular las ganancias, especialmente cuando necesitamos calcular las ganancias flotantes.exchange.GetAccount()De hecho, la mayoría de las plataformas de futuros de criptomonedas proporcionan los datos del capital total, pero esta propiedad no está uniformemente empaquetada en FMZ.

Por lo tanto, diseñamos por separado las funciones para obtener los datos de acuerdo con 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
}

EltotalEquityEntonces escribimos una función como la entrada de invocación, y llamamos a la función correspondiente según el nombre de la 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"
    }
}

Diseño de varias funciones auxiliares

Antes de diseñar la función principal y la lógica principal, también necesitamos diseñar algunas funciones auxiliares para la preparación.

  • Cancelar todas las órdenes pendientes

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

    Se cree que esta función es familiar para aquellos que a menudo leen el código de ejemplo de estrategia en el cuadrado de estrategia FMZ, y muchas estrategias han utilizado el diseño similar.

  • La operación de colocación de órdenes 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)
    }
    

    Hay cuatro direcciones para el comercio de futuros: posición larga abierta (openLong), posición corta abierta (openShort), posición larga cerrada (coverLong) y posición corta cerrada (coverShort). Por lo tanto, diseñamos cuatro funciones de orden para corresponder a estas operaciones. Si solo considera la colocación de órdenes, entonces hay varios factores necesarios: dirección, precio de la orden y monto de la orden.

    También diseñamos una función llamada:tradepara manejar la operación cuandodirection (distance), order price (price)yorder amount (amount)se especifican.

    Las llamadas de las funciones de posiciones largas abiertas (openLong), posiciones cortas abiertas (openShort), posiciones largas cerradas (coverLong) y posiciones cortas cerradas (coverShort) se completan en última instancia por eltradefunción, es decir, de acuerdo con la dirección especificada, precio y importe, colocar órdenes en las plataformas de futuros.

Función principal

La idea de la estrategia es muy simple; tomar el precio actual como la línea de base, y desde una cierta distancia por encima y por debajo de la línea de base para colocar órdenes de venta (corto) y órdenes de compra (largo). Si las órdenes de un lado se ejecutan, cancelar todas las órdenes restantes, y luego se colocarán nuevas órdenes de cierre a una cierta distancia de acuerdo con el precio de la posición, y las órdenes de compra se colocarán al precio actual actualizado, pero las órdenes de compra no duplicarán el monto del pedido.

  • Trabajos iniciales Para que queramos pedidos pendientes, necesitamos dos variables para registrar la ID del pedido.

    var buyOrderId = null
    var sellOrderId = null
    

    Luego, la opción de usar el bot simulado OKEX_V5 está diseñada en los parámetros de la interfaz de estrategia, por lo que se necesita realizar algún procesamiento en el código:

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

    La opción de restablecer toda la información también está diseñada en los parámetros de la estrategia, por lo que se necesita realizar algún procesamiento en el código:

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

    Solo ejecutamos contratos perpetuos, así que aquí lo escribimos en un bucle infinito, y solo lo establecemos en contrato perpetuo.

    exchange.SetContractType("swap")
    

    Además, necesitamos considerar los problemas de precisión del precio del pedido y el monto del pedido. Si la precisión no se establece correctamente, se perderá durante el proceso de cálculo de la estrategia. Si los datos tienen un gran número de decimales, es fácil hacer que el pedido sea rechazado por la interfaz de la plataforma.

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

    La función de recuperación de datos simple en el diseño

    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
        }
    }
    

    Si desea especificar el capital total inicial de la cuenta al ejecutar la estrategia, puede establecer el parámetrototalEqSi este parámetro está establecido en -1, la estrategia leerá los datos de capital total almacenados. Si no hay datos de capital total almacenados, el capital total actualmente leído se usa como el capital total inicial en la estrategia en curso. Más tarde, si el capital total aumenta, significa que ha ganado un beneficio; si el capital total disminuye, significa que hay una pérdida. Si se leen los datos de capital total, use los datos para continuar funcionando.

  • La lógica principal Después de que el trabajo inicial está hecho, finalmente llegamos a la parte lógica principal de la estrategia.

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

Toda la lógica y el diseño están completamente explicados entonces.

Prueba de retroceso

Que la estrategia cruce las cotizaciones del mercado el 19 de mayo de 2021.

img

img

Como podemos ver, la estrategia similar a la estrategia Martingale todavía tiene ciertos riesgos.

La prueba de bot puede usar el bot simulado de OKEX V5 para ejecutar

img

Dirección estratégica:https://www.fmz.com/strategy/294957

La estrategia se utiliza principalmente para el estudio, así que no operar la estrategia en un bot real!


Más.