use crate::{
Identifier,
exchange::{Connector, subscription::ExchangeSub},
instrument::InstrumentData,
subscriber::mapper::SubscriptionMapper,
subscription::{Map, Subscription, SubscriptionKind, SubscriptionMeta},
};
use fnv::FnvHashMap;
use rustrade_integration::subscription::SubscriptionId;
use serde::{Deserialize, Serialize};
pub(super) fn subscription_id(symbol: &str) -> SubscriptionId {
SubscriptionId::from(symbol)
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
pub struct LseSubMapper;
impl SubscriptionMapper for LseSubMapper {
fn map<Exchange, Instrument, Kind>(
subscriptions: &[Subscription<Exchange, Instrument, Kind>],
) -> SubscriptionMeta<Instrument::Key>
where
Exchange: Connector,
Instrument: InstrumentData,
Kind: SubscriptionKind,
Subscription<Exchange, Instrument, Kind>:
Identifier<Exchange::Channel> + Identifier<Exchange::Market>,
{
let mut instrument_map = Map(FnvHashMap::with_capacity_and_hasher(
subscriptions.len(),
Default::default(),
));
let exchange_subs = subscriptions
.iter()
.map(|subscription| {
let exchange_sub =
ExchangeSub::<Exchange::Channel, Exchange::Market>::new(subscription);
instrument_map.0.insert(
subscription_id(exchange_sub.market.as_ref()),
subscription.instrument.key().clone(),
);
exchange_sub
})
.collect::<Vec<_>>();
SubscriptionMeta {
instrument_map,
ws_subscriptions: Exchange::requests(exchange_subs),
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)] mod tests {
use super::*;
use crate::{exchange::lse::LseOptions, subscription::trade::PublicTrades};
use rust_decimal_macros::dec;
use rustrade_instrument::instrument::{
kind::option::{OptionExercise, OptionKind},
market_data::{
MarketDataInstrument,
kind::{MarketDataInstrumentKind, MarketDataOptionContract},
},
};
const LONGEST_CONTRACT: &str = "GOOGLX261231C01234500";
#[test]
fn the_longest_option_contract_is_filed_inline() {
assert_eq!(LONGEST_CONTRACT.len(), 21);
let id = subscription_id(LONGEST_CONTRACT);
assert_eq!(id.as_ref(), LONGEST_CONTRACT);
assert!(!id.0.is_heap_allocated());
}
#[test]
fn the_instrument_map_files_a_contract_under_its_bare_symbol() {
let subscription: Subscription<LseOptions, MarketDataInstrument, PublicTrades> =
Subscription::from((
LseOptions::default(),
"googl",
"usd",
MarketDataInstrumentKind::Option(MarketDataOptionContract {
kind: OptionKind::Call,
exercise: OptionExercise::American,
expiry: "2026-09-30T20:00:00Z".parse().unwrap(),
strike: dec!(700),
}),
PublicTrades,
));
let SubscriptionMeta { instrument_map, .. } =
LseSubMapper::map(std::slice::from_ref(&subscription));
let (id, instrument) = instrument_map.0.iter().next().unwrap();
assert_eq!(instrument_map.0.len(), 1);
assert_eq!(id, &subscription_id("GOOGL260930C00700000"));
assert!(!id.0.is_heap_allocated());
assert_eq!(instrument, &subscription.instrument);
}
}