4
پر توجہ دیں
1076
پیروکار

موجد مقداری تجارتی پلیٹ فارم جنرل پروٹوکول رسائی گائیڈ

میں تخلیق کیا: 2024-10-29 14:37:56, تازہ کاری: 2024-11-12 21:58:55
comments   0
hits   207

[TOC]

موجد مقداری تجارتی پلیٹ فارم جنرل پروٹوکول رسائی گائیڈ

موجد مقداری تجارتی پلیٹ فارم بہت سے کریپٹو کرنسی ایکسچینجز کو سپورٹ کرتا ہے اور مارکیٹ میں مرکزی دھارے کے تبادلے کو سمیٹتا ہے۔ تاہم، ابھی بھی بہت سے ایکسچینجز ہیں جو پیک نہیں کیے گئے ہیں، جن صارفین کو ان ایکسچینجز کو استعمال کرنے کی ضرورت ہے، وہ ان تک رسائی حاصل کر سکتے ہیں جو کہ موجد کے ذریعہ طے شدہ یونیورسل پروٹوکول ہے۔ کرپٹو کرنسی ایکسچینج تک محدود نہیں، کوئی بھیRESTمعاہدہ یاFIXمعاہدے کے پلیٹ فارم تک بھی رسائی حاصل کی جا سکتی ہے۔

یہ مضمون کرے گاRESTپروٹوکول تک رسائی کو ایک مثال کے طور پر لیتے ہوئے، یہ بتاتا ہے کہ OKX ایکسچینج کے API کو سمیٹنے اور اس تک رسائی حاصل کرنے کے لیے Inventor Quantitative Trading Platform کے عمومی پروٹوکول کو کیسے استعمال کیا جائے۔ جب تک کہ دوسری صورت میں وضاحت نہ کی گئی ہو، یہ مضمون REST جنرل پروٹوکول کا حوالہ دیتا ہے۔

  • عام پروٹوکول کا ورک فلو یہ ہے: درخواست کا عمل: محافظ پر چلنے والی حکمت عملی مثال -> جنرل پروٹوکول پروگرام -> ایکسچینج API رسپانس کا عمل: ایکسچینج API -> جنرل پروٹوکول پروگرام -> سٹریٹیجی مثال کسٹوڈین پر چل رہی ہے

1. ایکسچینج کو ترتیب دیں۔

موجد مقداری تجارتی پلیٹ فارم پر تبادلے کو ترتیب دینے کا صفحہ:

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

موجد مقداری تجارتی پلیٹ فارم جنرل پروٹوکول رسائی گائیڈ

  • پروٹوکول منتخب کریں: “جنرل پروٹوکول” کو منتخب کریں۔
  • سروس کا پتہ: جنرل پروٹوکول پروگرام بنیادی طور پر ایک RPC سروس ہے۔ لہذا، ایکسچینج کو ترتیب دیتے وقت سروس کا پتہ اور پورٹ واضح طور پر بتانا ضروری ہے۔ تو میں托管者上运行的策略实例 -> 通用协议程序عمل کے دوران، میزبان جانتا ہے کہ عام پروٹوکول پروگرام تک کہاں رسائی حاصل کرنی ہے۔ مثال کے طور پر:http://127.0.0.1:6666/OKXعام طور پر، مشترکہ پروٹوکول پروگرام اور میزبان ایک ہی ڈیوائس (سرور) پر چلائے جاتے ہیں، اس لیے سروس ایڈریس کو لوکل مشین (لوکل ہوسٹ) کے طور پر لکھا جاتا ہے، اور پورٹ ایک ایسی بندرگاہ ہو سکتی ہے جس پر سسٹم کا قبضہ نہ ہو۔
  • Access Key: 托管者上运行的策略实例 -> 通用协议程序تبادلے کی ترتیب کی معلومات اس عمل کے دوران گزر گئی۔
  • Secret Key: 托管者上运行的策略实例 -> 通用协议程序تبادلے کی ترتیب کی معلومات اس عمل کے دوران گزر گئی۔
  • لیبل: انوینٹر کوانٹیٹیو ٹریڈنگ پلیٹ فارم پر ایکسچینج آبجیکٹ کا لیبل کسی مخصوص ایکسچینج آبجیکٹ کی شناخت کے لیے استعمال ہوتا ہے۔

مضمون میں ظاہر کردہ OKX پلگ ان کنفیگریشن کا اسکرین شاٹ درج ذیل ہے:

