Skip to content

Commit 798400f

Browse files
committed
Add Actor.unsubscribe_order_book_depth
1 parent 9c1fa48 commit 798400f

File tree

4 files changed

+90
-12
lines changed

4 files changed

+90
-12
lines changed

RELEASES.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Released on TBD (UTC).
55
### Enhancements
66
- Added processing of `OrderBookDepth10` for `BacktestEngine` and `OrderMatchingEngine` (#2542), thanks @limx0
77
- Added `Actor.subscribe_order_book_depth(...)` subscription method (#2555), thanks @limx0
8+
- Added `Actor.unsubscribe_order_book_depth(...)` subscription method
89
- Added `Actor.on_order_book_depth(...)` handler method (#2555), thanks @limx0
910
- Added WebSocket batch order operations for Bybit (#2521), thanks @sunlei
1011
- Added `UnixNanos::max()` convenience method for the maximum valid value

nautilus_trader/common/actor.pxd

+1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ cdef class Actor(Component):
187187
cpdef void unsubscribe_instruments(self, Venue venue, ClientId client_id=*, dict[str, object] params=*)
188188
cpdef void unsubscribe_instrument(self, InstrumentId instrument_id, ClientId client_id=*, dict[str, object] params=*)
189189
cpdef void unsubscribe_order_book_deltas(self, InstrumentId instrument_id, ClientId client_id=*, dict[str, object] params=*)
190+
cpdef void unsubscribe_order_book_depth(self, InstrumentId instrument_id, ClientId client_id=*, dict[str, object] params=*)
190191
cpdef void unsubscribe_order_book_at_interval(self, InstrumentId instrument_id, int interval_ms=*, ClientId client_id=*, dict[str, object] params=*)
191192
cpdef void unsubscribe_quote_ticks(self, InstrumentId instrument_id, ClientId client_id=*, dict[str, object] params=*)
192193
cpdef void unsubscribe_trade_ticks(self, InstrumentId instrument_id, ClientId client_id=*, dict[str, object] params=*)

nautilus_trader/common/actor.pyx

+44-2
Original file line numberDiff line numberDiff line change
@@ -1987,6 +1987,48 @@ cdef class Actor(Component):
19871987

19881988
self._send_data_cmd(command)
19891989

1990+
cpdef void unsubscribe_order_book_depth(
1991+
self,
1992+
InstrumentId instrument_id,
1993+
ClientId client_id = None,
1994+
dict[str, object] params = None,
1995+
):
1996+
"""
1997+
Unsubscribe the order book depth stream for the given instrument ID.
1998+
1999+
Parameters
2000+
----------
2001+
instrument_id : InstrumentId
2002+
The order book instrument to subscribe to.
2003+
client_id : ClientId, optional
2004+
The specific client ID for the command.
2005+
If ``None`` then will be inferred from the venue in the instrument ID.
2006+
params : dict[str, Any], optional
2007+
Additional parameters potentially used by a specific client.
2008+
2009+
"""
2010+
Condition.not_none(instrument_id, "instrument_id")
2011+
Condition.is_true(self.trader_id is not None, "The actor has not been registered")
2012+
2013+
self._msgbus.unsubscribe(
2014+
topic=f"data.book.depth"
2015+
f".{instrument_id.venue}"
2016+
f".{instrument_id.symbol.topic()}",
2017+
handler=self.handle_order_book_depth,
2018+
)
2019+
2020+
cdef UnsubscribeOrderBook command = UnsubscribeOrderBook(
2021+
instrument_id=instrument_id,
2022+
only_deltas=True,
2023+
client_id=client_id,
2024+
venue=instrument_id.venue,
2025+
command_id=UUID4(),
2026+
ts_init=self._clock.timestamp_ns(),
2027+
params=params,
2028+
)
2029+
2030+
self._send_data_cmd(command)
2031+
19902032
cpdef void unsubscribe_order_book_at_interval(
19912033
self,
19922034
InstrumentId instrument_id,
@@ -3295,7 +3337,7 @@ cdef class Actor(Component):
32953337
"""
32963338
Handle the given order book depth
32973339
3298-
Passes to `on_order_book` if state is ``RUNNING``.
3340+
Passes to `on_order_book_depth` if state is ``RUNNING``.
32993341
33003342
Parameters
33013343
----------
@@ -3307,7 +3349,7 @@ cdef class Actor(Component):
33073349
System method (not intended to be called by user code).
33083350
33093351
"""
3310-
Condition.not_none(depth, "order_book")
3352+
Condition.not_none(depth, "depth")
33113353

33123354
if self._fsm.state == ComponentState.RUNNING:
33133355
try:

tests/unit_tests/common/test_actor.py

+44-10
Original file line numberDiff line numberDiff line change
@@ -1589,7 +1589,7 @@ def test_unsubscribe_custom_data_with_client_id(self) -> None:
15891589
assert self.data_engine.command_count == 2
15901590
assert len(actor.msgbus.subscriptions()) == 4 # Portfolio subscriptions only
15911591

1592-
def test_subscribe_order_book_at_interval(self) -> None:
1592+
def test_subscribe_order_book_deltas(self) -> None:
15931593
# Arrange
15941594
actor = MockActor()
15951595
actor.register_base(
@@ -1600,12 +1600,12 @@ def test_subscribe_order_book_at_interval(self) -> None:
16001600
)
16011601

16021602
# Act
1603-
actor.subscribe_order_book_at_interval(AUDUSD_SIM.id, book_type=BookType.L2_MBP)
1603+
actor.subscribe_order_book_deltas(AUDUSD_SIM.id, book_type=BookType.L2_MBP)
16041604

16051605
# Assert
16061606
assert self.data_engine.command_count == 1
16071607

1608-
def test_unsubscribe_order_book_at_interval(self) -> None:
1608+
def test_unsubscribe_order_book_deltas(self) -> None:
16091609
# Arrange
16101610
actor = MockActor()
16111611
actor.register_base(
@@ -1615,15 +1615,15 @@ def test_unsubscribe_order_book_at_interval(self) -> None:
16151615
clock=self.clock,
16161616
)
16171617

1618-
actor.subscribe_order_book_at_interval(AUDUSD_SIM.id, book_type=BookType.L2_MBP)
1618+
actor.subscribe_order_book_deltas(AUDUSD_SIM.id)
16191619

16201620
# Act
1621-
actor.unsubscribe_order_book_at_interval(AUDUSD_SIM.id)
1621+
actor.unsubscribe_order_book_deltas(AUDUSD_SIM.id)
16221622

16231623
# Assert
16241624
assert self.data_engine.command_count == 2
16251625

1626-
def test_subscribe_order_book_data(self) -> None:
1626+
def test_subscribe_order_book_depth10(self) -> None:
16271627
# Arrange
16281628
actor = MockActor()
16291629
actor.register_base(
@@ -1634,12 +1634,12 @@ def test_subscribe_order_book_data(self) -> None:
16341634
)
16351635

16361636
# Act
1637-
actor.subscribe_order_book_deltas(AUDUSD_SIM.id, book_type=BookType.L2_MBP)
1637+
actor.subscribe_order_book_depth(AUDUSD_SIM.id, book_type=BookType.L2_MBP, depth=10)
16381638

16391639
# Assert
16401640
assert self.data_engine.command_count == 1
16411641

1642-
def test_unsubscribe_order_book_deltas(self) -> None:
1642+
def test_unsubscribe_order_book_depth10(self) -> None:
16431643
# Arrange
16441644
actor = MockActor()
16451645
actor.register_base(
@@ -1649,10 +1649,44 @@ def test_unsubscribe_order_book_deltas(self) -> None:
16491649
clock=self.clock,
16501650
)
16511651

1652-
actor.unsubscribe_order_book_deltas(AUDUSD_SIM.id)
1652+
actor.subscribe_order_book_depth(AUDUSD_SIM.id, book_type=BookType.L2_MBP, depth=10)
16531653

16541654
# Act
1655-
actor.unsubscribe_order_book_deltas(AUDUSD_SIM.id)
1655+
actor.unsubscribe_order_book_depth(AUDUSD_SIM.id)
1656+
1657+
# Assert
1658+
assert self.data_engine.command_count == 2
1659+
1660+
def test_subscribe_order_book_at_interval(self) -> None:
1661+
# Arrange
1662+
actor = MockActor()
1663+
actor.register_base(
1664+
portfolio=self.portfolio,
1665+
msgbus=self.msgbus,
1666+
cache=self.cache,
1667+
clock=self.clock,
1668+
)
1669+
1670+
# Act
1671+
actor.subscribe_order_book_at_interval(AUDUSD_SIM.id, book_type=BookType.L2_MBP)
1672+
1673+
# Assert
1674+
assert self.data_engine.command_count == 1
1675+
1676+
def test_unsubscribe_order_book_at_interval(self) -> None:
1677+
# Arrange
1678+
actor = MockActor()
1679+
actor.register_base(
1680+
portfolio=self.portfolio,
1681+
msgbus=self.msgbus,
1682+
cache=self.cache,
1683+
clock=self.clock,
1684+
)
1685+
1686+
actor.subscribe_order_book_at_interval(AUDUSD_SIM.id, book_type=BookType.L2_MBP)
1687+
1688+
# Act
1689+
actor.unsubscribe_order_book_at_interval(AUDUSD_SIM.id)
16561690

16571691
# Assert
16581692
assert self.data_engine.command_count == 2

0 commit comments

Comments
 (0)