Skip to content

Commit

Permalink
Implement OrderBookDepth10 Arrow schema
Browse files Browse the repository at this point in the history
  • Loading branch information
cjdsellers committed Jan 3, 2024
1 parent 5f74278 commit b33dd05
Show file tree
Hide file tree
Showing 7 changed files with 767 additions and 10 deletions.
89 changes: 88 additions & 1 deletion nautilus_core/model/src/data/depth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
// limitations under the License.
// -------------------------------------------------------------------------------------------------

use std::fmt::{Display, Formatter};
use std::{
collections::HashMap,
fmt::{Display, Formatter},
};

use indexmap::IndexMap;
use nautilus_core::{serialization::Serializable, time::UnixNanos};
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -86,6 +90,89 @@ impl OrderBookDepth10 {
ts_init,
}
}

/// Returns the metadata for the type, for use with serialization formats.
pub fn get_metadata(
instrument_id: &InstrumentId,
price_precision: u8,
size_precision: u8,
) -> HashMap<String, String> {
let mut metadata = HashMap::new();
metadata.insert("instrument_id".to_string(), instrument_id.to_string());
metadata.insert("price_precision".to_string(), price_precision.to_string());
metadata.insert("size_precision".to_string(), size_precision.to_string());
metadata
}

/// Returns the field map for the type, for use with Arrow schemas.
pub fn get_fields() -> IndexMap<String, String> {
let mut metadata = IndexMap::new();
metadata.insert("bid_price_0".to_string(), "Int64".to_string());
metadata.insert("bid_price_1".to_string(), "Int64".to_string());
metadata.insert("bid_price_2".to_string(), "Int64".to_string());
metadata.insert("bid_price_3".to_string(), "Int64".to_string());
metadata.insert("bid_price_4".to_string(), "Int64".to_string());
metadata.insert("bid_price_5".to_string(), "Int64".to_string());
metadata.insert("bid_price_6".to_string(), "Int64".to_string());
metadata.insert("bid_price_7".to_string(), "Int64".to_string());
metadata.insert("bid_price_8".to_string(), "Int64".to_string());
metadata.insert("bid_price_9".to_string(), "Int64".to_string());
metadata.insert("ask_price_0".to_string(), "Int64".to_string());
metadata.insert("ask_price_1".to_string(), "Int64".to_string());
metadata.insert("ask_price_2".to_string(), "Int64".to_string());
metadata.insert("ask_price_3".to_string(), "Int64".to_string());
metadata.insert("ask_price_4".to_string(), "Int64".to_string());
metadata.insert("ask_price_5".to_string(), "Int64".to_string());
metadata.insert("ask_price_6".to_string(), "Int64".to_string());
metadata.insert("ask_price_7".to_string(), "Int64".to_string());
metadata.insert("ask_price_8".to_string(), "Int64".to_string());
metadata.insert("ask_price_9".to_string(), "Int64".to_string());
metadata.insert("bid_size_0".to_string(), "UInt64".to_string());
metadata.insert("bid_size_1".to_string(), "UInt64".to_string());
metadata.insert("bid_size_2".to_string(), "UInt64".to_string());
metadata.insert("bid_size_3".to_string(), "UInt64".to_string());
metadata.insert("bid_size_4".to_string(), "UInt64".to_string());
metadata.insert("bid_size_5".to_string(), "UInt64".to_string());
metadata.insert("bid_size_6".to_string(), "UInt64".to_string());
metadata.insert("bid_size_7".to_string(), "UInt64".to_string());
metadata.insert("bid_size_8".to_string(), "UInt64".to_string());
metadata.insert("bid_size_9".to_string(), "UInt64".to_string());
metadata.insert("ask_size_0".to_string(), "UInt64".to_string());
metadata.insert("ask_size_1".to_string(), "UInt64".to_string());
metadata.insert("ask_size_2".to_string(), "UInt64".to_string());
metadata.insert("ask_size_3".to_string(), "UInt64".to_string());
metadata.insert("ask_size_4".to_string(), "UInt64".to_string());
metadata.insert("ask_size_5".to_string(), "UInt64".to_string());
metadata.insert("ask_size_6".to_string(), "UInt64".to_string());
metadata.insert("ask_size_7".to_string(), "UInt64".to_string());
metadata.insert("ask_size_8".to_string(), "UInt64".to_string());
metadata.insert("ask_size_9".to_string(), "UInt64".to_string());
metadata.insert("bid_count_0".to_string(), "UInt32".to_string());
metadata.insert("bid_count_1".to_string(), "UInt32".to_string());
metadata.insert("bid_count_2".to_string(), "UInt32".to_string());
metadata.insert("bid_count_3".to_string(), "UInt32".to_string());
metadata.insert("bid_count_4".to_string(), "UInt32".to_string());
metadata.insert("bid_count_5".to_string(), "UInt32".to_string());
metadata.insert("bid_count_6".to_string(), "UInt32".to_string());
metadata.insert("bid_count_7".to_string(), "UInt32".to_string());
metadata.insert("bid_count_8".to_string(), "UInt32".to_string());
metadata.insert("bid_count_9".to_string(), "UInt32".to_string());
metadata.insert("ask_count_0".to_string(), "UInt32".to_string());
metadata.insert("ask_count_1".to_string(), "UInt32".to_string());
metadata.insert("ask_count_2".to_string(), "UInt32".to_string());
metadata.insert("ask_count_3".to_string(), "UInt32".to_string());
metadata.insert("ask_count_4".to_string(), "UInt32".to_string());
metadata.insert("ask_count_5".to_string(), "UInt32".to_string());
metadata.insert("ask_count_6".to_string(), "UInt32".to_string());
metadata.insert("ask_count_7".to_string(), "UInt32".to_string());
metadata.insert("ask_count_8".to_string(), "UInt32".to_string());
metadata.insert("ask_count_9".to_string(), "UInt32".to_string());
metadata.insert("flags".to_string(), "UInt8".to_string());
metadata.insert("sequence".to_string(), "UInt64".to_string());
metadata.insert("ts_event".to_string(), "UInt64".to_string());
metadata.insert("ts_init".to_string(), "UInt64".to_string());
metadata
}
}

