def test_order_info():
    oi = OrderInfo('COINBASE', 'BTC-USD', None, BUY, PENDING, LIMIT,
                   Decimal(40000.00), Decimal(1.25), Decimal(1.25), time())
    d = oi.to_dict(numeric_type=str)
    d = json.dumps(d)
    d = json.loads(d)
    oi2 = OrderInfo.from_dict(d)
    assert oi == oi2
Example #2
0
    def _order_status(self, data: dict):
        if 'status' not in data:
            raise UnexpectedMessage(f"Message from exchange: {data}")
        status = data['status']
        if data['status'] == 'done' and data['done_reason'] == 'canceled':
            status = PARTIAL
        elif data['status'] == 'done':
            status = FILLED
        elif data['status'] == 'open':
            status = OPEN
        elif data['status'] == 'pending':
            status = PENDING
        elif data['status'] == CANCELLED:
            status = CANCELLED

        if 'price' not in data:
            price = Decimal(data['executed_value']) / Decimal(
                data['filled_size'])
        else:
            price = Decimal(data['price'])

        # exchange, symbol, id, side, status, type, price, amount, remaining, timestamp, account=None, raw=None):
        return OrderInfo(self.id,
                         data['product_id'],
                         data['id'],
                         BUY if data['side'] == 'buy' else SELL,
                         status,
                         LIMIT if data['type'] == 'limit' else MARKET,
                         price,
                         Decimal(data['size']),
                         Decimal(data['size']) - Decimal(data['filled_size']),
                         data['done_at'].timestamp() if 'done_at' in data else
                         data['created_at'].timestamp(),
                         client_order_id=data['client_oid'],
                         raw=data)
Example #3
0
    async def _order(self, msg: dict, timestamp: float):
        """
        {
            "topic": "order",
            "action": "",
            "data": [
                {
                    "order_id": "xxxxxxxx-xxxx-xxxx-9a8f-4a973eb5c418",
                    "order_link_id": "",
                    "symbol": "BTCUSDT",
                    "side": "Buy",
                    "order_type": "Limit",
                    "price": 11000,
                    "qty": 0.001,
                    "leaves_qty": 0.001,
                    "last_exec_price": 0,
                    "cum_exec_qty": 0,
                    "cum_exec_value": 0,
                    "cum_exec_fee": 0,
                    "time_in_force": "GoodTillCancel",
                    "create_type": "CreateByUser",
                    "cancel_type": "UNKNOWN",
                    "order_status": "New",
                    "take_profit": 0,
                    "stop_loss": 0,
                    "trailing_stop": 0,
                    "reduce_only": false,
                    "close_on_trigger": false,
                    "create_time": "2020-08-12T21:18:40.780039678Z",
                    "update_time": "2020-08-12T21:18:40.787986415Z"
                }
            ]
        }
        """
        order_status = {
            'Created': SUBMITTING,
            'Rejected': FAILED,
            'New': OPEN,
            'PartiallyFilled': PARTIAL,
            'Filled': FILLED,
            'Cancelled': CANCELLED,
            'PendingCancel': CANCELLING
        }

        for i in range(len(msg['data'])):
            data = msg['data'][i]

            oi = OrderInfo(self.id,
                           self.exchange_symbol_to_std_symbol(data['symbol']),
                           data["order_id"],
                           BUY if msg["side"] == 'Buy' else SELL,
                           order_status[data["order_status"]],
                           LIMIT if data['order_type'] == 'Limit' else MARKET,
                           Decimal(data['price']),
                           Decimal(data['cumQuantity']),
                           Decimal(data['qty']) - Decimal(data['cumQuantity']),
                           self.timestamp_normalize(data["updateTime"]),
                           raw=data)
            await self.callback(ORDER_INFO, oi, timestamp)
