Skip to content

Commit d0b2158

Browse files
committed
ADD: Add statistics schema to C++ client
1 parent 06e7258 commit d0b2158

File tree

6 files changed

+215
-7
lines changed

6 files changed

+215
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 0.7.0 - TBD
44
- Added initial support for live data with `LiveBlocking` and `LiveThreaded` clients
5+
- Added support for statistics schema
56
- Added `SystemMsg` and `ErrorMsg` records for use in live data
67
- Added `strike_price`, `strike_price_currency`, and `instrument_class` to `InstrumentDefMsg`
78
- Renamed `BatchJob.cost` to `cost_usd` and value now expressed as US dollars
@@ -16,6 +17,7 @@
1617
- Renamed `InstrumentDefMsg::symbol` to `raw_symbol`
1718
- Renamed `SymbolMapping::native_symbol` to `raw_symbol`
1819
- Deprecated `SType::Smart` to split into `SType::Parent` and `SType::Continuous`
20+
- Changed `expiration` and `action` type to `UnixNanos`
1921
- Changed some fields to enums in `InstrumentDefMsg`
2022
- Added optional `compression` parameter to `BatchSubmitJob`
2123
- Fixed parsing of `BatchSubmitJob` response

include/databento/enums.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ enum RType : std::uint8_t {
116116
Error = 0x15,
117117
SymbolMapping = 0x16,
118118
System = 0x17,
119+
Statistics = 0x18,
119120
Mbo = 0xA0,
120121
};
121122
} // namespace rtype
@@ -194,6 +195,49 @@ enum class UserDefinedInstrument : char {
194195
Yes = 'Y',
195196
};
196197

198+
namespace stat_type {
199+
// The type of statistic contained in a StatMsg.
200+
enum StatType : std::uint16_t {
201+
// The price of the first trade of an instrument. `price` will be set.
202+
OpeningPrice = 1,
203+
// The probable price of the first trade of an instrument published during
204+
// pre-open. Both `price` and `quantity` will be set.
205+
IndicativeOpeningPrice = 2,
206+
// The settlement price of an instrument. `price` will be set and `flags`
207+
// indicate whether the price is final or preliminary and actual or
208+
// theoretical.
209+
SettlementPrice = 3,
210+
// The lowest trade price of an instrument during the trading session.
211+
// `price` will be set.
212+
TradingSessionLowPrice = 4,
213+
// The highest trade price of an instrument during the trading session.
214+
// `price` will be set.
215+
TradingSessionHighPrice = 5,
216+
// The number of contracts cleared for an instrument on the previous trading
217+
// date. `quantity` will be set.
218+
ClearedVolume = 6,
219+
// The lowest offer price for an instrument during the trading session.
220+
// `price` will be set.
221+
LowestOffer = 7,
222+
// The highest bid price for an instrument during the trading session.
223+
// `price` will be set.
224+
HighestBid = 8,
225+
// The current number of outstanding contracts of an instrument. `quantity`
226+
// will be set.
227+
OpenInterest = 9,
228+
// The volume-weighted average price (VWAP) for a fixing period. `price` will
229+
// be set.
230+
FixingPrice = 10,
231+
};
232+
} // namespace stat_type
233+
using stat_type::StatType;
234+
235+
// The type of StatMsg update.
236+
enum class StatUpdateAction : std::uint8_t {
237+
New = 1,
238+
Delete = 2,
239+
};
240+
197241
// Convert a HistoricalGateway to a URL.
198242
const char* UrlFromGateway(HistoricalGateway gateway);
199243

@@ -214,6 +258,8 @@ const char* ToString(InstrumentClass instrument_class);
214258
const char* ToString(MatchAlgorithm match_algorithm);
215259
const char* ToString(SecurityUpdateAction update_action);
216260
const char* ToString(UserDefinedInstrument user_def_instr);
261+
const char* ToString(StatType stat_type);
262+
const char* ToString(StatUpdateAction stat_update_action);
217263

