Reka bentuk Sistem Pengurusan Pemesanan Simultan Berasaskan Kuantiti FMZ (1)

Penulis:Mimpi kecil, Dicipta: 2022-02-14 19:46:30, Dikemas kini: 2023-09-15 20:44:11

img

Reka bentuk Sistem Pengurusan Pemesanan Simultan Berasaskan Kuantiti FMZ (1)

Dalam artikel-artikel lama kami di FMZ, kami telah merancang beberapa strategi pemesanan, simulasi simpanan dan pemasangan.

Ini adalah untuk meletakkan akaun rujukan dan akaun sinkronisasi dalam satu strategi untuk menguruskan pemasangan pesanan, simkronisasi simpanan. Hari ini kita akan mencuba reka bentuk yang sedikit berbeza, berdasarkan antara muka API lanjutan yang kuat untuk platform dagangan kuantitatif FMZ, kita akan merancang sistem pengurusan pesanan sinkronisasi.

Idea Reka Bentuk

Pertama sekali, kita perlu mempunyai beberapa cadangan yang baik, keperluan. Dua pesanan jangka masa lama di atas, strategi sinkronisasi simpanan mempunyai beberapa titik kesakitan yang jelas, mari kita bincangkan bersama:

  • 1. Pelaksana strategi simultan di tempat nyata mesti mempunyai API KEY bagi akaun rujukan, dan API KEY untuk akaun simultan. Masalahnya adalah: tidak mengapa jika akaun pertukaran lain anda mengikuti akaun anda sendiri. Tetapi ia akan menjadi masalah untuk akaun rujukan dan akaun sinkronisasi bukan satu pemilik. Pemilik akaun sinkronisasi kadang-kadang tidak bersedia untuk memberikan kunci API akaun pertukaran mereka sendiri atas alasan keselamatan. Tetapi bagaimana untuk mensinkronisasi transaksi tanpa menyediakan kunci API?

    Penyelesaian: Dengan menggunakan antara muka API lanjutan FMZ, pemilik akaun sinkronisasi (pengikut) hanya perlu mendaftar di platform dagangan kuantitatif FMZ dan kemudian menjalankan satu strategi (dalam sistem yang direka untuk artikel ini):订单同步管理系统(Synchronous Server)Dasar cakera sebenar); anda kemudian boleh memberikan ID cakera nyata kepada pemilik akaun rujukan (penerima) dengan FMZ's extension API KEY (catatan, bukan API KEY akaun bursa). Apabila merujuk kepada pemegang akaun (bandwidth) dalam sistem yang direka untuk artikel ini订单同步管理系统类库(Single Server)Jika anda menghantar isyarat, akaun simultan anda akan menerima isyarat dagangan, dan pesanan akan diteruskan secara automatik.

  • 2. Banyak pemaju mempunyai strategi yang lebih baik dan tidak dapat menggunakan dua pesanan masa depan yang dijelaskan di atas, strategi sinkronisasi simpanan; kerana itu memerlukan penggabungan strategi mereka dengan strategi sinkronisasi ini, yang mungkin memerlukan perubahan besar dan percubaan. Adakah ada cara yang baik untuk meningkatkan beberapa strategi lama mereka secara langsung ke sinkronisasi pesanan? Penyelesaian: Anda boleh merancang perpustakaan kelas templat sinkronisasi pesanan (dalam sistem yang direka untuk artikel ini)订单同步管理系统类库(Single Server)Strategi), membolehkan pemilik akaun rujukan (bander) menyematkan perpustakaan templat ini secara langsung ke dalam dasar mereka sendiri untuk mencapai fungsi pemesanan, simkronisasi simpanan.

  • 3. mengurangkan satu cakera sebenar tambahan. Titik kesakitan terakhir ialah jika anda menggunakan dua pesanan masa hadapan yang diterangkan di atas, anda memerlukan tambahan akaun pemantauan rujukan rak yang diperlukan untuk memegang akaun. Penyelesaian: Menggunakan perpustakaan template untuk menyematkan ciri-ciri dalam dasar akaun rujukan.

Oleh itu, sistem ini terdiri daripada dua bahagian: 1, Perpustakaan sistem pengurusan sinkronisasi pesanan (Single Server) 2, Sistem Pengurusan Penghantaran Bersekitar (Synchronous Server)

Jika anda tahu apa yang anda perlukan, mulalah merancang.

Reka bentuk 1: Perpustakaan Kelas Sistem Pengurusan Simulasi Perintah (Single Server)

Perhatikan bahawa ini bukan satu strategi. Ini adalah perpustakaan templat FMZ. Konsep perpustakaan templat boleh dicari di dalam dokumen API FMZ.

Kod perpustakaan template:

// 全局变量
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)
    }
}

Perpustakaan ini mempunyai dua fungsi fungsi yang sangat mudah.订单同步管理系统类库(Single Server)Selepas perpustakaan kelas templat. Kaedah ini boleh digunakan dengan fungsi berikut.

  • $. PosMonitor Fungsi ini berfungsi untuk memantau perubahan saham objek bursa dalam dasar, dan kemudian menghantar isyarat dagangan pada piringan sebenar yang ditetapkan dalam parameter Template:Order Synchronous Management System (Single Server).

  • $.getTbl Mengembalikan data sinkronisasi yang dipantau.

Contoh penggunaan ialah: Perpustakaan Kelas Sistem Pengurusan Simulasi Pemesanan (template Single Server)mainFungsi:

// 引用该模板类库的策略调用范例
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)
    }
}

Sebuah perpustakaan kelas templat sendiri juga boleh membuat rak rak politik, yang biasanya digunakan untuk menguji perpustakaan kelas templat; contohnya, ujian untuk templat tersebut. Anda boleh memahami apa yang terdapat dalam templat.mainFungsi adalah strategi anda sendiri.mainFungsi tersebut.

