avatar of 发明者量化-小小梦 发明者量化-小小梦
fokus pada mesej peribadi
4
fokus pada
1271
Pengikut

Perbincangan tentang penerimaan isyarat luaran platform FMZ: API lanjutan vs strategi perkhidmatan HTTP terbina dalam

Dicipta dalam: 2024-12-12 18:33:26, dikemas kini pada: 2025-05-16 15:53:52
comments   0
hits   583

Perbincangan tentang penerimaan isyarat luaran platform FMZ: API lanjutan vs strategi perkhidmatan HTTP terbina dalam

Mukadimah

Terdapat beberapa artikel dalam perpustakaan platform tentang menyambung ke webhooks Trading View, yang membenarkan strategi untuk memacu dagangan berdasarkan isyarat daripada sistem luaran Pada masa itu, platform tidak mempunyai fungsi perkhidmatan http terbina dalam yang menyokong bahasa JavaScript. Antara muka API lanjutan platform digunakan:CommandRobotRingkasnya, permintaan http/https isyarat luaran dihantar ke platform FMZ dan platform memajukan isyarat sebagai mesej interaksi strategi kepada program strategi.

Apabila platform berkembang dan berulang, banyak ciri baharu telah dinaik taraf dan dikemas kini. Terdapat juga penyelesaian baharu untuk menerima isyarat luaran. Setiap penyelesaian mempunyai kelebihan tersendiri Dalam artikel ini, kita akan membincangkan topik ini bersama-sama.

Gunakan platform FMZ untuk mengembangkan antara muka API

Kelebihan menggunakan kaedah ini untuk menyambung ke sistem luaran ialah ia agak mudah, sangat selamat dan bergantung pada kestabilan antara muka API lanjutan platform.

Proses menerima isyarat luaran:

Sistem luaran (Trading View webhook) –> Perkhidmatan API lanjutan FMZ –> Strategi pasaran sebenar

  1. Sistem luaran (webhook Trading View): Contohnya, skrip PINE yang berjalan pada Trading View boleh menetapkan penggera, yang akan menghantar permintaan http ke alamat url webhook yang ditetapkan sebagai isyarat apabila dicetuskan.
  2. Perkhidmatan API lanjutan FMZ: Selepas berjaya mengakses antara muka, platform memajukan maklumat dan menghantarnya ke pasaran sebenar strategi sebagai mesej interaktif.
  3. Pelaksanaan strategi: Dalam pelaksanaan strategi, anda boleh mereka bentuk fungsi GetCommand untuk mendengar mesej interaktif dan melaksanakan operasi yang ditentukan selepas mengesan mesej.

Berbanding dengan menggunakan perkhidmatan Http terbina dalam untuk terus mencipta perkhidmatan untuk menerima isyarat, terdapat langkah tambahan di tengah (pemindahan platform).

Perkhidmatan Http terbina dalam strategi

Selepas platform menyokong fungsi perkhidmatan Http terbina dalam bahasa JavaScript, anda boleh terus membuat perkhidmatan serentak untuk mendengar isyarat luaran. Kelebihannya ialah: perkhidmatan Http yang dibuat ialah benang yang berasingan dan tidak menjejaskan logik fungsi utama Ia boleh memantau mesej seperti fungsi GetCommand dan terus memantau isyarat luaran Berbanding dengan menggunakan penyelesaian API lanjutan, ia menghapuskan pautan pemindahan.

Proses menerima isyarat luaran:

Sistem luaran (Trading View webhook) –> Strategi perdagangan langsung

  1. Sistem luaran (webhook Trading View): Contohnya, skrip PINE yang berjalan pada Trading View boleh menetapkan penggera Apabila dicetuskan, ia akan menghantar permintaan http ke alamat url webhook yang ditetapkan sebagai isyarat.
  2. Pelaksanaan strategi: Strategi ini secara serentak menjalankan perkhidmatan Http untuk menerima isyarat luaran secara langsung.

