Skip to main content

rustrade_data/
instrument.rs

1use rustrade_instrument::{
2    Keyed,
3    instrument::{
4        Instrument,
5        market_data::{MarketDataInstrument, kind::MarketDataInstrumentKind},
6        name::InstrumentNameExchange,
7    },
8};
9use serde::{Deserialize, Serialize};
10use std::fmt::Debug;
11
12/// Instrument related data that defines an associated unique `Id`.
13///
14/// Verbose `InstrumentData` is often used to subscribe to market data feeds, but it's unique `Id`
15/// can then be used to key consumed [MarketEvents](crate::event::MarketEvent), significantly reducing
16/// duplication in the case of complex instruments (eg/ options).
17pub trait InstrumentData
18where
19    Self: Clone + Debug + Send + Sync,
20{
21    type Key: Debug + Clone + Eq + Send + Sync;
22    fn key(&self) -> &Self::Key;
23    fn kind(&self) -> &MarketDataInstrumentKind;
24}
25
26impl<InstrumentKey> InstrumentData for Keyed<InstrumentKey, MarketDataInstrument>
27where
28    InstrumentKey: Debug + Clone + Eq + Send + Sync,
29{
30    type Key = InstrumentKey;
31
32    fn key(&self) -> &Self::Key {
33        &self.key
34    }
35
36    fn kind(&self) -> &MarketDataInstrumentKind {
37        &self.value.kind
38    }
39}
40
41impl InstrumentData for MarketDataInstrument {
42    type Key = Self;
43
44    fn key(&self) -> &Self::Key {
45        self
46    }
47
48    fn kind(&self) -> &MarketDataInstrumentKind {
49        &self.kind
50    }
51}
52
53#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
54pub struct MarketInstrumentData<InstrumentKey> {
55    pub key: InstrumentKey,
56    pub name_exchange: InstrumentNameExchange,
57    pub kind: MarketDataInstrumentKind,
58}
59
60#[cfg(feature = "hyperliquid")]
61impl<InstrumentKey> MarketInstrumentData<InstrumentKey> {
62    /// A Hyperliquid perpetual, keyed by `key`, to subscribe to with
63    /// [`Hyperliquid`](crate::exchange::hyperliquid::Hyperliquid).
64    ///
65    /// Find `perp` with
66    /// [`HyperliquidMeta::perp_coin`](crate::exchange::hyperliquid::HyperliquidMeta::perp_coin),
67    /// so the subscription names its coin as Hyperliquid spells it.
68    pub fn hyperliquid_perp(
69        key: InstrumentKey,
70        perp: &rustrade_instrument::hyperliquid::PerpCoin,
71    ) -> Self {
72        Self {
73            key,
74            name_exchange: InstrumentNameExchange::from(perp.coin()),
75            kind: MarketDataInstrumentKind::Perpetual,
76        }
77    }
78
79    /// A Hyperliquid spot pair, keyed by `key`, to subscribe to with
80    /// [`HyperliquidSpot`](crate::exchange::hyperliquid::HyperliquidSpot).
81    ///
82    /// Find `pair` with
83    /// [`HyperliquidMeta::spot_pair`](crate::exchange::hyperliquid::HyperliquidMeta::spot_pair),
84    /// so the subscription names its coin (`@107`) rather than its tokens.
85    pub fn hyperliquid_spot(
86        key: InstrumentKey,
87        pair: &rustrade_instrument::hyperliquid::SpotPair,
88    ) -> Self {
89        Self {
90            key,
91            name_exchange: InstrumentNameExchange::from(pair.coin()),
92            kind: MarketDataInstrumentKind::Spot,
93        }
94    }
95}
96
97impl<InstrumentKey> InstrumentData for MarketInstrumentData<InstrumentKey>
98where
99    InstrumentKey: Debug + Clone + Eq + Send + Sync,
100{
101    type Key = InstrumentKey;
102
103    fn key(&self) -> &Self::Key {
104        &self.key
105    }
106
107    fn kind(&self) -> &MarketDataInstrumentKind {
108        &self.kind
109    }
110}
111
112impl<InstrumentKey> std::fmt::Display for MarketInstrumentData<InstrumentKey>
113where
114    InstrumentKey: std::fmt::Display,
115{
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        write!(
118            f,
119            "{}_{}_{}",
120            self.key,
121            self.name_exchange.as_ref(),
122            self.kind
123        )
124    }
125}
126
127impl<ExchangeKey, AssetKey, InstrumentKey>
128    From<&Keyed<InstrumentKey, Instrument<ExchangeKey, AssetKey>>>
129    for MarketInstrumentData<InstrumentKey>
130where
131    InstrumentKey: Clone,
132{
133    fn from(value: &Keyed<InstrumentKey, Instrument<ExchangeKey, AssetKey>>) -> Self {
134        Self {
135            key: value.key.clone(),
136            // The DATA venue's symbol, not the execution venue's. These differ whenever the two
137            // venues spell one instrument differently (`BP.L` against `BP`), and subscribing under
138            // the execution venue's name would silently yield no ticks -- or another instrument's.
139            // Falls back to `name_exchange` for every single-venue instrument.
140            name_exchange: value.value.data_name_exchange().clone(),
141            kind: MarketDataInstrumentKind::from(&value.value.kind),
142        }
143    }
144}