Skip to content

Commit 7c059b5

Browse files
authored
VER: Release 0.27.0
2 parents c778b93 + b36445f commit 7c059b5

File tree

11 files changed

+251
-93
lines changed

11 files changed

+251
-93
lines changed

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
# Changelog
22

3+
## 0.27.0 - 2025-06-10
4+
5+
### Enhancements
6+
- Made the buffer size used by the live client when reading from the TCP socket
7+
configurable through the `LiveBuilder::buffer_size()` method
8+
- Added support for using `rustls` without pulling in OpenSSL. `reqwest` with OpenSSL is
9+
still the default
10+
- Upgraded DBN version to 0.36.0:
11+
- Added support for width, fill, and padding when formatting `pretty::Ts`
12+
- Added support for sign, precision, width, fill, and padding when formatting
13+
`pretty::Px`
14+
- Optimized pretty formatting of prices and timestamps
15+
16+
### Breaking changes
17+
- Changed type of `split_duration` to `Option<SplitDuration>` to support setting no
18+
split duration
19+
- Breaking changes from DBN:
20+
- Moved core async decoding and encoding functionality to new traits to
21+
match the sync interface and present a standardized interface
22+
- Decoding: `AsyncDecodeRecordRef` and `AsyncDecodeRecord`
23+
- Encoding: `AsyncEncodeRecord`, `AsyncEncodeRecordRef`, and
24+
`AsyncEncodeRecordTextExt`
25+
26+
### Deprecations
27+
- Deprecated `LiveClient::connect` and `LiveClient::connect_with_addr` methods in favor
28+
of using the builder so additional optional parameters can be added without a breaking
29+
change
30+
31+
### Bug fixes
32+
- Fixed bug with deserializing `null` `split_duration` in historical
33+
`batch().list_jobs()`
34+
335
## 0.26.2 - 2025-06-03
436

537
### Enhancements

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "databento"
33
authors = ["Databento <support@databento.com>"]
4-
version = "0.26.2"
4+
version = "0.27.0"
55
edition = "2021"
66
repository = "https://github.com/databento/databento-rs"
77
description = "Official Databento client library"
@@ -18,7 +18,7 @@ all-features = true
1818
rustdoc-args = ["--cfg", "docsrs"]
1919

