rustrade_data/exchange/lse/
mapper.rs1use crate::{
5 Identifier,
6 exchange::{Connector, subscription::ExchangeSub},
7 instrument::InstrumentData,
8 subscriber::mapper::SubscriptionMapper,
9 subscription::{Map, Subscription, SubscriptionKind, SubscriptionMeta},
10};
11use fnv::FnvHashMap;
12use rustrade_integration::subscription::SubscriptionId;
13use serde::{Deserialize, Serialize};
14
15pub(super) fn subscription_id(symbol: &str) -> SubscriptionId {
33 SubscriptionId::from(symbol)
34}
35
36#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
46pub struct LseSubMapper;
47
48impl SubscriptionMapper for LseSubMapper {
49 fn map<Exchange, Instrument, Kind>(
50 subscriptions: &[Subscription<Exchange, Instrument, Kind>],
51 ) -> SubscriptionMeta<Instrument::Key>
52 where
53 Exchange: Connector,
54 Instrument: InstrumentData,
55 Kind: SubscriptionKind,
56 Subscription<Exchange, Instrument, Kind>:
57 Identifier<Exchange::Channel> + Identifier<Exchange::Market>,
58 {
59 let mut instrument_map = Map(FnvHashMap::with_capacity_and_hasher(
60 subscriptions.len(),
61 Default::default(),
62 ));
63
64 let exchange_subs = subscriptions
65 .iter()
66 .map(|subscription| {
67 let exchange_sub =
68 ExchangeSub::<Exchange::Channel, Exchange::Market>::new(subscription);
69
70 instrument_map.0.insert(
71 subscription_id(exchange_sub.market.as_ref()),
72 subscription.instrument.key().clone(),
73 );
74
75 exchange_sub
76 })
77 .collect::<Vec<_>>();
78
79 SubscriptionMeta {
80 instrument_map,
81 ws_subscriptions: Exchange::requests(exchange_subs),
82 }
83 }
84}
85
86#[cfg(test)]
87#[allow(clippy::unwrap_used)] mod tests {
89 use super::*;
90 use crate::{exchange::lse::LseOptions, subscription::trade::PublicTrades};
91 use rust_decimal_macros::dec;
92 use rustrade_instrument::instrument::{
93 kind::option::{OptionExercise, OptionKind},
94 market_data::{
95 MarketDataInstrument,
96 kind::{MarketDataInstrumentKind, MarketDataOptionContract},
97 },
98 };
99
100 const LONGEST_CONTRACT: &str = "GOOGLX261231C01234500";
102
103 #[test]
104 fn the_longest_option_contract_is_filed_inline() {
105 assert_eq!(LONGEST_CONTRACT.len(), 21);
106
107 let id = subscription_id(LONGEST_CONTRACT);
108
109 assert_eq!(id.as_ref(), LONGEST_CONTRACT);
110 assert!(!id.0.is_heap_allocated());
111 }
112
113 #[test]
116 fn the_instrument_map_files_a_contract_under_its_bare_symbol() {
117 let subscription: Subscription<LseOptions, MarketDataInstrument, PublicTrades> =
118 Subscription::from((
119 LseOptions::default(),
120 "googl",
121 "usd",
122 MarketDataInstrumentKind::Option(MarketDataOptionContract {
123 kind: OptionKind::Call,
124 exercise: OptionExercise::American,
125 expiry: "2026-09-30T20:00:00Z".parse().unwrap(),
126 strike: dec!(700),
127 }),
128 PublicTrades,
129 ));
130
131 let SubscriptionMeta { instrument_map, .. } =
132 LseSubMapper::map(std::slice::from_ref(&subscription));
133
134 let (id, instrument) = instrument_map.0.iter().next().unwrap();
135 assert_eq!(instrument_map.0.len(), 1);
136 assert_eq!(id, &subscription_id("GOOGL260930C00700000"));
137 assert!(!id.0.is_heap_allocated());
138 assert_eq!(instrument, &subscription.instrument);
139 }
140}