6#include <arrow/io/file.h>
7#include <parquet/arrow/writer.h>
16struct ArrowExporter::Impl {
21 arrow::StringBuilder
symbol;
23 arrow::StringBuilder
side;
24 arrow::UInt64Builder
shares;
25 arrow::DoubleBuilder
price;
28 arrow::StringBuilder
extra;
29 std::uint64_t row_count {0};
30 std::string last_error;
33 template <
typename MsgType>
34 auto append_common(
const MsgType& msg) ->
void {
35 (void)
message_type.Append(std::string {msg.message_type});
42 auto append_blank_specific() ->
void {
43 (void)
symbol.AppendEmptyValue();
45 (void)
side.AppendEmptyValue();
47 (void)
price.AppendNull();
50 (void)
extra.AppendEmptyValue();
54ArrowExporter::ArrowExporter() : m_impl {std::make_unique<Impl>()} {}
55ArrowExporter::~ArrowExporter() =
default;
57auto ArrowExporter::rows() const noexcept -> std::uint64_t {
return m_impl->row_count; }
58auto ArrowExporter::error() const -> const std::
string& {
return m_impl->last_error; }
60auto ArrowExporter::append(
const Message& message) ->
void {
62 std::visit([&impl](
const auto& msg) { impl.append_common(msg); }, message);
67 std::string symbol_value;
68 bool has_reference =
false;
69 std::uint64_t reference = 0;
70 std::string side_value;
71 bool has_shares =
false;
72 std::uint64_t shares_value = 0;
73 bool has_price =
false;
74 double price_value = 0.0;
75 bool has_match =
false;
76 std::uint64_t match_value = 0;
77 std::string printable_value;
78 std::string extra_value;
80 if (
const auto* add = std::get_if<AddOrderMessage>(&message)) {
81 symbol_value =
to_string(add->stock, STOCK_LEN);
83 reference = add->order_reference_number;
84 side_value = std::string {add->buy_sell_indicator};
86 shares_value = add->shares;
89 }
else if (
const auto* add_mpid = std::get_if<AddOrderMPIDAttributionMessage>(&message)) {
90 symbol_value =
to_string(add_mpid->stock, STOCK_LEN);
92 reference = add_mpid->order_reference_number;
93 side_value = std::string {add_mpid->buy_sell_indicator};
95 shares_value = add_mpid->shares;
98 extra_value =
"mpid=" +
to_string(add_mpid->attribution, 4);
99 }
else if (
const auto* exec = std::get_if<OrderExecutedMessage>(&message)) {
100 has_reference =
true;
101 reference = exec->order_reference_number;
103 shares_value = exec->executed_shares;
105 match_value = exec->match_number;
106 }
else if (
const auto* exec_px = std::get_if<OrderExecutedWithPriceMessage>(&message)) {
107 has_reference =
true;
108 reference = exec_px->order_reference_number;
110 shares_value = exec_px->executed_shares;
114 match_value = exec_px->match_number;
115 printable_value = std::string {exec_px->printable};
116 }
else if (
const auto* cancel = std::get_if<OrderCancelMessage>(&message)) {
117 has_reference =
true;
118 reference = cancel->order_reference_number;
120 shares_value = cancel->cancelled_shares;
121 }
else if (
const auto* del = std::get_if<OrderDeleteMessage>(&message)) {
122 has_reference =
true;
123 reference = del->order_reference_number;
124 }
else if (
const auto* replace = std::get_if<OrderReplaceMessage>(&message)) {
125 has_reference =
true;
126 reference = replace->new_order_reference_number;
128 shares_value = replace->shares;
131 extra_value =
"orig=" + std::to_string(replace->original_order_reference_number);
132 }
else if (
const auto* trade = std::get_if<NonCrossTradeMessage>(&message)) {
133 symbol_value =
to_string(trade->stock, STOCK_LEN);
134 has_reference =
true;
135 reference = trade->order_reference_number;
136 side_value = std::string {trade->buy_sell_indicator};
138 shares_value = trade->shares;
142 match_value = trade->match_number;
143 }
else if (
const auto* cross = std::get_if<CrossTradeMessage>(&message)) {
144 symbol_value =
to_string(cross->stock, STOCK_LEN);
146 shares_value = cross->shares;
150 match_value = cross->match_number;
151 extra_value = std::string {
"cross="} + cross->cross_type;
152 }
else if (
const auto* event = std::get_if<SystemEventMessage>(&message)) {
153 extra_value = std::string {
"event="} +
event->event_code;
154 }
else if (
const auto* directory = std::get_if<StockDirectoryMessage>(&message)) {
155 symbol_value =
to_string(directory->stock, STOCK_LEN);
158 (void)impl.symbol.Append(symbol_value);
160 (void)impl.reference_number.Append(reference);
162 (void)impl.reference_number.AppendNull();
164 (void)impl.side.Append(side_value);
166 (void)impl.shares.Append(shares_value);
168 (void)impl.shares.AppendNull();
171 (void)impl.price.Append(price_value);
173 (void)impl.price.AppendNull();
176 (void)impl.match_number.Append(match_value);
178 (void)impl.match_number.AppendNull();
180 (void)impl.printable.Append(printable_value);
181 (void)impl.extra.Append(extra_value);
185auto ArrowExporter::write_parquet(
const std::string& path) ->
bool {
186 Impl& impl = *m_impl;
189 [&impl](arrow::ArrayBuilder& builder, std::shared_ptr<arrow::Array>& out) ->
bool {
190 const arrow::Status status = builder.Finish(&out);
192 impl.last_error = status.ToString();
198 std::shared_ptr<arrow::Array> columns[12];
199 arrow::ArrayBuilder* builders[12] = {
203 &impl.tracking_number,
205 &impl.reference_number,
213 for (
int index = 0; index < 12; ++index) {
214 if (!finish(*builders[index], columns[index])) {
219 auto schema = arrow::schema({
220 arrow::field(
"message_type", arrow::utf8()),
221 arrow::field(
"timestamp", arrow::uint64()),
222 arrow::field(
"stock_locate", arrow::uint16()),
223 arrow::field(
"tracking_number", arrow::uint16()),
224 arrow::field(
"symbol", arrow::utf8()),
225 arrow::field(
"reference_number", arrow::uint64()),
226 arrow::field(
"side", arrow::utf8()),
227 arrow::field(
"shares", arrow::uint64()),
228 arrow::field(
"price", arrow::float64()),
229 arrow::field(
"match_number", arrow::uint64()),
230 arrow::field(
"printable", arrow::utf8()),
231 arrow::field(
"extra", arrow::utf8()),
234 std::vector<std::shared_ptr<arrow::Array>> column_vector {columns, columns + 12};
235 const auto table = arrow::Table::Make(schema, column_vector);
237 auto outfile_result = arrow::io::FileOutputStream::Open(path);
238 if (!outfile_result.ok()) {
239 impl.last_error = outfile_result.status().ToString();
242 const auto status = parquet::arrow::WriteTable(
244 arrow::default_memory_pool(),
246 impl.row_count > 0 ? impl.row_count : 1
249 impl.last_error = status.ToString();
Apache Arrow / Parquet columnar export.
constexpr auto to_double() const noexcept -> double
The price as a floating-point value (raw / 10^Decimals).
std::string reference_number
std::uint16_t tracking_number
std::uint16_t stock_locate
BasicPrice< std::uint32_t, 4 > StandardPrice
Price scale for every ITCH price field except MWCB decline levels.
auto to_string(const char *source, size_t size) -> std::string
Converts a fixed-width character array to a string, trimming trailing spaces and NUL characters.
Strongly typed, fixed-point price representation for ITCH price fields.