ITCHCPP 1.6.0
High-Performance NASDAQ TotalView-ITCH 5.0 Parser & Market-Data Platform
Loading...
Searching...
No Matches
encoder.cpp
Go to the documentation of this file.
1#include "itch/encoder.hpp"
2
3#include <array>
4#include <cstdint>
5#include <cstring>
6#include <variant>
7
8#include "itch/parser.hpp" // utils::from_big_endian
9
10namespace itch {
11
12namespace {
13
15class ByteWriter {
16 public:
17 // Appends an integral field of width sizeof(IntType) in big-endian order.
18 template <typename IntType>
19 auto put(IntType value) -> void {
20 const auto big = utils::from_big_endian(value);
21 std::array<std::byte, sizeof(IntType)> bytes {};
22 std::memcpy(bytes.data(), &big, sizeof(IntType));
23 m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end());
24 }
25
26 auto put_char(char value) -> void { m_bytes.push_back(static_cast<std::byte>(value)); }
27
28 // Appends a fixed-width character field exactly as stored (no trimming).
29 auto put_chars(const char* source, std::size_t size) -> void {
30 for (std::size_t index = 0; index < size; ++index) {
31 m_bytes.push_back(static_cast<std::byte>(source[index]));
32 }
33 }
34
35 // Appends the 48-bit ITCH timestamp (2-byte high, 4-byte low), big-endian.
36 auto put_timestamp(std::uint64_t timestamp) -> void {
37 constexpr int LOWER_SHIFT = 32;
38 put<std::uint16_t>(static_cast<std::uint16_t>(timestamp >> LOWER_SHIFT));
39 put<std::uint32_t>(static_cast<std::uint32_t>(timestamp & 0xFFFFFFFFULL));
40 }
41
42 [[nodiscard]] auto take() -> std::vector<std::byte> { return std::move(m_bytes); }
43
44 private:
45 std::vector<std::byte> m_bytes;
46};
47
48// Writes the header common to every message: type, locate, tracking, timestamp.
49template <typename MsgType>
50auto write_header(ByteWriter& writer, const MsgType& msg) -> void {
51 writer.put_char(msg.message_type);
52 writer.put<std::uint16_t>(msg.stock_locate);
53 writer.put<std::uint16_t>(msg.tracking_number);
54 writer.put_timestamp(msg.timestamp);
55}
56
57auto write_body(ByteWriter& writer, const SystemEventMessage& msg) -> void {
58 writer.put_char(msg.event_code);
59}
60
61auto write_body(ByteWriter& writer, const StockDirectoryMessage& msg) -> void {
62 writer.put_chars(msg.stock, STOCK_LEN);
63 writer.put_char(msg.market_category);
64 writer.put_char(msg.financial_status_indicator);
65 writer.put<std::uint32_t>(msg.round_lot_size);
66 writer.put_char(msg.round_lots_only);
67 writer.put_char(msg.issue_classification);
68 writer.put_chars(msg.issue_sub_type, 2);
69 writer.put_char(msg.authenticity);
70 writer.put_char(msg.short_sale_threshold_indicator);
71 writer.put_char(msg.ipo_flag);
72 writer.put_char(msg.luld_ref);
73 writer.put_char(msg.etp_flag);
74 writer.put<std::uint32_t>(msg.etp_leverage_factor);
75 writer.put_char(msg.inverse_indicator);
76}
77
78auto write_body(ByteWriter& writer, const StockTradingActionMessage& msg) -> void {
79 writer.put_chars(msg.stock, STOCK_LEN);
80 writer.put_char(msg.trading_state);
81 writer.put_char(msg.reserved);
82 writer.put_chars(msg.reason, 4);
83}
84
85auto write_body(ByteWriter& writer, const RegSHOMessage& msg) -> void {
86 writer.put_chars(msg.stock, STOCK_LEN);
87 writer.put_char(msg.reg_sho_action);
88}
89
90auto write_body(ByteWriter& writer, const MarketParticipantPositionMessage& msg) -> void {
91 writer.put_chars(msg.mpid, 4);
92 writer.put_chars(msg.stock, STOCK_LEN);
93 writer.put_char(msg.primary_market_maker);
94 writer.put_char(msg.market_maker_mode);
95 writer.put_char(msg.market_participant_state);
96}
97
98auto write_body(ByteWriter& writer, const MWCBDeclineLevelMessage& msg) -> void {
99 writer.put<std::uint64_t>(msg.level1);
100 writer.put<std::uint64_t>(msg.level2);
101 writer.put<std::uint64_t>(msg.level3);
102}
103
104auto write_body(ByteWriter& writer, const MWCBStatusMessage& msg) -> void {
105 writer.put_char(msg.breached_level);
106}
107
108auto write_body(ByteWriter& writer, const IPOQuotingPeriodUpdateMessage& msg) -> void {
109 writer.put_chars(msg.stock, STOCK_LEN);
110 writer.put<std::uint32_t>(msg.ipo_quotation_release_time);
111 writer.put_char(msg.ipo_quotation_release_qualifier);
112 writer.put<std::uint32_t>(msg.ipo_price);
113}
114
115auto write_body(ByteWriter& writer, const LULDAuctionCollarMessage& msg) -> void {
116 writer.put_chars(msg.stock, STOCK_LEN);
117 writer.put<std::uint32_t>(msg.auction_collar_reference_price);
118 writer.put<std::uint32_t>(msg.upper_auction_collar_price);
119 writer.put<std::uint32_t>(msg.lower_auction_collar_price);
120 writer.put<std::uint32_t>(msg.auction_collar_extension);
121}
122
123auto write_body(ByteWriter& writer, const OperationalHaltMessage& msg) -> void {
124 writer.put_chars(msg.stock, STOCK_LEN);
125 writer.put_char(msg.market_code);
126 writer.put_char(msg.operational_halt_action);
127}
128
129auto write_body(ByteWriter& writer, const AddOrderMessage& msg) -> void {
130 writer.put<std::uint64_t>(msg.order_reference_number);
131 writer.put_char(msg.buy_sell_indicator);
132 writer.put<std::uint32_t>(msg.shares);
133 writer.put_chars(msg.stock, STOCK_LEN);
134 writer.put<std::uint32_t>(msg.price);
135}
136
137auto write_body(ByteWriter& writer, const AddOrderMPIDAttributionMessage& msg) -> void {
138 writer.put<std::uint64_t>(msg.order_reference_number);
139 writer.put_char(msg.buy_sell_indicator);
140 writer.put<std::uint32_t>(msg.shares);
141 writer.put_chars(msg.stock, STOCK_LEN);
142 writer.put<std::uint32_t>(msg.price);
143 writer.put_chars(msg.attribution, 4);
144}
145
146auto write_body(ByteWriter& writer, const OrderExecutedMessage& msg) -> void {
147 writer.put<std::uint64_t>(msg.order_reference_number);
148 writer.put<std::uint32_t>(msg.executed_shares);
149 writer.put<std::uint64_t>(msg.match_number);
150}
151
152auto write_body(ByteWriter& writer, const OrderExecutedWithPriceMessage& msg) -> void {
153 writer.put<std::uint64_t>(msg.order_reference_number);
154 writer.put<std::uint32_t>(msg.executed_shares);
155 writer.put<std::uint64_t>(msg.match_number);
156 writer.put_char(msg.printable);
157 writer.put<std::uint32_t>(msg.execution_price);
158}
159
160auto write_body(ByteWriter& writer, const OrderCancelMessage& msg) -> void {
161 writer.put<std::uint64_t>(msg.order_reference_number);
162 writer.put<std::uint32_t>(msg.cancelled_shares);
163}
164
165auto write_body(ByteWriter& writer, const OrderDeleteMessage& msg) -> void {
166 writer.put<std::uint64_t>(msg.order_reference_number);
167}
168
169auto write_body(ByteWriter& writer, const OrderReplaceMessage& msg) -> void {
170 writer.put<std::uint64_t>(msg.original_order_reference_number);
171 writer.put<std::uint64_t>(msg.new_order_reference_number);
172 writer.put<std::uint32_t>(msg.shares);
173 writer.put<std::uint32_t>(msg.price);
174}
175
176auto write_body(ByteWriter& writer, const NonCrossTradeMessage& msg) -> void {
177 writer.put<std::uint64_t>(msg.order_reference_number);
178 writer.put_char(msg.buy_sell_indicator);
179 writer.put<std::uint32_t>(msg.shares);
180 writer.put_chars(msg.stock, STOCK_LEN);
181 writer.put<std::uint32_t>(msg.price);
182 writer.put<std::uint64_t>(msg.match_number);
183}
184
185auto write_body(ByteWriter& writer, const CrossTradeMessage& msg) -> void {
186 writer.put<std::uint64_t>(msg.shares);
187 writer.put_chars(msg.stock, STOCK_LEN);
188 writer.put<std::uint32_t>(msg.cross_price);
189 writer.put<std::uint64_t>(msg.match_number);
190 writer.put_char(msg.cross_type);
191}
192
193auto write_body(ByteWriter& writer, const BrokenTradeMessage& msg) -> void {
194 writer.put<std::uint64_t>(msg.match_number);
195}
196
197auto write_body(ByteWriter& writer, const NOIIMessage& msg) -> void {
198 writer.put<std::uint64_t>(msg.paired_shares);
199 writer.put<std::uint64_t>(msg.imbalance_shares);
200 writer.put_char(msg.imbalance_direction);
201 writer.put_chars(msg.stock, STOCK_LEN);
202 writer.put<std::uint32_t>(msg.far_price);
203 writer.put<std::uint32_t>(msg.near_price);
204 writer.put<std::uint32_t>(msg.current_reference_price);
205 writer.put_char(msg.cross_type);
206 writer.put_char(msg.price_variation_indicator);
207}
208
209auto write_body(ByteWriter& writer, const RetailPriceImprovementIndicatorMessage& msg) -> void {
210 writer.put_chars(msg.stock, STOCK_LEN);
211 writer.put_char(msg.interest_flag);
212}
213
214auto write_body(ByteWriter& writer, const DLCRMessage& msg) -> void {
215 writer.put_chars(msg.stock, STOCK_LEN);
216 writer.put_char(msg.open_eligibility_status);
217 writer.put<std::uint32_t>(msg.minimum_allowable_price);
218 writer.put<std::uint32_t>(msg.maximum_allowable_price);
219 writer.put<std::uint32_t>(msg.near_execution_price);
220 writer.put<std::uint64_t>(msg.near_execution_time);
221 writer.put<std::uint32_t>(msg.lower_price_range_collar);
222 writer.put<std::uint32_t>(msg.upper_price_range_collar);
223}
224
225} // namespace
226
227auto encode_message(const Message& message) -> std::vector<std::byte> {
228 ByteWriter writer;
229 std::visit(
230 [&writer](const auto& concrete) {
231 write_header(writer, concrete);
232 write_body(writer, concrete);
233 },
234 message
235 );
236 return writer.take();
237}
238
239auto encode_frame(const Message& message) -> std::vector<std::byte> {
240 const std::vector<std::byte> body = encode_message(message);
241 ByteWriter writer;
242 writer.put<std::uint16_t>(static_cast<std::uint16_t>(body.size()));
243 std::vector<std::byte> frame = writer.take();
244 frame.insert(frame.end(), body.begin(), body.end());
245 return frame;
246}
247
248} // namespace itch
std::uint64_t timestamp
Definition csv_sink.cpp:16
Serializes parsed ITCH messages back to valid wire bytes.
constexpr int STOCK_LEN
Definition messages.hpp:485
std::variant< SystemEventMessage, StockDirectoryMessage, StockTradingActionMessage, RegSHOMessage, MarketParticipantPositionMessage, MWCBDeclineLevelMessage, MWCBStatusMessage, IPOQuotingPeriodUpdateMessage, LULDAuctionCollarMessage, OperationalHaltMessage, AddOrderMessage, AddOrderMPIDAttributionMessage, OrderExecutedMessage, OrderExecutedWithPriceMessage, OrderCancelMessage, OrderDeleteMessage, OrderReplaceMessage, NonCrossTradeMessage, CrossTradeMessage, BrokenTradeMessage, NOIIMessage, RetailPriceImprovementIndicatorMessage, DLCRMessage > Message
A variant able to hold any one of the ITCH 5.0 message structs.
Definition messages.hpp:483
auto encode_message(const Message &message) -> std::vector< std::byte >
Encodes a message body and header without the 2-byte length prefix.
Definition encoder.cpp:227
auto encode_frame(const Message &message) -> std::vector< std::byte >
Encodes a complete length-prefixed frame (2-byte big-endian length followed by the message bytes),...
Definition encoder.cpp:239
Public parsing interface for NASDAQ TotalView-ITCH 5.0 feeds, plus the low-level byte-unpacking utili...