Type/to search
8
Follow
1363
Followers
Panduan Akses Protokol Umum Platform Perdagangan Kuantitatif Pencipta
Discussions
Created 2024-10-29 14:37:56  Updated 2024-11-12 21:58:55
 0
 1361

img

Platform Dagangan Kuantitatif Inventor menyokong banyak pertukaran mata wang kripto dan merangkumi pertukaran arus perdana di pasaran. Walau bagaimanapun, masih terdapat banyak pertukaran yang tidak dibungkus Bagi pengguna yang perlu menggunakan pertukaran ini, mereka boleh mengaksesnya melalui protokol universal yang dikira oleh pencipta. Tidak terhad kepada pertukaran mata wang kripto, mana-manaRESTPerjanjian atauFIXPlatform perjanjian juga boleh diakses.

Artikel ini akanRESTMengambil akses protokol sebagai contoh, ia menerangkan cara menggunakan protokol umum Platform Dagangan Kuantitatif Pencipta untuk merangkum dan mengakses API OKX Exchange. Melainkan dinyatakan sebaliknya, artikel ini merujuk kepada protokol umum REST.

  • Aliran kerja protokol umum ialah:
    Proses permintaan: Contoh strategi berjalan pada penjaga -> Program protokol umum -> API Pertukaran
    Proses respons: Exchange API -> Program protokol umum -> Contoh strategi berjalan pada penjaga

1. Konfigurasikan pertukaran

Halaman untuk mengkonfigurasi pertukaran pada Platform Dagangan Kuantitatif Pencipta:

https://www.fmz.com/m/platforms/add

img

  • Pilih protokol: Pilih "Protokol Umum".
  • Alamat perkhidmatan: Program protokol umum pada asasnya ialah perkhidmatan RPC
    Oleh itu, adalah perlu untuk menyatakan dengan jelas alamat perkhidmatan dan port semasa mengkonfigurasi pertukaran. Jadi dalam托管者上运行的策略实例 -> 通用协议程序Semasa proses itu, hos mengetahui tempat untuk mengakses program protokol biasa.
    Contohnya:http://127.0.0.1:6666/OKXBiasanya, program protokol biasa dan hos dijalankan pada peranti yang sama (pelayan), jadi alamat perkhidmatan ditulis sebagai mesin tempatan (localhost), dan port boleh menjadi port yang tidak diduduki oleh sistem.
  • Access Key:
    托管者上运行的策略实例 -> 通用协议程序Maklumat konfigurasi pertukaran diluluskan semasa proses.
  • Secret Key:
    托管者上运行的策略实例 -> 通用协议程序Maklumat konfigurasi pertukaran diluluskan semasa proses.
  • Label:
    Label objek pertukaran pada Platform Dagangan Kuantitatif Pencipta digunakan untuk mengenal pasti objek pertukaran tertentu.

Tangkapan skrin konfigurasi pemalam OKX yang didedahkan dalam artikel adalah seperti berikut:

img

OKX bertukar maklumat konfigurasi kunci rahsia:

txt
accessKey: accesskey123 // accesskey123 这些并不是实际秘钥,仅仅是演示 secretKey: secretkey123 passphrase: passphrase123

2. Penggunaan penjaga dan program protokol universal (plugin)

    1. Hos
      Untuk menjalankan sebarang strategi masa nyata pada Platform Dagangan Kuantitatif Pencipta, anda mesti menggunakan kustodian Untuk penempatan khusus penjaga, sila rujuk tutorial platform, yang tidak akan diulang di sini.
    1. Program protokol umum (plugin)
      Hos dan protokol universal biasanya digunakan pada peranti yang sama Program protokol (perkhidmatan) universal boleh ditulis dalam mana-mana bahasa Artikel ini ditulis dalam Python3. Sama seperti menjalankan sebarang program Python, anda boleh melaksanakannya secara langsung (membuat pelbagai konfigurasi persekitaran Python terlebih dahulu).
      Sudah tentu, FMZ juga menyokong menjalankan program Python, dan protokol umum ini boleh dijalankan sebagai cakera sebenar untuk menyediakan platform dagangan kuantitatif pencipta dengan sokongan untuk akses API pertukaran yang tidak dibungkus.
      Selepas program protokol umum berjalan, mulakan pemantauan:http://127.0.0.1:6666,Dalam program protokol umum, laluan khusus boleh ditentukan, sebagai contoh/OKXuntuk diproses.

