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