موجد مقداری تجارتی پلیٹ فارم جنرل پروٹوکول رسائی گائیڈ

OKX تبادلہ خفیہ کلیدی ترتیب کی معلومات:

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

2. نگران کی تعیناتی اور یونیورسل پروٹوکول پروگرام (پلگ ان)

    1. میزبان انوینٹر کوانٹیٹیو ٹریڈنگ پلیٹ فارم پر کسی بھی حقیقی وقت کی حکمت عملی کو چلانے کے لیے، آپ کو ایک نگران تعینات کرنا چاہیے، براہ کرم پلیٹ فارم ٹیوٹوریل کا حوالہ دیں، جسے یہاں دہرایا نہیں جائے گا۔
    1. جنرل پروٹوکول پروگرام (پلگ ان) ہوسٹ اور یونیورسل پروٹوکول کو عام طور پر ایک ہی ڈیوائس پر لگایا جاتا ہے۔ یہ مضمون Python3 میں لکھا جا سکتا ہے۔ کسی بھی Python پروگرام کو چلانے کی طرح، آپ اسے براہ راست انجام دے سکتے ہیں (پائیتھون ماحول کی مختلف کنفیگریشنز پہلے سے بنائیں)۔ بلاشبہ، FMZ Python پروگراموں کو چلانے کی بھی حمایت کرتا ہے، اور یہ عام پروٹوکول ایک حقیقی ڈسک کے طور پر چلایا جا سکتا ہے تاکہ موجد کے مقداری تجارتی پلیٹ فارم کو بغیر پیکج شدہ ایکسچینج API تک رسائی کے لیے تعاون فراہم کیا جا سکے۔ عام پروٹوکول پروگرام چلنے کے بعد، نگرانی شروع کریں:http://127.0.0.1:6666عام پروٹوکول پروگرام میں، مخصوص راستے بتائے جا سکتے ہیں، مثال کے طور پر/OKXعملدرآمد کیا جائے.

3. حکمت عملی مثال FMZ API فنکشن کی درخواست کرتی ہے۔

جب حکمت عملی میں (FMZ) پلیٹ فارم API فنکشن کو کال کیا جاتا ہے، تو یونیورسل پروٹوکول پروگرام کو کسٹوڈین سے ایک درخواست موصول ہوتی ہے۔ آپ پلیٹ فارم کے ڈیبگنگ ٹولز کا استعمال کرتے ہوئے بھی ٹیسٹ کر سکتے ہیں، مثال کے طور پر:

ڈیبگنگ ٹولز کا صفحہ:

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

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

کال کریں۔exchange.GetTicker()فنکشن، جنرل پروٹوکول پروگرام کو درخواست موصول ہوتی ہے:

POST /OKX HTTP/1.1 
{
    "access_key":"xxx",
    "method":"ticker",
    "nonce":1730275031047002000,
    "params":{"symbol":"LTC_USDT"},
    "secret_key":"xxx"
}
  • access_key: اوپر دیئے گئے پلیٹ فارم “کنفیگر ایکسچینج” میں کنفیگر کردہ ایکسچینج کلید
  • secret_key: اوپر پلیٹ فارم “کنفیگر ایکسچینج” میں کنفیگر کردہ ایکسچینج کلید
  • طریقہ: حکمت عملی میں کالنگ انٹرفیس سے متعلق، کالنگexchange.GetTicker()گھنٹہmethodیعنیticker
  • nonce: ٹائم اسٹیمپ جب درخواست ہوئی تھی۔
  • params: پالیسی میں انٹرفیس کال سے متعلق پیرامیٹرز۔exchange.GetTicker()کال کرتے وقت، متعلقہ پیرامیٹرز یہ ہیں:{"symbol":"LTC_USDT"}

4. جنرل پروٹوکول پروگرام ایکسچینج انٹرفیس تک رسائی

جب عام پروٹوکول پروگرام کو کسٹوڈین کی طرف سے کوئی درخواست موصول ہوتی ہے، تو وہ معلومات حاصل کر سکتا ہے جیسے کہ پلیٹ فارم API فنکشن (بشمول پیرامیٹر کی معلومات) حکمت عملی کے ذریعے درخواست کی گئی، تبادلے کی کلید وغیرہ۔ درخواست میں دی گئی معلومات کی بنیاد پر۔

