async def _book(self, pair: str, l2_book: dict, msg: dict, timestamp: float): """For L2 book updates.""" if not isinstance(msg[1], list): if msg[1] != 'hb': LOG.warning('%s: Unexpected book L2 msg %s', self.id, msg) return delta = {BID: [], ASK: []} if isinstance(msg[1][0], list): # snapshot so clear book forced = True l2_book[BID] = sd() l2_book[ASK] = sd() for update in msg[1]: price, _, amount = update price = Decimal(price) amount = Decimal(amount) if amount > 0: side = BID else: side = ASK amount = abs(amount) l2_book[side][price] = amount else: # book update forced = False price, count, amount = msg[1] price = Decimal(price) amount = Decimal(amount) if amount > 0: side = BID else: side = ASK amount = abs(amount) if count > 0: # change at price level delta[side].append((price, amount)) l2_book[side][price] = amount else: # remove price level if price in l2_book[side]: del l2_book[side][price] delta[side].append((price, 0)) await self.book_callback(l2_book, L2_BOOK, pair, forced, delta, timestamp, timestamp)
async def _book(self, msg: dict, timestamp: float): if msg['action'] == 'partial': # snapshot for update in msg['data']: pair = symbol_exchange_to_std(update['instrument_id']) self.l2_book[pair] = { BID: sd({ Decimal(price): Decimal(amount) for price, amount, *_ in update['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount, *_ in update['asks'] }) } if self.checksum_validation and self.__calc_checksum(pair) != ( update['checksum'] & 0xFFFFFFFF): raise BadChecksum await self.book_callback( self.l2_book[pair], L2_BOOK, pair, True, None, timestamp_normalize(self.id, update['timestamp']), timestamp) else: # update for update in msg['data']: delta = {BID: [], ASK: []} pair = symbol_exchange_to_std(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][s]: delta[s].append((price, 0)) del self.l2_book[pair][s][price] else: delta[s].append((price, amount)) self.l2_book[pair][s][price] = amount if self.checksum_validation and self.__calc_checksum(pair) != ( update['checksum'] & 0xFFFFFFFF): raise BadChecksum await self.book_callback( self.l2_book[pair], L2_BOOK, pair, False, delta, timestamp_normalize(self.id, update['timestamp']), timestamp)
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 = symbol_std_to_exchange(msg['ch'].split('.')[1], self.id) data = msg['tick'] forced = pair not in self.l2_book # 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: update = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in data['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in data['asks'] }) } if not forced: self.previous_book[pair] = self.l2_book[pair] self.l2_book[pair] = update await self.book_callback(self.l2_book[pair], L2_BOOK, pair, forced, False, timestamp_normalize(self.id, msg['ts']), timestamp)
async def _book(self, msg): pair = pair_exchange_to_std(msg['ch'].split('.')[1]) data = msg['tick'] self.l2_book[pair] = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in data['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in data['asks'] }) } await self.book_callback(pair, L2_BOOK, False, False, timestamp_normalize(self.id, msg['ts']))
def __init__(self, pairs=None, channels=None, callbacks=None): if len(pairs) != 1: LOG.error("Gemini requires a websocket per trading pair") raise ValueError("Gemini requires a websocket per trading pair") if channels is not None: LOG.error("Gemini does not support different channels") raise ValueError("Gemini does not support different channels") self.pair = pairs[0] super().__init__('wss://api.gemini.com/v1/marketdata/' + pair_std_to_exchange(self.pair, 'GEMINI'), pairs=None, channels=None, callbacks=callbacks) self.book = {BID: sd(), ASK: sd()}
async def _pair_level2_snapshot(self, msg): timestamp = dt.utcnow() timestamp = timestamp.strftime("%Y-%m-%dT%H:%M:%S.%fZ") self.l2_book[msg['product_id']] = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in msg['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in msg['asks'] }) } await self.book_callback(msg['product_id'], L2_BOOK, True, None, timestamp)
def depth(book: dict, depth: int, book_type=L2_BOOK) -> dict: """ Take a book and return a new dict with max `depth` levels per side """ ret = {BID: sd(), ASK: sd()} for side in (BID, ASK): prices = list(book[side].keys())[:depth] if side == ASK else list(book[side].keys())[-depth:] if book_type == L2_BOOK: for price in prices: ret[side][price] = book[side][price] else: for price in prices: ret[side][price] = {order_id: size for order_id, size in ret[side][price].items()} return ret
async def _book(self, msg): chan_id = msg[0] pair = self.channel_map[chan_id]['symbol'] pair = pair_exchange_to_std(pair) if isinstance(msg[1], list): if isinstance(msg[1][0], list): # snapshot so clear book self.l2_book[pair] = {BID: sd(), ASK: sd()} for update in msg[1]: price, _, amount = [Decimal(x) for x in update] if amount > 0: side = BID else: side = ASK amount = abs(amount) self.l2_book[pair][side][price] = amount else: # book update price, count, amount = [Decimal(x) for x in msg[1]] if amount > 0: side = BID else: side = ASK amount = abs(amount) if count > 0: # change at price level self.l2_book[pair][side][price] = amount else: # remove price level del self.l2_book[pair][side][price] elif msg[1] == 'hb': pass else: LOG.warning("{} - Unexpected book msg {}".format(self.id, msg)) if L3_BOOK in self.channels: await self.callbacks[L3_BOOK](feed=self.id, pair=pair, timestamp=None, sequence=None, book=self.l2_book[pair]) else: await self.callbacks[L2_BOOK](feed=self.id, pair=pair, book=self.l2_book[pair])
async def _book(self, msg: dict, timestamp: float): """ example messages: snapshot: {"channel": "orderbook", "market": "BTC/USD", "type": "partial", "data": {"time": 1564834586.3382702, "checksum": 427503966, "bids": [[10717.5, 4.092], ...], "asks": [[10720.5, 15.3458], ...], "action": "partial"}} update: {"channel": "orderbook", "market": "BTC/USD", "type": "update", "data": {"time": 1564834587.1299787, "checksum": 3115602423, "bids": [], "asks": [[10719.0, 14.7461]], "action": "update"}} """ if msg['type'] == 'partial': # snapshot pair = pair_exchange_to_std(msg['market']) self.l2_book[pair] = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in msg['data']['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in msg['data']['asks'] }) } await self.book_callback(self.l2_book[pair], L2_BOOK, pair, True, None, float(msg['data']['time']), timestamp) else: # update delta = {BID: [], ASK: []} pair = pair_exchange_to_std(msg['market']) for side in ('bids', 'asks'): s = BID if side == 'bids' else ASK for price, amount in msg['data'][side]: price = Decimal(price) amount = Decimal(amount) if amount == 0: delta[s].append((price, 0)) del self.l2_book[pair][s][price] else: delta[s].append((price, amount)) self.l2_book[pair][s][price] = amount await self.book_callback(self.l2_book[pair], L2_BOOK, pair, False, delta, float(msg['data']['time']), timestamp)
async def _book(self, msg): """ For L2 book updates """ timestamp = time.time() chan_id = msg[0] pair = self.channel_map[chan_id]['symbol'] pair = pair_exchange_to_std(pair) delta = {BID: defaultdict(list), ASK: defaultdict(list)} forced = False if isinstance(msg[1], list): if isinstance(msg[1][0], list): # snapshot so clear book self.l2_book[pair] = {BID: sd(), ASK: sd()} for update in msg[1]: price, _, amount = update if amount > 0: side = BID else: side = ASK amount = abs(amount) self.l2_book[pair][side][price] = amount forced = True else: # book update price, count, amount = msg[1] if amount > 0: side = BID else: side = ASK amount = abs(amount) if count > 0: # change at price level delta[side] = {UPD: [(price, amount)]} self.l2_book[pair][side][price] = amount else: # remove price level del self.l2_book[pair][side][price] delta[side] = {DEL: [price]} elif msg[1] == 'hb': pass else: LOG.warning("%s: Unexpected book msg %s", self.id, msg) await self.book_callback(pair, L2_BOOK, forced, delta, timestamp)
async def _pair_level2_snapshot(self, msg: dict, timestamp: float): self.l2_book[msg['product_id']] = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in msg['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in msg['asks'] }) } await self.book_callback(msg['product_id'], L2_BOOK, True, None, timestamp)
async def _l3_book(self, msg: dict, timestamp: float): data = msg['data'] chan = msg['channel'] ts = int(data['microtimestamp']) pair = pair_exchange_to_std(chan.split('_')[-1]) book = {BID: sd(), ASK: sd()} for side in (BID, ASK): for price, size, order_id in data[side + 's']: price = Decimal(price) size = Decimal(size) book[side].get(price, sd())[order_id] = size self.l3_book[pair] = book await self.book_callback(self.l3_book[pair], L3_BOOK, pair, False, False, timestamp_normalize(self.id, ts), timestamp)
async def _book_snapshot(self, msg): timestamp = msg["params"]["data"]["timestamp"] pair = msg["params"]["data"]["instrument_name"] self.l2_book[pair] = { BID: sd({ Decimal(price): Decimal(amount) # _ is always 'new' for snapshot for _, price, amount in msg["params"]["data"]["bids"] }), ASK: sd({ Decimal(price): Decimal(amount) for _, price, amount in msg["params"]["data"]["asks"] }) } await self.book_callback(self.l2_book[pair], L2_BOOK, pair, True, None, timestamp_normalize(self.id, timestamp))
async def _snapshot(self, pair: str) -> None: url = f'{self.rest_endpoint}/depth?symbol={pair}&limit={self.book_depth}' async with aiohttp.ClientSession() as session: async with session.get(url) as response: response.raise_for_status() resp = await response.json() std_pair = symbol_exchange_to_std(pair) self.last_update_id[std_pair] = resp['lastUpdateId'] self.l2_book[std_pair] = {BID: sd(), ASK: sd()} for s, side in (('bids', BID), ('asks', ASK)): for update in resp[s]: price = Decimal(update[0]) amount = Decimal(update[1]) self.l2_book[std_pair][side][price] = amount
async def _book(self, msg, chan_id): msg_type = msg[0][0] pair = None # initial update (i.e. snapshot) if msg_type == 'i': pair = msg[0][1]['currencyPair'] pair = pair_exchange_to_std(pair) self.l3_book[pair] = {BID: sd(), ASK: sd()} # 0 is asks, 1 is bids order_book = msg[0][1]['orderBook'] for key in order_book[0]: amount = Decimal(order_book[0][key]) price = Decimal(key) self.l3_book[pair][ASK][price] = amount for key in order_book[1]: amount = Decimal(order_book[1][key]) price = Decimal(key) self.l3_book[pair][BID][price] = amount else: pair = poloniex_id_pair_mapping[chan_id] pair = pair_exchange_to_std(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: del self.l3_book[pair][side][price] else: self.l3_book[pair][side][price] = amount elif msg_type == 't': # index 1 is trade id, 2 is side, 3 is price, 4 is amount, 5 is timestamp price = Decimal(update[3]) side = ASK if update[2] == 0 else BID amount = Decimal(update[4]) await self.callbacks[TRADES](feed=self.id, pair=pair, side=side, amount=amount, price=price) else: LOG.warning("{} - Unexpected message received: {}".format(self.id, msg)) await self.callbacks[L3_BOOK](feed=self.id, pair=pair, book=self.l3_book[pair])
async def _book_snapshot(self, msg: dict): pair = pair_exchange_to_std(msg['symbol']) self.l2_book[pair] = { BID: sd({ Decimal(bid['price']): Decimal(bid['size']) for bid in msg['bid'] }), ASK: sd({ Decimal(ask['price']): Decimal(ask['size']) for ask in msg['ask'] }) } await self.book_callback( self.l2_book[pair], L2_BOOK, pair, True, None, timestamp_normalize(self.id, msg['timestamp']))
async def _book(self, msg: dict, pair: str, timestamp: float): delta = {BID: [], ASK: []} msg = msg[1:-2] if 'as' in msg[0]: # Snapshot self.l2_book[pair] = { BID: sd({ Decimal(update[0]): Decimal(update[1]) for update in msg[0]['bs'] }), ASK: sd({ Decimal(update[0]): Decimal(update[1]) for update in msg[0]['as'] }) } await self.book_callback(self.l2_book[pair], L2_BOOK, pair, True, delta, timestamp, timestamp) else: for m in msg: for s, updates in m.items(): side = BID if s == 'b' else ASK 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][side]: del self.l2_book[pair][side][price] delta[side].append((price, 0)) else: delta[side].append((price, size)) self.l2_book[pair][side][price] = size for side in (BID, ASK): while len(self.l2_book[pair][side]) > self.book_depth: del_price = self.l2_book[pair][side].items( )[0 if side == BID else -1][0] del self.l2_book[pair][side][del_price] delta[side].append((del_price, 0)) await self.book_callback(self.l2_book[pair], L2_BOOK, pair, False, delta, timestamp, timestamp)
async def _pair_level2_snapshot(self, msg: dict, timestamp: float): pair = self.exchange_symbol_to_std_symbol(msg['product_id']) self.l2_book[pair] = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in msg['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in msg['asks'] }) } await self.book_callback(self.l2_book[pair], L2_BOOK, pair, True, None, timestamp, timestamp)
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 = pair_std_to_exchange(msg['ch'].split('.')[1], self.id) data = msg['tick'] forced = pair not in self.l2_book update = { BID: sd({ Decimal(price): Decimal(amount) for price, amount in data['bids'] }), ASK: sd({ Decimal(price): Decimal(amount) for price, amount in data['asks'] }) } if not forced: self.previous_book[pair] = self.l2_book[pair] self.l2_book[pair] = update await self.book_callback(self.l2_book[pair], L2_BOOK, pair, forced, False, timestamp_normalize(self.id, msg['ts']), timestamp)
def __init__(self, pairs=None, channels=None, callbacks=None, **kwargs): if len(pairs) != 1: LOG.error("Gemini requires a websocket per trading pair") raise ValueError("Gemini requires a websocket per trading pair") if channels is not None: LOG.error("Gemini does not support different channels") raise ValueError("Gemini does not support different channels") self.pair = pairs[0] super().__init__('wss://api.gemini.com/v1/marketdata/', pairs=None, channels=None, callbacks=callbacks, **kwargs) self.address += pair_std_to_exchange(self.pair, self.id) self.l2_book = {self.pair: {BID: sd(), ASK: sd()}} self.seq_no = None
def __init__(self, pairs=None, channels=None, callbacks=None, **kwargs): self.channels = None if pairs and len(pairs) == 1: self.pair = pairs[0] super().__init__('wss://api.gemini.com/v1/marketdata/', pairs=None, channels=None, callbacks=callbacks, **kwargs) self.address += pair_std_to_exchange(self.pair, self.id) self.l2_book = {self.pair: {BID: sd(), ASK: sd()}} self.seq_no = None self.pairs = pairs else: self.pairs = pairs self.config = kwargs.get('config', None) self.callbacks = callbacks
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 conn.get(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 = symbol_exchange_to_std(pair) if pair else 'BTC-USD' self.last_update_id[std_pair] = r['timestamp'] self.l2_book[std_pair] = {BID: sd(), ASK: sd()} for s, side in (('bids', BID), ('asks', ASK)): for update in r[s]: price = Decimal(update[0]) amount = Decimal(update[1]) self.l2_book[std_pair][side][price] = amount
async def _l3_book(self, msg): data = msg['data'] chan = msg['channel'] timestamp = data['timestamp'] pair = pair_exchange_to_std(chan.split('_')[-1]) book = {BID: sd(), ASK: sd()} for side in (BID, ASK): for price, size, order_id in data[side + 's']: price = Decimal(price) size = Decimal(size) book[side].get(price, sd())[order_id] = size self.l3_book[pair] = book await self.book_callback(pair=pair, book_type=L3_BOOK, forced=False, delta=False, timestamp=timestamp)
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) url = 'https://api.pro.coinbase.com/products/{}/book?level=3' urls = [url.format(pair) for pair in pairs] results = [] for url in urls: # getting whole book on a initial request 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] = {BID: sd(), ASK: sd()} self.seq_no[npair] = orders['sequence'] for side in (BID, ASK): # orders: # {'bid':['36805.81', '0.03757999', '3b69b4e9-12f0-4a8a-b97f-66f6253db226']} # {'ask':['36805.82', '0.008421', 'e1bf1be9-c323-40ca-97db-87d239ff8a96']} for price, size, order_id in orders[side + 's']: price = Decimal(price) size = Decimal(size) if price in self.l3_book[npair][side]: self.l3_book[npair][side][price][order_id] = size else: self.l3_book[npair][side][price] = {order_id: size} # self.l3_book # 'bids': {Decimal('36804.93'): {'f0ad3603-cafc-484a-bac5-6fde4c12cedf': Decimal('0.09719021'), 'c2061f36-11fd-4d77-a315-2398021930c6': Decimal('2.97219063')}} # 'asks': {Decimal('36804.93'): {'f0ad3603-cafc-484a-bac5-6fde4c12cedf': Decimal('0.09719021'), 'c2061f36-11fd-4d77-a315-2398021930c6': Decimal('2.97219063')}} self.order_map[order_id] = (price, size) # self.order_map: # '07e01fbf-448c-4544-9547-7f531ce86351': (Decimal('1000000000'), Decimal('0.001')) # def book_callback(self, book: dict, book_type: str, symbol: str, forced: bool, delta: dict, timestamp: float, receipt_timestamp: float): await self.book_callback(self.l3_book[npair], L3_BOOK, npair, True, None, timestamp, timestamp)
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 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] = {BID: sd(), ASK: sd()} for s, side in (('bids', BID), ('asks', ASK)): for update in resp[s]: price = Decimal(update[0]) amount = Decimal(update[1]) self.l2_book[std_pair][side][price] = amount
async def _book(self, msg: dict, timestamp: float): pair = self.exchange_symbol_to_std_symbol(msg['id']) delta = {BID: [], ASK: []} forced = False if msg['type'] == 'channel_data': for side, data in msg['contents'].items(): if side == 'offset': offset = int(data) continue side = BID if side == 'bids' else ASK for entry in data: price = Decimal(entry[0]) amount = Decimal(entry[1]) if price in self.offsets[ pair] and offset <= self.offsets[pair][price]: continue self.offsets[pair][price] = offset if amount == 0: if price in self.l2_book[pair]: del self.l2_book[pair][side][price] delta[side].append((price, 0)) else: self.l2_book[pair][side][price] = amount delta[side].append((price, amount)) else: # snapshot self.l2_book[pair] = {BID: sd(), ASK: sd()} self.offsets[pair] = {} forced = True for side, data in msg['contents'].items(): side = BID if side == 'bids' else ASK for entry in data: self.offsets[pair][Decimal(entry['price'])] = int( entry['offset']) self.l2_book[pair][side][Decimal( entry['price'])] = Decimal(entry['size']) await self.book_callback(self.l2_book[pair], L2_BOOK, pair, forced, delta, timestamp, timestamp)
async def _snapshot(self, pairs: list): urls = [f'{self.rest_endpoint}/depth?symbol={sym}&limit={self.book_depth}' for sym in pairs] async def fetch(session, url): async with session.get(url) as response: response.raise_for_status() return await response.json() async with aiohttp.ClientSession() as session: results = await asyncio.gather(*[fetch(session, url) for url in urls]) for r, pair in zip(results, pairs): std_pair = pair_exchange_to_std(pair) self.last_update_id[pair] = r['lastUpdateId'] self.l2_book[std_pair] = {BID: sd(), ASK: sd()} for s, side in (('bids', BID), ('asks', ASK)): for update in r[s]: price = Decimal(update[0]) amount = Decimal(update[1]) self.l2_book[std_pair][side][price] = amount
async def _l2_book(self, msg): """ top 10 orders from each side """ timestamp = msg['data'][0]['timestamp'] pair = None for update in msg['data']: pair = update['symbol'] self.l2_book[pair][BID] = sd({ Decimal(price): Decimal(amount) for price, amount in update['bids'] }) self.l2_book[pair][ASK] = sd({ Decimal(price): Decimal(amount) for price, amount in update['asks'] }) await self.callbacks[L2_BOOK](feed=self.id, pair=pair, book=self.l2_book[pair], timestamp=timestamp)
async def _l2_book(self, msg): data = msg['data'] chan = msg['channel'] timestamp = data['timestamp'] pair = pair_exchange_to_std(chan.split('_')[-1]) book = {} for side in (BID, ASK): book[side] = sd({Decimal(price): Decimal(size) for price, size in data[side + 's']}) self.l2_book[pair] = book await self.book_callback(pair=pair, book_type=L2_BOOK, forced=False, delta=False, timestamp=timestamp)
async def _snapshot(self, pairs: list): await asyncio.sleep(5) urls = [f'https://www.bitstamp.net/api/v2/order_book/{sym}' for sym in pairs] async def fetch(session, url): async with session.get(url) as response: response.raise_for_status() return await response.json() async with aiohttp.ClientSession() as session: results = await asyncio.gather(*[fetch(session, url) for url in urls]) for r, pair in zip(results, pairs): std_pair = pair_exchange_to_std(pair) if pair else 'BTC-USD' self.last_update_id[std_pair] = r['timestamp'] self.l2_book[std_pair] = {BID: sd(), ASK: sd()} for s, side in (('bids', BID), ('asks', ASK)): for update in r[s]: price = Decimal(update[0]) amount = Decimal(update[1]) self.l2_book[std_pair][side][price] = amount