Skip to main content

betfair_stream_api/cache/primitives/
orderbook_cache.rs

1//! Order book cache
2
3use std::collections::HashMap;
4
5use betfair_adapter::betfair_types::handicap::Handicap;
6use betfair_adapter::betfair_types::types::sports_aping::{MarketId, SelectionId};
7use betfair_stream_types::response::order_change_message::OrderMarketChange;
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10
11use super::orderbook_runner_cache::OrderBookRunner;
12
13/// Represents a cache for order book data.
14#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
15pub struct OrderBookCache {
16    market_id: MarketId,
17    publish_time: DateTime<Utc>,
18    closed: bool,
19    /// cache of orders placed on a runner
20    runners: HashMap<(SelectionId, Option<Handicap>), OrderBookRunner>,
21
22    last_change: Option<OrderMarketChange>,
23}
24
25/// Implements methods for managing the order book cache.
26impl OrderBookCache {
27    /// Creates a new `OrderBookCache` with the given market ID and publish time.
28    #[must_use]
29    pub fn new(market_id: MarketId, publish_time: DateTime<Utc>) -> Self {
30        Self {
31            market_id,
32            publish_time,
33            closed: false,
34            runners: HashMap::new(),
35            last_change: None,
36        }
37    }
38
39    /// Checks if the order book is closed.
40    #[must_use]
41    pub const fn is_closed(&self) -> bool {
42        self.closed
43    }
44
45    /// Updates the cache with changes from the order market.
46    pub fn update_cache(&mut self, change: OrderMarketChange, publish_time: DateTime<Utc>) {
47        self.publish_time = publish_time;
48        self.closed = change.closed.unwrap_or(self.closed);
49
50        if let Some(ref order_runner_change) = change.order_runner_change {
51            for runner_change in order_runner_change {
52                let runner = self
53                    .runners
54                    .entry((runner_change.id, runner_change.handicap))
55                    .or_insert_with(|| {
56                        OrderBookRunner::new(self.market_id.clone(), runner_change.id)
57                    });
58
59                if let Some(ref ml) = runner_change.matched_lays {
60                    runner.update_matched_lays(ml);
61                }
62                if let Some(ref mb) = runner_change.matched_backs {
63                    runner.update_matched_backs(mb);
64                }
65                if let Some(ref uo) = runner_change.unmatched_orders {
66                    runner.update_unmatched(uo);
67                }
68                if let Some(ref sm) = runner_change.strategy_matches {
69                    runner.update_strategy_matches(sm);
70                }
71            }
72        }
73
74        self.last_change = Some(change);
75    }
76
77    /// Returns the publish time of the order book.
78    #[must_use]
79    pub const fn publish_time(&self) -> DateTime<Utc> {
80        self.publish_time
81    }
82
83    /// Returns a reference to the runners in the order book cache.
84    #[must_use]
85    pub const fn runners(&self) -> &HashMap<(SelectionId, Option<Handicap>), OrderBookRunner> {
86        &self.runners
87    }
88
89    /// Consumes the `OrderBookCache` and returns the runners.
90    #[must_use]
91    pub fn into_runners(self) -> HashMap<(SelectionId, Option<Handicap>), OrderBookRunner> {
92        self.runners
93    }
94
95    /// Returns a reference to the market ID of the order book cache.
96    #[must_use]
97    pub const fn market_id(&self) -> &MarketId {
98        &self.market_id
99    }
100
101    /// Returns a reference to the last change applied to the order book cache, if any.
102    #[must_use]
103    pub const fn last_change(&self) -> Option<&OrderMarketChange> {
104        self.last_change.as_ref()
105    }
106}