avatar of 发明者量化-小小梦 发明者量化-小小梦
tập trung vào tin nhắn riêng tư
4
tập trung vào
1271
Người theo dõi

Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

Được tạo ra trong: 2021-06-04 10:08:48, cập nhật trên: 2024-12-04 21:14:15
comments   6
hits   2596

Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

Trong bài viết trước, chúng ta đã 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 ta sẽ nâng cấp và mở rộng chiến lược này thành một chiến lược lưới đa dạng và đưa chiến lược này vào thử nghiệm trong chiến đấu thực tế. Mục đích không phải là tìm ra “chén thánh” mà là khám phá các vấn đề và giải pháp khác nhau khi 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ày. Nội dung của bài viết này hơi phức tạp và đòi hỏi một nền tảng nhất định về lập trình.

Tư duy thiết kế dựa trên nhu cầu chiến lược

Bài viết này, giống như bài viết trước, vẫn thảo luận về thiết kế dựa trên Inventor Quantization (FMZ.COM).

  • Nhiều loại Nói một cách thẳng thắn, tôi nghĩ chiến lược lưới này không chỉBTC_USDT, cũng có thể làmLTC_USDT/EOS_USDT/DOGE_USDT/ETC_USDT/ETH_USDT. Dù sao đi nữa, đối với các cặp giao dịch giao ngay, tất cả sản phẩm bạn muốn giao dịch đều có thể được giao dịch theo lưới cùng một lúc.

Ừm~~Thật tuyệt khi nắm bắt được thị trường biến động của nhiều loại sản phẩm khác nhau. Các yêu cầu nghe có vẻ đơn giản, nhưng lại nảy sinh vấn đề trong quá trình thiết kế.

    1. Đầu tiên, hãy thu thập thông tin thị trường của nhiều loại sản phẩm khác nhau. Đây là vấn đề đầu tiên cần giải quyết. Sau khi kiểm tra tài liệu API của sàn giao dịch, tôi thấy rằng hầu hết các sàn giao dịch đều cung cấp giao diện thông tin thị trường tổng hợp. Được, hãy sử dụng giao diện dữ liệu thị trường tổng hợp để lấy dữ liệu.
    1. Vấn đề thứ hai gặp phải là tài sản tài khoản. Vì chúng ta muốn triển khai chiến lược đa dạng nên chúng ta cần cân nhắc việc quản lý tài sản riêng biệt cho từng giao dịch. Và để có được dữ liệu và hồ sơ của tất cả tài sản cùng một lúc. Tại sao chúng ta cần phải lấy dữ liệu tài sản tài khoản? Chúng ta có cần phải lưu giữ hồ sơ riêng cho từng cặp giao dịch không? Vì bạn cần phải đánh giá các tài sản có sẵn khi đặt lệnh, bạn có cần phải có chúng trước khi đưa ra đánh giá không? Và bạn cần tính toán thu nhập. Bạn có cần ghi lại dữ liệu tài sản tài khoản ban đầu trước, sau đó lấy dữ liệu tài sản tài khoản hiện tại và so sánh với dữ liệu ban đầu để tính toán lãi lỗ không? May mắn thay, giao diện tài khoản tài sản của sàn giao dịch thườ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 lấy dữ liệu một lần rồi xử lý dữ liệu.
    1. Thiết kế tham số chiến lược. Thiết kế tham số của nhiều loại khác nhau khá khác so với thiết kế tham số của từng loại đơn lẻ, vì mặc dù logic giao dịch của mỗi loại là giống nhau, nhưng các tham số trong quá trình giao dịch có thể khác nhau. Ví dụ, trong chiến lược lưới, bạn có thể muốn giao dịch 0,01 BTC mỗi lần khi thực hiện cặp giao dịch BTC_USDT. Tuy nhiên, nếu bạn vẫn sử dụng tham số này (giao dịch 0,01 coin) khi thực hiện DOGE_USDT, thì rõ ràng là không phù hợp. Tất nhiên, bạn có thể cũng xử lý theo số lượng USDT. Nhưng vẫn sẽ có vấn đề. Còn nếu bạn chỉ muốn giao dịch 1000U với BTC_USDT và 10U với DOGE_USDT thì sao? Nhu cầu không bao giờ có thể đáp ứng được. Một số học sinh có thể nghĩ về câu hỏi này và sau đó nói: “Tôi có thể thiết lập nhiều nhóm tham số để kiểm soát riêng các tham số của các cặp giao dịch khác nhau”. Điều này vẫn không thể đáp ứng nhu cầu một cách linh hoạt. Cần thiết lập bao nhiêu nhóm tham số? Có ba bộ tham số được thiết lập. Nếu tôi muốn giao dịch 4 loại thì sao? Có thể sửa đổi chiến lược và thêm tham số không… Do đó, khi thiết kế các tham số của chiến lược đa dạng, chúng ta phải cân nhắc đầy đủ nhu cầu về các tham số khác biệt. Một giải pháp là thiết kế các tham số dưới dạng chuỗi thông thường hoặc chuỗi JSON. Ví dụ:
    ETHUSDT:100:0.002|LTCUSDT:20:0.1
    

    Dấu “|” phân tách dữ liệu của từng loại, có nghĩa làETHUSDT:100:0.002Nó kiểm soát cặp giao dịch ETH_USDT.LTCUSDT:20:0.1Nó kiểm soát cặp giao dịch LTC_USDT. Dấu “|” ở giữa có tác dụng phân tách. ETHUSDT:100:0.002, trong đó ETHUSDT biểu thị cặp giao dịch bạn muốn giao dịch, 100 là khoảng cách lưới, 0,002 là số lượng đồng ETH được giao dịch trong mỗi lưới và dấu “:” được sử dụng để phân tách các dữ liệu này (tất nhiên, các quy tắc tham số này là được thiết lập bởi nhà thiết kế chiến lược). Bạn có thể thiết kế nó theo nhu cầu của mình). Các chuỗi này chứa thông tin tham số của từng sản phẩm bạn muốn giao dịch. Phân tích các chuỗi này trong chiến lược và gán các giá trị cụ thể cho các biến của chiến lược để kiểm soát logic giao dịch của từng sản phẩm. Vậy làm sao để phân tích nó? Chúng ta hãy sử dụng lại ví dụ trên.

    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)
    }
    

    Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

    Bạn có thể thấy các tham số được phân tích theo cách này. Tất nhiên, bạn cũng có thể sử dụng trực tiếp chuỗi JSON, đơ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)
        })
    }
    

    Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

    1. Sự tồn tại của dữ liệu Ngoài ra còn có một sự khác biệt lớn giữa các chiến lược có thể áp dụng vào thực tế và các chiến lược giảng dạy. Chiến lược giảng dạy trong bài viết trước chỉ là một bài kiểm tra sơ bộ về logic và thiết kế chiến lược. Còn nhiều vấn đề khác cần xem xét trong thực tế. Trong quá trình giao dịch thực tế, bạn có thể bắt đầu và dừng giao dịch thực tế. Lúc này, toàn bộ dữ liệu trong quá trình hoạt động thời gian thực sẽ bị mất. Vậy làm thế nào chúng ta có thể khiến đĩa thật dừng lại rồi khởi động lại để tiếp tục chạy ở trạng thái trước đó? Ở đây, cần phải lưu trữ dữ liệu chính trong quá trình hoạt động thời gian thực để dữ liệu có thể được đọc và tiếp tục khi hệ thống khởi động lại. Nó có thể được sử dụng trên Nền tảng giao dịch định lượng Inventor_G()Chức năng, hoặc sử dụng chức năng hoạt động cơ sở dữ liệuDBExec()Để biết chi tiết, vui lòng tham khảo tài liệu API FMZ.

    Ví dụ, chúng tôi thiết kế một hàm quét, sử dụng_G()Chức năng lưu 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()
    }
    
    1. Hạn chế về độ chính xác của số lượng đặt hàng, độ chính xác của giá đặt hàng, số lượng đặt hàng tối thiểu, số tiền đặt hàng tối thiểu, v.v.

    Hệ thống kiểm tra ngược không áp đặt những hạn chế nghiêm ngặt như vậy đối với số lượng lệnh và độ chính xác của lệnh, nhưng trong giao dịch thực tế, mỗi sàn giao dịch có thể có những tiêu chuẩn nghiêm ngặt về giá lệnh và số lượng lệnh, và những tiêu chuẩn này đối với mỗi cặp giao dịch cũng rất nghiêm ngặt. Những hạn chế không giống nhau. Do đó, người mới thường kiểm tra hệ thống kiểm tra ngược và thấy đủ loại vấn đề khi kích hoạt giao dịch trên thị trường thực. Sau đó, họ thậm chí không đọc thông báo lỗi và gặp phải đủ loại vấn đề điên rồ [dog head].

    Đối với nhiều loại, yêu cầu này phức tạp hơn. Đối với chiến lược sản phẩm đơn lẻ, bạn có thể thiết kế một tham số để chỉ định thông tin như độ chính xác. Tuy nhiên, khi thiết kế chiến lược nhiều sản phẩm, rõ ràng là việc ghi thông tin này vào tham số sẽ khiến tham số trông rất cồng kềnh.

    Lúc này, bạn cần kiểm tra tài liệu API của sàn giao dịch để xem có giao diện nào chứa thông tin liên quan đến cặp giao dịch trong tài liệu của sàn giao dịch hay không. Nếu các giao diện này khả dụng, bạn có thể thiết kế một giao diện truy cập tự động trong chiến lược để lấy thông tin như độ chính xác và cấu hình nó cho thông tin cặp giao dịch liên quan đến giao dịch (nói một cách đơn giản, độ chính xác được tự động yêu cầu từ sàn giao dịch và sau đó điều chỉnh theo các tham số chiến lược).

    1. Thích ứng với các trao đổi khác nhau Tại sao lại đặt câu hỏi này ở cuối? Bởi vì các giải pháp cho các vấn đề mà chúng ta đã nói ở trên sẽ mang lại vấn đề cuối cùng này, bởi vì chiến lược của chúng tôi có kế hoạch sử dụng giao diện thị trường tổng hợp, truy cập vào độ chính xác của cặp giao dịch trao đổi và việc điều chỉnh dữ liệu khác, truy cập vào thông tin tài khoản và xử lý từng cặp giao dịch riêng biệt, v.v. . Các giải pháp này sẽ có sự khác biệt rất lớn giữa các sàn giao dịch. Có sự khác biệt trong các lệnh gọi giao diện và sự khác biệt trong các cơ chế. Đối với các sàn giao dịch giao ngay, sự khác biệt sẽ nhỏ hơn nếu chiến lược lưới này được mở rộng thành phiên bản tương lai. Sự khác biệt trong cơ chế của nhiều loại trao đổi thậm chí còn lớn hơn. Một giải pháp là thiết kế thư viện mẫu FMZ. Viết và thiết kế các triển khai khác biệt này trong thư viện lớp. Giảm sự liên kết giữa chiến lược và sàn giao dịch. Nhược điểm của cách này là bạn cần phải viết một thư viện mẫu và triển khai nó cụ thể cho từng trao đổi trong mẫu này.

