|
ITCHCPP 1.6.0
High-Performance NASDAQ TotalView-ITCH 5.0 Parser & Market-Data Platform
|
A modern, high-performance C++20 library for parsing NASDAQ TotalView-ITCH 5.0 protocol data feeds. This parser is designed for maximum speed, minimal memory overhead, and type safety, making it ideal for latency-sensitive financial applications, market data analysis, and quantitative research.
📖 API documentation:.
The design of this ITCH parser is guided by three principles:
.pcap/.pcapng captures, with per-session sequence tracking and gap detection. No libpcap dependency. See Feed Ingestion.itch-tool CLI (inspect/filter/stats/convert), and native Python bindings (pybind11). See Interoperability.parse(encode(msg)) == msg), multi-venue extension seams, and Conan/vcpkg packaging. See Simulation.std::variant of dedicated, packed structs, ensuring compile-time safety.std::vector for convenience.vcpkg.The library is built on some key principles to deliver maximum performance and safety.
The parser is a fast, allocation-free, single-pass field decoder. Each message type is defined as a packed struct whose layout mirrors the ITCH wire format, and each frame is decoded in one forward pass: fields are copied out and converted from network byte order directly into the typed struct, with no intermediate buffers and no per-message heap allocation on the callback path.
Dispatch is driven by a compile-time table keyed on the one-byte message type, so selecting the right decoder is a single flat-array lookup followed by a direct, inlinable call. There is no red-black-tree lookup and no type-erased std::function indirection. The frame length declared on the wire is validated against the size the message type requires before any field is read, so a truncated or malformed frame can never cause the decoder to read into an adjacent message.
This is genuine single-pass decoding rather than a zero-copy overlay: the bytes are converted eagerly into host-order fields.
All possible ITCH messages are handled using a single, modern C++ object: itch::Message, which is a std::variant. This approach provides significant advantages over traditional designs:
The ITCH protocol specifies that all multi-byte numbers use a big-endian (network) byte order. Most modern CPUs, however, use a little-endian format.
The parser handles this discrepancy automatically. After a message is read into a struct, the library transparently converts all multi-byte fields (such as prices and quantities) from the network order to the native order of the machine. This ensures all numerical data is immediately correct and ready for use without requiring any manual conversion.
Clone the Repository
bash git clone https://github.com/bbalouki/itchcpp.git cd itchcpp
Configure with CMake This step generates the build system and automatically downloads any developer dependencies if needed.
bash cmake -S . -B build
bash cmake --build build --config Release The project includes unit tests and performance benchmarks that can be built by enabling the corresponding CMake options.
To build and run tests:
To build and run benchmarks:
This library has zero external runtime dependencies.
For development purposes, it uses two popular libraries:
These are handled automatically by Microsoft's vcpkg package manager. When you enable tests or benchmarks, You will need to install them on your system separately or install them in manifest mode.
Download some sample data here
This is the simplest approach. It reads an entire file into memory and returns a std::vector of parsed messages. This method is convenient for smaller files but may consume significant memory for large datasets.
This is the most memory-efficient way to process large files. The parser invokes your callback function for each message it finds, avoiding the need to store all messages in memory at once. For best performance, read the file into a buffer first.
You can instruct the parser to only deserialize specific message types. This provides a significant performance boost if you are only interested in a subset of the data (e.g., just trades and quotes).
This standalone example demonstrates how to use std::visit with a visitor to process different message types and print their details correctly.
Beyond simple parsing, this library provides a high-level LimitOrderBook utility that reconstructs the full order book state for a given financial instrument from an ITCH data stream. This is essential for applications requiring market depth analysis, such as algorithmic trading or market making.
The itch::LimitOrderBook class processes ITCH messages and internally manages the addition, removal, and modification of orders, giving you a complete, real-time view of the market. This example demonstrates how to parse an ITCH file and use the messages to build an order book for a specific stock (e.g., "AAPL"). After processing all messages, it prints a snapshot of the final book state.
The print() method provides a formatted snapshot of the top of the book. It displays the total volume at each price level for both bids and asks.
The raw parser assumes a concatenation of length-prefixed messages, but ITCH is delivered inside transport framing. The itch::transport module decodes the framing that actually arrives on the wire and on disk, then feeds the existing parser. Everything is implemented in-house with no libpcap dependency.
| Decoder | Header | Purpose |
|---|---|---|
MoldUdp64Decoder | itch/transport/moldudp64.hpp | UDP multicast framing for live dissemination. |
SoupBinDecoder | itch/transport/soupbintcp.hpp | TCP framing for Glimpse snapshots and recovery/replay. |
PcapReader | itch/transport/pcap.hpp | Replay a feed from a .pcap/.pcapng capture file. |
SequenceTracker | itch/transport/sequencing.hpp | Per-session sequence tracking, gap detection, recovery hooks. |
For a live or captured MoldUDP64 datagram you already have in memory, call MoldUdp64Decoder::decode_packet(span) directly; for a SoupBinTCP byte stream, push segments through SoupBinDecoder::feed(span) as they arrive.
The original LimitOrderBook reconstructs a single, pre-selected symbol. The Phase 2 itch::book::BookManager reconstructs every symbol on the feed in one pass, routing each message to that security's book by stock locate code in O(1). Each book (itch::book::L3Book) is allocation-light: orders live in a reusable object pool linked into intrusive FIFO queues, price levels are kept in flat sorted ladders, and order lookup by reference number uses a flat open-addressed map, so there is no per-order heap allocation or atomic refcount on the hot path.
For callers that touch only a few fields per message, itch/overlay.hpp provides a zero-copy alternative to the eager parser: for_each_message(buffer, cb) yields a MessageView (and typed views like AddOrderView) that decode each field lazily on access.
The header-only itch::analytics layer computes the metrics quants ask for, directly off the trade tape and book so every downstream team does not reimplement them.
| Component | Header | Provides |
|---|---|---|
BarBuilder<Clock> | analytics/bars.hpp | OHLCV bars over TimeClock, TickClock, VolumeClock. |
Vwap, Twap | analytics/vwap.hpp | Running/interval volume- and time-weighted average price. |
| spread / mid / imbalance | analytics/microstructure.hpp | Spread, mid, depth-at-level, queue imbalance, order-flow imbalance. |
ImbalanceInfo | analytics/imbalance.hpp | Decoded NOII (I) imbalance data. |
AuctionTracker | analytics/auctions.hpp | Opening/closing/halt/IPO cross reconstruction. |
Meet researchers in the tools they already use.
Output sinks. itch/io/csv_sink.hpp flattens any message stream into a wide CSV table (dependency-free). With -DITCH_WITH_ARROW=ON (the arrow vcpkg feature), itch/io/arrow_export.hpp writes Parquet for pandas/Polars/DuckDB/Spark.
**itch-tool CLI** (-DITCH_BUILD_TOOLS=ON). Inspect, filter, and convert feeds without writing code; input may be a raw ITCH stream or a .pcap/.pcapng capture (auto-detected):
Python bindings (-DITCH_BUILD_PYTHON=ON, pybind11). The itchcpp package is a faster, drop-in backend for the pure-Python itch package (PyPI: itchfeed). It mirrors that package's layout (itchcpp.messages, itchcpp.parser, itchcpp.indicators) and semantics, the same message classes with the same raw bytes/int attributes, the same MessageParser (type filter, lazy iteration, parse_file/parse_stream/parse_messages), create_message, and decode/decode_price/to_bytes helpers, so migrating only changes the import root. See itchcpp.
Replay engine (itch/replay.hpp). Drive a consumer at the feed's original cadence (or a scaled speed) for realistic backtesting:
Encoder / writer (itch/encoder.hpp). Serialize any message back to valid wire bytes, with a guaranteed parse(encode(msg)) == msg round-trip, used to synthesize streams and golden fixtures:
Multi-venue seam (itch/venue.hpp). NASDAQ TotalView-ITCH 5.0 is the only implemented venue; itch::venue::VenuePolicy (modelled by itch::venue::Nasdaq50) is the extension point for adding BX/PSX or older ITCH versions without rewriting the dispatch machinery.
Packaging. The library is consumable through vcpkg (manifest with optional python and arrow features) and Conan (conanfile.py). See CONTRIBUTING for the build options and the versioning/ABI compatibility policy.
This library supports all message types defined in the ITCH 5.0 specification. The char represents the message type on the wire.
| Type | Struct Name | Description |
|---|---|---|
S | SystemEventMessage | Signals a market or data feed handler event. |
| Type | Struct Name | Description |
|---|---|---|
R | StockDirectoryMessage | Conveys stock symbol directory information. |
H | StockTradingActionMessage | Indicates a change in trading status for a security (e.g., Halted, Trading). |
Y | RegSHORestrictionMessage | Regulation SHO short sale price test restricted indicator. |
L | MarketParticipantPositionMessage | Conveys a market participant's status (e.g., Primary Market Maker). |
V | MWCBDeclineLevelMessage | Informs of the Market-Wide Circuit Breaker (MWCB) breach points for the day. |
W | MWCBStatusMessage | Indicates that a MWCB level has been breached. |
h | OperationalHaltMessage | Indicates an operational halt for a security on a specific market center. |
| Type | Struct Name | Description |
|---|---|---|
A | AddOrderMessage | A new order has been accepted (no MPID attribution). |
F | AddOrderMPIDMessage | A new order has been accepted (with MPID attribution). |
E | OrderExecutedMessage | An order on the book was executed in part or in full. |
C | OrderExecutedWithPriceMessage | An order was executed at a price different from the display price. |
X | OrderCancelMessage | An order was partially canceled; this message contains the canceled quantity. |
D | OrderDeleteMessage | An order was canceled in its entirety and removed from the book. |
U | OrderReplaceMessage | An existing order has been replaced with a new order. |
| Type | Struct Name | Description |
|---|---|---|
P | TradeMessage | Reports a trade for a non-displayable order type. |
Q | CrossTradeMessage | Reports a cross trade (e.g., Opening, Closing, IPO Cross). |
B | BrokenTradeMessage | Reports that a previously disseminated execution has been broken. |
| Type | Struct Name | Description |
|---|---|---|
K | IPOQuotingPeriodUpdateMessage | Provides the anticipated IPO quotation release time. |
J | LULDAuctionCollarMessage | Indicates auction collar thresholds for a security in a LULD Trading Pause. |
I | NOIIMessage | Net Order Imbalance Indicator message, used for opening/closing crosses. |
N | RetailPriceImprovementIndicator | Indicates the presence of Retail Price Improvement (RPII) interest. |
O | DirectListingCapitalRaisePriceDiscovery | Disseminated for Direct Listing with Capital Raise (DLCR) securities. |
The parser is designed for high-throughput scenarios. Performance is heavily dependent on the underlying hardware (CPU speed, memory bandwidth, and I/O speed).
The numbers below were produced by benchmarks/parser_bench.cpp parsing from an in-memory buffer (file I/O excluded). They are reproducible with the setup described under How to reproduce.
| Configuration | Throughput |
|---|---|
parse(..., callback), allocation-free callback path | 2.24 GiB/s |
parse(...), collect all messages into a std::vector | 1.23 GiB/s |
‘parse(..., {'A’,'P','E','C','X'}), filtered into astd::vector` | 1.15 GiB/s |
-DCMAKE_BUILD_TYPE=Release, C++23.01302020), a ~300 MB frame-aligned slice loaded fully into memory.The collect/filter paths are slower than the callback path because they allocate and copy each parsed message into a std::vector; the callback path does neither, which is why it is the recommended interface for latency-sensitive processing.
These are produced by benchmarks/book_bench.cpp. The throughput figures below were measured on a synthetic, churn-heavy stream (adds and deletes around a moving mid across 100 symbols) on the same hardware, Clang 22 -DCMAKE_BUILD_TYPE=Release, C++23; book-rebuild throughput on real data depends heavily on the depth and churn profile of the feed.
| Configuration | Throughput |
|---|---|
BookManager::process, full multi-symbol L3 reconstruction | ~150 MiB/s |
Eager parse, touching one field per message | ~5.4 GiB/s |
Zero-copy overlay::for_each_message, touching one field per message | **~9.7 GiB/s** |
The overlay is materially faster than the eager decoder when only a few fields are read, because it never decodes the fields the caller does not touch. Reproduce with ./build/benchmarks/book_bench <itch_file>.
The output reports throughput in GiB/s for each parsing strategy.
The project uses .clang-format to enforce a consistent code style. A .clang-tidy configuration is also provided to catch common programming errors and enforce best practices. Developers contributing to the project are expected to format their code using these tools.
Contributions are welcome! Whether it's a bug report, a feature request, or a pull request, your input is valuable. Please feel free to open an issue or submit a PR.
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.