Количественная торговля криптовалютами для новичков - приближение к количественной криптовалюте (6)

Автор:Лидия., Создано: 2022-08-05 17:13:26, Обновлено: 2023-09-21 21:02:17

img

В предыдущей статье мы вместе разработали простую стратегию сетки. В этой статье мы обновили и расширили эту стратегию в стратегию сетки с множественными видами мест, и позволили этой стратегии быть протестирована на практике. Цель не в том, чтобы найти "святой Грааль", а для обсуждения различных проблем и решений при разработке стратегий. Эта статья объяснит некоторые из моих опытов в разработке этой стратегии. Содержание этой статьи немного сложное и требует определенной основы в программировании.

Мышление дизайна на основе стратегических потребностей

Эта статья, как и предыдущая, по-прежнему обсуждает дизайн на основе FMZ Quant (FMZ.COM).

  • Многовиды Если говорить прямо, я думаю, что эта стратегия сети может не толькоBTC_USDT, но такжеLTC_USDT/EOS_USDT/DOGE_USDT/ETC_USDT/ETH_USDTВ любом случае, спотовые торговые пары и сорта, которые хотят работать, все торгуются в сети одновременно.

    Хмм, хорошо захватывать нестабильный рынок нескольких видов. Требование звучит очень просто, а проблема возникает при проектировании.

      1. Сначала получаются рыночные котировки нескольких сортов. Это первая проблема, которую нужно решить. После ознакомления с документацией API биржи, я обнаружил, что большинство бирж предоставляют агрегированные рыночные интерфейсы. Хорошо, используйте агрегированный рыночный интерфейс для получения данных.
      1. Вторая проблема, с которой мы сталкиваемся, это активы счета. Поскольку это многовидовая стратегия, необходимо рассматривать управление каждым активом торговой пары отдельно. И мы должны получить данные для всех активов сразу и записать их. Почему нам нужно получить данные активов счета? Почему нам нужно отделять записи каждой пары? Потому что вам нужно оценить доступные активы, когда вы делаете заказ. И вы должны рассчитать прибыль, это также необходимо, чтобы записать первоначальные данные актива счета сначала, затем получить данные активов текущего счета и сравнить его с первоначальным для расчета прибыли и убытка? К счастью, интерфейс счета активов биржи обычно возвращает все данные валютных активов, нам нужно получить их только один раз, а затем обработать данные.
      1. Дизайн параметров стратегии. Дизайн параметров мульти-вида довольно отличается от параметров дизайна одиночного сорта, хотя логика торговли каждого сорта мульти-сорта одинакова, возможно, что параметры во время торговли различаются. Например, в сетке стратегии вы можете захотеть торговать 0,01 BTC каждый раз, когда делаете торговую пару BTC_USDT, но, очевидно, неуместно использовать этот параметр (торговля 0,01 монетами), когда делаете DOGE_USDT. Конечно, вы также можете иметь дело с суммой USDT. Но все равно будут проблемы. Что делать, если вы хотите торговать 1000U за BTC_USDT и 10U за DOGE_USDT? Спрос никогда не может быть удовлетворен. Возможно, кто-то подумает об этой проблеме и спросит: Я могу установить несколько наборов параметров для управления параметрами различных торговых пар, которые должны быть выполнены отдельно. Это все еще недостаточно гибко, чтобы удовлетворить потребности, сколько наборов параметров хорошо установить? Три набора параметров установлены, что, если я хочу сделать 4 разновидности? Таким образом, при разработке параметров стратегии многовидового использования необходимо в полной мере учитывать потребности таких дифференцированных параметров. Например:
      ETHUSDT:100:0.002|LTCUSDT:20:0.1
      

      Среди них gaman разделяет данные каждого вида, что означает, чтоETHUSDT:100:0.002контролирует торговую пару ETH_USDT, иLTCUSDT:20:0.1контролирует торговую пару LTC_USDT. Средний используется для деления.ETHUSDT:100:0.002, где ETHUSDT указывает, какую торговую пару вы хотите использовать, 100 - это расстояние между сетками, 0,002 - это количество монет ETH, торгуемых в каждой сетке, и : - это разделить эти данные (конечно, эти правила параметров создаются разработчиком стратегии, вы можете разработать что угодно в соответствии с вашими потребностями). Эти строки содержат информацию о параметрах каждого вида, который вы хотите сделать. Проанализируйте эти строки в стратегии и присвоите значения переменным стратегии для управления логикой торговли каждого вида. Как это сделать? Все равно используйте приведенный выше пример.

      function main() {
          var net = []  // The recorded grid parameters, use the data when running to the grid trading logic
          var params = "ETHUSDT:100:0.002|LTCUSDT:20:0.1"
          var arrPair = params.split("|")
          _.each(arrPair, function(pair) {
              var arr = pair.split(":")
              var symbol = arr[0]              // Trading pair name
              var diff = parseFloat(arr[1])    // Grid spacing
              var amount = parseFloat(arr[2])  // Grid order volume
              net.push({symbol : symbol, diff : diff, amount : amount})
          })
          Log("Grid parameter data:", net)
      }
      

      img

      Конечно, вы также можете использовать строки JSON напрямую, что проще.

      function main() {        
          var params = '[{"symbol":"ETHUSDT","diff":100,"amount":0.002},{"symbol":"LTCUSDT","diff":20,"amount":0.1}]'
          var net = JSON.parse(params)  // The recorded grid parameters, use the data when running to the grid trading logic        
          _.each(net, function(pair) {
              Log("Trading pairs:", pair.symbol, pair)
          })
      }
      

      img

      1. Прочность данных Существует также большая разница между стратегиями, которые могут быть применены на практике и учебными стратегиями. Учебные стратегии в предыдущей статье являются только предварительным испытанием логики и дизайна стратегии, и есть больше вопросов, которые следует учитывать, когда дело доходит до реального мира. В реальном боте возможно начать и остановить реальную торговлю. В это время все данные во время реальной операции бота будут потеряны. Итак, как заставить реального бота перезагрузиться, чтобы продолжать работать в предыдущем состоянии после того, как он остановился? Здесь необходимо сохранять ключевые данные постоянно, когда работает настоящий бот, чтобы данные могли быть прочитаны и продолжены при перезагрузке. Вы можете использовать_G()функция на Платформе количественной торговли FMZ или использовать функцию работы базы данныхDBExec(), и вы можете проверить документацию FMZ API для деталей.

      Например, мы разрабатываем функцию "защита хвоста" и используем_G()Функция сохранения сетевых данных.

      var net = null 
      function main() {  // Strategy main functions
          // Read the stored net first
          net = _G("net")
          
          // ...
      }
      
      function onExit() {
          _G("net", net)
          Log("Perform tail-sweeping processing and save data", "#FF0000")
      }
      
      function onexit() {    // The exit sweep function defined by the platform system, triggered the execution when the real bot is clicked to stop
          onExit()
      }
      
      function onerror() {   // The abnormal exit function defined by the platform system, triggered the execution when the program is abnormal
          onExit()
      }
      
      1. Ограничения, такие как точность количества заказа, точность цены заказа, минимальное количество заказа и минимальная сумма заказа и т.д.

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

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

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

      1. Приспособление к различным биржам Зачем ставить этот вопрос в конце? Поскольку решения этих проблем, о которых мы говорили выше, приведут к последней проблеме, поскольку наша стратегия планирует использовать агрегированный рыночный интерфейс, доступ к точности биржевой торговой пары и другим адаптивным данным, доступ к информации о счете для обработки каждой торговой пары отдельно, эти решения могут сильно варьироваться от биржи к бирже. Существуют различия в вызовах интерфейса и механизмах. Для спотовых бирж разница меньше, если стратегия сетки распространяется на фьючерсную версию. Различия в механизме различных бирж еще больше. Одним из решений является проектирование библиотеки классов шаблонов FMZ. Напишите дизайн в библиотеке классов для реализации этих различий. Уменьшите связь между самой стратегией и биржей. Недостатком этого является то, что вам нужно написать библиотеку классов шаблонов и реализовать ее специально для каждой разницы обмена в этом шаблоне.

