Skip to content

Commit 9aeef86

Browse files
committed
ADD: Add fixed price helper class
1 parent 53533b6 commit 9aeef86

File tree

7 files changed

+102
-49
lines changed

7 files changed

+102
-49
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Added `SystemMsg` and `ErrorMsg` records for use in live data
66
- Added `strike_price`, `strike_price_currency`, and `instrument_class` to `InstrumentDefMsg`
77
- Renamed `BatchJob.cost` to `cost_usd` and value now expressed as US dollars
8+
- Added `FixedPx` helper class for formatting fixed prices
89
- Added `instrument_class`, `strike_price`, and `strike_price_currency` to definition schema
910
- Added additional `condition` variants for `DatasetConditionDetail` (degraded, pending, missing)
1011
- Added additional member `last_modified_date` to `DatasetConditionDetail` Added `has_mixed_schema`, `has_mixed_stype_in`, and `ts_out` to `Metadata` to support live data

cmake/SourcesAndHeaders.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set(headers
77
include/databento/dbn_file_store.hpp
88
include/databento/enums.hpp
99
include/databento/exceptions.hpp
10+
include/databento/fixed_price.hpp
1011
include/databento/flag_set.hpp
1112
include/databento/historical.hpp
1213
include/databento/ireadable.hpp
@@ -36,6 +37,7 @@ set(sources
3637
src/enums.cpp
3738
src/exceptions.cpp
3839
src/dbn_file_store.cpp
40+
src/fixed_price.cpp
3941
src/historical.cpp
4042
src/live.cpp
4143
src/live_blocking.cpp

include/databento/constants.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace databento {
77
static constexpr auto kApiVersion = 0;
88
static constexpr auto kApiVersionStr = "0";
99
static constexpr auto kApiKeyLength = 32;
10+
// The decimal scaler of fixed prices.
11+
static constexpr std::int64_t kFixedPriceScale = 1000000000;
1012
// The sentinel value for a null or undefined price.
1113
static constexpr auto kUndefPrice = std::numeric_limits<std::int64_t>::max();
1214
// The sentinel value for a null or undefined order size.

include/databento/fixed_price.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <sstream>
5+
#include <string>
6+
7+
#include "databento/constants.hpp"
8+
9+
namespace databento {
10+
// A fixed-precision price.
11+
struct FixPx {
12+
bool IsUndefined() const { return val == databento::kUndefPrice; }
13+
14+
std::int64_t val;
15+
};
16+
17+
std::ostream& operator<<(std::ostream& stream, FixPx fix_px);
18+
19+
// Convert a fixed-precision price to a formatted string.
20+
inline std::string PxToString(std::int64_t px) {
21+
std::ostringstream ss;
22+
ss << FixPx{px};
23+
return ss.str();
24+
}
25+
} // namespace databento

src/fixed_price.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include "databento/fixed_price.hpp"
2+
3+
#include <iomanip>
4+
5+
namespace databento {
6+
std::ostream& operator<<(std::ostream& stream, FixPx fix_px) {
7+
if (fix_px.IsUndefined()) {
8+
stream << "kUndefPrice";
9+
return stream;
10+
}
11+
const bool price_neg = (fix_px.val < 0);
12+
const int64_t fixed_price_abs = price_neg ? -fix_px.val : fix_px.val;
13+
const int64_t price_integer = fixed_price_abs / kFixedPriceScale;
14+
const int64_t price_fraction = fixed_price_abs % kFixedPriceScale;
15+
if (price_neg) {
16+
stream << '-';
17+
}
18+
stream << price_integer << '.' << std::setw(9) << std::setfill('0')
19+
<< price_fraction;
20+
return stream;
21+
}
22+
} // namespace databento

src/record.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "databento/enums.hpp"
66
#include "databento/exceptions.hpp" // InvalidArgumentError
7+
#include "databento/fixed_price.hpp"
78
#include "stream_op_helper.hpp"
89

910
using databento::Record;
@@ -194,7 +195,7 @@ std::ostream& operator<<(std::ostream& stream, const Mbp1Msg& mbp_msg) {
194195
.SetSpacer("\n ")
195196
.Build()
196197
.AddField("hd", mbp_msg.hd)
197-
.AddField("price", mbp_msg.price)
198+
.AddField("price", FixPx{mbp_msg.price})
198199
.AddField("size", mbp_msg.size)
199200
.AddField("action", mbp_msg.action)
200201
.AddField("side", mbp_msg.side)
@@ -219,7 +220,7 @@ std::ostream& operator<<(std::ostream& stream, const Mbp10Msg& mbp_msg) {
219220
.SetSpacer("\n ")
220221
.Build()
221222
.AddField("hd", mbp_msg.hd)
222-
.AddField("price", mbp_msg.price)
223+
.AddField("price", FixPx{mbp_msg.price})
223224
.AddField("size", mbp_msg.size)
224225
.AddField("action", mbp_msg.action)
225226
.AddField("side", mbp_msg.side)
@@ -255,7 +256,7 @@ std::ostream& operator<<(std::ostream& stream, const MboMsg& mbo_msg) {
255256
.Build()
256257
.AddField("hd", mbo_msg.hd)
257258
.AddField("order_id", mbo_msg.order_id)
258-
.AddField("price", mbo_msg.price)
259+
.AddField("price", FixPx{mbo_msg.price})
259260
.AddField("size", mbo_msg.size)
260261
.AddField("flags", mbo_msg.flags)
261262
.AddField("channel_id", mbo_msg.channel_id)
@@ -272,8 +273,8 @@ std::ostream& operator<<(std::ostream& stream, const BidAskPair& ba_pair) {
272273
.SetSpacer(" ")
273274
.SetTypeName("BidAskPair")
274275
.Build()
275-
.AddField("bid_px", ba_pair.bid_px)
276-
.AddField("ask_px", ba_pair.ask_px)
276+
.AddField("bid_px", FixPx{ba_pair.bid_px})
277+
.AddField("ask_px", FixPx{ba_pair.ask_px})
277278
.AddField("bid_sz", ba_pair.bid_sz)
278279
.AddField("ask_sz", ba_pair.ask_sz)
279280
.AddField("bid_ct", ba_pair.bid_ct)
@@ -289,7 +290,7 @@ std::ostream& operator<<(std::ostream& stream, const TradeMsg& trade_msg) {
289290
.SetTypeName("TradeMsg")
290291
.Build()
291292
.AddField("hd", trade_msg.hd)
292-
.AddField("price", trade_msg.price)
293+
.AddField("price", FixPx{trade_msg.price})
293294
.AddField("size", trade_msg.size)
294295
.AddField("action", trade_msg.action)
295296
.AddField("side", trade_msg.side)
@@ -309,10 +310,10 @@ std::ostream& operator<<(std::ostream& stream, const OhlcvMsg& ohlcv_msg) {
309310
.SetTypeName("OhlcvMsg")
310311
.Build()
311312
.AddField("hd", ohlcv_msg.hd)
312-
.AddField("open", ohlcv_msg.open)
313-
.AddField("high", ohlcv_msg.high)
314-
.AddField("low", ohlcv_msg.low)
315-
.AddField("close", ohlcv_msg.close)
313+
.AddField("open", FixPx{ohlcv_msg.open})
314+
.AddField("high", FixPx{ohlcv_msg.high})
315+
.AddField("low", FixPx{ohlcv_msg.low})
316+
.AddField("close", FixPx{ohlcv_msg.close})
316317
.AddField("volume", ohlcv_msg.volume)
317318
.Finish();
318319
}
@@ -327,18 +328,18 @@ std::ostream& operator<<(std::ostream& stream,
327328
.Build()
328329
.AddField("hd", instr_def_msg.hd)
329330
.AddField("ts_recv", instr_def_msg.ts_recv)
330-
.AddField("min_price_increment", instr_def_msg.min_price_increment)
331+
.AddField("min_price_increment", FixPx{instr_def_msg.min_price_increment})
331332
.AddField("display_factor", instr_def_msg.display_factor)
332333
.AddField("expiration", instr_def_msg.expiration)
333334
.AddField("activation", instr_def_msg.activation)
334-
.AddField("high_limit_price", instr_def_msg.high_limit_price)
335-
.AddField("low_limit_price", instr_def_msg.low_limit_price)
336-
.AddField("max_price_variation", instr_def_msg.max_price_variation)
335+
.AddField("high_limit_price", FixPx{instr_def_msg.high_limit_price})
336+
.AddField("low_limit_price", FixPx{instr_def_msg.low_limit_price})
337+
.AddField("max_price_variation", FixPx{instr_def_msg.max_price_variation})
337338
.AddField("trading_reference_price",
338-
instr_def_msg.trading_reference_price)
339+
FixPx{instr_def_msg.trading_reference_price})
339340
.AddField("unit_of_measure_qty", instr_def_msg.unit_of_measure_qty)
340341
.AddField("min_price_increment_amount",
341-
instr_def_msg.min_price_increment_amount)
342+
FixPx{instr_def_msg.min_price_increment_amount})
342343
.AddField("price_ratio", instr_def_msg.price_ratio)
343344
.AddField("inst_attrib_value", instr_def_msg.inst_attrib_value)
344345
.AddField("underlying_id", instr_def_msg.underlying_id)
@@ -373,7 +374,7 @@ std::ostream& operator<<(std::ostream& stream,
373374
.AddField("underlying", instr_def_msg.underlying)
374375
.AddField("strike_price_currency", instr_def_msg.strike_price_currency)
375376
.AddField("instrument_class", instr_def_msg.instrument_class)
376-
.AddField("strike_price", instr_def_msg.strike_price)
377+
.AddField("strike_price", FixPx{instr_def_msg.strike_price})
377378
.AddField("match_algorithm", instr_def_msg.match_algorithm)
378379
.AddField("md_security_trading_status",
379380
instr_def_msg.md_security_trading_status)
@@ -406,15 +407,15 @@ std::ostream& operator<<(std::ostream& stream,
406407
.Build()
407408
.AddField("hd", imbalance_msg.hd)
408409
.AddField("ts_recv", imbalance_msg.ts_recv)
409-
.AddField("ref_price", imbalance_msg.ref_price)
410+
.AddField("ref_price", FixPx{imbalance_msg.ref_price})
410411
.AddField("auction_time", imbalance_msg.auction_time)
411-
.AddField("cont_book_clr_price", imbalance_msg.cont_book_clr_price)
412+
.AddField("cont_book_clr_price", FixPx{imbalance_msg.cont_book_clr_price})
412413
.AddField("auct_interest_clr_price",
413-
imbalance_msg.auct_interest_clr_price)
414-
.AddField("ssr_filling_price", imbalance_msg.ssr_filling_price)
415-
.AddField("ind_match_price", imbalance_msg.ind_match_price)
416-
.AddField("upper_collar", imbalance_msg.upper_collar)
417-
.AddField("lower_collar", imbalance_msg.lower_collar)
414+
FixPx{imbalance_msg.auct_interest_clr_price})
415+
.AddField("ssr_filling_price", FixPx{imbalance_msg.ssr_filling_price})
416+
.AddField("ind_match_price", FixPx{imbalance_msg.ind_match_price})
417+
.AddField("upper_collar", FixPx{imbalance_msg.upper_collar})
418+
.AddField("lower_collar", FixPx{imbalance_msg.lower_collar})
418419
.AddField("paired_qty", imbalance_msg.paired_qty)
419420
.AddField("total_imbalance_qty", imbalance_msg.total_imbalance_qty)
420421
.AddField("market_imbalance_qty", imbalance_msg.market_imbalance_qty)

test/src/record_tests.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ TEST(RecordTests, TestMbp10MsgToString) {
3535
const auto res = ToString(target);
3636
ASSERT_EQ(res, R"(Mbp10Msg {
3737
hd = RecordHeader { length = 92, rtype = Mbp10, publisher_id = 1, instrument_id = 1, ts_event = 0 },
38-
price = 100000000,
38+
price = 0.100000000,
3939
size = 10,
4040
action = Add,
4141
side = Bid,
@@ -45,16 +45,16 @@ TEST(RecordTests, TestMbp10MsgToString) {
4545
ts_in_delta = 100,
4646
sequence = 50,
4747
booklevel = {
48-
BidAskPair { bid_px = 0, ask_px = 0, bid_sz = 0, ask_sz = 0, bid_ct = 0, ask_ct = 0 },
49-
BidAskPair { bid_px = 5, ask_px = 6, bid_sz = 4, ask_sz = 3, bid_ct = 2, ask_ct = 1 },
50-
BidAskPair { bid_px = 10, ask_px = 12, bid_sz = 8, ask_sz = 6, bid_ct = 4, ask_ct = 2 },
51-
BidAskPair { bid_px = 15, ask_px = 18, bid_sz = 12, ask_sz = 9, bid_ct = 6, ask_ct = 3 },
52-
BidAskPair { bid_px = 20, ask_px = 24, bid_sz = 16, ask_sz = 12, bid_ct = 8, ask_ct = 4 },
53-
BidAskPair { bid_px = 25, ask_px = 30, bid_sz = 20, ask_sz = 15, bid_ct = 10, ask_ct = 5 },
54-
BidAskPair { bid_px = 30, ask_px = 36, bid_sz = 24, ask_sz = 18, bid_ct = 12, ask_ct = 6 },
55-
BidAskPair { bid_px = 35, ask_px = 42, bid_sz = 28, ask_sz = 21, bid_ct = 14, ask_ct = 7 },
56-
BidAskPair { bid_px = 40, ask_px = 48, bid_sz = 32, ask_sz = 24, bid_ct = 16, ask_ct = 8 },
57-
BidAskPair { bid_px = 45, ask_px = 54, bid_sz = 36, ask_sz = 27, bid_ct = 18, ask_ct = 9 }
48+
BidAskPair { bid_px = 0.000000000, ask_px = 0.000000000, bid_sz = 0, ask_sz = 0, bid_ct = 0, ask_ct = 0 },
49+
BidAskPair { bid_px = 0.000000005, ask_px = 0.000000006, bid_sz = 4, ask_sz = 3, bid_ct = 2, ask_ct = 1 },
50+
BidAskPair { bid_px = 0.000000010, ask_px = 0.000000012, bid_sz = 8, ask_sz = 6, bid_ct = 4, ask_ct = 2 },
51+
BidAskPair { bid_px = 0.000000015, ask_px = 0.000000018, bid_sz = 12, ask_sz = 9, bid_ct = 6, ask_ct = 3 },
52+
BidAskPair { bid_px = 0.000000020, ask_px = 0.000000024, bid_sz = 16, ask_sz = 12, bid_ct = 8, ask_ct = 4 },
53+
BidAskPair { bid_px = 0.000000025, ask_px = 0.000000030, bid_sz = 20, ask_sz = 15, bid_ct = 10, ask_ct = 5 },
54+
BidAskPair { bid_px = 0.000000030, ask_px = 0.000000036, bid_sz = 24, ask_sz = 18, bid_ct = 12, ask_ct = 6 },
55+
BidAskPair { bid_px = 0.000000035, ask_px = 0.000000042, bid_sz = 28, ask_sz = 21, bid_ct = 14, ask_ct = 7 },
56+
BidAskPair { bid_px = 0.000000040, ask_px = 0.000000048, bid_sz = 32, ask_sz = 24, bid_ct = 16, ask_ct = 8 },
57+
BidAskPair { bid_px = 0.000000045, ask_px = 0.000000054, bid_sz = 36, ask_sz = 27, bid_ct = 18, ask_ct = 9 }
5858
}
5959
})");
6060
}
@@ -132,16 +132,16 @@ TEST(RecordTests, TestInstrumentDefMsgToString) {
132132
ASSERT_EQ(res, R"(InstrumentDefMsg {
133133
hd = RecordHeader { length = 90, rtype = InstrumentDef, publisher_id = 1, instrument_id = 1, ts_event = 0 },
134134
ts_recv = 0,
135-
min_price_increment = 1,
135+
min_price_increment = 0.000000001,
136136
display_factor = 2,
137137
expiration = 3,
138138
activation = 4,
139-
high_limit_price = 5,
140-
low_limit_price = 6,
141-
max_price_variation = 7,
142-
trading_reference_price = 8,
139+
high_limit_price = 0.000000005,
140+
low_limit_price = 0.000000006,
141+
max_price_variation = 0.000000007,
142+
trading_reference_price = 0.000000008,
143143
unit_of_measure_qty = 9,
144-
min_price_increment_amount = 10,
144+
min_price_increment_amount = 0.000000010,
145145
price_ratio = 11,
146146
inst_attrib_value = 12,
147147
underlying_id = 13,
@@ -176,7 +176,7 @@ TEST(RecordTests, TestInstrumentDefMsgToString) {
176176
underlying = "",
177177
strike_price_currency = "",
178178
instrument_class = Future,
179-
strike_price = 9223372036854775807,
179+
strike_price = kUndefPrice,
180180
match_algorithm = Fifo,
181181
md_security_trading_status = 33,
182182
main_fraction = 34,
@@ -224,14 +224,14 @@ TEST(RecordTests, TestImbalanceMsgToString) {
224224
ASSERT_EQ(res, R"(ImbalanceMsg {
225225
hd = RecordHeader { length = 28, rtype = Imbalance, publisher_id = 1, instrument_id = 1, ts_event = 0 },
226226
ts_recv = 0,
227-
ref_price = 1,
227+
ref_price = 0.000000001,
228228
auction_time = 0,
229-
cont_book_clr_price = 3,
230-
auct_interest_clr_price = 4,
231-
ssr_filling_price = 5,
232-
ind_match_price = 6,
233-
upper_collar = 7,
234-
lower_collar = 8,
229+
cont_book_clr_price = 0.000000003,
230+
auct_interest_clr_price = 0.000000004,
231+
ssr_filling_price = 0.000000005,
232+
ind_match_price = 0.000000006,
233+
upper_collar = 0.000000007,
234+
lower_collar = 0.000000008,
235235
paired_qty = 9,
236236
total_imbalance_qty = 10,
237237
market_imbalance_qty = 11,

0 commit comments

Comments
 (0)