Sumber daya yang dimuat... Pemuatan...

FMZ Platform Eksternal Signal Reception: Extension API vs Strategi Layanan HTTP Terbentuk

Penulis:Penemu Kuantitas - Mimpi Kecil, Dibuat: 2024-12-12 18:33:26, Diperbarui: 2024-12-16 09:15:23

img

Pengantar

Ada beberapa artikel di pustaka platform tentang pairing webhook Trading View, yang memungkinkan perdagangan yang didorong sinyal dari sistem luar strategi, ketika platform belum mendukung fungsi layanan HTTP bawaan bahasa JavaScript.CommandRobotDengan kata lain, permintaan sinyal eksternal https/https dikirim ke platform FMZ, yang memindahkan sinyalnya ke program strategi sebagai pemberitahuan pesan interaktif.

Dengan perkembangan, iterasi, dan peningkatan platform, banyak fitur baru yang diperbarui. Penerimaan sinyal eksternal juga memiliki pilihan baru. Semua pilihan memiliki kelebihan masing-masing, dan kita akan membahas topik ini bersama-sama.

Menggunakan platform FMZ untuk memperluas API

Dengan menggunakan cara ini untuk menghubungkan sistem eksternal, keuntungan adalah relatif sederhana, keamanan yang kuat, dan platform-dependent API yang dapat diperluas antarmuka stabilitas tinggi.

Proses penerimaan sinyal eksternal:

Sistem eksternal (Trading View webhook) > FMZ Extended API Service > Strategi real disk

Sistem eksternal (Trading View webhook): misalnya, skrip PINE yang berjalan di Trading View dapat mengatur alarm, yang setelah dipicu akan mengirim permintaan http ke alamat url webhook yang ditetapkan, sebagai sinyal. 2, FMZ Extension API Service: Setelah mengakses antarmuka ini dengan sukses, platform akan mengirimkan informasi, yang akan dikirim sebagai pesan interaktif ke policy real disk. 3. Disk Politik: Dalam Disk Politik, fungsi GetCommand dapat dirancang untuk mendengarkan pesan interaktif, mendeteksi pesan dan melakukan operasi yang ditetapkan.

Ini adalah langkah di tengah (pergeseran platform) dibandingkan dengan menggunakan layanan Http built-in untuk membuat sinyal penerimaan layanan secara langsung.

Kebijakan layanan HTTP bawaan

Setelah platform mendukung fungsi layanan Http built-in dari bahasa JavaScript, Anda dapat langsung membuat sinyal luar untuk mendengarkan layanan paralel. Keuntungan adalah: layanan Http yang dibuat adalah thread terpisah, dan tidak mempengaruhi logika fungsi utama, dapat mendengarkan pesan seperti fungsi GetCommand, dan mendengarkan sinyal eksternal secara langsung, dibandingkan dengan menggunakan program API ekstensi, menghilangkan putaran tengah.

Proses penerimaan sinyal eksternal:

Sistem eksternal (Trading View webhook)

Sistem eksternal (Trading View webhook): Misalnya, skrip PINE yang berjalan di Trading View dapat mengatur alarm, yang setelah dipicu akan mengirim permintaan http ke alamat url webhook yang ditetapkan, sebagai sinyal. 2, kebijakan real disk: Kebijakan paralel menjalankan layanan HTTP, menerima sinyal eksternal secara langsung.

Perangkat lunak ini menghemat langkah, tetapi untuk meningkatkan keamanan, sebaiknya mengkonfigurasi layanan https, yang perlu dilipat; dibandingkan dengan program yang menggunakan API ekstensi.

Kode pengujian

Untuk menguji dua program, kebijakan berikut akan berputar dan mengirim 10 permintaan HTTP/Https per putaran untuk meniru sinyal eksternal. Kemudian kebijakan akan mendengarkan "pesan interaktif" dan "pesan yang didorong oleh thread layanan HTTP". Kemudian kebijakan akan mencocokkan pesan sinyal eksternal satu per satu dengan sinyal yang diterima, mendeteksi apakah ada hilangnya sinyal, dan menghitung waktu.

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 diuji, Anda harus mengisi alamat IP server tertentu, yang merupakan ekstensi API KEY dari platform FMZ.

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

Fungsi serverFunc membuat layanan HTTP paralel untuk mendengarkan sinyal eksternal. Untuk pesan eksternal yang diterima oleh antarmuka API ekstensi, fungsi GetCommand digunakan untuk mendengarkan.

  • Pemberitahuan yang dikirim melalui thread https: olehvar msg = threading.mainThread().peekMessage(-1)Perhatikan.

  • Pesan interaktif yang diteruskan melalui antarmuka API ekstensi: olehvar cmd = GetCommand()Perhatikan.

2. Proses mengirim dan menerima sinyal tidak terhambat, dan platform mengoptimalkan mekanisme pengambilan sumber daya multi-threaded di bawahnya untukThreadAtauexchange.GoFungsi simultan, tanpa perlu lagi secara eksplisit menunggu tugas simultan selesai (misalnya fungsi join, fungsi wait, dll.)

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

Berikut ini adalah proses pengujian yang menunjukkan bahwa informasi itu langsung dicatat dalam kode:

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 tes

img

img

Dengan pengujian jangka panjang, kita dapat melihat bahwa HTTP hanya membutuhkan waktu yang sedikit lebih singkat dari rata-rata API.

Untuk kedua metode pengambilan sinyal, strategi built-in https layanan menerima sinyal, metode pengujian ini tidak sangat ketat, permintaan harus berasal dari luar. Untuk pemahaman yang sederhana, dapat mengabaikan faktor ini. Untuk kedua metode pengambilan sinyal, strategi built-in https layanan setelah semua mengurangi satu link, seharusnya kecepatan respons sedikit lebih cepat. Untuk stabilitas sinyal, yang lebih penting adalah sinyal tidak hilang atau terlewatkan. Hasil pengujian dapat dilihat bahwa FMZ platform ekstensi API juga stabil, tidak melihat kehilangan sinyal dalam pengujian, tetapi tidak menyingkirkan berbagai aspek jaringan seperti faktor yang menyebabkan masalah sinyal, menggunakan built-in https layanan untuk menerima sinyal eksternal langsung juga merupakan solusi yang lebih baik.

Dalam artikel ini, kita akan membahas tentang layanan HTTP bawaan yang tidak melakukan verifikasi, dan hanya menerima data pesan sederhana. Dalam artikel berikutnya, kita akan membahas tentang template layanan HTTP bawaan yang dapat digunakan untuk menerima sinyal Trading View eksternal.


Lebih banyak