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