اس معلومات کی بنیاد پر، جنرل پروٹوکول پروگرام مطلوبہ ڈیٹا حاصل کرنے یا کچھ آپریشنز کرنے کے لیے ایکسچینج انٹرفیس تک رسائی حاصل کر سکتا ہے۔

عام طور پر ایکسچینج انٹرفیس میں GET/POST/PUT/DELETE جیسے طریقے ہوتے ہیں، جنہیں عوامی انٹرفیس اور نجی انٹرفیس میں تقسیم کیا جاتا ہے۔

  • عوامی انٹرفیس: ایک انٹرفیس جس میں دستخطی تصدیق کی ضرورت نہیں ہوتی ہے اور اس کی براہ راست درخواست ایک عام پروٹوکول پروگرام میں کی جاتی ہے۔
  • پرائیویٹ انٹرفیس: ایک انٹرفیس جس میں دستخط کی تصدیق کی ضرورت ہوتی ہے ان ایکسچینجز کے API انٹرفیس کی درخواست کرنے کے لیے دستخط کو عام پروٹوکول پروگرام میں لاگو کرنے کی ضرورت ہوتی ہے۔

جنرل پروٹوکول پروگرام ایکسچینج انٹرفیس رسپانس ڈیٹا حاصل کرتا ہے، اس پر مزید کارروائی کرتا ہے، اور اسے نگران کے متوقع ڈیٹا میں بناتا ہے (ذیل میں بیان کیا گیا ہے)۔ OKX سپاٹ ایکسچینج، Python جنرل پروٹوکول کی مثال میں CustomProtocolOKX کلاس کا نفاذ دیکھیںGetTickerGetAccountاور دیگر افعال۔

5. جنرل پروٹوکول پروگرام کسٹوڈین کو ڈیٹا کا جواب دیتا ہے۔

جب عام پروٹوکول پروگرام ایکسچینج کے API انٹرفیس تک رسائی حاصل کرتا ہے، کچھ آپریشن کرتا ہے یا کچھ ڈیٹا حاصل کرتا ہے، تو اسے نتائج کو محافظ کو واپس کرنے کی ضرورت ہوتی ہے۔

نگہبان کو دیا گیا ڈیٹا حکمت عملی کے ذریعے بلائے گئے انٹرفیس کے مطابق مختلف ہوتا ہے، اور اسے پہلے دو قسموں میں تقسیم کیا جاتا ہے:

  • جنرل پروٹوکول پروگرام کامیابی کے ساتھ ایکسچینج انٹرفیس کو کال کرتا ہے:
  {
      "data": null,  // "data" can be of any type 
      "raw": null    // "raw" can be of any type 
  }
  • ڈیٹا: اس فیلڈ کا مخصوص ڈھانچہ وہی ہے جو عام پروٹوکول پروگرام کے ذریعے موصول ہونے والی درخواست میں ہے۔methodذیل میں FMZ پلیٹ فارم API فنکشن کے ذریعے واپس کیے گئے ڈیٹا ڈھانچے کی تعمیر کے لیے استعمال ہونے والے تمام انٹرفیسز کی فہرست ہے۔

  • Raw: اس فیلڈ کو ایکسچینج API جواب کے خام ڈیٹا میں منتقل کرنے کے لیے استعمال کیا جا سکتا ہے، مثال کے طور پرexchange.GetTicker()فنکشن کے ذریعے لوٹائے گئے ٹکر ڈھانچے میں درج ذیل معلومات ٹکر ڈھانچے کے انفارمیشن فیلڈ میں درج ہوتی ہیں۔rawفیلڈز اورdataفیلڈ کا ڈیٹا؛ کچھ پلیٹ فارم API فنکشنز کو اس ڈیٹا کی ضرورت نہیں ہے۔

  • جنرل پروٹوکول پروگرام ایکسچینج انٹرفیس کو کال کرنے میں ناکام رہا (کاروباری غلطی، نیٹ ورک کی خرابی، وغیرہ)

  {
      "error": ""    // "error" contains an error message as a string
  }
  • ایرر: ایرر کی معلومات، جو (FMZ) پلیٹ فارم ریئل ڈسک، ڈیبگنگ ٹول اور دیگر صفحات کے لاگ ایریا میں ایرر لاگ میں ظاہر ہوگی۔

پالیسی پروگرام کو موصول ہونے والے عمومی پروٹوکول جوابی ڈیٹا کو ظاہر کرتا ہے:

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

