Main Message Types and Common Fields

First, let's identify the common message structure and fields that appear across different message types:

#![allow(unused)]
fn main() {
// Common message header fields that appear in all messages
struct MessageHeader {
    message_type: MessageType,
    stock_locate: u16,
    tracking_number: u16,
    timestamp: u64,  // Nanoseconds since midnight
}

// Enum for all possible message types
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
enum MessageType {
    SystemEvent = b'S',              // System Event Message
    StockDirectory = b'R',           // Stock Directory Message
    StockTradingAction = b'H',       // Stock Trading Action Message
    RegShoRestriction = b'Y',        // Reg SHO Short Sale Price Test Restricted Indicator
    MarketParticipantPosition = b'L', // Market Participant Position
    MwcbDeclineLevel = b'V',         // MWCB Decline Level Message
    MwcbStatus = b'W',               // MWCB Status Message
    IpoQuotingPeriodUpdate = b'K',   // IPO Quoting Period Update Message
    LuldAuctionCollar = b'J',        // LULD Auction Collar
    OperationalHalt = b'h',          // Operational Halt
    AddOrderNoMpid = b'A',           // Add Order – No MPID Attribution
    AddOrderMpid = b'F',             // Add Order with MPID Attribution
    OrderExecuted = b'E',            // Order Executed Message
    OrderExecutedWithPrice = b'C',   // Order Executed With Price Message
    OrderCancel = b'X',              // Order Cancel Message
    OrderDelete = b'D',              // Order Delete Message
    OrderReplace = b'U',             // Order Replace Message
    Trade = b'P',                    // Trade Message (Non-Cross)
    CrossTrade = b'Q',               // Cross Trade Message
    BrokenTrade = b'B',              // Broken Trade Message
    Noii = b'I',                     // Net Order Imbalance Indicator (NOII) Message
    RpiiIndicator = b'N',            // Retail Price Improvement Indicator (RPII)
    DirectListingWithCapitalRaise = b'O', // Direct Listing with Capital Raise Price Discovery Message
}
}

System Event Message

#![allow(unused)]
fn main() {
struct SystemEventMessage {
    header: MessageHeader,
    event_code: SystemEventCode,
}

enum SystemEventCode {
    StartOfMessages = b'O',
    StartOfSystemHours = b'S',
    StartOfMarketHours = b'Q',
    EndOfMarketHours = b'M',
    EndOfSystemHours = b'E',
    EndOfMessages = b'C',
}
}

Stock Directory Message

#![allow(unused)]
fn main() {
struct StockDirectoryMessage {
    header: MessageHeader,
    stock: [u8; 8],                  // Stock symbol, right padded with spaces
    market_category: MarketCategory,
    financial_status_indicator: FinancialStatusIndicator,
    round_lot_size: u32,
    round_lots_only: RoundLotsOnly,
    issue_classification: u8,         // Alpha
    issue_sub_type: [u8; 2],          // Alpha
    authenticity: Authenticity,
    short_sale_threshold_indicator: ShortSaleThresholdIndicator,
    ipo_flag: IpoFlag,
    luld_reference_price_tier: LuldReferencePriceTier,
    etp_flag: EtpFlag,
    etp_leverage_factor: u32,
    inverse_indicator: InverseIndicator,
}

enum MarketCategory {
    NasdaqGlobalSelectMarket = b'Q',
    NasdaqGlobalMarket = b'G',
    NasdaqCapitalMarket = b'S',
    Nyse = b'N',
    NyseAmerican = b'A',
    NyseArca = b'P',
    BatsZExchange = b'Z',
    InvestorsExchange = b'V',
    NotAvailable = b' ',
}

enum FinancialStatusIndicator {
    Deficient = b'D',
    Delinquent = b'E',
    Bankrupt = b'Q',
    Suspended = b'S',
    DeficientAndBankrupt = b'G',
    DeficientAndDelinquent = b'H',
    DelinquentAndBankrupt = b'J',
    DeficientDelinquentAndBankrupt = b'K',
    CreationsRedemptionsSuspended = b'C',
    Normal = b'N',
    NotAvailable = b' ',
}

enum RoundLotsOnly {
    RoundLotsOnly = b'Y',
    NoRestrictions = b'N',
}

enum Authenticity {
    LiveProduction = b'P',
    Test = b'T',
}

enum ShortSaleThresholdIndicator {
    Restricted = b'Y',
    NotRestricted = b'N',
    NotAvailable = b' ',
}

enum IpoFlag {
    SetUpAsNewIpo = b'Y',
    NotNewIpo = b'N',
    NotAvailable = b' ',
}

enum LuldReferencePriceTier {
    Tier1 = b'1',
    Tier2 = b'2',
    NotAvailable = b' ',
}

enum EtpFlag {
    Etp = b'Y',
    NotEtp = b'N',
    NotAvailable = b' ',
}

enum InverseIndicator {
    InverseEtp = b'Y',
    NotInverseEtp = b'N',
}
}

