উদ্ভাবকরা নতুন বৈশিষ্ট্য পরিমাপ করে: ব্যবহার করুন_সার্ভ ফাংশন সহজেই HTTP পরিষেবা তৈরি করে

তৈরি: 2024-11-12 22:10:49, আপডেট করা হয়েছে: 2024-11-15 09:27:20
comments   0
hits   210

[TOC]

উদ্ভাবকরা নতুন বৈশিষ্ট্য পরিমাপ করে: ব্যবহার করুন_সার্ভ ফাংশন সহজেই HTTP পরিষেবা তৈরি করে

পরিমাণগত ট্রেডিং এবং স্বয়ংক্রিয় কৌশল বিকাশে, HTTP পরিষেবাগুলি কখনও কখনও ব্যবহার করা হয়। উদ্ভাবক কোয়ান্টিফিকেশন প্ল্যাটফর্ম সম্প্রতি যোগ করেছে_Serve() ফাংশন, ব্যবহারকারীদের নমনীয় HTTP, HTTPS এবং TCP পরিষেবা তৈরির ক্ষমতা প্রদান করে। এই বৈশিষ্ট্যের সাহায্যে, ডেভেলপাররা পরিষেবা কনফিগারেশন প্রক্রিয়াটি সহজ করতে পারে এবং পরিমাণগত পরিবেশে আরও কাস্টমাইজড পরিষেবা বাস্তবায়ন করতে পারে, কৌশল নকশাকে আরও মসৃণ এবং সুবিধাজনক করে তোলে। এই প্রবন্ধটি কভার করবে_Serve() ফাংশনের ব্যবহারের পরিস্থিতি এবং মৌলিক ক্রিয়াকলাপগুলি আপনাকে উদ্ভাবকের দ্বারা পরিমাপের এই নতুন ফাংশনটি দ্রুত শুরু করতে সহায়তা করে।

সম্পর্কে_Serve()প্ল্যাটফর্ম API ডকুমেন্টেশনে আপডেট করা হয়েছে:

https://www.fmz.com/syntax-guide/fun/global/__serve


প্রয়োজন

প্লাটফর্মটি আপগ্রেড করা হয়েছে_Serve()ফাংশন (যেহেতু জাভাস্ক্রিপ্ট ভাষার আগে পরিষেবা তৈরি করার ফাংশন ছিল না, এই ফাংশনটি শুধুমাত্র জাভাস্ক্রিপ্ট ভাষার নীতিগুলিকে সমর্থন করে), সহজভাবে বলতে গেলে, এটি নীতিটিকে নেটওয়ার্ক পরিষেবা তৈরি করার ক্ষমতা দেয়৷ এই ফাংশনের উপর ভিত্তি করে, আমরা অনেক ফাংশন বিকাশ করতে পারি এবং অনেক চাহিদা সমাধান করতে পারি। উদাহরণস্বরূপ, কৌশলটিতে বাহ্যিক ইন্টারফেস, ডেটা ফরওয়ার্ডিং এবং FMZ প্ল্যাটফর্ম দ্বারা সমর্থিত নয় এমন এক্সচেঞ্জগুলিকে নিরবিচ্ছিন্নভাবে এনক্যাপসুলেট করার জন্য প্ল্যাটফর্মের সাধারণ প্রোটোকল ফাংশনগুলির সাথে সহযোগিতা করা যাক।

এই প্রবন্ধে, আমরা “FMZ প্ল্যাটফর্ম দ্বারা সমর্থিত নয় এমন এক্সচেঞ্জগুলিকে নির্বিঘ্নে ক্যাপসুলেট করার জন্য প্ল্যাটফর্মের সাধারণ প্রোটোকল ফাংশনের সাথে সহযোগিতা করার” প্রয়োজনীয়তাটিকে উদাহরণ হিসেবে নেব। পূর্ববর্তী প্রবন্ধগুলিতে“সাধারণ প্রোটোকল গাইড”আমরা স্পট মোডে OKX এক্সচেঞ্জের API এনক্যাপসুলেট করতে পাইথন ভাষা ব্যবহার করি (যেহেতু FMZ নিজেই OKX সমর্থন করে, এখানে OKX-এর ব্যবহার শুধুমাত্র একটি উদাহরণ, এবং এটি FMZ প্ল্যাটফর্মের সাথে সংযুক্ত নয় এমন অন্যান্য এক্সচেঞ্জের ক্ষেত্রে প্রযোজ্য)। যখন জাভাস্ক্রিপ্ট ভাষা সমর্থন করে তখন এই নিবন্ধে পাইথনের সাধারণ প্রোটোকল প্রোগ্রামটি আলাদাভাবে চালানো দরকার_Serve()ফাংশনের পরে, সাধারণ প্রোটোকলগুলিতে জাভাস্ক্রিপ্ট ভাষার কৌশলগুলিকে একীভূত করা সহজ।