موجد مقداری تجارتی پلیٹ فارم جنرل پروٹوکول رسائی گائیڈ

6. عام پروٹوکول میں ڈیٹا ڈھانچہ کا معاہدہ

مندرجہ بالا ایک مختصر عمل ہے کہ کس طرح عام پروٹوکول پروگرام (FMZ unpackaged) ایکسچینج API تک رسائی حاصل کرتا ہے یہ عمل صرف اس بات کی وضاحت کرتا ہے کہ (FMZ) پلیٹ فارم ڈیبگنگ ٹول کو کیسے کال کرنا ہے۔exchange.GetTicker()فنکشن کا عمل۔ اس کے بعد، تمام پلیٹ فارم API فنکشنز کے تعامل کی تفصیلات کو تفصیل سے بیان کیا جائے گا۔

پلیٹ فارم مختلف ایکسچینجز کے مشترکہ افعال کو سمیٹتا ہے اور انہیں ایک مخصوص فنکشن میں یکجا کرتا ہے، جیسے کہ گیٹ ٹِکر فنکشن، جو کسی خاص پروڈکٹ کی موجودہ مارکیٹ کی معلومات کی درخواست کرتا ہے، یہ بنیادی طور پر ایک API ہے جو تمام ایکسچینجز کے پاس ہے۔ لہذا جب حکمت عملی کی مثال میں پلیٹ فارم encapsulated API انٹرفیس تک رسائی حاصل کی جاتی ہے، تو نگران “یونیورسل پروٹوکول” پلگ ان (اوپر مذکور) کو ایک درخواست بھیجے گا۔

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

حکمت عملی میں مختلف موجد پلیٹ فارم encapsulated API فنکشنز کو کال کرتے وقت (جیسے GetTicker)، نگران کی طرف سے جنرل پروٹوکول کو بھیجی جانے والی درخواست کی شکل بھی مختلف ہوگی۔ جسم میں ڈیٹا (JSON) صرف اس میں مختلف ہے۔methodاورparams. عام پروٹوکول کو ڈیزائن کرتے وقت،methodآپ مواد کی بنیاد پر مخصوص آپریشن کر سکتے ہیں۔ مندرجہ ذیل تمام انٹرفیس کے لیے درخواست کے جواب کے منظرنامے ہیں۔

اسپاٹ ایکسچینج