Stock Trading Action Message

#![allow(unused)]
fn main() {
struct StockTradingActionMessage {
    header: MessageHeader,
    stock: [u8; 8],                   // Stock symbol, right padded with spaces
    trading_state: TradingState,
    reason: [u8; 4],                  // Trading Action reason
}

enum TradingState {
    Halted = b'H',
    Paused = b'P',
    QuotationOnly = b'Q',
    Trading = b'T',
}
}

Add Order Messages

#![allow(unused)]
fn main() {
struct AddOrderNoMpidMessage {
    header: MessageHeader,
    order_reference_number: u64,
    buy_sell_indicator: BuySellIndicator,
    shares: u32,
    stock: [u8; 8],                   // Stock symbol, right padded with spaces
    price: u32,                       // Price (4 decimal places)
}

struct AddOrderMpidMessage {
    header: MessageHeader,
    order_reference_number: u64,
    buy_sell_indicator: BuySellIndicator,
    shares: u32,
    stock: [u8; 8],                   // Stock symbol, right padded with spaces
    price: u32,                       // Price (4 decimal places)
    attribution: [u8; 4],             // MPID
}

enum BuySellIndicator {
    Buy = b'B',
    Sell = b'S',
}
}

Order Execute/Modify Messages

#![allow(unused)]
fn main() {
struct OrderExecutedMessage {
    header: MessageHeader,
    order_reference_number: u64,
    executed_shares: u32,
    match_number: u64,
}

struct OrderExecutedWithPriceMessage {
    header: MessageHeader,
    order_reference_number: u64,
    executed_shares: u32,
    match_number: u64,
    printable: Printable,
    execution_price: u32,             // Price (4 decimal places)
}

struct OrderCancelMessage {
    header: MessageHeader,
    order_reference_number: u64,
    cancelled_shares: u32,
}

struct OrderDeleteMessage {
    header: MessageHeader,
    order_reference_number: u64,
}

struct OrderReplaceMessage {
    header: MessageHeader,
    original_order_reference_number: u64,
    new_order_reference_number: u64,
    shares: u32,
    price: u32,                       // Price (4 decimal places)
}

enum Printable {
    NonPrintable = b'N',
    Printable = b'Y',
}
}

Trade Messages

#![allow(unused)]
fn main() {
struct TradeMessage {
    header: MessageHeader,
    order_reference_number: u64,
    buy_sell_indicator: BuySellIndicator,
    shares: u32,
    stock: [u8; 8],                   // Stock symbol, right padded with spaces
    price: u32,                       // Price (4 decimal places)
    match_number: u64,
}

struct CrossTradeMessage {
    header: MessageHeader,
    shares: u64,
    stock: [u8; 8],                   // Stock symbol, right padded with spaces
    cross_price: u32,                 // Price (4 decimal places)
    match_number: u64,
    cross_type: CrossType,
}

struct BrokenTradeMessage {
    header: MessageHeader,
    match_number: u64,
}

enum CrossType {
    NasdaqOpeningCross = b'O',
    NasdaqClosingCross = b'C',
    CrossForIpoAndHaltedPaused = b'H',
    ExtendedTradingClose = b'A',
}
}

NOII Message

#![allow(unused)]
fn main() {
struct NoiiMessage {
    header: MessageHeader,
    paired_shares: u64,
    imbalance_shares: u64,
    imbalance_direction: ImbalanceDirection,
    stock: [u8; 8],                   // Stock symbol, right padded with spaces
    far_price: u32,                   // Price (4 decimal places)
    near_price: u32,                  // Price (4 decimal places)
    current_reference_price: u32,     // Price (4 decimal places)
    cross_type: CrossType,
    price_variation_indicator: PriceVariationIndicator,
}

enum ImbalanceDirection {
    Buy = b'B',
    Sell = b'S',
    NoImbalance = b'N',
    InsufficientOrders = b'O',
    Paused = b'P',
}

enum PriceVariationIndicator {
    LessThan1Percent = b'L',
    OneToTwoPercent = b'1',
    TwoToThreePercent = b'2',
    ThreeToFourPercent = b'3',
    FourToFivePercent = b'4',
    FiveToSixPercent = b'5',
    SixToSevenPercent = b'6',
    SevenToEightPercent = b'7',
    EightToNinePercent = b'8',
    NineToTenPercent = b'9',
    TenToTwentyPercent = b'A',
    TwentyToThirtyPercent = b'B',
    ThirtyPercentOrMore = b'C',
    NotAvailable = b' ',
}
}