Проектировать библиотеку шаблонов классов

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

Мы можем спроектировать библиотеку классов шаблонов вот так (часть кода пропущена):

function createBaseEx(e, funcConfigure) {
    var self = {}
    self.e = e 
    
    self.funcConfigure = funcConfigure
    self.name = e.GetName()
    self.type = self.name.includes("Futures_") ? "Futures" : "Spot"
    self.label = e.GetLabel()
    
    // Interfaces to be implemented
    self.interfaceGetTickers = null   // Create a function to asynchronously obtain a thread of aggregated market data
    self.interfaceGetAcc = null       // Create a function that asynchronously obtains account data thread
    self.interfaceGetPos = null       // Get a position
    self.interfaceTrade = null        // Create concurrent orders
    self.waitTickers = null           // Waiting for concurrent market data 
    self.waitAcc = null               // Waiting for account concurrent data
    self.waitTrade = null             // Waiting for order concurrent data
    self.calcAmount = null            // Calculate the order volume based on data such as trading pair accuracy
    self.init = null                  // Initialization work, obtaining data such as accuracy
    
    // Execute the configuration function to configure the object
    funcConfigure(self)

    // Check whether the interfaces agreed by configList are implemented
    _.each(configList, function(funcName) {
        if (!self[funcName]) {
            throw "interface" + funcName + "unimplemented"
        }
    })
    
    return self
}