Penyelesaian ini menjimatkan satu langkah, tetapi untuk meningkatkan keselamatan, adalah yang terbaik untuk mengkonfigurasi perkhidmatan https, yang memerlukan sedikit usaha. Ia sedikit lebih menyusahkan daripada menggunakan API lanjutan.

Kod ujian

Uji dua penyelesaian Strategi berikut akan menghantar 10 permintaan HTTP/HTTPS secara serentak dalam setiap kitaran untuk mensimulasikan isyarat luaran. Kemudian strategi memantau “mesej interaksi” dan “mesej yang ditolak oleh utas perkhidmatan Http”. Kemudian program strategi memadankan mesej isyarat luaran dengan isyarat yang diterima satu demi satu, mengesan sama ada terdapat kehilangan isyarat, dan mengira penggunaan masa.

var httpUrl = "http://123.123.123.123:8088/CommandRobot"
var accessKey = ""
var secretKey = ""

function serverFunc(ctx) {
    var path = ctx.path()
    if (path == "/CommandRobot") {
        var body = ctx.body()
        threading.mainThread().postMessage(body)
        ctx.write("OK")
        // 200
    } else {
        ctx.setStatus(404)
    }
}

function createMsgTester(accessKey, secretKey, httpUrl) {
    var tester = {}
    
    tester.currentRobotId = _G()
    tester.arrSendMsgByAPI = []
    tester.arrSendMsgByHttp = []
    tester.arrEchoMsgByAPI = []
    tester.arrEchoMsgByHttp = []
    tester.idByAPI = 0
    tester.idByHttp = 0

    var sendMsgByAPI = function(msgByAPI, robotId, accessKey, secretKey) {
        var headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
            "Content-Type": "application/json"
        }
        HttpQuery(`https://www.fmz.com/api/v1?access_key=${accessKey}&secret_key=${secretKey}&method=CommandRobot&args=[${robotId},+""]`, {"method": "POST", "body": JSON.stringify(msgByAPI), "headers": headers})
    }

    var sendMsgByHttp = function(msgByHttp, httpUrl) {
        HttpQuery(httpUrl, {"method": "POST", "body": JSON.stringify(msgByHttp)})
    }

    tester.run = function() {
        var robotId = tester.currentRobotId

        for (var i = 0; i < 10; i++) {
            var msgByAPI = {"ts": new Date().getTime(), "id": tester.idByAPI, "way": "ByAPI"}            
            tester.arrSendMsgByAPI.push(msgByAPI)
            tester.idByAPI++
            threading.Thread(sendMsgByAPI, msgByAPI, robotId, accessKey, secretKey)

            var msgByHttp = {"ts": new Date().getTime(), "id": tester.idByHttp, "way": "ByHttp"}
            tester.arrSendMsgByHttp.push(msgByHttp)
            tester.idByHttp++
            threading.Thread(sendMsgByHttp, msgByHttp, httpUrl)
        }
    }

    tester.getEcho =function(msg) {
        if (msg["way"] == "ByAPI") {
            tester.arrEchoMsgByAPI.push(msg)
        } else {
            tester.arrEchoMsgByHttp.push(msg)
        }
    }

    tester.deal = function() {
        var tbls = []
        for (var pair of [[tester.arrEchoMsgByHttp, tester.arrSendMsgByHttp, "ByHttp"], [tester.arrEchoMsgByAPI, tester.arrSendMsgByAPI, "ByAPI"]]) {
            var receivedMessages = pair[0]
            var sentMessages = pair[1]
            var testType = pair[2]

            var receivedMap = new Map()
            receivedMessages.forEach(message => {
                receivedMap.set(message["id"], message)
            })
            
            var matchedPairs = []
            var timeDifferences = []
            for (var sentMessage of sentMessages) {
                var receivedMessage = receivedMap.get(sentMessage["id"])
                if (receivedMessage) {
                    matchedPairs.push([JSON.stringify(sentMessage), JSON.stringify(receivedMessage), receivedMessage["ts"] - sentMessage["ts"]])
                    timeDifferences.push(receivedMessage["ts"] - sentMessage["ts"])
                } else {
                    Log("no matched sentMessage:", sentMessage, "#FF0000")
                }
            }
            
            var averageTimeDifference = timeDifferences.reduce((sum, diff) => sum + diff, 0) / timeDifferences.length
            
            var tbl = {
                "type": "table",
                "title": testType + " / averageTimeDifference:" + averageTimeDifference,
                "cols": ["send", "received", "ts diff"],
                "rows": []
            }

            for (var pair of matchedPairs) {
                tbl["rows"].push(pair)
            }

            tbls.push(tbl)
            Log(testType, ", averageTimeDifference:", averageTimeDifference, "ms")
        }

        tester.arrSendMsgByAPI = []
        tester.arrSendMsgByHttp = []
        tester.arrEchoMsgByAPI = []
        tester.arrEchoMsgByHttp = []

        return tbls
    }

    return tester
}

