File size: 7,396 Bytes
f86fb3b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#pragma once

#include <cstdint>
#include <span>
#include <string_view>
#include <cstring>
#include <optional>
#include <array>

namespace quant::protocol::itch50 {

// Byte swapping utilities for Big-Endian Nasdaq ITCH 5.0 wire protocol
inline uint16_t be16_to_cpu(uint16_t v) noexcept { return __builtin_bswap16(v); }
inline uint32_t be32_to_cpu(uint32_t v) noexcept { return __builtin_bswap32(v); }
inline uint64_t be64_to_cpu(uint64_t v) noexcept { return __builtin_bswap64(v); }

inline uint64_t be48_to_cpu(const uint8_t* p) noexcept {
    return (static_cast<uint64_t>(p[0]) << 40) |
           (static_cast<uint64_t>(p[1]) << 32) |
           (static_cast<uint64_t>(p[2]) << 24) |
           (static_cast<uint64_t>(p[3]) << 16) |
           (static_cast<uint64_t>(p[4]) << 8)  |
           (static_cast<uint64_t>(p[5]));
}

inline void cpu_to_be48(uint64_t v, uint8_t* p) noexcept {
    p[0] = static_cast<uint8_t>((v >> 40) & 0xFF);
    p[1] = static_cast<uint8_t>((v >> 32) & 0xFF);
    p[2] = static_cast<uint8_t>((v >> 24) & 0xFF);
    p[3] = static_cast<uint8_t>((v >> 16) & 0xFF);
    p[4] = static_cast<uint8_t>((v >> 8) & 0xFF);
    p[5] = static_cast<uint8_t>(v & 0xFF);
}

#pragma pack(push, 1)

// 1. System Event Message ('S', 12 bytes)
struct SystemEventMsg {
    char msg_type{'S'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    char event_code{'O'}; // 'O'=Start of Messages, 'S'=Start System, 'Q'=Start Market, 'M'=End Market, 'E'=End System, 'C'=End Messages
};

// 2. Stock Directory ('R', 39 bytes)
struct StockDirectoryMsg {
    char msg_type{'R'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    char stock[8]{' '};
    char market_category{'Q'};
    char financial_status{'N'};
    uint32_t round_lot_size{0};
    char round_lots_only{'N'};
    char issue_classification{'C'};
    char issue_sub_type[2]{'S', 'I'};
    char authenticity{'P'};
    char short_sale_threshold{'N'};
    char ipo_flag{'N'};
    char luld_tier{'1'};
    char etp_flag{'N'};
    uint32_t etp_leverage{0};
    char inverse_indicator{'N'};
};

// 3. Stock Trading Action ('H', 25 bytes)
struct StockTradingActionMsg {
    char msg_type{'H'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    char stock[8]{' '};
    char trading_state{'T'}; // 'H'=Halted, 'P'=Paused, 'T'=Trading
    char reserved{' '};
    char reason[4]{' ', ' ', ' ', ' '};
};

// 4. Add Order Message ('A', 36 bytes)
struct AddOrderMsg {
    char msg_type{'A'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
    char buy_sell_indicator{'B'}; // 'B'=Buy, 'S'=Sell
    uint32_t shares{0};
    char stock[8]{' '};
    uint32_t price{0}; // Price (4 decimal fixed point, scaled by 10,000)
};

// 5. Add Order with MPID ('F', 40 bytes)
struct AddOrderMPIDMsg {
    char msg_type{'F'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
    char buy_sell_indicator{'B'};
    uint32_t shares{0};
    char stock[8]{' '};
    uint32_t price{0};
    char attribution[4]{' ', ' ', ' ', ' '};
};

// 6. Order Executed ('E', 31 bytes)
struct OrderExecutedMsg {
    char msg_type{'E'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
    uint32_t executed_shares{0};
    uint64_t match_number{0};
};

// 7. Order Executed with Price ('C', 36 bytes)
struct OrderExecutedWithPriceMsg {
    char msg_type{'C'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
    uint32_t executed_shares{0};
    uint64_t match_number{0};
    char printable{'Y'};
    uint32_t execution_price{0};
};

// 8. Order Cancel ('X', 23 bytes)
struct OrderCancelMsg {
    char msg_type{'X'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
    uint32_t canceled_shares{0};
};

// 9. Order Delete ('D', 19 bytes)
struct OrderDeleteMsg {
    char msg_type{'D'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
};

// 10. Order Replace ('U', 35 bytes)
struct OrderReplaceMsg {
    char msg_type{'U'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t orig_order_ref_num{0};
    uint64_t new_order_ref_num{0};
    uint32_t shares{0};
    uint32_t price{0};
};

// 11. Trade Message Non-Cross ('P', 44 bytes)
struct TradeMsg {
    char msg_type{'P'};
    uint16_t stock_locate{0};
    uint16_t tracking_num{0};
    uint8_t timestamp[6]{0};
    uint64_t order_ref_num{0};
    char buy_sell_indicator{'B'};
    uint32_t shares{0};
    char stock[8]{' '};
    uint32_t price{0};
    uint64_t match_number{0};
};

// 12. Snapshot Header for state recovery ('Z', 26 bytes)
struct SnapshotHeaderMsg {
    char msg_type{'Z'};
    uint16_t stock_locate{0};
    uint64_t sequence_num{0};
    char stock[8]{' '};
    uint32_t bid_levels_count{0};
    uint32_t ask_levels_count{0};
};

#pragma pack(pop)

// Decoded C++ Friendly In-Memory Structs
struct DecodedAddOrder {
    uint16_t stock_locate;
    uint64_t timestamp_ns;
    uint64_t order_ref_num;
    char side; // 'B' or 'S'
    uint32_t shares;
    std::string_view symbol;
    double price;
};

struct DecodedOrderExecuted {
    uint16_t stock_locate;
    uint64_t timestamp_ns;
    uint64_t order_ref_num;
    uint32_t executed_shares;
    uint64_t match_number;
};

struct DecodedOrderCancel {
    uint16_t stock_locate;
    uint64_t timestamp_ns;
    uint64_t order_ref_num;
    uint32_t canceled_shares;
};

struct DecodedOrderReplace {
    uint16_t stock_locate;
    uint64_t timestamp_ns;
    uint64_t orig_order_ref_num;
    uint64_t new_order_ref_num;
    uint32_t shares;
    double price;
};

class ITCH50Decoder {
public:
    static std::string_view decode_symbol(const char stock[8]) noexcept;

