4
ফোকাস
1271
অনুসারী

FMZ প্ল্যাটফর্মের বাহ্যিক সংকেত অভ্যর্থনা নিয়ে আলোচনা: বর্ধিত API বনাম কৌশল অন্তর্নির্মিত HTTP পরিষেবা

তৈরি: 2024-12-12 18:33:26, আপডেট করা হয়েছে: 2025-05-16 15:53:52
comments   0
hits   583

FMZ প্ল্যাটফর্মের বাহ্যিক সংকেত অভ্যর্থনা নিয়ে আলোচনা: বর্ধিত API বনাম কৌশল অন্তর্নির্মিত HTTP পরিষেবা

ভূমিকা

প্ল্যাটফর্ম লাইব্রেরিতে ট্রেডিং ভিউ ওয়েবহুকের সাথে সংযোগ স্থাপন সম্পর্কে বেশ কয়েকটি নিবন্ধ ছিল, যা বহিরাগত সিস্টেম থেকে প্রাপ্ত সংকেতের উপর ভিত্তি করে কৌশলগুলি ট্রেড চালানোর অনুমতি দেয়। সেই সময়ে, প্ল্যাটফর্মটিতে জাভাস্ক্রিপ্ট ভাষা সমর্থনকারী কোনও অন্তর্নির্মিত HTTP পরিষেবা ফাংশন ছিল না। প্ল্যাটফর্মের বর্ধিত API ইন্টারফেস ব্যবহার করা হয়েছে:CommandRobot, সহজভাবে বলতে গেলে, বাহ্যিক সংকেতের http/https অনুরোধটি FMZ প্ল্যাটফর্মে পাঠানো হয়, এবং প্ল্যাটফর্মটি সংকেত স্থানান্তর করে এবং একটি নীতি মিথস্ক্রিয়া বার্তা হিসাবে নীতি প্রোগ্রামকে অবহিত করে।

প্ল্যাটফর্মের বিকাশ এবং পুনরাবৃত্তির সাথে, অনেক নতুন ফাংশন আপগ্রেড এবং আপডেট করা হয়েছে। বাহ্যিক সংকেত গ্রহণের জন্য নতুন সমাধানও রয়েছে। প্রতিটি সমাধানের নিজস্ব সুবিধা রয়েছে এই নিবন্ধে, আমরা এই বিষয়ে একসাথে আলোচনা করব।

FMZ প্ল্যাটফর্ম ব্যবহার করে API ইন্টারফেস প্রসারিত করুন

বাহ্যিক সিস্টেমগুলিকে সংযুক্ত করার জন্য এই পদ্ধতিটি ব্যবহার করার সুবিধাগুলি হল এটি তুলনামূলকভাবে সহজ, অত্যন্ত সুরক্ষিত এবং প্ল্যাটফর্ম-নির্ভর বর্ধিত API ইন্টারফেসের উপর ভিত্তি করে উচ্চ স্থিতিশীলতা রয়েছে।

বাহ্যিক সংকেত প্রাপ্তির প্রক্রিয়া:

বাহ্যিক সিস্টেম (ট্রেডিং ভিউ ওয়েবহুক) –> FMZ বর্ধিত API পরিষেবা –> কৌশল বাস্তব অফার

  1. বাহ্যিক সিস্টেম (ট্রেডিং ভিউ ওয়েবহুক): উদাহরণস্বরূপ, ট্রেডিং ভিউতে চলমান PINE স্ক্রিপ্ট একটি অ্যালার্ম সেট করতে পারে যখন ট্রিগার করা হয়, একটি সংকেত হিসাবে সেট ওয়েবহুক url ঠিকানায় একটি HTTP অনুরোধ পাঠানো হবে৷
  2. FMZ বর্ধিত API পরিষেবা: এই ইন্টারফেসটি সফলভাবে অ্যাক্সেস করার পরে, প্ল্যাটফর্ম তথ্য ফরোয়ার্ড করে এবং একটি ইন্টারেক্টিভ বার্তা হিসাবে কৌশল সংস্থার কাছে পাঠায়।
  3. কৌশল বাস্তবায়ন: কৌশল বাস্তবায়নে, GetCommand ফাংশনটি ইন্টারেক্টিভ বার্তাগুলি নিরীক্ষণ করার জন্য এবং বার্তা সনাক্ত করার পরে পূর্বনির্ধারিত ক্রিয়াকলাপ সম্পাদন করার জন্য ডিজাইন করা যেতে পারে।

