itchfeed 1.0.2__py3-none-any.whl → 1.0.3__py3-none-any.whl

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.
itch/parser.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from queue import Queue
2
- from typing import BinaryIO, List
2
+ from typing import BinaryIO, List, Type
3
3
 
4
4
  from itch.messages import MESSAGES, MarketMessage
5
5
  from itch.messages import messages as msgs
@@ -157,7 +157,7 @@ class MessageParser(object):
157
157
 
158
158
  return messages
159
159
 
160
- def get_message_type(self, message: bytes):
160
+ def get_message_type(self, message: bytes) -> Type[MarketMessage]:
161
161
  """
162
162
  Take an entire bytearray and return the appropriate ITCH message
163
163
  instance based on the message type indicator (first byte of the message).
@@ -0,0 +1,422 @@
1
+ Metadata-Version: 2.4
2
+ Name: itchfeed
3
+ Version: 1.0.3
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)
11
+ Project-URL: Source Code, https://github.com/bbalouki/itch
12
+ Keywords: Finance,Financial,Quantitative,Equities,Totalview-ITCH,Totalview,Nasdaq-ITCH,Nasdaq,ITCH,Data,Feed,ETFs,Funds,Trading,Investing
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Financial and Insurance Industry
16
+ Classifier: Topic :: Office/Business :: Financial :: Investment
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Operating System :: OS Independent
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ 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
+ Dynamic: license-file
32
+ Dynamic: maintainer
33
+ Dynamic: project-url
34
+ Dynamic: requires-dist
35
+ Dynamic: summary
36
+
37
+ # Nasdaq TotalView-ITCH 5.0 Parser
38
+ [![PYPI Version](https://img.shields.io/pypi/v/itchfeed)](https://pypi.org/project/itchfeed/)
39
+ [![PyPi status](https://img.shields.io/pypi/status/itchfeed.svg?maxAge=60)](https://pypi.python.org/pypi/itchfeed)
40
+ [![Supported Python Versions](https://img.shields.io/pypi/pyversions/itchfeed)](https://pypi.org/project/itchfeed/)
41
+ [![PyPI Downloads](https://static.pepy.tech/badge/itchfeed)](https://pepy.tech/projects/itchfeed)
42
+ [![CodeFactor](https://www.codefactor.io/repository/github/bbalouki/itch/badge)](https://www.codefactor.io/repository/github/bbalouki/itch)
43
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-grey?logo=Linkedin&logoColor=white)](https://www.linkedin.com/in/bertin-balouki-simyeli-15b17a1a6/)
44
+ [![PayPal Me](https://img.shields.io/badge/PayPal%20Me-blue?logo=paypal)](https://paypal.me/bertinbalouki?country.x=SN&locale.x=en_US)
45
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
46
+
47
+ ## Table of Contents
48
+
49
+ * [Overview](#overview)
50
+ * [Features](#features)
51
+ * [Installation](#installation)
52
+ * [Usage](#usage)
53
+ * [Parsing from a Binary File](#parsing-from-a-binary-file)
54
+ * [Parsing from Raw Bytes](#parsing-from-raw-bytes)
55
+ * [Interpreting Market Data (Conceptual Overview)](#interpreting-market-data-conceptual-overview)
56
+ * [Supported Message Types](#supported-message-types)
57
+ * [Data Representation](#data-representation)
58
+ * [Common Attributes of `MarketMessage`](#common-attributes-of-marketmessage)
59
+ * [Common Methods of `MarketMessage`](#common-methods-of-marketmessage)
60
+ * [Serializing Messages with `pack()`](#serializing-messages-with-pack)
61
+ * [Data Types in Parsed Messages](#data-types-in-parsed-messages)
62
+ * [Error Handling](#error-handling)
63
+ * [Handling Strategies](#handling-strategies)
64
+ * [Contributing](#contributing)
65
+ * [License](#license)
66
+ * [References](#references)
67
+
68
+ A Python library for parsing binary data conforming to the Nasdaq TotalView-ITCH 5.0 protocol specification. This parser converts the raw byte stream into structured Python objects, making it easier to work with Nasdaq market data.
69
+
70
+ ## Overview
71
+
72
+ The Nasdaq TotalView-ITCH 5.0 protocol is a binary protocol used by Nasdaq to disseminate full order book depth, trade information, and system events for equities traded on its execution system. This parser handles the low-level details of reading the binary format, unpacking fields according to the specification, and presenting the data as intuitive Python objects.
73
+
74
+ ## Features
75
+
76
+ * **Parses ITCH 5.0 Binary Data:** Accurately interprets the binary message structures defined in the official specification.
77
+ * **Supports All Standard Message Types:** Implements classes for all messages defined in the ITCH 5.0 specification (System Event, Stock Directory, Add Order, Trade, etc.).
78
+ * **Object-Oriented Representation:** Each ITCH message type is represented by a dedicated Python class (`SystemEventMessage`, `AddOrderMessage`, etc.), inheriting from a common `MarketMessage` base class.
79
+ * **Flexible Input:** Reads and parses messages from:
80
+ * Binary files (`.gz` or similar).
81
+ * Raw byte streams (e.g., from network sockets).
82
+ * **Data Decoding:** Provides a `.decode()` method on each message object to convert it into a human-readable `dataclass` representation, handling:
83
+ * Byte-to-string conversion (ASCII).
84
+ * Stripping padding spaces.
85
+ * Price decoding based on defined precision.
86
+ * **Timestamp Handling:** Correctly reconstructs the 6-byte (48-bit) nanosecond timestamps.
87
+ * **Price Handling:** Decodes fixed-point price fields into floating-point numbers based on the standard 4 or 8 decimal place precision.
88
+ * **Pure Python:** Relies only on the Python standard library. No external dependencies required.
89
+
90
+ ## Installation
91
+
92
+ The recommended way to install `itchfeed` is from PyPI using `pip`:
93
+ ```bash
94
+ pip install itchfeed
95
+ ```
96
+
97
+ If you want to contribute to development or need the latest unreleased version, you can clone the repository:
98
+ ```bash
99
+ git clone https://github.com/bbalouki/itch.git
100
+ cd itch
101
+ # Then you might install it in editable mode or run tests, etc.
102
+ ```
103
+
104
+ After installation (typically via pip), import the necessary modules directly into your Python project:
105
+ ```python
106
+ from itch.parser import MessageParser
107
+ from itch.messages import ModifyOrderMessage
108
+ ```
109
+
110
+ ## Usage
111
+
112
+ ### Parsing from a Binary File
113
+
114
+ This is useful for processing historical ITCH data stored in files. The `MessageParser` handles buffering efficiently.
115
+
116
+ ```python
117
+ from itch.parser import MessageParser
118
+ from itch.messages import AddOrderMessage, TradeMessage
119
+
120
+ # Initialize the parser.
121
+ # By default, MessageParser() will parse all known message types.
122
+ # Optionally, you can filter for specific messages by providing the `message_type` parameter.
123
+ # This parameter takes a bytes string containing the characters of the message types you want to parse.
124
+ # For example, to only parse Add Order (No MPID 'A'), Stock Directory ('R'), and Stock Trading Action ('H') messages:
125
+ # parser = MessageParser(message_type=b"ARH")
126
+ # Refer to the MESSAGES constant in `itch.messages` or the table in the "Supported Message Types"
127
+ # section for all available type codes.
128
+ parser = MessageParser() # Parses all messages by default
129
+
130
+ # Path to your ITCH 5.0 data file
131
+ itch_file_path = 'path/to/your/data'
132
+ # you can find sample data [here](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
133
+
134
+ # The `read_message_from_file()` method reads the ITCH data in chunks.
135
+ # - `cachesize` (optional, default: 65536 bytes): This parameter determines the size of data chunks
136
+ # read from the file at a time. Adjusting this might impact performance for very large files
137
+ # or memory usage, but the default is generally suitable.
138
+ # The parsing process stops when either:
139
+ # 1. The end of the file is reached.
140
+ # 2. A System Event Message (type 'S') with an event_code of 'C' (End of Messages)
141
+ # is encountered, signaling the end of the ITCH feed for the session.
142
+
143
+ try:
144
+ with open(itch_file_path, 'rb') as itch_file:
145
+ # read_message_from_file returns a list of parsed message objects
146
+ 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)
147
+
148
+ print(f"Parsed {len(parsed_messages)} messages.")
149
+
150
+ # Process the messages
151
+ for message in parsed_messages:
152
+ # Access attributes directly
153
+ print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
154
+
155
+ if isinstance(message, AddOrderMessage):
156
+ print(f" Add Order: Ref={message.order_reference_number}, "
157
+ f"Side={message.buy_sell_indicator.decode()}, "
158
+ f"Shares={message.shares}, Stock={message.stock.decode().strip()}, "
159
+ f"Price={message.decode_price('price')}")
160
+
161
+ elif isinstance(message, TradeMessage):
162
+ print(f" Trade: Match={message.match_number}")
163
+ # Access specific trade type attributes...
164
+
165
+ # Get a human-readable dataclass representation
166
+ decoded_msg = message.decode()
167
+ print(f" Decoded: {decoded_msg}")
168
+
169
+ except FileNotFoundError:
170
+ print(f"Error: File not found at {itch_file_path}")
171
+ except Exception as e:
172
+ print(f"An error occurred: {e}")
173
+
174
+ ```
175
+
176
+ ### Parsing from Raw Bytes
177
+
178
+ This is suitable for real-time processing, such as reading from a network stream.
179
+
180
+ ```python
181
+ from itch.parser import MessageParser
182
+ from itch.messages import AddOrderMessage
183
+ from queue import Queue
184
+
185
+ # Initialize the parser
186
+ parser = MessageParser()
187
+
188
+ # Simulate receiving a chunk of binary data (e.g., from a network socket)
189
+ # This chunk contains multiple ITCH messages, each prefixed with 0x00 and length byte
190
+ # Example: \x00\x0bS...\x00\x25R...\x00\x27F...
191
+ raw_binary_data: bytes = b"..." # Your raw ITCH 5.0 data chunk
192
+
193
+ # read_message_from_bytes returns a queue of parsed message objects
194
+ message_queue: Queue = parser.read_message_from_bytes(raw_binary_data)
195
+
196
+ print(f"Parsed {message_queue.qsize()} messages from the byte chunk.")
197
+
198
+ # Process messages from the queue
199
+ while not message_queue.empty():
200
+ message = message_queue.get()
201
+
202
+ print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
203
+
204
+ if isinstance(message, AddOrderMessage):
205
+ print(f" Add Order: Ref={message.order_reference_number}, "
206
+ f"Stock={message.stock.decode().strip()}, Price={message.decode_price('price')}")
207
+
208
+ # Use the decoded representation
209
+ decoded_msg = message.decode(prefix="Decoded")
210
+ print(f" Decoded: {decoded_msg}")
211
+
212
+ ```
213
+
214
+ ## Interpreting Market Data (Conceptual Overview)
215
+
216
+ Parsing individual ITCH messages is the first step; understanding market dynamics often requires processing and correlating a sequence of these messages. This library provides the tools to decode messages, but interpreting their collective meaning requires building further logic.
217
+
218
+ A common use case is to build and maintain a local representation of the order book for a particular stock. Here's a simplified, high-level overview of how different messages interact in this context:
219
+
220
+ * **Building the Book:**
221
+ * `AddOrderNoMPIAttributionMessage` (Type `A`) and `AddOrderMPIDAttribution` (Type `F`) represent new orders being added to the order book. These messages provide the initial size, price, and side (buy/sell) of the order, along with a unique `order_reference_number`.
222
+
223
+ * **Modifying and Removing Orders:**
224
+ * `OrderExecutedMessage` (Type `E`) and `OrderExecutedWithPriceMessage` (Type `C`) indicate that a portion or all of an existing order (identified by `order_reference_number`) has been executed. The executed shares should be subtracted from the remaining quantity of the order on the book. If the execution fully fills the order, it's removed.
225
+ * `OrderCancelMessage` (Type `X`) indicates that a number of shares from an existing order (identified by `order_reference_number`) have been canceled. The canceled shares should be subtracted from the order's quantity. If this results in zero shares, the order is removed.
226
+ * `OrderDeleteMessage` (Type `D`) indicates that an entire existing order (identified by `order_reference_number`) has been deleted from the book.
227
+ * `OrderReplaceMessage` (Type `U`) is effectively a cancel-and-replace operation. The order identified by `order_reference_number` should be removed, and a new order with a `new_order_reference_number` and new characteristics (size, price) should be added to the book.
228
+
229
+ * **Observing Trades:**
230
+ * `NonCrossTradeMessage` (Type `P`) and `CrossTradeMessage` (Type `Q`) provide information about actual trades that have occurred. While `OrderExecutedMessage` and `OrderExecutedWithPriceMessage` detail the impact on specific orders in the book, `TradeMessage` types provide a direct stream of trade prints.
231
+
232
+ **Important Considerations:**
233
+
234
+ This is a very simplified overview. Building a complete and accurate order book or a sophisticated trading analysis tool requires:
235
+ * Careful handling of message sequences and their `timestamp` order.
236
+ * Managing state for each `order_reference_number` across multiple messages.
237
+ * Understanding the nuances of different order types, market events (like halts or auctions signaled by `StockTradingActionMessage` or `NOIIMessage`), and how they impact the book.
238
+ * Adhering closely to the official Nasdaq TotalView-ITCH 5.0 specification for detailed business logic.
239
+
240
+ This library aims to handle the binary parsing, allowing you to focus on implementing this higher-level interpretative logic.
241
+
242
+ ## Supported Message Types
243
+
244
+ The parser supports the following ITCH 5.0 message types. Each message object has attributes corresponding to the fields defined in the specification. Refer to the class docstrings in `itch.messages` for detailed attribute descriptions.
245
+
246
+ | Type (Byte) | Class Name | Description |
247
+ | :---------- | :-------------------------------- | :----------------------------------------------- |
248
+ | `S` | `SystemEventMessage` | System Event Message. Signals a market or data feed handler event. <br> `event_code` indicates the type: <br> - `O`: Start of Messages <br> - `S`: Start of System Hours <br> - `Q`: Start of Market Hours <br> - `M`: End of Market Hours <br> - `E`: End of System Hours <br> - `C`: End of Messages |
249
+ | `R` | `StockDirectoryMessage` | Stock Directory Message. Disseminated for all active symbols at the start of each trading day. <br> Key fields include: <br> - `market_category`: (e.g., `Q`: NASDAQ Global Select Market) <br> - `financial_status_indicator`: (e.g., `D`: Deficient) <br> - `issue_classification`: (e.g., `A`: American Depositary Share) <br> - `issue_sub_type`: (e.g., `AI`: ADR representing an underlying foreign issuer) |
250
+ | `H` | `StockTradingActionMessage` | Stock Trading Action Message. Indicates the current trading status of a security. <br> Key fields: <br> - `trading_state`: (e.g., `H`: Halted, `T`: Trading) <br> - `reason`: (e.g., `T1`: Halt due to news pending) |
251
+ | `Y` | `RegSHOMessage` | Reg SHO Short Sale Price Test Restricted Indicator. <br> `reg_sho_action` indicates status: <br> - `0`: No price test in place <br> - `1`: Restriction in effect (intra-day drop) <br> - `2`: Restriction remains in effect |
252
+ | `L` | `MarketParticipantPositionMessage`| Market Participant Position message. Provides status for each Nasdaq market participant firm in an issue. <br> Key fields: <br> - `primary_market_maker`: (e.g., `Y`: Yes, `N`: No) <br> - `market_maker_mode`: (e.g., `N`: Normal) <br> - `market_participant_state`: (e.g., `A`: Active) |
253
+ | `V` | `MWCBDeclineLeveMessage` | Market-Wide Circuit Breaker (MWCB) Decline Level Message. Informs recipients of the daily MWCB breach points. |
254
+ | `W` | `MWCBStatusMessage` | Market-Wide Circuit Breaker (MWCB) Status Message. Informs when a MWCB level has been breached. |
255
+ | `K` | `IPOQuotingPeriodUpdateMessage` | IPO Quoting Period Update Message. Indicates anticipated IPO quotation release time. |
256
+ | `J` | `LULDAuctionCollarMessage` | LULD Auction Collar Message. Indicates auction collar thresholds for a paused security. |
257
+ | `h` | `OperationalHaltMessage` | Operational Halt Message. Indicates an interruption of service on the identified security impacting only the designated Market Center. |
258
+ | `A` | `AddOrderNoMPIAttributionMessage` | Add Order (No MPID Attribution). A new unattributed order has been accepted and added to the displayable book. |
259
+ | `F` | `AddOrderMPIDAttribution` | Add Order (MPID Attribution). A new attributed order or quotation has been accepted. |
260
+ | `E` | `OrderExecutedMessage` | Order Executed Message. An order on the book has been executed in whole or in part. |
261
+ | `C` | `OrderExecutedWithPriceMessage` | Order Executed With Price Message. An order on the book has been executed at a price different from its initial display price. |
262
+ | `X` | `OrderCancelMessage` | Order Cancel Message. An order on the book is modified due to a partial cancellation. |
263
+ | `D` | `OrderDeleteMessage` | Order Delete Message. An order on the book is being cancelled. |
264
+ | `U` | `OrderReplaceMessage` | Order Replace Message. An order on the book has been cancel-replaced. |
265
+ | `P` | `NonCrossTradeMessage` | Trade Message (Non-Cross). Provides execution details for normal match events involving non-displayable order types. |
266
+ | `Q` | `CrossTradeMessage` | Cross Trade Message. Indicates completion of a cross process (Opening, Closing, Halt/IPO) for a specific security. |
267
+ | `B` | `BrokenTradeMessage` | Broken Trade / Order Execution Message. An execution on Nasdaq has been broken. |
268
+ | `I` | `NOIIMessage` | Net Order Imbalance Indicator (NOII) Message. <br> Key fields: <br> - `cross_type`: Context of the imbalance (e.g., `O`: Opening Cross, `C`: Closing Cross, `H`: Halt/IPO Cross, `A`: Extended Trading Close). <br> - `price_variation_indicator`: Deviation of Near Indicative Clearing Price from Current Reference Price (e.g., `L`: Less than 1%). <br> - `imbalance_direction`: (e.g., `B`: Buy imbalance, `S`: Sell imbalance, `N`: No imbalance, `O`: Insufficient orders to calculate) |
269
+ | `N` | `RetailPriceImprovementIndicator` | Retail Price Improvement Indicator (RPII). Identifies retail interest on Bid, Ask, or both. |
270
+ | `O` | `DLCRMessage` | Direct Listing with Capital Raise Message. Disseminated for DLCR securities once volatility test passes. |
271
+
272
+ ## Data Representation
273
+
274
+ All message classes inherit from `itch.messages.MarketMessage`. This base class provides a common structure and utility methods for all ITCH message types.
275
+
276
+ ### Common Attributes of `MarketMessage`
277
+
278
+ Each instance of a `MarketMessage` (and its subclasses) will have the following attributes:
279
+
280
+ * `message_type` (bytes): A single byte character identifying the type of the ITCH message (e.g., `b'S'` for System Event, `b'A'` for Add Order).
281
+ * `description` (str): A human-readable description of the message type (e.g., "System Event Message", "Add Order No MPID Attribution Message").
282
+ * `message_format` (str): An internal string defining the `struct` format for packing/unpacking the core message fields. This is primarily for internal parser use.
283
+ * `message_pack_format` (str): An internal string, often similar to `message_format`, specifically for packing operations. This is primarily for internal parser use.
284
+ * `message_size` (int): The size of the binary message in bytes, as read from the message header or defined by the specification.
285
+ * `timestamp` (int): A 64-bit integer representing the time of the event in nanoseconds since midnight. This is reconstructed from the 6-byte raw timestamp. See `set_timestamp()` and `split_timestamp()` methods.
286
+ * `stock_locate` (int): A code used to identify the stock for Nasdaq messages. Usually, this is the first field after the Message Type.
287
+ * `tracking_number` (int): A tracking number assigned by Nasdaq to each message.
288
+ * `price_precision` (int): An integer (typically 4 or 8) indicating the number of decimal places for price fields within this message type. This is crucial for correctly interpreting price data. See `decode_price()`.
289
+
290
+ ### Common Methods of `MarketMessage`
291
+
292
+ The `MarketMessage` base class, and therefore all specific message classes, provide these useful methods:
293
+
294
+ * `set_timestamp(timestamp_high: int, timestamp_low: int)`:
295
+ * This method is typically used internally by the parser. It reconstructs the full 48-bit nanosecond timestamp from two parts provided by unpacking the raw message bytes.
296
+ * `timestamp_high`: The higher-order 2 bytes (16 bits) of the 6-byte ITCH timestamp.
297
+ * `timestamp_low`: The lower-order 4 bytes (32 bits) of the 6-byte ITCH timestamp.
298
+ * These are combined to set the `timestamp` attribute (a 64-bit integer representing nanoseconds since midnight) of the message object. The full 48-bit value is stored within this 64-bit integer.
299
+ * `split_timestamp(timestamp_nanoseconds: int = None) -> tuple[int, int]`:
300
+ * Takes an optional 64-bit integer timestamp (nanoseconds since midnight); if `None`, it uses the message's current `timestamp` attribute (which holds the 48-bit value).
301
+ * Splits this timestamp into two integer components: the higher-order 2 bytes (16 bits) and the lower-order 4 bytes (32 bits), matching how they are packed in the raw ITCH message. This is primarily for internal use during packing.
302
+ * `decode_price(attribute_name: str) -> float`:
303
+ * Takes the string name of a price attribute within the message object (e.g., `'price'`, `'execution_price'`).
304
+ * Retrieves the raw integer value of that attribute.
305
+ * Divides the raw integer by `10 ** self.price_precision` to convert it into a floating-point number with the correct decimal places. For example, if `price_precision` is 4 and the raw price is `1234500`, this method returns `123.45`.
306
+ * `decode() -> dataclass`:
307
+ * This is a key method for usability. It processes the raw byte fields of the message object and converts them into a more human-readable Python `dataclass`.
308
+ * Specifically, it:
309
+ * Converts alpha-numeric byte strings (like stock symbols or MPIDs) into standard Python strings, stripping any right-padding spaces.
310
+ * Converts price fields into floating-point numbers using the `decode_price()` logic internally.
311
+ * Keeps other fields (like share counts or reference numbers) in their appropriate integer or byte format if no further conversion is needed.
312
+ * The returned `dataclass` provides a clean, immutable, and easily inspectable representation of the message content.
313
+ * `get_attributes() -> dict`:
314
+ * Returns a dictionary of all attributes (fields) of the message instance, along with their current values.
315
+ * This can be useful for generic inspection or logging of message contents without needing to know the specific type of the message beforehand.
316
+
317
+ ### Serializing Messages with `pack()`
318
+
319
+ Each specific message class (e.g., `SystemEventMessage`, `AddOrderNoMPIAttributionMessage`) also provides a `pack()` method. This method is the inverse of the parsing process.
320
+
321
+ * **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.
322
+ * **Usefulness:**
323
+ * **Generating Test Data:** Create custom ITCH messages for testing your own ITCH processing applications.
324
+ * **Modifying Messages:** Parse an existing message, modify some of its attributes, and then `pack()` it back into binary form.
325
+ * **Creating Custom ITCH Feeds:** While more involved, you could use this to construct sequences of ITCH messages for specialized scenarios.
326
+
327
+ **Example:**
328
+
329
+ ```python
330
+ from itch.messages import SystemEventMessage
331
+ import time
332
+
333
+ # 1. Create a SystemEventMessage instance.
334
+ # For direct packing, you need to provide all fields that are part of its `message_pack_format`.
335
+ # The `SystemEventMessage` constructor in `itch.messages` expects the raw bytes of the message body
336
+ # (excluding the common message type, stock_locate, tracking_number, and timestamp parts that are
337
+ # handled by its `__init__` if you were parsing).
338
+ # When creating from scratch for packing, it's often easier to instantiate and then set attributes.
339
+ # Let's assume SystemEventMessage can be instantiated with default or required values.
340
+ # (Note: The actual SystemEventMessage.__init__ takes raw message bytes, so direct instantiation
341
+ # for packing requires setting attributes manually if not using raw bytes for construction)
342
+
343
+ event_msg = SystemEventMessage.__new__(SystemEventMessage) # Create instance without calling __init__
344
+ event_msg.message_type = b'S' # Must be set for pack() to know its type
345
+ event_msg.stock_locate = 0 # Placeholder or actual value
346
+ event_msg.tracking_number = 0 # Placeholder or actual value
347
+ event_msg.event_code = b'O' # Example: Start of Messages
348
+
349
+ # 2. Set the timestamp.
350
+ # The `timestamp` attribute (nanoseconds since midnight) must be set.
351
+ # The `pack()` method will internally use `split_timestamp()` to get the parts.
352
+ current_nanoseconds = int(time.time() * 1e9) % (24 * 60 * 60 * int(1e9))
353
+ event_msg.timestamp = current_nanoseconds # Directly set the nanosecond timestamp
354
+
355
+ # 3. Pack the message into binary format.
356
+ # The pack() method prepends the message type and then packs stock_locate,
357
+ # tracking_number, the split timestamp, and then the message-specific fields.
358
+ packed_bytes = event_msg.pack()
359
+
360
+ # 4. The result is a bytes object
361
+ print(f"Packed {len(packed_bytes)} bytes: {packed_bytes.hex().upper()}")
362
+ print(f"Type of packed_bytes: {type(packed_bytes)}")
363
+
364
+ # Example Output (will vary based on actual timestamp and other values if not fixed):
365
+ # Packed 12 bytes: 53000000002F39580A004F
366
+ # Type of packed_bytes: <class 'bytes'>
367
+ ```
368
+ The `message_pack_format` attribute of each message class dictates how its fields are packed. Note that for messages read by the `MessageParser`, fields like `stock_locate` and `tracking_number` are prepended during parsing; when packing an object directly, ensure all fields defined in its `message_pack_format` are appropriately set.
369
+
370
+ ### Data Types in Parsed Messages
371
+
372
+ * **Strings:** Alpha fields (e.g., stock symbols, MPIDs) are initially parsed as `bytes`. The `decode()` method converts these to standard Python strings (ASCII) and typically removes any right-padding spaces used in the fixed-width ITCH fields.
373
+ * **Prices:** As mentioned under `decode_price()`, price fields are stored as raw integers in the initial message object. The `decode_price()` method or the comprehensive `decode()` method should be used to obtain correctly scaled floating-point values.
374
+ * **Timestamps:** Handled by `set_timestamp()` and `split_timestamp()` as described above, resulting in a nanosecond-precision integer for the `timestamp` attribute.
375
+ * **Decoded Objects:** The `message.decode()` method is the recommended way to get a fully processed, user-friendly representation of any message, with all fields converted to appropriate Python types (strings, floats, integers).
376
+
377
+ ## Error Handling
378
+
379
+ When parsing ITCH data, the `MessageParser` may encounter issues due to malformed data, incorrect file formats, or unexpected message types. These situations typically result in a `ValueError` being raised.
380
+
381
+ Common scenarios that can lead to a `ValueError` include:
382
+
383
+ * **Unexpected Byte:** When reading from a file or a raw byte stream, each ITCH message is expected to be prefixed by a `0x00` byte followed by a byte indicating the length of the upcoming message. If the parser encounters a byte other than `0x00` where this prefix is expected, it suggests data corruption, that the file is not a valid ITCH feed, or that the stream is out of sync.
384
+ * **Unknown Message Type:** After successfully reading the length-prefixed message, the first byte of the actual message content indicates its type (e.g., `S` for System Event, `A` for Add Order). If this byte does not correspond to one of the known ITCH 5.0 message types, the parser will raise an error.
385
+ * **Malformed Message Structure:** Even if the message type is known, errors can occur if the message's length does not match the expected length for that type, or if the internal structure cannot be unpacked correctly according to the defined format. This often points to data corruption or a non-standard message.
386
+
387
+ ### Handling Strategies
388
+
389
+ It's crucial to anticipate these errors in your application:
390
+
391
+ * **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.
392
+ ```python
393
+ try:
394
+ # ... parsing operations ...
395
+ messages = parser.read_message_from_file(itch_file)
396
+ except ValueError as e:
397
+ print(f"An error occurred during parsing: {e}")
398
+ # Log the error, problematic data chunk, or take other actions
399
+ ```
400
+ * **Logging:** When an error is caught, log the exception details. If possible, log the problematic chunk of data that caused the error. This is invaluable for debugging and understanding the nature of the data issue.
401
+ * **Application-Specific Decisions:**
402
+ * **Skip and Continue:** For some applications, it might be acceptable to log the error, skip the problematic message or data chunk, and attempt to continue parsing the rest of the stream/file. This can be useful for robustly processing large datasets where a small amount of corrupted data is tolerable.
403
+ * **Halt Processing:** In other scenarios, particularly where data integrity is paramount, any parsing error might necessitate halting the entire process and flagging the data source as invalid.
404
+
405
+ Choosing the right strategy depends on the requirements of your application and the expected quality of your ITCH data sources.
406
+
407
+ ## Contributing
408
+
409
+ Contributions are welcome! If you find a bug, have a suggestion, or want to add a feature:
410
+
411
+ 1. **Check Issues:** See if an issue for your topic already exists.
412
+ 2. **Open an Issue:** If not, open a new issue describing the bug or feature request.
413
+ 3. **Fork and Branch:** Fork the repository and create a new branch for your changes.
414
+ 4. **Implement Changes:** Make your code changes, ensuring adherence to the ITCH 5.0 specification. Add tests if applicable.
415
+ 5. **Submit Pull Request:** Open a pull request from your branch to the main repository, referencing the relevant issue.
416
+
417
+ ## License
418
+
419
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
420
+
421
+ ## References
422
+ * **Nasdaq TotalView-ITCH 5.0 Specification:** The official [documentation](https://www.nasdaqtrader.com/content/technicalsupport/specifications/dataproducts/NQTVITCHspecification.pdf) is the definitive source for protocol details.
@@ -0,0 +1,9 @@
1
+ itch/__init__.py,sha256=m8ulOH0nET4yLoKcqWJA-VjOEZldGo932t95rHOZh4w,204
2
+ itch/indicators.py,sha256=-Ed2M8I60xGQ1bIPZCGCKGb8ayT87JAnIaosfiBimXI,6542
3
+ itch/messages.py,sha256=UHr4eBTtgiLg9vO53GpciAxiAO9AD9uCu8Xz3WnfadM,61927
4
+ itch/parser.py,sha256=BOrkGsmRkcYnXSf5S9yqrwzP0jqtkH5mGCpWCeiWNTg,6155
5
+ itchfeed-1.0.3.dist-info/licenses/LICENSE,sha256=f2u79rUzh-UcYH0RN0Ph0VvVYHBkYlVxtguhKmrHqsw,1089
6
+ itchfeed-1.0.3.dist-info/METADATA,sha256=nfZbTBXUq5Ghq1xhls4fttblPNlpRGtqZth1h8lnx-4,30699
7
+ itchfeed-1.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ itchfeed-1.0.3.dist-info/top_level.txt,sha256=xwsOYShvy3gc1rfyitCTgSxBZDGG1y6bfQxkdhIGmEM,5
9
+ itchfeed-1.0.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,225 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: itchfeed
3
- Version: 1.0.2
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)
11
- Project-URL: Source Code, https://github.com/bbalouki/itch
12
- Keywords: Finance,Financial,Quantitative,Equities,Totalview-ITCH,Totalview,Nasdaq-ITCH,Nasdaq,ITCH,Data,Feed,ETFs,Funds,Trading,Investing
13
- Classifier: Development Status :: 5 - Production/Stable
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: Financial and Insurance Industry
16
- Classifier: Topic :: Office/Business :: Financial :: Investment
17
- Classifier: Programming Language :: Python :: 3
18
- Classifier: Operating System :: OS Independent
19
- Description-Content-Type: text/markdown
20
- License-File: LICENSE
21
- 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
- Dynamic: license-file
32
- Dynamic: maintainer
33
- Dynamic: project-url
34
- Dynamic: requires-dist
35
- Dynamic: summary
36
-
37
- # Nasdaq TotalView-ITCH 5.0 Parser
38
- [![PYPI Version](https://img.shields.io/pypi/v/itchfeed)](https://pypi.org/project/itchfeed/)
39
- [![PyPi status](https://img.shields.io/pypi/status/itchfeed.svg?maxAge=60)](https://pypi.python.org/pypi/itchfeed)
40
- [![Supported Python Versions](https://img.shields.io/pypi/pyversions/itchfeed)](https://pypi.org/project/itchfeed/)
41
- [![PyPI Downloads](https://static.pepy.tech/badge/itchfeed)](https://pepy.tech/projects/itchfeed)
42
- [![CodeFactor](https://www.codefactor.io/repository/github/bbalouki/itch/badge)](https://www.codefactor.io/repository/github/bbalouki/itch)
43
- [![LinkedIn](https://img.shields.io/badge/LinkedIn-grey?logo=Linkedin&logoColor=white)](https://www.linkedin.com/in/bertin-balouki-simyeli-15b17a1a6/)
44
- [![PayPal Me](https://img.shields.io/badge/PayPal%20Me-blue?logo=paypal)](https://paypal.me/bertinbalouki?country.x=SN&locale.x=en_US)
45
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
46
-
47
- A Python library for parsing binary data conforming to the Nasdaq TotalView-ITCH 5.0 protocol specification. This parser converts the raw byte stream into structured Python objects, making it easier to work with Nasdaq market data.
48
-
49
- ## Overview
50
-
51
- The Nasdaq TotalView-ITCH 5.0 protocol is a binary protocol used by Nasdaq to disseminate full order book depth, trade information, and system events for equities traded on its execution system. This parser handles the low-level details of reading the binary format, unpacking fields according to the specification, and presenting the data as intuitive Python objects.
52
-
53
- ## Features
54
-
55
- * **Parses ITCH 5.0 Binary Data:** Accurately interprets the binary message structures defined in the official specification.
56
- * **Supports All Standard Message Types:** Implements classes for all messages defined in the ITCH 5.0 specification (System Event, Stock Directory, Add Order, Trade, etc.).
57
- * **Object-Oriented Representation:** Each ITCH message type is represented by a dedicated Python class (`SystemEventMessage`, `AddOrderMessage`, etc.), inheriting from a common `MarketMessage` base class.
58
- * **Flexible Input:** Reads and parses messages from:
59
- * Binary files (`.gz` or similar).
60
- * Raw byte streams (e.g., from network sockets).
61
- * **Data Decoding:** Provides a `.decode()` method on each message object to convert it into a human-readable `dataclass` representation, handling:
62
- * Byte-to-string conversion (ASCII).
63
- * Stripping padding spaces.
64
- * Price decoding based on defined precision.
65
- * **Timestamp Handling:** Correctly reconstructs the 6-byte (48-bit) nanosecond timestamps.
66
- * **Price Handling:** Decodes fixed-point price fields into floating-point numbers based on the standard 4 or 8 decimal place precision.
67
- * **Pure Python:** Relies only on the Python standard library . No external dependencies required.
68
-
69
- ## Installation
70
-
71
- You can install this project using ``pip``
72
-
73
- 1. **Clone the repository (or download the source code):**
74
- ```bash
75
- pip install itchfeed
76
- ```
77
- 2. **Import the necessary modules** directly into your Python project:
78
- ```python
79
- from itch.parser import MessageParser
80
- from itch.messages import ModifyOrderMessage
81
- ```
82
-
83
- ## Usage
84
-
85
- ### Parsing from a Binary File
86
-
87
- This is useful for processing historical ITCH data stored in files. The `MessageParser` handles buffering efficiently.
88
-
89
- ```python
90
- from itch.parser import MessageParser
91
- from itch.messages import AddOrderMessage, TradeMessage
92
-
93
- # Initialize the parser. Optionally filter messages by type.
94
- # parser = MessageParser(message_type=b"AP") # Only parse AddOrder and NonCrossTrade messages
95
- parser = MessageParser()
96
-
97
- # Path to your ITCH 5.0 data file
98
- itch_file_path = 'path/to/your/data'
99
- # you can find sample data [here](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
100
-
101
- try:
102
- with open(itch_file_path, 'rb') as itch_file:
103
- # read_message_from_file returns a list of parsed message objects
104
- parsed_messages = parser.read_message_from_file(itch_file)
105
-
106
- print(f"Parsed {len(parsed_messages)} messages.")
107
-
108
- # Process the messages
109
- for message in parsed_messages:
110
- # Access attributes directly
111
- print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
112
-
113
- if isinstance(message, AddOrderMessage):
114
- print(f" Add Order: Ref={message.order_reference_number}, "
115
- f"Side={message.buy_sell_indicator.decode()}, "
116
- f"Shares={message.shares}, Stock={message.stock.decode().strip()}, "
117
- f"Price={message.decode_price('price')}")
118
-
119
- elif isinstance(message, TradeMessage):
120
- print(f" Trade: Match={message.match_number}")
121
- # Access specific trade type attributes...
122
-
123
- # Get a human-readable dataclass representation
124
- decoded_msg = message.decode()
125
- print(f" Decoded: {decoded_msg}")
126
-
127
- except FileNotFoundError:
128
- print(f"Error: File not found at {itch_file_path}")
129
- except Exception as e:
130
- print(f"An error occurred: {e}")
131
-
132
- ```
133
-
134
- ### Parsing from Raw Bytes
135
-
136
- This is suitable for real-time processing, such as reading from a network stream.
137
-
138
- ```python
139
- from itch.parser import MessageParser
140
- from itch.messages import AddOrderMessage
141
- from queue import Queue
142
-
143
- # Initialize the parser
144
- parser = MessageParser()
145
-
146
- # Simulate receiving a chunk of binary data (e.g., from a network socket)
147
- # This chunk contains multiple ITCH messages, each prefixed with 0x00 and length byte
148
- # Example: \x00\x0bS...\x00\x25R...\x00\x27F...
149
- raw_binary_data: bytes = b"..." # Your raw ITCH 5.0 data chunk
150
-
151
- # read_message_from_bytes returns a queue of parsed message objects
152
- message_queue: Queue = parser.read_message_from_bytes(raw_binary_data)
153
-
154
- print(f"Parsed {message_queue.qsize()} messages from the byte chunk.")
155
-
156
- # Process messages from the queue
157
- while not message_queue.empty():
158
- message = message_queue.get()
159
-
160
- print(f"Type: {message.message_type.decode()}, Timestamp: {message.timestamp}")
161
-
162
- if isinstance(message, AddOrderMessage):
163
- print(f" Add Order: Ref={message.order_reference_number}, "
164
- f"Stock={message.stock.decode().strip()}, Price={message.decode_price('price')}")
165
-
166
- # Use the decoded representation
167
- decoded_msg = message.decode(prefix="Decoded")
168
- print(f" Decoded: {decoded_msg}")
169
-
170
- ```
171
-
172
- ## Supported Message Types
173
-
174
- The parser supports the following ITCH 5.0 message types. Each message object has attributes corresponding to the fields defined in the specification. Refer to the class docstrings in `itch.messages` for detailed attribute descriptions.
175
-
176
- | Type (Byte) | Class Name | Description |
177
- | :---------- | :-------------------------------- | :----------------------------------------------- |
178
- | `S` | `SystemEventMessage` | System Event Message |
179
- | `R` | `StockDirectoryMessage` | Stock Directory Message |
180
- | `H` | `StockTradingActionMessage` | Stock Trading Action Message |
181
- | `Y` | `RegSHOMessage` | Reg SHO Short Sale Price Test Restricted Indicator |
182
- | `L` | `MarketParticipantPositionMessage`| Market Participant Position message |
183
- | `V` | `MWCBDeclineLeveMessage` | Market-Wide Circuit Breaker (MWCB) Decline Level |
184
- | `W` | `MWCBStatusMessage` | Market-Wide Circuit Breaker (MWCB) Status |
185
- | `K` | `IPOQuotingPeriodUpdateMessage` | IPO Quoting Period Update Message |
186
- | `J` | `LULDAuctionCollarMessage` | LULD Auction Collar Message |
187
- | `h` | `OperationalHaltMessage` | Operational Halt Message |
188
- | `A` | `AddOrderNoMPIAttributionMessage` | Add Order (No MPID Attribution) |
189
- | `F` | `AddOrderMPIDAttribution` | Add Order (MPID Attribution) |
190
- | `E` | `OrderExecutedMessage` | Order Executed Message |
191
- | `C` | `OrderExecutedWithPriceMessage` | Order Executed With Price Message |
192
- | `X` | `OrderCancelMessage` | Order Cancel Message |
193
- | `D` | `OrderDeleteMessage` | Order Delete Message |
194
- | `U` | `OrderReplaceMessage` | Order Replace Message |
195
- | `P` | `NonCrossTradeMessage` | Trade Message (Non-Cross) |
196
- | `Q` | `CrossTradeMessage` | Cross Trade Message |
197
- | `B` | `BrokenTradeMessage` | Broken Trade / Order Execution Message |
198
- | `I` | `NOIIMessage` | Net Order Imbalance Indicator (NOII) Message |
199
- | `N` | `RetailPriceImprovementIndicator` | Retail Price Improvement Indicator (RPII) |
200
- | `O` | `DLCRMessage` | Direct Listing with Capital Raise Message |
201
-
202
- ## Data Representation
203
-
204
- * **Base Class:** All message classes inherit from `itch.messages.MarketMessage`. This base class provides common attributes like `message_type`, `description`, `stock_locate`, `tracking_number`, and `timestamp`.
205
- * **Timestamp:** Timestamps are stored as 64-bit integers representing nanoseconds since midnight. The `set_timestamp` and `split_timestamp` methods handle the conversion from/to the 6-byte representation used in the raw messages.
206
- * **Prices:** Price fields (e.g., `price`, `execution_price`, `level1_price`) are stored as integers in the raw message objects. Use the `message.decode_price('attribute_name')` method to get the correctly scaled floating-point value (usually 4 or 8 decimal places, defined by `message.price_precision`).
207
- * **Strings:** Alpha fields are stored as `bytes`. The `.decode()` method converts these to ASCII strings and removes right-padding spaces.
208
- * **Decoded Objects:** The `message.decode()` method returns a standard Python `dataclass` instance. This provides a clean, immutable, and easily inspectable representation of the message content with correct data types (float for prices, string for text).
209
-
210
- ## Contributing
211
-
212
- Contributions are welcome! If you find a bug, have a suggestion, or want to add a feature:
213
-
214
- 1. **Check Issues:** See if an issue for your topic already exists.
215
- 2. **Open an Issue:** If not, open a new issue describing the bug or feature request.
216
- 3. **Fork and Branch:** Fork the repository and create a new branch for your changes.
217
- 4. **Implement Changes:** Make your code changes, ensuring adherence to the ITCH 5.0 specification. Add tests if applicable.
218
- 5. **Submit Pull Request:** Open a pull request from your branch to the main repository, referencing the relevant issue.
219
-
220
- ## License
221
-
222
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
223
-
224
- ## References
225
- * **Nasdaq TotalView-ITCH 5.0 Specification:** The official [documentation](https://www.nasdaqtrader.com/content/technicalsupport/specifications/dataproducts/NQTVITCHspecification.pdf) is the definitive source for protocol details.
@@ -1,9 +0,0 @@
1
- itch/__init__.py,sha256=m8ulOH0nET4yLoKcqWJA-VjOEZldGo932t95rHOZh4w,204
2
- itch/indicators.py,sha256=-Ed2M8I60xGQ1bIPZCGCKGb8ayT87JAnIaosfiBimXI,6542
3
- itch/messages.py,sha256=UHr4eBTtgiLg9vO53GpciAxiAO9AD9uCu8Xz3WnfadM,61927
4
- itch/parser.py,sha256=Hn7ixJsvflSGSwvDyK4IO8yCjEd7ctBz-JsBbK7Arl4,6126
5
- itchfeed-1.0.2.dist-info/licenses/LICENSE,sha256=f2u79rUzh-UcYH0RN0Ph0VvVYHBkYlVxtguhKmrHqsw,1089
6
- itchfeed-1.0.2.dist-info/METADATA,sha256=0IDg9F5c87rS3KCy-tHstJlYnre9BMNMkfD9004ntpY,12638
7
- itchfeed-1.0.2.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
8
- itchfeed-1.0.2.dist-info/top_level.txt,sha256=xwsOYShvy3gc1rfyitCTgSxBZDGG1y6bfQxkdhIGmEM,5
9
- itchfeed-1.0.2.dist-info/RECORD,,