use std::hash::{Hash, Hasher};
use nautilus_core::{
correctness::{check_equal_u8, check_positive_i64, check_positive_u64, FAILED},
nanos::UnixNanos,
};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use ustr::Ustr;
use super::{any::InstrumentAny, Instrument};
use crate::{
enums::{AssetClass, InstrumentClass, OptionKind},
identifiers::{InstrumentId, Symbol},
types::{currency::Currency, money::Money, price::Price, quantity::Quantity},
};
#[repr(C)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
)]
#[cfg_attr(feature = "trivial_copy", derive(Copy))]
pub struct BettingInstrument {
pub id: InstrumentId,
pub raw_symbol: Symbol,
pub event_type_id: u64,
pub event_type_name: Ustr,
pub competition_id: u64,
pub competition_name: Ustr,
pub event_id: u64,
pub event_name: Ustr,
pub event_country_code: Ustr,
pub event_open_date: UnixNanos,
pub betting_type: Ustr,
pub market_id: Ustr,
pub market_name: Ustr,
pub market_type: Ustr,
pub market_start_time: UnixNanos,
pub selection_id: u64,
pub selection_name: Ustr,
pub selection_handicap: f64,
pub currency: Currency,
pub price_precision: u8,
pub size_precision: u8,
pub price_increment: Price,
pub size_increment: Quantity,
pub maker_fee: Decimal,
pub taker_fee: Decimal,
pub max_quantity: Option<Quantity>,
pub min_quantity: Option<Quantity>,
pub max_notional: Option<Money>,
pub min_notional: Option<Money>,
pub max_price: Option<Price>,
pub min_price: Option<Price>,
pub ts_event: UnixNanos,
pub ts_init: UnixNanos,
}
impl BettingInstrument {
#[allow(clippy::too_many_arguments)]
pub fn new_checked(
id: InstrumentId,
raw_symbol: Symbol,
event_type_id: u64,
event_type_name: Ustr,
competition_id: u64,
competition_name: Ustr,
event_id: u64,
event_name: Ustr,
event_country_code: Ustr,
event_open_date: UnixNanos,
betting_type: Ustr,
market_id: Ustr,
market_name: Ustr,
market_type: Ustr,
market_start_time: UnixNanos,
selection_id: u64,
selection_name: Ustr,
selection_handicap: f64,
currency: Currency,
price_precision: u8,
size_precision: u8,
price_increment: Price,
size_increment: Quantity,
maker_fee: Decimal,
taker_fee: Decimal,
max_quantity: Option<Quantity>,
min_quantity: Option<Quantity>,
max_notional: Option<Money>,
min_notional: Option<Money>,
max_price: Option<Price>,
min_price: Option<Price>,
ts_event: UnixNanos,
ts_init: UnixNanos,
) -> anyhow::Result<Self> {
check_equal_u8(
price_precision,
price_increment.precision,
stringify!(price_precision),
stringify!(price_increment.precision),
)?;
check_equal_u8(
size_precision,
size_increment.precision,
stringify!(size_precision),
stringify!(size_increment.precision),
)?;
check_positive_i64(price_increment.raw, stringify!(price_increment.raw))?;
check_positive_u64(size_increment.raw, stringify!(size_increment.raw))?;
Ok(Self {
id,
raw_symbol,
event_type_id,
event_type_name,
competition_id,
competition_name,
event_id,
event_name,
event_country_code,
event_open_date,
betting_type,
market_id,
market_name,
market_type,
market_start_time,
selection_id,
selection_name,
selection_handicap,
currency,
price_precision,
size_precision,
price_increment,
size_increment,
maker_fee,
taker_fee,
max_quantity,
min_quantity,
max_notional,
min_notional,
max_price,
min_price,
ts_event,
ts_init,
})
}
#[allow(clippy::too_many_arguments)]
pub fn new(
id: InstrumentId,
raw_symbol: Symbol,
event_type_id: u64,
event_type_name: Ustr,
competition_id: u64,
competition_name: Ustr,
event_id: u64,
event_name: Ustr,
event_country_code: Ustr,
event_open_date: UnixNanos,
betting_type: Ustr,
market_id: Ustr,
market_name: Ustr,
market_type: Ustr,
market_start_time: UnixNanos,
selection_id: u64,
selection_name: Ustr,
selection_handicap: f64,
currency: Currency,
price_precision: u8,
size_precision: u8,
price_increment: Price,
size_increment: Quantity,
maker_fee: Decimal,
taker_fee: Decimal,
max_quantity: Option<Quantity>,
min_quantity: Option<Quantity>,
max_notional: Option<Money>,
min_notional: Option<Money>,
max_price: Option<Price>,
min_price: Option<Price>,
ts_event: UnixNanos,
ts_init: UnixNanos,
) -> Self {
Self::new_checked(
id,
raw_symbol,
event_type_id,
event_type_name,
competition_id,
competition_name,
event_id,
event_name,
event_country_code,
event_open_date,
betting_type,
market_id,
market_name,
market_type,
market_start_time,
selection_id,
selection_name,
selection_handicap,
currency,
price_precision,
size_precision,
price_increment,
size_increment,
maker_fee,
taker_fee,
max_quantity,
min_quantity,
max_notional,
min_notional,
max_price,
min_price,
ts_event,
ts_init,
)
.expect(FAILED)
}
}
impl PartialEq<Self> for BettingInstrument {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for BettingInstrument {}
impl Hash for BettingInstrument {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Instrument for BettingInstrument {
fn into_any(self) -> InstrumentAny {
InstrumentAny::Betting(self)
}
fn id(&self) -> InstrumentId {
self.id
}
fn raw_symbol(&self) -> Symbol {
self.raw_symbol
}
fn asset_class(&self) -> AssetClass {
AssetClass::Alternative
}
fn instrument_class(&self) -> InstrumentClass {
InstrumentClass::SportsBetting
}
fn underlying(&self) -> Option<Ustr> {
None
}
fn quote_currency(&self) -> Currency {
self.currency
}
fn base_currency(&self) -> Option<Currency> {
None
}
fn settlement_currency(&self) -> Currency {
self.currency
}
fn isin(&self) -> Option<Ustr> {
None
}
fn exchange(&self) -> Option<Ustr> {
None
}
fn option_kind(&self) -> Option<OptionKind> {
None
}
fn is_inverse(&self) -> bool {
false
}
fn price_precision(&self) -> u8 {
self.price_precision
}
fn size_precision(&self) -> u8 {
self.size_precision
}
fn price_increment(&self) -> Price {
self.price_increment
}
fn size_increment(&self) -> Quantity {
self.size_increment
}
fn multiplier(&self) -> Quantity {
Quantity::from(1)
}
fn lot_size(&self) -> Option<Quantity> {
Some(Quantity::from(1))
}
fn max_quantity(&self) -> Option<Quantity> {
self.max_quantity
}
fn min_quantity(&self) -> Option<Quantity> {
self.min_quantity
}
fn max_price(&self) -> Option<Price> {
self.max_price
}
fn min_price(&self) -> Option<Price> {
self.min_price
}
fn ts_event(&self) -> UnixNanos {
self.ts_event
}
fn ts_init(&self) -> UnixNanos {
self.ts_init
}
fn strike_price(&self) -> Option<Price> {
None
}
fn activation_ns(&self) -> Option<UnixNanos> {
Some(self.market_start_time)
}
fn expiration_ns(&self) -> Option<UnixNanos> {
None
}
fn max_notional(&self) -> Option<Money> {
self.max_notional
}
fn min_notional(&self) -> Option<Money> {
self.min_notional
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use crate::instruments::{betting::BettingInstrument, stubs::*};
#[rstest]
fn test_equality(betting: BettingInstrument) {
let cloned = betting;
assert_eq!(betting, cloned);
}
}