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
23/// Implements methods for managing the order book cache.
24impl OrderBookCache {
25    /// Creates a new `OrderBookCache` with the given market ID and publish time.
26    #[must_use]
27    pub fn new(market_id: MarketId, publish_time: DateTime<Utc>) -> Self {
28        Self {
29            market_id,
30            publish_time,
31            closed: false,
32            runners: HashMap::new(),
33        }
34    }
35
36    /// Checks if the order book is closed.
37    #[must_use]
38    pub const fn is_closed(&self) -> bool {
39        self.closed
40    }
41
42    /// Updates the cache with changes from the order market.
43    pub fn update_cache(&mut self, change: OrderMarketChange, publish_time: DateTime<Utc>) {
44        self.publish_time = publish_time;
45        self.closed = change.closed.unwrap_or(self.closed);
46
47        if let Some(order_runner_change) = change.order_runner_change {
48            for runner_change in order_runner_change {
49                let runner = self
50                    .runners
51                    .entry((runner_change.id.clone(), runner_change.handicap))
52                    .or_insert_with(|| {
53                        OrderBookRunner::new(self.market_id.clone(), runner_change.id.clone())
54                    });
55
56                if let Some(ml) = runner_change.matched_lays {
57                    runner.update_matched_lays(ml);
58                }
59                if let Some(mb) = runner_change.matched_backs {
60                    runner.update_matched_backs(mb);
61                }
62                if let Some(uo) = runner_change.unmatched_orders {
63                    runner.update_unmatched(uo);
64                }
65            }
66        }
67    }
68
69    /// Returns the publish time of the order book.
70    #[must_use]
71    pub const fn publish_time(&self) -> DateTime<Utc> {
72        self.publish_time
73    }
74
75    /// Returns a reference to the runners in the order book cache.
76    #[must_use]
77    pub const fn runners(&self) -> &HashMap<(SelectionId, Option<Handicap>), OrderBookRunner> {
78        &self.runners
79    }
80
81    /// Consumes the `OrderBookCache` and returns the runners.
82    #[must_use]
83    pub fn into_runners(self) -> HashMap<(SelectionId, Option<Handicap>), OrderBookRunner> {
84        self.runners
85    }
86
87    /// Returns a reference to the market ID of the order book cache.
88    #[must_use]
89    pub const fn market_id(&self) -> &MarketId {
90        &self.market_id
91    }
92}