Skip to main content

rustrade_data/
event.rs

1use crate::{
2    error::DataError,
3    streams::consumer::MarketStreamResult,
4    subscription::{
5        book::{OrderBookEvent, OrderBookL1},
6        candle::Candle,
7        greeks::OptionGreeks,
8        liquidation::Liquidation,
9        trade::PublicTrade,
10    },
11};
12use chrono::{DateTime, Utc};
13use derive_more::From;
14use rustrade_instrument::{exchange::ExchangeId, instrument::market_data::MarketDataInstrument};
15use serde::{Deserialize, Serialize};
16
17/// Convenient new type containing a collection of [`MarketEvent<T>`](MarketEvent)s.
18#[derive(Debug)]
19pub struct MarketIter<InstrumentKey, T>(pub Vec<Result<MarketEvent<InstrumentKey, T>, DataError>>);
20
21impl<InstrumentKey, T> FromIterator<Result<MarketEvent<InstrumentKey, T>, DataError>>
22    for MarketIter<InstrumentKey, T>
23{
24    fn from_iter<Iter>(iter: Iter) -> Self
25    where
26        Iter: IntoIterator<Item = Result<MarketEvent<InstrumentKey, T>, DataError>>,
27    {
28        Self(iter.into_iter().collect())
29    }
30}
31
32/// Normalised Barter [`MarketEvent<T>`](Self) wrapping the `T` data variant in metadata.
33///
34/// Note: `T` can be an enum such as the [`DataKind`] if required.
35///
36/// See [`crate::subscription`] for all existing Barter Market event variants.
37///
38/// ### Examples
39/// - [`MarketEvent<PublicTrade>`](PublicTrade)
40/// - [`MarketEvent<OrderBookL1>`](OrderBookL1)
41/// - [`MarketEvent<DataKind>`](DataKind)
42#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
43pub struct MarketEvent<InstrumentKey = MarketDataInstrument, T = DataKind> {
44    /// Exchange timestamp of the event — its position on the **engine timeline**.
45    ///
46    /// A consuming engine treats this as *the* time the event occurred: the
47    /// historical/backtest clock derives "current time" from it and replays
48    /// events in `time_exchange` order (see `rustrade`'s `EngineClock` /
49    /// `TimeExchange`).
50    ///
51    /// # Contract for aggregated / windowed payloads (candles, OHLCV bars)
52    ///
53    /// For a point-in-time payload (e.g. [`PublicTrade`], [`OrderBookL1`]) this is
54    /// simply the venue event time. For a payload that aggregates a **time window**
55    /// (a [`Candle`]), `time_exchange` **must be the period END**, i.e. the
56    /// candle's [`close_time`](crate::subscription::candle::Candle::close_time) —
57    /// **never the period start**.
58    ///
59    /// Stamping the open instant makes a *completed* bar enter the engine timeline
60    /// at the moment its period *began*, so a strategy would act on a fully-formed
61    /// bar before it could possibly exist — silent lookahead / repaint bias. This
62    /// applies to **any** windowed payload, including a custom `T` supplied by a
63    /// consumer driving the engine without this crate's producers. The library's
64    /// own candle producers already stamp `close_time` here; when wrapping a
65    /// [`Candle`] into a `MarketEvent` yourself, use its `close_time`.
66    pub time_exchange: DateTime<Utc>,
67    /// Local timestamp at which this event was received/decoded. Diagnostic only —
68    /// the engine clock and replay ordering use [`time_exchange`](Self::time_exchange).
69    pub time_received: DateTime<Utc>,
70    pub exchange: ExchangeId,
71    pub instrument: InstrumentKey,
72    pub kind: T,
73}
74
75impl<InstrumentKey, T> MarketEvent<InstrumentKey, T> {
76    pub fn map_kind<F, O>(self, op: F) -> MarketEvent<InstrumentKey, O>
77    where
78        F: FnOnce(T) -> O,
79    {
80        MarketEvent {
81            time_exchange: self.time_exchange,
82            time_received: self.time_received,
83            exchange: self.exchange,
84            instrument: self.instrument,
85            kind: op(self.kind),
86        }
87    }
88}
89
90impl<InstrumentKey> MarketEvent<InstrumentKey, DataKind> {
91    pub fn as_public_trade(&self) -> Option<MarketEvent<&InstrumentKey, &PublicTrade>> {
92        match &self.kind {
93            DataKind::Trade(public_trade) => Some(self.as_event(public_trade)),
94            _ => None,
95        }
96    }
97
98    pub fn as_order_book_l1(&self) -> Option<MarketEvent<&InstrumentKey, &OrderBookL1>> {
99        match &self.kind {
100            DataKind::OrderBookL1(orderbook) => Some(self.as_event(orderbook)),
101            _ => None,
102        }
103    }
104
105    pub fn as_order_book(&self) -> Option<MarketEvent<&InstrumentKey, &OrderBookEvent>> {
106        match &self.kind {
107            DataKind::OrderBook(orderbook) => Some(self.as_event(orderbook)),
108            _ => None,
109        }
110    }
111
112    pub fn as_candle(&self) -> Option<MarketEvent<&InstrumentKey, &Candle>> {
113        match &self.kind {
114            DataKind::Candle(candle) => Some(self.as_event(candle)),
115            _ => None,
116        }
117    }
118
119    pub fn as_liquidation(&self) -> Option<MarketEvent<&InstrumentKey, &Liquidation>> {
120        match &self.kind {
121            DataKind::Liquidation(liquidation) => Some(self.as_event(liquidation)),
122            _ => None,
123        }
124    }
125
126    pub fn as_option_greeks(&self) -> Option<MarketEvent<&InstrumentKey, &OptionGreeks>> {
127        match &self.kind {
128            DataKind::OptionGreeks(greeks) => Some(self.as_event(greeks)),
129            _ => None,
130        }
131    }
132
133    fn as_event<'a, K>(&'a self, kind: &'a K) -> MarketEvent<&'a InstrumentKey, &'a K> {
134        MarketEvent {
135            time_exchange: self.time_exchange,
136            time_received: self.time_received,
137            exchange: self.exchange,
138            instrument: &self.instrument,
139            kind,
140        }
141    }
142}
143
144/// Available kinds of normalised Barter [`MarketEvent<T>`](MarketEvent).
145///
146/// ### Notes
147/// - [`Self`] is only used as the [`MarketEvent<DataKind>`](MarketEvent) `Output` when combining
148///   several [`Streams<SubscriptionKind::Event>`](crate::streams::Streams) using the
149///   [`MultiStreamBuilder<Output>`](crate::streams::builder::multi::MultiStreamBuilder), or via
150///   the [`DynamicStreams::select_all`](crate::streams::builder::dynamic::DynamicStreams) method.
151/// - [`Self`] is purposefully not supported in any
152///   [`Subscription`](crate::subscription::Subscription)s directly, it is only used to
153///   make ergonomic [`Streams`](crate::streams::Streams) containing many
154///   [`MarketEvent<T>`](MarketEvent) kinds.
155#[derive(Clone, PartialEq, Debug, Deserialize, Serialize, From)]
156pub enum DataKind {
157    Trade(PublicTrade),
158    OrderBookL1(OrderBookL1),
159    OrderBook(OrderBookEvent),
160    Candle(Candle),
161    Liquidation(Liquidation),
162    OptionGreeks(OptionGreeks),
163}
164
165impl DataKind {
166    pub fn kind_name(&self) -> &str {
167        match self {
168            DataKind::Trade(_) => "public_trade",
169            DataKind::OrderBookL1(_) => "l1",
170            DataKind::OrderBook(_) => "l2",
171            DataKind::Candle(_) => "candle",
172            DataKind::Liquidation(_) => "liquidation",
173            DataKind::OptionGreeks(_) => "option_greeks",
174        }
175    }
176}
177
178impl<InstrumentKey> From<MarketEvent<InstrumentKey, OptionGreeks>>
179    for MarketEvent<InstrumentKey, DataKind>
180{
181    fn from(value: MarketEvent<InstrumentKey, OptionGreeks>) -> Self {
182        value.map_kind(OptionGreeks::into)
183    }
184}
185
186impl<InstrumentKey> From<MarketStreamResult<InstrumentKey, OptionGreeks>>
187    for MarketStreamResult<InstrumentKey, DataKind>
188{
189    fn from(value: MarketStreamResult<InstrumentKey, OptionGreeks>) -> Self {
190        value.map_ok(MarketEvent::from)
191    }
192}
193
194impl<InstrumentKey> From<MarketStreamResult<InstrumentKey, PublicTrade>>
195    for MarketStreamResult<InstrumentKey, DataKind>
196{
197    fn from(value: MarketStreamResult<InstrumentKey, PublicTrade>) -> Self {
198        value.map_ok(MarketEvent::from)
199    }
200}
201
202impl<InstrumentKey> From<MarketEvent<InstrumentKey, PublicTrade>>
203    for MarketEvent<InstrumentKey, DataKind>
204{
205    fn from(value: MarketEvent<InstrumentKey, PublicTrade>) -> Self {
206        value.map_kind(PublicTrade::into)
207    }
208}
209
210impl<InstrumentKey> From<MarketStreamResult<InstrumentKey, OrderBookL1>>
211    for MarketStreamResult<InstrumentKey, DataKind>
212{
213    fn from(value: MarketStreamResult<InstrumentKey, OrderBookL1>) -> Self {
214        value.map_ok(MarketEvent::from)
215    }
216}
217
218impl<InstrumentKey> From<MarketEvent<InstrumentKey, OrderBookL1>>
219    for MarketEvent<InstrumentKey, DataKind>
220{
221    fn from(value: MarketEvent<InstrumentKey, OrderBookL1>) -> Self {
222        value.map_kind(OrderBookL1::into)
223    }
224}
225
226impl<InstrumentKey> From<MarketStreamResult<InstrumentKey, OrderBookEvent>>
227    for MarketStreamResult<InstrumentKey, DataKind>
228{
229    fn from(value: MarketStreamResult<InstrumentKey, OrderBookEvent>) -> Self {
230        value.map_ok(MarketEvent::from)
231    }
232}
233
234impl<InstrumentKey> From<MarketEvent<InstrumentKey, OrderBookEvent>>
235    for MarketEvent<InstrumentKey, DataKind>
236{
237    fn from(value: MarketEvent<InstrumentKey, OrderBookEvent>) -> Self {
238        value.map_kind(OrderBookEvent::into)
239    }
240}
241
242impl<InstrumentKey> From<MarketStreamResult<InstrumentKey, Candle>>
243    for MarketStreamResult<InstrumentKey, DataKind>
244{
245    fn from(value: MarketStreamResult<InstrumentKey, Candle>) -> Self {
246        value.map_ok(MarketEvent::from)
247    }
248}
249
250impl<InstrumentKey> From<MarketEvent<InstrumentKey, Candle>>
251    for MarketEvent<InstrumentKey, DataKind>
252{
253    fn from(value: MarketEvent<InstrumentKey, Candle>) -> Self {
254        value.map_kind(Candle::into)
255    }
256}
257
258impl<InstrumentKey> From<MarketStreamResult<InstrumentKey, Liquidation>>
259    for MarketStreamResult<InstrumentKey, DataKind>
260{
261    fn from(value: MarketStreamResult<InstrumentKey, Liquidation>) -> Self {
262        value.map_ok(MarketEvent::from)
263    }
264}
265
266impl<InstrumentKey> From<MarketEvent<InstrumentKey, Liquidation>>
267    for MarketEvent<InstrumentKey, DataKind>
268{
269    fn from(value: MarketEvent<InstrumentKey, Liquidation>) -> Self {
270        value.map_kind(Liquidation::into)
271    }
272}