function main() {
    __Serve("http://0.0.0.0:8088", serverFunc)

    var t = createMsgTester(accessKey, secretKey, httpUrl)
    while (true) {
        Log("测试开始...", "#FF0000")
        t.run()

        var beginTS = new Date().getTime()
        while (new Date().getTime() - beginTS < 60 * 1000) {
            var cmd = GetCommand()
            if (cmd) {
                try {
                    var obj = JSON.parse(cmd)
                    obj["ts"] = new Date().getTime()
                    t.getEcho(obj)
                } catch (e) {
                    Log(e)
                }
            }
            
            var msg = threading.mainThread().peekMessage(-1)
            if (msg) {
                try {
                    var obj = JSON.parse(msg)
                    obj["ts"] = new Date().getTime()
                    t.getEcho(obj)                
                } catch (e) {
                    Log(e)
                }
            }
        }
        Log("等待结束...", "#FF0000")
                
        var tbls = t.deal()
        LogStatus(_D(), "\n`" + JSON.stringify(tbls) + "`")
        Sleep(20000)
    }
}

Jika menguji, anda perlu mengisi alamat IP pelayan khusus dan API KUNCI lanjutan platform FMZ.

var httpUrl = "http://123.123.123.123:8088/CommandRobot"
var accessKey = "xxx"
var secretKey = "xxx"
  1. Fungsi serverFunc mencipta perkhidmatan Http serentak untuk memantau isyarat luaran. Untuk mesej luaran yang diterima oleh antara muka API lanjutan, fungsi GetCommand digunakan untuk memantau.
  • Mesej yang ditolak oleh urutan perkhidmatan Http: Bergantung padavar msg = threading.mainThread().peekMessage(-1)pantau.

  • Mesej interaksi yang dimajukan oleh antara muka API lanjutan: Bergantung padavar cmd = GetCommand()pantau.

  1. Kedua-dua proses menghantar dan menerima isyarat tidak menyekat Platform ini mengoptimumkan mekanisme kitar semula sumber berbilang benang.Threadatauexchange.GoFungsi serentak tidak lagi perlu menunggu secara eksplisit tugas serentak selesai (seperti fungsi gabungan, fungsi tunggu, dll.), dan sistem asas akan mengendalikan kitar semula sumber secara automatik (memerlukan versi terbaharu hos untuk menyokong ini).
    // 摘录代码片段,发送信号
    tester.run = function() {
        var robotId = tester.currentRobotId

        for (var i = 0; i < 10; i++) {
            var msgByAPI = {"ts": new Date().getTime(), "id": tester.idByAPI, "way": "ByAPI"}            
            tester.arrSendMsgByAPI.push(msgByAPI)
            tester.idByAPI++
            threading.Thread(sendMsgByAPI, msgByAPI, robotId, accessKey, secretKey)   // 并发调用,非阻塞

            var msgByHttp = {"ts": new Date().getTime(), "id": tester.idByHttp, "way": "ByHttp"}
            tester.arrSendMsgByHttp.push(msgByHttp)
            tester.idByHttp++
            threading.Thread(sendMsgByHttp, msgByHttp, httpUrl)                       // 并发调用,非阻塞
        }
    }

    // 摘录代码片段,接收信号
    var cmd = GetCommand()                              // 监听来自扩展API的消息,非阻塞
    var msg = threading.mainThread().peekMessage(-1)    // 监听来自自建Http服务的消息,使用了参数-1,非阻塞

