Sumber dimuat naik... memuat...

Penyelidikan penerimaan isyarat luaran platform FMZ: API yang diperluaskan vs strategi perkhidmatan HTTP terbina dalam

Penulis:Pencipta Kuantiti - Impian Kecil, Dicipta: 2024-12-12 18:33:26, Dikemas kini: 2024-12-16 09:15:23

img

Pengantar

Terdapat beberapa artikel dalam pustaka platform mengenai pairing webhook Trading View, yang membolehkan perdagangan yang didorong isyarat oleh sistem luar strategi ketika platform belum menyokong fungsi perkhidmatan HTTP terbina dalam bahasa JavaScript.CommandRobotSecara ringkasnya, adalah permintaan isyarat luar https/https yang dihantar ke platform FMZ, yang memindahkan isyarat sebagai pemberitahuan mesej interaksi dasar kepada program dasar.

Dengan perkembangan, pengulangan, dan peningkatan platform, terdapat banyak fungsi baru yang diperbaharui; menerima isyarat luaran juga mempunyai pilihan baru; pelbagai pilihan mempunyai kelebihan masing-masing, dan kami akan meneroka topik ini bersama-sama.

Peningkatan API menggunakan platform FMZ

Dengan menggunakan cara ini untuk menghubungkan sistem luaran, kelebihan adalah yang lebih mudah, lebih selamat, dan API yang bergantung kepada platform yang lebih stabil.

Proses menerima isyarat luar:

Sistem luaran (Trading View webhook) > Perkhidmatan API FMZ yang diperluaskan > Dasar Dasar

1. Sistem luaran (Trading View webhook): Contohnya skrip PINE yang berjalan di Trading View, boleh menetapkan amaran yang akan menghantar permintaan http ke alamat url webhook yang ditetapkan sebagai isyarat apabila dicetuskan. 2, FMZ Extension API Service: Setelah mengakses antara muka ini dengan berjaya, platform menghantar mesej, yang dihantar ke cakera dasar sebagai mesej interaksi. 3. Disk sebenar dasar: Dalam cakera sebenar dasar, fungsi GetCommand boleh direka untuk mendengar mesej interaksi, dan melakukan tindakan yang ditetapkan selepas mengesan mesej.

Perbandingan dengan menggunakan perkhidmatan HTTP terbina dalam untuk mencipta isyarat penerimaan perkhidmatan secara langsung, ia adalah satu langkah di tengah-tengah (menukar platform).

Dasar Perkhidmatan Http terbina dalam

Platform ini menyokong fungsi perkhidmatan Http terbina dalam bahasa JavaScript, yang membolehkan anda membuat isyarat luar yang didengar secara serentak. Kelebihannya ialah: perkhidmatan Http yang dibuat adalah utas berasingan dan tidak mempengaruhi logik fungsi utama, dapat mendengar mesej seperti fungsi GetCommand, dan mendengar isyarat luar secara langsung, berbanding dengan menggunakan program API lanjutan, yang mengecualikan putaran tengah.

Proses menerima isyarat luar:

Sistem luaran (Trading View webhook)

1. Sistem luaran (Trading View webhook): Contohnya skrip PINE yang berjalan di Trading View, boleh menetapkan amaran yang akan menghantar permintaan http ke alamat url webhook yang ditetapkan sebagai isyarat apabila dipicu. 2, Dasar rak: Dasar yang disatukan untuk menjalankan perkhidmatan HTTP dan menerima isyarat luar secara langsung.

Ini menghemat satu langkah, tetapi untuk meningkatkan keselamatan, adalah lebih baik untuk mengkonfigurasi perkhidmatan https, yang memerlukan lipatan; berbanding dengan program yang menggunakan API lanjutan.

Kode Ujian

Untuk menguji kedua-dua program, polis berikut akan berputar dan menghantar 10 permintaan HTTP/Https setiap pusingan untuk meniru isyarat luaran. Kemudian polis akan mendengar "pesan interaksi" dan "pesan yang disuntik oleh benang perkhidmatan HTTP". Kemudian polis akan mencocokkan isyarat luaran dengan isyarat yang diterima, mengesan apakah ada kehilangan isyarat, dan mengira 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 ujian, anda perlu mengisi alamat IP pelayan tertentu, dan FMZ platform perlu menambah API KEY.

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

1, fungsi serverFunc mencipta perkhidmatan HTTP serentak untuk mendengar isyarat luaran. Untuk mesej luaran yang diterima oleh antarmuka API yang diperluaskan, fungsi GetCommand digunakan untuk mendengar.

  • Berita yang dihantar oleh thread perkhidmatan https: Olehvar msg = threading.mainThread().peekMessage(-1)Perhatikan.

  • Mesej interaktif yang dihantar melalui antarmuka API lanjutan: Olehvar cmd = GetCommand()Perhatikan.

2, Proses menghantar isyarat dan menerima isyarat adalah bebas hambatan, platform mengoptimumkan mekanisme pemulihan sumber pelbagai benang di bawah untukThreadatauexchange.GoFungsi simultan, tanpa perlu lagi menunggu tugas simultan selesai (seperti fungsi join, fungsi tunggu, dan lain-lain), lapisan bawah sistem akan memproses pemulihan sumber secara automatik (hanya memerlukan sokongan hos versi terkini).

    // 摘录代码片段,发送信号
    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,非阻塞

Di sini, kita akan melihat proses ujian yang menunjukkan bahawa maklumat itu dicatatkan secara langsung 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)
    }
}

Hasil ujian

img

img

Dengan ujian jangka masa, kita dapat melihat bahawa Http mengambil masa sedikit lebih singkat berbanding API.

Strategi dalaman perkhidmatan HTTP menerima isyarat, kaedah ujian ini tidak sangat ketat, permintaan harus berasal dari luar. Untuk pemahaman yang mudah, anda boleh mengabaikan faktor ini. Untuk kedua-dua cara pengambilan isyarat, strategi perkhidmatan HTTP terbina dalaman mengurangkan satu pautan, selepas semua, ia harus menjadi sedikit lebih cepat. Untuk kestabilan isyarat, yang lebih penting adalah isyarat tidak boleh hilang atau terlepas. Hasil ujian dapat melihat bahawa API pengembangan platform FMZ juga stabil, tidak melihat kehilangan isyarat dalam ujian, tetapi tidak mengecualikan pelbagai aspek rangkaian seperti faktor yang menyebabkan masalah isyarat, menggunakan perkhidmatan HTTP terbina dalam untuk menerima isyarat luar secara langsung juga merupakan penyelesaian yang lebih baik.

Dalam artikel ini, perkhidmatan HTTP terbina dalam kod teks tidak diperiksa, dan hanya menerima data mesej yang mudah, di artikel seterusnya, kami menyempurnakan template perkhidmatan HTTP terbina dalam yang boleh digunakan untuk menerima isyarat Trading View luaran, selamat berbincang, terima kasih kerana membaca.


Lebih lanjut