3. Contoh strategi meminta fungsi API FMZ

Apabila fungsi API platform (FMZ) dipanggil dalam strategi, Program Protokol Universal menerima permintaan daripada penjaga. Anda juga boleh menguji menggunakan alat penyahpepijatan platform, contohnya:

Halaman alat penyahpepijatan:

https://www.fmz.com/m/debug

javascript
function main() { return exchange.GetTicker("LTC_USDT") }

Panggilexchange.GetTicker()Berfungsi, program protokol umum menerima permintaan:

http
POST /OKX HTTP/1.1 { "access_key":"xxx", "method":"ticker", "nonce":1730275031047002000, "params":{"symbol":"LTC_USDT"}, "secret_key":"xxx" }
  • access_key: Kunci pertukaran yang dikonfigurasikan dalam platform "Konfigurasikan Exchange" di atas
  • secret_key: Kunci pertukaran yang dikonfigurasikan dalam platform "Konfigurasikan Pertukaran" di atas
  • kaedah: berkaitan dengan antara muka panggilan dalam strategi, memanggilexchange.GetTicker()jam,methodiaituticker
  • nonce: Cap masa apabila permintaan berlaku.
  • params: Parameter yang berkaitan dengan panggilan antara muka dalam dasar.exchange.GetTicker()Apabila memanggil, parameter yang berkaitan ialah:{"symbol":"LTC_USDT"}

4. Akses program protokol umum ke antara muka pertukaran

Apabila program protokol umum menerima permintaan daripada penjaga, ia boleh mendapatkan maklumat seperti fungsi API platform (termasuk maklumat parameter) yang diminta oleh strategi, kunci pertukaran, dsb. berdasarkan maklumat yang dibawa dalam permintaan.

Berdasarkan maklumat ini, program protokol umum boleh mengakses antara muka pertukaran untuk mendapatkan data yang diperlukan atau melakukan operasi tertentu.

Biasanya antara muka pertukaran mempunyai kaedah seperti GET/POST/PUT/DELETE, yang dibahagikan kepada antara muka awam dan antara muka peribadi.

  • Antara muka awam: antara muka yang tidak memerlukan pengesahan tandatangan dan diminta secara langsung dalam program protokol umum.
  • Antara muka peribadi: antara muka yang memerlukan pengesahan tandatangan. Tandatangan perlu dilaksanakan dalam program protokol umum untuk meminta antara muka API pertukaran ini.

Program protokol umum menerima data tindak balas antara muka pertukaran, memprosesnya lagi dan membinanya ke dalam data yang diharapkan oleh penjaga (diterangkan di bawah).
Rujuk pertukaran tempat OKX, pelaksanaan kelas CustomProtocolOKX dalam contoh protokol umum PythonGetTickerGetAccountDan fungsi lain.

5. Program protokol am bertindak balas data kepada penjaga

Apabila program protokol umum mengakses antara muka API pertukaran, menjalankan operasi tertentu atau memperoleh data tertentu, ia perlu memberi suapan kembali keputusan kepada penjaga.

