def test_byte_reader_parser(self): def block_parser(block: bytes, instrument_provider): for raw in block.split(b"\\n"): ts, line = raw.split(b" - ") state = { "ts_init": int(pd.Timestamp(ts.decode(), tz="UTC").to_datetime64()) } line = line.strip().replace(b"b'", b"") orjson.loads(line) for obj in BetfairTestStubs.parse_betfair( line, instrument_provider=instrument_provider): values = obj.to_dict(obj) values["ts_init"] = state["ts_init"] yield obj.from_dict(values) provider = BetfairInstrumentProvider.from_instruments( [BetfairTestStubs.betting_instrument()]) block = BetfairDataProvider.badly_formatted_log() reader = ByteReader( block_parser=partial(block_parser, instrument_provider=provider), instrument_provider=provider, ) data = list(reader.parse(block=block)) result = [pd.Timestamp(d.ts_init).isoformat() for d in data] expected = ["2021-06-29T06:03:14.528000"] assert result == expected
def instrument_list(mock_load_markets_metadata, loop: asyncio.AbstractEventLoop): """Prefill `INSTRUMENTS` cache for tests""" global INSTRUMENTS # Setup logger = LiveLogger(loop=loop, clock=LiveClock(), level_stdout=LogLevel.ERROR) client = BetfairTestStubs.betfair_client(loop=loop, logger=logger) logger = LiveLogger(loop=loop, clock=LiveClock(), level_stdout=LogLevel.DEBUG) instrument_provider = BetfairInstrumentProvider(client=client, logger=logger, market_filter={}) # Load instruments market_ids = BetfairDataProvider.market_ids() catalog = { r["marketId"]: r for r in BetfairResponses.betting_list_market_catalogue()["result"] if r["marketId"] in market_ids } mock_load_markets_metadata.return_value = catalog t = loop.create_task( instrument_provider.load_all_async( market_filter={"market_id": market_ids})) loop.run_until_complete(t) # Fill INSTRUMENTS global cache INSTRUMENTS.extend(instrument_provider.list_all()) assert INSTRUMENTS
def test_betfair_orderbook(self): book = L2OrderBook( instrument_id=BetfairTestStubs.instrument_id(), price_precision=2, size_precision=2, ) for update in BetfairDataProvider.raw_market_updates(): for message in on_market_update( instrument_provider=self.instrument_provider, update=update): try: if isinstance(message, OrderBookSnapshot): book.apply_snapshot(message) elif isinstance(message, OrderBookDeltas): book.apply_deltas(message) elif isinstance(message, OrderBookDelta): book.apply_delta(message) elif isinstance(message, (Ticker, TradeTick, InstrumentStatusUpdate, InstrumentClosePrice)): pass else: raise NotImplementedError(str(type(message))) book.check_integrity() except Exception as ex: print(str(type(ex)) + " " + str(ex))
def test_instrument_in_play_events(self): events = [ msg for update in BetfairDataProvider.raw_market_updates() for msg in on_market_update( instrument_provider=self.client.instrument_provider(), update=update) if isinstance(msg, InstrumentStatusUpdate) ] assert len(events) == 14 result = [ev.status for ev in events] expected = [ InstrumentStatus.PRE_OPEN.value, InstrumentStatus.PRE_OPEN.value, InstrumentStatus.PRE_OPEN.value, InstrumentStatus.PRE_OPEN.value, InstrumentStatus.PRE_OPEN.value, InstrumentStatus.PRE_OPEN.value, InstrumentStatus.PAUSE.value, InstrumentStatus.PAUSE.value, InstrumentStatus.OPEN.value, InstrumentStatus.OPEN.value, InstrumentStatus.PAUSE.value, InstrumentStatus.PAUSE.value, InstrumentStatus.CLOSED.value, InstrumentStatus.CLOSED.value, ] assert result == expected
def test_instrument_closing_events(self): updates = BetfairDataProvider.raw_market_updates() messages = on_market_update( instrument_provider=self.client.instrument_provider(), update=updates[-1], ) assert len(messages) == 4 assert ( isinstance(messages[0], InstrumentStatusUpdate) and messages[0].status == InstrumentStatus.CLOSED ) assert isinstance(messages[1], InstrumentClosePrice) and messages[1].close_price == 1.0000 assert ( isinstance(messages[1], InstrumentClosePrice) and messages[1].close_type == InstrumentCloseType.EXPIRED ) assert ( isinstance(messages[2], InstrumentStatusUpdate) and messages[2].status == InstrumentStatus.CLOSED ) assert isinstance(messages[3], InstrumentClosePrice) and messages[3].close_price == 0.0 assert ( isinstance(messages[3], InstrumentClosePrice) and messages[3].close_type == InstrumentCloseType.EXPIRED )
def test_instrument_opening_events(self): updates = BetfairDataProvider.raw_market_updates() messages = on_market_update( instrument_provider=self.client.instrument_provider(), update=updates[0]) assert len(messages) == 2 assert (isinstance(messages[0], InstrumentStatusUpdate) and messages[0].status == InstrumentStatus.PRE_OPEN) assert (isinstance(messages[1], InstrumentStatusUpdate) and messages[0].status == InstrumentStatus.PRE_OPEN)
async def test_generate_trades_list(self): patch( "betfairlightweight.endpoints.betting.Betting.list_cleared_orders", return_value=BetfairDataProvider.list_cleared_orders(order_id="226125004209"), ) patch.object( self.client, "venue_order_id_to_client_order_id", {"226125004209": ClientOrderId("1")}, ) result = await generate_trades_list( self=self.client, venue_order_id="226125004209", symbol=None, since=None ) assert result
def handle(self): self.on_connection_message() if self.connection_info.get("auth") is None: return self.close() for n, data in enumerate(BetfairDataProvider.raw_market_updates()): line = orjson.dumps(data) try: print("SERVER [SEND]", line) self.wfile.write(line.strip() + b"\r\n") time.sleep(0.1) if (self.connection_info.get("num_lines") is not None and n > self.connection_info["num_lines"]): return self.close() except BrokenPipeError: return self.close()
def setup(self): # Fixture Setup data_catalog_setup() config = BacktestEngineConfig( bypass_logging=True, run_analysis=False, ) self.engine = BacktestEngine(config=config) self.venue = Venue("BETFAIR") data = BetfairDataProvider.betfair_feed_parsed( market_id="1.166811431.bz2", folder="data/betfair") instruments = [d for d in data if isinstance(d, BettingInstrument)] for instrument in instruments[:1]: trade_ticks = [ d for d in data if isinstance(d, TradeTick) and d.instrument_id == instrument.id ] order_book_deltas = [ d for d in data if isinstance(d, OrderBookData) and d.instrument_id == instrument.id ] self.engine.add_instrument(instrument) self.engine.add_ticks(trade_ticks) self.engine.add_order_book_data(order_book_deltas) self.instrument = instrument self.engine.add_venue( venue=self.venue, venue_type=VenueType.EXCHANGE, account_type=AccountType.MARGIN, base_currency=None, oms_type=OMSType.NETTING, starting_balances=[Money(10_000, GBP)], book_type=BookType.L2_MBP, )
def setup(self): # Fixture Setup self.loop = asyncio.get_event_loop() self.loop.set_debug(True) self.clock = LiveClock() self.uuid_factory = UUIDFactory() self.trader_id = TestStubs.trader_id() self.uuid = UUID4() self.venue = BETFAIR_VENUE self.account_id = AccountId(self.venue.value, "001") # Setup logging self.logger = LiveLogger(loop=self.loop, clock=self.clock, level_stdout=LogLevel.ERROR) self._log = LoggerAdapter("TestBetfairExecutionClient", self.logger) self.msgbus = MessageBus( trader_id=self.trader_id, clock=self.clock, logger=self.logger, ) self.cache = TestStubs.cache() self.cache.add_instrument(BetfairTestStubs.betting_instrument()) self.portfolio = Portfolio( msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) self.data_engine = LiveDataEngine( loop=self.loop, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) self.betfair_client = BetfairTestStubs.betfair_client( loop=self.loop, logger=self.logger) self.instrument_provider = BetfairTestStubs.instrument_provider( betfair_client=self.betfair_client) # Add a subset of instruments instruments = [ ins for ins in INSTRUMENTS if ins.market_id in BetfairDataProvider.market_ids() ] self.instrument_provider.add_bulk(instruments) self.client = BetfairDataClient( loop=self.loop, client=self.betfair_client, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, instrument_provider=self.instrument_provider, market_filter={}, ) self.data_engine.register_client(self.client) # Re-route exec engine messages through `handler` self.messages = [] def handler(x, endpoint): self.messages.append(x) if endpoint == "execute": self.data_engine.execute(x) elif endpoint == "process": self.data_engine.process(x) elif endpoint == "response": self.data_engine.response(x) self.msgbus.deregister( endpoint="DataEngine.execute", handler=self.data_engine.execute) # type: ignore self.msgbus.register( endpoint="DataEngine.execute", handler=partial(handler, endpoint="execute") # type: ignore ) self.msgbus.deregister( endpoint="DataEngine.process", handler=self.data_engine.process) # type: ignore self.msgbus.register( endpoint="DataEngine.process", handler=partial(handler, endpoint="process") # type: ignore ) self.msgbus.deregister( endpoint="DataEngine.response", handler=self.data_engine.response) # type: ignore self.msgbus.register( endpoint="DataEngine.response", handler=partial(handler, endpoint="response") # type: ignore )