Type/to search
8
Follow
1364
Followers
Os inventores quantificam novos recursos: usando_A função Serve cria facilmente serviços HTTP
Discussions
Created 2024-11-12 22:10:49  Updated 2024-11-15 09:27:20
 0
 918

img

Na negociação quantitativa e no desenvolvimento de estratégias automatizadas, às vezes são usados ​​serviços http. A Plataforma Quantitativa do Inventor adicionou recentemente_Serve() Função que fornece aos usuários recursos flexíveis de criação de serviços HTTP, HTTPS e TCP. Com esse recurso, os desenvolvedores podem simplificar o processo de configuração de serviços e implementar serviços mais personalizados em um ambiente quantitativo, tornando o design da estratégia mais suave e conveniente. Este artigo irá apresentar_Serve() Os cenários de uso e as operações básicas da função ajudam você a começar rapidamente a usar esta nova função do Inventor Quant.

sobre_Serve()Atualizado na documentação da API da plataforma:

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


precisar

A plataforma foi atualizada_Serve()função (já que a linguagem JavaScript não tinha a função de criar serviços antes, esta função suporta apenas políticas de linguagem JavaScript). Em termos simples, ela permite que as políticas tenham a capacidade de criar serviços de rede. Com base nessa função, podemos desenvolver muitas funções e resolver muitas necessidades. Por exemplo, a estratégia pode ter interfaces externas, encaminhamento de dados e cooperar com as funções gerais do protocolo da plataforma para encapsular perfeitamente as trocas que não são suportadas pela plataforma FMZ.

Neste artigo, tomaremos como exemplo o requisito de "cooperar com a função de protocolo geral da plataforma para encapsular perfeitamente as trocas que não são suportadas pela plataforma FMZ". Em artigos anteriores「Guia de Protocolo Geral」Neste artigo, usamos a linguagem Python para encapsular a API da exchange OKX no modo spot (como a própria FMZ oferece suporte à OKX, a OKX é usada aqui apenas como exemplo e é aplicável a outras exchanges às quais a plataforma FMZ não está conectada). O programa de protocolo geral Python neste artigo precisa ser executado separadamente. Quando a linguagem JavaScript suporta_Serve()Após a função, fica mais fácil acessar o protocolo comum da estratégia da linguagem JavaScript.

Encapsulamos o protocolo geral da interface de troca para ser encapsulado em uma "biblioteca de modelos" e o integramos diretamente à estratégia, para que a estratégia possa acessar facilmente as trocas que não são suportadas no FMZ. Não entrarei em detalhes sobre como configurar o objeto de troca "Protocolo Geral" aqui, você pode consultar o artigo:

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

  • A configuração geral de troca de protocolo na plataforma é a seguinte:

    img

    Ao projetar o modelo, você pode/OKXIdentifica a qual troca o objeto de troca de protocolo genérico configurado pertence.


Implementação de modelo de protocolo genérico

Primeiro, crie uma nova estratégia na Plataforma de Negociação Quantitativa do Inventor, defina o tipo de estratégia como biblioteca de modelos e a linguagem da estratégia como JavaScript.

Design de parâmetros de modelo

Adicione três parâmetros ao modelo de política criado:

img

Então você pode começar a projetar e escrever código para o modelo de protocolo geral.

Implementação de código

O código é escrito no estilo TS.$.startService()A função é uma função de interface de modelo usada para iniciar o serviço de protocolo geral.

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

Devido ao espaço limitado, nem todas as interfaces são implementadas aqui, apenasConsulta de mercadoConsulta de ativosChamadas de E/SOs alunos interessados ​​podem implementar todas as interfaces; após a conclusão do design, salve o código do modelo e salve o nome do modelo como: "Exemplo de protocolo geral da versão TypeScript".


Estratégia de teste

Depois de configurar a apikey, a secretkey, a passphrase, etc. da exchange OKX, podemos escrever uma estratégia de teste para testar.

Estratégia Confira nossa biblioteca de modelos projetados:

img

Código da estratégia de teste:

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

Executando testes

img

Como você pode ver, a estratégia só precisa verificar um modelo para obter acesso contínuo à bolsa OKX (embora a bolsa OKX já suporte isso, por exemplo, a OKX é substituída aqui por uma bolsa à qual a FMZ ainda não se conectou).

Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)