Skip to content

Commit

Permalink
Add Databento statistics and imbalance schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
cjdsellers committed Mar 3, 2024
1 parent 694d22d commit ceedd7f
Show file tree
Hide file tree
Showing 10 changed files with 759 additions and 13 deletions.
1 change: 1 addition & 0 deletions nautilus_core/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions nautilus_core/adapters/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ rust_decimal_macros = { workspace = true }
tracing = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
strum = { workspace = true }
tokio = { workspace = true }
thiserror = { workspace = true }
ustr = { workspace = true }
Expand Down
93 changes: 80 additions & 13 deletions nautilus_core/adapters/src/databento/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ use nautilus_model::{
Data,
},
enums::{
AggregationSource, AggressorSide, AssetClass, BarAggregation, BookAction, InstrumentClass,
OptionKind, OrderSide, PriceType,
AggregationSource, AggressorSide, AssetClass, BarAggregation, BookAction, FromU8,
InstrumentClass, OptionKind, OrderSide, PriceType,
},
identifiers::{instrument_id::InstrumentId, trade_id::TradeId},
instruments::{
Expand All @@ -46,6 +46,11 @@ use nautilus_model::{
};
use ustr::Ustr;

use super::{
enums::{DatabentoStatisticType, DatabentoStatisticUpdateAction},
types::{DatabentoImbalance, DatabentoStatistics},
};

const BAR_SPEC_1S: BarSpecification = BarSpecification {
step: 1,
aggregation: BarAggregation::Second,
Expand Down Expand Up @@ -141,7 +146,7 @@ pub fn parse_cfi_iso10926(value: &str) -> Result<(Option<AssetClass>, Option<Ins
Ok((asset_class, instrument_class))
}

pub fn decode_min_price_increment(value: i64, currency: Currency) -> Result<Price> {
pub fn decode_price(value: i64, currency: Currency) -> Result<Price> {
match value {
0 | i64::MAX => Price::new(
10f64.powi(-i32::from(currency.precision)),
Expand All @@ -151,6 +156,20 @@ pub fn decode_min_price_increment(value: i64, currency: Currency) -> Result<Pric
}
}

pub fn decode_optional_price(value: i64, currency: Currency) -> Result<Option<Price>> {
match value {
i64::MAX => Ok(None),
_ => Ok(Some(Price::from_raw(value, currency.precision)?)),
}
}

pub fn decode_optional_quantity_i32(value: i32, currency: Currency) -> Result<Option<Quantity>> {
match value {
i32::MAX => Ok(None),
_ => Ok(Some(Quantity::new(value as f64, currency.precision)?)),
}
}

/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
Expand Down Expand Up @@ -182,7 +201,7 @@ pub fn decode_equity_v1(
None, // No ISIN available yet
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Some(Quantity::new(msg.min_lot_size_round_lot.into(), 0)?),
None, // TBD
None, // TBD
Expand Down Expand Up @@ -212,7 +231,7 @@ pub fn decode_futures_contract_v1(
msg.expiration,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -245,7 +264,7 @@ pub fn decode_futures_spread_v1(
msg.expiration,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -285,7 +304,7 @@ pub fn decode_options_contract_v1(
Price::from_raw(msg.strike_price, currency.precision)?,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -325,7 +344,7 @@ pub fn decode_options_spread_v1(
msg.expiration,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -736,7 +755,7 @@ pub fn decode_equity(
None, // No ISIN available yet
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Some(Quantity::new(msg.min_lot_size_round_lot.into(), 0)?),
None, // TBD
None, // TBD
Expand Down Expand Up @@ -766,7 +785,7 @@ pub fn decode_futures_contract(
msg.expiration,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -799,7 +818,7 @@ pub fn decode_futures_spread(
msg.expiration,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -839,7 +858,7 @@ pub fn decode_options_contract(
Price::from_raw(msg.strike_price, currency.precision)?,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand Down Expand Up @@ -879,7 +898,7 @@ pub fn decode_options_spread(
msg.expiration,
currency,
currency.precision,
decode_min_price_increment(msg.min_price_increment, currency)?,
decode_price(msg.min_price_increment, currency)?,
Quantity::new(1.0, 0)?, // TBD
Quantity::new(1.0, 0)?, // TBD
None, // TBD
Expand All @@ -890,3 +909,51 @@ pub fn decode_options_spread(
ts_init,
)
}

pub fn decode_imbalance_msg(
msg: &dbn::ImbalanceMsg,
instrument_id: InstrumentId,
ts_init: UnixNanos,
) -> anyhow::Result<DatabentoImbalance> {
DatabentoImbalance::new(
instrument_id,
Price::from_raw(msg.ref_price, 2)?,
Price::from_raw(msg.cont_book_clr_price, 2)?,
Price::from_raw(msg.auct_interest_clr_price, 2)?,
Quantity::new(msg.paired_qty as f64, 0)?,
Quantity::new(msg.total_imbalance_qty as f64, 0)?,
parse_order_side(msg.side),
msg.significant_imbalance as c_char,
msg.hd.ts_event,
msg.ts_recv,
ts_init,
)
}

pub fn decode_statistics_msg(
msg: &dbn::StatMsg,
instrument_id: InstrumentId,
ts_init: UnixNanos,
) -> anyhow::Result<DatabentoStatistics> {
let currency = Currency::USD(); // Hard coded for now
let stat_type = DatabentoStatisticType::from_u8(msg.stat_type as u8)
.expect("Invalid value for `stat_type`");
let update_action = DatabentoStatisticUpdateAction::from_u8(msg.stat_type as u8)
.expect("Invalid value for `update_action`");

DatabentoStatistics::new(
instrument_id,
stat_type,
update_action,
decode_optional_price(msg.price, currency)?,
decode_optional_quantity_i32(msg.quantity, currency)?,
msg.channel_id,
msg.stat_flags,
msg.sequence,
msg.ts_ref,
msg.ts_in_delta,
msg.hd.ts_event,
msg.ts_recv,
ts_init,
)
}
123 changes: 123 additions & 0 deletions nautilus_core/adapters/src/databento/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// -------------------------------------------------------------------------------------------------
// Copyright (C) 2015-2024 Nautech Systems Pty Ltd. All rights reserved.
// https://nautechsystems.io
//
// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------

//! Defines enumerations for the Databento integration.
use std::str::FromStr;

use nautilus_model::{enum_strum_serde, enums::FromU8};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use strum::{AsRefStr, Display, EnumIter, EnumString, FromRepr};

/// Represents a Databento statistic type.
#[repr(C)]
#[derive(
Copy,
Clone,
Debug,
Display,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
AsRefStr,
FromRepr,
EnumIter,
EnumString,
)]
#[strum(ascii_case_insensitive)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.databento")
)]
pub enum DatabentoStatisticType {
OpeningPrice = 1,
IndicativeOpeningPrice = 2,
SettlementPrice = 3,
TradingSessionLowPrice = 4,
TradingSessionHighPrice = 5,
ClearedVolume = 6,
LowestOffer = 7,
HighestBid = 8,
OpenInterest = 9,
FixingPrice = 10,
ClosePrice = 11,
NetChange = 12,
Vwap = 13,
}

impl FromU8 for DatabentoStatisticType {
fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(Self::OpeningPrice),
2 => Some(Self::IndicativeOpeningPrice),
3 => Some(Self::SettlementPrice),
4 => Some(Self::TradingSessionLowPrice),
5 => Some(Self::TradingSessionHighPrice),
6 => Some(Self::ClearedVolume),
7 => Some(Self::LowestOffer),
8 => Some(Self::HighestBid),
9 => Some(Self::OpenInterest),
10 => Some(Self::FixingPrice),
11 => Some(Self::ClosePrice),
12 => Some(Self::NetChange),
13 => Some(Self::Vwap),
_ => None,
}
}
}

/// Represents a Databento statistic update action.
#[repr(C)]
#[derive(
Copy,
Clone,
Debug,
Display,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
AsRefStr,
FromRepr,
EnumIter,
EnumString,
)]
#[strum(ascii_case_insensitive)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.databento")
)]
pub enum DatabentoStatisticUpdateAction {
Added = 1,
Deleted = 2,
}

impl FromU8 for DatabentoStatisticUpdateAction {
fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(Self::Added),
2 => Some(Self::Deleted),
_ => None,
}
}
}

enum_strum_serde!(DatabentoStatisticType);
enum_strum_serde!(DatabentoStatisticUpdateAction);
1 change: 1 addition & 0 deletions nautilus_core/adapters/src/databento/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

pub mod common;
pub mod decode;
pub mod enums;
pub mod live;
pub mod loader;
pub mod symbology;
Expand Down
Loading

0 comments on commit ceedd7f

Please sign in to comment.