1use crate::error::KeyError;
2use barter_instrument::{
3 Keyed,
4 asset::{AssetIndex, name::AssetNameExchange},
5 exchange::{ExchangeId, ExchangeIndex},
6 index::{IndexedInstruments, error::IndexError},
7 instrument::{InstrumentIndex, name::InstrumentNameExchange},
8};
9use barter_integration::collection::{FnvIndexMap, FnvIndexSet};
10use fnv::FnvHashMap;
11
12#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct ExecutionInstrumentMap {
23 pub exchange: Keyed<ExchangeIndex, ExchangeId>,
24 pub assets: FnvIndexSet<AssetNameExchange>,
25 pub instruments: FnvIndexSet<InstrumentNameExchange>,
26 pub asset_names: FnvHashMap<AssetNameExchange, AssetIndex>,
27 pub instrument_names: FnvHashMap<InstrumentNameExchange, InstrumentIndex>,
28}
29
30impl ExecutionInstrumentMap {
31 pub fn new(
33 exchange: Keyed<ExchangeIndex, ExchangeId>,
34 assets: FnvIndexMap<AssetIndex, AssetNameExchange>,
35 instruments: FnvIndexMap<InstrumentIndex, InstrumentNameExchange>,
36 ) -> Self {
37 Self {
38 exchange,
39 asset_names: assets
40 .iter()
41 .map(|(key, value)| (value.clone(), *key))
42 .collect(),
43 instrument_names: instruments
44 .iter()
45 .map(|(key, value)| (value.clone(), *key))
46 .collect(),
47 assets: assets.into_values().collect(),
48 instruments: instruments.into_values().collect(),
49 }
50 }
51
52 pub fn exchange_assets(&self) -> impl Iterator<Item = &AssetNameExchange> {
53 self.assets.iter()
54 }
55
56 pub fn exchange_instruments(&self) -> impl Iterator<Item = &InstrumentNameExchange> {
57 self.instruments.iter()
58 }
59
60 pub fn find_exchange_id(&self, exchange: ExchangeIndex) -> Result<ExchangeId, KeyError> {
61 if self.exchange.key == exchange {
62 Ok(self.exchange.value)
63 } else {
64 Err(KeyError::ExchangeId(format!(
65 "ExecutionInstrumentMap does not contain {exchange}"
66 )))
67 }
68 }
69
70 pub fn find_exchange_index(&self, exchange: ExchangeId) -> Result<ExchangeIndex, IndexError> {
71 if self.exchange.value == exchange {
72 Ok(self.exchange.key)
73 } else {
74 Err(IndexError::ExchangeIndex(format!(
75 "ExecutionInstrumentMap does not contain {exchange}"
76 )))
77 }
78 }
79
80 pub fn find_asset_name_exchange(
81 &self,
82 asset: AssetIndex,
83 ) -> Result<&AssetNameExchange, KeyError> {
84 self.assets.get_index(asset.index()).ok_or_else(|| {
85 KeyError::AssetKey(format!("ExecutionInstrumentMap does not contain: {asset}"))
86 })
87 }
88
89 pub fn find_asset_index(&self, asset: &AssetNameExchange) -> Result<AssetIndex, IndexError> {
90 self.asset_names.get(asset).copied().ok_or_else(|| {
91 IndexError::AssetIndex(format!("ExecutionInstrumentMap does not contain: {asset}"))
92 })
93 }
94
95 pub fn find_instrument_name_exchange(
96 &self,
97 instrument: InstrumentIndex,
98 ) -> Result<&InstrumentNameExchange, KeyError> {
99 self.instruments
100 .get_index(instrument.index())
101 .ok_or_else(|| {
102 KeyError::InstrumentKey(format!(
103 "ExecutionInstrumentMap does not contain: {instrument}"
104 ))
105 })
106 }
107
108 pub fn find_instrument_index(
109 &self,
110 instrument: &InstrumentNameExchange,
111 ) -> Result<InstrumentIndex, IndexError> {
112 self.instrument_names
113 .get(instrument)
114 .copied()
115 .ok_or_else(|| {
116 IndexError::InstrumentIndex(format!(
117 "ExecutionInstrumentMap does not contain: {instrument}"
118 ))
119 })
120 }
121}
122
123pub fn generate_execution_instrument_map(
124 instruments: &IndexedInstruments,
125 exchange: ExchangeId,
126) -> Result<ExecutionInstrumentMap, IndexError> {
127 let exchange_index = instruments
128 .exchanges()
129 .iter()
130 .find_map(|keyed_exchange| (keyed_exchange.value == exchange).then_some(keyed_exchange.key))
131 .ok_or_else(|| {
132 IndexError::ExchangeIndex(format!(
133 "IndexedInstrument does not contain index for: {exchange}"
134 ))
135 })?;
136
137 Ok(ExecutionInstrumentMap::new(
138 Keyed::new(exchange_index, exchange),
139 instruments
140 .assets()
141 .iter()
142 .filter_map(|asset| {
143 (asset.value.exchange == exchange)
144 .then_some((asset.key, asset.value.asset.name_exchange.clone()))
145 })
146 .collect(),
147 instruments
148 .instruments()
149 .iter()
150 .filter_map(|instrument| {
151 (instrument.value.exchange.value == exchange)
152 .then_some((instrument.key, instrument.value.name_exchange.clone()))
153 })
154 .collect(),
155 ))
156}