218264
std::ostream& operator<<(std::ostream& out, Schema schema);
219265
std::ostream& operator<<(std::ostream& out, Encoding encoding);
@@ -233,6 +279,9 @@ std::ostream& operator<<(std::ostream& out, MatchAlgorithm match_algorithm);
233279
std::ostream& operator<<(std::ostream& out, SecurityUpdateAction update_action);
234280
std::ostream& operator<<(std::ostream& out,
235281
UserDefinedInstrument user_def_instr);
282+
std::ostream& operator<<(std::ostream& out, StatType stat_type);
283+
std::ostream& operator<<(std::ostream& out,
284+
StatUpdateAction stat_update_action);
236285

237286
template <typename T>
238287
T FromString(const std::string& str);

include/databento/record.hpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cstdint>
77
#include <cstring> // strncmp
88
#include <string>
9+
#include <tuple> // tie
910

1011
#include "databento/datetime.hpp" // UnixNanos
1112
#include "databento/enums.hpp"
@@ -171,8 +172,8 @@ struct InstrumentDefMsg {
171172
UnixNanos ts_recv;
172173
std::int64_t min_price_increment;
173174
std::int64_t display_factor;
174-
std::uint64_t expiration;
175-
std::uint64_t activation;
175+
UnixNanos expiration;
176+
UnixNanos activation;
176177
std::int64_t high_limit_price;
177178
std::int64_t low_limit_price;
178179
std::int64_t max_price_variation;
@@ -265,11 +266,33 @@ struct ImbalanceMsg {
265266
Side unpaired_side;
266267
char significant_imbalance;
267268
// padding for alignment
268-
std::array<char, 1> dummy[1];
269+
std::array<char, 1> dummy;
269270
};
270271

271272
static_assert(sizeof(ImbalanceMsg) == 112, "ImbalanceMsg size must match C");
272273

274+
/// A statistics message. A catchall for various data disseminated by
275+
/// publishers. The `stat_type` indicates the statistic contained in the
276+
/// message.
277+
struct StatMsg {
278+
static bool HasRType(RType rtype) { return rtype == RType::Statistics; }
279+
280+
RecordHeader hd;
281+
UnixNanos ts_recv;
282+
UnixNanos ts_ref;
283+
std::int64_t price;
284+
std::int32_t quantity;
285+
std::uint32_t sequence;
286+
TimeDeltaNanos ts_in_delta;
287+
StatType stat_type;
288+
std::uint16_t channel_id;
289+
StatUpdateAction update_action;
290+
std::uint8_t stat_flags;
291+
std::array<char, 6> dummy;
292+
};
293+
294+
static_assert(sizeof(StatMsg) == 64, "StatMsg size must match C");
295+
273296
// An error message from the Live Subscription Gateway (LSG). This will never
274297
// be present in historical data.
275298
struct ErrorMsg {
@@ -396,13 +419,32 @@ inline bool operator!=(const ImbalanceMsg& lhs, const ImbalanceMsg& rhs) {
396419
return !(lhs == rhs);
397420
}
398421

422+
inline bool operator==(const StatMsg& lhs, const StatMsg& rhs) {
423+
return std::tie(lhs.hd, lhs.ts_recv, lhs.ts_ref, lhs.price, lhs.quantity,
424+
lhs.sequence, lhs.ts_in_delta, lhs.stat_type, lhs.channel_id,
425+
lhs.update_action, lhs.stat_flags) ==
426+
std::tie(rhs.hd, rhs.ts_recv, rhs.ts_ref, rhs.price, rhs.quantity,
427+
rhs.sequence, rhs.ts_in_delta, rhs.stat_type, rhs.channel_id,
428+
rhs.update_action, rhs.stat_flags);
429+
}
430+
inline bool operator!=(const StatMsg& lhs, const StatMsg& rhs) {
431+
return !(lhs == rhs);
432+
}
433+
399434
inline bool operator==(const ErrorMsg& lhs, const ErrorMsg& rhs) {
400435
return lhs.hd == rhs.hd && lhs.err == rhs.err;
401436
}
402437
inline bool operator!=(const ErrorMsg& lhs, const ErrorMsg& rhs) {
403438
return !(lhs == rhs);
404439
}
405440

441+
inline bool operator==(const SystemMsg& lhs, const SystemMsg& rhs) {
442+
return lhs.hd == rhs.hd && lhs.msg == rhs.msg;
443+
}
444+
inline bool operator!=(const SystemMsg& lhs, const SystemMsg& rhs) {
445+
return !(lhs == rhs);
446+
}
447+
406448
inline bool operator==(const SymbolMappingMsg& lhs,
407449
const SymbolMappingMsg& rhs) {
408450
return lhs.hd == rhs.hd && lhs.stype_in_symbol == rhs.stype_in_symbol &&
@@ -430,8 +472,12 @@ std::ostream& operator<<(std::ostream& stream,
430472
std::string ToString(const ImbalanceMsg& imbalance_msg);
431473
std::ostream& operator<<(std::ostream& stream,
432474
const ImbalanceMsg& imbalance_msg);
475+
std::string ToString(const StatMsg& stat_msg);
476+
std::ostream& operator<<(std::ostream& stream, const StatMsg& stat_msg);
433477
std::string ToString(const ErrorMsg& err_msg);
434478
std::ostream& operator<<(std::ostream& stream, const ErrorMsg& err_msg);
479+
std::string ToString(const SystemMsg& system_msg);
480+
std::ostream& operator<<(std::ostream& stream, const SystemMsg& system_msg);
435481
std::string ToString(const SymbolMappingMsg& symbol_mapping_msg);
436482
std::ostream& operator<<(std::ostream& stream,
437483
const SymbolMappingMsg& symbol_mapping_msg);

src/enums.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ const char* ToString(RType rtype) {
280280
case RType::System: {
281281
return "System";
282282
}
283+
case RType::Statistics: {
284+
return "Statistics";
285+
}
283286
case RType::Mbo: {
284287
return "Mbo";
285288
}
@@ -430,6 +433,58 @@ const char* ToString(UserDefinedInstrument user_def_instr) {
430433
}
431434
}
432435

436+
const char* ToString(StatType stat_type) {
437+
switch (stat_type) {
438+
case StatType::OpeningPrice: {
439+
return "OpeningPrice";
440+
}
441+
case StatType::IndicativeOpeningPrice: {
442+
return "IndicativeOpeningPrice";
443+
}
444+
case StatType::SettlementPrice: {
445+
return "SettlementPrice";
446+
}
447+
case StatType::TradingSessionLowPrice: {
448+
return "TradingSessionLowPrice";
449+
}
450+
case StatType::TradingSessionHighPrice: {
451+
return "TradingSessionHighPrice";
452+
}
453+
case StatType::ClearedVolume: {
454+
return "ClearedVolume";
455+
}
456+
case StatType::LowestOffer: {
457+
return "LowestOffer";
458+
}
459+
case StatType::HighestBid: {
460+
return "HighestBid";
461+
}
462+
case StatType::OpenInterest: {
463+
return "OpenInterest";
464+
}
465+
case StatType::FixingPrice: {
466+
return "FixingPrice";
467+
}
468+
default: {
469+
return "Unknown";
470+
}
471+
}
472+
}
473+
474+
const char* ToString(StatUpdateAction stat_update_action) {
475+
switch (stat_update_action) {
476+
case StatUpdateAction::New: {
477+
return "New";
478+
}
479+
case StatUpdateAction::Delete: {
480+
return "Delete";
481+
}
482+
default: {
483+
return "Unknown";
484+
}
485+
}
486+
}
487+
433488
std::ostream& operator<<(std::ostream& out, Schema schema) {
434489
out << ToString(schema);
435490
return out;
@@ -517,6 +572,17 @@ std::ostream& operator<<(std::ostream& out,
517572
return out;
518573
}
519574

575+
std::ostream& operator<<(std::ostream& out, StatType stat_type) {
576+
out << ToString(stat_type);
577+
return out;
578+
}
579+
580+
std::ostream& operator<<(std::ostream& out,
581+
StatUpdateAction stat_update_action) {
582+
out << ToString(stat_update_action);
583+
return out;
584+
}
585+
520586
template <>
521587
Schema FromString(const std::string& str) {
522588
if (str == "mbo") {

src/record.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ std::size_t Record::SizeOfSchema(const Schema schema) {
4343
case Schema::Definition: {
4444
return sizeof(InstrumentDefMsg);
4545
}
46+
case Schema::Statistics: {
47+
return sizeof(StatMsg);
48+
}
49+
case Schema::Imbalance: {
50+
return sizeof(ImbalanceMsg);
51+
}
4652
default: {
4753
throw InvalidArgumentError{
4854
"Record::SizeOfSchema", "schema",
@@ -84,6 +90,12 @@ RType Record::RTypeFromSchema(const Schema schema) {
8490
case Schema::Definition: {
8591
return RType::InstrumentDef;
8692
}
93+
case Schema::Statistics: {
94+
return RType::Statistics;
95+
}
96+
case Schema::Imbalance: {
97+
return RType::Imbalance;
98+
}
8799
default: {
88100
throw InvalidArgumentError{
89101
"Record::RTypeFromSchema", "schema",
@@ -430,6 +442,26 @@ std::ostream& operator<<(std::ostream& stream,
430442
.Finish();
431443
}
432444

445+
std::string ToString(const StatMsg& stat_msg) { return MakeString(stat_msg); }
446+
std::ostream& operator<<(std::ostream& stream, const StatMsg& stat_msg) {
447+
return StreamOpBuilder{stream}
448+
.SetSpacer("\n ")
449+
.SetTypeName("StatMsg")
450+
.Build()
451+
.AddField("hd", stat_msg.hd)
452+
.AddField("ts_recv", stat_msg.ts_recv)
453+
.AddField("ts_ref", stat_msg.ts_ref)
454+
.AddField("price", FixPx{stat_msg.price})
455+
.AddField("quantity", stat_msg.quantity)
456+
.AddField("sequence", stat_msg.sequence)
457+
.AddField("ts_in_delta", stat_msg.ts_in_delta)
458+
.AddField("stat_type", stat_msg.stat_type)
459+
.AddField("channel_id", stat_msg.channel_id)
460+
.AddField("update_action", stat_msg.update_action)
461+
.AddField("stat_flags", stat_msg.stat_flags)
462+
.Finish();
463+
}
464+
433465
std::string ToString(const ErrorMsg& err_msg) { return MakeString(err_msg); }
434466
std::ostream& operator<<(std::ostream& stream, const ErrorMsg& err_msg) {
435467
return StreamOpBuilder{stream}
@@ -441,6 +473,19 @@ std::ostream& operator<<(std::ostream& stream, const ErrorMsg& err_msg) {
441473
.Finish();
442474
}
443475

476+
std::string ToString(const SystemMsg& system_msg) {
477+
return MakeString(system_msg);
478+
}
479+
std::ostream& operator<<(std::ostream& stream, const SystemMsg& system_msg) {
480+
return StreamOpBuilder{stream}
481+
.SetSpacer("\n ")
482+
.SetTypeName("SystemMsg")
483+
.Build()
484+
.AddField("hd", system_msg.hd)
485+
.AddField("msg", system_msg.msg)
486+
.Finish();
487+
}
488+
444489
std::string ToString(const SymbolMappingMsg& symbol_mapping_msg) {
445490
return MakeString(symbol_mapping_msg);
446491
}

test/src/record_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ TEST(RecordTests, TestInstrumentDefMsgToString) {
6666
UnixNanos{},
6767
1,
6868
2,
69-
3,
70-
4,
69+
UnixNanos{},
70+
UnixNanos{},
7171
5,
7272
6,
7373
7,
@@ -134,8 +134,8 @@ TEST(RecordTests, TestInstrumentDefMsgToString) {
134134
ts_recv = 0,
135135
min_price_increment = 0.000000001,
136136
display_factor = 2,
137-
expiration = 3,
138-
activation = 4,
137+
expiration = 0,
138+
activation = 0,
139139
high_limit_price = 0.000000005,
140140
low_limit_price = 0.000000006,
141141
max_price_variation = 0.000000007,

0 commit comments

Comments
 (0)