আমরা এক্সচেঞ্জ ইন্টারফেসের সাধারণ প্রোটোকলকে একটি “টেমপ্লেট ক্লাস লাইব্রেরি”-এ এনক্যাপসুলেট করি এবং এটিকে সরাসরি কৌশলের সাথে একীভূত করি, যাতে কৌশলটি FMZ-এ সমর্থিত নয় এমন এক্সচেঞ্জগুলির সাথে নির্বিঘ্নে সংযুক্ত হতে পারে। “ইউনিভার্সাল প্রোটোকল” এক্সচেঞ্জ অবজেক্টটি কীভাবে কনফিগার করতে হয় সে সম্পর্কে আমি এখানে বিস্তারিত জানাব না আপনি নিবন্ধটি পরীক্ষা করতে পারেন:

https://www.fmz.com/digest-topic/10518

  • প্ল্যাটফর্মে সাধারণ প্রোটোকল বিনিময় কনফিগারেশন নিম্নরূপ:

উদ্ভাবকরা নতুন বৈশিষ্ট্য পরিমাপ করে: ব্যবহার করুন_সার্ভ ফাংশন সহজেই HTTP পরিষেবা তৈরি করে

আপনি পাস করতে পারেন/OKXকনফিগার করা সর্বজনীন প্রোটোকল এক্সচেঞ্জ অবজেক্টটি কোন এক্সচেঞ্জের অন্তর্গত তা সনাক্ত করে৷


ইউনিভার্সাল প্রোটোকল টেমপ্লেট বাস্তবায়ন

প্রথমত, উদ্ভাবক পরিমাণগত ট্রেডিং প্ল্যাটফর্মে একটি নতুন কৌশল তৈরি করুন, কৌশলের ধরনটি টেমপ্লেট ক্লাস লাইব্রেরিতে এবং কৌশল ভাষাটি জাভাস্ক্রিপ্টে সেট করুন।

টেমপ্লেট প্যারামিটার ডিজাইন

তৈরি করা নীতি টেমপ্লেটে 3টি পরামিতি যোগ করুন:

উদ্ভাবকরা নতুন বৈশিষ্ট্য পরিমাপ করে: ব্যবহার করুন_সার্ভ ফাংশন সহজেই HTTP পরিষেবা তৈরি করে

তারপর আপনি সাধারণ প্রোটোকল টেমপ্লেটের জন্য কোড ডিজাইন এবং লেখা শুরু করতে পারেন।

কোড বাস্তবায়ন

কোডটি টিএস স্টাইলে লেখা হয়েছে,$.startService()ফাংশনটি টেমপ্লেটের ইন্টারফেস ফাংশন, যা সাধারণ প্রোটোকল পরিষেবা শুরু করতে ব্যবহৃত হয়।

// @ts-check