2020
[features]
21-
default = ["historical", "live"]
21+
default = ["historical", "live", "reqwest/default-tls"]
2222
historical = [
2323
"dep:async-compression",
2424
"dep:futures",
@@ -31,14 +31,14 @@ historical = [
3131
live = ["dep:hex", "dep:sha2", "tokio/net"]
3232

3333
[dependencies]
34-
dbn = { version = "0.35.1", features = ["async", "serde"] }
34+
dbn = { version = "0.36.0", features = ["async", "serde"] }
3535

3636
async-compression = { version = "0.4", features = ["tokio", "zstd"], optional = true }
3737
# Async stream trait
3838
futures = { version = "0.3", optional = true }
3939
# Used for Live authentication
4040
hex = { version = "0.4", optional = true }
41-
reqwest = { version = "0.12", optional = true, features = ["json", "stream"] }
41+
reqwest = { version = "0.12", optional = true, features = ["json", "stream"], default-features = false }
4242
serde = { version = "1.0", optional = true, features = ["derive"] }
4343
serde_json = { version = "1.0", optional = true }
4444
# Used for Live authentication

README.md

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
The official Rust client library for [Databento](https://databento.com).
1010
The clients support fast and safe streaming of both real-time and historical market data
1111
through similar interfaces.
12+
The library is built on top of the tokio asynchronous runtime and
13+
[Databento's efficient binary encoding](https://databento.com/docs/standards-and-conventions/databento-binary-encoding).
14+
15+
You can find getting started tutorials, full API method documentation, examples with output on the
16+
[Databento docs site](https://databento.com/docs/?historical=rust&live=rust).
1217

1318
## Installation
1419

@@ -17,14 +22,70 @@ To add the crate to an existing project, run the following command:
1722
cargo add databento
1823
```
1924

25+
### Feature flags
26+
27+
- `historical`: enables the historical client for data older than 24 hours
28+
- `live`: enables the live client for real-time and intraday historical data
29+
30+
By default both features are enabled and the historical client uses OpenSSL for TLS.
31+
To use `rustls`, disable default features for both the databento crate and [reqwest](https://github.com/seanmonstar/reqwest).
32+
```toml
33+
databento = { features = ["historical"], default-features = false }
34+
reqwest = { features = ["rustls-tls"], default-features = false }
35+
```
36+
2037
## Usage
2138

39+
### Historical
40+
41+
Here is a simple program that fetches 10 minutes worth of historical trades for E-mini S&P 500 futures from CME Globex:
42+
```rust no_run
43+
use std::error::Error;
44+
45+
use databento::{
46+
dbn::{decode::DbnMetadata, Dataset, SType, Schema, TradeMsg},
47+
historical::timeseries::GetRangeParams,
48+
HistoricalClient,
49+
};
50+
use time::macros::{date, datetime};
51+
52+
#[tokio::main]
53+
async fn main() -> Result<(), Box<dyn Error>> {
54+
let mut client = HistoricalClient::builder().key_from_env()?.build()?;
55+
let mut decoder = client
56+
.timeseries()
57+
.get_range(
58+
&GetRangeParams::builder()
59+
.dataset(Dataset::GlbxMdp3)
60+
.date_time_range((
61+
datetime!(2022-06-10 14:30 UTC),
62+
datetime!(2022-06-10 14:40 UTC),
63+
))
64+
.symbols("ES.FUT")
65+
.stype_in(SType::Parent)
66+
.schema(Schema::Trades)
67+
.build(),
68+
)
69+
.await?;
70+
let symbol_map = decoder
71+
.metadata()
72+
.symbol_map_for_date(date!(2022 - 06 - 10))?;
73+
while let Some(trade) = decoder.decode_record::<TradeMsg>().await? {
74+
let symbol = &symbol_map[trade];
75+
println!("Received trade for {symbol}: {trade:?}");
76+
}
77+
Ok(())
78+
}
79+
```
80+
81+
To run this program, set the `DATABENTO_API_KEY` environment variable with an API key and run `cargo bin --example historical`.
82+
2283
### Live
2384

2485
Real-time and intraday replay is provided through the Live clients.
25-
Here is a simple program that fetches the next ES mini futures trade:
86+
Here is a simple program that fetches the next E-mini S&P 500 futures trade:
2687

27-
```rust
88+
```rust no_run
2889
use std::error::Error;
2990

3091
use databento::{
@@ -65,54 +126,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
65126
Ok(())
66127
}
67128
```
68-
To run this program, set the `DATABENTO_API_KEY` environment variable with an API key and run `cargo run --example historical`
69-
70-
### Historical
71-
72-
Here is a simple program that fetches 10 minutes worth of historical trades for the entire CME Globex market:
73-
```rust
74-
use std::error::Error;
75-
76-
use databento::{
77-
dbn::{Schema, TradeMsg},
78-
historical::timeseries::GetRangeParams,
79-
HistoricalClient, Symbols,
80-
};
81-
use time::macros::{date, datetime};
82-
83-
#[tokio::main]
84-
async fn main() -> Result<(), Box<dyn Error>> {
85-
let mut client = HistoricalClient::builder().key_from_env()?.build()?;
86-
let mut decoder = client
87-
.timeseries()
88-
.get_range(
89-
&GetRangeParams::builder()
90-
.dataset("GLBX.MDP3")
91-
.date_time_range((
92-
datetime!(2022-06-10 14:30 UTC),
93-
datetime!(2022-06-10 14:40 UTC),
94-
))
95-
.symbols(Symbols::All)
96-
.schema(Schema::Trades)
97-
.build(),
98-
)
99-
.await?;
100-
let symbol_map = decoder
101-
.metadata()
102-
.symbol_map_for_date(date!(2022 - 06 - 10))?;
103-
while let Some(trade) = decoder.decode_record::<TradeMsg>().await? {
104-
let symbol = &symbol_map[trade];
105-
println!("Received trade for {symbol}: {trade:?}");
106-
}
107-
Ok(())
108-
}
109-
```
110-
111-
To run this program, set the `DATABENTO_API_KEY` environment variable with an API key and run `cargo bin --example live`.
112-
113-
## Documentation
114129

115-
You can find more detailed examples and the full API documentation on the [Databento docs site](https://databento.com/docs/quickstart?historical=rust&live=rust).
130+
To run this program, set the `DATABENTO_API_KEY` environment variable with an API key and run `cargo run --example live`
116131

117132
## License
118133

examples/historical.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
use std::error::Error;
33

44
use databento::{
5-
dbn::{Schema, TradeMsg},
5+
dbn::{decode::DbnMetadata, Dataset, SType, Schema, TradeMsg},
66
historical::timeseries::GetRangeParams,
7-
HistoricalClient, Symbols,
7+
HistoricalClient,
88
};
99
use time::macros::{date, datetime};
1010

@@ -15,12 +15,13 @@ async fn main() -> Result<(), Box<dyn Error>> {
1515
.timeseries()
1616
.get_range(
1717
&GetRangeParams::builder()
18-
.dataset("GLBX.MDP3")
18+
.dataset(Dataset::GlbxMdp3)
1919
.date_time_range((
2020
datetime!(2022-06-10 14:30 UTC),
2121
datetime!(2022-06-10 14:40 UTC),
2222
))
23-
.symbols(Symbols::All)
23+
.symbols("ES.FUT")
24+
.stype_in(SType::Parent)
2425
.schema(Schema::Trades)
2526
.build(),
2627
)

examples/split_symbols.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use anyhow::Context;
66
use async_compression::tokio::write::ZstdEncoder;
77
use databento::{
88
dbn::{
9-
decode::AsyncDbnDecoder, encode::AsyncDbnEncoder, InstrumentDefMsg, Metadata, Schema,
10-
SymbolIndex,
9+
decode::{AsyncDbnDecoder, DbnMetadata},
10+
encode::{AsyncDbnEncoder, AsyncEncodeRecord, AsyncEncodeRecordRef},
11+
InstrumentDefMsg, Metadata, Schema, SymbolIndex,
1112
},
1213
historical::timeseries::GetRangeParams,
1314
HistoricalClient,
@@ -55,7 +56,7 @@ async fn main() -> anyhow::Result<()> {
5556
encoders.insert(parent.clone(), encoder);
5657
};
5758
}
58-
for (parent, encoder) in encoders {
59+
for (parent, mut encoder) in encoders {
5960
if let Err(e) = encoder.shutdown().await {
6061
eprintln!("Failed to shutdown encoder for {parent}: {e:?}");
6162
}

src/historical/batch.rs

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ impl BatchClient<'_> {
5151
("pretty_ts", params.pretty_ts.to_string()),
5252
("map_symbols", params.map_symbols.to_string()),
5353
("split_symbols", params.split_symbols.to_string()),
54-
("split_duration", params.split_duration.to_string()),
5554
("delivery", params.delivery.to_string()),
5655
("stype_in", params.stype_in.to_string()),
5756
("stype_out", params.stype_out.to_string()),
@@ -64,6 +63,9 @@ impl BatchClient<'_> {
6463
if let Some(limit) = params.limit {
6564
form.push(("limit", limit.to_string()));
6665
}
66+
if let Some(split_duration) = params.split_duration {
67+
form.push(("split_duration", split_duration.to_string()));
68+
}
6769
let builder = self.post("submit_job")?.form(&form);
6870
let resp = builder.send().await?;
6971
handle_response(resp).await
@@ -270,10 +272,11 @@ pub struct SubmitJobParams {
270272
/// If `true`, files will be split by raw symbol. Cannot be requested with [`Symbols::All`].
271273
#[builder(default)]
272274
pub split_symbols: bool,
273-
/// The maximum time duration before batched data is split into multiple files.
274-
/// Defaults to [`Day`](SplitDuration::Day).
275-
#[builder(default)]
276-
pub split_duration: SplitDuration,
275+
/// The maximum time duration before batched data is split into multiple
276+
/// files. If `None` the data will not be split by time. Defaults to
277+
/// [`Day`](SplitDuration::Day).
278+
#[builder(default = Some(SplitDuration::default()))]
279+
pub split_duration: Option<SplitDuration>,
277280
/// The optional maximum size (in bytes) of each batched data file before being split.
278281
/// Must be an integer between 1e9 and 10e9 inclusive (1GB - 10GB). Defaults to `None`.
279282
#[builder(default, setter(strip_option))]
@@ -339,7 +342,7 @@ pub struct BatchJob {
339342
pub split_symbols: bool,
340343
/// The maximum time interval for an individual file before splitting into multiple
341344
/// files.
342-
pub split_duration: SplitDuration,
345+
pub split_duration: Option<SplitDuration>,
343346
/// The maximum size for an individual file before splitting into multiple files.
344347
pub split_size: Option<NonZeroU64>,
345348
/// The delivery mechanism of the batch data.
@@ -689,6 +692,41 @@ mod tests {
689692
"ts_process_start": "2023-07-19 23:01:04.000000+00:00",
690693
"ts_process_done": null,
691694
"ts_expiration": null
695+
},
696+
{
697+
"id": "XNAS-20250602-5KM3HL5BUW",
698+
"user_id": "AA89XSlBV",
699+
"bill_id": null,
700+
"cost_usd": 0.0,
701+
"dataset": "XNAS.ITCH",
702+
"symbols": "MSFT",
703+
"stype_in": "raw_symbol",
704+
"stype_out": "instrument_id",
705+
"schema": "trades",
706+
"start": "2022-06-10T12:30:00.000000000Z",
707+
"end": "2022-06-10T14:00:00.000000000Z",
708+
"limit": 1000,
709+
"encoding": "csv",
710+
"compression": null,
711+
"pretty_px": false,
712+
"pretty_ts": false,
713+
"map_symbols": true,
714+
"split_symbols": false,
715+
"split_duration": null,
716+
"split_size": null,
717+
"packaging": null,
718+
"delivery": "download",
719+
"record_count": 1000,
720+
"billed_size": 48000,
721+
"actual_size": 94000,
722+
"package_size": 97690,
723+
"state": "done",
724+
"ts_received": "2025-06-02T15:51:19.251582000Z",
725+
"ts_queued": "2025-06-02T15:51:20.997673000Z",
726+
"ts_process_start": "2025-06-02T15:51:45.312317000Z",
727+
"ts_process_done": "2025-06-02T15:51:46.324860000Z",
728+
"ts_expiration": "2025-07-02T16:00:00.000000000Z",
729+
"progress": 100
692730
}])),
693731
)
694732
.mount(&mock_server)
@@ -699,8 +737,8 @@ mod tests {
699737
HistoricalGateway::Bo1,
700738
)?;
701739
let job_descs = target.batch().list_jobs(&ListJobsParams::default()).await?;
702-
assert_eq!(job_descs.len(), 1);
703-
let job_desc = &job_descs[0];
740+
assert_eq!(job_descs.len(), 2);
741+
let mut job_desc = &job_descs[0];
704742
assert_eq!(
705743
job_desc.ts_queued.unwrap(),
706744
datetime!(2023-07-19 23:00:08.095538123 UTC)
@@ -713,6 +751,26 @@ mod tests {
713751
assert!(job_desc.pretty_px);
714752
assert!(!job_desc.pretty_ts);
715753
assert!(job_desc.map_symbols);
754+
assert_eq!(job_desc.split_duration, Some(SplitDuration::Day));
755+
756+
job_desc = &job_descs[1];
757+
assert_eq!(
758+
job_desc.ts_queued.unwrap(),
759+
datetime!(2025-06-02 15:51:20.997673000 UTC)
760+
);
761+
assert_eq!(
762+
job_desc.ts_process_start.unwrap(),
763+
datetime!(2025-06-02 15:51:45.312317000 UTC)
764+
);
765+
assert_eq!(job_desc.start, datetime!(2022-06-10 12:30:00.000000000 UTC));
766+
assert_eq!(job_desc.end, datetime!(2022-06-10 14:00:00.000000000 UTC));
767+
assert_eq!(job_desc.encoding, Encoding::Csv);
768+
assert!(!job_desc.pretty_px);
769+
assert!(!job_desc.pretty_ts);
770+
assert!(job_desc.map_symbols);
771+
assert!(!job_desc.split_symbols);
772+
assert_eq!(job_desc.split_duration, None);
773+
716774
Ok(())
717775
}
718776

0 commit comments

Comments
 (0)