Trong bài viết trước, chúng tôi đã cùng nhau thực hiện một chiến lược lưới đơn giản, bài viết này chúng tôi đã nâng cấp và mở rộng chiến lược này, mở rộng thành một chiến lược lưới trực tiếp đa dạng và cho phép chiến lược này được thử nghiệm thực tế. Mục đích không phải là tìm kiếm một "bàn thánh", mà là để tìm ra các vấn đề trong việc thiết kế chiến lược từ thiết kế chiến lược. Bài viết này sẽ giải thích một số kinh nghiệm của tôi trong việc thiết kế chiến lược, nội dung này hơi phức tạp và cần một nền tảng nào đó để viết chương trình.
Bài viết này cũng giống như bài trước, vẫn dựa trên định lượng của nhà phát minh.FMZ.COMCác bạn có thể tham gia tham khảo bài viết này.
Nhiều giống
Nói thật là tôi muốn chiến lược lưới này không chỉ làmBTC_USDT
Có thể làm.LTC_USDT
/EOS_USDT
/DOGE_USDT
/ETC_USDT
/ETH_USDT
Các đối tượng muốn chạy cũng được giao dịch trên mạng lưới.
1, đầu tiên là mua nhiều loại thị trường. Đây là vấn đề đầu tiên cần giải quyết. Sau khi xem tài liệu API của sàn giao dịch, tôi thấy rằng các sàn giao dịch thông thường cung cấp giao diện thị trường tổng hợp. OK, lấy dữ liệu bằng giao diện thị trường tổng hợp.
2, Vấn đề thứ hai gặp phải là tài sản tài khoản. Vì đây là một chiến lược đa dạng, nên bạn phải xem xét quản lý tài sản riêng cho từng giao dịch. Và bạn phải lấy dữ liệu, hồ sơ của tất cả các tài sản cùng một lúc. Tại sao bạn nên lấy dữ liệu tài sản tài khoản? Vì bạn cần phải đánh giá tài sản có sẵn khi đặt hàng, hay là để có được và đánh giá lại? Bạn có cần tính lợi nhuận, hay bạn phải ghi lại dữ liệu tài sản tài khoản ban đầu trước khi lấy dữ liệu tài sản tài khoản hiện tại và tính lợi nhuận và lỗ so với so sánh ban đầu? Tuy nhiên, giao diện tài khoản tài sản của sàn giao dịch thường cũng trả về dữ liệu tài sản của tất cả các loại tiền tệ, chúng ta chỉ cần truy cập một lần và sau đó xử lý dữ liệu.
3, thiết kế tham số chiến lược. Thiết kế tham số nhiều giống và thiết kế tham số một giống có sự khác biệt lớn, bởi vì các loại giao dịch của nhiều giống mặc dù logic giao dịch là giống nhau, nhưng các tham số giao dịch có thể khác nhau. Ví dụ, chiến lược lưới, có thể làm BTC_USDT giao dịch đôi khi mong muốn 0.01 BTC mỗi giao dịch, nhưng làm DOGE_USDT nếu vẫn là tham số này (( giao dịch 0.01 đồng xu) rõ ràng là không phù hợp, tất nhiên bạn cũng có thể xử lý theo số tiền USDT.
Có lẽ bạn cùng lớp sẽ nghĩ về vấn đề này, và sau đó đưa ra:
ETHUSDT:100:0.002|LTCUSDT:20:0.1
Trong đó phân chia phân chia phân chia là dữ liệu cho mỗi giống, nghĩa làETHUSDT:100:0.002
Trong khi đó, các nhà đầu tư khác cũng có thể sử dụng ETH để kiểm soát các giao dịch.LTCUSDT:20:0.1
LTC_USDT là cặp giao dịch được điều khiển.ETHUSDT:100:0.002
Trong đó, ETHUSDT cho biết bạn sẽ thực hiện giao dịch với cặp nào, 100 là khoảng lưới, 0.002 là số tiền ETH giao dịch trên mỗi lưới, và
function main() {
var net = [] // 记录的网格参数,具体运行到网格交易逻辑时,使用这里面的数据
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] // 交易对名称
var diff = parseFloat(arr[1]) // 网格间距
var amount = parseFloat(arr[2]) // 网格下单量
net.push({symbol : symbol, diff : diff, amount : amount})
})
Log("网格参数数据:", net)
}
Bạn có thể sử dụng một 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) // 记录的网格参数,具体运行到网格交易逻辑时,使用这里面的数据
_.each(net, function(pair) {
Log("交易对:", pair.symbol, pair)
})
}
4. Dữ liệu vĩnh viễn
Chiến lược thực tế và chiến lược giảng dạy cũng có sự khác biệt lớn, chiến lược giảng dạy ở trên chỉ là thử nghiệm chiến lược logic, thiết kế, nhiều vấn đề được xem xét trong thực tế. Trong thực tế, có thể mở, dừng thực tế.
Ở đây, bạn cần lưu giữ dữ liệu quan trọng khi ổ đĩa thực chạy để đọc dữ liệu này khi khởi động lại và tiếp tục chạy.
Có thể sử dụng trên nền tảng giao dịch định lượng của nhà phát minh_G()
Các hàm, hoặc sử dụng các hàm để vận hành cơ sở dữ liệuDBExec()
Bạn có thể tham khảo tài liệu API FMZ.
Ví dụ, chúng ta thiết kế một hàm quét, sử dụng_G()
Chức năng lưu trữ dữ liệu lưới.
var net = null
function main() { // 策略主函数
// 首先读取储存的net
net = _G("net")
// ...
}
function onExit() {
_G("net", net)
Log("执行扫尾处理,保存数据", "#FF0000")
}
function onexit() { // 平台系统定义的退出扫尾函数,在点击实盘停止时触发执行
onExit()
}
function onerror() { // 平台系统定义的异常退出函数,在程序发生异常时触发执行
onExit()
}
5. Các hạn chế như độ chính xác đơn hàng, độ chính xác giá đơn hàng, số lượng đơn hàng tối thiểu, số tiền đơn hàng tối thiểu
Trong hệ thống kiểm tra lại không có những hạn chế nghiêm ngặt như vậy đối với đơn hàng, độ chính xác đơn hàng, vv, nhưng trong thời gian thực, các sàn giao dịch có thể có các tiêu chuẩn nghiêm ngặt về giá đơn hàng, số lượng đơn hàng, và các cặp giao dịch khác nhau. Vì vậy, thường có những vấn đề khác nhau khi thử nghiệm hệ thống kiểm tra lại OK, một lần trên đĩa thực, khi kích hoạt giao dịch, sau đó cũng không xem nội dung thông tin sai, có nhiều hiện tượng điên cuồng xuất hiện.
Trong trường hợp đa giống, nhu cầu này phức tạp hơn. Trong một chính sách đơn giống, bạn có thể thiết kế một tham số để chỉ định thông tin chính xác, nhưng khi thiết kế chính sách đa giống, rõ ràng thông tin này được viết trong các tham số sẽ rất phức tạp.
Khi đó, bạn cần xem tài liệu API của sàn giao dịch để xem liệu tài liệu sàn giao dịch có giao dịch với các giao diện thông tin liên quan không. Nếu có giao diện này, bạn có thể thiết kế chính sách để truy cập tự động vào giao diện để có được thông tin chính xác, cấu hình thông tin chính xác cho thông tin giao dịch tham gia giao dịch (một cách đơn giản là chính xác những gì được yêu cầu tự động từ sàn giao dịch để có được và sau đó phù hợp với các biến liên quan đến tham số chính sách).
6/ Phương pháp phù hợp với các sàn giao dịch khác nhau Tại sao lại đặt câu hỏi này ở cuối? Vì những giải pháp giải quyết các vấn đề trên sẽ gây ra vấn đề cuối cùng này, vì chiến lược của chúng tôi là sử dụng giao diện thị trường tổng hợp, truy cập giao dịch trên sàn giao dịch để điều chỉnh dữ liệu, truy cập thông tin tài khoản riêng biệt để xử lý các giao dịch khác nhau. Có sự khác biệt về các cuộc gọi giao diện, sự khác biệt về cơ chế. Đối với các sàn giao dịch hiện tại, sự khác biệt còn nhỏ hơn một chút nếu chính sách lưới này được mở rộng sang phiên bản tương lai. Sự khác biệt về các cơ chế giao dịch lớn hơn. Một giải pháp là thiết kế một thư viện mẫu FMZ. Nhược điểm của việc làm như vậy là cần phải viết một thư viện các lớp mẫu và thực hiện cụ thể cho mỗi sàn giao dịch trong mẫu này.
Dựa trên các phân tích trên, thiết kế một thư viện mẫu để giảm sự kết nối giữa chiến lược và cơ chế giao dịch, giao diện.
Chúng ta có thể thiết kế thư viện các lớp mẫu như sau:
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()
// 需要实现的接口
self.interfaceGetTickers = null // 创建异步获取聚合行情数据线程的函数
self.interfaceGetAcc = null // 创建异步获取账户数据线程的函数
self.interfaceGetPos = null // 获取持仓
self.interfaceTrade = null // 创建并发下单
self.waitTickers = null // 等待并发行情数据
self.waitAcc = null // 等待账户并发数据
self.waitTrade = null // 等待下单并发数据
self.calcAmount = null // 根据交易对精度等数据计算下单量
self.init = null // 初始化工作,获取精度等数据
// 执行配置函数,给对象配置
funcConfigure(self)
// 检测configList约定的接口是否都实现
_.each(configList, function(funcName) {
if (!self[funcName]) {
throw "接口" + funcName + "未实现"
}
})
return self
}
$.createBaseEx = createBaseEx
$.getConfigureFunc = function(exName) {
dicRegister = {
"Futures_OKCoin" : funcConfigure_Futures_OKCoin, // OK期货的实现
"Huobi" : funcConfigure_Huobi,
"Futures_Binance" : funcConfigure_Futures_Binance,
"Binance" : funcConfigure_Binance,
"WexApp" : funcConfigure_WexApp, // wexApp的实现
}
return dicRegister
}
Thực hiện viết cho các sàn giao dịch cụ thể trong mẫu, ví dụ như WexApp, một đĩa tương tự của 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) {
// 获取交易对信息
var symbolInfo = self.getSymbolInfo(symbol)
if (!symbol) {
throw symbol + ",交易对信息查询不到"
}
var tradeAmount = null
var equalAmount = null // 记录币数
if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
tradeAmount = _N(amount * price, parseFloat(symbolInfo.pricePrecision))
// 检查最小交易量
if (tradeAmount < symbolInfo.min) {
Log(self.name, " tradeAmount:", tradeAmount, "小于", symbolInfo.min)
return false
}
equalAmount = tradeAmount / price
} else {
tradeAmount = _N(amount, parseFloat(symbolInfo.amountPrecision))
// 检查最小交易量
if (tradeAmount < symbolInfo.min / price) {
Log(self.name, " tradeAmount:", tradeAmount, "小于", symbolInfo.min / price)
return false
}
equalAmount = tradeAmount
}
return [tradeAmount, equalAmount]
}
self.init = function init() { // 自动处理精度等条件的函数
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 chiến lược là rất đơ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()
// 测试获取行情
ex.goGetTickers()
var tickers = ex.getTickers()
Log("tickers:", tickers)
// 测试获取账户信息
ex.goGetAcc(symbol, ts)
_.each(arrTestSymbol, function(symbol) {
_.each(tickers, function(ticker) {
if (symbol == ticker.originalSymbol) {
// 打印行情数据
Log(symbol, ticker)
}
})
// 打印资产数据
var acc = ex.getAcc(symbol, ts)
Log("acc:", acc.symbol, acc)
})
}
Theo mô hình trên, một chiến lược viết rất đơn giản, khoảng 300+ dòng, thực hiện một chiến lược lưới đa dạng tiền kỹ thuật số.
Hiện tại đang mất tiền.T_T
Có thể bạn sẽ thấy một số hình ảnh của những người đang làm việc tại một công ty.
Nếu bạn muốn chơi trên WexApp, hãy gửi một vài mã đăng ký:
购买地址: https://www.fmz.com/m/s/284507
注册码:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
Khi chạy lên, bạn sẽ thấy một làn sóng lớn, chảy máu chậm. Ưu điểm lớn nhất của lưới mặt hàng là: bạn có thể ngủ! Sự ổn định cũng đang kết hợp, không có động thái nào từ ngày 27 tháng 5 đến nay, và lưới tương lai tạm thời không dám thử.
Kiểu học số lượngCảm ơn nhà xây dựng, số lượng. Có đèn sáng trên đường hầm.
Chín mặt trờiTổng thống Mạnh Điện!
Động vật quỹ đạoCảm ơn.
Những nhà phát minh định lượng - những giấc mơ nhỏCảm ơn sự ủng hộ của bạn!
Những nhà phát minh định lượng - những giấc mơ nhỏCảm ơn sự ủng hộ của bạn!