nautilus_model/instruments/
mod.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Instrument definitions for the trading domain model.
17
18pub mod any;
19pub mod betting;
20pub mod binary_option;
21pub mod crypto_future;
22pub mod crypto_perpetual;
23pub mod currency_pair;
24pub mod equity;
25pub mod futures_contract;
26pub mod futures_spread;
27pub mod option_contract;
28pub mod option_spread;
29pub mod synthetic;
30
31#[cfg(feature = "stubs")]
32pub mod stubs;
33
34use nautilus_core::UnixNanos;
35use rust_decimal::Decimal;
36use rust_decimal_macros::dec;
37use ustr::Ustr;
38
39// Re-exports
40pub use crate::instruments::{
41    any::InstrumentAny, betting::BettingInstrument, binary_option::BinaryOption,
42    crypto_future::CryptoFuture, crypto_perpetual::CryptoPerpetual, currency_pair::CurrencyPair,
43    equity::Equity, futures_contract::FuturesContract, futures_spread::FuturesSpread,
44    option_contract::OptionContract, option_spread::OptionSpread, synthetic::SyntheticInstrument,
45};
46use crate::{
47    enums::{AssetClass, InstrumentClass, OptionKind},
48    identifiers::{InstrumentId, Symbol, Venue},
49    types::{Currency, Money, Price, Quantity},
50};
51
52pub trait Instrument: 'static + Send {
53    fn into_any(self) -> InstrumentAny;
54    fn id(&self) -> InstrumentId;
55    fn symbol(&self) -> Symbol {
56        self.id().symbol
57    }
58    fn venue(&self) -> Venue {
59        self.id().venue
60    }
61    fn raw_symbol(&self) -> Symbol;
62    fn asset_class(&self) -> AssetClass;
63    fn instrument_class(&self) -> InstrumentClass;
64    fn underlying(&self) -> Option<Ustr>;
65    fn base_currency(&self) -> Option<Currency>;
66    fn quote_currency(&self) -> Currency;
67    fn settlement_currency(&self) -> Currency;
68    fn isin(&self) -> Option<Ustr>;
69    fn option_kind(&self) -> Option<OptionKind>;
70    fn exchange(&self) -> Option<Ustr>;
71    fn strike_price(&self) -> Option<Price>;
72    fn activation_ns(&self) -> Option<UnixNanos>;
73    fn expiration_ns(&self) -> Option<UnixNanos>;
74    fn is_inverse(&self) -> bool;
75    fn price_precision(&self) -> u8;
76    fn size_precision(&self) -> u8;
77    fn price_increment(&self) -> Price;
78    fn size_increment(&self) -> Quantity;
79    fn multiplier(&self) -> Quantity;
80    fn lot_size(&self) -> Option<Quantity>;
81    fn max_quantity(&self) -> Option<Quantity>;
82    fn min_quantity(&self) -> Option<Quantity>;
83    fn max_notional(&self) -> Option<Money>;
84    fn min_notional(&self) -> Option<Money>;
85    fn max_price(&self) -> Option<Price>;
86    fn min_price(&self) -> Option<Price>;
87    fn margin_init(&self) -> Decimal {
88        dec!(0) // Temporary until separate fee models
89    }
90
91    fn margin_maint(&self) -> Decimal {
92        dec!(0) // Temporary until separate fee models
93    }
94
95    fn maker_fee(&self) -> Decimal {
96        dec!(0) // Temporary until separate fee models
97    }
98
99    fn taker_fee(&self) -> Decimal {
100        dec!(0) // Temporary until separate fee models
101    }
102    fn ts_event(&self) -> UnixNanos;
103    fn ts_init(&self) -> UnixNanos;
104
105    /// Creates a new `Price` from the given `value` with the correct price precision for the instrument.
106    fn make_price(&self, value: f64) -> Price {
107        Price::new(value, self.price_precision())
108    }
109
110    /// Creates a new `Quantity` from the given `value` with the correct size precision for the instrument.
111    fn make_qty(&self, value: f64) -> Quantity {
112        Quantity::new(value, self.size_precision())
113    }
114
115    /// Calculates the notional value from the given parameters.
116    /// The `use_quote_for_inverse` flag is only applicable for inverse instruments.
117    ///
118    /// # Panics
119    ///
120    /// This function panics:
121    /// - If instrument is inverse and not `use_quote_for_inverse`, with no base currency.
122    fn calculate_notional_value(
123        &self,
124        quantity: Quantity,
125        price: Price,
126        use_quote_for_inverse: Option<bool>,
127    ) -> Money {
128        let use_quote_for_inverse = use_quote_for_inverse.unwrap_or(false);
129        let (amount, currency) = if self.is_inverse() {
130            if use_quote_for_inverse {
131                (quantity.as_f64(), self.quote_currency())
132            } else {
133                let amount =
134                    quantity.as_f64() * self.multiplier().as_f64() * (1.0 / price.as_f64());
135                let currency = self
136                    .base_currency()
137                    .expect("Error: no base currency for notional calculation");
138                (amount, currency)
139            }
140        } else {
141            let amount = quantity.as_f64() * self.multiplier().as_f64() * price.as_f64();
142            let currency = self.quote_currency();
143            (amount, currency)
144        };
145
146        Money::new(amount, currency)
147    }
148
149    /// Returns the equivalent quantity of the base asset.
150    fn calculate_base_quantity(&self, quantity: Quantity, last_px: Price) -> Quantity {
151        let value = quantity.as_f64() * (1.0 / last_px.as_f64());
152        Quantity::new(value, self.size_precision())
153    }
154}
155
156pub const EXPIRING_INSTRUMENT_TYPES: [InstrumentClass; 4] = [
157    InstrumentClass::Future,
158    InstrumentClass::FuturesSpread,
159    InstrumentClass::Option,
160    InstrumentClass::OptionSpread,
161];