Dalam artikel yang lalu, kami membuat strategi grid yang mudah bersama-sama. Dalam artikel ini, kami menaik taraf dan memperluaskan strategi ini menjadi strategi grid spot pelbagai spesies, dan biarkan strategi ini diuji dalam amalan. Tujuannya bukan untuk mencari
Artikel ini, seperti yang sebelumnya, masih membincangkan reka bentuk berdasarkan FMZ Quant (FMZ.COM).
Pelbagai spesies
Untuk mengatakannya secara terang-terangan, saya fikir strategi grid ini tidak hanya bolehBTC_USDT
, tetapi jugaLTC_USDT
/EOS_USDT
/DOGE_USDT
/ETC_USDT
/ETH_USDT
Bagaimanapun, pasangan dagangan spot dan varieti yang ingin berjalan semua didagangkan di grid pada masa yang sama.
Hmm~ Rasanya baik untuk menangkap pasaran pelbagai spesies. Keperluan itu terdengar sangat mudah, dan masalah datang semasa mereka merancang.
ETHUSDT:100:0.002|LTCUSDT:20:0.1
Di antara mereka, ETHUSDT:100:0.002
mengawal pasangan dagangan ETH_USDT, danLTCUSDT:20:0.1
Mengendalikan pasangan dagangan LTC_USDT.ETHUSDT:100:0.002
, di mana ETHUSDT menunjukkan apa pasangan dagangan yang anda ingin lakukan, 100 adalah jarak grid, 0.002 adalah bilangan duit syiling ETH yang didagangkan dalam setiap grid, 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)
}
Memandangkan ini, parameter dianalisis. sudah tentu, anda juga boleh menggunakan rentetan JSON secara langsung, yang lebih mudah.
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 Dagangan Kuantitatif FMZ, atau menggunakan fungsi operasi pangkalan dataDBExec()
, dan anda boleh memeriksa dokumentasi FMZ API untuk butiran.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 mengenakan sekatan yang ketat terhadap jumlah pesanan dan ketepatan pesanan, tetapi setiap bursa boleh mempunyai piawaian yang ketat untuk harga dan jumlah pesanan apabila meletakkan pesanan di bot sebenar, dan sekatan ini tidak sama di bursa yang berbeza. Oleh itu, ada pemula yang menguji dalam sistem backtesting tanpa masalah. Setelah bot sebenar dilancarkan, terdapat pelbagai masalah apabila perdagangan dicetuskan, dan kemudian kandungan mesej ralat tidak dibaca, dan pelbagai fenomena gila muncul.
Untuk kes pelbagai spesies, keperluan ini lebih rumit. Untuk strategi spesies tunggal, anda boleh merancang parameter untuk menentukan maklumat seperti ketepatan, tetapi ketika merancang strategi pelbagai spesies, adalah jelas bahawa menulis maklumat ini ke dalam parameter akan membuat parameter sangat kembung.
Pada masa ini, anda perlu menyemak dokumentasi API bursa untuk melihat sama ada terdapat maklumat antara muka yang berkaitan dengan pasangan dagangan dalam dokumentasi bursa. Jika ada, anda boleh merancang antara muka akses automatik dalam strategi untuk mendapatkan maklumat seperti ketepatan, dan menyusunnya ke dalam maklumat pasangan dagangan yang terlibat dalam perdagangan (singkatnya, ketepatan atau sesuatu yang diperoleh dari bursa secara automatik, dan kemudian disesuaikan dengan pembolehubah yang berkaitan dengan parameter strategi).
Berdasarkan analisis di atas, perpustakaan kelas templat direka untuk mengurangkan hubungan antara strategi dan mekanisme pertukaran dan antara muka.
Kita boleh merancang perpustakaan kelas templat ini seperti ini (sebahagian kod 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 templat, ia 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 templat ini dalam strategi adalah mudah:
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)
})
}
Ia adalah sangat mudah untuk merancang dan menulis strategi berdasarkan templat di atas. keseluruhan strategi adalah kira-kira 300+ baris dan melaksanakan mata wang digital spot strategi grid pelbagai spesies.
Ia kehilangan wang sekarangT_T
, kod sumber tidak akan dikeluarkan buat masa ini.
Berikut adalah beberapa kod pendaftaran, jika anda berminat, anda boleh menggunakan wexApp untuk mencuba:
Buy address: https://www.fmz.com/m/s/284507
Registration code:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
Hanya lebih daripada 200 U, ketika saya mula berlari, saya menemui pasaran satu sisi yang besar, tetapi saya pulih perlahan. Stabiliti tidak buruk, ia tidak diubahsuai sejak 27 Mei, dan grid niaga hadapan tidak berani untuk mencuba sementara.