Example #4
0
 async def _order_update(self, msg: dict, timestamp: float):
     """
     {
         "e":"ORDER_TRADE_UPDATE",     // Event Type
         "E":1568879465651,            // Event Time
         "T":1568879465650,            // Transaction Time
         "o":
         {
             "s":"BTCUSDT",              // Symbol
             "c":"TEST",                 // Client Order Id
             // special client order id:
             // starts with "autoclose-": liquidation order
             // "adl_autoclose": ADL auto close order
             "S":"SELL",                 // Side
             "o":"TRAILING_STOP_MARKET", // Order Type
             "f":"GTC",                  // Time in Force
             "q":"0.001",                // Original Quantity
             "p":"0",                    // Original Price
             "ap":"0",                   // Average Price
             "sp":"7103.04",             // Stop Price. Please ignore with TRAILING_STOP_MARKET order
             "x":"NEW",                  // Execution Type
             "X":"NEW",                  // Order Status
             "i":8886774,                // Order Id
             "l":"0",                    // Order Last Filled Quantity
             "z":"0",                    // Order Filled Accumulated Quantity
             "L":"0",                    // Last Filled Price
             "N":"USDT",             // Commission Asset, will not push if no commission
             "n":"0",                // Commission, will not push if no commission
             "T":1568879465651,          // Order Trade Time
             "t":0,                      // Trade Id
             "b":"0",                    // Bids Notional
             "a":"9.91",                 // Ask Notional
             "m":false,                  // Is this trade the maker side?
             "R":false,                  // Is this reduce only
             "wt":"CONTRACT_PRICE",      // Stop Price Working Type
             "ot":"TRAILING_STOP_MARKET",    // Original Order Type
             "ps":"LONG",                        // Position Side
             "cp":false,                     // If Close-All, pushed with conditional order
             "AP":"7476.89",             // Activation Price, only puhed with TRAILING_STOP_MARKET order
             "cr":"5.0",                 // Callback Rate, only puhed with TRAILING_STOP_MARKET order
             "rp":"0"                            // Realized Profit of the trade
         }
     }
     """
     oi = OrderInfo(self.id,
                    self.exchange_symbol_to_std_symbol(msg['o']['s']),
                    str(msg['o']['i']),
                    BUY if msg['o']['S'].lower() == 'buy' else SELL,
                    msg['o']['x'],
                    LIMIT if msg['o']['o'].lower() == 'limit' else
                    MARKET if msg['o']['o'].lower() == 'market' else None,
                    Decimal(msg['o']['ap']) if
                    not Decimal.is_zero(Decimal(msg['o']['ap'])) else None,
                    Decimal(msg['o']['q']),
                    Decimal(msg['o']['q']) - Decimal(msg['o']['z']),
                    self.timestamp_normalize(msg['E']),
                    raw=msg)
     await self.callback(ORDER_INFO, oi, timestamp)
Example #5
0
 async def _order_status(self, msg: str, ts: float):
     status_lookup = {
         'new': OPEN,
         'partiallyFilled': PARTIAL,
         'filled': FILLED,
         'canceled': CANCELLED,
         'expired': EXPIRED,
         'suspended': SUSPENDED,
     }
     type_lookup = {
         'limit': LIMIT,
         'market': MARKET,
         'stopLimit': STOP_LIMIT,
         'stopMarket': STOP_MARKET,
     }
     """
     Example response:
     {
         "jsonrpc": "2.0",
         "method": "report",
         "params": {
             "id": "4345697765",
             "clientOrderId": "53b7cf917963464a811a4af426102c19",
             "symbol": "ETHBTC",
             "side": "sell",
             "status": "filled",
             "type": "limit",
             "timeInForce": "GTC",
             "quantity": "0.001",
             "price": "0.053868",
             "cumQuantity": "0.001",
             "postOnly": false,
             "createdAt": "2017-10-20T12:20:05.952Z",
             "updatedAt": "2017-10-20T12:20:38.708Z",
             "reportType": "trade",
             "tradeQuantity": "0.001",
             "tradePrice": "0.053868",
             "tradeId": 55051694,
             "tradeFee": "-0.000000005"
         }
     }
     """
     oi = OrderInfo(
         self.id,
         self.exchange_symbol_to_std_symbol(msg["symbol"]),
         msg["id"],
         SELL if msg["side"] == 'sell' else BUY,
         status_lookup[msg["status"]],
         type_lookup[msg["type"]],
         Decimal(msg['price']),
         Decimal(msg['cumQuantity']),
         Decimal(msg['quantity']) - Decimal(msg['cumQuantity']),
         self.timestamp_normalize(msg["updatedAt"]) if msg["updatedAt"] else
         self.timestamp_normalize(msg["createdAt"]),
         raw=msg)
     await self.callback(ORDER_INFO, oi, ts)
