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