Kod ujian ditulis untuk menguji menggunakan OKEX analog disk, yang memerlukan konfigurasi API KEY OKEX analog disk di FMZ sebagai akaun rujukan (band), mula beralih ke analog disk dalam fungsi utama; kemudian menetapkan pasangan dagangan sebagai ETH_USDT, yang menetapkan kontrak sebagai kekal (swap); kemudian masuk ke dalam lingkaran sementara; perdagangan di bawah pesanan dilakukan setiap 3 minit dalam lingkaran, yang digunakan untuk mencetuskan perdagangan strategi analog; sementara dalam lingkaran dipanggil.$.PosMonitor(0, "ETH_USDT", "swap"), parameter pertama yang dipanggil untuk fungsi ini adalah 0 yang menunjukkan pemantauan pertukaran[0] objek pertukaran ini, pemantauan pasangan dagangan ETH_USDT, kontrak swap; kemudian dipanggil$.getTbl()Mengambil maklumat carta, menggunakannyaLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")Membuat data carta dipaparkan pada tetingkap status.

Jadi anda lihat, jika anda menggunakan strategi yang merujuk kepada templat ini$.PosMonitor(0, "ETH_USDT", "swap")Dengan cara ini, anda boleh membuat strategi yang mempunyai fungsi untuk memantau pegangan jenis tertentu, perubahan pegangan untuk memajukan mesej.

Beritahu saya sebelum ujian.订单同步管理系统类库(Single Server)Perancangan parameter strategi: Saya baru sahaja membincangkan bagaimana menggunakan fungsi antara muka templat untuk menaik taraf satu dasar dengan fungsi jalur; jadi, kepada siapa isyarat yang dihantar apabila saham berubah? Soalan kepada siapa untuk dihantar adalah soalan yang sama.订单同步管理系统类库(Single Server)Parameter yang digunakan untuk mengkonfigurasi.

img

Terdapat 5 parameter yang boleh dilihat, yang paling banyak menyokong 5 push (boleh diperluaskan sendiri jika perlu ditambah), parameter lalai adalah strings kosong, iaitu tidak diuruskan. Format string konfigurasi: label, robotId, accessKey, secretKey

  • label Tag akaun sinkronisasi, digunakan untuk memberi tanda kepada akaun tertentu, nama boleh ditetapkan dengan mudah.

  • robotId ID cakera, dicipta oleh pemilik akaun sinkronisasi订单同步管理系统(Synchronous Server)ID cakera sebenar.

  • AccessKey AccessKey untuk API lanjutan FMZ

  • Kunci rahsia SecretKey untuk API FMZ

Selepas itu, kita boleh melakukan ujian mudah.

Perpustakaan Kelas Sistem Pengurusan Simulasi Perintah (Single Server) berjalan di:

img

Sistem Pengurusan Pemesanan Sinkron (Synchronous Server) menerima isyarat: Sistem Pengurusan Pemesanan Bersinkron (Synchronous Server) Kami belum merancang sepenuhnya, kami mulakan dengan kod yang mudah, tidak melakukan transaksi, hanya mencetak isyarat:

Kod sementara Sistem Pengurusan Simkron pesanan (Synchronous Server):

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

img

Di sini, anda boleh melihat bahawa akaun sinkronisasi telah menerima mesej di cakera keras:ETH_USDT,swap,buy,1Saya tidak tahu. Dengan cara ini, anda boleh membuat senarai automatik anda sendiri berdasarkan pasangan dagangan, kod kontrak, arah dagangan, dan kuantiti dalam maklumat.

Pada masa ini订单同步管理系统(Synchronous Server)Ini hanya kod sementara, dan kami akan terus menerusi reka bentuknya dalam edisi seterusnya.


Berkaitan

Lebih lanjut

Mingxi1005Untuk mewujudkan senarai, anda memerlukan dua cakera, satu adalah cakera perpustakaan kelas dan satu adalah cakera sistem pengurusan pesanan.

Mingxi1005Dibuat mengikut tutorial, menunjukkan kesalahan konfigurasi

AllahParameter mana yang perlu diubah dalam senarai pemandu balik

AllahJika anda mempunyai dua cakera, satu untuk menghantar isyarat dan satu untuk menerima isyarat, bolehkah kedua-dua itu digabungkan?

Mimpi kecilMungkin anda tidak faham artikel ini, perpustakaan ini adalah alat yang boleh disematkan secara langsung ke dalam baris dasar pembekal, dan kemudian dasar ini mempunyai fungsi pembekal, ia akan menghantar mesej kepada akaun pembekal yang disiapkan dengan baik, dan bot akan menerima mesej pembekal. Dalam kes ini, ia adalah satu-satunya cara yang boleh digunakan untuk membetulkan keadaan.

Mimpi kecilAnda boleh melihat artikel ini, maklumat konfigurasi: tag, ID cakera sebenar, akseskey, secretkey.

Mingxi1005Kesalahan configs error!, di dalam perpustakaan sistem pengurusan sinkronisasi pesanan (Single Server), memasukkan kedua-dua cakera dan 2 KEY, dan kemudian merujuk ke perpustakaan sistem pengurusan sinkronisasi pesanan (Single Server) di dalam cakera, memberikan kesalahan, kesalahan configs error!

Mingxi1005Kesilapan configs error!

Mimpi kecilUntuk melihat maklumat yang salah yang dilaporkan.

Mimpi kecilPeraturan baru perlu dibuat.

Mimpi kecilKodnya terbuka, anda boleh mengubahnya mengikut keperluan anda dan ia boleh dilaksanakan.