Example #6
0
 async def _order(self, msg: dict, timestamp: float):
     """
     {
         "channel":"order",
         "timestamp":1587994934089,
         "data":[
             {
                 "order_id":"1590",
                 "instrument_id":"BTC-1MAY20-8750-P",
                 "qty":"0.50000000",
                 "filled_qty":"0.10000000",
                 "remain_qty":"0.40000000",
                 "price":"0.16000000",
                 "avg_price":"0.16000000",
                 "side":"buy",
                 "order_type":"limit",
                 "time_in_force":"gtc",
                 "created_at":1587870609000,
                 "updated_at":1587870609000,
                 "status":"open",
                 "fee":"0.00002000",
                 "cash_flow":"-0.01600000",
                 "pnl":"0.00000000",
                 "is_liquidation": false,
                 "auto_price":"0.00000000",
                 "auto_price_type":"",
                 "taker_fee_rate": "0.00050000",
                 "maker_fee_rate": "0.00020000",
                 "label": "hedge",
                 "stop_price": "0.00000000",
                 "reduce_only": false,
                 "post_only": false,
                 "reject_post_only": false,
                 "mmp": false,
                 "reorder_index": 1
             }
         ]
     }
     """
     for entry in msg['data']:
         oi = OrderInfo(self.id,
                        self.exchange_symbol_to_std_symbol(
                            entry['instrument_id']),
                        entry['order_id'],
                        BUY if entry['side'] == 'buy' else SELL,
                        self._status_translate(entry['status']),
                        self._order_type_translate(entry['order_type']),
                        Decimal(entry['price']),
                        Decimal(entry['filled_qty']),
                        Decimal(entry['remain_qty']),
                        self.timestamp_normalize(entry['updated_at']),
                        raw=entry)
         await self.callback(ORDER_INFO, oi, timestamp)
Example #7
0
 async def _order_update(self, msg: dict, timestamp: float):
     """
     {
         "e": "executionReport",        // Event type
         "E": 1499405658658,            // Event time
         "s": "ETHBTC",                 // Symbol
         "c": "mUvoqJxFIILMdfAW5iGSOW", // Client order ID
         "S": "BUY",                    // Side
         "o": "LIMIT",                  // Order type
         "f": "GTC",                    // Time in force
         "q": "1.00000000",             // Order quantity
         "p": "0.10264410",             // Order price
         "P": "0.00000000",             // Stop price
         "F": "0.00000000",             // Iceberg quantity
         "g": -1,                       // OrderListId
         "C": "",                       // Original client order ID; This is the ID of the order being canceled
         "x": "NEW",                    // Current execution type
         "X": "NEW",                    // Current order status
         "r": "NONE",                   // Order reject reason; will be an error code.
         "i": 4293153,                  // Order ID
         "l": "0.00000000",             // Last executed quantity
         "z": "0.00000000",             // Cumulative filled quantity
         "L": "0.00000000",             // Last executed price
         "n": "0",                      // Commission amount
         "N": null,                     // Commission asset
         "T": 1499405658657,            // Transaction time
         "t": -1,                       // Trade ID
         "I": 8641984,                  // Ignore
         "w": true,                     // Is the order on the book?
         "m": false,                    // Is this trade the maker side?
         "M": false,                    // Ignore
         "O": 1499405658657,            // Order creation time
         "Z": "0.00000000",             // Cumulative quote asset transacted quantity
         "Y": "0.00000000",             // Last quote asset transacted quantity (i.e. lastPrice * lastQty)
         "Q": "0.00000000"              // Quote Order Qty
     }
     """
     oi = OrderInfo(self.id,
                    self.exchange_symbol_to_std_symbol(msg['s']),
                    str(msg['i']),
                    BUY if msg['S'].lower() == 'buy' else SELL,
                    msg['x'],
                    LIMIT if msg['o'].lower() == 'limit' else
                    MARKET if msg['o'].lower() == 'market' else None,
                    Decimal(msg['Z']) / Decimal(msg['z'])
                    if not Decimal.is_zero(Decimal(msg['z'])) else None,
                    Decimal(msg['q']),
                    Decimal(msg['q']) - Decimal(msg['z']),
                    self.timestamp_normalize(msg['E']),
                    raw=msg)
     await self.callback(ORDER_INFO, oi, timestamp)
Example #8
0
 def init_order_info(self, o):
     oi = OrderInfo(
         self.id,
         self.exchange_symbol_to_std_symbol(o['symbol']),
         o['orderID'],
         BUY if o['side'] == 'Buy' else SELL,
         self.normalize_order_status(o['ordStatus']),
         LIMIT if o['ordType'].lower() == 'limit' else MARKET if o['ordType'].lower() == 'market' else None,
         Decimal(o['avgPx']) if o['avgPx'] else Decimal(o['price']),
         Decimal(o['orderQty']),
         Decimal(o['leavesQty']),
         self.timestamp_normalize(o['timestamp']),
         raw=str(o),     # Need to convert to string to avoid json serialization error when updating order
     )
     return oi
