nautilus_model/instruments/
any.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
16use nautilus_core::UnixNanos;
17use rust_decimal::Decimal;
18use ustr::Ustr;
19
20use super::{
21    betting::BettingInstrument, binary_option::BinaryOption, crypto_future::CryptoFuture,
22    crypto_perpetual::CryptoPerpetual, currency_pair::CurrencyPair, equity::Equity,
23    futures_contract::FuturesContract, futures_spread::FuturesSpread,
24    option_contract::OptionContract, option_spread::OptionSpread, Instrument,
25};
26use crate::{
27    enums::InstrumentClass,
28    identifiers::{InstrumentId, Symbol, Venue},
29    types::{Currency, Money, Price, Quantity},
30};
31
32#[derive(Clone, Debug)]
33pub enum InstrumentAny {
34    Betting(BettingInstrument),
35    BinaryOption(BinaryOption),
36    CryptoFuture(CryptoFuture),
37    CryptoPerpetual(CryptoPerpetual),
38    CurrencyPair(CurrencyPair),
39    Equity(Equity),
40    FuturesContract(FuturesContract),
41    FuturesSpread(FuturesSpread),
42    OptionContract(OptionContract),
43    OptionSpread(OptionSpread),
44}
45
46impl InstrumentAny {
47    /// Consumes the `OrderAny` enum and returns the underlying order as a boxed trait.
48    #[must_use]
49    pub fn into_instrument(self) -> Box<dyn Instrument> {
50        match self {
51            Self::Betting(inst) => Box::new(inst),
52            Self::BinaryOption(inst) => Box::new(inst),
53            Self::CryptoFuture(inst) => Box::new(inst),
54            Self::CryptoPerpetual(inst) => Box::new(inst),
55            Self::CurrencyPair(inst) => Box::new(inst),
56            Self::Equity(inst) => Box::new(inst),
57            Self::FuturesContract(inst) => Box::new(inst),
58            Self::FuturesSpread(inst) => Box::new(inst),
59            Self::OptionContract(inst) => Box::new(inst),
60            Self::OptionSpread(inst) => Box::new(inst),
61        }
62    }
63
64    #[must_use]
65    pub fn instrument_class(&self) -> InstrumentClass {
66        match self {
67            Self::Betting(inst) => inst.instrument_class(),
68            Self::BinaryOption(inst) => inst.instrument_class(),
69            Self::CryptoFuture(inst) => inst.instrument_class(),
70            Self::CryptoPerpetual(inst) => inst.instrument_class(),
71            Self::CurrencyPair(inst) => inst.instrument_class(),
72            Self::Equity(inst) => inst.instrument_class(),
73            Self::FuturesContract(inst) => inst.instrument_class(),
74            Self::FuturesSpread(inst) => inst.instrument_class(),
75            Self::OptionContract(inst) => inst.instrument_class(),
76            Self::OptionSpread(inst) => inst.instrument_class(),
77        }
78    }
79
80    #[must_use]
81    pub fn id(&self) -> InstrumentId {
82        match self {
83            Self::Betting(inst) => inst.id,
84            Self::BinaryOption(inst) => inst.id,
85            Self::CryptoFuture(inst) => inst.id,
86            Self::CryptoPerpetual(inst) => inst.id,
87            Self::CurrencyPair(inst) => inst.id,
88            Self::Equity(inst) => inst.id,
89            Self::FuturesContract(inst) => inst.id,
90            Self::FuturesSpread(inst) => inst.id,
91            Self::OptionContract(inst) => inst.id,
92            Self::OptionSpread(inst) => inst.id,
93        }
94    }
95
96    #[must_use]
97    pub fn symbol(&self) -> Symbol {
98        match self {
99            Self::Betting(inst) => inst.id.symbol,
100            Self::BinaryOption(inst) => inst.id.symbol,
101            Self::CryptoFuture(inst) => inst.id.symbol,
102            Self::CryptoPerpetual(inst) => inst.id.symbol,
103            Self::CurrencyPair(inst) => inst.id.symbol,
104            Self::Equity(inst) => inst.id.symbol,
105            Self::FuturesContract(inst) => inst.id.symbol,
106            Self::FuturesSpread(inst) => inst.id.symbol,
107            Self::OptionContract(inst) => inst.id.symbol,
108            Self::OptionSpread(inst) => inst.id.symbol,
109        }
110    }
111
112    #[must_use]
113    pub fn venue(&self) -> Venue {
114        match self {
115            Self::Betting(inst) => inst.id.venue,
116            Self::BinaryOption(inst) => inst.id.venue,
117            Self::CryptoFuture(inst) => inst.id.venue,
118            Self::CryptoPerpetual(inst) => inst.id.venue,
119            Self::CurrencyPair(inst) => inst.id.venue,
120            Self::Equity(inst) => inst.id.venue,
121            Self::FuturesContract(inst) => inst.id.venue,
122            Self::FuturesSpread(inst) => inst.id.venue,
123            Self::OptionContract(inst) => inst.id.venue,
124            Self::OptionSpread(inst) => inst.id.venue,
125        }
126    }
127
128    #[must_use]
129    pub fn raw_symbol(&self) -> Symbol {
130        match self {
131            Self::Betting(inst) => inst.raw_symbol(),
132            Self::BinaryOption(inst) => inst.raw_symbol(),
133            Self::CryptoFuture(inst) => inst.raw_symbol(),
134            Self::CryptoPerpetual(inst) => inst.raw_symbol(),
135            Self::CurrencyPair(inst) => inst.raw_symbol(),
136            Self::Equity(inst) => inst.raw_symbol(),
137            Self::FuturesContract(inst) => inst.raw_symbol(),
138            Self::FuturesSpread(inst) => inst.raw_symbol(),
139            Self::OptionContract(inst) => inst.raw_symbol(),
140            Self::OptionSpread(inst) => inst.raw_symbol(),
141        }
142    }
143
144    #[must_use]
145    pub fn underlying(&self) -> Option<&Ustr> {
146        match self {
147            Self::Betting(_) => None,
148            Self::BinaryOption(_) => None,
149            Self::CryptoFuture(inst) => Some(&inst.underlying.code),
150            Self::CryptoPerpetual(_) => None,
151            Self::CurrencyPair(_) => None,
152            Self::Equity(_) => None,
153            Self::FuturesContract(inst) => Some(&inst.underlying),
154            Self::FuturesSpread(inst) => Some(&inst.underlying),
155            Self::OptionContract(inst) => Some(&inst.underlying),
156            Self::OptionSpread(inst) => Some(&inst.underlying),
157        }
158    }
159
160    #[must_use]
161    pub fn base_currency(&self) -> Option<Currency> {
162        match self {
163            Self::Betting(inst) => inst.base_currency(),
164            Self::BinaryOption(inst) => inst.base_currency(),
165            Self::CryptoFuture(inst) => inst.base_currency(),
166            Self::CryptoPerpetual(inst) => inst.base_currency(),
167            Self::CurrencyPair(inst) => inst.base_currency(),
168            Self::Equity(inst) => inst.base_currency(),
169            Self::FuturesContract(inst) => inst.base_currency(),
170            Self::FuturesSpread(inst) => inst.base_currency(),
171            Self::OptionContract(inst) => inst.base_currency(),
172            Self::OptionSpread(inst) => inst.base_currency(),
173        }
174    }
175
176    #[must_use]
177    pub fn quote_currency(&self) -> Currency {
178        match self {
179            Self::Betting(inst) => inst.quote_currency(),
180            Self::BinaryOption(inst) => inst.quote_currency(),
181            Self::CryptoFuture(inst) => inst.quote_currency(),
182            Self::CryptoPerpetual(inst) => inst.quote_currency(),
183            Self::CurrencyPair(inst) => inst.quote_currency(),
184            Self::Equity(inst) => inst.quote_currency(),
185            Self::FuturesContract(inst) => inst.quote_currency(),
186            Self::FuturesSpread(inst) => inst.quote_currency(),
187            Self::OptionContract(inst) => inst.quote_currency(),
188            Self::OptionSpread(inst) => inst.quote_currency(),
189        }
190    }
191
192    #[must_use]
193    pub fn settlement_currency(&self) -> Currency {
194        match self {
195            Self::Betting(inst) => inst.settlement_currency(),
196            Self::BinaryOption(inst) => inst.settlement_currency(),
197            Self::CryptoFuture(inst) => inst.settlement_currency(),
198            Self::CryptoPerpetual(inst) => inst.settlement_currency(),
199            Self::CurrencyPair(inst) => inst.settlement_currency(),
200            Self::Equity(inst) => inst.settlement_currency(),
201            Self::FuturesContract(inst) => inst.settlement_currency(),
202            Self::FuturesSpread(inst) => inst.settlement_currency(),
203            Self::OptionContract(inst) => inst.settlement_currency(),
204            Self::OptionSpread(inst) => inst.settlement_currency(),
205        }
206    }
207
208    #[must_use]
209    pub fn is_inverse(&self) -> bool {
210        match self {
211            Self::Betting(inst) => inst.is_inverse(),
212            Self::BinaryOption(inst) => inst.is_inverse(),
213            Self::CryptoFuture(inst) => inst.is_inverse(),
214            Self::CryptoPerpetual(inst) => inst.is_inverse(),
215            Self::CurrencyPair(inst) => inst.is_inverse(),
216            Self::Equity(inst) => inst.is_inverse(),
217            Self::FuturesContract(inst) => inst.is_inverse(),
218            Self::FuturesSpread(inst) => inst.is_inverse(),
219            Self::OptionContract(inst) => inst.is_inverse(),
220            Self::OptionSpread(inst) => inst.is_inverse(),
221        }
222    }
223
224    #[must_use]
225    pub fn price_precision(&self) -> u8 {
226        match self {
227            Self::Betting(inst) => inst.price_precision(),
228            Self::BinaryOption(inst) => inst.price_precision(),
229            Self::CryptoFuture(inst) => inst.price_precision(),
230            Self::CryptoPerpetual(inst) => inst.price_precision(),
231            Self::CurrencyPair(inst) => inst.price_precision(),
232            Self::Equity(inst) => inst.price_precision(),
233            Self::FuturesContract(inst) => inst.price_precision(),
234            Self::FuturesSpread(inst) => inst.price_precision(),
235            Self::OptionContract(inst) => inst.price_precision(),
236            Self::OptionSpread(inst) => inst.price_precision(),
237        }
238    }
239
240    #[must_use]
241    pub fn size_precision(&self) -> u8 {
242        match self {
243            Self::Betting(inst) => inst.size_precision(),
244            Self::BinaryOption(inst) => inst.size_precision(),
245            Self::CryptoFuture(inst) => inst.size_precision(),
246            Self::CryptoPerpetual(inst) => inst.size_precision(),
247            Self::CurrencyPair(inst) => inst.size_precision(),
248            Self::Equity(inst) => inst.size_precision(),
249            Self::FuturesContract(inst) => inst.size_precision(),
250            Self::FuturesSpread(inst) => inst.size_precision(),
251            Self::OptionContract(inst) => inst.size_precision(),
252            Self::OptionSpread(inst) => inst.size_precision(),
253        }
254    }
255
256    #[must_use]
257    pub fn price_increment(&self) -> Price {
258        match self {
259            Self::Betting(inst) => inst.price_increment(),
260            Self::BinaryOption(inst) => inst.price_increment(),
261            Self::CryptoFuture(inst) => inst.price_increment(),
262            Self::CryptoPerpetual(inst) => inst.price_increment(),
263            Self::CurrencyPair(inst) => inst.price_increment(),
264            Self::Equity(inst) => inst.price_increment(),
265            Self::FuturesContract(inst) => inst.price_increment(),
266            Self::FuturesSpread(inst) => inst.price_increment(),
267            Self::OptionContract(inst) => inst.price_increment(),
268            Self::OptionSpread(inst) => inst.price_increment(),
269        }
270    }
271
272    #[must_use]
273    pub fn size_increment(&self) -> Quantity {
274        match self {
275            Self::Betting(inst) => inst.size_increment(),
276            Self::BinaryOption(inst) => inst.size_increment(),
277            Self::CryptoFuture(inst) => inst.size_increment(),
278            Self::CryptoPerpetual(inst) => inst.size_increment(),
279            Self::CurrencyPair(inst) => inst.size_increment(),
280            Self::Equity(inst) => inst.size_increment(),
281            Self::FuturesContract(inst) => inst.size_increment(),
282            Self::FuturesSpread(inst) => inst.size_increment(),
283            Self::OptionContract(inst) => inst.size_increment(),
284            Self::OptionSpread(inst) => inst.size_increment(),
285        }
286    }
287
288    #[must_use]
289    pub fn multiplier(&self) -> Quantity {
290        match self {
291            Self::Betting(inst) => inst.multiplier(),
292            Self::BinaryOption(inst) => inst.multiplier(),
293            Self::CryptoFuture(inst) => inst.multiplier(),
294            Self::CryptoPerpetual(inst) => inst.multiplier(),
295            Self::CurrencyPair(inst) => inst.multiplier(),
296            Self::Equity(inst) => inst.multiplier(),
297            Self::FuturesContract(inst) => inst.multiplier(),
298            Self::FuturesSpread(inst) => inst.multiplier(),
299            Self::OptionContract(inst) => inst.multiplier(),
300            Self::OptionSpread(inst) => inst.multiplier(),
301        }
302    }
303
304    #[must_use]
305    pub fn activation_ns(&self) -> Option<UnixNanos> {
306        match self {
307            Self::Betting(inst) => inst.activation_ns(),
308            Self::BinaryOption(inst) => inst.activation_ns(),
309            Self::CryptoFuture(inst) => inst.activation_ns(),
310            Self::CryptoPerpetual(inst) => inst.activation_ns(),
311            Self::CurrencyPair(inst) => inst.activation_ns(),
312            Self::Equity(inst) => inst.activation_ns(),
313            Self::FuturesContract(inst) => inst.activation_ns(),
314            Self::FuturesSpread(inst) => inst.activation_ns(),
315            Self::OptionContract(inst) => inst.activation_ns(),
316            Self::OptionSpread(inst) => inst.activation_ns(),
317        }
318    }
319
320    #[must_use]
321    pub fn expiration_ns(&self) -> Option<UnixNanos> {
322        match self {
323            Self::Betting(inst) => inst.expiration_ns(),
324            Self::BinaryOption(inst) => inst.expiration_ns(),
325            Self::CryptoFuture(inst) => inst.expiration_ns(),
326            Self::CryptoPerpetual(inst) => inst.expiration_ns(),
327            Self::CurrencyPair(inst) => inst.expiration_ns(),
328            Self::Equity(inst) => inst.expiration_ns(),
329            Self::FuturesContract(inst) => inst.expiration_ns(),
330            Self::FuturesSpread(inst) => inst.expiration_ns(),
331            Self::OptionContract(inst) => inst.expiration_ns(),
332            Self::OptionSpread(inst) => inst.expiration_ns(),
333        }
334    }
335
336    pub fn max_quantity(&self) -> Option<Quantity> {
337        match self {
338            Self::Betting(inst) => inst.max_quantity(),
339            Self::BinaryOption(inst) => inst.max_quantity(),
340            Self::CryptoFuture(inst) => inst.max_quantity(),
341            Self::CryptoPerpetual(inst) => inst.max_quantity(),
342            Self::CurrencyPair(inst) => inst.max_quantity(),
343            Self::Equity(inst) => inst.max_quantity(),
344            Self::FuturesContract(inst) => inst.max_quantity(),
345            Self::FuturesSpread(inst) => inst.max_quantity(),
346            Self::OptionContract(inst) => inst.max_quantity(),
347            Self::OptionSpread(inst) => inst.max_quantity(),
348        }
349    }
350
351    pub fn min_quantity(&self) -> Option<Quantity> {
352        match self {
353            Self::Betting(inst) => inst.min_quantity(),
354            Self::BinaryOption(inst) => inst.min_quantity(),
355            Self::CryptoFuture(inst) => inst.min_quantity(),
356            Self::CryptoPerpetual(inst) => inst.min_quantity(),
357            Self::CurrencyPair(inst) => inst.min_quantity(),
358            Self::Equity(inst) => inst.min_quantity(),
359            Self::FuturesContract(inst) => inst.min_quantity(),
360            Self::FuturesSpread(inst) => inst.min_quantity(),
361            Self::OptionContract(inst) => inst.min_quantity(),
362            Self::OptionSpread(inst) => inst.min_quantity(),
363        }
364    }
365
366    pub fn max_notional(&self) -> Option<Money> {
367        match self {
368            Self::Betting(inst) => inst.max_notional(),
369            Self::BinaryOption(inst) => inst.max_notional(),
370            Self::CryptoFuture(inst) => inst.max_notional(),
371            Self::CryptoPerpetual(inst) => inst.max_notional(),
372            Self::CurrencyPair(inst) => inst.max_notional(),
373            Self::Equity(inst) => inst.max_notional(),
374            Self::FuturesContract(inst) => inst.max_notional(),
375            Self::FuturesSpread(inst) => inst.max_notional(),
376            Self::OptionContract(inst) => inst.max_notional(),
377            Self::OptionSpread(inst) => inst.max_notional(),
378        }
379    }
380
381    pub fn min_notional(&self) -> Option<Money> {
382        match self {
383            Self::Betting(inst) => inst.min_notional(),
384            Self::BinaryOption(inst) => inst.min_notional(),
385            Self::CryptoFuture(inst) => inst.min_notional(),
386            Self::CryptoPerpetual(inst) => inst.min_notional(),
387            Self::CurrencyPair(inst) => inst.min_notional(),
388            Self::Equity(inst) => inst.min_notional(),
389            Self::FuturesContract(inst) => inst.min_notional(),
390            Self::FuturesSpread(inst) => inst.min_notional(),
391            Self::OptionContract(inst) => inst.min_notional(),
392            Self::OptionSpread(inst) => inst.min_notional(),
393        }
394    }
395
396    pub fn make_price(&self, value: f64) -> Price {
397        match self {
398            Self::Betting(inst) => inst.make_price(value),
399            Self::BinaryOption(inst) => inst.make_price(value),
400            Self::CryptoFuture(inst) => inst.make_price(value),
401            Self::CryptoPerpetual(inst) => inst.make_price(value),
402            Self::CurrencyPair(inst) => inst.make_price(value),
403            Self::Equity(inst) => inst.make_price(value),
404            Self::FuturesContract(inst) => inst.make_price(value),
405            Self::FuturesSpread(inst) => inst.make_price(value),
406            Self::OptionContract(inst) => inst.make_price(value),
407            Self::OptionSpread(inst) => inst.make_price(value),
408        }
409    }
410
411    pub fn make_qty(&self, value: f64) -> Quantity {
412        match self {
413            Self::Betting(inst) => inst.make_qty(value),
414            Self::BinaryOption(inst) => inst.make_qty(value),
415            Self::CryptoFuture(inst) => inst.make_qty(value),
416            Self::CryptoPerpetual(inst) => inst.make_qty(value),
417            Self::CurrencyPair(inst) => inst.make_qty(value),
418            Self::Equity(inst) => inst.make_qty(value),
419            Self::FuturesContract(inst) => inst.make_qty(value),
420            Self::FuturesSpread(inst) => inst.make_qty(value),
421            Self::OptionContract(inst) => inst.make_qty(value),
422            Self::OptionSpread(inst) => inst.make_qty(value),
423        }
424    }
425
426    #[must_use]
427    pub fn calculate_notional_value(
428        &self,
429        quantity: Quantity,
430        price: Price,
431        use_quote_for_inverse: Option<bool>,
432    ) -> Money {
433        match self {
434            Self::Betting(inst) => {
435                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
436            }
437            Self::BinaryOption(inst) => {
438                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
439            }
440            Self::CryptoFuture(inst) => {
441                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
442            }
443            Self::CryptoPerpetual(inst) => {
444                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
445            }
446            Self::CurrencyPair(inst) => {
447                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
448            }
449            Self::Equity(inst) => {
450                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
451            }
452            Self::FuturesContract(inst) => {
453                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
454            }
455            Self::FuturesSpread(inst) => {
456                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
457            }
458            Self::OptionContract(inst) => {
459                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
460            }
461            Self::OptionSpread(inst) => {
462                inst.calculate_notional_value(quantity, price, use_quote_for_inverse)
463            }
464        }
465    }
466
467    // #[deprecated(since = "0.21.0", note = "Will be removed in a future version")]
468    #[must_use]
469    pub fn maker_fee(&self) -> Decimal {
470        match self {
471            Self::Betting(inst) => inst.maker_fee(),
472            Self::BinaryOption(inst) => inst.maker_fee(),
473            Self::CryptoFuture(inst) => inst.maker_fee(),
474            Self::CryptoPerpetual(inst) => inst.maker_fee(),
475            Self::CurrencyPair(inst) => inst.maker_fee(),
476            Self::Equity(inst) => inst.maker_fee(),
477            Self::FuturesContract(inst) => inst.maker_fee(),
478            Self::FuturesSpread(inst) => inst.maker_fee(),
479            Self::OptionContract(inst) => inst.maker_fee(),
480            Self::OptionSpread(inst) => inst.maker_fee(),
481        }
482    }
483
484    // #[deprecated(since = "0.21.0", note = "Will be removed in a future version")]
485    #[must_use]
486    pub fn taker_fee(&self) -> Decimal {
487        match self {
488            Self::Betting(inst) => inst.taker_fee(),
489            Self::BinaryOption(inst) => inst.taker_fee(),
490            Self::CryptoFuture(inst) => inst.taker_fee(),
491            Self::CryptoPerpetual(inst) => inst.taker_fee(),
492            Self::CurrencyPair(inst) => inst.taker_fee(),
493            Self::Equity(inst) => inst.taker_fee(),
494            Self::FuturesContract(inst) => inst.taker_fee(),
495            Self::FuturesSpread(inst) => inst.taker_fee(),
496            Self::OptionContract(inst) => inst.taker_fee(),
497            Self::OptionSpread(inst) => inst.taker_fee(),
498        }
499    }
500
501    pub fn get_base_quantity(&self, quantity: Quantity, last_px: Price) -> Quantity {
502        match self {
503            Self::Betting(inst) => inst.calculate_base_quantity(quantity, last_px),
504            Self::BinaryOption(inst) => inst.calculate_base_quantity(quantity, last_px),
505            Self::CryptoFuture(inst) => inst.calculate_base_quantity(quantity, last_px),
506            Self::CryptoPerpetual(inst) => inst.calculate_base_quantity(quantity, last_px),
507            Self::CurrencyPair(inst) => inst.calculate_base_quantity(quantity, last_px),
508            Self::Equity(inst) => inst.calculate_base_quantity(quantity, last_px),
509            Self::FuturesContract(inst) => inst.calculate_base_quantity(quantity, last_px),
510            Self::FuturesSpread(inst) => inst.calculate_base_quantity(quantity, last_px),
511            Self::OptionContract(inst) => inst.calculate_base_quantity(quantity, last_px),
512            Self::OptionSpread(inst) => inst.calculate_base_quantity(quantity, last_px),
513        }
514    }
515}
516
517impl PartialEq for InstrumentAny {
518    fn eq(&self, other: &Self) -> bool {
519        self.id() == other.id()
520    }
521}