$.createBaseEx = createBaseEx
$.getConfigureFunc = function(exName) {
    dicRegister = {
        "Futures_OKCoin" : funcConfigure_Futures_OKCoin,    // Implementation of OK futures
        "Huobi" : funcConfigure_Huobi,
        "Futures_Binance" : funcConfigure_Futures_Binance,
        "Binance" : funcConfigure_Binance,
        "WexApp" : funcConfigure_WexApp,                    // Implementation of wexApp
    }
    return dicRegister
}

В шаблоне, он написан для конкретных бирж, возьмите FMZs симулированный бот WexApp в качестве примера:

function funcConfigure_WexApp(self) {
    var formatSymbol = function(originalSymbol) {
        // BTC_USDT
        var arr = originalSymbol.split("_")
        var baseCurrency = arr[0]
        var quoteCurrency = arr[1]
        return [originalSymbol, baseCurrency, quoteCurrency]
    }

    self.interfaceGetTickers = function interfaceGetTickers() {
        self.routineGetTicker = HttpQuery_Go("https://api.wex.app/api/v1/public/tickers")
    }

    self.waitTickers = function waitTickers() {
        var ret = []
        var arr = JSON.parse(self.routineGetTicker.wait()).data
        _.each(arr, function(ele) {
            ret.push({
                bid1: parseFloat(ele.buy), 
                bid1Vol: parseFloat(-1),
                ask1: parseFloat(ele.sell), 
                ask1Vol: parseFloat(-1),
                symbol: formatSymbol(ele.market)[0],
                type: "Spot", 
                originalSymbol: ele.market
            })
        })
        return ret 
    }

    self.interfaceGetAcc = function interfaceGetAcc(symbol, updateTS) {
        if (self.updateAccsTS != updateTS) {
            self.routineGetAcc = self.e.Go("GetAccount")
        }
    }

    self.waitAcc = function waitAcc(symbol, updateTS) {
        var arr = formatSymbol(symbol)
        var ret = null 
        if (self.updateAccsTS != updateTS) {
            ret = self.routineGetAcc.wait().Info
            self.bufferGetAccRet = ret 
        } else {
            ret = self.bufferGetAccRet
        }
        if (!ret) {
            return null 
        }        
        var acc = {symbol: symbol, Stocks: 0, FrozenStocks: 0, Balance: 0, FrozenBalance: 0, originalInfo: ret}
        _.each(ret.exchange, function(ele) {
            if (ele.currency == arr[1]) {
                // baseCurrency
                acc.Stocks = parseFloat(ele.free)
                acc.FrozenStocks = parseFloat(ele.frozen)
            } else if (ele.currency == arr[2]) {
                // quoteCurrency
                acc.Balance = parseFloat(ele.free)
                acc.FrozenBalance = parseFloat(ele.frozen)
            }
        })
        return acc
    }

    self.interfaceGetPos = function interfaceGetPos(symbol, price, initSpAcc, nowSpAcc) {
        var symbolInfo = self.getSymbolInfo(symbol)
        var sumInitStocks = initSpAcc.Stocks + initSpAcc.FrozenStocks
        var sumNowStocks = nowSpAcc.Stocks + nowSpAcc.FrozenStocks
        var diffStocks = _N(sumNowStocks - sumInitStocks, symbolInfo.amountPrecision)
        if (Math.abs(diffStocks) < symbolInfo.min / price) {
            return []
        }
        return [{symbol: symbol, amount: diffStocks, price: null, originalInfo: {}}]
    }

    self.interfaceTrade = function interfaceTrade(symbol, type, price, amount) {
        var tradeType = ""
        if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
            tradeType = "bid"
        } else {
            tradeType = "ask"
        }
        var params = {
            "market": symbol,
            "side": tradeType,
            "amount": String(amount),
            "price" : String(-1),
            "type" : "market"
        }
        self.routineTrade = self.e.Go("IO", "api", "POST", "/api/v1/private/order", self.encodeParams(params))
    }

    self.waitTrade = function waitTrade() {
        return self.routineTrade.wait()
    }

    self.calcAmount = function calcAmount(symbol, type, price, amount) {
        // Obtain trading pair information
        var symbolInfo = self.getSymbolInfo(symbol)
        if (!symbol) {
            throw symbol + ", the trading pair information cannot be checked"
        }
        var tradeAmount = null 
        var equalAmount = null  // Number of coins recorded
        if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
            tradeAmount = _N(amount * price, parseFloat(symbolInfo.pricePrecision))
            // Check the minimum trading volume
            if (tradeAmount < symbolInfo.min) {
                Log(self.name, " tradeAmount:", tradeAmount, "less than", symbolInfo.min)
                return false 
            }
            equalAmount = tradeAmount / price
        } else {
            tradeAmount = _N(amount, parseFloat(symbolInfo.amountPrecision))
            // Check the minimum trading volume
            if (tradeAmount < symbolInfo.min / price) {
                Log(self.name, " tradeAmount:", tradeAmount, "less than", symbolInfo.min / price)
                return false 
            }
            equalAmount = tradeAmount
        }
        return [tradeAmount, equalAmount]
    }

    self.init = function init() {   // Functions that deal with conditions such as accuracy automatically
        var ret = JSON.parse(HttpQuery("https://api.wex.app/api/v1/public/markets"))
        _.each(ret.data, function(symbolInfo) {
            self.symbolsInfo.push({
                symbol: symbolInfo.pair,
                amountPrecision: parseFloat(symbolInfo.basePrecision),
                pricePrecision: parseFloat(symbolInfo.quotePrecision),
                multiplier: 1,
                min: parseFloat(symbolInfo.minQty),
                originalInfo: symbolInfo
            })
        })        
    }
}