Example #9
0
    async def _order(self, msg: dict, timestamp: float):
        '''
        [{
            "type": "accepted",
            "order_id": "109535951",
            "event_id": "109535952",
            "api_session": "UI",
            "symbol": "btcusd",
            "side": "buy",
            "order_type": "exchange limit",
            "timestamp": "1547742904",
            "timestampms": 1547742904989,
            "is_live": true,
            "is_cancelled": false,
            "is_hidden": false,
            "original_amount": "1",
            "price": "3592.00",
            "socket_sequence": 13
        }]
        '''
        if msg['type'] == "initial" or msg['type'] == "accepted":
            status = SUBMITTING
        elif msg['type'] == "fill":
            status = FILLED
        elif msg['type'] == 'booked':
            status = OPEN
        elif msg['type'] == 'rejected':
            status = FAILED
        elif msg['type'] == 'cancelled':
            status = CANCELLED
        else:
            status = msg['type']

        oi = OrderInfo(
            self.id,
            self.exchange_symbol_to_std_symbol(msg['symbol'].upper()),
            msg['order_id'],
            BUY if msg['side'].lower() == 'buy' else SELL,
            status,
            LIMIT if msg['order_type'] == 'exchange limit' else STOP_LIMIT,
            Decimal(msg['price']),
            Decimal(msg['executed_amount']),
            Decimal(msg['remaining_amount']),
            msg['timestampms'] / 1000.0,
            raw=msg)
        await self.callback(ORDER_INFO, oi, timestamp)
Example #10
0
    async def _order(self, msg: dict, timestamp: float):
        """
        example message:
        {
            "channel": "orders",
            "data": {
                "id": 24852229,
                "clientId": null,
                "market": "XRP-PERP",
                "type": "limit",
                "side": "buy",
                "size": 42353.0,
                "price": 0.2977,
                "reduceOnly": false,
                "ioc": false,
                "postOnly": false,
                "status": "closed",
                "filledSize": 0.0,
                "remainingSize": 0.0,
                "avgFillPrice": 0.2978
            },
            "type": "update"
        }
        """
        order = msg['data']
        status = order['status']
        if status == 'new':
            status = SUBMITTING
        elif status == 'open':
            status = OPEN
        elif status == 'closed':
            status = CLOSED

        oi = OrderInfo(self.id,
                       self.exchange_symbol_to_std_symbol(order['market']),
                       str(order['id']),
                       BUY if order['side'].lower() == 'buy' else SELL,
                       status,
                       LIMIT if order['type'] == 'limit' else MARKET,
                       Decimal(order['price']) if order['price'] else None,
                       Decimal(order['filledSize']),
                       Decimal(order['remainingSize']),
                       None,
                       account=self.subaccount,
                       raw=msg)
        await self.callback(ORDER_INFO, oi, timestamp)
Example #11
0
    async def _order(self, msg: dict, timestamp: float):
        '''
        {
          "arg": {
            "channel": "orders",
            "instType": "FUTURES",
            "instId": "BTC-USD-200329"
          },
          "data": [
            {
              "instType": "FUTURES",
              "instId": "BTC-USD-200329",
              "ccy": "BTC",
              "ordId": "312269865356374016",
              "clOrdId": "b1",
              "tag": "",
              "px": "999",
              "sz": "333",
              "notionalUsd": "",
              "ordType": "limit",
              "side": "buy",
              "posSide": "long",
              "tdMode": "cross",
              "tgtCcy": "",
              "fillSz": "0",
              "fillPx": "long",
              "tradeId": "0",
              "accFillSz": "323",
              "fillNotionalUsd": "",
              "fillTime": "0",
              "fillFee": "0.0001",
              "fillFeeCcy": "BTC",
              "execType": "T",
              "state": "canceled",
              "avgPx": "0",
              "lever": "20",
              "tpTriggerPx": "0",
              "tpOrdPx": "20",
              "slTriggerPx": "0",
              "slOrdPx": "20",
              "feeCcy": "",
              "fee": "",
              "rebateCcy": "",
              "rebate": "",
              "tgtCcy":"",
              "pnl": "",
              "category": "",
              "uTime": "1597026383085",
              "cTime": "1597026383085",
              "reqId": "",
              "amendResult": "",
              "code": "0",
              "msg": ""
            }
          ]
        }
        '''
        status = msg['data'][0]['state']
        if status == 'canceled':
            status == CANCELLED
        elif status == 'live':
            status == OPEN
        elif status == 'partially-filled':
            status = PARTIAL
        elif status == 'filled':
            status = FILLED

        o_type = msg['data'][0]['ordType']
        if o_type == 'market':
            o_type = MARKET
        elif o_type == 'post_only':
            o_type = MAKER_OR_CANCEL
        elif o_type == 'fok':
            o_type = FILL_OR_KILL
        elif o_type == 'ioc':
            o_type = IMMEDIATE_OR_CANCEL
        elif o_type == 'limit':
            o_type = LIMIT

        oi = OrderInfo(
            self.id,
            self.exchange_symbol_to_std_symbol(
                msg['data'][0]['instId'].upper()),
            msg['data'][0]['ordId'],
            BUY if msg['data'][0]['side'].lower() == 'buy' else SELL,
            status,
            o_type,
            Decimal(msg['data'][0]['px'])
            if msg['data'][0]['px'] else Decimal(msg['data'][0]['avgPx']),
            Decimal(msg['data'][0]['sz']),
            Decimal(msg['data'][0]['sz']) -
            Decimal(msg['data'][0]['accFillSz'])
            if msg['data'][0]['accFillSz'] else Decimal(msg['data'][0]['sz']),
            self.timestamp_normalize(int(msg['data'][0]['uTime'])),
            raw=msg)
        await self.callback(ORDER_INFO, oi, timestamp)