    static bool decode_add_order(std::span<const uint8_t> buffer, DecodedAddOrder& out) noexcept;
    static bool decode_order_executed(std::span<const uint8_t> buffer, DecodedOrderExecuted& out) noexcept;
    static bool decode_order_cancel(std::span<const uint8_t> buffer, DecodedOrderCancel& out) noexcept;
    static bool decode_order_replace(std::span<const uint8_t> buffer, DecodedOrderReplace& out) noexcept;

    // Fast message length lookup
    static constexpr size_t message_length(char msg_type) noexcept {
        switch (msg_type) {
            case 'S': return sizeof(SystemEventMsg);
            case 'R': return sizeof(StockDirectoryMsg);
            case 'H': return sizeof(StockTradingActionMsg);
            case 'A': return sizeof(AddOrderMsg);
            case 'F': return sizeof(AddOrderMPIDMsg);
            case 'E': return sizeof(OrderExecutedMsg);
            case 'C': return sizeof(OrderExecutedWithPriceMsg);
            case 'X': return sizeof(OrderCancelMsg);
            case 'D': return sizeof(OrderDeleteMsg);
            case 'U': return sizeof(OrderReplaceMsg);
            case 'P': return sizeof(TradeMsg);
            case 'Z': return sizeof(SnapshotHeaderMsg);
            default: return 0;
        }
    }
};

} // namespace quant::protocol::itch50