// TODO: Exact format for Debug and Display TBD
Expand Down
80 changes: 77 additions & 3 deletions nautilus_core/model/src/python/data/depth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@
// -------------------------------------------------------------------------------------------------

use std::{
collections::hash_map::DefaultHasher,
collections::{hash_map::DefaultHasher, HashMap},
hash::{Hash, Hasher},
};

use nautilus_core::time::UnixNanos;
use pyo3::{prelude::*, pyclass::CompareOp};
use nautilus_core::{
python::{serialization::from_dict_pyo3, to_pyvalue_err},
serialization::Serializable,
time::UnixNanos,
};
use pyo3::{prelude::*, pyclass::CompareOp, types::PyDict};

use crate::{
data::{
Expand Down Expand Up @@ -130,4 +134,74 @@ impl OrderBookDepth10 {
fn py_fully_qualified_name() -> String {
format!("{}:{}", PY_MODULE_MODEL, stringify!(OrderBookDepth10))
}

/// Return a dictionary representation of the object.
#[pyo3(name = "as_dict")]
fn py_as_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
// Serialize object to JSON bytes
let json_str = serde_json::to_string(self).map_err(to_pyvalue_err)?;
// Parse JSON into a Python dictionary
let py_dict: Py<PyDict> = PyModule::import(py, "json")?
.call_method("loads", (json_str,), None)?
.extract()?;
Ok(py_dict)
}

/// Return a new object from the given dictionary representation.
#[staticmethod]
#[pyo3(name = "from_dict")]
fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
from_dict_pyo3(py, values)
}

#[staticmethod]
#[pyo3(name = "get_metadata")]
fn py_get_metadata(
instrument_id: &InstrumentId,
price_precision: u8,
size_precision: u8,
) -> PyResult<HashMap<String, String>> {
Ok(Self::get_metadata(
instrument_id,
price_precision,
size_precision,
))
}

#[staticmethod]
#[pyo3(name = "get_fields")]
fn py_get_fields(py: Python<'_>) -> PyResult<&PyDict> {
let py_dict = PyDict::new(py);
for (k, v) in Self::get_fields() {
py_dict.set_item(k, v)?;
}

Ok(py_dict)
}

#[staticmethod]
#[pyo3(name = "from_json")]
fn py_from_json(data: Vec<u8>) -> PyResult<Self> {
Self::from_json_bytes(data).map_err(to_pyvalue_err)
}

#[staticmethod]
#[pyo3(name = "from_msgpack")]
fn py_from_msgpack(data: Vec<u8>) -> PyResult<Self> {
Self::from_msgpack_bytes(data).map_err(to_pyvalue_err)
}

/// Return JSON encoded bytes representation of the object.
#[pyo3(name = "as_json")]
fn py_as_json(&self, py: Python<'_>) -> Py<PyAny> {
// Unwrapping is safe when serializing a valid object
self.as_json_bytes().unwrap().into_py(py)
}

/// Return MsgPack encoded bytes representation of the object.
#[pyo3(name = "as_msgpack")]
fn py_as_msgpack(&self, py: Python<'_>) -> Py<PyAny> {
// Unwrapping is safe when serializing a valid object
self.as_msgpack_bytes().unwrap().into_py(py)
}
}
12 changes: 6 additions & 6 deletions nautilus_core/model/src/python/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ mod tests {
/// Loaded as nautilus_pyo3.model
#[pymodule]
pub fn model(_: Python<'_>, m: &PyModule) -> PyResult<()> {
// data
// Data
m.add_class::<crate::data::bar::BarSpecification>()?;
m.add_class::<crate::data::bar::BarType>()?;
m.add_class::<crate::data::bar::Bar>()?;
Expand All @@ -233,7 +233,7 @@ pub fn model(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<crate::data::depth::OrderBookDepth10>()?;
m.add_class::<crate::data::quote::QuoteTick>()?;
m.add_class::<crate::data::trade::TradeTick>()?;
// enums
// Enums
m.add_class::<enums::AccountType>()?;
m.add_class::<enums::AggregationSource>()?;
m.add_class::<enums::AggressorSide>()?;
Expand All @@ -258,7 +258,7 @@ pub fn model(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<enums::TradingState>()?;
m.add_class::<enums::TrailingOffsetType>()?;
m.add_class::<enums::TriggerType>()?;
// identifiers
// Identifiers
m.add_class::<crate::identifiers::account_id::AccountId>()?;
m.add_class::<crate::identifiers::client_id::ClientId>()?;
m.add_class::<crate::identifiers::client_order_id::ClientOrderId>()?;
Expand All @@ -273,7 +273,7 @@ pub fn model(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<crate::identifiers::trader_id::TraderId>()?;
m.add_class::<crate::identifiers::venue::Venue>()?;
m.add_class::<crate::identifiers::venue_order_id::VenueOrderId>()?;
// orders
// Orders
m.add_class::<crate::orders::limit::LimitOrder>()?;
m.add_class::<crate::orders::limit_if_touched::LimitIfTouchedOrder>()?;
m.add_class::<crate::orders::market::MarketOrder>()?;
Expand All @@ -286,15 +286,15 @@ pub fn model(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<crate::types::money::Money>()?;
m.add_class::<crate::types::price::Price>()?;
m.add_class::<crate::types::quantity::Quantity>()?;
// instruments
// Instruments
m.add_class::<crate::instruments::crypto_future::CryptoFuture>()?;
m.add_class::<crate::instruments::crypto_perpetual::CryptoPerpetual>()?;
m.add_class::<crate::instruments::currency_pair::CurrencyPair>()?;
m.add_class::<crate::instruments::equity::Equity>()?;
m.add_class::<crate::instruments::futures_contract::FuturesContract>()?;
m.add_class::<crate::instruments::options_contract::OptionsContract>()?;
m.add_class::<crate::instruments::synthetic::SyntheticInstrument>()?;
// events
// Events
m.add_class::<crate::events::order::denied::OrderDenied>()?;
m.add_class::<crate::events::order::filled::OrderFilled>()?;
m.add_class::<crate::events::order::initialized::OrderInitialized>()?;
Expand Down
Loading

0 comments on commit b33dd05

Please sign in to comment.