Seterusnya, mari kita lihat proses ujian ini, di mana maklumat dianotasi terus dalam kod:

function main() {
    __Serve("http://0.0.0.0:8088", serverFunc)      // 在当前策略实例中,创建一个并发的http服务

    var t = createMsgTester(accessKey, secretKey, httpUrl)   // 创建一个用于测试管理的对象
    while (true) {                                           // 策略主循环开始
        Log("测试开始...", "#FF0000")
        t.run()                                              // 每次循环开始,调用测试管理对象的run函数,使用两种方式(1、通过扩展API发送信号,2、直接向当前策略创建的Http服务发送信号),每种方式并发发送10个请求

        var beginTS = new Date().getTime()
        while (new Date().getTime() - beginTS < 60 * 1000) {   // 循环检测来自扩展API的交互消息,循环检测来自自建Http服务的消息
            var cmd = GetCommand()
            if (cmd) {
                try {
                    var obj = JSON.parse(cmd)
                    obj["ts"] = new Date().getTime()        // 检测到交互消息,记录消息,更新时间为收到时间
                    t.getEcho(obj)                          // 记录到对应数组
                } catch (e) {
                    Log(e)
                }
            }
            
            var msg = threading.mainThread().peekMessage(-1)
            if (msg) {
                try {
                    var obj = JSON.parse(msg)
                    obj["ts"] = new Date().getTime()        // 检测到自建的Http服务收到的消息,更新时间为收到时间
                    t.getEcho(obj)                          // ...
                } catch (e) {
                    Log(e)
                }
            }
        }
        Log("等待结束...", "#FF0000")
                
        var tbls = t.deal()                                  // 根据记录的消息,配对,检查是否有未配对的消息,如果有说明有信号丢失
        LogStatus(_D(), "\n`" + JSON.stringify(tbls) + "`")
        Sleep(20000)
    }
}

Keputusan Ujian

Perbincangan tentang penerimaan isyarat luaran platform FMZ: API lanjutan vs strategi perkhidmatan HTTP terbina dalam

Perbincangan tentang penerimaan isyarat luaran platform FMZ: API lanjutan vs strategi perkhidmatan HTTP terbina dalam

Selepas tempoh ujian, boleh diperhatikan bahawa kaedah Http mengambil masa yang lebih sedikit secara purata daripada kaedah API.

Strategi ini mempunyai perkhidmatan Http terbina dalam untuk menerima isyarat Kaedah ujian ini tidak begitu ketat dan permintaan harus datang dari luar. Demi kesederhanaan, faktor ini boleh diabaikan. Untuk kedua-dua kaedah pemerolehan isyarat, perkhidmatan Http terbina dalam strategi mengurangkan satu pautan selepas semua, dan sepatutnya mempunyai kelajuan tindak balas yang lebih pantas. Untuk kestabilan isyarat, adalah lebih penting bahawa isyarat tidak hilang atau terlepas. Keputusan ujian menunjukkan bahawa API lanjutan platform FMZ juga stabil Tiada kehilangan isyarat diperhatikan semasa ujian, tetapi tidak diketepikan bahawa pelbagai faktor seperti rangkaian boleh menyebabkan masalah isyarat Menggunakan perkhidmatan Http terbina dalam untuk terus menerima isyarat luaran juga merupakan cara yang lebih baik.

Artikel ini hanyalah titik permulaan Perkhidmatan Http terbina dalam dalam kod tidak disahkan dan hanya menerima data mesej Dalam artikel seterusnya, kami akan melaksanakan sepenuhnya templat perkhidmatan Http terbina dalam untuk menerima isyarat Trading View luaran. Selamat berbincang. Terima kasih kerana membaca.