[TOC]
Dịch vụ HTTP đôi khi được sử dụng trong việc phát triển giao dịch định lượng và chiến lược tự động hóa._Serve()
Các chức năng này cung cấp cho người dùng khả năng tạo các dịch vụ HTTP, HTTPS và TCP linh hoạt. Thông qua chức năng này, các nhà phát triển có thể đơn giản hóa quá trình cấu hình dịch vụ và thực hiện nhiều dịch vụ tùy chỉnh hơn trong môi trường định lượng, làm cho việc thiết kế chính sách dễ dàng hơn._Serve()
Các kịch bản sử dụng và các hoạt động cơ bản của các hàm giúp bạn nhanh chóng có thể định lượng các tính năng mới này.
Về_Serve()
Các tài liệu API đã được cập nhật trên nền tảng:
Nâng cấp nền tảng_Serve()
Chức năng (vì ngôn ngữ JavaScript trước đây không có chức năng tạo dịch vụ, chỉ hỗ trợ các chính sách của ngôn ngữ JavaScript) đơn giản là cho các chính sách có khả năng tạo các dịch vụ mạng. Dựa trên chức năng này, chúng ta có thể phát triển nhiều chức năng để giải quyết nhiều nhu cầu. Ví dụ như cho các chính sách có giao diện bên ngoài, chuyển dữ liệu, hỗ trợ các nền tảng giao thức chung không hỗ trợ các sàn giao dịch FMZ.
Trong bài viết này, chúng tôi đã đưa ra ví dụ về nhu cầu: "các sàn giao dịch không được hỗ trợ bởi nền tảng FMZ được đóng gói một cách liền mạch với các chức năng giao thức chung của nền tảng"."Hướng dẫn giao thức chung"Trong đó, chúng tôi sử dụng ngôn ngữ Python để giao dịch OKX vì vậy mô hình hiện tại được gói gọn API ((vì FMZ tự hỗ trợ OKX, sử dụng OKX ở đây chỉ là một ví dụ, áp dụng cho các sàn giao dịch khác mà không có quyền truy cập nền tảng FMZ)); Trong văn bản, các chương trình giao thức chung của Python cần phải chạy riêng biệt, khi ngôn ngữ JavaScript được hỗ trợ._Serve()
Sau các hàm, các chiến lược của ngôn ngữ JavaScript để truy cập vào giao thức chung sẽ đơn giản hơn.
Chúng tôi sẽ gói giao thức chung của giao diện giao dịch để được đóng gói như là "thư viện mẫu" trực tiếp tích hợp vào chính sách, để có thể truy cập một cách liền mạch vào các giao dịch không được hỗ trợ trên FMZ.
Các giao dịch thông thường trên nền tảng được cấu hình như sau:
Bạn có thể sử dụng nó để thiết kế mẫu./OKX
Định dạng giao dịch giao dịch thông thường được xác định là đối tượng của sàn giao dịch nào.
Đầu tiên là tạo ra một chính sách mới trên nền tảng giao dịch định lượng của nhà phát minh, đặt loại chính sách là thư viện mẫu và ngôn ngữ chính sách là ngôn ngữ JavaScript.
Các công cụ này được sử dụng để tạo ra các mô hình chính sách tốt.
Sau đó, bạn có thể bắt đầu thiết kế, viết mã cho mẫu giao thức chung.
Có thể sử dụng các mã khác nhau.$.startService()
Các hàm là các hàm giao diện của mẫu, được sử dụng để khởi động các dịch vụ giao thức chung.
// @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")
}
}
Một phần của nó là một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của một phần của mộtCác cuộc điều tra、Tìm kiếm tài sản、Gọi IOCác học sinh quan tâm có thể thực hiện tất cả các giao diện; thiết kế hoàn tất, lưu mã mẫu, tên mẫu được lưu như:
Sau khi cấu hình OKX cho các giao dịch như apkey, secretkey, passphrase, chúng ta có thể viết một chính sách thử nghiệm để kiểm tra.
Các chiến lược chọn thư viện các mẫu chúng tôi thiết kế:
Có thể sử dụng các công cụ như:
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())
}
Như bạn có thể thấy, chỉ cần chọn một mẫu, chính sách thực hiện truy cập liền mạch vào sàn giao dịch OKX (mặc dù sàn giao dịch OKX đã được hỗ trợ, ví dụ như OKX thay thế một sàn giao dịch FMZ chưa được truy cập).