Diseño de estrategia de Martingale para futuros de criptomonedas

El autor:- ¿ Por qué?, Creado: 2022-08-04 15:41:45, Actualizado: 2023-09-21 21:10:49

img

Diseño de estrategia de Martingale para futuros de criptomonedas

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

Este artículo explica y aprende principalmente del diseño de estrategias de tipo Martin.

Obtener el capital total

El capital total se utiliza a menudo al diseñar estrategias de futuros de criptomonedas. Esto se debe a que se deben calcular los rendimientos, especialmente cuando se necesitan calcular los rendimientos flotantes.exchange.GetAccount()De hecho, la mayoría de los intercambios de futuros de criptomonedas proporcionan los datos del capital total, pero este atributo no está uniformemente empaquetado en FMZ.

Así que diseñamos funciones para obtener estos datos de acuerdo con diferentes intercambios:

// OKEX V5 obtain 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("failed to obtain the total equity of the account!")
            return null
        }
    }
    return totalEquity
}

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

EltotalEquityEntonces escribimos una función como la entrada de llamada, y llamamos a la función correspondiente de acuerdo con el nombre del intercambio.

function getTotalEquity() {
    var exName = exchange.GetName()
    if (exName == "Futures_OKCoin") {
        return getTotalEquity_OKEX_V5()
    } else if (exName == "Futures_Binance") {
        return getTotalEquity_Binance()
    } else {
        throw "This exchange is not supported"
    }
}

Diseñar algunas funciones auxiliares

Antes de diseñar la función principal y la lógica principal, necesitamos hacer algunos preparativos y diseñar algunas funciones auxiliares.

  • Cancelar todas las órdenes pendientes actuales

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

    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 diseños similares.

  • Operaciones de colocación 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: openLong, openShort, coverLong y coverShort. Así que diseñamos cuatro funciones de orden correspondientes a estas operaciones. Si usted considera sólo el pedido, entonces hay varios factores necesarios: dirección, precio del pedido y volumen del pedido. Así que también diseñamos una función llamada:tradepara manejar la operación cuandodistance, price, amountse especifican. Las llamadas de la función a openLong, openShort, coverLong y coverShort se completan en última instancia por eltradefunción, es decir, colocar una orden en un intercambio de futuros basado en la distancia, el precio y la cantidad establecidos.

Función principal

La idea de la estrategia es muy simple, tomar el precio actual como la línea de base, y colocar órdenes de venta (corto) y compra (largo) a una cierta distancia hacia arriba o hacia abajo. Una vez que se completa la transacción, todas las órdenes restantes serán canceladas, y luego se colocará una nueva orden de cierre a una cierta distancia de acuerdo con el precio de la posición, y se colocará una orden de aumento al precio actual actualizado, pero el volumen de la orden no se duplicará para posiciones adicionales.

  • Trabajos iniciales Debido a la orden pendiente, necesitamos dos variables globales para registrar la ID de la orden.

    var buyOrderId = null
    var sellOrderId = null
    

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

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

    También hay una opción para restablecer toda la información en los parámetros de la interfaz, por lo que debe haber un procesamiento correspondiente en el código:

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

    Solo tenemos contratos perpetuos, así que la escritura está fija aquí y sólo está fijada en perpetuo.

    exchange.SetContractType("swap")
    

    Entonces también necesitamos considerar la precisión del precio del pedido y el monto del pedido. Si la precisión no se establece correctamente, la precisión 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 intercambio.

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

    Recuperación de datos sencilla por diseño

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

    Si desea especificar el capital total inicial de la cuenta cuando la estrategia se está ejecutando, se 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 leído actual se utiliza como el capital total inicial de la estrategia en curso. Después de eso, un aumento en el capital total indica una ganancia, y una disminución en el capital total indica una pérdida. Si se leen los datos de capital total, la estrategia continuará ejecutándose con estos datos.

  • La lógica principal Después de que el trabajo inicial está hecho, finalmente llegamos a la parte lógica principal de la estrategia. Para mayor comodidad de explicación, escribí las instrucciones directamente en los comentarios del código.

      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, mainly using the latest transaction price
          var pos = _C(exchange.GetPosition)       // Read current position data
          if (pos.length > 1) {                    // Judging the position data, because of the logic of this strategy, it is unlikely that long and short positions will appear at the same time, so if there are long and short positions at the same time, an error will be thrown
              Log(pos)
              throw "Simultaneous long and short positions"                  // Throw an error to stop the strategy
          }
          //Depends on status
          if (pos.length == 0) {                    // Make different operations according to the position status, when there is no position, pos.length == 0 
              // If you have not held a position, count the profit once
              if (!IsVirtual()) {
                  var currTotalEq = getTotalEquity()
                  if (currTotalEq) {
                      LogProfit(currTotalEq - totalEq, "current total equity:", currTotalEq)
                  }
              }
    
              buyOrderId = openLong(ticker.Last - targetProfit, amount)       // Open a buy order for a long position
              sellOrderId = openShort(ticker.Last + targetProfit, amount)     // Open a short sell order
          } else if (pos[0].Type == PD_LONG) {   // For long positions, the position and quantity of pending orders are different
              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) {   // For short positions, the position and quantity of pending orders 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 one side of the pending order fails, cancel all pending orders and start over
              cancelAll()
              buyOrderId = null 
              sellOrderId = null
              continue
          } 
    
          while (1) {  // The pending order is completed, start monitoring 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) {    // Detected that both buy and sell orders have been filled
                  cancelAll()
                  break
              } else if (!isFindBuyId) {   // Detected buy order closing
                  Log("buy order closing")
                  cancelAll()
                  break
              } else if (!isFindSellId) {  // Detected sell order closing
                  Log("sell order closing")
                  cancelAll()
                  break
              }
              LogStatus(_D())
              Sleep(3000)
          }
          Sleep(500)
      }
    

Toda la lógica y el diseño se explican.

Pruebas de retroceso

Dejemos que la estrategia pase por un mercado del 19 de mayo.

img

img

Se puede ver que la estrategia Martingale todavía tiene ciertos riesgos.

El bot real se puede ejecutar con el bot de simulación OKEX V5

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

Las estrategias se usan principalmente para aprender, y el dinero real debe usarse con precaución~!


Relacionados

Más.