From e503aeb77a7f22829d4894edfb57ffe568de77e2 Mon Sep 17 00:00:00 2001 From: rundef Date: Sun, 27 Apr 2025 21:23:51 -0400 Subject: [PATCH 1/9] Start order book endpoint implementation (wip) --- async_rithmic/plants/base.py | 10 +++-- async_rithmic/plants/ticker.py | 44 +++++++++++++++++++ .../depth_by_order_end_event_pb2.py | 26 +++++++++++ .../protocol_buffers/depth_by_order_pb2.py | 30 +++++++++++++ .../protocol_buffers/forced_logout_pb2.py | 26 +++++++++++ .../protocol_buffers/order_book_pb2.py | 30 +++++++++++++ async_rithmic/protocol_buffers/reject_pb2.py | 26 +++++++++++ .../request_depth_by_order_snapshot_pb2.py | 26 +++++++++++ .../request_depth_by_order_updates_pb2.py | 28 ++++++++++++ .../response_depth_by_order_snapshot_pb2.py | 28 ++++++++++++ .../response_depth_by_order_updates_pb2.py | 26 +++++++++++ .../source/forced_logout.proto | 10 +++++ .../protocol_buffers/source/reject.proto | 12 +++++ 13 files changed, 318 insertions(+), 4 deletions(-) create mode 100644 async_rithmic/protocol_buffers/depth_by_order_end_event_pb2.py create mode 100644 async_rithmic/protocol_buffers/depth_by_order_pb2.py create mode 100644 async_rithmic/protocol_buffers/forced_logout_pb2.py create mode 100644 async_rithmic/protocol_buffers/order_book_pb2.py create mode 100644 async_rithmic/protocol_buffers/reject_pb2.py create mode 100644 async_rithmic/protocol_buffers/request_depth_by_order_snapshot_pb2.py create mode 100644 async_rithmic/protocol_buffers/request_depth_by_order_updates_pb2.py create mode 100644 async_rithmic/protocol_buffers/response_depth_by_order_snapshot_pb2.py create mode 100644 async_rithmic/protocol_buffers/response_depth_by_order_updates_pb2.py create mode 100644 async_rithmic/protocol_buffers/source/forced_logout.proto create mode 100644 async_rithmic/protocol_buffers/source/reject.proto diff --git a/async_rithmic/plants/base.py b/async_rithmic/plants/base.py index d684cd6..15b0810 100644 --- a/async_rithmic/plants/base.py +++ b/async_rithmic/plants/base.py @@ -25,6 +25,8 @@ 17: pb.response_rithmic_system_info_pb2.ResponseRithmicSystemInfo, 18: pb.request_heartbeat_pb2.RequestHeartbeat, 19: pb.response_heartbeat_pb2.ResponseHeartbeat, + 75: pb.reject_pb2.Reject, + 77: pb.forced_logout_pb2.ForcedLogout, # Market Data Infrastructure 100: pb.request_market_data_update_pb2.RequestMarketDataUpdate, @@ -34,10 +36,10 @@ 113: pb.request_front_month_contract_pb2.RequestFrontMonthContract, 114: pb.response_front_month_contract_pb2.ResponseFrontMonthContract, - #115: pb.request_depth_by_order_snapshot_pb2.RequestDepthByOrderSnapshot, - #116: pb.response_depth_by_order_snapshot_pb2.ResponseDepthByOrderSnapshot, - #117: pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates, - #118: pb.response_depth_by_order_updates_pb2.ResponseDepthByOrderUpdates, + 115: pb.request_depth_by_order_snapshot_pb2.RequestDepthByOrderSnapshot, + 116: pb.response_depth_by_order_snapshot_pb2.ResponseDepthByOrderSnapshot, + 117: pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates, + 118: pb.response_depth_by_order_updates_pb2.ResponseDepthByOrderUpdates, 150: pb.last_trade_pb2.LastTrade, 151: pb.best_bid_offer_pb2.BestBidOffer, diff --git a/async_rithmic/plants/ticker.py b/async_rithmic/plants/ticker.py index e488870..9d901b4 100644 --- a/async_rithmic/plants/ticker.py +++ b/async_rithmic/plants/ticker.py @@ -73,6 +73,49 @@ async def search_symbols(self, search_text, **kwargs): **kwargs ) + async def request_depth( + self, + symbol: str, + exchange: str, + depth_price: float + ): + return await self._send_and_recv_many( + template_id=115, + symbol=symbol, + exchange=exchange, + depth_price=depth_price + ) + + async def subscribe_depth( + self, + symbol: str, + exchange: str, + depth_price: float + ): + async with self.lock: + await self._send_request( + template_id=100, + symbol=symbol, + exchange=exchange, + depth_price=depth_price, + request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.SUBSCRIBE, + ) + + async def unsubscribe_depth( + self, + symbol: str, + exchange: str, + depth_price: float + ): + async with self.lock: + await self._send_request( + template_id=100, + symbol=symbol, + exchange=exchange, + depth_price=depth_price, + request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.UNSUBSCRIBE, + ) + async def _process_response(self, response): if response.template_id == 101: # Market data update response @@ -96,3 +139,4 @@ async def _process_response(self, response): else: logger.warning(f"Ticker plant: unhandled inbound message with template_id={response.template_id}") + print(response) diff --git a/async_rithmic/protocol_buffers/depth_by_order_end_event_pb2.py b/async_rithmic/protocol_buffers/depth_by_order_end_event_pb2.py new file mode 100644 index 0000000..4b755fc --- /dev/null +++ b/async_rithmic/protocol_buffers/depth_by_order_end_event_pb2.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: depth_by_order_end_event.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x64\x65pth_by_order_end_event.proto\x12\x03rti\"\x90\x01\n\x14\x44\x65pthByOrderEndEvent\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x10\n\x06symbol\x18\x94\xdc\x06 \x03(\t\x12\x12\n\x08\x65xchange\x18\x95\xdc\x06 \x03(\t\x12\x19\n\x0fsequence_number\x18\x82\xeb\x06 \x01(\x04\x12\x0f\n\x05ssboe\x18\xd4\x94\t \x01(\x05\x12\x0f\n\x05usecs\x18\xd5\x94\t \x01(\x05\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'depth_by_order_end_event_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_DEPTHBYORDERENDEVENT']._serialized_start=40 + _globals['_DEPTHBYORDERENDEVENT']._serialized_end=184 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/depth_by_order_pb2.py b/async_rithmic/protocol_buffers/depth_by_order_pb2.py new file mode 100644 index 0000000..886d59a --- /dev/null +++ b/async_rithmic/protocol_buffers/depth_by_order_pb2.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: depth_by_order.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x64\x65pth_by_order.proto\x12\x03rti\"\xa7\x05\n\x0c\x44\x65pthByOrder\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x10\n\x06symbol\x18\x94\xdc\x06 \x01(\t\x12\x12\n\x08\x65xchange\x18\x95\xdc\x06 \x01(\t\x12\x19\n\x0fsequence_number\x18\x82\xeb\x06 \x01(\x04\x12\x33\n\x0bupdate_type\x18\xa9\xdc\x06 \x03(\x0e\x32\x1c.rti.DepthByOrder.UpdateType\x12=\n\x10transaction_type\x18\x8c\xb0\t \x03(\x0e\x32!.rti.DepthByOrder.TransactionType\x12\x15\n\x0b\x64\x65pth_price\x18\xa5\xb6\t \x03(\x01\x12\x1a\n\x10prev_depth_price\x18\x9a\xba\t \x03(\x01\x12\x1f\n\x15prev_depth_price_flag\x18\xb2\xba\t \x03(\x08\x12\x14\n\ndepth_size\x18\xa6\xb6\t \x03(\x05\x12\x1e\n\x14\x64\x65pth_order_priority\x18\x8d\xb0\t \x03(\x04\x12\x1b\n\x11\x65xchange_order_id\x18\xf6\x8d\t \x03(\t\x12\x0f\n\x05ssboe\x18\xd4\x94\t \x01(\x05\x12\x0f\n\x05usecs\x18\xd5\x94\t \x01(\x05\x12\x16\n\x0csource_ssboe\x18\x80\x97\t \x01(\x05\x12\x16\n\x0csource_usecs\x18\x81\x97\t \x01(\x05\x12\x16\n\x0csource_nsecs\x18\x84\x97\t \x01(\x05\x12\x13\n\tjop_ssboe\x18\xc8\x98\t \x01(\x05\x12\x13\n\tjop_nsecs\x18\xcc\x98\t \x01(\x05\"E\n\x0fTransactionType\x12\x1f\n\x1bTRANSACTIONTYPE_UNSPECIFIED\x10\x00\x12\x07\n\x03\x42UY\x10\x01\x12\x08\n\x04SELL\x10\x02\"I\n\nUpdateType\x12\x1a\n\x16UPDATETYPE_UNSPECIFIED\x10\x00\x12\x07\n\x03NEW\x10\x01\x12\n\n\x06\x43HANGE\x10\x02\x12\n\n\x06\x44\x45LETE\x10\x03\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'depth_by_order_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_DEPTHBYORDER']._serialized_start=30 + _globals['_DEPTHBYORDER']._serialized_end=709 + _globals['_DEPTHBYORDER_TRANSACTIONTYPE']._serialized_start=565 + _globals['_DEPTHBYORDER_TRANSACTIONTYPE']._serialized_end=634 + _globals['_DEPTHBYORDER_UPDATETYPE']._serialized_start=636 + _globals['_DEPTHBYORDER_UPDATETYPE']._serialized_end=709 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/forced_logout_pb2.py b/async_rithmic/protocol_buffers/forced_logout_pb2.py new file mode 100644 index 0000000..9953451 --- /dev/null +++ b/async_rithmic/protocol_buffers/forced_logout_pb2.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: forced_logout.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13\x66orced_logout.proto\x12\x03rti\"%\n\x0c\x46orcedLogout\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'forced_logout_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_FORCEDLOGOUT']._serialized_start=28 + _globals['_FORCEDLOGOUT']._serialized_end=65 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/order_book_pb2.py b/async_rithmic/protocol_buffers/order_book_pb2.py new file mode 100644 index 0000000..30a9436 --- /dev/null +++ b/async_rithmic/protocol_buffers/order_book_pb2.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: order_book.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10order_book.proto\x12\x03rti\"\xb1\x04\n\tOrderBook\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x10\n\x06symbol\x18\x94\xdc\x06 \x01(\t\x12\x12\n\x08\x65xchange\x18\x95\xdc\x06 \x01(\t\x12\x17\n\rpresence_bits\x18\x92\x8d\t \x01(\r\x12\x30\n\x0bupdate_type\x18\xa8\xcf\t \x01(\x0e\x32\x19.rti.OrderBook.UpdateType\x12\x13\n\tbid_price\x18\xaa\xb5\t \x03(\x01\x12\x12\n\x08\x62id_size\x18\xab\xb5\t \x03(\x05\x12\x14\n\nbid_orders\x18\xa1\xb6\t \x03(\x05\x12\x17\n\rimpl_bid_size\x18\xac\xb6\t \x03(\x05\x12\x13\n\task_price\x18\xac\xb5\t \x03(\x01\x12\x12\n\x08\x61sk_size\x18\xad\xb5\t \x03(\x05\x12\x14\n\nask_orders\x18\xa2\xb6\t \x03(\x05\x12\x17\n\rimpl_ask_size\x18\xaf\xb6\t \x03(\x05\x12\x0f\n\x05ssboe\x18\xd4\x94\t \x01(\x05\x12\x0f\n\x05usecs\x18\xd5\x94\t \x01(\x05\">\n\x0cPresenceBits\x12\x1c\n\x18PRESENCEBITS_UNSPECIFIED\x10\x00\x12\x07\n\x03\x42ID\x10\x01\x12\x07\n\x03\x41SK\x10\x02\"\x89\x01\n\nUpdateType\x12\x1a\n\x16UPDATETYPE_UNSPECIFIED\x10\x00\x12\x14\n\x10\x43LEAR_ORDER_BOOK\x10\x01\x12\x0b\n\x07NO_BOOK\x10\x02\x12\x12\n\x0eSNAPSHOT_IMAGE\x10\x03\x12\t\n\x05\x42\x45GIN\x10\x04\x12\n\n\x06MIDDLE\x10\x05\x12\x07\n\x03\x45ND\x10\x06\x12\x08\n\x04SOLO\x10\x07\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'order_book_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_ORDERBOOK']._serialized_start=26 + _globals['_ORDERBOOK']._serialized_end=587 + _globals['_ORDERBOOK_PRESENCEBITS']._serialized_start=385 + _globals['_ORDERBOOK_PRESENCEBITS']._serialized_end=447 + _globals['_ORDERBOOK_UPDATETYPE']._serialized_start=450 + _globals['_ORDERBOOK_UPDATETYPE']._serialized_end=587 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/reject_pb2.py b/async_rithmic/protocol_buffers/reject_pb2.py new file mode 100644 index 0000000..6937502 --- /dev/null +++ b/async_rithmic/protocol_buffers/reject_pb2.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: reject.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0creject.proto\x12\x03rti\"F\n\x06Reject\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x12\n\x08user_msg\x18\x98\x8d\x08 \x03(\t\x12\x11\n\x07rp_code\x18\x9e\x8d\x08 \x03(\tb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'reject_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_REJECT']._serialized_start=21 + _globals['_REJECT']._serialized_end=91 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/request_depth_by_order_snapshot_pb2.py b/async_rithmic/protocol_buffers/request_depth_by_order_snapshot_pb2.py new file mode 100644 index 0000000..c68bb55 --- /dev/null +++ b/async_rithmic/protocol_buffers/request_depth_by_order_snapshot_pb2.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: request_depth_by_order_snapshot.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%request_depth_by_order_snapshot.proto\x12\x03rti\"\x85\x01\n\x1bRequestDepthByOrderSnapshot\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x12\n\x08user_msg\x18\x98\x8d\x08 \x03(\t\x12\x10\n\x06symbol\x18\x94\xdc\x06 \x01(\t\x12\x12\n\x08\x65xchange\x18\x95\xdc\x06 \x01(\t\x12\x15\n\x0b\x64\x65pth_price\x18\xa5\xb6\t \x01(\x01\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'request_depth_by_order_snapshot_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_REQUESTDEPTHBYORDERSNAPSHOT']._serialized_start=47 + _globals['_REQUESTDEPTHBYORDERSNAPSHOT']._serialized_end=180 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/request_depth_by_order_updates_pb2.py b/async_rithmic/protocol_buffers/request_depth_by_order_updates_pb2.py new file mode 100644 index 0000000..10f8ebe --- /dev/null +++ b/async_rithmic/protocol_buffers/request_depth_by_order_updates_pb2.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: request_depth_by_order_updates.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$request_depth_by_order_updates.proto\x12\x03rti\"\x84\x02\n\x1aRequestDepthByOrderUpdates\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x12\n\x08user_msg\x18\x98\x8d\x08 \x03(\t\x12:\n\x07request\x18\xa0\x8d\x06 \x01(\x0e\x32\'.rti.RequestDepthByOrderUpdates.Request\x12\x10\n\x06symbol\x18\x94\xdc\x06 \x01(\t\x12\x12\n\x08\x65xchange\x18\x95\xdc\x06 \x01(\t\x12\x15\n\x0b\x64\x65pth_price\x18\xa5\xb6\t \x01(\x01\"B\n\x07Request\x12\x17\n\x13REQUEST_UNSPECIFIED\x10\x00\x12\r\n\tSUBSCRIBE\x10\x01\x12\x0f\n\x0bUNSUBSCRIBE\x10\x02\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'request_depth_by_order_updates_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_REQUESTDEPTHBYORDERUPDATES']._serialized_start=46 + _globals['_REQUESTDEPTHBYORDERUPDATES']._serialized_end=306 + _globals['_REQUESTDEPTHBYORDERUPDATES_REQUEST']._serialized_start=240 + _globals['_REQUESTDEPTHBYORDERUPDATES_REQUEST']._serialized_end=306 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/response_depth_by_order_snapshot_pb2.py b/async_rithmic/protocol_buffers/response_depth_by_order_snapshot_pb2.py new file mode 100644 index 0000000..8f0d598 --- /dev/null +++ b/async_rithmic/protocol_buffers/response_depth_by_order_snapshot_pb2.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: response_depth_by_order_snapshot.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n&response_depth_by_order_snapshot.proto\x12\x03rti\"\xb5\x03\n\x1cResponseDepthByOrderSnapshot\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x12\n\x08user_msg\x18\x98\x8d\x08 \x03(\t\x12\x1c\n\x12rq_handler_rp_code\x18\x9c\x8d\x08 \x03(\t\x12\x11\n\x07rp_code\x18\x9e\x8d\x08 \x03(\t\x12\x12\n\x08\x65xchange\x18\x95\xdc\x06 \x01(\t\x12\x10\n\x06symbol\x18\x94\xdc\x06 \x01(\t\x12\x19\n\x0fsequence_number\x18\x82\xeb\x06 \x01(\x04\x12G\n\ndepth_side\x18\x8c\xb0\t \x01(\x0e\x32\x31.rti.ResponseDepthByOrderSnapshot.TransactionType\x12\x15\n\x0b\x64\x65pth_price\x18\xa5\xb6\t \x01(\x01\x12\x14\n\ndepth_size\x18\xa6\xb6\t \x03(\x05\x12\x1e\n\x14\x64\x65pth_order_priority\x18\x8d\xb0\t \x03(\x04\x12\x1b\n\x11\x65xchange_order_id\x18\xf6\x8d\t \x03(\t\"E\n\x0fTransactionType\x12\x1f\n\x1bTRANSACTIONTYPE_UNSPECIFIED\x10\x00\x12\x07\n\x03\x42UY\x10\x01\x12\x08\n\x04SELL\x10\x02\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'response_depth_by_order_snapshot_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_RESPONSEDEPTHBYORDERSNAPSHOT']._serialized_start=48 + _globals['_RESPONSEDEPTHBYORDERSNAPSHOT']._serialized_end=485 + _globals['_RESPONSEDEPTHBYORDERSNAPSHOT_TRANSACTIONTYPE']._serialized_start=416 + _globals['_RESPONSEDEPTHBYORDERSNAPSHOT_TRANSACTIONTYPE']._serialized_end=485 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/response_depth_by_order_updates_pb2.py b/async_rithmic/protocol_buffers/response_depth_by_order_updates_pb2.py new file mode 100644 index 0000000..c8092f9 --- /dev/null +++ b/async_rithmic/protocol_buffers/response_depth_by_order_updates_pb2.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: response_depth_by_order_updates.proto +# Protobuf Python Version: 4.25.4 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%response_depth_by_order_updates.proto\x12\x03rti\"[\n\x1bResponseDepthByOrderUpdates\x12\x15\n\x0btemplate_id\x18\xe3\xb6\t \x01(\x05\x12\x12\n\x08user_msg\x18\x98\x8d\x08 \x03(\t\x12\x11\n\x07rp_code\x18\x9e\x8d\x08 \x03(\tb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'response_depth_by_order_updates_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_RESPONSEDEPTHBYORDERUPDATES']._serialized_start=46 + _globals['_RESPONSEDEPTHBYORDERUPDATES']._serialized_end=137 +# @@protoc_insertion_point(module_scope) diff --git a/async_rithmic/protocol_buffers/source/forced_logout.proto b/async_rithmic/protocol_buffers/source/forced_logout.proto new file mode 100644 index 0000000..2383074 --- /dev/null +++ b/async_rithmic/protocol_buffers/source/forced_logout.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package rti; + +message ForcedLogout + { + // PB_OFFSET = 100000 , is the offset added for each MNM field id + + int32 template_id = 154467; // PB_OFFSET + MNM_TEMPLATE_ID + } diff --git a/async_rithmic/protocol_buffers/source/reject.proto b/async_rithmic/protocol_buffers/source/reject.proto new file mode 100644 index 0000000..710dbe7 --- /dev/null +++ b/async_rithmic/protocol_buffers/source/reject.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package rti; + +message Reject + { + // PB_OFFSET = 100000 , is the offset added for each MNM field id + + int32 template_id = 154467; // PB_OFFSET + MNM_TEMPLATE_ID + repeated string user_msg = 132760; // PB_OFFSET + MNM_USER_MSG + repeated string rp_code = 132766; // PB_OFFSET + MNM_RESPONSE_CODE + } From d0533fa49845cf0b357ddf45f4c523df12adcfe4 Mon Sep 17 00:00:00 2001 From: rundef Date: Fri, 6 Jun 2025 14:06:22 -0400 Subject: [PATCH 2/9] Handle market depth subscriptions (wip) --- async_rithmic/client.py | 1 + async_rithmic/plants/base.py | 9 ++++---- async_rithmic/plants/history.py | 3 +++ async_rithmic/plants/ticker.py | 41 +++++++++++++++++++++++++++++---- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/async_rithmic/client.py b/async_rithmic/client.py index 6c7ab0e..89f7e06 100644 --- a/async_rithmic/client.py +++ b/async_rithmic/client.py @@ -30,6 +30,7 @@ class RithmicClient(DelegateMixin): # Real-time market updates events on_tick = Event() on_time_bar = Event() + on_market_depth = Event() # Order updates events on_rithmic_order_notification = Event() diff --git a/async_rithmic/plants/base.py b/async_rithmic/plants/base.py index 0a85828..d47191f 100644 --- a/async_rithmic/plants/base.py +++ b/async_rithmic/plants/base.py @@ -31,8 +31,6 @@ 17: pb.response_rithmic_system_info_pb2.ResponseRithmicSystemInfo, 18: pb.request_heartbeat_pb2.RequestHeartbeat, 19: pb.response_heartbeat_pb2.ResponseHeartbeat, - 75: pb.reject_pb2.Reject, - 77: pb.forced_logout_pb2.ForcedLogout, # Template 75 is a generic message sent in case of failures. (e.g. trying to place an order before logging in) 75: pb.reject_pb2.Reject, @@ -55,8 +53,8 @@ 150: pb.last_trade_pb2.LastTrade, 151: pb.best_bid_offer_pb2.BestBidOffer, #156: pb.order_book_pb2.OrderBook, - #160: pb.depth_by_order.DepthByOrder, - #161: pb.depth_by_order_end_event.DepthByOrderEndEvent, + 160: pb.depth_by_order.DepthByOrder, + 161: pb.depth_by_order_end_event.DepthByOrderEndEvent, # Order Plant Infrastructure 300: pb.request_login_info_pb2.RequestLoginInfo, @@ -496,10 +494,11 @@ async def _process_response(self, response): Handles async responses """ - if response.template_id in [13, 19, 401]: + if response.template_id in [13, 19, 161, 401]: # Ignore # - logout responses # - heartbeat responses + # - market depth end event # - pnl subscription responses return True diff --git a/async_rithmic/plants/history.py b/async_rithmic/plants/history.py index d002df5..804d8e5 100644 --- a/async_rithmic/plants/history.py +++ b/async_rithmic/plants/history.py @@ -159,6 +159,9 @@ async def unsubscribe_from_time_bar_data( bar_type: TimeBarType, bar_type_periods: int ): + sub = (symbol, exchange, bar_type, bar_type_periods) + self._subscriptions["time_bar"].discard(sub) + return await self._send_and_recv_immediate( template_id=200, symbol=symbol, diff --git a/async_rithmic/plants/ticker.py b/async_rithmic/plants/ticker.py index 3e08ae9..9ccda5b 100644 --- a/async_rithmic/plants/ticker.py +++ b/async_rithmic/plants/ticker.py @@ -13,6 +13,9 @@ async def _login(self): for symbol, exchange, update_bits in self._subscriptions["market_data"]: await self.subscribe_to_market_data(symbol, exchange, update_bits) + for symbol, exchange, depth_price in self._subscriptions["market_depth"]: + await self.subscribe_to_market_depth(symbol, exchange, depth_price) + async def list_exchanges(self): return await self._send_and_collect( template_id=342, @@ -67,6 +70,9 @@ async def unsubscribe_from_market_data( ): update_bits = data_type.value if isinstance(data_type, DataType) else int(data_type) + sub = (symbol, exchange, update_bits) + self._subscriptions["market_data"].discard(sub) + await self._send_request( template_id=100, symbol=symbol, @@ -95,40 +101,57 @@ async def search_symbols(self, search_text, **kwargs): **kwargs ) - async def request_depth( + async def request_market_depth( self, symbol: str, exchange: str, depth_price: float ): - return await self._send_and_recv_many( + responses = await self._send_and_collect( template_id=115, + expected_response=dict(template_id=116), symbol=symbol, exchange=exchange, depth_price=depth_price ) + # TODO: verify that there's indeed only one response + return responses[0] - async def subscribe_depth( + async def subscribe_to_market_depth( self, symbol: str, exchange: str, depth_price: float ): + """ + Subscribes to market depth updates (L2 data) + """ + + sub = (symbol, exchange, depth_price) + self._subscriptions["market_depth"].add(sub) + async with self.lock: await self._send_request( - template_id=100, + template_id=117, symbol=symbol, exchange=exchange, depth_price=depth_price, request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.SUBSCRIBE, ) - async def unsubscribe_depth( + async def unsubscribe_from_market_depth( self, symbol: str, exchange: str, depth_price: float ): + """ + Unsubscribes from market depth updates (L2 data) + """ + + sub = (symbol, exchange, depth_price) + self._subscriptions["market_depth"].add(sub) + async with self.lock: await self._send_request( template_id=100, @@ -146,6 +169,10 @@ async def _process_response(self, response): # Market data update response pass + elif response.template_id == 118: + # Market depth data update response + pass + elif response.template_id == 150: # Market data stream: Last Trade data = self._response_to_dict(response) @@ -162,5 +189,9 @@ async def _process_response(self, response): await self.client.on_tick.call_async(data) + elif response.template_id == 160: + # Market depth data stream + await self.client.on_market_depth(response) + else: self.logger.warning(f"Unhandled inbound message with template_id={response.template_id}") From 212b3fd81ebab82933128228b67350c848823c27 Mon Sep 17 00:00:00 2001 From: rundef Date: Fri, 6 Jun 2025 14:08:11 -0400 Subject: [PATCH 3/9] Whoops --- async_rithmic/plants/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/async_rithmic/plants/base.py b/async_rithmic/plants/base.py index d47191f..d52b871 100644 --- a/async_rithmic/plants/base.py +++ b/async_rithmic/plants/base.py @@ -53,8 +53,8 @@ 150: pb.last_trade_pb2.LastTrade, 151: pb.best_bid_offer_pb2.BestBidOffer, #156: pb.order_book_pb2.OrderBook, - 160: pb.depth_by_order.DepthByOrder, - 161: pb.depth_by_order_end_event.DepthByOrderEndEvent, + 160: pb.depth_by_order_pb2.DepthByOrder, + 161: pb.depth_by_order_end_event_pb2.DepthByOrderEndEvent, # Order Plant Infrastructure 300: pb.request_login_info_pb2.RequestLoginInfo, From 97bd60958276fbbbb92e4092ecd18d5d371654c9 Mon Sep 17 00:00:00 2001 From: rundef Date: Sun, 29 Jun 2025 19:05:45 -0400 Subject: [PATCH 4/9] Implement market depth endpoints + update docs --- async_rithmic/client.py | 1 + async_rithmic/enums.py | 6 ++++- async_rithmic/plants/base.py | 2 +- async_rithmic/plants/ticker.py | 49 +++++++++++++++++++--------------- docs/orders.rst | 4 +-- docs/realtime_data.rst | 49 ++++++++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 26 deletions(-) diff --git a/async_rithmic/client.py b/async_rithmic/client.py index 9527fb1..a1af79e 100644 --- a/async_rithmic/client.py +++ b/async_rithmic/client.py @@ -39,6 +39,7 @@ def __init__( # Real-time market updates events self.on_tick = Event() self.on_time_bar = Event() + self.on_order_book = Event() self.on_market_depth = Event() # Order updates events diff --git a/async_rithmic/enums.py b/async_rithmic/enums.py index e75ffd7..dc9ce6e 100644 --- a/async_rithmic/enums.py +++ b/async_rithmic/enums.py @@ -2,9 +2,12 @@ from . import protocol_buffers as pb -class DataType(int, enum.Enum): + +class DataType(enum.IntEnum): LAST_TRADE = 1 BBO = 2 + ORDER_BOOK = 4 + OrderType = pb.request_new_order_pb2.RequestNewOrder.PriceType OrderDuration = pb.request_new_order_pb2.RequestNewOrder.Duration @@ -12,6 +15,7 @@ class DataType(int, enum.Enum): LastTradePresenceBits = pb.last_trade_pb2.LastTrade.PresenceBits BestBidOfferPresenceBits = pb.best_bid_offer_pb2.BestBidOffer.PresenceBits +OrderBookPresenceBits = pb.order_book_pb2.OrderBook.PresenceBits ExchangeOrderNotificationType = pb.exchange_order_notification_pb2.ExchangeOrderNotification.NotifyType diff --git a/async_rithmic/plants/base.py b/async_rithmic/plants/base.py index fd91ffa..19b7e55 100644 --- a/async_rithmic/plants/base.py +++ b/async_rithmic/plants/base.py @@ -52,7 +52,7 @@ 150: pb.last_trade_pb2.LastTrade, 151: pb.best_bid_offer_pb2.BestBidOffer, - #156: pb.order_book_pb2.OrderBook, + 156: pb.order_book_pb2.OrderBook, 160: pb.depth_by_order_pb2.DepthByOrder, 161: pb.depth_by_order_end_event_pb2.DepthByOrderEndEvent, diff --git a/async_rithmic/plants/ticker.py b/async_rithmic/plants/ticker.py index 9ccda5b..8ac01ec 100644 --- a/async_rithmic/plants/ticker.py +++ b/async_rithmic/plants/ticker.py @@ -107,15 +107,18 @@ async def request_market_depth( exchange: str, depth_price: float ): + """ + Request order book data for a given price + """ responses = await self._send_and_collect( template_id=115, expected_response=dict(template_id=116), symbol=symbol, exchange=exchange, - depth_price=depth_price + depth_price=depth_price, + account_id=None, ) - # TODO: verify that there's indeed only one response - return responses[0] + return responses[0] if responses else None async def subscribe_to_market_depth( self, @@ -124,20 +127,19 @@ async def subscribe_to_market_depth( depth_price: float ): """ - Subscribes to market depth updates (L2 data) + Subscribes to market depth updates (L2 data) for a given price """ sub = (symbol, exchange, depth_price) self._subscriptions["market_depth"].add(sub) - async with self.lock: - await self._send_request( - template_id=117, - symbol=symbol, - exchange=exchange, - depth_price=depth_price, - request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.SUBSCRIBE, - ) + await self._send_request( + template_id=117, + symbol=symbol, + exchange=exchange, + depth_price=depth_price, + request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.SUBSCRIBE, + ) async def unsubscribe_from_market_depth( self, @@ -146,20 +148,19 @@ async def unsubscribe_from_market_depth( depth_price: float ): """ - Unsubscribes from market depth updates (L2 data) + Unsubscribes from market depth updates (L2 data) for a given price """ sub = (symbol, exchange, depth_price) self._subscriptions["market_depth"].add(sub) - async with self.lock: - await self._send_request( - template_id=100, - symbol=symbol, - exchange=exchange, - depth_price=depth_price, - request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.UNSUBSCRIBE, - ) + await self._send_request( + template_id=117, + symbol=symbol, + exchange=exchange, + depth_price=depth_price, + request=pb.request_depth_by_order_updates_pb2.RequestDepthByOrderUpdates.Request.UNSUBSCRIBE, + ) async def _process_response(self, response): if await super()._process_response(response): @@ -189,9 +190,13 @@ async def _process_response(self, response): await self.client.on_tick.call_async(data) + elif response.template_id == 156: + # Market data stream: Order Book + await self.client.on_order_book.call_async(response) + elif response.template_id == 160: # Market depth data stream - await self.client.on_market_depth(response) + await self.client.on_market_depth.call_async(response) else: self.logger.warning(f"Unhandled inbound message with template_id={response.template_id}") diff --git a/docs/orders.rst b/docs/orders.rst index 9e280a7..fefb362 100644 --- a/docs/orders.rst +++ b/docs/orders.rst @@ -194,8 +194,8 @@ This method allows you to update one or more attributes of an active order, such stop_ticks=25 ) -Exit a position ---------------- +Exiting a position +------------------ Closes an open trading position for the specified symbol and exchange. If no symbol is provided, exits all active positions. diff --git a/docs/realtime_data.rst b/docs/realtime_data.rst index 44d15fe..0265dd7 100644 --- a/docs/realtime_data.rst +++ b/docs/realtime_data.rst @@ -170,3 +170,52 @@ The possible time bar types are: `SECOND_BAR`, `MINUTE_BAR`, `DAILY_BAR` and `WE asyncio.run(main()) See the `time_bar.proto `_ definition for field details. + +Order Book +---------- + +Here's an example that streams full order book updates: + +.. code-block:: python + + async def callback(data): + print("Received order book update") + print(data) + + async def main(): + # ... connection + get_front_month_contract ... + + # Stream market data + print(f"Streaming order book updates for {security_code}") + client.on_order_book += callback + + await client.subscribe_to_market_data(security_code, exchange, DataType.ORDER_BOOK) + +Market Depth +------------ + +Here's an example that retrieves the order book state for a specific price: + +.. code-block:: python + + async def callback(data): + print("Received market depth update") + print(data) + + async def main(): + # ... connection + get_front_month_contract ... + + price = 6150 + + # Request market depth for this price level + depth = await client.request_market_depth(security_code, exchange, price) + print("Depth:", depth) + + # Subscribe to market depth updates for this price level + print(f"Subscribing to market depth updates for {security_code} @ {price}") + + client.on_market_depth += callback + await client.subscribe_to_market_depth(security_code, exchange, price) + + await asyncio.sleep(20) + await client.unsubscribe_from_market_depth(security_code, exchange, price) From 9e8d2358d47fc353f91ca1f62bb738dd6704a5ae Mon Sep 17 00:00:00 2001 From: rundef Date: Sun, 29 Jun 2025 19:12:33 -0400 Subject: [PATCH 5/9] whoops --- async_rithmic/plants/ticker.py | 2 +- docs/realtime_data.rst | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/async_rithmic/plants/ticker.py b/async_rithmic/plants/ticker.py index 8ac01ec..52b3b1a 100644 --- a/async_rithmic/plants/ticker.py +++ b/async_rithmic/plants/ticker.py @@ -152,7 +152,7 @@ async def unsubscribe_from_market_depth( """ sub = (symbol, exchange, depth_price) - self._subscriptions["market_depth"].add(sub) + self._subscriptions["market_depth"].discard(sub) await self._send_request( template_id=117, diff --git a/docs/realtime_data.rst b/docs/realtime_data.rst index 0265dd7..50f123f 100644 --- a/docs/realtime_data.rst +++ b/docs/realtime_data.rst @@ -191,6 +191,9 @@ Here's an example that streams full order book updates: await client.subscribe_to_market_data(security_code, exchange, DataType.ORDER_BOOK) + await asyncio.sleep(10) + await client.unsubscribe_from_market_data(security_code, exchange, DataType.ORDER_BOOK) + Market Depth ------------ From a6b33baf7f002f952d251963ecc6ddc5f2fe738f Mon Sep 17 00:00:00 2001 From: rundef Date: Sun, 29 Jun 2025 19:18:04 -0400 Subject: [PATCH 6/9] Update README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a3de1a5..bc36ea1 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,14 @@ Designed with reliability and extensibility in mind, `async_rithmic` is a strong ## ✨ Key Features - ✅ **Python 3.10+ Compatibility**: Fully tested and supported. +- ⚡ **Async-first design**: Better scalability & responsiveness. - 🛠️ **Robust architecture**: Built-in reconnection & fault-tolerance. - [**Automatic reconnection**](https://async-rithmic.readthedocs.io/en/latest/connection.html#custom-reconnection-settings): Resilient to network interruptions with customizable backoff and retry logic. - [**Automatic retries**](https://async-rithmic.readthedocs.io/en/latest/connection.html#custom-retry-settings): Configure how many times a slow request will be retried and for how long, making your client more resilient to network delays and backend slowness. - 👥 **Multi-account support** - 📊 **Historical + Live Time Bars**: Ideal for time-based strategies. - 🎯 **Live Tick Data & Best Bid/Ask Streaming**: Fine-grained market data for real-time decision-making. -- ⚡ **Async-first design**: Better scalability & responsiveness. +- 🪟 **Full Order Book (L2) Streaming**: Stream real-time depth of market (all bids/asks, multiple price levels) for advanced order flow analysis. ## 📦 Installation From 2b2fff0e75105239d3978c8b89a1ffeed1f0eda2 Mon Sep 17 00:00:00 2001 From: rundef Date: Fri, 4 Jul 2025 14:54:21 -0400 Subject: [PATCH 7/9] Add doc about how to handle the different values of update_type --- docs/realtime_data.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/realtime_data.rst b/docs/realtime_data.rst index 50f123f..8295e12 100644 --- a/docs/realtime_data.rst +++ b/docs/realtime_data.rst @@ -194,6 +194,15 @@ Here's an example that streams full order book updates: await asyncio.sleep(10) await client.unsubscribe_from_market_data(security_code, exchange, DataType.ORDER_BOOK) +.. note:: + Here's how to handle the different values for the `update_type` field: + + - **CLEAR_ORDER_BOOK**: you should clear the order book. + - **BEGIN, END, MIDDLE**: the update is part of a set of updates, the set will begin with an update type of BEGIN and end with an update type of END. There may be additional MIDDLE updates in between. + - **SOLO**: the update is a solitary update and the order book can be evaluated immediately. + - **SNAPSHOT_IMAGE**: indicates that the market depth updates are being aggregated over a time period. + - **NO_BOOK**: indicates that the symbol has no order book levels (e.g. lack of L2 data) or the symbol is invalid. + Market Depth ------------ From d5d9313d762a4b0408dcd4291c735a72b6a2bfa2 Mon Sep 17 00:00:00 2001 From: rundef Date: Mon, 28 Jul 2025 12:58:11 -0400 Subject: [PATCH 8/9] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b1e11..64b33c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [1.5.4] - 2025-07-28 +### Added +- Order book/market depth methods + ## [1.5.3] - 2025-07-09 ### Added - Logger name suffix kwarg From 5aa00075b8ee7f056a62eb3f927a5b0d817649fe Mon Sep 17 00:00:00 2001 From: rundef Date: Mon, 28 Jul 2025 12:58:38 -0400 Subject: [PATCH 9/9] =?UTF-8?q?Bump=20version:=201.5.3=20=E2=86=92=201.5.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- async_rithmic/__init__.py | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 295d9fd..18cf060 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.5.3 +current_version = 1.5.4 commit = True tag = True diff --git a/async_rithmic/__init__.py b/async_rithmic/__init__.py index 33c7f89..1c6c250 100644 --- a/async_rithmic/__init__.py +++ b/async_rithmic/__init__.py @@ -4,4 +4,4 @@ from .exceptions import * from .objects import RetrySettings, ReconnectionSettings -__version__ = '1.5.3' +__version__ = '1.5.4' diff --git a/pyproject.toml b/pyproject.toml index efacb8f..91a8e28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "async_rithmic" -version = "1.5.3" +version = "1.5.4" description = "Python API Integration with Rithmic Protocol Buffer API" readme = "README.md" requires-python = ">=3.10"