Data yang disalurkan kembali kepada penjaga berbeza-beza mengikut antara muka yang dipanggil oleh strategi, dan mula-mula dibahagikan kepada dua kategori:

  • Program protokol umum berjaya memanggil antara muka pertukaran:

    json
    { "data": null, // "data" can be of any type "raw": null // "raw" can be of any type }
    • data: Struktur khusus medan ini adalah sama seperti dalam permintaan yang diterima oleh program protokol umum.methodBerikut ialah senarai semua antara muka yang digunakan untuk membina struktur data yang dikembalikan oleh fungsi API platform FMZ.
    • Raw: Medan ini boleh digunakan untuk menghantar data mentah respons API pertukaran, contohnyaexchange.GetTicker()Struktur Ticker yang dikembalikan oleh fungsi mempunyai maklumat berikut yang direkodkan dalam medan Maklumat struktur Ticker:rawPadang dandataData medan; beberapa fungsi API platform tidak memerlukan data ini.
  • Program protokol umum gagal memanggil antara muka pertukaran (ralat perniagaan, ralat rangkaian, dll.)

    json
    { "error": "" // "error" contains an error message as a string }
    • ralat: maklumat ralat, yang akan dipaparkan dalam log ralat di kawasan log cakera sebenar platform (FMZ), alat penyahpepijatan dan halaman lain.

Menunjukkan data tindak balas protokol umum yang diterima oleh program dasar:

javascript
// FMZ平台的调试工具中测试 function main() { Log(exchange.GetTicker("USDT")) // 交易对不完整,缺少BaseCurrency部分,需要通用协议插件程序返回报错信息: {"error": "..."} Log(exchange.GetTicker("LTC_USDT")) }

img

6. Perjanjian struktur data dalam protokol umum

Di atas ialah proses ringkas tentang cara program protokol umum mengambil bahagian dalam mengakses API pertukaran (FMZ tidak dibungkus) Proses ini hanya menerangkan cara memanggil alat penyahpepijatan platform (FMZ).exchange.GetTicker()Proses fungsi. Seterusnya, butiran interaksi semua fungsi API platform akan diterangkan secara terperinci.

Platform ini merangkum fungsi umum pelbagai pertukaran dan menyatukannya ke dalam fungsi tertentu, seperti fungsi GetTicker, yang meminta maklumat pasaran semasa bagi produk tertentu Ini pada dasarnya adalah API yang dimiliki oleh semua bursa. Oleh itu, apabila antara muka API terkapsul platform diakses dalam contoh strategi, penjaga akan menghantar permintaan kepada pemalam "Protokol Universal" (disebutkan di atas):

http
POST /OKX HTTP/1.1 { "access_key": "xxx", "method": "ticker", "nonce": 1730275031047002000, "params": {"symbol":"LTC_USDT"}, "secret_key": "xxx" }

Apabila memanggil fungsi API terkapsul platform pencipta yang berbeza dalam strategi (seperti GetTicker), format permintaan yang dihantar oleh penjaga kepada protokol umum juga akan berbeza. Data (JSON) dalam badan berbeza hanya dalammethoddanparams. Apabila mereka bentuk protokol umum,methodAnda boleh melakukan operasi khusus berdasarkan kandungan. Berikut ialah senario permintaan-tindak balas untuk semua antara muka.

Pertukaran Spot

Sebagai contoh, pasangan dagangan semasa ialah:ETH_USDT, saya tidak akan menjelaskan secara terperinci kemudian. Data yang penjaga menjangkakan protokol umum bertindak balas terutamanya ditulis dalam medan data, dan medan mentah juga boleh ditambah untuk merekodkan data asal antara muka pertukaran.

  • GetTicker

    • medan kaedah: "ticker"

    • medan params:

      json
      {"symbol":"ETH_USDT"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": { "symbol": "ETH_USDT", // 对应GetTicker函数返回的Ticker结构中的Symbol字段 "buy": "2922.18", // ...对应Buy字段 "sell": "2922.19", "high": "2955", "low": "2775.15", "open": "2787.72", "last": "2922.18", "vol": "249400.888156", "time": "1731028903911" }, "raw": {} // 可以增加一个raw字段记录交易所API接口应答的原始数据 }
  • GetDepth

    • medan kaedah: "kedalaman"

    • medan params:

      json
      {"limit":"30","symbol":"ETH_USDT"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data" : { "time" : 1500793319499, "asks" : [ [1000, 0.5], [1001, 0.23], [1004, 2.1] // ... ], "bids" : [ [999, 0.25], [998, 0.8], [995, 1.4] // ... ] } }
  • GetTrades

    • medan kaedah: "perdagangan"

    • medan params:

      json
      {"symbol":"eth_usdt"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": [ { "id": 12232153, "time" : 1529919412968, "price": 1000, "amount": 0.5, "type": "buy", // "buy"、"sell"、"bid"、"ask" }, { "id": 12545664, "time" : 1529919412900, "price": 1001, "amount": 1, "type": "sell", } // ... ] }
  • GetRecords

    • medan kaedah: "rekod"

    • medan params:

      json
      { "limit":"500", "period":"60", // 60分钟 "symbol":"ETH_USDT" }
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": [ // "Time":1500793319000,"Open":1.1,"High":2.2,"Low":3.3,"Close":4.4,"Volume":5.5 [1500793319, 1.1, 2.2, 3.3, 4.4, 5.5], [1500793259, 1.01, 2.02, 3.03, 4.04, 5.05], // ... ] }
  • GetMarkets
    Untuk dilaksanakan

    • medan kaedah: ""

    • medan params:

      json
      {}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      {}
  • GetTickers
    Untuk dilaksanakan

    • medan kaedah: ""

    • medan params:

      json
      {}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      {}
  • GetAccount

    • medan kaedah: "akaun"

    • medan params:

      json
      {}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": [ {"currency": "TUSD", "free": "3000", "frozen": "0"}, {"currency": "BTC", "free": "0.2482982056277609", "frozen": "0"}, // ... ] }
  • GetAssets

    • medan kaedah: "aset"

    • medan params:

      json
      {}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": [ {"currency": "TUSD", "free": "3000", "frozen": "0"}, {"currency": "BTC", "free": "0.2482982056277609", "frozen": "0"}, // ... ] }
  • CreateOrder / Buy / Sell

    • medan kaedah: "perdagangan"

    • medan params:

      json
      {"amount":"0.1","price":"1000","symbol":"BTC_USDT","type":"buy"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": { "id": "BTC-USDT,123456" } }
  • GetOrders

    • medan kaedah: "pesanan"

    • medan params:

      json
      {"symbol":"ETH_USDT"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": [ { "id": "ETH-USDT,123456", "symbol": "ETH_USDT", "amount": 0.25, "price": 1005, "deal_amount": 0, "avg_price": "1000", "type": "buy", // "buy"、"sell" "status": "pending", // "pending", "pre-submitted", "submitting", "submitted", "partial-filled" }, // ... ] }
  • GetOrder

    • medan kaedah: "pesanan"

    • medan params:

      json
      { "id":"ETH-USDT,123456", // 策略中调用:exchange.GetOrder("ETH-USDT,123456") "symbol":"ETH_USDT" }
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": { "id": "ETH-USDT,123456", "symbol": "ETH_USDT" "amount": 0.15, "price": 1002, "status": "pending", // "pending", "pre-submitted", "submitting", "submitted", "partial-filled", "filled", "closed", "finished", "partial-canceled", "canceled" "deal_amount": 0, "type": "buy", // "buy"、"sell" "avg_price": 0, // 如果交易所没有提供,在处理时可以赋值为0 } }
  • GetHistoryOrders

    • medan kaedah: "historyorders"

    • medan params:

      json
      {"limit":0,"since":0,"symbol":"ETH_USDT"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": [ { "id": "ETH-USDT,123456", "symbol": "ETH_USDT", "amount": 0.25, "price": 1005, "deal_amount": 0, "avg_price": 1000, "type": "buy", // "buy"、"sell" "status": "filled", // "filled" }, // ... ] }
  • CancelOrder

    • medan kaedah: "batalkan"

    • medan params:

      json
      {"id":"ETH-USDT,123456","symbol":"ETH_USDT"}
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": true // 只要该JSON中没有error字段,都默认为撤单成功 }
  • IO

    Fungsi exchange.IO digunakan untuk mengakses terus antara muka pertukaran Sebagai contoh, kita gunakanGET /api/v5/trade/orders-pending, 参数:instType=SPOT,instId=ETH-USDTContohnya.

    javascript
    // 策略实例中调用 exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT&instId=ETH-USDT")
    • medan kaedah:"__api_/api/v5/trade/orders-pending"Medan kaedah bermula dengan _api, menunjukkan bahawa ini dicetuskan oleh panggilan fungsi pertukaran.IO dalam contoh strategi.

    • medan params:

      json
      {"instId":"ETH-USDT","instType":"SPOT"} // instType=SPOT&instId=ETH-USDT编码的参数会被还原为JSON
    • Data yang diharapkan oleh hos dalam tindak balas protokol umum:

      json
      { "data": {"code": "0", "data": [], "msg": ""} // data属性值为交易所API:GET /api/v5/trade/orders-pending 应答的数据 }
  • lain
    Fungsi API Platform Pencipta lain yang digunakan dalam contoh strategi, seperti:
    exchange.Go()exchange.GetRawJSON()Fungsi seperti ini tidak perlu dikapsulkan, dan kaedah dan fungsi panggilan kekal tidak berubah.

Bursa Niaga Hadapan

Selain menyokong semua fungsi pertukaran spot, bursa niaga hadapan juga mempunyai beberapa fungsi API yang unik kepada bursa niaga hadapan.

Untuk dilaksanakan

  • GetPositions
  • SetMarginLevel
  • GetFundings

Versi Python contoh protokol umum

Protokol umum REST - akses kepada antara muka API REST pertukaran OKX dan merangkumnya sebagai objek pertukaran spot.
Melaksanakan antara muka biasa untuk enkapsulasi data permintaan dan tindak balas.
Melaksanakan tandatangan antara muka peribadi, enkapsulasi data permintaan dan tindak balas.
Contoh ini adalah terutamanya untuk ujian dan pembelajaran Antara muka lain menggunakan data simulasi untuk bertindak balas terus kepada hos untuk ujian.

python
import http.server import socketserver import json import urllib.request import urllib.error import argparse import ssl import hmac import hashlib import base64 from datetime import datetime ssl._create_default_https_context = ssl._create_unverified_context class BaseProtocol: ERR_NOT_SUPPORT = {"error": "not support"} def __init__(self, apiBase, accessKey, secretKey): self._apiBase = apiBase self._accessKey = accessKey self._secretKey = secretKey def _httpRequest(self, method, path, query="", params={}, addHeaders={}): 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' } # add headers for key in addHeaders: headers[key] = addHeaders[key] if method == "GET": url = f"{self._apiBase}{path}?{query}" if query != "" else f"{self._apiBase}{path}" req = urllib.request.Request(url, method=method, headers=headers) else: url = f"{self._apiBase}{path}" req = urllib.request.Request(url, json.dumps(params, separators=(',', ':')).encode('utf-8'), method=method, headers=headers) print(f'send request by protocol: {self.exName}, req:', req.method, req.full_url, req.headers, req.data, "\n") try: with urllib.request.urlopen(req) as resp: data = json.loads(resp.read()) except json.JSONDecodeError: data = {"error": "Invalid JSON response"} except urllib.error.HTTPError as e: data = {"error": f"HTTP error: {e.code}"} except urllib.error.URLError as e: data = {"error": f"URL error: {e.reason}"} except Exception as e: data = {"error": f"Exception occurred: {str(e)}"} print(f'protocol response received: {self.exName}, resp:', data, "\n") return data def GetTickers(self): return self.ERR_NOT_SUPPORT def GetMarkets(self): return self.ERR_NOT_SUPPORT def GetTicker(self, symbol): return self.ERR_NOT_SUPPORT def GetDepth(self, symbol=""): return self.ERR_NOT_SUPPORT def GetTrades(self, symbol=""): return self.ERR_NOT_SUPPORT def GetRecords(self, symbol, period, limit): return self.ERR_NOT_SUPPORT def GetAssets(self): return self.ERR_NOT_SUPPORT def GetAccount(self): return self.ERR_NOT_SUPPORT def CreateOrder(self, symbol, side, price, amount): return self.ERR_NOT_SUPPORT def GetOrders(self, symbol=""): return self.ERR_NOT_SUPPORT def GetOrder(self, orderId): return self.ERR_NOT_SUPPORT def CancelOrder(self, orderId): return self.ERR_NOT_SUPPORT def GetHistoryOrders(self, symbol, since, limit): return self.ERR_NOT_SUPPORT def GetPostions(self, symbol=""): return self.ERR_NOT_SUPPORT def SetMarginLevel(self, symbol, marginLevel): return self.ERR_NOT_SUPPORT def GetFundings(self, symbol=""): return self.ERR_NOT_SUPPORT def IO(self, params): return self.ERR_NOT_SUPPORT class ProtocolFactory: @staticmethod def createExWrapper(apiBase, accessKey, secretKey, exName) -> BaseProtocol: if exName == "OKX": return CustomProtocolOKX(apiBase, accessKey, secretKey, exName) else: raise ValueError(f'Unknown exName: {exName}') class CustomProtocolOKX(BaseProtocol): """ CustomProtocolOKX - OKX API Wrapper # TODO: add information. """ def __init__(self, apiBase, accessKey, secretKey, exName): secretKeyList = secretKey.split(",") self.exName = exName self._x_simulated_trading = 0 if len(secretKeyList) > 1: self._passphrase = secretKeyList[1] if len(secretKeyList) > 2: if secretKeyList[2] == "simulate": self._x_simulated_trading = 1 else: raise ValueError(f"{self.exName}: invalid secretKey format.") super().__init__(apiBase, accessKey, secretKeyList[0]) def getCurrencys(self, symbol): baseCurrency, quoteCurrency = "", "" arrCurrency = symbol.split("_") if len(arrCurrency) == 2: baseCurrency = arrCurrency[0] quoteCurrency = arrCurrency[1] return baseCurrency, quoteCurrency def getSymbol(self, instrument): arrCurrency = instrument.split("-") if len(arrCurrency) == 2: baseCurrency = arrCurrency[0] quoteCurrency = arrCurrency[1] else: raise ValueError(f"{self.exName}: invalid instrument: {instrument}") return f'{baseCurrency}_{quoteCurrency}' def callUnsignedAPI(self, httpMethod, path, query="", params={}): return self._httpRequest(httpMethod, path, query, params) def callSignedAPI(self, httpMethod, path, query="", params={}): strTime = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' if httpMethod == "GET": jsonStr = json.dumps(params, separators=(',', ':')) if len(params) > 0 else "" else: jsonStr = json.dumps(params, separators=(',', ':')) if len(params) > 0 else "{}" message = f'{strTime}{httpMethod}{path}{jsonStr}' if httpMethod == "GET" and query != "": message = f'{strTime}{httpMethod}{path}?{query}{jsonStr}' mac = hmac.new(bytes(self._secretKey, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256') signature = base64.b64encode(mac.digest()) headers = {} if self._x_simulated_trading == 1: headers["x-simulated-trading"] = str(self._x_simulated_trading) headers["OK-ACCESS-KEY"] = self._accessKey headers["OK-ACCESS-PASSPHRASE"] = self._passphrase headers["OK-ACCESS-TIMESTAMP"] = strTime headers["OK-ACCESS-SIGN"] = signature return self._httpRequest(httpMethod, path, query, params, headers) # Encapsulates requests to the exchange API. def GetTicker(self, symbol): """ GET /api/v5/market/ticker , param: instId """ baseCurrency, quoteCurrency = self.getCurrencys(symbol) if baseCurrency == "" or quoteCurrency == "": return {"error": "invalid symbol"} path = "/api/v5/market/ticker" query = f'instId={baseCurrency}-{quoteCurrency}' data = self.callUnsignedAPI("GET", path, query=query) if "error" in data.keys() and "data" not in data.keys(): return data ret_data = {} if data["code"] != "0" or not isinstance(data["data"], list): return {"error": json.dumps(data, ensure_ascii=False)} for tick in data["data"]: if not all(k in tick for k in ("instId", "bidPx", "askPx", "high24h", "low24h", "vol24h", "ts")): return {"error": json.dumps(data, ensure_ascii=False)} ret_data["symbol"] = self.getSymbol(tick["instId"]) ret_data["buy"] = tick["bidPx"] ret_data["sell"] = tick["askPx"] ret_data["high"] = tick["high24h"] ret_data["low"] = tick["low24h"] ret_data["open"] = tick["open24h"] ret_data["last"] = tick["last"] ret_data["vol"] = tick["vol24h"] ret_data["time"] = tick["ts"] return {"data": ret_data, "raw": data} def GetDepth(self, symbol): """ TODO: Implementation code """ # Mock data for testing. ret_data = { "time" : 1500793319499, "asks" : [ [1000, 0.5], [1001, 0.23], [1004, 2.1] ], "bids" : [ [999, 0.25], [998, 0.8], [995, 1.4] ] } return {"data": ret_data} def GetTrades(self, symbol): """ TODO: Implementation code """ # Mock data for testing. ret_data = [ { "id": 12232153, "time" : 1529919412968, "price": 1000, "amount": 0.5, "type": "buy", }, { "id": 12545664, "time" : 1529919412900, "price": 1001, "amount": 1, "type": "sell", } ] return {"data": ret_data} def GetRecords(self, symbol, period, limit): """ TODO: Implementation code """ # Mock data for testing. ret_data = [ [1500793319, 1.1, 2.2, 3.3, 4.4, 5.5], [1500793259, 1.01, 2.02, 3.03, 4.04, 5.05], ] return {"data": ret_data} def GetMarkets(self): """ TODO: Implementation code """ ret_data = {} return {"data": ret_data} def GetTickers(self): """ TODO: Implementation code """ ret_data = {} return {"data": ret_data} def GetAccount(self): """ GET /api/v5/account/balance """ path = "/api/v5/account/balance" data = self.callSignedAPI("GET", path) ret_data = [] if data["code"] != "0" or "data" not in data or not isinstance(data["data"], list): return {"error": json.dumps(data, ensure_ascii=False)} for ele in data["data"]: if "details" not in ele or not isinstance(ele["details"], list): return {"error": json.dumps(data, ensure_ascii=False)} for detail in ele["details"]: asset = {"currency": detail["ccy"], "free": detail["availEq"], "frozen": detail["ordFrozen"]} if detail["availEq"] == "": asset["free"] = detail["availBal"] ret_data.append(asset) return {"data": ret_data, "raw": data} def GetAssets(self): """ TODO: Implementation code """ # Mock data for testing. ret_data = [ {"currency": "TUSD", "free": "3000", "frozen": "0"}, {"currency": "BTC", "free": "0.2482982056277609", "frozen": "0"} ] return {"data": ret_data} def CreateOrder(self, symbol, side, price, amount): """ TODO: Implementation code """ # Mock data for testing. ret_data = { "id": "BTC-USDT,123456" } return {"data": ret_data} def GetOrders(self, symbol): """ GET /api/v5/trade/orders-pending instType SPOT instId after limit """ baseCurrency, quoteCurrency = self.getCurrencys(symbol) if baseCurrency == "" or quoteCurrency == "": return {"error": "invalid symbol"} path = "/api/v5/trade/orders-pending" after = "" limit = 100 ret_data = [] while True: query = f"instType=SPOT&instId={baseCurrency}-{quoteCurrency}&limit={limit}" if after != "": query = f"instType=SPOT&instId={baseCurrency}-{quoteCurrency}&limit={limit}&after={after}" data = self.callSignedAPI("GET", path, query=query) if data["code"] != "0" or not isinstance(data["data"], list): return {"error": json.dumps(data, ensure_ascii=False)} for ele in data["data"]: order = {} order["id"] = f'{ele["instId"]},{ele["ordId"]}' order["symbol"] = f'{baseCurrency}-{quoteCurrency}' order["amount"] = ele["sz"] order["price"] = ele["px"] order["deal_amount"] = ele["accFillSz"] order["avg_price"] = 0 if ele["avgPx"] == "" else ele["avgPx"] order["type"] = "buy" if ele["side"] == "buy" else "sell" order["state"] = "pending" ret_data.append(order) after = ele["ordId"] if len(data["data"]) < limit: break return {"data": ret_data} def GetOrder(self, orderId): """ TODO: Implementation code """ # Mock data for testing. ret_data = { "id": "ETH-USDT,123456", "symbol": "ETH_USDT", "amount": 0.15, "price": 1002, "status": "pending", "deal_amount": 0, "type": "buy", "avg_price": 0, } return {"data": ret_data} def GetHistoryOrders(self, symbol, since, limit): """ TODO: Implementation code """ # Mock data for testing. ret_data = [ { "id": "ETH-USDT,123456", "symbol": "ETH_USDT", "amount": 0.25, "price": 1005, "deal_amount": 0, "avg_price": 1000, "type": "buy", "status": "filled" } ] return {"data": ret_data} def CancelOrder(self, orderId): """ TODO: Implementation code """ # Mock data for testing. ret_data = True return {"data": ret_data} def IO(self, httpMethod, path, params={}): if httpMethod == "GET": query = urllib.parse.urlencode(params) data = self.callSignedAPI(httpMethod, path, query=query) else: data = self.callSignedAPI(httpMethod, path, params=params) if data["code"] != "0": return {"error": json.dumps(data, ensure_ascii=False)} return {"data": data} class HttpServer(http.server.SimpleHTTPRequestHandler): def __init__(self, *args, **kwargs): self.request_body = None self.request_path = None super().__init__(*args, **kwargs) def log_message(self, format, *args): return def _sendResponse(self, body): self.send_response(200) self.send_header('Content-type', 'application/json; charset=utf-8') self.end_headers() self.wfile.write(json.dumps(body).encode('utf-8')) def do_GET(self): # The FMZ.COM custom protocol only send GET method request self._sendResponse({"error": "not support GET method."}) def do_POST(self): """ Returns: json: success, {"data": ...} json: error, {"error": ...} """ contentLen = int(self.headers['Content-Length']) self.request_body = self.rfile.read(contentLen) self.request_path = self.path exName = self.request_path.lstrip("/") # Print the request received from the FMZ.COM robot print(f"--------- request received from the FMZ.COM robot: --------- \n {self.requestline} | Body: {self.request_body} | Headers: {self.headers} \n") try: data = json.loads(self.request_body) except json.JSONDecodeError: data = {"error": self.request_body.decode('utf-8')} self._sendResponse(data) return # fault tolerant if not all(k in data for k in ("access_key", "secret_key", "method", "params")): data = {"error": "missing required parameters"} self._sendResponse(data) return respData = {} accessKey = data["access_key"] secretKey = data["secret_key"] method = data["method"] params = data["params"] exchange = ProtocolFactory.createExWrapper("https://www.okx.com", accessKey, secretKey, exName) if method == "ticker": symbol = str(params["symbol"]).upper() respData = exchange.GetTicker(symbol) elif method == "depth": symbol = str(params["symbol"]).upper() respData = exchange.GetDepth(symbol) elif method == "trades": symbol = str(params["symbol"]).upper() respData = exchange.GetTrades(symbol) elif method == "records": symbol = str(params["symbol"]).upper() period = int(params["period"]) limit = int(params["limit"]) respData = exchange.GetRecords(symbol, period, limit) elif method == "accounts": respData = exchange.GetAccount() elif method == "assets": respData = exchange.GetAssets() elif method == "trade": amount = float(params["amount"]) price = float(params["price"]) symbol = str(params["symbol"]) tradeType = str(params["type"]) respData = exchange.CreateOrder(symbol, tradeType, price, amount) elif method == "orders": symbol = str(params["symbol"]).upper() respData = exchange.GetOrders(symbol) elif method == "order": orderId = str(params["id"]) respData = exchange.GetOrder(orderId) elif method == "historyorders": symbol = str(params["symbol"]) since = int(params["since"]) limit = int(params["limit"]) respData = exchange.GetHistoryOrders(symbol, since, limit) elif method == "cancel": orderId = str(params["id"]) respData = exchange.CancelOrder(orderId) elif method[:6] == "__api_": respData = exchange.IO(self.headers["Http-Method"], method[6:], params) else: respData = {"error": f'invalid method: {method}'} # Print the response to send to FMZ.COM robot print(f"response to send to FMZ.COM robot: {respData} \n") self._sendResponse(respData) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run a FMZ.COM custom protocol plugin.") parser.add_argument("--port", type=int, default=6666, help="Port to run the server on.") parser.add_argument("--address", type=str, default="localhost", help="Address to bind the server to.") args = parser.parse_args() with socketserver.TCPServer((args.address, args.port), HttpServer) as httpd: print(f"running... {args.address}:{args.port}", "\n") httpd.serve_forever()
Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)