В предыдущей статье мы вместе разработали простую стратегию сетки. В этой статье мы обновили и расширили эту стратегию в стратегию сетки с множеством символов, и позволили этой стратегии быть протестирована на практике. Цель не в том, чтобы найти "святой Грааль", а в том, чтобы обсудить различные проблемы и решения в процессе разработки стратегий. Эта статья объяснит некоторые из моих опытов в разработке стратегии. Содержание этой статьи немного сложно и требует определенной основы в программировании.
В этой статье, как и в предыдущей, мы обсуждаем дизайн на базе FMZ Quant Trading Platform (FMZ.COM).
Многочисленный символ
Честно говоря, я хочу, чтобы стратегия сети не толькоBTC_USDT
, но такжеLTC_USDT
/EOS_USDT
/DOGE_USDT
/ETC_USDT
/ETH_USDT
В любом случае, для спотовых торговых пар, выполните сетевую торговлю всеми символами, которые вы хотите торговать одновременно.
Да, приятно запечатлеть вибрирующие котировки рынка с несколькими символами.
Хотя требование звучит просто, оно становится сложным, когда вы начинаете проектировать.
Поскольку вам необходимо оценить доступные активы при размещении заказов, разве не необходимо получить данные до вынесения решения? Кроме того, прибыль должна быть рассчитана.Прежде всего, следует ли записывать первоначальные данные о активах, а затем получать данные о активах текущего счета и рассчитывать прибыль и убыток, сравнивая с первоначальным? К счастью, интерфейс счета активов платформы обычно возвращает все данные валютных активов, поэтому нам нужно получить их только один раз, а затем обработать данные.
ETHUSDT:100:0.002|LTCUSDT:20:0.1
ETHUSDT:100:0.002
контролирует торговую пару ETH_USDT, иLTCUSDT:20:0.1
ETHUSDT:100:0.002
,
Эти строки уже содержат информацию о параметрах каждого символа, который вам нужен для работы. Вы можете проанализировать строки и назначить значения переменным в стратегии, чтобы контролировать логику торговли каждого символа. Как проанализировать? Давайте воспользуемся примером, упомянутым выше.
function main() {
var net = [] // the recorded grid parameters; when specifically running the grid trading logic, use the data from here
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 amount
net.push({symbol : symbol, diff : diff, amount : amount})
})
Log("Grid parameter data:", net)
}
Конечно, вы можете использовать прямые строки 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; when specifically running the grid trading logic, use the data from here
_.each(net, function(pair) {
Log("Trading pair:", pair.symbol, pair)
})
}
_G()
Функция на FMZ Quant, или использовать функцию операцииDBExec()
в базе данных, и вы можете запросить документацию FMZ API для подробной информации.Например, мы хотим спроектировать функцию очистки, используя функцию_G()
, чтобы сохранить сетевые данные.
var net = null
function main() { // strategy main function
// first read the stored net
net = _G("net")
// ...
}
function onExit() {
_G("net", net)
Log("Execute the clean-up processing, and save the data", "#FF0000")
}
function onexit() { // the onexit function defined by the platform system, which will be triggered when clicking the bot to stop
onExit()
}
function onerror() { // the onerror function defined by the platform system, which will be triggered when the program exception occurs
onExit()
}
Система бэкстеста не имеет столь строгих ограничений на объем заказов и точность заказов; но в боте у каждой платформы есть строгие стандарты на цену заказов и объем заказов, а у разных торговых пар есть разные ограничения. Поэтому новички часто тестируют OKEX в системе бэкстеста. Как только стратегия запускается на боте, возникают различные проблемы при запуске торговли, а затем не читается содержание сообщения об ошибке, и появляются различные безумные явления.
Для случаев с несколькими символами требование более сложное. Для стратегии с одним символом вы можете разработать параметр для указания информации, такой как точность. Однако, когда вы разрабатываете стратегию с несколькими символами, очевидно, что запись информации в параметр сделает параметр очень утомительным.
В это время вам нужно проверить документацию API платформы, чтобы увидеть, есть ли в документации интерфейсы для информации о торговых парах. Если есть эти интерфейсы, вы можете разработать автоматический интерфейс доступа в стратегии для получения информации, такой как точность, и настроить его в информацию о торговых парах в торговле (коротко говоря, точность автоматически получается с платформы, а затем адаптируется к переменной, связанной с параметром стратегии).
На основе вышеуказанного анализа мы разработали библиотеку шаблонов, чтобы уменьшить связь между стратегией, механизмом платформы и интерфейсом.
Мы можем спроектировать библиотеку шаблонов так (часть кода пропущена):
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()
// the interfaces that need to be implemented
self.interfaceGetTickers = null // create a function that asynchronously obtains the aggregated market quote threads
self.interfaceGetAcc = null // create a function that asynchronously obtains the account data threads
self.interfaceGetPos = null // obtain positions
self.interfaceTrade = null // create concurrent orders
self.waitTickers = null // wait for the concurrent market quote data
self.waitAcc = null // wait for the account concurrent data
self.waitTrade = null // wait for order concurrent data
self.calcAmount = null // calculate the order amount according to the trading pair precision and other data
self.init = null // initialization; obtain the precision and other data
// execute the configuration function, to configure objects
funcConfigure(self)
// detect whether all the interfaces arranged by configList can be implemented
_.each(configList, function(funcName) {
if (!self[funcName]) {
throw "interface" + funcName + "not implemented"
}
})
return self
}
$.createBaseEx = createBaseEx
$.getConfigureFunc = function(exName) {
dicRegister = {
"Futures_OKCoin" : funcConfigure_Futures_OKCoin, // the implementation of OKEX Futures
"Huobi" : funcConfigure_Huobi,
"Futures_Binance" : funcConfigure_Futures_Binance,
"Binance" : funcConfigure_Binance,
"WexApp" : funcConfigure_WexApp, // the implementation of wexApp
}
return dicRegister
}
В шаблоне реализуйте написание кода, направленного на конкретную форму игры; возьмите в качестве примера моделируемый бот FMZ 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 the trading pair information
var symbolInfo = self.getSymbolInfo(symbol)
if (!symbol) {
throw symbol + ",trading pair information not found"
}
var tradeAmount = null
var equalAmount = null // record the symbol amount
if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
tradeAmount = _N(amount * price, parseFloat(symbolInfo.pricePrecision))
// detect the minimum trading amount
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))
// detect the minimum trading amount
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() { // the function that automatically processes conditions like precision, etc.
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 obtain the market quotes
ex.goGetTickers()
var tickers = ex.getTickers()
Log("tickers:", tickers)
// test to obtain the account information
ex.goGetAcc(symbol, ts)
_.each(arrTestSymbol, function(symbol) {
_.each(tickers, function(ticker) {
if (symbol == ticker.originalSymbol) {
// print the market quote data
Log(symbol, ticker)
}
})
// print asset data
var acc = ex.getAcc(symbol, ts)
Log("acc:", acc.symbol, acc)
})
}
Это очень просто, чтобы разработать и написать стратегию на основе вышеприведенного шаблона. Вся стратегия имеет около более 300 строк кода. Это реализует криптовалютные точки многосимвольной сетки стратегии.
Сейчас у него есть потери.T_T
, поэтому исходный код не будет предоставлен.
Есть несколько регистрационных кодов; если вы заинтересованы, вы можете попробовать их в wexApp:
Purchase Address: https://www.fmz.com/m/s/284507
Registration Code:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
Существовало всего более 200 долларов США, и когда бот только начался, он столкнулся с большим односторонним рынком. Ему нужно время, чтобы покрыть убытки. Самое большое преимущество стратегии спотовой сетки заключается в следующем: