Thiết kế hệ thống quản lý đồng bộ đơn đặt hàng dựa trên FMZ định lượng (1)

Tác giả:Giấc mơ nhỏ, Tạo: 2022-02-14 19:46:30, Cập nhật: 2023-09-15 20:44:11

img

Thiết kế hệ thống quản lý đồng bộ đơn đặt hàng dựa trên FMZ định lượng (1)

Trong các bài viết trước đây của FMZ, chúng tôi đã thiết kế một số lệnh, chiến lược đồng bộ hóa kho.

Đây là việc đặt tài khoản tham chiếu và đồng bộ trong một chính sách để quản lý thực hiện lệnh, đồng bộ hóa lưu trữ. Hôm nay chúng tôi sẽ thử một thiết kế khác, dựa trên giao diện API mở rộng mạnh mẽ của nền tảng giao dịch định lượng FMZ, chúng tôi sẽ thiết kế một hệ thống quản lý đồng bộ hóa lệnh.

Ý tưởng thiết kế

Trước tiên, chúng ta cần có một số lời khuyên tốt, nhu cầu.

  • Người thực hiện chính sách đồng bộ trên thực tế phải có API KEY của sàn giao dịch tài khoản tham khảo, API KEY của sàn giao dịch tài khoản đồng bộ. Vấn đề đối với trường hợp sử dụng là: tài khoản giao dịch khác của bạn theo dõi tài khoản của bạn là không có vấn đề. Tuy nhiên, trong trường hợp tài khoản tham khảo và tài khoản đồng bộ không phải là một chủ sở hữu, nó sẽ rất khó khăn. Chủ sở hữu tài khoản đồng bộ đôi khi không sẵn sàng cung cấp API KEY của tài khoản giao dịch của mình vì lý do an ninh.

    Giải pháp: Sử dụng giao diện API mở rộng của FMZ, chủ sở hữu tài khoản đồng bộ (những người đăng ký) chỉ cần đăng ký nền tảng giao dịch định lượng FMZ và sau đó chạy một chính sách (trong hệ thống được thiết kế trong bài viết này):订单同步管理系统(Synchronous Server)Sau đó, bạn có thể cung cấp ID ổ đĩa thực của FMZ cho chủ sở hữu tài khoản tham khảo (lưu ý, không phải là API KEY của tài khoản giao dịch) và hệ thống quản lý đồng bộ hóa đơn (Synchronous Server). Khi tham khảo tài khoản chủ sở hữu (đơn giản là người sử dụng) trong hệ thống được thiết kế cho bài viết này订单同步管理系统类库(Single Server)Một tín hiệu sẽ được gửi đến máy tính của chủ tài khoản đồng bộ để nhận được tín hiệu giao dịch và tự động đặt hàng.

  • 2, Nhiều nhà phát triển có chiến lược tốt hơn, không thể sử dụng hai lệnh tương lai được mô tả ở trên, chiến lược đồng bộ hóa tồn kho. Vì vậy, cần phải kết hợp chiến lược của mình với các chiến lược đồng bộ hóa, có thể sẽ cần phải thay đổi lớn, tốn công. Có cách nào tốt để nâng cấp một số chiến lược đã có sẵn của mình trực tiếp lên chức năng đồng bộ hóa lệnh không? Giải pháp: Có thể thiết kế một thư viện mẫu đồng bộ theo lệnh (trong hệ thống được thiết kế trong bài viết này)订单同步管理系统类库(Single Server)Chính sách), cho phép chủ sở hữu tài khoản tham khảo (nhà đăng ký) trực tiếp nhúng thư viện mẫu này vào chính sách của mình để thực hiện chức năng đồng bộ hóa lệnh, lưu trữ.

  • 3, giảm thêm một đĩa thực. Điểm đau cuối cùng là nếu sử dụng 2 lệnh tương lai được mô tả ở trên, bạn sẽ cần mở thêm một tài khoản chứng khoán theo dõi thực tế. Giải pháp: Sử dụng thư viện mẫu để nhúng chức năng vào chính sách tài khoản tham khảo.

Vì vậy, hệ thống này có hai phần: 1, thư viện hệ thống quản lý đồng bộ đơn hàng (Single Server) 2, Hệ thống quản lý đồng bộ lệnh (Synchronous Server)

Khi bạn biết rõ nhu cầu của mình, hãy bắt đầu thiết kế.

Thiết kế 1: thư viện hệ thống quản lý đồng bộ đơn hàng (Single Server)

Lưu ý rằng đây không phải là một chiến lược. Nhưng là một thư viện mẫu của FMZ, khái niệm về thư viện mẫu có thể được tìm kiếm trong tài liệu API của FMZ, không được thảo luận thêm ở đây.

Mã thư viện mẫu:

// 全局变量
var keyName_label = "label"
var keyName_robotId = "robotId"
var keyName_extendAccessKey = "extendAccessKey"
var keyName_extendSecretKey = "extendSecretKey"
var fmzExtendApis = parseConfigs([config1, config2, config3, config4, config5])
var mapInitRefPosAmount = {}

function parseConfigs(configs) {
    var arr = []
    _.each(configs, function(config) {
        if (config == "") {
            return 
        }
        var strArr = config.split(",")
        if (strArr.length != 4) {
            throw "configs error!"
        }
        var obj = {}
        obj[keyName_label] = strArr[0]
        obj[keyName_robotId] = strArr[1]
        obj[keyName_extendAccessKey] = strArr[2]
        obj[keyName_extendSecretKey] = strArr[3]
        arr.push(obj)
    })
    return arr 
}

function getPosAmount(pos, ct) {
    var longPosAmount = 0
    var shortPosAmount = 0
    _.each(pos, function(ele) {
        if (ele.ContractType == ct && ele.Type == PD_LONG) {
            longPosAmount = ele.Amount
        } else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
            shortPosAmount = ele.Amount
        }
    })
    var timestamp = new Date().getTime()
    return {ts: timestamp, long: longPosAmount, short: shortPosAmount}
}

function sendCommandRobotMsg (robotId, accessKey, secretKey, msg) {
    // https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
    var url = "https://www.fmz.com/api/v1?access_key=" + accessKey + "&secret_key=" + secretKey + "&method=CommandRobot&args=[" + robotId + ',"' + msg + '"]'
    Log(url)
    var ret = HttpQuery(url)
    return ret 
}

function follow(nowPosAmount, symbol, ct, type, delta) {
    var msg = ""
    var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
    if (delta > 0) {
        // 开仓
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // 平仓
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("未检测到持仓")
            return 
        }
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "错误"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("调用CommandRobot接口,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // 判断ex类型
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "仅支持期货跟单"
    }

    if (exType == "futures") {
        // 缓存 symbol ct
        var buffSymbol = ex.GetCurrency()
        var buffCt = ex.GetContractType()

        // 切换到对应的交易对、合约代码
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // 监控持仓
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // 没有初始化数据,初始化          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // 监控
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // 计算仓位变动
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // 检测变动
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // 执行多头动作
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行多头跟单,变动量:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // 执行空头动作
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行空头跟单,变动量:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // 执行跟单操作后,更新
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // 恢复 symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // 现货
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "同步数据", 
        "cols" : [], 
        "rows" : []
    }
    // 构造表头
    tbl.cols.push("监控账户:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`监控持仓:{"时间戳":xxx,"多头持仓量":xxx,"空头持仓量":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // 写入数据
    _.each(mapInitRefPosAmount, function(initRefPosAmount, key) {
        var arr = [key, JSON.stringify(initRefPosAmount)]
        _.each(fmzExtendApis, function(extendApiData) {
            arr.push(extendApiData[keyName_robotId])
        })
        tbl.rows.push(arr)
    })

    return tbl
}

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Thiết kế rất đơn giản, thư viện này có hai chức năng.订单同步管理系统类库(Single Server)Sau thư viện lớp mẫu. Bạn có thể sử dụng hàm này.

  • $ PosMonitor Vai trò của chức năng này là giám sát sự thay đổi của đối tượng giao dịch trong chính sách, sau đó gửi tín hiệu giao dịch thực tế được thiết lập trong các tham số của Template:Order Synchronous Management System (Single Server).

  • $$.getTbl Các thông tin đồng bộ được giám sát sẽ được trả về.

Ví dụ sử dụng là: thư mục hệ thống quản lý đồng bộ đơn hàng (Single Server)mainTrong hàm:

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Một thư viện lớp mẫu tự nó cũng có thể tạo ra một ổ đĩa thực chính sách, thường được sử dụng để kiểm tra thư viện lớp mẫu. Ví dụ như kiểm tra mẫu. Bạn có thể hiểu trong mẫu.mainCác hàm là những chiến lược của bạn.mainChức năng.

Mã thử nghiệm được viết để thử nghiệm sử dụng OKEX analog disk, cần cấu hình API KEY của OKEX analog disk trên FMZ như một tài khoản tham khảo, bắt đầu chuyển đổi thành analog disk trong hàm main. Sau đó đặt cặp giao dịch thành ETH_USDT, đặt hợp đồng là vĩnh viễn (swap). Sau đó đi vào vòng lặp while.$.PosMonitor(0, "ETH_USDT", "swap")Các tham số đầu tiên được gọi cho chức năng này được truyền vào 0, biểu thị việc giám sát exchange[0] đối tượng giao dịch này, giám sát cặp giao dịch ETH_USDT, hợp đồng đổi; sau đó gọi$.getTbl()Thu thập thông tin biểu đồ, sử dụngLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")Để dữ liệu biểu đồ hiển thị trên thanh trạng thái.

Vì vậy, bạn thấy, chỉ cần sử dụng trong một số chính sách tham chiếu đến mẫu$.PosMonitor(0, "ETH_USDT", "swap")Trong khi đó, các chiến lược có thể có chức năng theo dõi một loại cổ phiếu, thay đổi cổ phiếu để đẩy thông báo.

Hãy giải thích trước khi thử.订单同步管理系统类库(Single Server)Thiết kế các tham số của chiến lược: Chúng tôi đã nói về cách sử dụng các chức năng giao diện của mẫu để nâng cấp một chính sách với chức năng băng. Câu hỏi gửi cho ai là do订单同步管理系统类库(Single Server)Các tham số của bạn sẽ được cấu hình.

img

Bạn có thể thấy 5 tham số, tối đa hỗ trợ 5 đẩy (cần thêm có thể tự mở rộng), tham số mặc định là một chuỗi trống, tức là không xử lý.

  • label Các thẻ của các tài khoản đồng bộ được sử dụng để đánh dấu một tài khoản và tên có thể được thiết lập tùy ý.

  • robotId ID đĩa thực, được tạo bởi chủ sở hữu của tài khoản đồng bộ订单同步管理系统(Synchronous Server)ID của ổ đĩa thực.

  • accessKey AccessKey cho FMZ API mở rộng

  • SecretKey SecretKey của FMZ extension API

Sau đó, chúng ta có thể làm một bài kiểm tra đơn giản.

Các thư viện hệ thống quản lý đồng bộ đơn hàng (Single Server) chạy trên ổ đĩa:

img

Một thông báo được nhận được trên ổ đĩa của hệ thống quản lý đơn hàng đồng bộ (Synchronous Server): Hiện tại, chúng tôi vẫn chưa hoàn thành thiết kế, chúng tôi đã thực hiện bằng một mã đơn giản, không thực hiện giao dịch, chỉ in tín hiệu:

Hệ thống quản lý đồng bộ đơn hàng (Synchronous Server) Mã tạm thời:

function main() {
    LogReset(1)
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            // cmd: ETH_USDT,swap,buy,1
            Log("cmd: ", cmd)
        }
        Sleep(1000)
    }
}

img

Bạn có thể thấy rằng máy tính của chủ sở hữu tài khoản đồng bộ đã nhận được thông báo:ETH_USDT,swap,buy,1‖ Sau đó, bạn có thể tự động theo dõi các cặp giao dịch, mã hợp đồng, hướng giao dịch và số lượng giao dịch trong thông tin.

Hiện tại订单同步管理系统(Synchronous Server)Chỉ là mã tạm thời, chúng ta sẽ tiếp tục nghiên cứu về thiết kế của nó trong bài viết tiếp theo.


Có liên quan

Thêm nữa

Mingxi1005Để thực hiện kế toán, bạn cần hai ổ đĩa, một ổ đĩa thư viện lớp và một ổ đĩa quản lý đơn đặt hàng.

Mingxi1005Làm theo hướng dẫn, hiển thị lỗi cấu hình

Alô.Các thông số cần thay đổi trong danh sách ngược

Alô.Bạn có thể sử dụng hai đĩa thực, một phát tín hiệu và một nhận tín hiệu, và cả hai đĩa thực được kết hợp với nhau không?

Giấc mơ nhỏBạn có thể không hiểu bài viết này, thư viện này là một công cụ có thể được nhúng trực tiếp vào dòng chính sách của người sử dụng và sau đó chính sách có chức năng liên kết, sẽ gửi thông báo đến tài khoản liên kết được thiết lập tốt, và bot sẽ nhận được thông báo liên kết. Một số người nói rằng, "Đó là một cảnh tượng rất đơn giản".

Giấc mơ nhỏBạn có thể xem bài viết, thông tin cấu hình: thẻ, đĩa thực ID, accesskey, secretkey.

Mingxi1005Trong thư mục hệ thống quản lý đồng bộ đơn hàng (Single Server), nhập cả hai ổ đĩa và 2 KEY, sau đó tham chiếu đến thư mục hệ thống quản lý đồng bộ đơn hàng (Single Server) trên ổ đĩa thực, báo lỗi, lỗi configs error!

Mingxi1005Nhầm configs error!

Giấc mơ nhỏNhững thông tin sai lệch trên mạng xã hội được đăng tải trên mạng xã hội.

Giấc mơ nhỏCác nhà lãnh đạo của các quốc gia khác cũng có thể tham gia vào cuộc họp.

Giấc mơ nhỏCó sẵn mã nguồn mở, bạn có thể thay đổi theo nhu cầu của mình, và bạn có thể thực hiện.