def test_from_dict_returns_expected_tick(self): # Arrange order1 = Order(price=10, size=5, side=OrderSide.BUY, id="1") delta1 = OrderBookDelta( instrument_id=AUDUSD, book_type=BookType.L2_MBP, action=BookAction.ADD, order=order1, ts_event=0, ts_init=0, ) order2 = Order(price=10, size=15, side=OrderSide.BUY, id="2") delta2 = OrderBookDelta( instrument_id=AUDUSD, book_type=BookType.L2_MBP, action=BookAction.ADD, order=order2, ts_event=0, ts_init=0, ) deltas = OrderBookDeltas( instrument_id=AUDUSD, book_type=BookType.L2_MBP, deltas=[delta1, delta2], ts_event=0, ts_init=0, ) # Act result = OrderBookDeltas.from_dict(OrderBookDeltas.to_dict(deltas)) # Assert assert result == deltas
def parse_diff_depth_stream_ws( instrument_id: InstrumentId, data: BinanceOrderBookData, ts_init: int, ) -> OrderBookDeltas: ts_event: int = millis_to_nanos( data.T) if data.T is not None else millis_to_nanos(data.E) bid_deltas: List[OrderBookDelta] = [ parse_book_delta_ws(instrument_id, OrderSide.BUY, d, ts_event, ts_init, data.u) for d in data.b ] ask_deltas: List[OrderBookDelta] = [ parse_book_delta_ws(instrument_id, OrderSide.SELL, d, ts_event, ts_init, data.u) for d in data.a ] return OrderBookDeltas( instrument_id=instrument_id, book_type=BookType.L2_MBP, deltas=bid_deltas + ask_deltas, ts_event=ts_event, ts_init=ts_init, update_id=data.u, )
def parse_book_update_ws( instrument_id: InstrumentId, data: Dict[str, Any], ts_init: int, ) -> OrderBookDeltas: ts_event: int = secs_to_nanos(data["time"]) update_id: int = data["checksum"] bid_deltas: List[OrderBookDelta] = [ parse_book_delta_ws(instrument_id, OrderSide.BUY, d, ts_event, ts_init, update_id) for d in data["bids"] ] ask_deltas: List[OrderBookDelta] = [ parse_book_delta_ws(instrument_id, OrderSide.SELL, d, ts_event, ts_init, update_id) for d in data["asks"] ] return OrderBookDeltas( instrument_id=instrument_id, book_type=BookType.L2_MBP, deltas=bid_deltas + ask_deltas, ts_event=ts_event, ts_init=ts_init, update_id=update_id, )
def order_book_deltas(deltas=None): return OrderBookDeltas( instrument_id=TestIdStubs.audusd_id(), book_type=BookType.L2_MBP, deltas=deltas or [TestDataStubs.order_book_delta()], ts_event=0, ts_init=0, )
def _build_order_book_deltas(values): return OrderBookDeltas( instrument_id=InstrumentId.from_str(values[0]["instrument_id"]), book_type=BookTypeParser.from_str_py(values[0]["book_type"]), deltas=[OrderBookDelta.from_dict(v) for v in values], ts_event=values[0]["ts_event"], ts_init=values[0]["ts_init"], )
def test_to_dict_returns_expected_dict(self): # Arrange order1 = Order(price=10, size=5, side=OrderSide.BUY, id="1") delta1 = OrderBookDelta( instrument_id=AUDUSD, book_type=BookType.L2_MBP, action=BookAction.ADD, order=order1, ts_event=0, ts_init=0, ) order2 = Order(price=10, size=15, side=OrderSide.BUY, id="2") delta2 = OrderBookDelta( instrument_id=AUDUSD, book_type=BookType.L2_MBP, action=BookAction.ADD, order=order2, ts_event=0, ts_init=0, ) deltas = OrderBookDeltas( instrument_id=AUDUSD, book_type=BookType.L2_MBP, deltas=[delta1, delta2], ts_event=0, ts_init=0, ) # Act result = OrderBookDeltas.to_dict(deltas) # Assert assert result == { "type": "OrderBookDeltas", "instrument_id": "AUD/USD.SIM", "book_type": "L2_MBP", "deltas": b'[{"type":"OrderBookDelta","instrument_id":"AUD/USD.SIM","book_type":"L2_MBP","action":"ADD","order_price":10.0,"order_size":5.0,"order_side":"BUY","order_id":"1","update_id":0,"ts_event":0,"ts_init":0},{"type":"OrderBookDelta","instrument_id":"AUD/USD.SIM","book_type":"L2_MBP","action":"ADD","order_price":10.0,"order_size":15.0,"order_side":"BUY","order_id":"2","update_id":0,"ts_event":0,"ts_init":0}]', # noqa "update_id": 0, "ts_event": 0, "ts_init": 0, }
def test_handle_order_book_operations_sends_to_data_engine(self): # Arrange deltas = OrderBookDeltas( instrument_id=ETHUSDT_BINANCE.id, book_type=BookType.L2_MBP, deltas=[], ts_event=0, ts_init=0, ) # Act self.client._handle_data_py(deltas) # Assert assert self.data_engine.data_count == 1
def _merge_order_book_deltas(all_deltas: List[OrderBookDeltas]): per_instrument_deltas = defaultdict(list) book_type = one(set(deltas.book_type for deltas in all_deltas)) ts_event = one(set(deltas.ts_event for deltas in all_deltas)) ts_init = one(set(deltas.ts_init for deltas in all_deltas)) for deltas in all_deltas: per_instrument_deltas[deltas.instrument_id].extend(deltas.deltas) return [ OrderBookDeltas( instrument_id=instrument_id, deltas=deltas, book_type=book_type, ts_event=ts_event, ts_init=ts_init, ) for instrument_id, deltas in per_instrument_deltas.items() ]
def test_hash_str_and_repr(self): # Arrange order1 = Order(price=10, size=5, side=OrderSide.BUY, id="1") delta1 = OrderBookDelta( instrument_id=AUDUSD, book_type=BookType.L2_MBP, action=BookAction.ADD, order=order1, ts_event=0, ts_init=0, ) order2 = Order(price=10, size=15, side=OrderSide.BUY, id="2") delta2 = OrderBookDelta( instrument_id=AUDUSD, book_type=BookType.L2_MBP, action=BookAction.ADD, order=order2, ts_event=0, ts_init=0, ) deltas = OrderBookDeltas( instrument_id=AUDUSD, book_type=BookType.L2_MBP, deltas=[delta1, delta2], ts_event=0, ts_init=0, ) # Act, Assert assert isinstance(hash(deltas), int) assert ( str(deltas) == "OrderBookDeltas('AUD/USD.SIM', book_type=L2_MBP, [OrderBookDelta('AUD/USD.SIM', book_type=L2_MBP, action=ADD, order=Order(10.0, 5.0, BUY, 1), update_id=0, ts_event=0, ts_init=0), OrderBookDelta('AUD/USD.SIM', book_type=L2_MBP, action=ADD, order=Order(10.0, 15.0, BUY, 2), update_id=0, ts_event=0, ts_init=0)], update_id=0, ts_event=0, ts_init=0)" # noqa ) assert ( repr(deltas) == "OrderBookDeltas('AUD/USD.SIM', book_type=L2_MBP, [OrderBookDelta('AUD/USD.SIM', book_type=L2_MBP, action=ADD, order=Order(10.0, 5.0, BUY, 1), update_id=0, ts_event=0, ts_init=0), OrderBookDelta('AUD/USD.SIM', book_type=L2_MBP, action=ADD, order=Order(10.0, 15.0, BUY, 2), update_id=0, ts_event=0, ts_init=0)], update_id=0, ts_event=0, ts_init=0)" # noqa )
def parse_diff_depth_stream_ws(instrument_id: InstrumentId, msg: Dict, ts_init: int) -> OrderBookDeltas: ts_event: int = millis_to_nanos(msg["E"]) update_id: int = msg["U"] bid_deltas = [ parse_book_delta_ws(instrument_id, OrderSide.BUY, d, ts_event, ts_init, update_id) for d in msg.get("b") ] ask_deltas = [ parse_book_delta_ws(instrument_id, OrderSide.SELL, d, ts_event, ts_init, update_id) for d in msg.get("a") ] return OrderBookDeltas( instrument_id=instrument_id, book_type=BookType.L2_MBP, deltas=bid_deltas + ask_deltas, ts_event=ts_event, ts_init=ts_init, update_id=update_id, )
def test_serialize_and_deserialize_order_book_deltas(self): kw = { "instrument_id": "AUD/USD.SIM", "ts_event": 0, "ts_init": 0, "book_type": "L2_MBP", } deltas = OrderBookDeltas( instrument_id=TestStubs.audusd_id(), book_type=BookType.L2_MBP, deltas=[ OrderBookDelta.from_dict({ "action": "ADD", "order_side": "BUY", "order_price": 8.0, "order_size": 30.0, "order_id": "e0364f94-8fcb-0262-cbb3-075c51ee4917", **kw, }), OrderBookDelta.from_dict({ "action": "ADD", "order_side": "SELL", "order_price": 15.0, "order_size": 10.0, "order_id": "cabec174-acc6-9204-9ebf-809da3896daf", **kw, }), ], ts_event=0, ts_init=0, ) serialized = ParquetSerializer.serialize(deltas) deserialized = ParquetSerializer.deserialize(cls=OrderBookDeltas, chunk=serialized) # Assert assert deserialized == [deltas] write_objects(catalog=self.catalog, chunk=[deltas])
def test_orderbook_operations(empty_l2_book): delta = OrderBookDelta( instrument_id=TestStubs.audusd_id(), book_type=BookType.L2_MBP, action=BookAction.UPDATE, order=Order( 0.5814, 672.45, OrderSide.SELL, "4a25c3f6-76e7-7584-c5a3-4ec84808e240", ), ts_event=pd.Timestamp.utcnow().timestamp() * 1e9, ts_init=pd.Timestamp.utcnow().timestamp() * 1e9, ) deltas = OrderBookDeltas( instrument_id=TestStubs.audusd_id(), book_type=BookType.L2_MBP, deltas=[delta], ts_event=pd.Timestamp.utcnow().timestamp() * 1e9, ts_init=pd.Timestamp.utcnow().timestamp() * 1e9, ) empty_l2_book.apply_deltas(deltas) assert empty_l2_book.best_ask_price() == 0.5814
def _handle_book_updates(runner, instrument, ts_event, ts_init): deltas = [] for side in B_SIDE_KINDS: for upd in runner.get(side, []): # TODO(bm): Clean this up if len(upd) == 3: _, price, volume = upd else: price, volume = upd if price == 0.0: continue deltas.append( OrderBookDelta( instrument_id=instrument.id, book_type=BookType.L2_MBP, action=BookAction.DELETE if volume == 0 else BookAction.UPDATE, order=Order( price=price_to_probability(str(price)), size=Quantity(volume, precision=8), side=B2N_MARKET_STREAM_SIDE[side], ), ts_event=ts_event, ts_init=ts_init, )) if deltas: ob_update = OrderBookDeltas( book_type=BookType.L2_MBP, instrument_id=instrument.id, deltas=deltas, ts_event=ts_event, ts_init=ts_init, ) return [ob_update] else: return []
def test_serialize_and_deserialize_order_book_delta(self): delta = OrderBookDelta( instrument_id=TestStubs.audusd_id(), book_type=BookType.L2_MBP, action=BookAction.CLEAR, order=None, ts_event=0, ts_init=0, ) serialized = ParquetSerializer.serialize(delta) [deserialized] = ParquetSerializer.deserialize(cls=OrderBookDelta, chunk=serialized) # Assert expected = OrderBookDeltas( instrument_id=TestStubs.audusd_id(), book_type=BookType.L2_MBP, deltas=[delta], ts_event=0, ts_init=0, ) assert deserialized == expected write_objects(catalog=self.catalog, chunk=[delta])
def test_add_order_book_deltas_adds_to_engine(self, capsys): # Arrange engine = BacktestEngine() engine.add_instrument(AUDUSD_SIM) engine.add_instrument(ETHUSDT_BINANCE) deltas = [ OrderBookDelta( instrument_id=AUDUSD_SIM.id, book_type=BookType.L2_MBP, action=BookAction.ADD, order=Order( price=Price.from_str("13.0"), size=Quantity.from_str("40"), side=OrderSide.SELL, ), ts_event=0, ts_init=0, ), OrderBookDelta( instrument_id=AUDUSD_SIM.id, book_type=BookType.L2_MBP, action=BookAction.ADD, order=Order( price=Price.from_str("12.0"), size=Quantity.from_str("30"), side=OrderSide.SELL, ), ts_event=0, ts_init=0, ), OrderBookDelta( instrument_id=AUDUSD_SIM.id, book_type=BookType.L2_MBP, action=BookAction.ADD, order=Order( price=Price.from_str("11.0"), size=Quantity.from_str("20"), side=OrderSide.SELL, ), ts_event=0, ts_init=0, ), OrderBookDelta( instrument_id=AUDUSD_SIM.id, book_type=BookType.L2_MBP, action=BookAction.ADD, order=Order( price=Price.from_str("10.0"), size=Quantity.from_str("20"), side=OrderSide.BUY, ), ts_event=0, ts_init=0, ), OrderBookDelta( instrument_id=AUDUSD_SIM.id, book_type=BookType.L2_MBP, action=BookAction.ADD, order=Order( price=Price.from_str("9.0"), size=Quantity.from_str("30"), side=OrderSide.BUY, ), ts_event=0, ts_init=0, ), OrderBookDelta( instrument_id=AUDUSD_SIM.id, book_type=BookType.L2_MBP, action=BookAction.ADD, order=Order( price=Price.from_str("0.0"), size=Quantity.from_str("40"), side=OrderSide.BUY, ), ts_event=0, ts_init=0, ), ] operations1 = OrderBookDeltas( instrument_id=ETHUSDT_BINANCE.id, book_type=BookType.L2_MBP, deltas=deltas, ts_event=0, ts_init=0, ) operations2 = OrderBookDeltas( instrument_id=ETHUSDT_BINANCE.id, book_type=BookType.L2_MBP, deltas=deltas, ts_event=1000, ts_init=1000, ) # Act engine.add_order_book_data([operations2, operations1]) # <-- not sorted # Assert log = "".join(capsys.readouterr()) assert "Added 2 ETHUSDT.BINANCE OrderBookData elements." in log
def test_serialize_and_deserialize_order_book_deltas_grouped(self): kw = { "instrument_id": "AUD/USD.SIM", "ts_event": 0, "ts_init": 0, "book_type": "L2_MBP", } deltas = [ { "action": "ADD", "order_side": "SELL", "order_price": 0.9901, "order_size": 327.25, "order_id": "1", }, { "action": "CLEAR", "order_side": None, "order_price": None, "order_size": None, "order_id": None, }, { "action": "ADD", "order_side": "SELL", "order_price": 0.98039, "order_size": 27.91, "order_id": "2", }, { "action": "ADD", "order_side": "SELL", "order_price": 0.97087, "order_size": 14.43, "order_id": "3", }, ] deltas = OrderBookDeltas( instrument_id=TestStubs.audusd_id(), book_type=BookType.L2_MBP, deltas=[OrderBookDelta.from_dict({ **kw, **d }) for d in deltas], ts_event=0, ts_init=0, ) serialized = ParquetSerializer.serialize(deltas) [deserialized] = ParquetSerializer.deserialize(cls=OrderBookDeltas, chunk=serialized) # Assert assert deserialized == deltas write_objects(catalog=self.catalog, chunk=[deserialized]) assert [d.action for d in deserialized.deltas] == [ BookAction.ADD, BookAction.CLEAR, BookAction.ADD, BookAction.ADD, ]
def test_fully_qualified_name(self): # Arrange, Act, Assert assert (OrderBookDeltas.fully_qualified_name() == "nautilus_trader.model.orderbook.data.OrderBookDeltas")