Тогда использование этого шаблона в стратегии просто:

function main() {
    var fuExName = exchange.GetName()
    var fuConfigureFunc = $.getConfigureFunc()[fuExName]
    var ex = $.createBaseEx(exchange, fuConfigureFunc)

    var arrTestSymbol = ["LTC_USDT", "ETH_USDT", "EOS_USDT"]
    var ts = new Date().getTime()
    
    // Test to get tickers
    ex.goGetTickers()
    var tickers = ex.getTickers()
    Log("tickers:", tickers)
    
    // Test to obtain account information
    ex.goGetAcc(symbol, ts)
    
    _.each(arrTestSymbol, function(symbol) {        
        _.each(tickers, function(ticker) {
            if (symbol == ticker.originalSymbol) {
                // print ticker data
                Log(symbol, ticker)
            }
        })

        // print asset data
        var acc = ex.getAcc(symbol, ts)
        Log("acc:", acc.symbol, acc)
    })
}

Стратегия реальный бот

Это очень просто, чтобы разработать и написать стратегию на основе вышеприведенного шаблона.

img

img

В настоящее время он теряет деньги.T_T, исходный код пока не будет опубликован.

Вот несколько регистрационных кодов, если вы заинтересованы, вы можете попробовать с помощью wexApp:

Buy address: https://www.fmz.com/m/s/284507
Registration code: 
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc

Чуть более 200 U, когда я только начал бегать, я столкнулся с большим односторонним рынком, но я восстановился медленно. Стабильность неплохая, она не изменялась с 27 мая, и фьючерсная сеть временно не решилась попробовать.


Связанные

Больше