Example #12
0
    async def _order(self, msg: dict, timestamp: float):
        '''
        {
            "table":"spot/order",
            "data":[
                {
                    "client_oid":"",
                    "filled_notional":"0",
                    "filled_size":"0",
                    "instrument_id":"ETC-USDT",
                    "last_fill_px":"0",
                    "last_fill_qty":"0",
                    "last_fill_time":"1970-01-01T00:00:00.000Z",
                    "margin_trading":"1",
                    "notional":"",
                    "order_id":"3576398568830976",
                    "order_type":"0",
                    "price":"5.826",
                    "side":"buy",
                    "size":"0.1",
                    "state":"0",
                    "status":"open",
                    "timestamp":"2019-09-24T06:45:11.394Z",
                    "type":"limit",
                    "created_at":"2019-09-24T06:45:11.394Z"
                }
            ]
        }
        '''
        status = msg['data'][0]['state']
        if status == -1:
            status = FAILED
        elif status == -1:
            status == CANCELLED
        elif status == 0:
            status == OPEN
        elif status == 1:
            status = PARTIAL
        elif status == 2:
            status = FILLED
        elif status == 3:
            status = SUBMITTING
        elif status == 4:
            status = CANCELLING

        o_type = msg['data'][0]['ordType']
        if o_type == 0:
            o_type = MARKET
        elif o_type == 1:
            o_type = MAKER_OR_CANCEL
        elif o_type == 2:
            o_type = FILL_OR_KILL
        elif o_type == 3:
            o_type = IMMEDIATE_OR_CANCEL

        oi = OrderInfo(
            self.id,
            self.exchange_symbol_to_std_symbol(
                msg['data'][0]['instId'].upper()),
            msg['data'][0]['ordId'],
            BUY if msg['data'][0]['side'].lower() == 'buy' else SELL,
            status,
            o_type,
            Decimal(msg['data'][0]['filled_notional'] /
                    msg['data'][0]['filled_size']),
            Decimal(msg['data'][0]['filled_size']),
            msg['data'][0]['uTime'].timestamp(),
            raw=msg)
        await self.callback(ORDER_INFO, oi, timestamp)