مثال کے طور پر، موجودہ تجارتی جوڑی ہے:ETH_USDT، میں بعد میں تفصیلات میں نہیں جاؤں گا۔ وہ ڈیٹا جس کا نگران عام پروٹوکول سے جواب دینے کی توقع کرتا ہے وہ بنیادی طور پر ڈیٹا فیلڈ میں لکھا جاتا ہے، اور ایکسچینج انٹرفیس کے اصل ڈیٹا کو ریکارڈ کرنے کے لیے ایک خام فیلڈ بھی شامل کیا جا سکتا ہے۔

  • GetTicker

    • طریقہ کا میدان: “ٹکر”
    • پیرامز فیلڈ:
    {"symbol":"ETH_USDT"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "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

    • طریقہ کا میدان: “گہرائی”
    • پیرامز فیلڈ:
    {"limit":"30","symbol":"ETH_USDT"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "data" : {
            "time" : 1500793319499,
            "asks" : [
                [1000, 0.5], [1001, 0.23], [1004, 2.1]
                // ... 
            ],
            "bids" : [
                [999, 0.25], [998, 0.8], [995, 1.4]
                // ... 
            ]
        }
    }
    
  • GetTrades

    • طریقہ کا میدان: “تجارت”
    • پیرامز فیلڈ:
    {"symbol":"eth_usdt"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    { 
        "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

    • طریقہ کا میدان: “ریکارڈز”
    • پیرامز فیلڈ:
    {
        "limit":"500",
        "period":"60",          // 60分钟
        "symbol":"ETH_USDT"
    }
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "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 عمل میں لایا جائے۔

    • طریقہ کا میدان: “”
    • پیرامز فیلڈ:
    {}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {}
    
  • GetTickers عمل میں لایا جائے۔

    • طریقہ کا میدان: “”
    • پیرامز فیلڈ:
    {}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {}
    
  • GetAccount

    • طریقہ کا میدان: “اکاؤنٹس”
    • پیرامز فیلڈ:
    {}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "data": [
            {"currency": "TUSD", "free": "3000", "frozen": "0"}, 
            {"currency": "BTC", "free": "0.2482982056277609", "frozen": "0"}, 
            // ...
        ]
    }
    
  • GetAssets

    • طریقہ کا میدان: “اثاثے”
    • پیرامز فیلڈ:
    {}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "data": [
            {"currency": "TUSD", "free": "3000", "frozen": "0"},
            {"currency": "BTC", "free": "0.2482982056277609", "frozen": "0"}, 
            // ...
        ]
    }
    
  • CreateOrder / Buy / Sell

    • طریقہ کا میدان: “تجارت”
    • پیرامز فیلڈ:
    {"amount":"0.1","price":"1000","symbol":"BTC_USDT","type":"buy"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "data": {
            "id": "BTC-USDT,123456"
        }
    }
    
  • GetOrders

    • طریقہ کا میدان: “احکامات”
    • پیرامز فیلڈ:
    {"symbol":"ETH_USDT"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "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

    • طریقہ کا میدان: “آرڈر”
    • پیرامز فیلڈ:
    {
        "id":"ETH-USDT,123456",       // 策略中调用:exchange.GetOrder("ETH-USDT,123456")
        "symbol":"ETH_USDT"
    }
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    { 
        "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

    • طریقہ کا میدان: “ہسٹری آرڈرز”
    • پیرامز فیلڈ:
    {"limit":0,"since":0,"symbol":"ETH_USDT"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "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

    • طریقہ کا میدان: “منسوخ کریں”
    • پیرامز فیلڈ:
    {"id":"ETH-USDT,123456","symbol":"ETH_USDT"}
    
    • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:
    {
        "data": true    // 只要该JSON中没有error字段,都默认为撤单成功
    }
    
  • IO

Exchange.IO فنکشن کو براہ راست ایکسچینج انٹرفیس تک رسائی حاصل کرنے کے لیے استعمال کیا جاتا ہے، مثال کے طور پر، ہم استعمال کرتے ہیں۔GET /api/v5/trade/orders-pending, 参数:instType=SPOT,instId=ETH-USDTمثال کے طور پر۔

  // 策略实例中调用
  exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT&instId=ETH-USDT")
  • طریقہ کا میدان:"__api_/api/v5/trade/orders-pending"میتھڈ فیلڈ _api سے شروع ہوتی ہے، جو اس بات کی نشاندہی کرتی ہے کہ یہ حکمت عملی مثال میں exchange.IO فنکشن کال کے ذریعے متحرک ہے۔

  • پیرامز فیلڈ:

    {"instId":"ETH-USDT","instType":"SPOT"}   // instType=SPOT&instId=ETH-USDT编码的参数会被还原为JSON
    
  • وہ ڈیٹا جس کی میزبان کو عام پروٹوکول کے جواب میں توقع ہے:

    {
        "data": {"code": "0", "data": [], "msg": ""}    // data属性值为交易所API:GET /api/v5/trade/orders-pending 应答的数据
    }
    
  • دوسرے حکمت عملی کی مثالوں میں استعمال ہونے والے دیگر موجد پلیٹ فارم API افعال، جیسے: exchange.Go()exchange.GetRawJSON()اس طرح کے افعال کو انکیپسولیٹ کرنے کی ضرورت نہیں ہے، اور کال کرنے کا طریقہ اور فعالیت میں کوئی تبدیلی نہیں ہے۔

فیوچر ایکسچینج

سپاٹ ایکسچینجز کے تمام فنکشنز کو سپورٹ کرنے کے علاوہ، فیوچر ایکسچینجز میں کچھ API فنکشنز بھی ہوتے ہیں جو فیوچر ایکسچینجز کے لیے منفرد ہوتے ہیں۔

عمل میں لایا جائے۔

  • GetPositions
  • SetMarginLevel
  • GetFundings

عام پروٹوکول کی مثال کا ازگر ورژن

REST جنرل پروٹوکول - OKX ایکسچینج REST API انٹرفیس تک رسائی اور اسے اسپاٹ ایکسچینج آبجیکٹ کے طور پر سمیٹیں۔ درخواست اور جوابی ڈیٹا انکیپسولیشن کے لیے ایک مشترکہ انٹرفیس نافذ کیا۔ ایک نجی انٹرفیس دستخط، درخواست اور جوابی ڈیٹا انکیپسولیشن کو نافذ کیا۔ یہ مثال بنیادی طور پر جانچ اور سیکھنے کے لیے ہے۔

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