সিগন্যাল পাওয়ার জন্য সরাসরি একটি পরিষেবা তৈরি করতে অন্তর্নির্মিত Http পরিষেবা ব্যবহার করার তুলনায়, মাঝখানে একটি অতিরিক্ত পদক্ষেপ (প্ল্যাটফর্ম স্থানান্তর) রয়েছে।

নীতি অন্তর্নির্মিত HTTP পরিষেবা

প্ল্যাটফর্মটি জাভাস্ক্রিপ্ট ভাষার অন্তর্নির্মিত Http পরিষেবা ফাংশন সমর্থন করার পরে, আপনি বহিরাগত সংকেত নিরীক্ষণের জন্য সরাসরি একটি সমবর্তী পরিষেবা তৈরি করতে পারেন। সুবিধা হল: তৈরি করা Http পরিষেবা একটি পৃথক থ্রেড এবং এটি মূল ফাংশন লজিককে প্রভাবিত করে না এটি GetCommand ফাংশনের মতো বার্তাগুলিকে নিরীক্ষণ করতে পারে এবং বর্ধিত API সলিউশন ব্যবহার করার সাথে তুলনা করে, ট্রানজিট লিঙ্কটি বাদ দেওয়া হয়৷

বাহ্যিক সংকেত প্রাপ্তির প্রক্রিয়া:

বাহ্যিক সিস্টেম (ট্রেডিং ভিউ ওয়েবহুক) –> কৌশল বাস্তব অফার

  1. বাহ্যিক সিস্টেম (ট্রেডিং ভিউ ওয়েবহুক): উদাহরণস্বরূপ, ট্রেডিং ভিউতে চলমান PINE স্ক্রিপ্ট একটি অ্যালার্ম সেট করতে পারে যখন ট্রিগার করা হয়, একটি সংকেত হিসাবে সেট ওয়েবহুক url ঠিকানায় একটি HTTP অনুরোধ পাঠানো হবে৷
  2. কৌশল বাস্তবায়ন: কৌশলটি একযোগে একটি HTTP পরিষেবা চালায় এবং সরাসরি বাহ্যিক সংকেত গ্রহণ করে।

এই সমাধানটি একটি পদক্ষেপ সংরক্ষণ করে, কিন্তু নিরাপত্তা উন্নত করার জন্য, https পরিষেবা কনফিগার করা সর্বোত্তম, যার জন্য কিছু ফিডলিং প্রয়োজন। এক্সটেনশন API ব্যবহার করে সমাধানের সাথে তুলনা করলে, এটি একটু বেশি ঝামেলাপূর্ণ।

পরীক্ষার কোড

দুটি সমাধান পরীক্ষা করুন নিম্নলিখিত কৌশলটি বহিরাগত সংকেত অনুকরণ করতে প্রতিটি চক্রে একই সাথে 10টি HTTP/Https অনুরোধ পাঠাবে৷ তারপর কৌশলটি “ইন্টারেক্টিভ মেসেজ” এবং “এইচটিটিপি সার্ভিস থ্রেড দ্বারা পুশ করা বার্তা” নিরীক্ষণ করে। তারপর নীতি প্রোগ্রাম বহিরাগত সংকেত বার্তা এবং প্রাপ্ত সংকেত এক এক করে মেলে, সংকেত ক্ষতি হয়েছে কিনা তা সনাক্ত করে, এবং গণনা সময়সাপেক্ষ।

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)
    }
}

পরীক্ষার হলে, আপনাকে নির্দিষ্ট সার্ভারের IP ঠিকানা এবং FMZ প্ল্যাটফর্মের বর্ধিত API KEY পূরণ করতে হবে।

