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

img

Platform Perdagangan Kuantitatif Inventor mendukung banyak bursa mata uang kripto dan merangkum bursa utama di pasar. Namun, masih banyak bursa yang tidak dikemas. Bagi pengguna yang perlu menggunakan bursa ini, mereka dapat mengaksesnya melalui protokol universal yang dikuantifikasi oleh penemunya. Tidak terbatas pada pertukaran mata uang kripto, apa punRESTPersetujuan atauFIXPlatform perjanjian juga dapat diakses.

Artikel ini akanRESTMengambil akses protokol sebagai contoh, dijelaskan cara menggunakan protokol umum Platform Perdagangan Kuantitatif Inventor untuk merangkum dan mengakses API Bursa OKX. Kecuali dinyatakan lain, artikel ini mengacu pada protokol umum REST.

  • Alur kerja protokol umum adalah:
    Proses permintaan: Instansi strategi yang berjalan pada kustodian -> Program protokol umum -> API Exchange
    Proses respons: API Exchange -> Program protokol umum -> Instans strategi yang berjalan pada kustodian

1. Konfigurasikan pertukaran

Halaman untuk mengonfigurasikan pertukaran pada Platform Perdagangan Kuantitatif Inventor:

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

img

  • Pilih protokol: Pilih "Protokol Umum".
  • Alamat layanan: Program protokol umum pada dasarnya adalah layanan RPC
    Oleh karena itu, penting untuk menentukan alamat layanan dan port dengan jelas saat mengonfigurasi pertukaran. Jadi di托管者上运行的策略实例 -> 通用协议程序Selama proses berlangsung, host mengetahui di mana mengakses program protokol umum.
    Misalnya:http://127.0.0.1:6666/OKXBiasanya, program protokol umum dan host dijalankan pada perangkat yang sama (server), sehingga alamat layanan ditulis sebagai mesin lokal (localhost), dan port dapat berupa port yang tidak ditempati oleh sistem.
  • Access Key:
    托管者上运行的策略实例 -> 通用协议程序Informasi konfigurasi pertukaran yang dikirimkan selama proses.
  • Secret Key:
    托管者上运行的策略实例 -> 通用协议程序Informasi konfigurasi pertukaran yang dikirimkan selama proses.
  • Label:
    Label objek pertukaran pada Platform Perdagangan Kuantitatif Inventor digunakan untuk mengidentifikasi objek pertukaran tertentu.

Tangkapan layar konfigurasi plug-in OKX yang diungkapkan dalam artikel adalah sebagai berikut:

img

Informasi konfigurasi kunci rahasia bursa OKX:

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

2. Penerapan kustodian dan program protokol universal (plugin)

    1. Tuan rumah
      Untuk menjalankan strategi real-time apa pun pada Inventor Quantitative Trading Platform, Anda harus menggunakan kustodian. Untuk penggunaan kustodian secara spesifik, silakan lihat tutorial platform, yang tidak akan diulang di sini.
    1. Program protokol umum (plugin)
      Host dan protokol universal biasanya digunakan pada perangkat yang sama. Program protokol universal (layanan) dapat ditulis dalam bahasa apa pun. Artikel ini ditulis dalam Python3. Sama seperti menjalankan program Python lainnya, Anda dapat mengeksekusinya secara langsung (membuat berbagai konfigurasi lingkungan Python terlebih dahulu).
      Tentu saja, FMZ juga mendukung jalannya program Python, dan protokol umum ini juga dapat dijalankan sebagai disk nyata untuk menyediakan platform perdagangan kuantitatif milik penemu dengan dukungan akses API bursa tanpa paket.
      Setelah program protokol umum berjalan, mulailah memantau:http://127.0.0.1:6666Dalam program protokol umum, jalur tertentu dapat ditentukan, misalnya/OKXuntuk diproses.

3. Permintaan instans strategi fungsi API FMZ

Ketika fungsi API platform (FMZ) dipanggil dalam strategi, Program Protokol Universal menerima permintaan dari kustodian. Anda juga dapat menguji menggunakan alat debugging platform, misalnya:

Halaman alat debugging:

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

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

Panggilanexchange.GetTicker()Fungsi, 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 di platform "Konfigurasi Pertukaran" di atas
  • secret_key: Kunci pertukaran yang dikonfigurasikan di platform "Konfigurasi Pertukaran" di atas
  • metode: terkait dengan antarmuka pemanggilan dalam strategi, pemanggilanexchange.GetTicker()jam,methodYaituticker
  • nonce: Cap waktu saat permintaan terjadi.
  • params: Parameter yang terkait dengan panggilan antarmuka dalam kebijakan.exchange.GetTicker()Saat memanggil, parameter yang relevan adalah:{"symbol":"LTC_USDT"}

