1#![forbid(unsafe_code)]
2#![deny(
3 clippy::unwrap_used,
4 clippy::expect_used,
5 clippy::cast_possible_truncation,
6 clippy::cast_sign_loss
7)]
8#![warn(
9 unused,
10 clippy::cognitive_complexity,
11 unused_crate_dependencies,
12 unused_extern_crates,
13 clippy::unused_self,
14 clippy::useless_let_if_seq,
15 missing_debug_implementations,
16 rust_2018_idioms
17)]
18#![allow(clippy::type_complexity, clippy::too_many_arguments, type_alias_bounds)]
19
20use derive_more::Constructor;
27use serde::{Deserialize, Serialize};
28use std::fmt::{Display, Formatter};
29
30pub mod exchange;
32
33pub mod asset;
37
38pub mod instrument;
42
43pub mod index;
46
47#[cfg(feature = "ibkr")]
49pub mod ibkr;
50
51#[derive(
55 Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Constructor,
56)]
57pub struct Keyed<Key, Value> {
58 pub key: Key,
59 pub value: Value,
60}
61
62impl<Key, Value> AsRef<Value> for Keyed<Key, Value> {
63 fn as_ref(&self) -> &Value {
64 &self.value
65 }
66}
67
68impl<Key, Value> Display for Keyed<Key, Value>
69where
70 Key: Display,
71 Value: Display,
72{
73 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
74 write!(f, "{}, {}", self.key, self.value)
75 }
76}
77
78#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
82pub struct Underlying<AssetKey> {
83 pub base: AssetKey,
84 pub quote: AssetKey,
85}
86
87impl<AssetKey> Underlying<AssetKey> {
88 pub fn new<A>(base: A, quote: A) -> Self
89 where
90 A: Into<AssetKey>,
91 {
92 Self {
93 base: base.into(),
94 quote: quote.into(),
95 }
96 }
97}
98
99#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
101pub enum Side {
102 #[serde(alias = "buy", alias = "BUY", alias = "b")]
103 Buy,
104 #[serde(alias = "sell", alias = "SELL", alias = "s")]
105 Sell,
106}
107
108impl Display for Side {
109 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
110 write!(
111 f,
112 "{}",
113 match self {
114 Side::Buy => "buy",
115 Side::Sell => "sell",
116 }
117 )
118 }
119}
120
121pub mod test_utils {
122 use crate::{
123 Underlying,
124 asset::{
125 Asset, ExchangeAsset,
126 name::{AssetNameExchange, AssetNameInternal},
127 },
128 exchange::ExchangeId,
129 instrument::{
130 Instrument,
131 kind::InstrumentKind,
132 name::{InstrumentNameExchange, InstrumentNameInternal},
133 quote::InstrumentQuoteAsset,
134 },
135 };
136
137 pub fn exchange_asset(exchange: ExchangeId, symbol: &str) -> ExchangeAsset<Asset> {
138 ExchangeAsset {
139 exchange,
140 asset: asset(symbol),
141 }
142 }
143
144 pub fn asset(symbol: &str) -> Asset {
145 Asset {
146 name_internal: AssetNameInternal::from(symbol),
147 name_exchange: AssetNameExchange::from(symbol),
148 }
149 }
150
151 pub fn instrument(
152 exchange: ExchangeId,
153 base: &str,
154 quote: &str,
155 ) -> Instrument<ExchangeId, Asset> {
156 let name_exchange = InstrumentNameExchange::from(format!("{base}_{quote}"));
157 let name_internal =
158 InstrumentNameInternal::new_from_exchange(exchange, name_exchange.clone());
159 let base_asset = asset(base);
160 let quote_asset = asset(quote);
161
162 Instrument::new(
163 exchange,
164 name_internal,
165 name_exchange,
166 Underlying::new(base_asset, quote_asset),
167 InstrumentQuoteAsset::UnderlyingQuote,
168 InstrumentKind::Spot,
169 None,
170 )
171 }
172}