Sumber dimuat naik... memuat...

Pencipta mengutip ciri baru: mudah membuat perkhidmatan HTTP menggunakan fungsi _Serve

Penulis:Pencipta Kuantiti - Impian Kecil, Dicipta: 2024-11-12 22:10:49, Dikemas kini: 2024-11-15 09:27:20

[TOC]

img

Perkhidmatan http kadang-kadang digunakan dalam pengembangan transaksi kuantitatif dan strategi automasi._Serve()Fungsi yang memberi pengguna keupayaan untuk membuat perkhidmatan HTTP, HTTPS dan TCP yang fleksibel. Dengan ciri ini, pemaju dapat menyederhanakan proses konfigurasi perkhidmatan dan melaksanakan lebih banyak perkhidmatan kustom dalam persekitaran kuantitatif, menjadikan reka bentuk dasar lebih lancar dan mudah._Serve()Senario kegunaan dan operasi asas fungsi untuk membantu anda mengukur fungsi baru ini dengan cepat.

Mengenai_Serve()Di laman web ini, anda boleh melihat beberapa gambar yang menarik.

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


Keperluan

Platform ditingkatkan_Serve()Fungsi (kerana sebelum ini bahasa JavaScript tidak mempunyai fungsi untuk membuat perkhidmatan, fungsi ini hanya menyokong dasar bahasa JavaScript), secara ringkasnya adalah untuk menjadikan dasar mempunyai keupayaan untuk membuat perkhidmatan rangkaian. Berdasarkan fungsi ini, kita boleh membangunkan banyak fungsi untuk menyelesaikan banyak keperluan. Contohnya, menjadikan dasar mempunyai antara muka luar, pemindahan data, fungsi protokol umum yang menyokong platform tanpa membungkus pertukaran yang tidak disokong oleh platform FMZ.

Dalam artikel ini, kita akan memberi contoh keperluan: "Pertandingan yang tidak disokong oleh platform FMZ yang mempunyai fungsi protokol umum yang berfungsi dengan lancar".Buku Panduan Protokol UmumDalam bahasa Python, kami menggunakan OKX untuk berdagang, jadi mod langsung terbungkus API ((kerana FMZ sendiri menyokong OKX, OKX digunakan di sini hanya sebagai contoh, untuk pertukaran lain yang tidak mempunyai akses ke platform FMZ). Dalam teks, program protokol umum Python perlu dijalankan secara berasingan, apabila bahasa JavaScript disokong._Serve()Selepas fungsi, strategi bahasa JavaScript untuk mengakses protokol umum menjadi lebih mudah.

Kami akan menggabungkan protokol umum antara muka pertukaran yang akan dibungkus sebagai "Layanan Templat" secara langsung ke dalam dasar, yang membolehkan akses lancar ke pertukaran yang tidak disokong di FMZ. Untuk mengkonfigurasi objek pertukaran protokol umum, lihat artikel:

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

  • Pertukaran protokol umum di platform ini disusun seperti berikut:

    img

    Ia boleh digunakan untuk membuat template./OKXPertukaran yang diiktiraf sebagai objek pertukaran protokol am yang diiktiraf.


Pelaksanaan Templat Protokol Umum

Pertama, pencipta membuat strategi baru di platform dagangan kuantitatif pencipta, dengan jenis strategi ditetapkan sebagai perpustakaan templat, dan bahasa strategi adalah bahasa JavaScript.

Reka bentuk parameter templat

Terdapat tiga parameter yang ditambah kepada templat strategi yang baik:

img

Kemudian anda boleh mula merancang, menulis kod untuk templat protokol umum.

Pelaksanaan kod

Kod ini ditulis dengan gaya TS.$.startService()Fungsi adalah fungsi antara muka templat yang digunakan untuk memulakan perkhidmatan protokol umum.

// @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")
    }
}

Jika anda ingin melihat lebih banyak, anda perlu melihat lebih banyak, tetapi anda tidak boleh melihat lebih banyak.SiasatanSoalan asetpanggilan IOPelajar yang berminat boleh melaksanakan semua antara muka; reka bentuk selesai, menyimpan kod templat, nama templat disimpan sebagai: TypeScript versi protokol umum contoh .


Strategi Ujian

Setelah konfigurasi OKX diperbaiki, seperti apikey, secretkey, passphrase, dan lain-lain, kita boleh menulis satu strategi ujian untuk menguji.

Rancangan yang kami buat untuk perpustakaan templat kami:

img

Kode teknik ujian:

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

Percubaan berjalan

img

Seperti yang dapat dilihat, strategi hanya memilih satu templat untuk mencapai akses lancar kepada bursa OKX (walaupun OKX telah menyokong, contohnya OKX menggantikan bursa FMZ yang belum disambungkan).


Lebih lanjut