Dalam artikel sebelumnya, kami membuat strategi grid sederhana bersama-sama. Dalam artikel ini, kami memperbarui dan memperluas strategi ini menjadi strategi grid spot multi spesies, dan biarkan strategi ini diuji dalam praktek. Tujuannya bukan untuk menemukan
Artikel ini, seperti yang sebelumnya, masih membahas desain berdasarkan FMZ Quant (FMZ.COM).
Berbagai spesies
Untuk mengatakannya secara langsung, saya pikir strategi grid ini tidak hanya dapatBTC_USDT
, tapi jugaLTC_USDT
/EOS_USDT
/DOGE_USDT
/ETC_USDT
/ETH_USDT
Bagaimanapun, pasangan perdagangan spot dan varietas yang ingin berjalan semua diperdagangkan di grid pada saat yang sama.
Hmm~ Rasanya enak untuk menangkap pasar volatile dari beberapa spesies. Persyaratan ini terdengar sangat sederhana, dan masalahnya datang saat merancang.
ETHUSDT:100:0.002|LTCUSDT:20:0.1
Di antara mereka, ETHUSDT:100:0.002
mengontrol pasangan perdagangan ETH_USDT, danLTCUSDT:20:0.1
Mengontrol pasangan perdagangan LTC_USDT.ETHUSDT:100:0.002
, di mana ETHUSDT menunjukkan pasangan perdagangan apa yang ingin Anda lakukan, 100 adalah jarak kisi, 0,002 adalah jumlah koin ETH yang diperdagangkan di setiap kisi, dan
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)
}
Dengan melihat ini, parameter dianalisis. tentu saja, Anda juga dapat menggunakan string JSON secara langsung, yang lebih sederhana.
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)
})
}
_G()
Fungsi di Platform Perdagangan Kuantitatif FMZ, atau menggunakan fungsi operasi basis dataDBExec()
, dan Anda dapat memeriksa dokumentasi FMZ API untuk rincian.Sebagai contoh, kita merancang fungsi sapu ekor dan menggunakan_G()
fungsi untuk menyimpan data grid.
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()
}
Sistem backtesting tidak memberlakukan pembatasan yang ketat pada jumlah pesanan dan akurasi pesanan, tetapi setiap bursa dapat memiliki standar yang ketat untuk harga dan jumlah pesanan saat menempatkan pesanan di bot nyata, dan pembatasan ini tidak sama di bursa yang berbeda. Oleh karena itu, ada pemula yang menguji dalam sistem backtesting tanpa masalah. Setelah bot nyata diluncurkan, ada berbagai masalah ketika perdagangan dipicu, dan kemudian isi pesan kesalahan tidak dibaca, dan berbagai fenomena gila muncul.
Untuk kasus multi-spesies, persyaratan ini lebih rumit. Untuk strategi satu spesies, Anda dapat merancang parameter untuk menentukan informasi seperti akurasi, tetapi ketika merancang strategi multi-spesies, jelas bahwa menulis informasi ini ke dalam parameter akan membuat parameter sangat kembung.
Pada saat ini, Anda perlu memeriksa dokumentasi API dari bursa untuk melihat apakah ada informasi antarmuka yang terkait dengan pasangan perdagangan dalam dokumentasi bursa. Jika ada, Anda dapat merancang antarmuka akses otomatis dalam strategi untuk mendapatkan informasi seperti akurasi, dan mengkonfigurasinya ke dalam informasi pasangan perdagangan yang terlibat dalam perdagangan (singkatnya, akurasi atau sesuatu yang diperoleh dari bursa secara otomatis, dan kemudian disesuaikan dengan variabel yang terkait dengan parameter strategi).
Berdasarkan analisis di atas, perpustakaan kelas templat dirancang untuk mengurangi kopling antara strategi dan mekanisme pertukaran dan antarmuka.
Kita bisa mendesain perpustakaan kelas templat ini seperti ini (sebagian kode dihilangkan):
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
}
Dalam template, ditulis untuk pertukaran tertentu, ambil FMZ
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
})
})
}
}
Kemudian menggunakan template ini dalam strategi adalah sederhana:
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)
})
}
Sangat sederhana untuk merancang dan menulis strategi berdasarkan template di atas. Seluruh strategi sekitar 300+ baris dan menerapkan strategi grid multi-spesies spot mata uang digital.
Ini kehilangan uang saat iniT_T
, kode sumbernya tidak akan dirilis untuk saat ini.
Berikut adalah beberapa kode pendaftaran, jika Anda tertarik, Anda dapat menggunakan wexApp untuk mencobanya:
Buy address: https://www.fmz.com/m/s/284507
Registration code:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
Hanya sekitar 200 U, ketika saya baru saja mulai berlari, saya menemukan pasar satu sisi yang besar, tetapi saya pulih perlahan. Stabilitasnya tidak buruk, tidak ada perubahan sejak 27 Mei, dan grid berjangka tidak berani mencoba sementara.