itchfeed 1.0.4__tar.gz → 1.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: itchfeed
3
- Version: 1.0.4
3
+ Version: 1.0.6
4
4
  Summary: Simple parser for ITCH messages
5
- Home-page: https://github.com/bbalouki/itch
6
- Download-URL: https://pypi.org/project/itchfeed/
7
- Author: Bertin Balouki SIMYELI
8
- Author-email: <bertin@bbstrader.com>
9
- Maintainer: Bertin Balouki SIMYELI
10
- License: The MIT License (MIT)
5
+ Author-email: Bertin Balouki SIMYELI <bertin@bbs-trading.com>
6
+ Maintainer-email: Bertin Balouki SIMYELI <bertin@bbs-trading.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/bbalouki/itch
9
+ Project-URL: Download, https://pypi.org/project/itchfeed/
11
10
  Project-URL: Source Code, https://github.com/bbalouki/itch
12
11
  Keywords: Finance,Financial,Quantitative,Equities,Totalview-ITCH,Totalview,Nasdaq-ITCH,Nasdaq,ITCH,Data,Feed,ETFs,Funds,Trading,Investing
13
12
  Classifier: Development Status :: 5 - Production/Stable
@@ -19,20 +18,7 @@ Classifier: Operating System :: OS Independent
19
18
  Description-Content-Type: text/markdown
20
19
  License-File: LICENSE
21
20
  Requires-Dist: pytest
22
- Dynamic: author
23
- Dynamic: author-email
24
- Dynamic: classifier
25
- Dynamic: description
26
- Dynamic: description-content-type
27
- Dynamic: download-url
28
- Dynamic: home-page
29
- Dynamic: keywords
30
- Dynamic: license
31
21
  Dynamic: license-file
32
- Dynamic: maintainer
33
- Dynamic: project-url
34
- Dynamic: requires-dist
35
- Dynamic: summary
36
22
 
37
23
  # Nasdaq TotalView-ITCH 5.0 Parser
