Skip to content

Commit c79cec1

Browse files
committed
Update betfair tests for sequence completed messages
1 parent f7dda69 commit c79cec1

File tree

4 files changed

+38
-14
lines changed

4 files changed

+38
-14
lines changed

RELEASES.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This release adds support for Python 3.13 (*not* yet compatible with free-thread
1212
- Added additional price and quantity precision validations for matching engine
1313
- Added log file rotation with additional config options `max_file_size` and `max_backup_count` (#2468), thanks @xingyanan and @twitu
1414
- Added `bars_timestamp_on_close` config option for `BybitDataClientConfig` (default `True` to match Nautilus conventions)
15+
- Added `BetfairSequenceCompleted` custom data type for Betfair to mark the completion of a sequence of messages
1516
- Improved robustness of in-flight order check for `LiveExecutionEngine`, once exceeded query retries will resolve submitted orders as rejected and pending orders as canceled
1617
- Improved logging for `BacktestNode` crashes with full stack trace and prettier config logging
1718

tests/integration_tests/adapters/betfair/test_betfair_data.py

+26-8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from nautilus_trader.adapters.betfair.constants import BETFAIR_VENUE
2525
from nautilus_trader.adapters.betfair.data import BetfairDataClient
26+
from nautilus_trader.adapters.betfair.data_types import BetfairSequenceCompleted
2627
from nautilus_trader.adapters.betfair.data_types import BetfairStartingPrice
2728
from nautilus_trader.adapters.betfair.data_types import BetfairTicker
2829
from nautilus_trader.adapters.betfair.data_types import BSPOrderBookDelta
@@ -176,7 +177,12 @@ async def test_market_sub_image_market_def(data_client, mock_data_engine_process
176177
# Assert - expected messages
177178
mock_calls = mock_data_engine_process.call_args_list
178179
result = [type(call.args[0]).__name__ for call in mock_data_engine_process.call_args_list]
179-
expected = ["BettingInstrument"] * 7 + ["InstrumentStatus"] * 7 + ["OrderBookDeltas"] * 7
180+
expected = (
181+
["BettingInstrument"] * 7
182+
+ ["InstrumentStatus"] * 7
183+
+ ["OrderBookDeltas"] * 7
184+
+ ["BetfairSequenceCompleted"]
185+
)
180186
assert result == expected
181187

182188
# Assert - Check orderbook prices
@@ -219,21 +225,27 @@ def test_market_update(data_client, mock_data_engine_process):
219225
def test_market_update_md(data_client, mock_data_engine_process):
220226
data_client.on_market_update(BetfairStreaming.mcm_UPDATE_md())
221227
result = [type(call.args[0]).__name__ for call in mock_data_engine_process.call_args_list]
222-
expected = ["BettingInstrument"] * 2 + ["InstrumentStatus"] * 2
228+
expected = ["BettingInstrument"] * 2 + ["InstrumentStatus"] * 2 + ["BetfairSequenceCompleted"]
223229
assert result == expected
224230

225231

226232
def test_market_update_live_image(data_client, mock_data_engine_process):
227233
data_client.on_market_update(BetfairStreaming.mcm_live_IMAGE())
228234
result = [type(call.args[0]).__name__ for call in mock_data_engine_process.call_args_list]
229-
expected = ["OrderBookDeltas"] + ["TradeTick"] * 13 + ["OrderBookDeltas"] + ["TradeTick"] * 17
235+
expected = (
236+
["OrderBookDeltas"]
237+
+ ["TradeTick"] * 13
238+
+ ["OrderBookDeltas"]
239+
+ ["TradeTick"] * 17
240+
+ ["BetfairSequenceCompleted"]
241+
)
230242
assert result == expected
231243

232244

233245
def test_market_update_live_update(data_client, mock_data_engine_process):
234246
data_client.on_market_update(BetfairStreaming.mcm_live_UPDATE())
235247
result = [type(call.args[0]).__name__ for call in mock_data_engine_process.call_args_list]
236-
expected = ["TradeTick", "OrderBookDeltas"]
248+
expected = ["TradeTick", "OrderBookDeltas", "BetfairSequenceCompleted"]
237249
assert result == expected
238250

239251

@@ -259,6 +271,7 @@ def test_market_bsp(data_client, mock_data_engine_process):
259271
mock_call_args = [call.args[0] for call in mock_data_engine_process.call_args_list]
260272
result = Counter([type(args).__name__ for args in mock_call_args])
261273
expected = {
274+
"BetfairSequenceCompleted": 2,
262275
"BettingInstrument": 9,
263276
"TradeTick": 95,
264277
"OrderBookDeltas": 11,
@@ -300,6 +313,8 @@ def test_orderbook_updates(data_client, parser):
300313
for raw_update in BetfairStreaming.market_updates():
301314
line = stream_decode(raw_update)
302315
for update in parser.parse(mcm=line):
316+
if isinstance(update, BetfairSequenceCompleted):
317+
continue
303318
if len(order_books) > 1 and update.instrument_id != list(order_books)[1]:
304319
continue
305320
if isinstance(update, OrderBookDeltas) and update.is_snapshot:
@@ -334,12 +349,13 @@ def test_orderbook_updates(data_client, parser):
334349
def test_instrument_opening_events(data_client, parser):
335350
updates = BetfairDataProvider.market_updates()
336351
messages = parser.parse(updates[0])
337-
assert len(messages) == 4
352+
assert len(messages) == 5
338353
assert isinstance(messages[0], BettingInstrument)
339354
assert isinstance(messages[2], InstrumentStatus)
340355
assert messages[2].action == MarketStatusAction.PRE_OPEN
341356
assert isinstance(messages[3], InstrumentStatus)
342357
assert messages[3].action == MarketStatusAction.PRE_OPEN
358+
assert isinstance(messages[4], BetfairSequenceCompleted)
343359

344360

345361
def test_instrument_in_play_events(data_client, parser):
@@ -389,8 +405,8 @@ def test_instrument_update(data_client, cache, parser):
389405
def test_instrument_closing_events(data_client, parser):
390406
updates = BetfairDataProvider.market_updates()
391407
messages = parser.parse(updates[-1])
392-
assert len(messages) == 6
393-
ins1, ins2, status1, status2, close1, close2 = messages
408+
assert len(messages) == 7
409+
ins1, ins2, status1, status2, close1, close2, completed = messages
394410

395411
# Instrument1
396412
assert isinstance(ins1, BettingInstrument)
@@ -408,6 +424,8 @@ def test_instrument_closing_events(data_client, parser):
408424
assert close2.close_price == 0.0
409425
assert close2.close_type == InstrumentCloseType.CONTRACT_EXPIRED
410426

427+
assert isinstance(completed, BetfairSequenceCompleted)
428+
411429

412430
def test_betfair_ticker(data_client, mock_data_engine_process) -> None:
413431
# Arrange
@@ -472,7 +490,7 @@ def test_betfair_orderbook(data_client, parser) -> None:
472490
# Act, Assert
473491
for update in BetfairDataProvider.market_updates():
474492
for message in parser.parse(update):
475-
if isinstance(message, BettingInstrument | CustomData):
493+
if isinstance(message, BetfairSequenceCompleted | BettingInstrument | CustomData):
476494
continue
477495
if message.instrument_id not in books:
478496
books[message.instrument_id] = create_betfair_order_book(

tests/integration_tests/adapters/betfair/test_betfair_parsing.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
# fmt: off
5050
from nautilus_trader.adapters.betfair.common import BETFAIR_TICK_SCHEME
5151
from nautilus_trader.adapters.betfair.common import OrderSideParser
52+
from nautilus_trader.adapters.betfair.data_types import BetfairSequenceCompleted
5253
from nautilus_trader.adapters.betfair.data_types import BetfairStartingPrice
5354
from nautilus_trader.adapters.betfair.data_types import BetfairTicker
5455
from nautilus_trader.adapters.betfair.data_types import BSPOrderBookDelta
@@ -194,6 +195,7 @@ def test_market_definition_to_instrument_updates(self):
194195
"InstrumentStatus": 7,
195196
"OrderBookDeltas": 7,
196197
"BettingInstrument": 7,
198+
"BetfairSequenceCompleted": 1,
197199
},
198200
)
199201
assert counts == expected
@@ -238,10 +240,10 @@ def test_market_change_ticker(self):
238240
@pytest.mark.parametrize(
239241
("filename", "num_msgs"),
240242
[
241-
("1-166564490.bz2", 2506),
242-
("1-166811431.bz2", 17852),
243-
("1-180305278.bz2", 15165),
244-
("1-206064380.bz2", 52111),
243+
("1-166564490.bz2", 4114),
244+
("1-166811431.bz2", 29209),
245+
("1-180305278.bz2", 22850),
246+
("1-206064380.bz2", 70904),
245247
],
246248
)
247249
def test_parsing_streaming_file(self, filename, num_msgs):
@@ -266,6 +268,7 @@ def test_parsing_streaming_file_message_counts(self):
266268
"OrderBookDeltas": 40525,
267269
"BetfairTicker": 4658,
268270
"TradeTick": 3487,
271+
"BetfairSequenceCompleted": 18793,
269272
"BettingInstrument": 260,
270273
"BSPOrderBookDelta": 2824,
271274
"InstrumentStatus": 260,
@@ -495,11 +498,12 @@ async def test_merge_order_book_deltas(self):
495498
)
496499
mcm = msgspec.json.decode(raw, type=MCM)
497500
updates = self.parser.parse(mcm)
498-
assert len(updates) == 3
499-
trade, ticker, deltas = updates
501+
assert len(updates) == 4
502+
trade, ticker, deltas, completed = updates
500503
assert isinstance(trade, TradeTick)
501504
assert isinstance(ticker, Data)
502505
assert isinstance(deltas, OrderBookDeltas)
506+
assert isinstance(completed, BetfairSequenceCompleted)
503507
assert len(deltas.deltas) == 2
504508

505509
def test_make_order_limit(self):

tests/unit_tests/persistence/test_catalog.py

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def test_list_data_types(catalog_betfair: ParquetDataCatalog) -> None:
5454
data_types = catalog_betfair.list_data_types()
5555
expected = [
5656
"betting_instrument",
57+
"custom_betfair_sequence_completed",
5758
"custom_betfair_ticker",
5859
"instrument_status",
5960
"order_book_delta",

0 commit comments

Comments
 (0)