Trong bài viết trước đây, chúng tôi đã cùng nhau tạo ra một chiến lược lưới đơn giản. Trong bài viết này, chúng tôi đã nâng cấp và mở rộng chiến lược này thành một chiến lược lưới điểm đa loài, và để cho chiến lược này được thử nghiệm trong thực tế. Mục đích không phải là để tìm ra một
Bài viết này, giống như bài trước, vẫn thảo luận về thiết kế dựa trên FMZ Quant (FMZ.COM).
Nhiều loài
Nói thẳng ra, tôi nghĩ rằng chiến lược lưới điện này không chỉ có thểBTC_USDT
, nhưng cũngLTC_USDT
/EOS_USDT
/DOGE_USDT
/ETC_USDT
/ETH_USDT
Dù sao, các cặp giao dịch tại chỗ và các loại muốn chạy đều được giao dịch trên lưới cùng một lúc.
Hmm~ Thật tốt khi nắm bắt được thị trường biến động của nhiều loài. Yêu cầu nghe có vẻ rất đơn giản, và vấn đề xuất hiện khi thiết kế.
ETHUSDT:100:0.002|LTCUSDT:20:0.1
Trong số đó, ETHUSDT:100:0.002
kiểm soát cặp giao dịch ETH_USDT, vàLTCUSDT:20:0.1
điều khiển cặp giao dịch LTC_USDT.ETHUSDT:100:0.002
, trong đó ETHUSDT chỉ ra cặp giao dịch bạn muốn làm, 100 là khoảng cách lưới, 0,002 là số tiền ETH được giao dịch trong mỗi lưới, và
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)
}
Tất nhiên, bạn cũng có thể sử dụng các chuỗi JSON trực tiếp, đơn giản hơn.
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()
chức năng trên nền tảng giao dịch định lượng FMZ, hoặc sử dụng chức năng hoạt động cơ sở dữ liệuDBExec()
, và bạn có thể kiểm tra tài liệu API FMZ để biết chi tiết.Ví dụ, chúng tôi thiết kế một chức năng quét đuôi và sử dụng_G()
chức năng để lưu dữ liệu lưới.
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()
}
Hệ thống backtesting không áp đặt những hạn chế nghiêm ngặt như vậy đối với số tiền đặt hàng và độ chính xác của lệnh, nhưng mỗi sàn giao dịch có thể có các tiêu chuẩn nghiêm ngặt về giá cả và số tiền đặt hàng khi đặt lệnh trong bot thực, và những hạn chế này không giống nhau trong các sàn giao dịch khác nhau. Do đó, có những người mới bắt đầu thử nghiệm trong hệ thống backtesting mà không có vấn đề. Một khi bot thực được khởi động, có nhiều vấn đề khác nhau khi giao dịch được kích hoạt, và sau đó nội dung của thông báo lỗi không được đọc, và nhiều hiện tượng điên rồ xuất hiện.
Đối với các trường hợp đa loài, yêu cầu này phức tạp hơn. Đối với một chiến lược một loài, bạn có thể thiết kế một tham số để chỉ định thông tin như độ chính xác, nhưng khi thiết kế một chiến lược đa loài, rõ ràng là viết thông tin này vào các tham số sẽ làm cho các tham số rất phồng phồng.
Tại thời điểm này, bạn cần kiểm tra tài liệu API của sàn giao dịch để xem liệu có thông tin giao diện liên quan đến các cặp giao dịch trong tài liệu sàn giao dịch hay không. Nếu có, bạn có thể thiết kế giao diện truy cập tự động trong chiến lược để có được thông tin như độ chính xác, và cấu hình nó vào thông tin cặp giao dịch liên quan đến giao dịch (tóm lại, độ chính xác hoặc một cái gì đó được lấy từ sàn giao dịch tự động, và sau đó điều chỉnh theo các biến liên quan đến các thông số chiến lược).
Dựa trên phân tích trên, thư viện lớp mẫu được thiết kế để giảm sự kết nối giữa chiến lược và cơ chế trao đổi và giao diện.
Chúng ta có thể thiết kế thư viện lớp mẫu này như thế này (một phần của mã bị bỏ qua):
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
}
Trong mẫu, nó được viết cho các sàn giao dịch cụ thể, lấy ví dụ về robot mô phỏng 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
})
})
}
}
Sau đó sử dụng mẫu này trong một chiến lược là đơn giản:
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)
})
}
Nó rất đơn giản để thiết kế và viết một chiến lược dựa trên mẫu trên. Toàn bộ chiến lược là khoảng 300+ dòng và thực hiện một chiến lược lưới đa loài tiền kỹ thuật số.
Nó đang mất tiền.T_T
, mã nguồn sẽ không được phát hành trong thời gian này.
Dưới đây là một vài mã đăng ký, nếu bạn quan tâm, bạn có thể sử dụng wexApp để thử:
Buy address: https://www.fmz.com/m/s/284507
Registration code:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
Một chút hơn 200 U, khi tôi mới bắt đầu chạy, tôi gặp một thị trường một bên lớn, nhưng tôi phục hồi từ từ. Sự ổn định không tệ, nó đã không thay đổi kể từ ngày 27 tháng 5, và mạng lưới tương lai không dám thử tạm thời.