Skip to content

Commit d702901

Browse files
committed
ADD: Add Imbalance support to C++ client
1 parent f657f5f commit d702901

File tree

6 files changed

+179
-15
lines changed

6 files changed

+179
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

33
## 0.6.0 - TBD
4+
- Added support for imbalance schema
45
- Changed `Historical::BatchDownload` to return the paths of the downloaded files
56

67
## 0.5.0 - 2023-03-13

include/databento/enums.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum class Schema : std::uint16_t {
3131
Definition = 9,
3232
Statistics = 10,
3333
Status = 11,
34+
Imbalance = 12,
3435
};
3536

3637
// Represents a data output encoding.
@@ -105,6 +106,7 @@ enum RType : std::uint8_t {
105106
Ohlcv1H = 0x22,
106107
Ohlcv1D = 0x23,
107108
InstrumentDef = 0x13,
109+
Imbalance = 0x14,
108110
Error = 0x15,
109111
SymbolMapping = 0x16,
110112
Mbo = 0xA0,

include/databento/record.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
namespace databento {
1414
// Common data for all Databento Records.
1515
struct RecordHeader {
16+
static constexpr std::size_t kLengthMultiplier = 4;
17+
1618
// The length of the message in 32-bit words.
1719
std::uint8_t length;
1820
// The record type.
@@ -232,6 +234,37 @@ struct InstrumentDefMsg {
232234
static_assert(sizeof(InstrumentDefMsg) == 360,
233235
"InstrumentDefMsg size must match C");
234236

237+
// An order imbalance message.
238+
struct ImbalanceMsg {
239+
static bool HasRType(RType rtype) { return rtype == RType::Imbalance; }
240+
241+
RecordHeader hd;
242+
UnixNanos ts_recv;
243+
std::int64_t ref_price;
244+
UnixNanos auction_time;
245+
std::int64_t cont_book_clr_price;
246+
std::int64_t auct_interest_clr_price;
247+
std::int64_t ssr_filling_price;
248+
std::int64_t ind_match_price;
249+
std::int64_t upper_collar;
250+
std::int64_t lower_collar;
251+
std::uint32_t paired_qty;
252+
std::uint32_t total_imbalance_qty;
253+
std::uint32_t market_imbalance_qty;
254+
std::uint32_t unpaired_qty;
255+
char auction_type;
256+
Side side;
257+
std::uint8_t auction_status;
258+
std::uint8_t freeze_status;
259+
std::uint8_t num_extensions;
260+
Side unpaired_side;
261+
char significant_imbalance;
262+
// padding for alignment
263+
std::array<char, 1> dummy[1];
264+
};
265+
266+
static_assert(sizeof(ImbalanceMsg) == 112, "ImbalanceMsg size must match C");
267+
235268
// An error message from the Live Subscription Gateway (LSG). This will never
236269
// be present in historical data.
237270
struct ErrorMsg {
@@ -335,6 +368,11 @@ inline bool operator!=(const InstrumentDefMsg& lhs,
335368
return !(lhs == rhs);
336369
}
337370

371+
bool operator==(const ImbalanceMsg& lhs, const ImbalanceMsg& rhs);
372+
inline bool operator!=(const ImbalanceMsg& lhs, const ImbalanceMsg& rhs) {
373+
return !(lhs == rhs);
374+
}
375+
338376
inline bool operator==(const ErrorMsg& lhs, const ErrorMsg& rhs) {
339377
return lhs.hd == rhs.hd && lhs.err == rhs.err;
340378
}
@@ -366,6 +404,9 @@ std::ostream& operator<<(std::ostream& stream, const OhlcvMsg& ohlcv_msg);
366404
std::string ToString(const InstrumentDefMsg& instr_def_msg);
367405
std::ostream& operator<<(std::ostream& stream,
368406
const InstrumentDefMsg& instr_def_msg);
407+
std::string ToString(const ImbalanceMsg& imbalance_msg);
408+
std::ostream& operator<<(std::ostream& stream,
409+
const ImbalanceMsg& imbalance_msg);
369410
std::string ToString(const ErrorMsg& err_msg);
370411
std::ostream& operator<<(std::ostream& stream, const ErrorMsg& err_msg);
371412
std::string ToString(const SymbolMappingMsg& symbol_mapping_msg);

src/enums.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const char* ToString(Schema schema) {
5353
case Schema::Definition: {
5454
return "definition";
5555
}
56+
case Schema::Imbalance: {
57+
return "imbalance";
58+
}
5659
case Schema::Statistics: {
5760
return "statistics";
5861
}
@@ -250,6 +253,9 @@ const char* ToString(RType rtype) {
250253
case RType::InstrumentDef: {
251254
return "InstrumentDef";
252255
}
256+
case RType::Imbalance: {
257+
return "Imbalance";
258+
}
253259
case RType::Mbo: {
254260
return "Mbo";
255261
}
@@ -396,6 +402,9 @@ Schema FromString(const std::string& str) {
396402
if (str == "definition") {
397403
return Schema::Definition;
398404
}
405+
if (str == "imbalance") {
406+
return Schema::Imbalance;
407+
}
399408
if (str == "statistics") {
400409
return Schema::Statistics;
401410
}

src/record.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ using databento::RecordHeader;
1111
using databento::RType;
1212

1313
std::size_t RecordHeader::Size() const {
14-
return static_cast<size_t>(length) * 4;
14+
return static_cast<size_t>(length) * kLengthMultiplier;
1515
}
1616

1717
std::size_t Record::Size() const { return record_->Size(); }
@@ -151,6 +151,30 @@ bool databento::operator==(const InstrumentDefMsg& lhs,
151151
lhs.tick_rule == rhs.tick_rule;
152152
}
153153

154+
using databento::ImbalanceMsg;
155+
156+
bool operator==(const ImbalanceMsg& lhs, const ImbalanceMsg& rhs) {
157+
return lhs.hd == rhs.hd && lhs.ts_recv == rhs.ts_recv &&
158+
lhs.ref_price == rhs.ref_price &&
159+
lhs.auction_time == rhs.auction_time &&
160+
lhs.cont_book_clr_price == rhs.cont_book_clr_price &&
161+
lhs.auct_interest_clr_price == rhs.auct_interest_clr_price &&
162+
lhs.ssr_filling_price == rhs.ssr_filling_price &&
163+
lhs.ind_match_price == rhs.ind_match_price &&
164+
lhs.upper_collar == rhs.upper_collar &&
165+
lhs.lower_collar == rhs.lower_collar &&
166+
lhs.paired_qty == rhs.paired_qty &&
167+
lhs.total_imbalance_qty == rhs.total_imbalance_qty &&
168+
lhs.market_imbalance_qty == rhs.market_imbalance_qty &&
169+
lhs.unpaired_qty == rhs.unpaired_qty &&
170+
lhs.auction_type == rhs.auction_type && lhs.side == rhs.side &&
171+
lhs.auction_status == rhs.auction_status &&
172+
lhs.freeze_status == rhs.freeze_status &&
173+
lhs.num_extensions == rhs.num_extensions &&
174+
lhs.unpaired_side == rhs.unpaired_side &&
175+
lhs.significant_imbalance == rhs.significant_imbalance;
176+
}
177+
154178
namespace databento {
155179
namespace detail {
156180
template <>
@@ -368,6 +392,40 @@ std::ostream& operator<<(std::ostream& stream,
368392
.Finish();
369393
}
370394

395+
std::string ToString(const ImbalanceMsg& imbalance_msg) {
396+
return MakeString(imbalance_msg);
397+
}
398+
std::ostream& operator<<(std::ostream& stream,
399+
const ImbalanceMsg& imbalance_msg) {
400+
return StreamOpBuilder{stream}
401+
.SetSpacer("\n ")
402+
.SetTypeName("ImbalanceMsg")
403+
.Build()
404+
.AddField("hd", imbalance_msg.hd)
405+
.AddField("ts_recv", imbalance_msg.ts_recv)
406+
.AddField("ref_price", imbalance_msg.ref_price)
407+
.AddField("auction_time", imbalance_msg.auction_time)
408+
.AddField("cont_book_clr_price", imbalance_msg.cont_book_clr_price)
409+
.AddField("auct_interest_clr_price",
410+
imbalance_msg.auct_interest_clr_price)
411+
.AddField("ssr_filling_price", imbalance_msg.ssr_filling_price)
412+
.AddField("ind_match_price", imbalance_msg.ind_match_price)
413+
.AddField("upper_collar", imbalance_msg.upper_collar)
414+
.AddField("lower_collar", imbalance_msg.lower_collar)
415+
.AddField("paired_qty", imbalance_msg.paired_qty)
416+
.AddField("total_imbalance_qty", imbalance_msg.total_imbalance_qty)
417+
.AddField("market_imbalance_qty", imbalance_msg.market_imbalance_qty)
418+
.AddField("unpaired_qty", imbalance_msg.unpaired_qty)
419+
.AddField("auction_type", imbalance_msg.auction_type)
420+
.AddField("side", imbalance_msg.side)
421+
.AddField("auction_status", imbalance_msg.auction_status)
422+
.AddField("freeze_status", imbalance_msg.freeze_status)
423+
.AddField("num_extensions", imbalance_msg.num_extensions)
424+
.AddField("unpaired_side", imbalance_msg.unpaired_side)
425+
.AddField("significant_imbalance", imbalance_msg.significant_imbalance)
426+
.Finish();
427+
}
428+
371429
std::string ToString(const ErrorMsg& err_msg) { return MakeString(err_msg); }
372430
std::ostream& operator<<(std::ostream& stream, const ErrorMsg& err_msg) {
373431
return StreamOpBuilder{stream}

test/src/record_tests.cpp

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@
99
namespace databento {
1010
namespace test {
1111
TEST(RecordTests, TestMbp10MsgToString) {
12-
Mbp10Msg target{RecordHeader{50, RType::Mbp10, 1, 1, UnixNanos{}},
13-
100000000,
14-
10,
15-
Action::Add,
16-
Side::Bid,
17-
{},
18-
0,
19-
UnixNanos{},
20-
TimeDeltaNanos{100},
21-
50,
22-
{}};
12+
Mbp10Msg target{
13+
RecordHeader{sizeof(Mbp10Msg) / RecordHeader::kLengthMultiplier,
14+
RType::Mbp10, 1, 1, UnixNanos{}},
15+
100000000,
16+
10,
17+
Action::Add,
18+
Side::Bid,
19+
{},
20+
0,
21+
UnixNanos{},
22+
TimeDeltaNanos{100},
23+
50,
24+
{}};
2325
for (std::uint32_t i = 0; i < 10; ++i) {
2426
target.booklevel[i].ask_ct = i;
2527
target.booklevel[i].bid_ct = i * 2;
@@ -30,7 +32,7 @@ TEST(RecordTests, TestMbp10MsgToString) {
3032
}
3133
const auto res = ToString(target);
3234
ASSERT_EQ(res, R"(Mbp10Msg {
33-
hd = RecordHeader { length = 50, rtype = Mbp10, publisher_id = 1, product_id = 1, ts_event = 0 },
35+
hd = RecordHeader { length = 92, rtype = Mbp10, publisher_id = 1, product_id = 1, ts_event = 0 },
3436
price = 100000000,
3537
size = 10,
3638
action = Add,
@@ -57,8 +59,8 @@ TEST(RecordTests, TestMbp10MsgToString) {
5759

5860
TEST(RecordTests, TestInstrumentDefMsgToString) {
5961
const InstrumentDefMsg target{
60-
RecordHeader{sizeof(InstrumentDefMsg) / 4, RType::InstrumentDef, 1, 1,
61-
UnixNanos{}},
62+
RecordHeader{sizeof(InstrumentDefMsg) / RecordHeader::kLengthMultiplier,
63+
RType::InstrumentDef, 1, 1, UnixNanos{}},
6264
UnixNanos{},
6365
1,
6466
2,
@@ -185,5 +187,56 @@ TEST(RecordTests, TestInstrumentDefMsgToString) {
185187
tick_rule = 44
186188
})");
187189
}
190+
191+
TEST(RecordTests, TestImbalanceMsgToString) {
192+
const ImbalanceMsg target{
193+
RecordHeader{sizeof(ImbalanceMsg) / RecordHeader::kLengthMultiplier,
194+
RType::Imbalance, 1, 1, UnixNanos{}},
195+
UnixNanos{},
196+
1,
197+
UnixNanos{},
198+
3,
199+
4,
200+
5,
201+
6,
202+
7,
203+
8,
204+
9,
205+
10,
206+
11,
207+
12,
208+
'A',
209+
Side::Ask,
210+
15,
211+
16,
212+
17,
213+
Side::None,
214+
'N',
215+
{}};
216+
const auto res = ToString(target);
217+
ASSERT_EQ(res, R"(ImbalanceMsg {
218+
hd = RecordHeader { length = 28, rtype = Imbalance, publisher_id = 1, product_id = 1, ts_event = 0 },
219+
ts_recv = 0,
220+
ref_price = 1,
221+
auction_time = 0,
222+
cont_book_clr_price = 3,
223+
auct_interest_clr_price = 4,
224+
ssr_filling_price = 5,
225+
ind_match_price = 6,
226+
upper_collar = 7,
227+
lower_collar = 8,
228+
paired_qty = 9,
229+
total_imbalance_qty = 10,
230+
market_imbalance_qty = 11,
231+
unpaired_qty = 12,
232+
auction_type = 'A',
233+
side = Ask,
234+
auction_status = 15,
235+
freeze_status = 16,
236+
num_extensions = 17,
237+
unpaired_side = None,
238+
significant_imbalance = 'N'
239+
})");
240+
}
188241
} // namespace test
189242
} // namespace databento

0 commit comments

Comments
 (0)