Sumber daya yang dimuat... Pemuatan...

Penemu mengkuantifikasi fitur baru: dengan mudah membuat layanan HTTP menggunakan fungsi _Serve

Penulis:Penemu Kuantitas - Mimpi Kecil, Dibuat: 2024-11-12 22:10:49, Diperbarui: 2024-11-15 09:27:20

[TOC]

img

Layanan http kadang-kadang digunakan dalam pengembangan transaksi kuantitatif dan strategi otomatisasi._Serve()Fungsi ini memberikan pengguna kemampuan untuk membuat layanan HTTP, HTTPS, dan TCP yang fleksibel. Dengan fitur ini, pengembang dapat menyederhanakan proses konfigurasi layanan dan menerapkan lebih banyak layanan kustomisasi di lingkungan kuantitatif, sehingga desain kebijakan lebih mulus dan mudah._Serve()Skenario penggunaan fungsi dan operasi dasar untuk membantu Anda mengkualifikasi fitur baru ini dengan cepat.

Tentang_Serve()Setelah itu, Anda dapat mengunduh aplikasi ini secara gratis.

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


Kebutuhan

Platform ditingkatkan_Serve()Fungsi (karena sebelumnya bahasa JavaScript tidak memiliki fungsi untuk membuat layanan, fungsi ini hanya mendukung kebijakan bahasa JavaScript), secara sederhana adalah membuat kebijakan memiliki kemampuan untuk membuat layanan jaringan. Berdasarkan fungsi ini, kita dapat mengembangkan banyak fungsi untuk memecahkan banyak kebutuhan.

Dalam artikel ini, kami akan memberikan contoh tentang kebutuhan untuk "memperlengkapi fungsi protokol umum yang mendukung platform FMZ tanpa membungkus bursa yang tidak didukung"."Panduan Protokol Umum"Di sini kita menggunakan bahasa Python untuk transaksi OKX sehingga mode langsung terbungkus API ((karena FMZ sendiri mendukung OKX, menggunakan OKX di sini hanya sebagai contoh, berlaku untuk bursa lain yang tidak memiliki akses ke platform FMZ)); dalam teks, program protokol umum Python perlu berjalan secara terpisah, ketika bahasa JavaScript didukung_Serve()Setelah fungsi, strategi bahasa JavaScript untuk mengakses protokol umum menjadi lebih sederhana.

Kami akan langsung mengintegrasikan protokol umum dari antarmuka bursa yang akan dibungkus sebagai "Library Template" ke dalam kebijakan, sehingga kebijakan ini dapat mengakses secara mulus bursa yang tidak didukung di FMZ. Untuk lebih lanjut tentang cara mengkonfigurasi objek bursa "protokol umum", lihat artikel:

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

  • Di platform ini, pertukaran protokol umum diatur sebagai berikut:

    img

    Anda dapat menggunakan template yang telah Anda buat./OKXUntuk mengidentifikasi objek pertukaran protokol umum yang dikonfigurasi, pilihlah bursa mana yang menjadi miliknya.


Implementasi template protokol umum

Pertama, pencipta membuat strategi baru di platform perdagangan kuantitatif, dengan tipe kebijakan ditetapkan sebagai perpustakaan template, dan bahasa strategi adalah bahasa JavaScript.

Desain Parameter Templat

Untuk membuat template strategi yang bagus, kami menambahkan tiga parameter:

img

Setelah itu, Anda dapat mulai merancang dan menulis kode untuk template protokol umum.

Implementasi kode

Kode ini ditulis dalam gaya TS.$.startService()Fungsi adalah fungsi antarmuka template yang digunakan untuk memulai layanan 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 menginstal aplikasi ini, Anda harus menginstal aplikasi yang lebih kecil, tetapi tidak semua antarmuka yang diimplementasikan.PenyelidikanPencarian AsetIO panggilan, Siswa yang tertarik dapat menerapkan semua antarmuka; desain selesai, menyimpan kode template, nama template disimpan sebagai: TypeScript versi protokol umum contoh .


Strategi pengujian

Setelah konfigurasi OKX, seperti apkey, secretkey, passphrase, dan lain-lain selesai, kita dapat menulis kebijakan pengujian untuk pengujian.

Strategi memilih template yang kami rancang:

img

Kode strategi pengujian:

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

Uji coba

img

Seperti yang dapat dilihat, strategi hanya memilih template yang memungkinkan akses lancar ke OKX (meskipun OKX sudah mendukung, misalnya OKX menggantikan FMZ sebagai pertukaran yang belum terhubung).


Lebih banyak