38
24
  [![PYPI Version](https://img.shields.io/pypi/v/itchfeed)](https://pypi.org/project/itchfeed/)
@@ -59,7 +45,7 @@ Dynamic: summary
59
45
  * [Data Representation](#data-representation)
60
46
  * [Common Attributes of `MarketMessage`](#common-attributes-of-marketmessage)
61
47
  * [Common Methods of `MarketMessage`](#common-methods-of-marketmessage)
62
- * [Serializing Messages with `pack()`](#serializing-messages-with-pack)
48
+ * [Serializing Messages with `to_bytes()`](#serializing-messages-with-to_bytes)
63
49
  * [Data Types in Parsed Messages](#data-types-in-parsed-messages)
64
50
  * [Error Handling](#error-handling)
65
51
  * [Handling Strategies](#handling-strategies)
@@ -111,6 +97,8 @@ After installation (typically via pip), import the necessary modules directly in
111
97
 
112
98
  ## Usage
113
99
 
100
+ Download some sample data [here](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
101
+
114
102
  ### Parsing from a Binary File
115
103
 
116
104
  This is useful for processing historical ITCH data stored in files. The `MessageParser` handles buffering efficiently.
@@ -131,9 +119,8 @@ parser = MessageParser() # Parses all messages by default
131
119
 
132
120
  # Path to your ITCH 5.0 data file
133
121
  itch_file_path = 'path/to/your/data'
134
- # you can find sample data [here](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
135
122
 
136
- # The `read_message_from_file()` method reads the ITCH data in chunks.
123
+ # The `parse_file()` method reads the ITCH data in chunks.
137
124
  # - `cachesize` (optional, default: 65536 bytes): This parameter determines the size of data chunks
138
125
  # read from the file at a time. Adjusting this might impact performance for very large files
139
126
  # or memory usage, but the default is generally suitable.
@@ -144,13 +131,9 @@ itch_file_path = 'path/to/your/data'
144
131
 
145
132
  try:
146
133
  with open(itch_file_path, 'rb') as itch_file:
147
- # read_message_from_file returns a list of parsed message objects
148
- parsed_messages = parser.read_message_from_file(itch_file) # You can also pass cachesize here, e.g., parser.read_message_from_file(itch_file, cachesize=131072)
149
-
150
- print(f"Parsed {len(parsed_messages)} messages.")
151
-
134
+ # parse_file returns an Iterator of parsed message objects
152
135
  # Process the messages
153
- for message in parsed_messages:
136
+ for message in parser.parse_file(itch_file):
154
137
  # Access attributes directly
155
138
  print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
156
139
 
@@ -170,8 +153,8 @@ try:
170
153
 
171
154
  except FileNotFoundError:
172
155
  print(f"Error: File not found at {itch_file_path}")
173
- except Exception as e:
174
- print(f"An error occurred: {e}")
156
+ except ValueError as e:
157
+ print(f"An error occurred during parsing: {e}")
175
158
 
176
159
  ```
177
160
 
@@ -192,14 +175,8 @@ parser = MessageParser()
192
175
  # Example: \x00\x0bS...\x00\x25R...\x00\x27F...
193
176
  raw_binary_data: bytes = b"..." # Your raw ITCH 5.0 data chunk
194
177
 
195
- # read_message_from_bytes returns a queue of parsed message objects
196
- message_queue: Queue = parser.read_message_from_bytes(raw_binary_data)
197
-
198
- print(f"Parsed {message_queue.qsize()} messages from the byte chunk.")
199
-
200
- # Process messages from the queue
201
- while not message_queue.empty():
202
- message = message_queue.get()
178
+ # parse_stream returns an Iterator of parsed message objects
179
+ for message in parser.parse_stream(raw_binary_data)
203
180
 
204
181
  print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
205
182
 
@@ -276,10 +253,10 @@ for message_type, sample_data in TEST_DATA.items():
276
253
  print(f"Creating message of type {message_type}")
277
254
  message = create_message(message_type, **sample_data)
278
255
  print(f"Created message: {message}")
279
- print(f"Packed message: {message.pack()}")
256
+ print(f"Packed message: {message.to_bytes()}")
280
257
  print(f"Message size: {message.message_size}")
281
258
  print(f"Message Attributes: {message.get_attributes()}")
282
- assert len(message.pack()) == message.message_size
259
+ assert len(message.to_bytes()) == message.message_size
283
260
  print()
284
261
  ```
285
262
 
@@ -388,14 +365,14 @@ The `MarketMessage` base class, and therefore all specific message classes, prov
388
365
  * Returns a dictionary of all attributes (fields) of the message instance, along with their current values.
389
366
  * This can be useful for generic inspection or logging of message contents without needing to know the specific type of the message beforehand.
390
367
 
391
- ### Serializing Messages with `pack()`
368
+ ### Serializing Messages with `to_bytes()`
392
369
 
393
- Each specific message class (e.g., `SystemEventMessage`, `AddOrderNoMPIAttributionMessage`) also provides a `pack()` method. This method is the inverse of the parsing process.
370
+ Each specific message class (e.g., `SystemEventMessage`, `AddOrderNoMPIAttributionMessage`) also provides a `to_bytes()` method. This method is the inverse of the parsing process.
394
371
 
395
372
  * **Purpose:** It serializes the message object, with its current attribute values, back into its raw ITCH 5.0 binary format. The output is a `bytes` object representing the exact byte sequence that would appear in an ITCH data feed for that message.
396
373
  * **Usefulness:**
397
374
  * **Generating Test Data:** Create custom ITCH messages for testing your own ITCH processing applications.
398
- * **Modifying Messages:** Parse an existing message, modify some of its attributes, and then `pack()` it back into binary form.
375
+ * **Modifying Messages:** Parse an existing message, modify some of its attributes, and then `to_bytes()` it back into binary form.
399
376
  * **Creating Custom ITCH Feeds:** While more involved, you could use this to construct sequences of ITCH messages for specialized scenarios.
400
377
 
401
378
  **Example:**
@@ -415,21 +392,21 @@ import time
415
392
  # for packing requires setting attributes manually if not using raw bytes for construction)
416
393
 
417
394
  event_msg = SystemEventMessage.__new__(SystemEventMessage) # Create instance without calling __init__
418
- event_msg.message_type = b'S' # Must be set for pack() to know its type
395
+ event_msg.message_type = b'S' # Must be set for to_bytes() to know its type
419
396
  event_msg.stock_locate = 0 # Placeholder or actual value
420
397
  event_msg.tracking_number = 0 # Placeholder or actual value
421
398
  event_msg.event_code = b'O' # Example: Start of Messages
422
399
 
423
400
  # 2. Set the timestamp.
424
401
  # The `timestamp` attribute (nanoseconds since midnight) must be set.
425
- # The `pack()` method will internally use `split_timestamp()` to get the parts.
402
+ # The `to_bytes()` method will internally use `split_timestamp()` to get the parts.
426
403
  current_nanoseconds = int(time.time() * 1e9) % (24 * 60 * 60 * int(1e9))
427
404
  event_msg.timestamp = current_nanoseconds # Directly set the nanosecond timestamp
428
405
 
429
406
  # 3. Pack the message into binary format.
430
- # The pack() method prepends the message type and then packs stock_locate,
407
+ # The to_bytes() method prepends the message type and then packs stock_locate,
431
408
  # tracking_number, the split timestamp, and then the message-specific fields.
432
- packed_bytes = event_msg.pack()
409
+ packed_bytes = event_msg.to_bytes()
433
410
 
434
411
  # 4. The result is a bytes object
435
412
  print(f"Packed {len(packed_bytes)} bytes: {packed_bytes.hex().upper()}")
@@ -462,11 +439,12 @@ Common scenarios that can lead to a `ValueError` include:
462
439
 
463
440
  It's crucial to anticipate these errors in your application:
464
441
 
465
- * **Use `try-except` Blocks:** Wrap your parsing calls (especially `read_message_from_file` or `read_message_from_bytes`) in `try-except ValueError as e:` blocks.
442
+ * **Use `try-except` Blocks:** Wrap your parsing calls (especially `parse_file` or `parse_stream`) in `try-except ValueError as e:` blocks.
466
443
  ```python
467
444
  try:
468
445
  # ... parsing operations ...
469
- messages = parser.read_message_from_file(itch_file)
446
+ for message in parser.parse_file(itch_file):
447
+ ...
470
448
  except ValueError as e:
471
449
  print(f"An error occurred during parsing: {e}")
472
450
  # Log the error, problematic data chunk, or take other actions
@@ -23,7 +23,7 @@
23
23
  * [Data Representation](#data-representation)
24
24
  * [Common Attributes of `MarketMessage`](#common-attributes-of-marketmessage)
25
25
  * [Common Methods of `MarketMessage`](#common-methods-of-marketmessage)
26
- * [Serializing Messages with `pack()`](#serializing-messages-with-pack)
26
+ * [Serializing Messages with `to_bytes()`](#serializing-messages-with-to_bytes)
27
27
  * [Data Types in Parsed Messages](#data-types-in-parsed-messages)
28
28
  * [Error Handling](#error-handling)
29
29
  * [Handling Strategies](#handling-strategies)
@@ -75,6 +75,8 @@ After installation (typically via pip), import the necessary modules directly in
75
75
 
76
76
  ## Usage
77
77
 
78
+ Download some sample data [here](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
79
+
78
80
  ### Parsing from a Binary File
79
81
 
80
82
  This is useful for processing historical ITCH data stored in files. The `MessageParser` handles buffering efficiently.
@@ -95,9 +97,8 @@ parser = MessageParser() # Parses all messages by default
95
97
 
96
98
  # Path to your ITCH 5.0 data file
97
99
  itch_file_path = 'path/to/your/data'
98
- # you can find sample data [here](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
99
100
 
100
- # The `read_message_from_file()` method reads the ITCH data in chunks.
101
+ # The `parse_file()` method reads the ITCH data in chunks.
101
102
  # - `cachesize` (optional, default: 65536 bytes): This parameter determines the size of data chunks
102
103
  # read from the file at a time. Adjusting this might impact performance for very large files
103
104
  # or memory usage, but the default is generally suitable.
@@ -108,13 +109,9 @@ itch_file_path = 'path/to/your/data'
108
109
 
109
110
  try:
110
111
  with open(itch_file_path, 'rb') as itch_file:
111
- # read_message_from_file returns a list of parsed message objects
112
- parsed_messages = parser.read_message_from_file(itch_file) # You can also pass cachesize here, e.g., parser.read_message_from_file(itch_file, cachesize=131072)
113
-
114
- print(f"Parsed {len(parsed_messages)} messages.")
115
-
112
+ # parse_file returns an Iterator of parsed message objects
116
113
  # Process the messages
117
- for message in parsed_messages:
114
+ for message in parser.parse_file(itch_file):
118
115
  # Access attributes directly
119
116
  print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
120
117
 
@@ -134,8 +131,8 @@ try:
134
131
 
135
132
  except FileNotFoundError:
136
133
  print(f"Error: File not found at {itch_file_path}")
137
- except Exception as e:
138
- print(f"An error occurred: {e}")
134
+ except ValueError as e:
135
+ print(f"An error occurred during parsing: {e}")
139
136
 
140
137
  ```
141
138
 
@@ -156,14 +153,8 @@ parser = MessageParser()
156
153
  # Example: \x00\x0bS...\x00\x25R...\x00\x27F...
157
154
  raw_binary_data: bytes = b"..." # Your raw ITCH 5.0 data chunk
158
155
 
159
- # read_message_from_bytes returns a queue of parsed message objects
160
- message_queue: Queue = parser.read_message_from_bytes(raw_binary_data)
161
-
162
- print(f"Parsed {message_queue.qsize()} messages from the byte chunk.")
163
-
164
- # Process messages from the queue
165
- while not message_queue.empty():
166
- message = message_queue.get()
156
+ # parse_stream returns an Iterator of parsed message objects
157
+ for message in parser.parse_stream(raw_binary_data)
167
158
 
168
159
  print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
169
160
 
@@ -240,10 +231,10 @@ for message_type, sample_data in TEST_DATA.items():
240
231
  print(f"Creating message of type {message_type}")
241
232
  message = create_message(message_type, **sample_data)
242
233
  print(f"Created message: {message}")
243
- print(f"Packed message: {message.pack()}")
234
+ print(f"Packed message: {message.to_bytes()}")
244
235
  print(f"Message size: {message.message_size}")
245
236
  print(f"Message Attributes: {message.get_attributes()}")
246
- assert len(message.pack()) == message.message_size
237
+ assert len(message.to_bytes()) == message.message_size
247
238
  print()
248
239
  ```
249
240
 
@@ -352,14 +343,14 @@ The `MarketMessage` base class, and therefore all specific message classes, prov
352
343
  * Returns a dictionary of all attributes (fields) of the message instance, along with their current values.
353
344
  * This can be useful for generic inspection or logging of message contents without needing to know the specific type of the message beforehand.
354
345
 
355
- ### Serializing Messages with `pack()`
346
+ ### Serializing Messages with `to_bytes()`
356
347
 
357
- Each specific message class (e.g., `SystemEventMessage`, `AddOrderNoMPIAttributionMessage`) also provides a `pack()` method. This method is the inverse of the parsing process.
348
+ Each specific message class (e.g., `SystemEventMessage`, `AddOrderNoMPIAttributionMessage`) also provides a `to_bytes()` method. This method is the inverse of the parsing process.
358
349
 
359
350
  * **Purpose:** It serializes the message object, with its current attribute values, back into its raw ITCH 5.0 binary format. The output is a `bytes` object representing the exact byte sequence that would appear in an ITCH data feed for that message.
360
351
  * **Usefulness:**
361
352
  * **Generating Test Data:** Create custom ITCH messages for testing your own ITCH processing applications.
362
- * **Modifying Messages:** Parse an existing message, modify some of its attributes, and then `pack()` it back into binary form.
353
+ * **Modifying Messages:** Parse an existing message, modify some of its attributes, and then `to_bytes()` it back into binary form.
363
354
  * **Creating Custom ITCH Feeds:** While more involved, you could use this to construct sequences of ITCH messages for specialized scenarios.
364
355
 
365
356
  **Example:**
@@ -379,21 +370,21 @@ import time
379
370
  # for packing requires setting attributes manually if not using raw bytes for construction)
380
371
 
381
372
  event_msg = SystemEventMessage.__new__(SystemEventMessage) # Create instance without calling __init__
382
- event_msg.message_type = b'S' # Must be set for pack() to know its type
373
+ event_msg.message_type = b'S' # Must be set for to_bytes() to know its type
383
374
  event_msg.stock_locate = 0 # Placeholder or actual value
384
375
  event_msg.tracking_number = 0 # Placeholder or actual value
385
376
  event_msg.event_code = b'O' # Example: Start of Messages
386
377
 
387
378
  # 2. Set the timestamp.
388
379
  # The `timestamp` attribute (nanoseconds since midnight) must be set.
389
- # The `pack()` method will internally use `split_timestamp()` to get the parts.
380
+ # The `to_bytes()` method will internally use `split_timestamp()` to get the parts.
390
381
  current_nanoseconds = int(time.time() * 1e9) % (24 * 60 * 60 * int(1e9))
391
382
  event_msg.timestamp = current_nanoseconds # Directly set the nanosecond timestamp
392
383
 
393
384
  # 3. Pack the message into binary format.
394
- # The pack() method prepends the message type and then packs stock_locate,
385
+ # The to_bytes() method prepends the message type and then packs stock_locate,
395
386
  # tracking_number, the split timestamp, and then the message-specific fields.
396
- packed_bytes = event_msg.pack()
387
+ packed_bytes = event_msg.to_bytes()
397
388
 
398
389
  # 4. The result is a bytes object
399
390
  print(f"Packed {len(packed_bytes)} bytes: {packed_bytes.hex().upper()}")
@@ -426,11 +417,12 @@ Common scenarios that can lead to a `ValueError` include:
426
417
 
427
418
  It's crucial to anticipate these errors in your application:
428
419
 
429
- * **Use `try-except` Blocks:** Wrap your parsing calls (especially `read_message_from_file` or `read_message_from_bytes`) in `try-except ValueError as e:` blocks.
420
+ * **Use `try-except` Blocks:** Wrap your parsing calls (especially `parse_file` or `parse_stream`) in `try-except ValueError as e:` blocks.
430
421
  ```python
431
422
  try:
432
423
  # ... parsing operations ...
433
- messages = parser.read_message_from_file(itch_file)
424
+ for message in parser.parse_file(itch_file):
425
+ ...
434
426
  except ValueError as e:
435
427
  print(f"An error occurred during parsing: {e}")
436
428
  # Log the error, problematic data chunk, or take other actions
@@ -0,0 +1,17 @@
1
+ """
2
+ Nasdaq TotalView-ITCH 5.0 Parser
3
+ """
4
+
5
+ __author__ = "Bertin Balouki SIMYELI"
6
+ __copyright__ = "2025 Bertin Balouki SIMYELI"
7
+ __email__ = "bertin@bbs-trading.com"
8
+ __license__ = "MIT"
9
+
10
+ from importlib.metadata import version, PackageNotFoundError
11
+
12
+ try:
13
+ __version__ = version("itchfeed")
14
+ except PackageNotFoundError:
15
+ __version__ = "unknown"
16
+
17
+
@@ -13,13 +13,21 @@ class MarketMessage(object):
13
13
 
14
14
  All Message have the following attributes:
15
15
  - message_type: A single letter that identify the message
16
+ - timestamp: Time at which the message was generated (Nanoseconds past midnight)
17
+ - stock_locate: Locate code identifying the security
18
+ - tracking_number: Nasdaq internal tracking number
19
+
20
+ The following attributes are not part of the message, but are used to describe the message:
16
21
  - description: Describe the message
17
22
  - message_format: string format using to unpack the message
18
23
  - message_pack_format: string format using to pack the message
19
24
  - message_size: The size in bytes of the message
20
- - timestamp: Time at which the message was generated (Nanoseconds past midnight)
21
- - stock_locate: Locate code identifying the security
22
- - tracking_number: Nasdaq internal tracking number
25
+
26
+ # NOTE:
27
+ Prices are integers fields supplied with an associated precision. When converted to a decimal format, prices are in
28
+ fixed point format, where the precision defines the number of decimal places. For example, a field flagged as Price
29
+ (4) has an implied 4 decimal places. The maximum value of price (4) in TotalView ITCH is 200,000.0000 (decimal,
30
+ 77359400 hex). ``price_precision`` is 4 for all messages except MWCBDeclineLeveMessage where ``price_precision`` is 8.
23
31
  """
24
32
 
25
33
  message_type: bytes
@@ -32,13 +40,24 @@ class MarketMessage(object):
32
40
  tracking_number: int
33
41
  price_precision: int = 4
34
42
 
35
- def __repr__(self):
43
+ def __repr__(self) -> str:
36
44
  return repr(self.decode())
37
45
 
38
- def pack(self) -> bytes:
46
+ def __bytes__(self) -> bytes:
47
+ return self.to_bytes()
48
+
49
+ def to_bytes(self) -> bytes: # type: ignore
39
50
  """
40
51
  Packs the message into bytes using the defined message_pack_format.
41
52
  This method should be overridden by subclasses to include specific fields.
53
+
54
+ Note:
55
+ All packed messages do not include
56
+ - ``description``,
57
+ - ``message_format``,
58
+ - ``message_pack_format``,
59
+ - ``message_size``
60
+ - ``price_precision``
42
61
  """
43
62
  pass
44
63
 
@@ -90,9 +109,7 @@ class MarketMessage(object):
90
109
  ts1 = self.timestamp >> 32
91
110
  ts2 = self.timestamp - (ts1 << 32)
92
111
  return (ts1, ts2)
93
- ts1 = self.timestamp >> 32
94
- ts2 = self.timestamp - (ts1 << 32)
95
- return (ts1, ts2)
112
+
96
113
 
97
114
  def decode_price(self, price_attr: str) -> float:
98
115
  precision = getattr(self, "price_precision")
@@ -166,7 +183,7 @@ class SystemEventMessage(MarketMessage):
166
183
  ) = struct.unpack(self.message_format, message[1:])
167
184
  self.set_timestamp(timestamp1, timestamp2)
168
185
 
169
- def pack(self):
186
+ def to_bytes(self):
170
187
  (timestamp1, timestamp2) = self.split_timestamp()
171
188
  message = struct.pack(
172
189
  self.message_pack_format,
@@ -288,7 +305,7 @@ class StockDirectoryMessage(MarketMessage):
288
305
  ) = struct.unpack(self.message_format, message[1:])
289
306
  self.set_timestamp(timestamp1, timestamp2)
290
307
 
291
- def pack(self):
308
+ def to_bytes(self):
292
309
  (timestamp1, timestamp2) = self.split_timestamp()
293
310
  message = struct.pack(
294
311
  self.message_pack_format,
@@ -368,7 +385,7 @@ class StockTradingActionMessage(MarketMessage):
368
385
  ) = struct.unpack(self.message_format, message[1:])
369
386
  self.set_timestamp(timestamp1, timestamp2)
370
387
 
371
- def pack(self):
388
+ def to_bytes(self):
372
389
  (timestamp1, timestamp2) = self.split_timestamp()
373
390
  message = struct.pack(
374
391
  self.message_pack_format,
@@ -429,7 +446,7 @@ class RegSHOMessage(MarketMessage):
429
446
  ) = struct.unpack(self.message_format, message[1:])
430
447
  self.set_timestamp(timestamp1, timestamp2)
431
448
 
432
- def pack(self):
449
+ def to_bytes(self):
433
450
  (timestamp1, timestamp2) = self.split_timestamp()
434
451
  message = struct.pack(
435
452
  self.message_pack_format,
@@ -491,7 +508,7 @@ class MarketParticipantPositionMessage(MarketMessage):
491
508
  ) = struct.unpack(self.message_format, message[1:])
492
509
  self.set_timestamp(timestamp1, timestamp2)
493
510
 
494
- def pack(self):
511
+ def to_bytes(self):
495
512
  (timestamp1, timestamp2) = self.split_timestamp()
496
513
  message = struct.pack(
497
514
  self.message_pack_format,
@@ -542,7 +559,7 @@ class MWCBDeclineLeveMessage(MarketMessage):
542
559
  ) = struct.unpack(self.message_format, message[1:])
543
560
  self.set_timestamp(timestamp1, timestamp2)
544
561
 
545
- def pack(self):
562
+ def to_bytes(self):
546
563
  (timestamp1, timestamp2) = self.split_timestamp()
547
564
  message = struct.pack(
548
565
  self.message_pack_format,
@@ -587,7 +604,7 @@ class MWCBStatusMessage(MarketMessage):
587
604
  ) = struct.unpack(self.message_format, message[1:])
588
605
  self.set_timestamp(timestamp1, timestamp2)
589
606
 
590
- def pack(self):
607
+ def to_bytes(self):
591
608
  (timestamp1, timestamp2) = self.split_timestamp()
592
609
  message = struct.pack(
593
610
  self.message_pack_format,
@@ -648,7 +665,7 @@ class IPOQuotingPeriodUpdateMessage(MarketMessage):
648
665
  ) = struct.unpack(self.message_format, message[1:])
649
666
  self.set_timestamp(timestamp1, timestamp2)
650
667
 
651
- def pack(self):
668
+ def to_bytes(self):
652
669
  (timestamp1, timestamp2) = self.split_timestamp()
653
670
  message = struct.pack(
654
671
  self.message_pack_format,
@@ -704,7 +721,7 @@ class LULDAuctionCollarMessage(MarketMessage):
704
721
  ) = struct.unpack(self.message_format, message[1:])
705
722
  self.set_timestamp(timestamp1, timestamp2)
706
723
 
707
- def pack(self):
724
+ def to_bytes(self):
708
725
  (timestamp1, timestamp2) = self.split_timestamp()
709
726
  message = struct.pack(
710
727
  self.message_pack_format,
@@ -769,7 +786,7 @@ class OperationalHaltMessage(MarketMessage):
769
786
  ) = struct.unpack(self.message_format, message[1:])
770
787
  self.set_timestamp(timestamp1, timestamp2)
771
788
 
772
- def pack(self):
789
+ def to_bytes(self):
773
790
  (timestamp1, timestamp2) = self.split_timestamp()
774
791
  message = struct.pack(
775
792
  self.message_pack_format,
@@ -832,7 +849,7 @@ class AddOrderNoMPIAttributionMessage(AddOrderMessage):
832
849
  ) = struct.unpack(self.message_format, message[1:])
833
850
  self.set_timestamp(timestamp1, timestamp2)
834
851
 
835
- def pack(self):
852
+ def to_bytes(self):
836
853
  (timestamp1, timestamp2) = self.split_timestamp()
837
854
  message = struct.pack(
838
855
  self.message_pack_format,
@@ -886,7 +903,7 @@ class AddOrderMPIDAttribution(AddOrderMessage):
886
903
  ) = struct.unpack(self.message_format, message[1:])
887
904
  self.set_timestamp(timestamp1, timestamp2)
888
905
 
889
- def pack(self):
906
+ def to_bytes(self):
890
907
  (timestamp1, timestamp2) = self.split_timestamp()
891
908
  message = struct.pack(
892
909
  self.message_pack_format,
@@ -957,7 +974,7 @@ class OrderExecutedMessage(ModifyOrderMessage):
957
974
  ) = struct.unpack(self.message_format, message[1:])
958
975
  self.set_timestamp(timestamp1, timestamp2)
959
976
 
960
- def pack(self):
977
+ def to_bytes(self):
961
978
  (timestamp1, timestamp2) = self.split_timestamp()
962
979
  message = struct.pack(
963
980
  self.message_pack_format,
@@ -1025,7 +1042,7 @@ class OrderExecutedWithPriceMessage(ModifyOrderMessage):
1025
1042
  ) = struct.unpack(self.message_format, message[1:])
1026
1043
  self.set_timestamp(timestamp1, timestamp2)
1027
1044
 
1028
- def pack(self):
1045
+ def to_bytes(self):
1029
1046
  (timestamp1, timestamp2) = self.split_timestamp()
1030
1047
  message = struct.pack(
1031
1048
  self.message_pack_format,
@@ -1071,7 +1088,7 @@ class OrderCancelMessage(ModifyOrderMessage):
1071
1088
  ) = struct.unpack(self.message_format, message[1:])
1072
1089
  self.set_timestamp(timestamp1, timestamp2)
1073
1090
 
1074
- def pack(self):
1091
+ def to_bytes(self):
1075
1092
  (timestamp1, timestamp2) = self.split_timestamp()
1076
1093
  message = struct.pack(
1077
1094
  self.message_pack_format,
@@ -1111,7 +1128,7 @@ class OrderDeleteMessage(ModifyOrderMessage):
1111
1128
  ) = struct.unpack(self.message_format, message[1:])
1112
1129
  self.set_timestamp(timestamp1, timestamp2)
1113
1130
 
1114
- def pack(self):
1131
+ def to_bytes(self):
1115
1132
  (timestamp1, timestamp2) = self.split_timestamp()
1116
1133
  message = struct.pack(
1117
1134
  self.message_pack_format,
@@ -1164,7 +1181,7 @@ class OrderReplaceMessage(ModifyOrderMessage):
1164
1181
  ) = struct.unpack(self.message_format, message[1:])
1165
1182
  self.set_timestamp(timestamp1, timestamp2)
1166
1183
 
1167
- def pack(self):
1184
+ def to_bytes(self):
1168
1185
  (timestamp1, timestamp2) = self.split_timestamp()
1169
1186
  message = struct.pack(
1170
1187
  self.message_pack_format,
@@ -1238,7 +1255,7 @@ class NonCrossTradeMessage(TradeMessage):
1238
1255
  ) = struct.unpack(self.message_format, message[1:])
1239
1256
  self.set_timestamp(timestamp1, timestamp2)
1240
1257
 
1241
- def pack(self):
1258
+ def to_bytes(self):
1242
1259
  (timestamp1, timestamp2) = self.split_timestamp()
1243
1260
  message = struct.pack(
1244
1261
  self.message_pack_format,
@@ -1309,7 +1326,7 @@ class CrossTradeMessage(TradeMessage):
1309
1326
  ) = struct.unpack(self.message_format, message[1:])
1310
1327
  self.set_timestamp(timestamp1, timestamp2)
1311
1328
 
1312
- def pack(self):
1329
+ def to_bytes(self):
1313
1330
  (timestamp1, timestamp2) = self.split_timestamp()
1314
1331
  message = struct.pack(
1315
1332
  self.message_pack_format,
@@ -1359,7 +1376,7 @@ class BrokenTradeMessage(TradeMessage):
1359
1376
  ) = struct.unpack(self.message_format, message[1:])
1360
1377
  self.set_timestamp(timestamp1, timestamp2)
1361
1378
 
1362
- def pack(self):
1379
+ def to_bytes(self):
1363
1380
  (timestamp1, timestamp2) = self.split_timestamp()
1364
1381
  message = struct.pack(
1365
1382
  self.message_pack_format,
@@ -1441,7 +1458,7 @@ class NOIIMessage(MarketMessage):
1441
1458
  ) = struct.unpack(self.message_format, message[1:])
1442
1459
  self.set_timestamp(timestamp1, timestamp2)
1443
1460
 
1444
- def pack(self):
1461
+ def to_bytes(self):
1445
1462
  (timestamp1, timestamp2) = self.split_timestamp()
1446
1463
  message = struct.pack(
1447
1464
  self.message_pack_format,
@@ -1496,7 +1513,7 @@ class RetailPriceImprovementIndicator(MarketMessage):
1496
1513
  ) = struct.unpack(self.message_format, message[1:])
1497
1514
  self.set_timestamp(timestamp1, timestamp2)
1498
1515
 
1499
- def pack(self):
1516
+ def to_bytes(self):
1500
1517
  (timestamp1, timestamp2) = self.split_timestamp()
1501
1518
  message = struct.pack(
1502
1519
  self.message_pack_format,
@@ -1559,7 +1576,7 @@ class DLCRMessage(MarketMessage):
1559
1576
  ) = struct.unpack(self.message_format, message[1:])
1560
1577
  self.set_timestamp(timestamp1, timestamp2)
1561
1578
 
1562
- def pack(self):
1579
+ def to_bytes(self):
1563
1580
  (timestamp1, timestamp2) = self.split_timestamp()
1564
1581
  message = struct.pack(
1565
1582
  self.message_pack_format,
@@ -1579,8 +1596,8 @@ class DLCRMessage(MarketMessage):
1579
1596
  )
1580
1597
  return message
1581
1598
 
1582
-
1583
- messages: Dict[bytes, Type[MarketMessage]] = {
1599
+ messages: Dict[bytes, Type[MarketMessage]]
1600
+ messages = {
1584
1601
  b"S": SystemEventMessage,
1585
1602
  b"R": StockDirectoryMessage,
1586
1603
  b"H": StockTradingActionMessage,
@@ -1607,7 +1624,7 @@ messages: Dict[bytes, Type[MarketMessage]] = {
1607
1624
  }
1608
1625
 
1609
1626
 
1610
- def create_message(message_type: bytes, **kwargs) -> Type[MarketMessage]:
1627
+ def create_message(message_type: bytes, **kwargs) -> MarketMessage:
1611
1628
  """
1612
1629
  Creates a new message of a given type with specified attributes.
1613
1630