Main Parsing Structure

Now let's put it all together with a main parser struct:

#![allow(unused)]
fn main() {
struct NasdaqTotalViewItchParser {
    // Any state your parser needs to maintain
}

impl NasdaqTotalViewItchParser {
    fn new() -> Self {
        Self {}
    }
    
    fn parse_message(&mut self, data: &[u8]) -> Result<ParsedMessage, ParseError> {
        if data.is_empty() {
            return Err(ParseError::EmptyData);
        }
        
        // First byte is the message type
        let message_type = data[0];
        
        match message_type {
            b'S' => self.parse_system_event(data),
            b'R' => self.parse_stock_directory(data),
            b'H' => self.parse_stock_trading_action(data),
            // ... add more message types
            _ => Err(ParseError::UnknownMessageType(message_type)),
        }
    }
    
    // Individual parsing methods for each message type
    fn parse_system_event(&self, data: &[u8]) -> Result<ParsedMessage, ParseError> {
        // Implementation
    }
    
    // ... other parsing methods
}

enum ParsedMessage {
    SystemEvent(SystemEventMessage),
    StockDirectory(StockDirectoryMessage),
    StockTradingAction(StockTradingActionMessage),
    // ... other message variants
}

enum ParseError {
    EmptyData,
    UnknownMessageType(u8),
    InvalidMessageLength,
    // ... other error types
}
}

This provides a solid framework for your Rust protocol parser for the Nasdaq TotalView-ITCH format. You'll need to implement the individual parsing methods for each message type, taking into account the binary format and field alignments specified in the documentation.

Would you like me to expand on any specific message type or provide more detailed implementation for certain parts of the parser?


Approach for implementation of the parser

If you're starting from scratch and implementing a low-latency protocol parser in Rust (e.g., for HFT), verifying correctness and performance is crucial. Here’s a structured approach:


1. Define the Protocol & Expected Behavior

Before coding, fully understand the protocol you're parsing (e.g., NASDAQ ITCH, CME MDP 3.0, FIX/FAST).

  • Read the exchange specification document (e.g., NASDAQ ITCH 5.0).
  • Identify message types (e.g., orders, trades, cancellations) and their binary layouts.
  • Define test cases (valid messages, edge cases, malformed inputs).

2. Implement the Parser in Rust

Key Rust Features for Performance & Safety

  • Zero-copy parsing: Use &[u8] slices instead of allocations.
  • No heap allocations: Avoid Vec, String in hot paths; use arrayvec or bytes::Bytes.
  • Branchless code: Leverage match, unwrap_unchecked (carefully) to reduce CPU stalls.
  • SIMD optimizations: For fixed-width fields (e.g., prices), use packed_simd (or std::simd in nightly).

Example (Simplified ITCH Parser)

#![allow(unused)]
fn main() {
use bytes::Buf;

// Define message types (ITCH example)
#[derive(Debug)]
pub enum ItchMessage {
    OrderAdd { stock: [u8; 8], price: u64, qty: u32 },
    Trade { stock: [u8; 8], price: u64, qty: u32 },
    // ...
}

pub fn parse_itch(buffer: &[u8]) -> Option<ItchMessage> {
    let mut buf = bytes::Bytes::copy_from_slice(buffer);
    match buf.get_u8() {  // Message type byte
        b'A' => Some(ItchMessage::OrderAdd {
            stock: buf.copy_to_bytes(8).as_ref().try_into().unwrap(),
            price: buf.get_u64_le(),
            qty: buf.get_u32_le(),
        }),
        b'T' => Some(ItchMessage::Trade { /* ... */ }),
        _ => None,  // Unknown message
    }
}
}

3. Verify Correctness

Unit Tests

  • Test valid messages against known outputs.
  • Test edge cases: Empty messages, max values, malformed data.
#![allow(unused)]
fn main() {
#[test]
fn test_order_add_parse() {
    let msg = [b'A', b'A', b'A', b'P', b'L', 0, 0, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0x64, 0, 0, 0];
    let parsed = parse_itch(&msg).unwrap();
    assert!(matches!(parsed, ItchMessage::OrderAdd { stock: b"AAPL", price: 128, qty: 100 }));
}
}

Fuzzing

Use cargo fuzz to test robustness against random inputs:

cargo install cargo-fuzz  
cargo fuzz init  
# Write a fuzz target that feeds random bytes to the parser.