Example #13
0
    async def _order(self, msg: dict, timestamp: float):
        """
        order msg example

        {
          "table": "order",
          "action": "partial",
          "keys": [
            "orderID"
          ],
          "types": {
            "orderID": "guid",
            "clOrdID": "string",
            "clOrdLinkID": "symbol",
            "account": "long",
            "symbol": "symbol",
            "side": "symbol",
            "simpleOrderQty": "float",
            "orderQty": "long",
            "price": "float",
            "displayQty": "long",
            "stopPx": "float",
            "pegOffsetValue": "float",
            "pegPriceType": "symbol",
            "currency": "symbol",
            "settlCurrency": "symbol",
            "ordType": "symbol",
            "timeInForce": "symbol",
            "execInst": "symbol",
            "contingencyType": "symbol",
            "exDestination": "symbol",
            "ordStatus": "symbol",
            "triggered": "symbol",
            "workingIndicator": "boolean",
            "ordRejReason": "symbol",
            "simpleLeavesQty": "float",
            "leavesQty": "long",
            "simpleCumQty": "float",
            "cumQty": "long",
            "avgPx": "float",
            "multiLegReportingType": "symbol",
            "text": "string",
            "transactTime": "timestamp",
            "timestamp": "timestamp"
          },
          "foreignKeys": {
            "symbol": "instrument",
            "side": "side",
            "ordStatus": "ordStatus"
          },
          "attributes": {
            "orderID": "grouped",
            "account": "grouped",
            "ordStatus": "grouped",
            "workingIndicator": "grouped"
          },
          "filter": {
            "account": 1600000,
            "symbol": "ETHUSDTH22"
          },
          "data": [
            {
              "orderID": "360fad5a-49e3-4187-ad04-8fac82b8a95f",
              "clOrdID": "",
              "clOrdLinkID": "",
              "account": 1600000,
              "symbol": "ETHUSDTH22",
              "side": "Buy",
              "simpleOrderQty": null,
              "orderQty": 1000,
              "price": 2000,
              "displayQty": null,
              "stopPx": null,
              "pegOffsetValue": null,
              "pegPriceType": "",
              "currency": "USDT",
              "settlCurrency": "USDt",
              "ordType": "Limit",
              "timeInForce": "GoodTillCancel",
              "execInst": "",
              "contingencyType": "",
              "exDestination": "XBME",
              "ordStatus": "New",
              "triggered": "",
              "workingIndicator": true,
              "ordRejReason": "",
              "simpleLeavesQty": null,
              "leavesQty": 1000,
              "simpleCumQty": null,
              "cumQty": 0,
              "avgPx": null,
              "multiLegReportingType": "SingleSecurity",
              "text": "Submitted via API.",
              "transactTime": "2022-02-13T00:15:02.570000Z",
              "timestamp": "2022-02-13T00:15:02.570000Z"
            },
            {
              "orderID": "74d2ad0a-49f1-44dc-820f-5f0cfd64c1a3",
              "clOrdID": "",
              "clOrdLinkID": "",
              "account": 1600000,
              "symbol": "ETHUSDTH22",
              "side": "Buy",
              "simpleOrderQty": null,
              "orderQty": 1000,
              "price": 2000,
              "displayQty": null,
              "stopPx": null,
              "pegOffsetValue": null,
              "pegPriceType": "",
              "currency": "USDT",
              "settlCurrency": "USDt",
              "ordType": "Limit",
              "timeInForce": "GoodTillCancel",
              "execInst": "",
              "contingencyType": "",
              "exDestination": "XBME",
              "ordStatus": "New",
              "triggered": "",
              "workingIndicator": true,
              "ordRejReason": "",
              "simpleLeavesQty": null,
              "leavesQty": 1000,
              "simpleCumQty": null,
              "cumQty": 0,
              "avgPx": null,
              "multiLegReportingType": "SingleSecurity",
              "text": "Submitted via API.",
              "transactTime": "2022-02-13T00:17:13.796000Z",
              "timestamp": "2022-02-13T00:17:13.796000Z"
            }
          ]
        }

        {
          "table": "order",
          "action": "insert",
          "data": [
            {
              "orderID": "0c4e4a8e-b234-495f-8b94-c4766786c4a5",
              "clOrdID": "",
              "clOrdLinkID": "",
              "account": 1600000,
              "symbol": "ETHUSDTH22",
              "side": "Buy",
              "simpleOrderQty": null,
              "orderQty": 1000,
              "price": 2000,
              "displayQty": null,
              "stopPx": null,
              "pegOffsetValue": null,
              "pegPriceType": "",
              "currency": "USDT",
              "settlCurrency": "USDt",
              "ordType": "Limit",
              "timeInForce": "GoodTillCancel",
              "execInst": "",
              "contingencyType": "",
              "exDestination": "XBME",
              "ordStatus": "New",
              "triggered": "",
              "workingIndicator": true,
              "ordRejReason": "",
              "simpleLeavesQty": null,
              "leavesQty": 1000,
              "simpleCumQty": null,
              "cumQty": 0,
              "avgPx": null,
              "multiLegReportingType": "SingleSecurity",
              "text": "Submitted via API.",
              "transactTime": "2022-02-13T00:21:50.268000Z",
              "timestamp": "2022-02-13T00:21:50.268000Z"
            }
          ]
        }

        {
          "table": "order",
          "action": "update",
          "data": [
            {
              "orderID": "360fa95a-49e3-4187-ad04-8fac82b8a95f",
              "ordStatus": "Canceled",
              "workingIndicator": false,
              "leavesQty": 0,
              "text": "Canceled: Cancel from www.bitmex.com\nSubmitted via API.",
              "timestamp": "2022-02-13T08:16:36.446000Z",
              "clOrdID": "",
              "account": 1600000,
              "symbol": "ETHUSDTH22"
            }
          ]
        }

        """
        if msg['action'] == 'partial':
            # Initial snapshot of open orders
            self.open_orders = {}
            for o in msg['data']:
                oi = self.init_order_info(o)
                self.open_orders[oi.id] = oi
        elif msg['action'] == 'insert':
            for o in msg['data']:
                oi = self.init_order_info(o)
                self.open_orders[oi.id] = oi
                await self.callback(ORDER_INFO, oi, timestamp)
        elif msg['action'] == 'update':
            for o in msg['data']:
                oi = self.open_orders.get(o['orderID'])
                if oi:
                    info = oi.to_dict()
                    if 'ordStatus' in o:
                        info['status'] = self.normalize_order_status(o['ordStatus'])
                    if 'leaveQty' in o:
                        info['remaining'] = Decimal(o['leavesQty'])
                    if 'avgPx' in o:
                        info['price'] = Decimal(o['avgPx'])
                    info['raw'] = str(o)    # Not sure if this is needed
                    new_oi = OrderInfo(**info)
                    if new_oi.status in (FILLED, CANCELLED):
                        self.open_orders.pop(new_oi.id)
                    else:
                        self.open_orders[new_oi.id] = oi
                    await self.callback(ORDER_INFO, new_oi, timestamp)
        else:
            LOG.warning("%s: Unexpected message received: %s", self.id, msg)
