4
Подписаться
1271
Подписчики

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

Создано: 2021-07-02 14:35:34, Обновлено: 2023-09-21 21:09:56
comments   22
hits   6170

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

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

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

Эта статья в основном объясняет и учит дизайну стратегий типа Мартина. Сама идея стратегии очень ясна. Как пользователи FMZ, мы больше рассматриваем дизайн стратегии.

Получить общий капитал

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

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

// OKEX V5 获取总权益
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("获取账户总权益失败!")
            return null
        }
    }
    return totalEquity
}

// 币安期货
function getTotalEquity_Binance() {
    var totalEquity = null 
    var ret = exchange.GetAccount()
    if (ret) {
        try {
            totalEquity = parseFloat(ret.Info.totalWalletBalance)
        } catch(e) {
            Log("获取账户总权益失败!")
            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 "不支持该交易所"
    }
}

Разработать несколько вспомогательных функций

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

  • Отменить все текущие отложенные ордера
  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 Strategy Square, очень хорошо знакомы с этой функцией. Многие стратегии использовали похожие конструкции. Его функция — получить текущий список отложенных ордеров, а затем отменить их один за другим.

  • Фьючерсная операция по заказу
  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, поэтому необходимо выполнить некоторую обработку в коде:

  var exName = exchange.GetName()    
  // 切换OKEX V5模拟盘
  if (isSimulate && exName == "Futures_OKCoin") {
      exchange.IO("simulate", true)
  }

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

  if (isReset) {
      _G(null)
      LogReset(1)
      LogProfitReset()
      LogVacuum()
      Log("重置所有数据", "#FF0000")
  }

Мы работаем только с бессрочными контрактами, поэтому здесь все жестко запрограммировано и настроено только на бессрочные контракты.

  exchange.SetContractType("swap")

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

  exchange.SetPrecision(pricePrecision, amountPrecision)
  Log("设置精度", pricePrecision, amountPrecision)

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

  if (totalEq == -1 && !IsVirtual()) {
      var recoverTotalEq = _G("totalEq")
      if (!recoverTotalEq) {
          var currTotalEq = getTotalEquity()
          if (currTotalEq) {
              totalEq = currTotalEq
              _G("totalEq", currTotalEq)
          } else {
              throw "获取初始权益失败"
          }
      } else {
          totalEq = recoverTotalEq
      }
  }

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

  • Основная логика После того, как начальная работа была сделана, мы наконец-то пришли к основной логике стратегии. Для удобства объяснения я написал объяснение прямо в комментариях к коду.
    while (1) {                                  // 策略主要逻辑设计为一个死循环
        var ticker = _C(exchange.GetTicker)      // 首先读取当前行情信息,主要用到最新成交价
        var pos = _C(exchange.GetPosition)       // 读取当前持仓数据
        if (pos.length > 1) {                    // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
            Log(pos)
            throw "同时有多空持仓"                  // 抛出错误,让策略停止
        }
        // 根据状态而定
        if (pos.length == 0) {                    // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
            // 未持仓了,统计一次收益
            if (!IsVirtual()) {
                var currTotalEq = getTotalEquity()
                if (currTotalEq) {
                    LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
                }
            }

            buyOrderId = openLong(ticker.Last - targetProfit, amount)       // 挂开多仓的买单
            sellOrderId = openShort(ticker.Last + targetProfit, amount)     // 挂开空仓的卖单
        } else if (pos[0].Type == PD_LONG) {   // 有多头持仓,挂单位置、数量有所不同
            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) {   // 有空头持仓,挂单位置、数量有所不同
            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) {   // 如果有一边挂单失败就取消所有挂单,重来
            cancelAll()
            buyOrderId = null 
            sellOrderId = null
            continue
        } 

        while (1) {  // 挂单完成,开始监控订单
            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) {    // 检测到买卖单都成交了
                cancelAll()
                break
            } else if (!isFindBuyId) {   // 检测到买单成交
                Log("买单成交")
                cancelAll()
                break
            } else if (!isFindSellId) {  // 检测到卖单成交
                Log("卖单成交")
                cancelAll()
                break
            }
            LogStatus(_D())
            Sleep(3000)
        }
        Sleep(500)
    }

Вся логика и конструкция объяснены.

Бэктестинг

Позвольте стратегии испытать рыночную ситуацию 19 мая.

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

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

Видно, что стратегия Мартингейла все еще несет определенные риски.

Вы можете попробовать демо-версию OKEX V5 для реальной торговли.

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

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

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