Skip to main content

nautilus_model/instruments/
stubs.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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 chrono::{TimeZone, Utc};
17use nautilus_core::UnixNanos;
18use rstest::fixture;
19use rust_decimal::Decimal;
20use rust_decimal_macros::dec;
21use ustr::Ustr;
22
23use super::{
24    CryptoOption, betting::BettingInstrument, binary_option::BinaryOption, cfd::Cfd,
25    commodity::Commodity, futures_spread::FuturesSpread, index_instrument::IndexInstrument,
26    option_spread::OptionSpread, perpetual_contract::PerpetualContract,
27    synthetic::SyntheticInstrument, tokenized_asset::TokenizedAsset,
28};
29use crate::{
30    enums::{AssetClass, OptionKind},
31    identifiers::{InstrumentId, Symbol, Venue},
32    instruments::{
33        CryptoFuture, CryptoPerpetual, CurrencyPair, Equity, FuturesContract, OptionContract,
34    },
35    types::{Currency, Money, Price, Quantity},
36};
37
38impl Default for SyntheticInstrument {
39    /// Creates a new default [`SyntheticInstrument`] instance for testing.
40    fn default() -> Self {
41        let btc_binance = InstrumentId::from("BTC.BINANCE");
42        let ltc_binance = InstrumentId::from("LTC.BINANCE");
43        let formula = "(BTC.BINANCE + LTC.BINANCE) / 2.0";
44        Self::new(
45            Symbol::new("BTC-LTC"),
46            2,
47            vec![btc_binance, ltc_binance],
48            formula,
49            0.into(),
50            0.into(),
51        )
52    }
53}
54
55////////////////////////////////////////////////////////////////////////////////
56// CryptoFuture
57////////////////////////////////////////////////////////////////////////////////
58
59#[fixture]
60pub fn crypto_future_btcusdt(
61    #[default(2)] price_precision: u8,
62    #[default(6)] size_precision: u8,
63    #[default(Price::from("0.01"))] price_increment: Price,
64    #[default(Quantity::from("0.000001"))] size_increment: Quantity,
65) -> CryptoFuture {
66    let activation = Utc.with_ymd_and_hms(2014, 4, 8, 0, 0, 0).unwrap();
67    let expiration = Utc.with_ymd_and_hms(2014, 7, 8, 0, 0, 0).unwrap();
68    CryptoFuture::new(
69        InstrumentId::from("ETHUSDT-123.BINANCE"),
70        Symbol::from("BTCUSDT"),
71        Currency::from("BTC"),
72        Currency::from("USDT"),
73        Currency::from("USDT"),
74        false,
75        UnixNanos::from(activation.timestamp_nanos_opt().unwrap() as u64),
76        UnixNanos::from(expiration.timestamp_nanos_opt().unwrap() as u64),
77        price_precision,
78        size_precision,
79        price_increment,
80        size_increment,
81        None,
82        None,
83        Some(Quantity::from("9000.0")),
84        Some(Quantity::from("0.000001")),
85        None,
86        Some(Money::new(10.00, Currency::from("USDT"))),
87        Some(Price::from("1000000.00")),
88        Some(Price::from("0.01")),
89        None,
90        None,
91        None,
92        None,
93        None, // info
94        0.into(),
95        0.into(),
96    )
97}
98
99#[fixture]
100pub fn ethbtc_quanto(
101    #[default(5)] price_precision: u8,
102    #[default(3)] size_precision: u8,
103    #[default(Price::from("0.00001"))] price_increment: Price,
104    #[default(Quantity::from("0.001"))] size_increment: Quantity,
105) -> CryptoFuture {
106    let activation = Utc.with_ymd_and_hms(2014, 4, 8, 0, 0, 0).unwrap();
107    let expiration = Utc.with_ymd_and_hms(2014, 7, 8, 0, 0, 0).unwrap();
108    CryptoFuture::new(
109        InstrumentId::from("ETHBTC-123.BINANCE"),
110        Symbol::from("ETHBTC"),
111        Currency::from("ETH"),
112        Currency::from("BTC"),
113        Currency::from("BTC"),
114        false,
115        UnixNanos::from(activation.timestamp_nanos_opt().unwrap() as u64),
116        UnixNanos::from(expiration.timestamp_nanos_opt().unwrap() as u64),
117        price_precision,
118        size_precision,
119        price_increment,
120        size_increment,
121        None,
122        None,
123        Some(Quantity::from("9000.0")),
124        Some(Quantity::from("0.001")),
125        None,
126        Some(Money::new(1.0, Currency::from("BTC"))),
127        Some(Price::from("1.0")),
128        Some(Price::from("0.00001")),
129        None,
130        None,
131        None,
132        None,
133        None, // info
134        0.into(),
135        0.into(),
136    )
137}
138
139////////////////////////////////////////////////////////////////////////////////
140// CryptoPerpetual – BitMEX inverse (XBTUSD)
141// ////////////////////////////////////////////////////////////////////////////
142
143#[fixture]
144pub fn xbtusd_inverse_perp(
145    // One-decimal tick (0.5 USD) and integer contract size
146    #[default(1)] price_precision: u8,
147    #[default(0)] size_precision: u8,
148    #[default(Price::from("0.5"))] price_increment: Price,
149    #[default(Quantity::from("1"))] size_increment: Quantity,
150) -> CryptoPerpetual {
151    CryptoPerpetual::new(
152        // BitMEX uses XBT for BTC; keep the “-PERP” suffix for clarity
153        InstrumentId::from("XBTUSD-PERP.BITMEX"),
154        Symbol::from("XBTUSD"),
155        Currency::BTC(), // base
156        Currency::USD(), // quote
157        Currency::BTC(), // settlement (inverse)
158        true,            // is_inverse
159        price_precision,
160        size_precision,
161        price_increment,
162        size_increment,
163        None,                              // lot_size
164        Some(Quantity::from("1")),         // multiplier: 1 USD/contract
165        None,                              // max_quantity
166        None,                              // min_quantity
167        Some(Money::from("10000000 USD")), // max_notional
168        Some(Money::from("1 USD")),        // min_notional
169        Some(Price::from("10000000")),     // max_price
170        Some(Price::from("0.01")),         // min_price
171        Some(dec!(0.01)),                  // margin_init
172        Some(dec!(0.0035)),                // margin_maint
173        Some(dec!(-0.00025)),              // maker_fee (rebate)
174        Some(dec!(0.00075)),               // taker_fee
175        None,                              // info
176        UnixNanos::default(),              // ts_event
177        UnixNanos::default(),              // ts_init
178    )
179}
180
181////////////////////////////////////////////////////////////////////////////////
182// CryptoOption
183////////////////////////////////////////////////////////////////////////////////
184
185#[fixture]
186pub fn crypto_option_btc_deribit(
187    #[default(3)] price_precision: u8,
188    #[default(1)] size_precision: u8,
189    #[default(Price::from("0.001"))] price_increment: Price,
190    #[default(Quantity::from("0.1"))] size_increment: Quantity,
191) -> CryptoOption {
192    let activation = UnixNanos::from(1_671_696_002_000_000_000);
193    let expiration = UnixNanos::from(1_673_596_800_000_000_000);
194    CryptoOption::new(
195        InstrumentId::from("BTC-13JAN23-16000-P.DERIBIT"),
196        Symbol::from("BTC-13JAN23-16000-P"),
197        Currency::from("BTC"),
198        Currency::from("USD"),
199        Currency::from("BTC"),
200        false,
201        OptionKind::Put,
202        Price::from("16000.000"),
203        activation,
204        expiration,
205        price_precision,
206        size_precision,
207        price_increment,
208        size_increment,
209        Some(Quantity::from(1)),
210        Some(Quantity::from(1)),
211        Some(Quantity::from("9000.0")),
212        Some(Quantity::from("0.1")),
213        None,
214        Some(Money::new(10.00, Currency::from("USD"))),
215        None,
216        None,
217        None,
218        None,
219        Some(dec!(0.0003)),
220        Some(dec!(0.0003)),
221        None, // info
222        0.into(),
223        0.into(),
224    )
225}
226
227////////////////////////////////////////////////////////////////////////////////
228// CryptoPerpetual
229////////////////////////////////////////////////////////////////////////////////
230
231#[fixture]
232pub fn crypto_perpetual_ethusdt() -> CryptoPerpetual {
233    CryptoPerpetual::new(
234        InstrumentId::from("ETHUSDT-PERP.BINANCE"),
235        Symbol::from("ETHUSDT"),
236        Currency::from("ETH"),
237        Currency::from("USDT"),
238        Currency::from("USDT"),
239        false,
240        2,
241        3,
242        Price::from("0.01"),
243        Quantity::from("0.001"),
244        None,
245        None,
246        Some(Quantity::from("10000.0")),
247        Some(Quantity::from("0.001")),
248        None,
249        Some(Money::new(10.00, Currency::from("USDT"))),
250        Some(Price::from("15000.00")),
251        Some(Price::from("1.0")),
252        Some(dec!(1.0)),
253        Some(dec!(0.35)),
254        Some(dec!(0.0002)),
255        Some(dec!(0.0004)),
256        None, // info
257        UnixNanos::default(),
258        UnixNanos::default(),
259    )
260}
261
262#[fixture]
263pub fn xbtusd_bitmex() -> CryptoPerpetual {
264    CryptoPerpetual::new(
265        InstrumentId::from("BTCUSDT.BITMEX"),
266        Symbol::from("XBTUSD"),
267        Currency::BTC(),
268        Currency::USD(),
269        Currency::BTC(),
270        true,
271        1,
272        0,
273        Price::from("0.5"),
274        Quantity::from("1"),
275        None,
276        None,
277        None,
278        None,
279        Some(Money::from("10000000 USD")),
280        Some(Money::from("1 USD")),
281        Some(Price::from("10000000")),
282        Some(Price::from("0.01")),
283        Some(dec!(0.01)),
284        Some(dec!(0.0035)),
285        Some(dec!(-0.00025)),
286        Some(dec!(0.00075)),
287        None, // info
288        UnixNanos::default(),
289        UnixNanos::default(),
290    )
291}
292
293#[fixture]
294pub fn ethusdt_bitmex() -> CryptoPerpetual {
295    CryptoPerpetual::new(
296        InstrumentId::from("ETHUSD.BITMEX"),
297        Symbol::from("ETHUSD"),
298        Currency::ETH(),
299        Currency::USD(),
300        Currency::ETH(),
301        true,
302        2,
303        0,
304        Price::from("0.05"),
305        Quantity::from("1"),
306        None,
307        None,
308        None,
309        None,
310        None,
311        None,
312        Some(Price::from("10000000")),
313        Some(Price::from("0.01")),
314        Some(dec!(0.01)),
315        Some(dec!(0.0035)),
316        Some(dec!(-0.00025)),
317        Some(dec!(0.00075)),
318        None, // info
319        UnixNanos::default(),
320        UnixNanos::default(),
321    )
322}
323
324////////////////////////////////////////////////////////////////////////////////
325// CurrencyPair
326////////////////////////////////////////////////////////////////////////////////
327
328#[fixture]
329pub fn currency_pair_btcusdt() -> CurrencyPair {
330    CurrencyPair::new(
331        InstrumentId::from("BTCUSDT.BINANCE"),
332        Symbol::from("BTCUSDT"),
333        Currency::from("BTC"),
334        Currency::from("USDT"),
335        2,
336        6,
337        Price::from("0.01"),
338        Quantity::from("0.000001"),
339        None,
340        None,
341        Some(Quantity::from("9000")),
342        Some(Quantity::from("0.000001")),
343        None,
344        None,
345        Some(Price::from("1000000")),
346        Some(Price::from("0.01")),
347        Some(dec!(0.001)),
348        Some(dec!(0.001)),
349        Some(dec!(0.001)),
350        Some(dec!(0.001)),
351        None, // info
352        UnixNanos::default(),
353        UnixNanos::default(),
354    )
355}
356
357#[fixture]
358pub fn currency_pair_ethusdt() -> CurrencyPair {
359    CurrencyPair::new(
360        InstrumentId::from("ETHUSDT.BINANCE"),
361        Symbol::from("ETHUSDT"),
362        Currency::from("ETH"),
363        Currency::from("USDT"),
364        2,
365        5,
366        Price::from("0.01"),
367        Quantity::from("0.00001"),
368        None,
369        None,
370        Some(Quantity::from("9000")),
371        Some(Quantity::from("0.00001")),
372        None,
373        None,
374        Some(Price::from("1000000")),
375        Some(Price::from("0.01")),
376        Some(dec!(0.01)),
377        Some(dec!(0.0035)),
378        Some(dec!(0.0001)),
379        Some(dec!(0.0001)),
380        None, // info
381        UnixNanos::default(),
382        UnixNanos::default(),
383    )
384}
385
386/// # Panics
387///
388/// Panics if `symbol` does not contain a '/' delimiter.
389#[must_use]
390pub fn default_fx_ccy(symbol: Symbol, venue: Option<Venue>) -> CurrencyPair {
391    let target_venue = venue.unwrap_or(Venue::from("SIM"));
392    let instrument_id = InstrumentId::new(symbol, target_venue);
393    let base_currency = symbol.as_str().split('/').next().unwrap();
394    let quote_currency = symbol.as_str().split('/').next_back().unwrap();
395    let price_precision = if quote_currency == "JPY" { 3 } else { 5 };
396    let price_increment = Price::new(
397        1.0 / 10.0f64.powi(i32::from(price_precision)),
398        price_precision,
399    );
400    CurrencyPair::new(
401        instrument_id,
402        symbol,
403        Currency::from(base_currency),
404        Currency::from(quote_currency),
405        price_precision,
406        0,
407        price_increment,
408        Quantity::from("1"),
409        None,
410        Some(Quantity::from("1000")),
411        Some(Quantity::from("1000000")),
412        Some(Quantity::from("100")),
413        None,
414        None,
415        None,
416        None,
417        Some(dec!(0.03)),
418        Some(dec!(0.03)),
419        Some(dec!(0.00002)),
420        Some(dec!(0.00002)),
421        None, // info
422        UnixNanos::default(),
423        UnixNanos::default(),
424    )
425}
426
427#[fixture]
428pub fn audusd_sim() -> CurrencyPair {
429    default_fx_ccy(Symbol::from("AUD/USD"), Some(Venue::from("SIM")))
430}
431
432#[fixture]
433pub fn gbpusd_sim() -> CurrencyPair {
434    default_fx_ccy(Symbol::from("GBP/USD"), Some(Venue::from("SIM")))
435}
436
437#[fixture]
438pub fn usdjpy_idealpro() -> CurrencyPair {
439    default_fx_ccy(Symbol::from("USD/JPY"), Some(Venue::from("IDEALPRO")))
440}
441
442////////////////////////////////////////////////////////////////////////////////
443// Equity
444////////////////////////////////////////////////////////////////////////////////
445
446#[fixture]
447pub fn equity_aapl() -> Equity {
448    Equity::new(
449        InstrumentId::from("AAPL.XNAS"),
450        Symbol::from("AAPL"),
451        Some(Ustr::from("US0378331005")),
452        Currency::from("USD"),
453        2,
454        Price::from("0.01"),
455        None,
456        None,
457        None,
458        None,
459        None,
460        None,
461        None,
462        None,
463        None,
464        None, // info
465        UnixNanos::default(),
466        UnixNanos::default(),
467    )
468}
469
470/// AAPL equity with ITCH-compatible precision (`price_precision=4`).
471#[must_use]
472pub fn equity_aapl_itch() -> Equity {
473    Equity::new(
474        InstrumentId::from("AAPL.XNAS"),
475        Symbol::from("AAPL"),
476        Some(Ustr::from("US0378331005")),
477        Currency::from("USD"),
478        4,
479        Price::from("0.0001"),
480        None,
481        None,
482        None,
483        None,
484        None,
485        None,
486        None,
487        None,
488        None,
489        None,
490        UnixNanos::default(),
491        UnixNanos::default(),
492    )
493}
494
495////////////////////////////////////////////////////////////////////////////////
496// FuturesContract
497////////////////////////////////////////////////////////////////////////////////
498
499/// # Panics
500///
501/// Panics if constructing the activation or expiration timestamp fails,
502/// e.g., if the provided dates are invalid or timestamp conversion returns `None`.
503#[must_use]
504pub fn futures_contract_es(
505    activation: Option<UnixNanos>,
506    expiration: Option<UnixNanos>,
507) -> FuturesContract {
508    let activation = activation.unwrap_or(UnixNanos::from(
509        Utc.with_ymd_and_hms(2021, 9, 10, 0, 0, 0)
510            .unwrap()
511            .timestamp_nanos_opt()
512            .unwrap() as u64,
513    ));
514    let expiration = expiration.unwrap_or(UnixNanos::from(
515        Utc.with_ymd_and_hms(2021, 12, 17, 0, 0, 0)
516            .unwrap()
517            .timestamp_nanos_opt()
518            .unwrap() as u64,
519    ));
520    FuturesContract::new(
521        InstrumentId::from("ESZ21.GLBX"),
522        Symbol::from("ESZ21"),
523        AssetClass::Index,
524        Some(Ustr::from("XCME")),
525        Ustr::from("ES"),
526        activation,
527        expiration,
528        Currency::USD(),
529        2,
530        Price::from("0.01"),
531        Quantity::from(1),
532        Quantity::from(1),
533        None,
534        None,
535        None,
536        None,
537        None,
538        None,
539        None,
540        None,
541        None, // info
542        UnixNanos::default(),
543        UnixNanos::default(),
544    )
545}
546
547////////////////////////////////////////////////////////////////////////////////
548// FuturesSpread
549////////////////////////////////////////////////////////////////////////////////
550
551#[fixture]
552pub fn futures_spread_es() -> FuturesSpread {
553    let activation = Utc.with_ymd_and_hms(2022, 6, 21, 13, 30, 0).unwrap();
554    let expiration = Utc.with_ymd_and_hms(2024, 6, 21, 13, 30, 0).unwrap();
555    FuturesSpread::new(
556        InstrumentId::from("ESM4-ESU4.GLBX"),
557        Symbol::from("ESM4-ESU4"),
558        AssetClass::Index,
559        Some(Ustr::from("XCME")),
560        Ustr::from("ES"),
561        Ustr::from("EQ"),
562        UnixNanos::from(activation.timestamp_nanos_opt().unwrap() as u64),
563        UnixNanos::from(expiration.timestamp_nanos_opt().unwrap() as u64),
564        Currency::USD(),
565        2,
566        Price::from("0.01"),
567        Quantity::from(1),
568        Quantity::from(1),
569        None,
570        None,
571        None,
572        None,
573        None,
574        None,
575        None,
576        None,
577        None, // info
578        UnixNanos::default(),
579        UnixNanos::default(),
580    )
581}
582
583////////////////////////////////////////////////////////////////////////////////
584// OptionContract
585////////////////////////////////////////////////////////////////////////////////
586
587#[fixture]
588pub fn option_contract_appl() -> OptionContract {
589    let activation = Utc.with_ymd_and_hms(2021, 9, 17, 0, 0, 0).unwrap();
590    let expiration = Utc.with_ymd_and_hms(2021, 12, 17, 0, 0, 0).unwrap();
591    OptionContract::new(
592        InstrumentId::from("AAPL211217C00150000.OPRA"),
593        Symbol::from("AAPL211217C00150000"),
594        AssetClass::Equity,
595        Some(Ustr::from("GMNI")),
596        Ustr::from("AAPL"),
597        OptionKind::Call,
598        Price::from("149.0"),
599        Currency::USD(),
600        UnixNanos::from(activation.timestamp_nanos_opt().unwrap() as u64),
601        UnixNanos::from(expiration.timestamp_nanos_opt().unwrap() as u64),
602        2,
603        Price::from("0.01"),
604        Quantity::from(1),
605        Quantity::from(1),
606        None,
607        None,
608        None,
609        None,
610        None,
611        None,
612        None,
613        None,
614        None, // info
615        UnixNanos::default(),
616        UnixNanos::default(),
617    )
618}
619
620////////////////////////////////////////////////////////////////////////////////
621// OptionSpread
622////////////////////////////////////////////////////////////////////////////////
623
624#[fixture]
625pub fn option_spread() -> OptionSpread {
626    let activation = Utc.with_ymd_and_hms(2023, 11, 6, 20, 54, 7).unwrap();
627    let expiration = Utc.with_ymd_and_hms(2024, 2, 23, 22, 59, 0).unwrap();
628    OptionSpread::new(
629        InstrumentId::from("UD:U$: GN 2534559.GLBX"),
630        Symbol::from("UD:U$: GN 2534559"),
631        AssetClass::FX,
632        Some(Ustr::from("XCME")),
633        Ustr::from("SR3"),
634        Ustr::from("GN"),
635        UnixNanos::from(activation.timestamp_nanos_opt().unwrap() as u64),
636        UnixNanos::from(expiration.timestamp_nanos_opt().unwrap() as u64),
637        Currency::USD(),
638        2,
639        Price::from("0.01"),
640        Quantity::from(1),
641        Quantity::from(1),
642        None,
643        None,
644        None,
645        None,
646        None,
647        None,
648        None,
649        None,
650        None, // info
651        UnixNanos::default(),
652        UnixNanos::default(),
653    )
654}
655
656////////////////////////////////////////////////////////////////////////////////
657// BettingInstrument
658////////////////////////////////////////////////////////////////////////////////
659
660#[fixture]
661pub fn betting() -> BettingInstrument {
662    let raw_symbol = Symbol::new("1-123456789");
663    let id = InstrumentId::from(format!("{raw_symbol}.BETFAIR"));
664    let event_type_id = 6423;
665    let event_type_name = Ustr::from("American Football");
666    let competition_id = 12_282_733;
667    let competition_name = Ustr::from("NFL");
668    let event_id = 29_678_534;
669    let event_name = Ustr::from("NFL");
670    let event_country_code = Ustr::from("GB");
671    let event_open_date = UnixNanos::from(
672        Utc.with_ymd_and_hms(2022, 2, 7, 23, 30, 0)
673            .unwrap()
674            .timestamp_nanos_opt()
675            .unwrap() as u64,
676    );
677    let betting_type = Ustr::from("ODDS");
678    let market_id = Ustr::from("1-123456789");
679    let market_name = Ustr::from("AFC Conference Winner");
680    let market_type = Ustr::from("SPECIAL");
681    let market_start_time = UnixNanos::from(
682        Utc.with_ymd_and_hms(2022, 2, 7, 23, 30, 0)
683            .unwrap()
684            .timestamp_nanos_opt()
685            .unwrap() as u64,
686    );
687    let selection_id = 50214;
688    let selection_name = Ustr::from("Kansas City Chiefs");
689    let selection_handicap = 0.0;
690    let currency = Currency::GBP();
691    let price_increment = Price::from("0.01");
692    let size_increment = Quantity::from("0.01");
693    let max_quantity = Some(Quantity::from("1000"));
694    let min_quantity = Some(Quantity::from("1"));
695    let max_notional = Some(Money::from("10000 GBP"));
696    let min_notional = Some(Money::from("10 GBP"));
697    let max_price = Some(Price::from("100.00"));
698    let min_price = Some(Price::from("1.00"));
699    let margin_init = Some(Decimal::from(1));
700    let margin_maint = Some(Decimal::from(1));
701    let maker_fee = Some(Decimal::from(0));
702    let taker_fee = Some(Decimal::from(0));
703    let ts_event = UnixNanos::default();
704    let ts_init = UnixNanos::default();
705
706    BettingInstrument::new(
707        id,
708        raw_symbol,
709        event_type_id,
710        event_type_name,
711        competition_id,
712        competition_name,
713        event_id,
714        event_name,
715        event_country_code,
716        event_open_date,
717        betting_type,
718        market_id,
719        market_name,
720        market_type,
721        market_start_time,
722        selection_id,
723        selection_name,
724        selection_handicap,
725        currency,
726        price_increment.precision,
727        size_increment.precision,
728        price_increment,
729        size_increment,
730        max_quantity,
731        min_quantity,
732        max_notional,
733        min_notional,
734        max_price,
735        min_price,
736        margin_init,
737        margin_maint,
738        maker_fee,
739        taker_fee,
740        None, // info
741        ts_event,
742        ts_init,
743    )
744}
745
746#[fixture]
747pub fn commodity_gold() -> Commodity {
748    Commodity::new(
749        InstrumentId::from("GOLD.COMEX"),
750        Symbol::from("GOLD"),
751        AssetClass::Commodity,
752        Currency::from("USD"),
753        2,
754        0,
755        Price::from("0.01"),
756        Quantity::from("1"),
757        Some(Quantity::from("1")),
758        None,
759        None,
760        None,
761        None,
762        None,
763        None,
764        None,
765        None,
766        None,
767        None,
768        None, // info
769        UnixNanos::default(),
770        UnixNanos::default(),
771    )
772}
773
774#[fixture]
775pub fn index_instrument_spx() -> IndexInstrument {
776    IndexInstrument::new(
777        InstrumentId::from("SPX.INDEX"),
778        Symbol::from("SPX"),
779        Currency::from("USD"),
780        2,
781        0,
782        Price::from("0.01"),
783        Quantity::from("1"),
784        None, // info
785        UnixNanos::default(),
786        UnixNanos::default(),
787    )
788}
789
790#[fixture]
791pub fn cfd_gold() -> Cfd {
792    Cfd::new(
793        InstrumentId::from("GOLD-CFD.SIM"),
794        Symbol::from("GOLD-CFD"),
795        AssetClass::Commodity,
796        None,
797        Currency::from("USD"),
798        2,
799        0,
800        Price::from("0.01"),
801        Quantity::from("1"),
802        Some(Quantity::from("1")),
803        None,
804        None,
805        None,
806        None,
807        None,
808        None,
809        None,
810        None,
811        None,
812        None,
813        None, // info
814        UnixNanos::default(),
815        UnixNanos::default(),
816    )
817}
818
819////////////////////////////////////////////////////////////////////////////////
820// PerpetualContract
821////////////////////////////////////////////////////////////////////////////////
822
823#[fixture]
824pub fn perpetual_contract_eurusd() -> PerpetualContract {
825    PerpetualContract::new(
826        InstrumentId::from("EURUSD-PERP.AX"),
827        Symbol::from("EURUSD-PERP"),
828        Ustr::from("EURUSD"),
829        AssetClass::FX,
830        Some(Currency::from("EUR")),
831        Currency::from("USD"),
832        Currency::from("USD"),
833        false,
834        5,
835        0,
836        Price::from("0.00001"),
837        Quantity::from("1"),
838        None,
839        None,
840        None,
841        None,
842        None,
843        None,
844        None,
845        None,
846        Some(dec!(0.03)),
847        Some(dec!(0.03)),
848        Some(dec!(0.00002)),
849        Some(dec!(0.00002)),
850        None, // info
851        UnixNanos::default(),
852        UnixNanos::default(),
853    )
854}
855
856////////////////////////////////////////////////////////////////////////////////
857// BinaryOption
858////////////////////////////////////////////////////////////////////////////////
859
860#[fixture]
861pub fn binary_option() -> BinaryOption {
862    let raw_symbol = Symbol::new(
863        "0x12a0cb60174abc437bf1178367c72d11f069e1a3add20b148fb0ab4279b772b2-92544998123698303655208967887569360731013655782348975589292031774495159624905",
864    );
865    let activation = Utc.with_ymd_and_hms(2023, 11, 6, 20, 54, 7).unwrap();
866    let expiration = Utc.with_ymd_and_hms(2024, 2, 23, 22, 59, 0).unwrap();
867    let price_increment = Price::from("0.001");
868    let size_increment = Quantity::from("0.01");
869    BinaryOption::new(
870        InstrumentId::from("{raw_symbol}.POLYMARKET"),
871        raw_symbol,
872        AssetClass::Alternative,
873        Currency::USDC(),
874        UnixNanos::from(activation.timestamp_nanos_opt().unwrap() as u64),
875        UnixNanos::from(expiration.timestamp_nanos_opt().unwrap() as u64),
876        price_increment.precision,
877        size_increment.precision,
878        price_increment,
879        size_increment,
880        None,
881        None,
882        None,
883        None,
884        None,
885        None,
886        None,
887        None,
888        None,
889        None,
890        None,
891        None,
892        None, // info
893        UnixNanos::default(),
894        UnixNanos::default(),
895    )
896}
897
898#[fixture]
899pub fn tokenized_asset_aaplx() -> TokenizedAsset {
900    TokenizedAsset::new(
901        InstrumentId::from("AAPLx/USD.KRAKEN"),
902        Symbol::from("AAPLxUSD"),
903        AssetClass::Equity,
904        Currency::get_or_create_crypto("AAPLx"),
905        Currency::from("USD"),
906        None,
907        2,
908        4,
909        Price::from("0.01"),
910        Quantity::from("0.0001"),
911        None,
912        None,
913        None,
914        Some(Quantity::from("0.0001")),
915        None,
916        None,
917        None,
918        None,
919        None,
920        None,
921        Some(dec!(-0.0002)),
922        Some(dec!(0.001)),
923        None, // info
924        UnixNanos::default(),
925        UnixNanos::default(),
926    )
927}