Example #14
0
    async def _user_channels(self, conn: AsyncConnection, msg: dict,
                             timestamp: float, subchan: str):
        order_status = {
            "open": OPEN,
            "filled": FILLED,
            "rejected": FAILED,
            "cancelled": CANCELLED,
            "untriggered": OPEN
        }
        order_types = {
            "limit": LIMIT,
            "market": MARKET,
            "stop_limit": STOP_LIMIT,
            "stop_market": STOP_MARKET
        }

        if 'data' in msg['params']:
            data = msg['params']['data']

            if subchan == 'portfolio':
                '''
                {
                    "params" : {
                        "data" : {
                            "total_pl" : 0.00000425,
                            "session_upl" : 0.00000425,
                            "session_rpl" : -2e-8,
                            "projected_maintenance_margin" : 0.00009141,
                            "projected_initial_margin" : 0.00012542,
                            "projected_delta_total" : 0.0043,
                            "portfolio_margining_enabled" : false,
                            "options_vega" : 0,
                            "options_value" : 0,
                            "options_theta" : 0,
                            "options_session_upl" : 0,
                            "options_session_rpl" : 0,
                            "options_pl" : 0,
                            "options_gamma" : 0,
                            "options_delta" : 0,
                            "margin_balance" : 0.2340038,
                            "maintenance_margin" : 0.00009141,
                            "initial_margin" : 0.00012542,
                            "futures_session_upl" : 0.00000425,
                            "futures_session_rpl" : -2e-8,
                            "futures_pl" : 0.00000425,
                            "estimated_liquidation_ratio" : 0.01822795,
                            "equity" : 0.2340038,
                            "delta_total" : 0.0043,
                            "currency" : "BTC",
                            "balance" : 0.23399957,
                            "available_withdrawal_funds" : 0.23387415,
                            "available_funds" : 0.23387838
                        },
                        "channel" : "user.portfolio.btc"
                    },
                    "method" : "subscription",
                    "jsonrpc" : "2.0"
                }
                '''
                b = Balance(self.id,
                            data['currency'],
                            Decimal(data['balance']),
                            Decimal(data['balance']) -
                            Decimal(data['available_withdrawal_funds']),
                            raw=data)
                await self.callback(BALANCES, b, timestamp)

            elif subchan == 'orders':
                '''
                {
                    "params" : {
                        "data" : {
                            "time_in_force" : "good_til_cancelled",
                            "replaced" : false,
                            "reduce_only" : false,
                            "profit_loss" : 0,
                            "price" : 10502.52,
                            "post_only" : false,
                            "original_order_type" : "market",
                            "order_type" : "limit",
                            "order_state" : "open",
                            "order_id" : "5",
                            "max_show" : 200,
                            "last_update_timestamp" : 1581507423789,
                            "label" : "",
                            "is_liquidation" : false,
                            "instrument_name" : "BTC-PERPETUAL",
                            "filled_amount" : 0,
                            "direction" : "buy",
                            "creation_timestamp" : 1581507423789,
                            "commission" : 0,
                            "average_price" : 0,
                            "api" : false,
                            "amount" : 200
                        },
                        "channel" : "user.orders.BTC-PERPETUAL.raw"
                    },
                    "method" : "subscription",
                    "jsonrpc" : "2.0"
                }
                '''
                oi = OrderInfo(
                    self.id,
                    self.exchange_symbol_to_std_symbol(
                        data['instrument_name']),
                    data["order_id"],
                    BUY if msg["side"] == 'Buy' else SELL,
                    order_status[data["order_state"]],
                    order_types[data['order_type']],
                    Decimal(data['price']),
                    Decimal(data['filled_amount']),
                    Decimal(data['amount']) - Decimal(data['cumQuantity']),
                    self.timestamp_normalize(data["last_update_timestamp"]),
                    raw=data)
                await self.callback(ORDER_INFO, oi, timestamp)

            elif subchan == 'trades':
                '''
                {
                    "params" : {
                        "data" : [
                        {
                            "trade_seq" : 30289432,
                            "trade_id" : "48079254",
                            "timestamp" : 1590484156350,
                            "tick_direction" : 0,
                            "state" : "filled",
                            "self_trade" : false,
                            "reduce_only" : false,
                            "price" : 8954,
                            "post_only" : false,
                            "order_type" : "market",
                            "order_id" : "4008965646",
                            "matching_id" : null,
                            "mark_price" : 8952.86,
                            "liquidity" : "T",
                            "instrument_name" : "BTC-PERPETUAL",
                            "index_price" : 8956.73,
                            "fee_currency" : "BTC",
                            "fee" : 0.00000168,
                            "direction" : "sell",
                            "amount" : 20
                        }]
                    }
                }
                '''
                for entry in data:
                    symbol = self.exchange_symbol_to_std_symbol(
                        entry['instrument_name'])
                    f = Fill(self.id,
                             symbol,
                             SELL if entry['direction'] == 'sell' else BUY,
                             Decimal(entry['amount']),
                             Decimal(entry['price']),
                             Decimal(entry['fee']),
                             entry['trade_id'],
                             entry['order_id'],
                             entry['order_type'],
                             TAKER if entry['liquidity'] == 'T' else MAKER,
                             self.timestamp_normalize(entry['timestamp']),
                             raw=entry)
                    await self.callback(FILLS, f, timestamp)
            else:
                LOG.warning("%s: Unknown channel 'user.%s'", conn.uuid,
                            subchan)
        else:
            LOG.warning("%s: Unknown message %s'", conn.uuid, msg)