4. Akses program protokol umum ke antarmuka pertukaran

Ketika program protokol umum menerima permintaan dari kustodian, ia dapat memperoleh informasi seperti fungsi API platform (termasuk informasi parameter) yang diminta oleh strategi, kunci pertukaran, dll. berdasarkan informasi yang dibawa dalam permintaan.

Berdasarkan informasi ini, program protokol umum dapat mengakses antarmuka pertukaran untuk mendapatkan data yang diperlukan atau melakukan operasi tertentu.

Biasanya antarmuka pertukaran memiliki metode seperti GET/POST/PUT/DELETE, yang terbagi menjadi antarmuka publik dan antarmuka pribadi.

  • Antarmuka publik: antarmuka yang tidak memerlukan verifikasi tanda tangan dan diminta secara langsung dalam program protokol umum.
  • Antarmuka pribadi: antarmuka yang memerlukan verifikasi tanda tangan. Tanda tangan perlu diimplementasikan dalam program protokol umum untuk meminta antarmuka API dari pertukaran ini.

Program protokol umum menerima data respons antarmuka pertukaran, memprosesnya lebih lanjut, dan menyusunnya menjadi data yang diharapkan oleh kustodian (dijelaskan di bawah).
Lihat pertukaran spot OKX, implementasi kelas CustomProtocolOKX dalam contoh protokol umum PythonGetTickerGetAccountDan fungsi lainnya.

5. Program protokol umum menanggapi kustodian

Saat program protokol umum mengakses antarmuka API bursa, melakukan operasi tertentu, atau memperoleh data tertentu, ia perlu memberikan umpan balik hasilnya kepada kustodian.

