async def book_callback(self, book_type: str, book: OrderBook, receipt_timestamp: float, timestamp=None, raw=None, sequence_number=None, checksum=None, delta=None): if self.cross_check: self.check_bid_ask_overlapping(book) book.timestamp = timestamp book.raw = raw book.sequence_number = sequence_number book.delta = delta book.checksum = checksum await self.callback(book_type, book, receipt_timestamp)
async def l2_book(self, symbol: str, retry_count=0, retry_delay=60): ret = OrderBook(self.id, symbol) symbol = self.std_symbol_to_exchange_symbol(symbol) data = await self.http_conn.read( f"{self.api}get_order_book?depth=10000&instrument_name={symbol}", retry_count=retry_count, retry_delay=retry_delay) data = json.loads(data, parse_float=Decimal) for side in ('bids', 'asks'): for entry_bid in data["result"][side]: price, amount = entry_bid ret.book[side][price] = amount return ret
async def _rest_book(self, symbol: str, l3=False, retry_count=0, retry_delay=60): ret = OrderBook(self.id, symbol) symbol = self.std_symbol_to_exchange_symbol(symbol) funding = 'f' in symbol precision = 'R0' if l3 is True else 'P0' r = await self.http_conn.read( f"{self.api}/book/{symbol}/{precision}?len=100", retry_delay=retry_delay, retry_count=retry_count) data = json.loads(r, parse_float=Decimal) if l3: for entry in data: if funding: order_id, period, price, amount = entry update = (abs(amount), period) else: order_id, price, amount = entry update = abs(amount) amount = Decimal(amount) price = Decimal(price) side = BID if (amount > 0 and not funding) or ( amount < 0 and funding) else ASK if price not in ret.book[side]: ret.book[side][price] = {order_id: update} else: ret.book[side][price][order_id] = update else: for entry in data: if funding: price, period, _, amount = entry update = (abs(amount), period) else: price, _, amount = entry update = abs(amount) price = Decimal(price) amount = Decimal(amount) side = BID if (amount > 0 and not funding) or ( amount < 0 and funding) else ASK ret.book[side][price] = update return ret
async def _snapshot(self, pair: str) -> None: max_depth = self.max_depth if self.max_depth else 1000 if max_depth not in self.valid_depths: for d in self.valid_depths: if d > max_depth: max_depth = d break url = f'{self.rest_endpoint}/depth?symbol={pair}&limit={max_depth}' resp = await self.http_conn.read(url) resp = json.loads(resp, parse_float=Decimal) std_pair = self.exchange_symbol_to_std_symbol(pair) self.last_update_id[std_pair] = resp['lastUpdateId'] self._l2_book[std_pair] = OrderBook( self.id, std_pair, max_depth=self.max_depth, bids={Decimal(u[0]): Decimal(u[1]) for u in resp['bids']}, asks={Decimal(u[0]): Decimal(u[1]) for u in resp['asks']}) await self.book_callback(L2_BOOK, self._l2_book[std_pair], time.time(), timestamp=None, raw=resp, sequence_number=self.last_update_id[std_pair])
def _reset(self): self.partial_received = defaultdict(bool) self.order_id = {} self.open_orders = {} for pair in self.normalized_symbols: self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) self.order_id[pair] = defaultdict(dict)
async def _book(self, msg: dict, timestamp: float): if msg['action'] == 'partial': # snapshot for update in msg['data']: pair = self.exchange_symbol_to_std_symbol(update['instrument_id']) bids = {Decimal(price): Decimal(amount) for price, amount, *_ in update['bids']} asks = {Decimal(price): Decimal(amount) for price, amount, *_ in update['asks']} self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth, checksum_format='OKCOIN', bids=bids, asks=asks) if self.checksum_validation and self._l2_book[pair].book.checksum() != (update['checksum'] & 0xFFFFFFFF): raise BadChecksum await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, timestamp=self.timestamp_normalize(update['timestamp']), raw=msg, checksum=update['checksum'] & 0xFFFFFFFF) else: # update for update in msg['data']: delta = {BID: [], ASK: []} pair = self.exchange_symbol_to_std_symbol(update['instrument_id']) for side in ('bids', 'asks'): s = BID if side == 'bids' else ASK for price, amount, *_ in update[side]: price = Decimal(price) amount = Decimal(amount) if amount == 0: if price in self._l2_book[pair].book[s]: delta[s].append((price, 0)) del self._l2_book[pair].book[s][price] else: delta[s].append((price, amount)) self._l2_book[pair].book[s][price] = amount if self.checksum_validation and self._l2_book[pair].book.checksum() != (update['checksum'] & 0xFFFFFFFF): raise BadChecksum await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, timestamp=self.timestamp_normalize(update['timestamp']), raw=msg, delta=delta, checksum=update['checksum'] & 0xFFFFFFFF)
async def _book(self, msg: dict, pair: str, timestamp: float): delta = {BID: [], ASK: []} msg = msg[1:-2] if 'as' in msg[0]: # Snapshot bids = { Decimal(update[0]): Decimal(update[1]) for update in msg[0]['bs'] } asks = { Decimal(update[0]): Decimal(update[1]) for update in msg[0]['as'] } self._l2_book[pair] = OrderBook( self.id, pair, max_depth=self.max_depth, bids=bids, asks=asks, checksum_format='KRAKEN', truncate=self.max_depth != self.valid_depths[-1]) await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, raw=msg) else: for m in msg: for s, updates in m.items(): side = False if s == 'b': side = BID elif s == 'a': side = ASK if side: for update in updates: price, size, *_ = update price = Decimal(price) size = Decimal(size) if size == 0: # Per Kraken's technical support # they deliver erroneous deletion messages # periodically which should be ignored if price in self._l2_book[pair].book[side]: del self._l2_book[pair].book[side][price] delta[side].append((price, 0)) else: delta[side].append((price, size)) self._l2_book[pair].book[side][price] = size if self.checksum_validation and 'c' in msg[0] and self._l2_book[ pair].book.checksum() != int(msg[0]['c']): raise BadChecksum("Checksum validation on orderbook failed") await self.book_callback( L2_BOOK, self._l2_book[pair], timestamp, delta=delta, raw=msg, checksum=int(msg[0]['c']) if 'c' in msg[0] else None)
async def _book(self, msg: dict, timestamp: float): """ { 'ch':'market.BTC_CW.depth.step0', 'ts':1565857755564, 'tick':{ 'mrid':14848858327, 'id':1565857755, 'bids':[ [ Decimal('9829.99'), 1], ... ] 'asks':[ [ 9830, 625], ... ] }, 'ts':1565857755552, 'version':1565857755, 'ch':'market.BTC_CW.depth.step0' } """ pair = self.exchange_symbol_to_std_symbol(msg['ch'].split('.')[1]) data = msg['tick'] # When Huobi Delists pairs, empty updates still sent: # {'ch': 'market.AKRO-USD.depth.step0', 'ts': 1606951241196, 'tick': {'mrid': 50651100044, 'id': 1606951241, 'ts': 1606951241195, 'version': 1606951241, 'ch': 'market.AKRO-USD.depth.step0'}} # {'ch': 'market.AKRO-USD.depth.step0', 'ts': 1606951242297, 'tick': {'mrid': 50651100044, 'id': 1606951242, 'ts': 1606951242295, 'version': 1606951242, 'ch': 'market.AKRO-USD.depth.step0'}} if 'bids' in data and 'asks' in data: if pair not in self._l2_book: self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) self._l2_book[pair].book.bids = {Decimal(price): Decimal(amount) for price, amount in data['bids']} self._l2_book[pair].book.asks = {Decimal(price): Decimal(amount) for price, amount in data['asks']} await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, timestamp=self.timestamp_normalize(msg['ts']), raw=msg)
async def _book(self, msg: dict, timestamp: float): ''' { 'instrument_name': 'BTC_USDT', 'subscription': 'book.BTC_USDT.150', 'channel': 'book', 'depth': 150, 'data': [ { 'bids': [ [Decimal('57553.03'), Decimal('0.481606'), 2], [Decimal('57552.47'), Decimal('0.000418'), 1], ... ] 'asks': [ [Decimal('57555.44'), Decimal('0.343236'), 1], [Decimal('57555.95'), Decimal('0.026062'), 1], ... ] } ] } ''' pair = self.exchange_symbol_to_std_symbol(msg['instrument_name']) for entry in msg['data']: if pair not in self._l2_book: self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) self._l2_book[pair].book.bids = {price: amount for price, amount, _ in entry['bids']} self._l2_book[pair].book.asks = {price: amount for price, amount, _ in entry['asks']} await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, timestamp=self.timestamp_normalize(entry['t']), raw=entry)
async def _snapshot(self, symbol: str, sequence_number: int): while True: ret, headers = await self.http_conn.read( f'https://api.bittrex.com/v3/markets/{symbol}/orderbook?depth={self.__depth()}', return_headers=True) seq = int(headers['Sequence']) if seq >= sequence_number: break await asyncio.sleep(1.0) self.seq_no[symbol] = seq data = json.loads(ret, parse_float=Decimal) self._l2_book[symbol] = OrderBook(self.id, symbol, max_depth=self.max_depth) for side, entries in data.items(): self._l2_book[symbol].book[side] = { Decimal(e['rate']): Decimal(e['quantity']) for e in entries } await self.book_callback(L2_BOOK, self._l2_book[symbol], time.time(), raw=data, sequence_number=seq)
async def _book_snapshot(self, msg: dict, pair: str, timestamp: float): """ { "feed": "book_snapshot", "product_id": "PI_XBTUSD", "timestamp": 1565342712774, "seq": 30007298, "bids": [ { "price": 11735.0, "qty": 50000.0 }, ... ], "asks": [ { "price": 11739.0, "qty": 47410.0 }, ... ], "tickSize": null } """ bids = {Decimal(update['price']): Decimal(update['qty']) for update in msg['bids']} asks = {Decimal(update['price']): Decimal(update['qty']) for update in msg['asks']} if pair in self._l2_book: self._l2_book[pair].book.bids = bids self._l2_book[pair].book.asks = asks else: self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth, bids=bids, asks=asks) self._l2_book[pair].timestamp = self.timestamp_normalize(msg["timestamp"]) if "timestamp" in msg else None await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, raw=msg, sequence_number=msg['seq'])
async def _snapshot(self, symbol: str): str_to_sign = "GET" + self.rest_endpoints[0].routes.l2book.format( symbol) headers = self.generate_token(str_to_sign) data = await self.http_conn.read(self.rest_endpoints[0].route( 'l2book', self.sandbox).format(symbol), header=headers) timestamp = time.time() data = json.loads(data, parse_float=Decimal) data = data['data'] self.seq_no[symbol] = int(data['sequence']) bids = { Decimal(price): Decimal(amount) for price, amount in data['bids'] } asks = { Decimal(price): Decimal(amount) for price, amount in data['asks'] } self._l2_book[symbol] = OrderBook(self.id, symbol, max_depth=self.max_depth, bids=bids, asks=asks) await self.book_callback(L2_BOOK, self._l2_book[symbol], timestamp, raw=data, sequence_number=int(data['sequence']))
async def _book_snapshot(self, pairs: list): # Coinbase needs some time to send messages to us # before we request the snapshot. If we don't sleep # the snapshot seq no could be much earlier than # the subsequent messages, causing a seq no mismatch. await asyncio.sleep(2) urls = [self.rest_endpoints[0].route('l3book', self.sandbox).format(pair) for pair in pairs] results = [] for url in urls: ret = await self.http_conn.read(url) results.append(ret) # rate limit - 3 per second await asyncio.sleep(0.3) timestamp = time.time() for res, pair in zip(results, pairs): orders = json.loads(res, parse_float=Decimal) npair = self.exchange_symbol_to_std_symbol(pair) self._l3_book[npair] = OrderBook(self.id, pair, max_depth=self.max_depth) self.seq_no[npair] = orders['sequence'] for side in (BID, ASK): for price, size, order_id in orders[side + 's']: price = Decimal(price) size = Decimal(size) if price in self._l3_book[npair].book[side]: self._l3_book[npair].book[side][price][order_id] = size else: self._l3_book[npair].book[side][price] = {order_id: size} self.order_map[order_id] = (price, size) await self.book_callback(L3_BOOK, self._l3_book[npair], timestamp, raw=orders)
async def _snapshot(self, symbol: str): """ { "id": 2679059670, "asks": [[price, amount], [...], ...], "bids": [[price, amount], [...], ...] } """ url = f'https://api.gateio.ws/api/v4/spot/order_book?currency_pair={symbol}&limit=100&with_id=true' ret = await self.http_conn.read(url) data = json.loads(ret, parse_float=Decimal) symbol = self.exchange_symbol_to_std_symbol(symbol) self._l2_book[symbol] = OrderBook(self.id, symbol, max_depth=self.max_depth) self.last_update_id[symbol] = data['id'] self._l2_book[symbol].book.bids = { Decimal(price): Decimal(amount) for price, amount in data['bids'] } self._l2_book[symbol].book.asks = { Decimal(price): Decimal(amount) for price, amount in data['asks'] } await self.book_callback(L2_BOOK, self._l2_book[symbol], time.time(), raw=data, sequence_number=data['id'])
async def _pair_l2_update(self, msg: str, timestamp: float): delta = {BID: [], ASK: []} pair = self.exchange_symbol_to_std_symbol(msg['symbol']) if msg['event'] == 'snapshot': # Reset the book self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) for side in (BID, ASK): for update in msg[side + 's']: price = update['px'] qty = update['qty'] self._l2_book[pair].book[side][price] = qty if qty <= 0: del self._l2_book[pair].book[side][price] delta[side].append((price, qty)) await self.book_callback( L2_BOOK, self._l2_book[pair], timestamp, raw=msg, delta=delta if msg['event'] != 'snapshot' else None, sequence_number=msg['seqnum'])
async def _book(self, msg: dict, timestamp: float): sequence_number = msg['data']['seqnum'] pair = self.exchange_symbol_to_std_symbol(msg['symbol']) delta = {BID: [], ASK: []} if msg['m'] == 'depth-snapshot': self.seq_no[pair] = sequence_number self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) else: # ignore messages while we wait for the snapshot if self.seq_no[pair] is None: return if self.seq_no[pair] + 1 != sequence_number: raise MissingSequenceNumber self.seq_no[pair] = sequence_number for side in ('bids', 'asks'): for price, amount in msg['data'][side]: s = BID if side == 'bids' else ASK price = Decimal(price) size = Decimal(amount) if size == 0: delta[s].append((price, 0)) if price in self._l2_book[pair].book[s]: del self._l2_book[pair].book[s][price] else: delta[s].append((price, size)) self._l2_book[pair].book[s][price] = size await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, timestamp=self.timestamp_normalize(msg['data']['ts']), raw=msg, delta=delta if msg['m'] != 'depth-snapshot' else None, sequence_number=sequence_number)
async def _snapshot(self, pair: str) -> None: max_depth = self.max_depth if self.max_depth else 1000 if max_depth not in self.valid_depths: for d in self.valid_depths: if d > max_depth: max_depth = d break resp = await self.http_conn.read(self.rest_endpoints[0].route( 'l2book', self.sandbox).format(pair, max_depth)) resp = json.loads(resp, parse_float=Decimal) timestamp = self.timestamp_normalize( resp['E']) if 'E' in resp else None std_pair = self.exchange_symbol_to_std_symbol(pair) self.last_update_id[std_pair] = resp['lastUpdateId'] self._l2_book[std_pair] = OrderBook( self.id, std_pair, max_depth=self.max_depth, bids={Decimal(u[0]): Decimal(u[1]) for u in resp['bids']}, asks={Decimal(u[0]): Decimal(u[1]) for u in resp['asks']}) await self.book_callback(L2_BOOK, self._l2_book[std_pair], time.time(), timestamp=timestamp, raw=resp, sequence_number=self.last_update_id[std_pair])
async def l3_book(self, symbol: str, retry_count=1, retry_delay=60): data = await self._request('GET', f'/products/{symbol}/book?level=3', retry_count=retry_count, retry_delay=retry_delay) ret = OrderBook(self.id, symbol) for side in ('bids', 'asks'): for price, size, order_id in data[side]: price = Decimal(price) size = Decimal(size) if price in ret.book[side]: ret.book[side][price][order_id] = size else: ret.book[side][price] = {order_id: size} return ret
async def _snapshot(self, symbol: str, sequence_number: int): while True: ret, headers = await self.http_conn.read( self.rest_endpoints[0].route('l2book', self.sandbox).format( symbol, self.__depth()), return_headers=True) seq = int(headers['Sequence']) if seq >= sequence_number: break await asyncio.sleep(1.0) self.seq_no[symbol] = seq data = json.loads(ret, parse_float=Decimal) self._l2_book[symbol] = OrderBook(self.id, symbol, max_depth=self.max_depth) for side, entries in data.items(): self._l2_book[symbol].book[side] = { Decimal(e['rate']): Decimal(e['quantity']) for e in entries } await self.book_callback(L2_BOOK, self._l2_book[symbol], time.time(), raw=data, sequence_number=seq)
async def _book_snapshot(self, msg: dict, timestamp: float): """ { 'jsonrpc': '2.0', 'method': 'subscription', 'params': { 'channel': 'book.BTC-PERPETUAL.raw', 'data': { 'timestamp': 1598232105378, 'instrument_name': 'BTC-PERPETUAL', 'change_id': 21486665526, ' 'bids': [['new', Decimal('11618.5'), Decimal('279310.0')], ..... ] 'asks': [[ ....... ]] } } } """ ts = msg["params"]["data"]["timestamp"] pair = self.exchange_symbol_to_std_symbol(msg["params"]["data"]["instrument_name"]) self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) self._l2_book[pair].book.bids = {Decimal(price): Decimal(amount) for _, price, amount in msg["params"]["data"]["bids"]} self._l2_book[pair].book.asks = {Decimal(price): Decimal(amount) for _, price, amount in msg["params"]["data"]["asks"]} self.seq_no[pair] = msg["params"]["data"]["change_id"] await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, timestamp=self.timestamp_normalize(ts), sequence_number=msg["params"]["data"]["change_id"], raw=msg)
async def _book(self, msg: dict, timestamp: float): """ { "jsonrpc":"2.0", "method":"channelMessage", "params":{ "channel":"lightning_board_BTC_JPY", "message":{ "mid_price":2534243.0, "bids":[ ], "asks":[ { "price":2534500.0, "size":0.0 }, { "price":2536101.0, "size":0.0 } ] } } } """ snapshot = msg['params']['channel'].startswith('lightning_board_snapshot') if snapshot: pair = msg['params']['channel'].split("lightning_board_snapshot")[1][1:] else: pair = msg['params']['channel'].split("lightning_board")[1][1:] pair = self.exchange_symbol_to_std_symbol(pair) # Ignore deltas until a snapshot is received if pair not in self._l2_book and not snapshot: return delta = None if snapshot: self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) else: delta = {BID: [], ASK: []} data = msg['params']['message'] for side in ('bids', 'asks'): s = BID if side == 'bids' else ASK if snapshot: self._l2_book[pair].book[side] = {d['price']: d['size'] for d in data[side]} else: for entry in data[side]: if entry['size'] == 0: if entry['price'] in self._l2_book[pair].book[side]: del self._l2_book[pair].book[side][entry['price']] delta[s].append((entry['price'], Decimal(0.0))) else: self._l2_book[pair].book[side][entry['price']] = entry['size'] delta[s].append((entry['price'], entry['size'])) await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, raw=msg, delta=delta)
async def l2_book(self, symbol: str, retry_count=1, retry_delay=60): ret = OrderBook(self.id, symbol) sym = self.std_symbol_to_exchange_symbol(symbol) data = await self.http_conn.read(f"{self.api}/markets/{sym}/orderbook?depth=100", retry_count=retry_count, retry_delay=retry_delay) data = json.loads(data, parse_float=Decimal)['result'] ret.book.bids = {u[0]: u[1] for u in data['bids']} ret.book.asks = {u[0]: u[1] for u in data['asks']} return ret
async def l2_book(self, symbol: str, retry_count=1, retry_delay=60): ret = OrderBook(self.id, symbol) sym = self.std_symbol_to_exchange_symbol(symbol).replace("/", "") data = await self._post_public("/public/Depth", {'pair': sym, 'count': 200}, retry_count=retry_count, retry_delay=retry_delay) for _, val in data['result'].items(): ret.book.bids = {Decimal(u[0]): Decimal(u[1]) for u in val['bids']} ret.book.asks = {Decimal(u[0]): Decimal(u[1]) for u in val['asks']} return ret
async def l2_book(self, symbol: str, retry_count=1, retry_delay=60): ret = OrderBook(self.id, symbol) data = await self._get('orderBook/L2', self.std_symbol_to_exchange_symbol(symbol), retry_count, retry_delay) for update in data: side = ASK if update['side'] == 'Sell' else BID ret.book[side][decimal.Decimal(update['price'])] = decimal.Decimal(update['size']) return ret
async def _book(self, msg: dict, chan_id: int, timestamp: float): delta = {BID: [], ASK: []} msg_type = msg[0][0] pair = None # initial update (i.e. snapshot) if msg_type == 'i': delta = None pair = msg[0][1]['currencyPair'] pair = self.exchange_symbol_to_std_symbol(pair) self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth) # 0 is asks, 1 is bids order_book = msg[0][1]['orderBook'] for index, side in enumerate([ASK, BID]): for key in order_book[index]: amount = Decimal(order_book[index][key]) price = Decimal(key) self._l2_book[pair].book[side][price] = amount else: pair = self._channel_map[chan_id] pair = self.exchange_symbol_to_std_symbol(pair) for update in msg: msg_type = update[0] # order book update if msg_type == 'o': side = ASK if update[1] == 0 else BID price = Decimal(update[2]) amount = Decimal(update[3]) if amount == 0: delta[side].append((price, 0)) del self._l2_book[pair].book[side][price] else: delta[side].append((price, amount)) self._l2_book[pair].book[side][price] = amount elif msg_type == 't': # index 1 is trade id, 2 is side, 3 is price, 4 is amount, 5 is timestamp, 6 is timestamp ms _, order_id, _, price, amount, server_ts, _ = update price = Decimal(price) amount = Decimal(amount) t = Trade(self.id, pair, BUY if update[2] == 1 else SELL, amount, price, float(server_ts), id=order_id, raw=msg) await self.callback(TRADES, t, timestamp) else: LOG.warning("%s: Unexpected message received: %s", self.id, msg) await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, delta=delta, raw=msg)
async def l2_book(self, symbol: str, retry_count=1, retry_delay=60): data = await self._request('GET', f'/products/{symbol}/book?level=2', retry_count=retry_count, retry_delay=retry_delay) ret = OrderBook(self.id, symbol) ret.book.bids = {Decimal(u[0]): Decimal(u[1]) for u in data['bids']} ret.book.asks = {Decimal(u[0]): Decimal(u[1]) for u in data['asks']} return ret
async def _process_l3_book(self, msg: dict, timestamp: float): data = msg['data'] chan = msg['channel'] ts = int(data['microtimestamp']) pair = self.exchange_symbol_to_std_symbol(chan.split('_')[-1]) book = OrderBook(self.id, pair, max_depth=self.max_depth) for side in (BID, ASK): for price, size, order_id in data[side + 's']: price = Decimal(price) size = Decimal(size) if price in book.book[side]: book.book[side][price][order_id] = size else: book.book[side][price] = {order_id: size} self._l3_book[pair] = book await self.book_callback(L3_BOOK, self._l3_book[pair], timestamp, timestamp=self.timestamp_normalize(ts), raw=msg)
async def l2_book(self, symbol: str, retry_count=1, retry_delay=60): ret = OrderBook(self.id, symbol) sym = self.std_symbol_to_exchange_symbol(symbol) data = await self._get("returnOrderBook", params=f"¤cyPair={sym}", retry_count=retry_count, retry_delay=retry_delay) ret.book.bids = {Decimal(u[0]): Decimal(u[1]) for u in data['bids']} ret.book.asks = {Decimal(u[0]): Decimal(u[1]) for u in data['asks']} return ret
async def _snapshot(self, pairs: list, conn: AsyncConnection): await asyncio.sleep(5) urls = [f'https://www.bitstamp.net/api/v2/order_book/{sym}' for sym in pairs] results = [await self.http_conn.read(url) for url in urls] results = [json.loads(resp, parse_float=Decimal) for resp in results] for r, pair in zip(results, pairs): std_pair = self.exchange_symbol_to_std_symbol(pair) if pair else 'BTC-USD' self.last_update_id[std_pair] = r['timestamp'] self._l2_book[std_pair] = OrderBook(self.id, std_pair, max_depth=self.max_depth, asks={Decimal(u[0]): Decimal(u[1]) for u in r['asks']}, bids={Decimal(u[0]): Decimal(u[1]) for u in r['bids']}) await self.book_callback(L2_BOOK, self._l2_book[std_pair], time.time(), timestamp=float(r['timestamp']), raw=r)
async def _pair_level2_snapshot(self, msg: dict, timestamp: float): pair = self.exchange_symbol_to_std_symbol(msg['product_id']) bids = {Decimal(price): Decimal(amount) for price, amount in msg['bids']} asks = {Decimal(price): Decimal(amount) for price, amount in msg['asks']} if pair not in self._l2_book: self._l2_book[pair] = OrderBook(self.id, pair, max_depth=self.max_depth, bids=bids, asks=asks) else: self._l2_book[pair].book.bids = bids self._l2_book[pair].book.asks = asks await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, raw=msg)