Example #15
0
    async def _order(self, msg: dict, symbol: str, timestamp: float):
        '''
        {
            'action': 'snapshot',
            'arg': {
                'instType': 'sumcbl',
                'channel': 'orders',
                'instId': 'default'
            }, 'data': [
                {
                    'accFillSz': '0',
                    'cTime': 1650407316266,
                    'clOrdId': '900439036248367104',
                    'force': 'normal',
                    'instId': 'SBTCSUSDT_SUMCBL',
                    'lever': '20',
                    'notionalUsd': '2065.175',
                    'ordId': '900439036185452544',
                    'ordType': 'market',
                    'orderFee': [
                        {'feeCcy': 'SUSDT', 'fee': '0'
                    }],
                    'posSide': 'long',
                    'px': '0',
                    'side': 'buy',
                    'status': 'new',
                    'sz': '0.05',
                    'tdMode': 'cross',
                    'tgtCcy': 'SUSDT',
                    'uTime': 1650407316266
                }
            ]
        }


        filled:

        {
            'action': 'snapshot',
            'arg': {
                'instType': 'sumcbl',
                'channel': 'orders',
                'instId': 'default'
            },
            'data': [{
                'accFillSz': '0.1',
                'avgPx': '41400',
                'cTime': 1650408010067,
                'clOrdId': '900441946260676608',
                'execType': 'T',
                'fillFee': '-2.484',
                'fillFeeCcy': 'SUSDT',
                'fillNotionalUsd': '4140',
                'fillPx': '41400',
                'fillSz': '0.1',
                'fillTime': '1650408010163',
                'force': 'normal',
                'instId': 'SBTCSUSDT_SUMCBL',
                'lever': '20',
                'notionalUsd': '4139.95',
                'ordId': '900441946180984832',
                'ordType': 'market',
                'orderFee': [{'feeCcy': 'SUSDT', 'fee': '-2.484'}],
                'pnl': '0',
                'posSide': 'long',
                'px': '0',
                'side': 'buy',
                'status': 'full-fill',
                'sz': '0.1',
                'tdMode': 'cross',
                'tgtCcy': 'SUSDT',
                'tradeId': '900441946663366657',
                'uTime': 1650408010163
            }]
        }
        '''
        for entry in msg['data']:

            o = OrderInfo(self.id,
                          self.exchange_symbol_to_std_symbol(entry['instId']),
                          entry['ordId'],
                          entry['side'],
                          self._status(entry['status']),
                          entry['ordType'],
                          Decimal(entry['px'] if 'fillPx' not in
                                  entry else entry['fillPx']),
                          Decimal(entry['sz']),
                          Decimal(entry['sz']) - Decimal(entry['accFillSz']),
                          self.timestamp_normalize(int(entry['uTime'])),
                          client_order_id=entry['clOrdId'],
                          raw=entry)
            await self.callback(ORDER_INFO, o, timestamp)