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