Replay Real Market Data

  • Capture real market data (e.g., NASDAQ ITCH pcap files).
  • Replay it through your parser and compare with reference implementations (e.g., exchange-provided tools).

4. Performance Analysis

Benchmarking

Use criterion for microbenchmarks:

#![allow(unused)]
fn main() {
use criterion::{criterion_group, criterion_main, Criterion};

fn bench_parse(c: &mut Criterion) {
    let msg = [b'A', b'A', b'A', b'P', b'L', /* ... */];
    c.bench_function("parse_itch", |b| b.iter(|| parse_itch(&msg)));
}

criterion_group!(benches, bench_parse);
criterion_main!(benches);
}

Run with:

cargo bench

Latency Measurement

  • Measure end-to-end parsing time (from packet arrival to parsed output).
  • Use rdtsc (cycle counters) for nanosecond precision:
    #![allow(unused)]
    fn main() {
    #[inline(always)]
    fn rdtsc() -> u64 {
        unsafe { std::arch::x86_64::_rdtsc() }
    }
    }

Profiling

  • perf (Linux):
    perf record --call-graph dwarf cargo bench
    perf report
    
  • Flamegraph: Identify hotspots.
    cargo flamegraph --bench my_benchmark
    

Key Metrics

  • Throughput: Messages parsed per second (aim for 1M+/sec in HFT).
  • Latency: 99th percentile <1µs for HFT-grade parsers.
  • CPU Cache Efficiency: Check with perf stat -e cache-misses.

5. Compare with Alternatives

  • Baseline vs. Optimized: Compare your Rust parser against a C++ reference (e.g., QuickFAST, SBE).
  • DPDK/FPGA Acceleration: If latency is still too high, consider offloading parsing to hardware.

Summary

  1. Start with specs and test cases.
  2. Implement in Rust with zero-copy, branchless code.
  3. Verify correctness with unit tests, fuzzing, and real data.
  4. Profile aggressively (perf, criterion, flamegraphs).
  5. Optimize until latency/throughput meet HFT standards.

For HFT, even 100ns saved in parsing can be the difference between profit and loss. Rust’s control over memory and lack of runtime overhead makes it a strong choice.


One week plan to build a protocol parser.

Absolutely — you can implement a solid ITCH parser in a week, especially given how much you've already done.

Here’s how I’d structure it to make fast progress, without getting stuck:


🗓️ One-Week Plan to Build a Functional ITCH Parser

Day 1–2: Core Infrastructure

  • ✅ You've already got the Rust structs and enums for all the message types — great start!
  • Next steps:
    • Set up a nom or zerocopy-based binary parser framework
    • Create a main loop that:
      • Reads the binary file or socket stream
      • Matches message types using the header byte
      • Dispatches to the appropriate parser per message type
    • Create a ParsedMessage enum that wraps each type
#![allow(unused)]
fn main() {
enum ParsedMessage {
    AddOrderNoMpid(AddOrderNoMpidMessage),
    OrderExecuted(OrderExecutedMessage),
    // etc.
}
}

Day 3–4: Real-World Sample Feed

  • Get a NASDAQ historical ITCH file (you can use TotalView-ITCH 5.0 sample files)
  • Build a replay engine that:
    • Reads one message at a time
    • Parses and prints (or logs) what it sees

Add unit tests like:

#![allow(unused)]
fn main() {
#[test]
fn test_add_order_parsing() {
    let raw: [u8; 36] = [ /* binary bytes for AddOrderNoMpid */ ];
    let msg = parse_add_order(&raw).unwrap();
    assert_eq!(msg.shares, 100);
    // ...
}
}

Day 5: In-Memory Order Book (Optional)

  • If you're up for it: implement a very basic order book using a BTreeMap<u32, Vec<Order>>
    • Insert on AddOrder
    • Remove on Cancel/Delete
    • Match on Trade

Day 6–7: Polish & Pitch

  • Add performance logging (how fast is your parser?)
  • Write a README or gig proposal:

    “Efficient binary parser for NASDAQ ITCH built in Rust, capable of parsing X msgs/sec from historical or live feeds. Pluggable design allows integration with custom order books or analytics.”


💡 Tips for Hitting the 1-Week Target

  • Focus on AddOrder, Cancel, Trade, and Execution first — the rest can follow
  • Use #[repr(packed)] or zerocopy::FromBytes for zero-allocation parsing if you're optimizing
  • You don’t need to build a full order book yet — just parse & log initially

You already did the hard part: understanding the protocol.

The rest is just writing Rust code in a clean, modular way. Want me to scaffold a minimal Rust parser framework for this so you can get coding right away?