nautilus_tardis/http/
instruments.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 nautilus_model::{
18    currencies::CURRENCY_MAP,
19    enums::CurrencyType,
20    identifiers::{InstrumentId, Symbol},
21    instruments::{CryptoFuture, CryptoOption, CryptoPerpetual, CurrencyPair, InstrumentAny},
22    types::{Currency, Price, Quantity},
23};
24use rust_decimal::Decimal;
25
26use super::{models::InstrumentInfo, parse::parse_settlement_currency};
27use crate::parse::parse_option_kind;
28
29/// Returns the currency either from the internal currency map or creates a default crypto.
30pub(crate) fn get_currency(code: &str) -> Currency {
31    CURRENCY_MAP
32        .lock()
33        .unwrap()
34        .get(code)
35        .copied()
36        .unwrap_or(Currency::new(code, 8, 0, code, CurrencyType::Crypto))
37}
38
39#[allow(clippy::too_many_arguments)]
40#[must_use]
41pub fn create_currency_pair(
42    info: &InstrumentInfo,
43    instrument_id: InstrumentId,
44    raw_symbol: Symbol,
45    price_increment: Price,
46    size_increment: Quantity,
47    margin_init: Decimal,
48    margin_maint: Decimal,
49    maker_fee: Decimal,
50    taker_fee: Decimal,
51    ts_event: UnixNanos,
52    ts_init: UnixNanos,
53) -> InstrumentAny {
54    InstrumentAny::CurrencyPair(CurrencyPair::new(
55        instrument_id,
56        raw_symbol,
57        get_currency(info.base_currency.to_uppercase().as_str()),
58        get_currency(info.quote_currency.to_uppercase().as_str()),
59        price_increment.precision,
60        size_increment.precision,
61        price_increment,
62        size_increment,
63        None, // lot_size TBD
64        None,
65        Some(Quantity::from(info.min_trade_amount.to_string().as_str())),
66        None,
67        None,
68        None,
69        None,
70        Some(margin_init),
71        Some(margin_maint),
72        Some(maker_fee),
73        Some(taker_fee),
74        ts_event,
75        ts_init,
76    ))
77}
78
79#[allow(clippy::too_many_arguments)]
80#[must_use]
81pub fn create_crypto_perpetual(
82    info: &InstrumentInfo,
83    instrument_id: InstrumentId,
84    raw_symbol: Symbol,
85    price_increment: Price,
86    size_increment: Quantity,
87    multiplier: Option<Quantity>,
88    margin_init: Decimal,
89    margin_maint: Decimal,
90    maker_fee: Decimal,
91    taker_fee: Decimal,
92    ts_event: UnixNanos,
93    ts_init: UnixNanos,
94) -> InstrumentAny {
95    let is_inverse = info.inverse.unwrap_or(false);
96
97    InstrumentAny::CryptoPerpetual(CryptoPerpetual::new(
98        instrument_id,
99        raw_symbol,
100        get_currency(info.base_currency.to_uppercase().as_str()),
101        get_currency(info.quote_currency.to_uppercase().as_str()),
102        get_currency(parse_settlement_currency(info, is_inverse).as_str()),
103        is_inverse,
104        price_increment.precision,
105        size_increment.precision,
106        price_increment,
107        size_increment,
108        multiplier,
109        None, // lot_size TBD
110        None,
111        Some(Quantity::from(info.min_trade_amount.to_string().as_str())),
112        None,
113        None,
114        None,
115        None,
116        Some(margin_init),
117        Some(margin_maint),
118        Some(maker_fee),
119        Some(taker_fee),
120        ts_event,
121        ts_init,
122    ))
123}
124
125#[allow(clippy::too_many_arguments)]
126#[must_use]
127pub fn create_crypto_future(
128    info: &InstrumentInfo,
129    instrument_id: InstrumentId,
130    raw_symbol: Symbol,
131    activation: UnixNanos,
132    expiration: UnixNanos,
133    price_increment: Price,
134    size_increment: Quantity,
135    multiplier: Option<Quantity>,
136    margin_init: Decimal,
137    margin_maint: Decimal,
138    maker_fee: Decimal,
139    taker_fee: Decimal,
140    ts_event: UnixNanos,
141    ts_init: UnixNanos,
142) -> InstrumentAny {
143    let is_inverse = info.inverse.unwrap_or(false);
144
145    InstrumentAny::CryptoFuture(CryptoFuture::new(
146        instrument_id,
147        raw_symbol,
148        get_currency(info.base_currency.to_uppercase().as_str()),
149        get_currency(info.quote_currency.to_uppercase().as_str()),
150        get_currency(parse_settlement_currency(info, is_inverse).as_str()),
151        is_inverse,
152        activation,
153        expiration,
154        price_increment.precision,
155        size_increment.precision,
156        price_increment,
157        size_increment,
158        multiplier,
159        None, // lot_size TBD
160        None,
161        Some(Quantity::from(info.min_trade_amount.to_string().as_str())),
162        None,
163        None,
164        None,
165        None,
166        Some(margin_init),
167        Some(margin_maint),
168        Some(maker_fee),
169        Some(taker_fee),
170        ts_event,
171        ts_init,
172    ))
173}
174
175#[allow(clippy::too_many_arguments)]
176#[must_use]
177pub fn create_crypto_option(
178    info: &InstrumentInfo,
179    instrument_id: InstrumentId,
180    raw_symbol: Symbol,
181    activation: UnixNanos,
182    expiration: UnixNanos,
183    price_increment: Price,
184    size_increment: Quantity,
185    multiplier: Option<Quantity>,
186    margin_init: Decimal,
187    margin_maint: Decimal,
188    maker_fee: Decimal,
189    taker_fee: Decimal,
190    ts_event: UnixNanos,
191    ts_init: UnixNanos,
192) -> InstrumentAny {
193    let is_inverse = info.inverse.unwrap_or(false);
194
195    InstrumentAny::CryptoOption(CryptoOption::new(
196        instrument_id,
197        raw_symbol,
198        get_currency(info.base_currency.to_uppercase().as_str()),
199        get_currency(info.quote_currency.to_uppercase().as_str()),
200        get_currency(parse_settlement_currency(info, is_inverse).as_str()),
201        is_inverse,
202        parse_option_kind(
203            info.option_type
204                .clone()
205                .expect("CryptoOption should have `option_type` field"),
206        ),
207        Price::new(
208            info.strike_price
209                .expect("CryptoOption should have `strike_price` field"),
210            price_increment.precision,
211        ),
212        activation,
213        expiration,
214        price_increment.precision,
215        size_increment.precision,
216        price_increment,
217        size_increment,
218        multiplier,
219        None,
220        Some(Quantity::from(info.min_trade_amount.to_string().as_str())),
221        None,
222        None,
223        None,
224        None,
225        Some(margin_init),
226        Some(margin_maint),
227        Some(maker_fee),
228        Some(taker_fee),
229        ts_event,
230        ts_init,
231    ))
232}