var httpUrl = "http://123.123.123.123:8088/CommandRobot"
var accessKey = "xxx"
var secretKey = "xxx"
  1. সার্ভারফাঙ্ক ফাংশন বহিরাগত সংকেত নিরীক্ষণের জন্য একটি সমবর্তী HTTP পরিষেবা তৈরি করে। বর্ধিত API ইন্টারফেস দ্বারা প্রাপ্ত বহিরাগত বার্তাগুলির জন্য, GetCommand ফাংশন শোনার জন্য ব্যবহৃত হয়।
  • Http পরিষেবা থ্রেড দ্বারা পুশ করা বার্তা: নির্ভর করেvar msg = threading.mainThread().peekMessage(-1)মনিটর

  • বর্ধিত API ইন্টারফেস দ্বারা ফরোয়ার্ড মিথস্ক্রিয়া বার্তা: নির্ভর করেvar cmd = GetCommand()মনিটর

  1. সিগন্যাল পাঠানো এবং গ্রহণ করার প্রক্রিয়াটি অ-ব্লকিং।Threadঅথবাexchange.Goসমসাময়িক ফাংশনগুলির সাথে, আপনাকে আর সমসাময়িক কাজগুলি সম্পূর্ণ করার জন্য স্পষ্টভাবে অপেক্ষা করতে হবে না (যেমন যোগদান ফাংশন, অপেক্ষা ফাংশন, ইত্যাদি) সিস্টেমের নীচের স্তরটি স্বয়ংক্রিয়ভাবে রিসোর্স রিসাইক্লিং পরিচালনা করবে (সমর্থনের জন্য হোস্টের সর্বশেষ সংস্করণ প্রয়োজন)৷ এটা)।
    // 摘录代码片段,发送信号
    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,非阻塞

এর পরে, আসুন এই পরীক্ষার প্রক্রিয়াটি দেখে নেওয়া যাক বিবরণের তথ্য সরাসরি কোডে টীকা করা হয়েছে:

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)
    }
}

পরীক্ষার ফলাফল

FMZ প্ল্যাটফর্মের বাহ্যিক সংকেত অভ্যর্থনা নিয়ে আলোচনা: বর্ধিত API বনাম কৌশল অন্তর্নির্মিত HTTP পরিষেবা

FMZ প্ল্যাটফর্মের বাহ্যিক সংকেত অভ্যর্থনা নিয়ে আলোচনা: বর্ধিত API বনাম কৌশল অন্তর্নির্মিত HTTP পরিষেবা

পরীক্ষার সময়কালের মাধ্যমে, এটি লক্ষ্য করা যায় যে HTTP পদ্ধতিটি API পদ্ধতির তুলনায় গড়ে কম সময় নেয়।

কৌশলে অন্তর্নির্মিত Http পরিষেবাটি সংকেত গ্রহণ করে এই পরীক্ষার পদ্ধতিটি খুব কঠোর নয় এবং অনুরোধটি বাইরে থেকে আসা উচিত। বোঝার সরলতার জন্য, এই ফ্যাক্টরটি উপেক্ষা করা যেতে পারে। সিগন্যাল অধিগ্রহণের দুটি পদ্ধতির জন্য, কৌশলটির অন্তর্নির্মিত HTTP পরিষেবা সর্বোপরি একটি লিঙ্ক কমিয়ে দেয় এবং প্রতিক্রিয়ার গতি দ্রুত হওয়া উচিত। সংকেত স্থিতিশীলতার জন্য, এটি আরও গুরুত্বপূর্ণ যে সংকেতটি হারিয়ে বা মিস করা যাবে না। পরীক্ষার ফলাফল থেকে দেখা যায়, এফএমজেড প্ল্যাটফর্মের বর্ধিত এপিআইও স্থিতিশীল ছিল, তবে, এটিকে অস্বীকার করা যায় না যে নেটওয়ার্ক এবং অন্যান্য কারণগুলিও ভাল সরাসরি বাহ্যিক সংকেত পেতে অন্তর্নির্মিত Http পরিষেবা ব্যবহার করতে।

এই নিবন্ধটি বিষয়ের একটি ভূমিকা যা নিবন্ধে কোডের অন্তর্নির্মিত এইচটিটিপি পরিষেবাটি যাচাই করে না এবং কেবলমাত্র পরবর্তী নিবন্ধে, আমরা বিল্ট-ইন এইচটিটিপি পরিষেবার জন্য একটি টেমপ্লেট সম্পূর্ণরূপে প্রয়োগ করব৷ বাহ্যিক ট্রেডিং ভিউ সিগন্যাল পেতে, পড়ার জন্য ধন্যবাদ।