4
پر توجہ دیں
1076
پیروکار

موجد نئی خصوصیات کی مقدار بتاتے ہیں: استعمال کرنا_سرو فنکشن آسانی سے 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() فنکشن کے استعمال کے منظرنامے اور بنیادی آپریشنز آپ کو Inventor Quant کے اس نئے فنکشن کے ساتھ جلدی شروع کرنے میں مدد کرتے ہیں۔

کے بارے میں_Serve()پلیٹ فارم API دستاویزات میں اپ ڈیٹ کیا گیا:

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


ضرورت

پلیٹ فارم کو اپ گریڈ کر دیا گیا ہے۔_Serve()فنکشن (چونکہ جاوا اسکرپٹ لینگویج میں پہلے سروسز بنانے کا فنکشن نہیں تھا، اس لیے یہ فنکشن صرف جاوا اسکرپٹ کی لینگویج پالیسیوں کو سپورٹ کرتا ہے)۔ اس فنکشن کی بنیاد پر، ہم بہت سے افعال تیار کر سکتے ہیں اور بہت سی ضروریات کو حل کر سکتے ہیں۔ مثال کے طور پر، حکمت عملی میں بیرونی انٹرفیس، ڈیٹا فارورڈنگ، اور پلیٹ فارم کے جنرل پروٹوکول کے افعال کے ساتھ تعاون کر سکتے ہیں تاکہ بغیر کسی رکاوٹ کے ان تبادلے کو سمیٹ سکیں جو FMZ پلیٹ فارم کے ذریعے تعاون یافتہ نہیں ہیں۔

اس آرٹیکل میں، ہم مثال کے طور پر “پلیٹ فارم کے جنرل پروٹوکول فنکشن کے ساتھ تعاون کرنے کی ضرورت کو بغیر کسی رکاوٹ کے ان ایکسچینجز کو سمیٹنے کے لیے لیں گے جو FMZ پلیٹ فارم سے تعاون یافتہ نہیں ہیں۔” پچھلے مضامین میں“جنرل پروٹوکول گائیڈ”اس آرٹیکل میں، ہم اسپاٹ موڈ میں OKX ایکسچینج کے API کو سمیٹنے کے لیے ازگر کی زبان کا استعمال کرتے ہیں (کیونکہ FMZ خود OKX کو سپورٹ کرتا ہے، OKX کو یہاں صرف ایک مثال کے طور پر استعمال کیا گیا ہے، اور یہ دیگر ایکسچینجز پر لاگو ہوتا ہے جن سے FMZ پلیٹ فارم منسلک نہیں ہے)۔ جب جاوا اسکرپٹ لینگویج سپورٹ کرتی ہے تو اس آرٹیکل میں Python جنرل پروٹوکول پروگرام کو الگ سے چلانے کی ضرورت ہے۔_Serve()فنکشن کے بعد، جاوا اسکرپٹ لینگویج اسٹریٹجی کے عام پروٹوکول تک رسائی آسان ہے۔

ہم ایکسچینج انٹرفیس کے عمومی پروٹوکول کو ایک “ٹیمپلیٹ لائبریری” میں سمیٹتے ہیں اور اسے براہ راست حکمت عملی میں ضم کرتے ہیں، تاکہ حکمت عملی بغیر کسی رکاوٹ کے ان ایکسچینجز تک رسائی حاصل کر سکے جو FMZ پر تعاون یافتہ نہیں ہیں۔ میں یہاں “جنرل پروٹوکول” ایکسچینج آبجیکٹ کو ترتیب دینے کے بارے میں تفصیلات میں نہیں جاؤں گا، آپ مضمون کا حوالہ دے سکتے ہیں:

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

  • پلیٹ فارم پر عام پروٹوکول ایکسچینج کنفیگریشن حسب ذیل ہے:

موجد نئی خصوصیات کی مقدار بتاتے ہیں: استعمال کرنا_سرو فنکشن آسانی سے HTTP خدمات تخلیق کرتا ہے۔

ٹیمپلیٹ کو ڈیزائن کرتے وقت، آپ کر سکتے ہیں۔/OKXشناخت کرتا ہے کہ کنفیگرڈ جنرک پروٹوکول ایکسچینج آبجیکٹ کس ایکسچینج سے تعلق رکھتا ہے۔


عام پروٹوکول ٹیمپلیٹ کا نفاذ

سب سے پہلے، موجد مقداری تجارتی پلیٹ فارم میں ایک نئی حکمت عملی بنائیں، حکمت عملی کی قسم کو ٹیمپلیٹ لائبریری، اور حکمت عملی کی زبان کو JavaScript پر سیٹ کریں۔

ٹیمپلیٹ پیرامیٹر ڈیزائن

بنائے گئے پالیسی ٹیمپلیٹ میں تین پیرامیٹرز شامل کریں:

موجد نئی خصوصیات کی مقدار بتاتے ہیں: استعمال کرنا_سرو فنکشن آسانی سے HTTP خدمات تخلیق کرتا ہے۔

پھر آپ جنرل پروٹوکول ٹیمپلیٹ کے لیے کوڈ ڈیزائن اور لکھنا شروع کر سکتے ہیں۔

کوڈ کا نفاذ

کوڈ TS انداز میں لکھا گیا ہے۔$.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")
    }
}

محدود جگہ کی وجہ سے، یہاں صرف تمام انٹرفیس لاگو نہیں ہوتے ہیں۔مارکیٹ کا سوالاثاثہ استفسار、*IO کال کرتا ہے۔*دلچسپی رکھنے والے طلباء تمام انٹرفیس کو نافذ کر سکتے ہیں؛ ڈیزائن مکمل ہونے کے بعد، ٹیمپلیٹ کوڈ کو محفوظ کریں اور ٹیمپلیٹ کا نام اس طرح محفوظ کریں: “TypeScript ورژن جنرل پروٹوکول مثال”۔


جانچ کی حکمت عملی

OKX ایکسچینج کی apikey، secretkey، پاسفریز وغیرہ کو ترتیب دینے کے بعد، ہم جانچنے کے لیے ایک ٹیسٹ حکمت عملی لکھ سکتے ہیں۔

حکمت عملی ہماری ڈیزائن کردہ ٹیمپلیٹ لائبریری کو چیک کریں:

موجد نئی خصوصیات کی مقدار بتاتے ہیں: استعمال کرنا_سرو فنکشن آسانی سے 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 ابھی تک منسلک نہیں ہوا ہے)۔