$.startService = function (address, port, proxyConfig) {
    __Serve(`http://${address}:${port}`, function (ctx, proxyConfig) {
        // interface
        interface IData {
            data: object
            raw: object
        }
        
        interface IError {
            error: any
        }
        
        // custom protocol for OKX
        class CustomProtocolOKX {
            apiBase: string = "https://www.okx.com"
            accessKey: string
            secretKey: string
            passphrase: string
            proxyConfig: string = ""
            simulate: boolean = false
            
            constructor(accessKey: string, secretKey: string, passphrase: string, simulate?: boolean, proxyConfig?: string) {
                this.accessKey = accessKey
                this.secretKey = secretKey
                this.passphrase = passphrase
                if (typeof(simulate) == "boolean") {
                    this.simulate = simulate
                }
                this.proxyConfig = proxyConfig
            }
            
            httpReq(method: string, path: string, query: string = "", params: {[key: string]: any} = {}, headers: {key: string, value: string | ArrayBuffer}[] = []): {[key: string]: any} {
                let ret = null
                let options = {
                    method: method,                    
                    headers: {
                        'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6', 
                        'Content-Type': 'application/json; charset=UTF-8',
                        'x-simulated-trading': this.simulate ? "1" : "0"
                    },
                }
                
                // headers
                if (Array.isArray(headers) && headers.length > 0) {
                    for (var pair of headers) {
                        options.headers[pair.key] = pair.value
                    }
                }
                
                let url = ""
                if (method == "GET") {
                    if (typeof(query) == "string" && query.length > 0) {
                        url = `${this.apiBase}${path}?${query}`
                    } else {
                        url = `${this.apiBase}${path}`
                    }
                } else {
                    url = `${this.apiBase}${path}`
                    options.body = JSON.stringify(params)
                }

                // request
                try {
                    if (this.proxyConfig != "") {
                        url = `${this.proxyConfig}${url}`
                    }
                    ret = JSON.parse(HttpQuery(url, options))
                } catch(e) {
                    return null
                }
    
                return ret
            }

            callSignedAPI(method: string, path: string, query: string = "", params: {[key: string]: any} = {}): {[key: string]: any} {
                const strTime = new Date().toISOString().slice(0, -5) + 'Z'
                let jsonStr = ""
                if (method == "GET") {
                    jsonStr = Object.keys(params).length > 0 ? JSON.stringify(params) : ""
                } else {
                    jsonStr = Object.keys(params).length > 0 ? JSON.stringify(params) : "{}"
                }                
                let message = `${strTime}${method}${path}${jsonStr}`
                if (method === "GET" && query !== "") {
                    message = `${strTime}${method}${path}?${query}${jsonStr}`
                }

                const signature = Encode("sha256", "string", "base64", message, "string", this.secretKey)
                let headers = []
                headers.push({key: "OK-ACCESS-KEY", value: this.accessKey})
                headers.push({key: "OK-ACCESS-PASSPHRASE", value: this.passphrase})
                headers.push({key: "OK-ACCESS-TIMESTAMP", value: strTime})
                headers.push({key: "OK-ACCESS-SIGN", value: signature})                

                return this.httpReq(method, path, query, params, headers)
            }
            
            urlEncode(params: {[key: string]: string | number}): string {
                let encodeParams: string[] = []
                for (const [key, value] of Object.entries(params)) {
                    encodeParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
                }

                return encodeParams.join("&")
            }

            symbol2Inst(symbol: string): string {
                let arr = symbol.split("_")
                if (arr.length >= 2) {
                    return `${arr[0]}-${arr[1]}`.toUpperCase()
                } else {
                    return `${arr[0]}-USDT`.toUpperCase()
                }
            }

            getSymbol(inst: string): string {
                let arr = inst.split("-")
                if (arr.length >= 2) {
                    return `${arr[0]}_${arr[1]}`.toUpperCase()
                } else {
                    return `${arr[0]}-USDT`.toUpperCase()
                }
            }
            
            // The following code encapsulates OKX's interface
            GetTicker(symbol: string): IData | IError {
                // GET /api/v5/market/ticker , param: instId 

                let inst = this.symbol2Inst(symbol)
                let ret = this.httpReq("GET", "/api/v5/market/ticker", `instId=${inst}`)

                let retData = {}
                for (var ele of ret["data"]) {
                    retData["symbol"] = this.getSymbol(ele["instId"])
                    retData["buy"] = ele["bidPx"]
                    retData["sell"] = ele["askPx"]
                    retData["high"] = ele["high24h"]
                    retData["low"] = ele["low24h"]
                    retData["open"] = ele["open24h"]
                    retData["last"] = ele["last"]
                    retData["vol"] = ele["vol24h"]
                    retData["time"] = ele["ts"]
                }

                return {data: retData, raw: ret}
            }
            
            GetAccount(): IData | IError {
                // GET /api/v5/account/balance
                
                let ret = this.callSignedAPI("GET", "/api/v5/account/balance")

                let retData = []
                for (var ele of ret["data"]) {
                    for (var detail of ele["details"]) {
                        let asset = {"currency": detail["ccy"], "free": detail["availEq"], "frozen": detail["ordFrozen"]}
                        if (detail["availEq"] == "") {
                            asset["free"] = detail["availBal"]
                        }
                        retData.push(asset)
                    }
                }
                
                return {data: retData, raw: ret}
            }

            IO(method: string, path: string, params: {[key: string]: any}): {[key: string]: any} {
                let ret = null 
                if (method == "GET") {
                    ret = this.callSignedAPI(method, path, this.urlEncode(params))
                } else {
                    ret = this.callSignedAPI(method, path, "", params)
                }

                return {data: ret}
            }
        }
        
        // protocol factory
        class ProtocolFactory {
            static createExWrapper(accessKey: string, secretKey: string, exName: string): any {
                let protocol = null
                if (exName == "/OKX") {
                    try {
                        let passphrase = ""
                        let simulate = false
                        let arrSecretKey = secretKey.split(",")

                        if (arrSecretKey.length == 2) {
                            secretKey = arrSecretKey[0]
                            passphrase = arrSecretKey[1]
                        } else if (arrSecretKey.length == 3) {
                            secretKey = arrSecretKey[0]
                            passphrase = arrSecretKey[1]
                            simulate = arrSecretKey[2] == "simulate" ? true : false 
                        } else {
                            return null
                        }
                        protocol = new CustomProtocolOKX(accessKey, secretKey, passphrase, simulate, proxyConfig)
                    } catch(e) {
                        Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
                        return null
                    }
                }
                return protocol
            }
        }
        
        // http service
        let resp = {}
        let reqMethod = ctx.method()
        let reqPath = ctx.path()
        let httpMethod = ctx.header("Http-Method")
        let reqBody = null

        try {
            reqBody = JSON.parse(ctx.body())
        } catch(e) {
            resp = {error: {name: e.name, stack: e.stack, message: e.message, errDesc: "JSON parse error."}}
        }

        // onPost
        if (reqMethod == "POST") {
            if (!["access_key", "secret_key", "method", "params"].every(key=> key in reqBody)) {
                resp = {error: {reqBody: reqBody, errDesc: "reqBody error."}}
            }

            if ("error" in resp) {
                ctx.write(JSON.stringify(resp))
                return 
            }

            let accessKey = reqBody["access_key"]
            let secretKey = reqBody["secret_key"]
            let method = reqBody["method"]
            let params = reqBody["params"]

            let protocol = ProtocolFactory.createExWrapper(accessKey, secretKey, reqPath)
            if (!protocol) {
                ctx.write(JSON.stringify({error: {errDesc: "createExWrapper error."}}))
                return 
            }

            // process GetTicker / GetAccount ...
            if (method == "ticker") {
                if (!["symbol"].every(key=> key in params)) {
                    resp = {error: {params: params, errDesc: "params error."}}
                } else {
                    let symbol = params["symbol"]
                    resp = protocol.GetTicker(symbol)
                }
            } else if (method == "accounts") {
                resp = protocol.GetAccount()
            } else if (method.slice(0, 6) == "__api_") {
                resp = protocol.IO(httpMethod, method.slice(6), params)
            } else {
                ctx.write(JSON.stringify({error: {method: method, errDesc: "method not support."}}))
                return 
            }

            ctx.write(JSON.stringify(resp))
        }
    }, proxyConfig)
}