Data yang diberikan kembali ke kustodian bervariasi menurut antarmuka yang dipanggil oleh strategi, dan pertama-tama dibagi menjadi dua kategori:

  • Program protokol umum berhasil memanggil antarmuka pertukaran:

    json
    { "data": null, // "data" can be of any type "raw": null // "raw" can be of any type }
    • data: Struktur spesifik bidang ini sama seperti pada permintaan yang diterima oleh program protokol umum.methodBerikut ini adalah daftar semua antarmuka yang digunakan untuk membangun struktur data yang dikembalikan oleh fungsi API platform FMZ.
    • Mentah: Bidang ini dapat digunakan untuk meneruskan data mentah dari respons API pertukaran, misalnyaexchange.GetTicker()Struktur Ticker yang dikembalikan oleh fungsi tersebut memiliki informasi berikut yang tercatat di bidang Info dari struktur Ticker:rawLapangan dandataData lapangan; beberapa fungsi API platform tidak memerlukan data ini.
  • Program protokol umum gagal memanggil antarmuka pertukaran (kesalahan bisnis, kesalahan jaringan, dll.)

    json
    { "error": "" // "error" contains an error message as a string }
    • kesalahan: informasi kesalahan, yang akan ditampilkan dalam log kesalahan di area log disk nyata platform (FMZ), alat debugging, dan halaman lainnya.

Menunjukkan data respons protokol umum yang diterima oleh program kebijakan:

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 adalah proses singkat tentang bagaimana program protokol umum berpartisipasi dalam mengakses API pertukaran (FMZ yang tidak dikemas). Proses ini hanya menjelaskan cara memanggil alat debugging platform (FMZ).exchange.GetTicker()Proses fungsi. Berikutnya, detail interaksi semua fungsi API platform akan dijelaskan secara rinci.

Platform ini merangkum fungsi-fungsi umum dari berbagai bursa dan menyatukannya ke dalam fungsi tertentu, seperti fungsi GetTicker, yang meminta informasi pasar terkini dari suatu produk tertentu. Ini pada dasarnya adalah API yang dimiliki semua bursa. Jadi ketika antarmuka API yang dienkapsulasi platform diakses dalam contoh strategi, kustodian akan mengirimkan permintaan ke plug-in "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" }

Saat memanggil fungsi API yang dienkapsulasi platform penemu yang berbeda dalam strategi (seperti GetTicker), format permintaan yang dikirim oleh kustodian ke protokol umum juga akan berbeda. Data (JSON) di badan hanya berbeda dimethodDanparams. Saat merancang protokol umum,methodAnda dapat melakukan operasi spesifik berdasarkan konten. Berikut ini adalah skenario permintaan-respons untuk semua antarmuka.

Pertukaran Spot

Misalnya, pasangan perdagangan saat ini adalah:ETH_USDTSaya tidak akan membahas rinciannya nanti. Data yang diharapkan kustodian agar ditanggapi oleh protokol umum sebagian besar ditulis dalam bidang data, dan bidang mentah juga dapat ditambahkan untuk merekam data asli dari antarmuka pertukaran.

  • GetTicker

    • bidang metode: "ticker"

    • bidang params:

      json
      {"symbol":"ETH_USDT"}
    • Data yang diharapkan host dalam respons 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

    • bidang metode: "kedalaman"

    • bidang params:

      json
      {"limit":"30","symbol":"ETH_USDT"}
    • Data yang diharapkan host dalam respons 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

    • bidang metode: "perdagangan"

    • bidang params:

      json
      {"symbol":"eth_usdt"}
    • Data yang diharapkan host dalam respons 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

    • bidang metode: "catatan"

    • bidang params:

      json
      { "limit":"500", "period":"60", // 60分钟 "symbol":"ETH_USDT" }
    • Data yang diharapkan host dalam respons 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
    Akan dilaksanakan

    • bidang metode: ""

    • bidang params:

      json
      {}
    • Data yang diharapkan host dalam respons protokol umum:

      json
      {}
  • GetTickers
    Akan dilaksanakan

    • bidang metode: ""

    • bidang params:

      json
      {}
    • Data yang diharapkan host dalam respons protokol umum:

      json
      {}
  • GetAccount

    • bidang metode: "akun"

    • bidang params:

      json
      {}
    • Data yang diharapkan host dalam respons protokol umum:

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

    • bidang metode: "aset"

    • bidang params:

      json
      {}
    • Data yang diharapkan host dalam respons protokol umum:

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

    • bidang metode: "perdagangan"

    • bidang params:

      json
      {"amount":"0.1","price":"1000","symbol":"BTC_USDT","type":"buy"}
    • Data yang diharapkan host dalam respons protokol umum:

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

    • bidang metode: "pesanan"

    • bidang params:

      json
      {"symbol":"ETH_USDT"}
    • Data yang diharapkan host dalam respons 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

    • bidang metode: "pesanan"

    • bidang params:

      json
      { "id":"ETH-USDT,123456", // 策略中调用:exchange.GetOrder("ETH-USDT,123456") "symbol":"ETH_USDT" }
    • Data yang diharapkan host dalam respons 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

    • bidang metode: "historyorders"

    • bidang params:

      json
      {"limit":0,"since":0,"symbol":"ETH_USDT"}
    • Data yang diharapkan host dalam respons 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

    • bidang metode: "batal"

    • bidang params:

      json
      {"id":"ETH-USDT,123456","symbol":"ETH_USDT"}
    • Data yang diharapkan host dalam respons protokol umum:

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

    Fungsi exchange.IO digunakan untuk mengakses langsung antarmuka pertukaran. Misalnya, kami menggunakanGET /api/v5/trade/orders-pending, 参数:instType=SPOT,instId=ETH-USDTMisalnya.

    javascript
    // 策略实例中调用 exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT&instId=ETH-USDT")
    • bidang metode:"__api_/api/v5/trade/orders-pending"Bidang metode dimulai dengan _api, yang menunjukkan bahwa ini dipicu oleh panggilan fungsi exchange.IO dalam contoh strategi.

    • bidang params:

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

      json
      { "data": {"code": "0", "data": [], "msg": ""} // data属性值为交易所API:GET /api/v5/trade/orders-pending 应答的数据 }
  • lainnya
    Fungsi API Platform Inventor lainnya yang digunakan dalam contoh strategi, seperti:
    exchange.Go()exchange.GetRawJSON()Fungsi seperti ini tidak perlu dienkapsulasi, dan metode pemanggil serta fungsionalitasnya tetap tidak berubah.

Bursa Berjangka

Selain mendukung semua fungsi bursa spot, bursa berjangka juga memiliki beberapa fungsi API yang unik untuk bursa berjangka.

Akan dilaksanakan

  • GetPositions
  • SetMarginLevel
  • GetFundings

Versi Python dari contoh protokol umum

Protokol umum REST - akses ke antarmuka REST API bursa OKX dan enkapsulasinya sebagai objek bursa spot.
Menerapkan antarmuka umum untuk enkapsulasi data permintaan dan respons.
Menerapkan tanda tangan antarmuka pribadi, enkapsulasi data permintaan dan respons.
Contoh ini terutama untuk pengujian dan pembelajaran. Antarmuka lainnya menggunakan data simulasi untuk langsung merespons host untuk pengujian.

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)