В процессе загрузки ресурсов... загрузка...

Дизайн стратегии Мартингейла для фьючерсов криптовалют

Автор:FMZ~Lydia, Создано: 2022-08-04 15:41:45, Обновлено: 2023-09-21 21:10:49

img

Дизайн стратегии Мартингейла для фьючерсов криптовалют

В последнее время в официальной группе FMZ обсуждается множество стратегий Мартингейла, и на платформе не так много стратегий Мартингейла контрактов криптовалют. Поэтому я воспользовался этой возможностью, чтобы разработать простую стратегию Мартингейла для фьючерсов криптовалют. Почему ее называют стратегией Мартингейл? Поскольку потенциальные риски стратегии Мартина действительно не малы, она не разработана точно в соответствии со стратегией Мартина. Однако этот тип стратегии все еще имеет много рисков, и параметры настройки стратегии типа Мартина тесно связаны с риском, и риск не должен игнорироваться.

Эта статья в основном объясняет и учится на разработке стратегий типа Мартина.

Получить совокупный капитал

Общий капитал часто используется при разработке криптовалютных фьючерсных стратегий. Это связано с тем, что прибыль должна быть рассчитана, особенно когда вам нужно рассчитать плавающие доходы. Поскольку позиция занята маржой, ожидаемый ордер также занят.exchange.GetAccount()Фактически, большинство криптовалютных фьючерсных бирж предоставляют данные об общем капитале, но этот атрибут не однородно упакован на FMZ.

Поэтому мы разрабатываем функции для получения этих данных в соответствии с различными обменами:

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

ВtotalEquityЗатем мы запишем функцию как запись вызова, и вызовем соответствующую функцию согласно названию биржи.

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

Проектировать некоторые вспомогательные функции

Перед тем, как разработать основную функцию и основную логику, нам нужно сделать некоторые приготовления и разработать некоторые вспомогательные функции.

  • Отменить все текущие заказы

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

    Эта функция знакома тем, кто часто читает примерный код стратегии на квадратной стратегии FMZ, и многие стратегии использовали аналогичные конструкции.

  • Операции по размещению фьючерсов

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

    Для торговли фьючерсами существует четыре направления: openLong, openShort, coverLong и coverShort. Поэтому мы разработали четыре функции ордера, соответствующие этим операциям. Если вы рассматриваете только ордер, то есть несколько необходимых факторов: направление, цена ордера и объем ордера. Также мы разработали функцию под названием:tradeдля обработки операции, когдаdistance, price, amountУказываются. Призывы к функции openLong, openShort, coverLong и coverShort в конечном итоге завершаютсяtradeфункция, то есть размещение ордера на бирже фьючерсов на основе установленного расстояния, цены и количества.

Основная функция

Идея стратегии очень проста, возьмите текущую цену в качестве базовой линии и разместите ордера на продажу (короткий) и покупку (длинный) на определенном расстоянии вверх или вниз. После завершения сделки все оставшиеся ордера будут отменены, а затем новый ордер на закрытие будет размещен на определенном расстоянии в соответствии с ценой позиции, и ордер на увеличение будет размещен по обновленной текущей цене, но объем ордера не будет удвоен для дополнительных позиций.

  • Первоначальные работы Из-за ожидания заказа, нам нужны две глобальные переменные для записи идентификатора заказа.

    var buyOrderId = null
    var sellOrderId = null
    

    Затем параметры интерфейса стратегии предназначены для использования опции OKEX_V5 simulated bot, поэтому в коде необходимо провести некоторую обработку:

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

    Существует также возможность сброса всей информации в параметрах интерфейса, поэтому в коде должна быть соответствующая обработка:

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

    У нас только постоянные контракты, так что запись фиксирована здесь и установлена только на постоянные.

    exchange.SetContractType("swap")
    

    В этом случае мы должны также учитывать точность цены заказа и суммы заказа. Если точность не установлена должным образом, то точность будет потеряна во время процесса расчета стратегии. Если данные имеют большое количество десятичных знаков, легко вызвать отказ заказа обменным интерфейсом.

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

    Простое восстановление данных по конструкции

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

    Если вы хотите указать начальный общий капитал счета, когда стратегия работает, вы можете установить параметрtotalEq. Если этот параметр установлен на -1, стратегия будет читать сохраненные данные об общем капитале. Если нет сохраненных данных об общем капитале, текущий прочитанный общий капитал используется в качестве начального общего капитала стратегии. После этого увеличение общего капитала указывает на прибыль, а снижение общего капитала указывает на убыток. Если читаются данные об общем капитале, стратегия будет продолжать работать с этими данными.

  • Основная логика После того, как начальная работа будет сделана, наконец, мы пришли к основной логической части стратегии. Для удобства объяснения, я написал инструкции непосредственно на комментариях кода.

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

Вся логика и дизайн объяснены.

Обратное тестирование

Пусть стратегия пройдет через рынок 19 мая.

img

img

Видно, что стратегия Мартингейла по-прежнему несет определенные риски.

Настоящий бот можно запустить с OKEX V5 симулятор бота

Адрес стратегии:https://www.fmz.com/strategy/294957

Стратегии используются в основном для обучения, и реальные деньги должны использоваться с осторожностью~!


Связанные

Больше