function init() {
    $.startService(address, port, proxyConfig)
    Log("启动通用协议服务,address:", address, ",port:", port, "#FF0000")
    if (proxyConfig != "") {
        Log("设置代理:", proxyConfig, "#FF0000")
    }
}

সীমিত স্থানের কারণে, এখানে সমস্ত ইন্টারফেস বাস্তবায়িত হয় না, শুধুমাত্রবাজার অনুসন্ধানসম্পদের প্রশ্নআইও কল, আগ্রহী শিক্ষার্থীরা সমস্ত ইন্টারফেস বাস্তবায়ন করতে পারে ডিজাইন সম্পূর্ণ হওয়ার পরে, টেমপ্লেট কোড সংরক্ষণ করা হয়, এবং টেমপ্লেটের নামটি এইভাবে সংরক্ষণ করা হয়: “TypeScript Version Universal Protocol Example”।


পরীক্ষার কৌশল

OKX এক্সচেঞ্জের অ্যাপিকি, সিক্রেটকি, পাসফ্রেজ ইত্যাদি কনফিগার করার পরে, আমরা পরীক্ষা করার জন্য একটি পরীক্ষা কৌশল লিখতে পারি।

আমাদের ডিজাইন করা টেমপ্লেট ক্লাস লাইব্রেরি চেক করার কৌশল:

উদ্ভাবকরা নতুন বৈশিষ্ট্য পরিমাপ করে: ব্যবহার করুন_সার্ভ ফাংশন সহজেই HTTP পরিষেবা তৈরি করে

পরীক্ষা কৌশল কোড:

function main() {
    // 测试GetTicker
    Log(`exchange.GetTicker():`, exchange.GetTicker())

    // 测试GetAccount
    Log(`exchange.GetAccount():`, exchange.GetAccount())

    // 测试exchange.IO
    Log(`exchange.IO("api", "POST", "/api/v5/trade/cancel-all-after", "timeOut=0"):`, exchange.IO("api", "POST", "/api/v5/trade/cancel-all-after", "timeOut=0"))

    // 输出通用协议添加的交易所名称
    Log(`exchange.GetName():`, exchange.GetName())

    // 输出通用协议添加的交易所标签
    Log(`exchange.GetLabel():`, exchange.GetLabel())
}

পরীক্ষা চালান

উদ্ভাবকরা নতুন বৈশিষ্ট্য পরিমাপ করে: ব্যবহার করুন_সার্ভ ফাংশন সহজেই HTTP পরিষেবা তৈরি করে

এটি দেখা যায় যে কৌশলটি OKX এক্সচেঞ্জে বিরামবিহীন অ্যাক্সেস অর্জনের জন্য শুধুমাত্র একটি টেমপ্লেট পরীক্ষা করে (যদিও OKX এক্সচেঞ্জ ইতিমধ্যে এটি সমর্থন করে, উদাহরণস্বরূপ, এখানে OKX একটি বিনিময় দ্বারা প্রতিস্থাপিত হয়েছে যা FMZ এখনও সংযুক্ত হয়নি)।