Thiết kế thư viện mẫu

Dựa trên phân tích trên, một thư viện mẫu được thiết kế để giảm sự kết hợp giữa các chiến lược và cơ chế trao đổi cũng như 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 số mã bị lược bỏ):

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
}

Trong mẫu, hãy viết cho mục đích triển khai trao đổi cụ thể, ví dụ, lấy đĩa mô phỏng WexApp của FMZ làm ví dụ:

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 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)
    })
}

Chiến lược thị trường thực tế

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 dài khoảng 300+ dòng, thực hiện chiến lược lưới đa dạng giao ngay tiền kỹ thuật số.

Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

Những người mới tham gia Giao dịch định lượng trong các Vòng tròn tiền điện tử, vui lòng xem qua bài viết này - Đưa bạn đến gần hơn với Giao dịch định lượng trong các Vòng tròn tiền điện tử (VI)

Hiện đang mất tiềnT_T, mã nguồn sẽ không được phát hành trong thời điểm hiện tại.

Sau đây là một số mã đăng ký. Nếu bạn quan tâm, bạn có thể dùng thử trên wexApp:

购买地址: https://www.fmz.com/m/s/284507
注册码: 
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc

Chỉ có hơn 200 Us, và ngay khi bắt đầu hoạt động, nó đã gặp phải một thị trường một chiều lớn và dần phục hồi. Ưu điểm lớn nhất của lưới điểm là: “Bạn có thể ngủ ngon!” Độ ổn định thì ổn. Tôi chưa đụng đến nó kể từ ngày 27 tháng 5. Tôi không dám thử lưới tương lai vào lúc này.