betfair_stream_api/cache/primitives/
runner_book_cache.rs1use betfair_adapter::betfair_types::numeric::F64Ord;
4use betfair_adapter::betfair_types::price::Price;
5use betfair_adapter::betfair_types::size::Size;
6use betfair_adapter::betfair_types::types::sports_aping::SelectionId;
7use betfair_stream_types::response::market_change_message::{RunnerChange, RunnerDefinition};
8use betfair_stream_types::response::{UpdateSet2, UpdateSet3};
9use eyre::bail;
10
11use super::available_cache::Available;
12
13#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
15pub struct RunnerBookCache {
16 selection_id: SelectionId,
17 last_price_traded: Option<Price>,
18 total_matched: Option<Size>,
19 traded: Available<UpdateSet2>,
20 available_to_back: Available<UpdateSet2>,
21 best_available_to_back: Available<UpdateSet3>,
22 best_display_available_to_back: Available<UpdateSet3>,
23 available_to_lay: Available<UpdateSet2>,
24 best_available_to_lay: Available<UpdateSet3>,
25 best_display_available_to_lay: Available<UpdateSet3>,
26 starting_price_back: Available<UpdateSet2>,
27 starting_price_lay: Available<UpdateSet2>,
28 starting_price_near: Option<Price>,
29 starting_price_far: Option<Price>,
30 handicap: Option<F64Ord>,
31 definition: Option<RunnerDefinition>,
32}
33
34impl RunnerBookCache {
35 pub fn new_from_runner_change(runner_change: RunnerChange) -> eyre::Result<Self> {
36 let Some(id) = runner_change.id else {
37 bail!("Invalid selection id");
38 };
39 let selection_id = id;
40 let handicap = runner_change.handicap;
41 let definition = None;
42
43 Ok(Self {
44 selection_id,
45 last_price_traded: runner_change.last_traded_price,
46 total_matched: runner_change.total_value,
47 traded: runner_change
48 .traded
49 .map_or_else(|| Available::new(&[]), Available::new),
50 available_to_back: runner_change
51 .available_to_back
52 .map_or_else(|| Available::new(&[]), Available::new),
53 best_available_to_back: runner_change
54 .best_available_to_back
55 .map_or_else(|| Available::new(&[]), Available::new),
56 best_display_available_to_back: runner_change
57 .best_display_available_to_back
58 .map_or_else(|| Available::new(&[]), Available::new),
59 available_to_lay: runner_change
60 .available_to_lay
61 .map_or_else(|| Available::new(&[]), Available::new),
62 best_available_to_lay: runner_change
63 .best_available_to_lay
64 .map_or_else(|| Available::new(&[]), Available::new),
65 best_display_available_to_lay: runner_change
66 .best_display_available_to_lay
67 .map_or_else(|| Available::new(&[]), Available::new),
68 starting_price_back: runner_change
69 .starting_price_back
70 .map_or_else(|| Available::new(&[]), Available::new),
71 starting_price_lay: runner_change
72 .starting_price_lay
73 .map_or_else(|| Available::new(&[]), Available::new),
74 starting_price_near: runner_change.starting_price_near,
75 starting_price_far: runner_change.starting_price_far,
76 handicap,
77 definition,
78 })
79 }
80
81 pub fn new_from_runner_definition(runner_definition: RunnerDefinition) -> eyre::Result<Self> {
82 let Some(selection_id) = runner_definition.id else {
83 bail!("Invalid selection id");
84 };
85 let definition = Some(runner_definition);
86
87 Ok(Self {
88 selection_id,
89 last_price_traded: None,
90 total_matched: None,
91 traded: Available::new(&[]),
92 available_to_back: Available::new(&[]),
93 best_available_to_back: Available::new(&[]),
94 best_display_available_to_back: Available::new(&[]),
95 available_to_lay: Available::new(&[]),
96 best_available_to_lay: Available::new(&[]),
97 best_display_available_to_lay: Available::new(&[]),
98 starting_price_back: Available::new(&[]),
99 starting_price_lay: Available::new(&[]),
100 starting_price_near: None,
101 starting_price_far: None,
102 handicap: None,
103 definition,
104 })
105 }
106
107 pub fn update_traded(&mut self, traded: &[UpdateSet2]) {
108 if traded.is_empty() {
109 self.traded.clear();
110 self.total_matched = Some(Size::zero());
111 return;
112 }
113 self.total_matched = Some(
114 traded
115 .iter()
116 .map(|x| x.1)
117 .fold(Size::zero(), |acc, x| acc.saturating_add(&x)),
118 );
119 self.traded.update(traded);
120 }
121
122 pub fn set_definition(&mut self, definition: RunnerDefinition) {
123 self.definition = Some(definition);
124 }
125
126 #[must_use]
127 pub const fn total_matched(&self) -> Option<Size> {
128 self.total_matched
129 }
130
131 #[must_use]
132 pub const fn selection_id(&self) -> &SelectionId {
133 &self.selection_id
134 }
135
136 pub fn set_last_price_traded(&mut self, last_price_traded: Price) {
137 self.last_price_traded = Some(last_price_traded);
138 }
139
140 pub fn set_total_matched(&mut self, total_matched: Size) {
141 self.total_matched = Some(total_matched);
142 }
143
144 pub(crate) fn set_starting_price_near(&mut self, spn: Price) {
145 self.starting_price_near = Some(spn);
146 }
147
148 pub(crate) fn set_starting_price_far(&mut self, spf: Price) {
149 self.starting_price_far = Some(spf);
150 }
151
152 pub(crate) fn update_available_to_back(&mut self, atb: impl AsRef<[UpdateSet2]>) {
153 self.available_to_back.update(atb);
154 }
155
156 pub(crate) fn update_available_to_lay(&mut self, atl: impl AsRef<[UpdateSet2]>) {
157 self.available_to_lay.update(atl);
158 }
159
160 pub(crate) fn update_best_available_to_back(&mut self, batb: impl AsRef<[UpdateSet3]>) {
161 self.best_available_to_back.update(batb);
162 }
163
164 pub(crate) fn update_best_available_to_lay(&mut self, batl: impl AsRef<[UpdateSet3]>) {
165 self.best_available_to_lay.update(batl);
166 }
167
168 pub(crate) fn update_best_display_available_to_back(
169 &mut self,
170 bdatb: impl AsRef<[UpdateSet3]>,
171 ) {
172 self.best_display_available_to_back.update(bdatb);
173 }
174
175 pub(crate) fn update_best_display_available_to_lay(&mut self, bdatl: impl AsRef<[UpdateSet3]>) {
176 self.best_display_available_to_lay.update(bdatl);
177 }
178
179 pub(crate) fn update_starting_price_back(&mut self, spb: impl AsRef<[UpdateSet2]>) {
180 self.starting_price_back.update(spb);
181 }
182
183 pub(crate) fn update_starting_price_lay(&mut self, spl: impl AsRef<[UpdateSet2]>) {
184 self.starting_price_lay.update(spl);
185 }
186
187 #[must_use]
188 pub const fn last_price_traded(&self) -> Option<&Price> {
189 self.last_price_traded.as_ref()
190 }
191
192 #[must_use]
193 pub const fn traded(&self) -> &Available<UpdateSet2> {
194 &self.traded
195 }
196
197 #[must_use]
198 pub const fn available_to_back(&self) -> &Available<UpdateSet2> {
199 &self.available_to_back
200 }
201
202 #[must_use]
203 pub const fn best_available_to_back(&self) -> &Available<UpdateSet3> {
204 &self.best_available_to_back
205 }
206
207 #[must_use]
208 pub const fn best_display_available_to_back(&self) -> &Available<UpdateSet3> {
209 &self.best_display_available_to_back
210 }
211
212 #[must_use]
213 pub const fn available_to_lay(&self) -> &Available<UpdateSet2> {
214 &self.available_to_lay
215 }
216
217 #[must_use]
218 pub const fn best_available_to_lay(&self) -> &Available<UpdateSet3> {
219 &self.best_available_to_lay
220 }
221
222 #[must_use]
223 pub const fn best_display_available_to_lay(&self) -> &Available<UpdateSet3> {
224 &self.best_display_available_to_lay
225 }
226
227 #[must_use]
228 pub const fn starting_price_back(&self) -> &Available<UpdateSet2> {
229 &self.starting_price_back
230 }
231
232 #[must_use]
233 pub const fn starting_price_lay(&self) -> &Available<UpdateSet2> {
234 &self.starting_price_lay
235 }
236
237 #[must_use]
238 pub const fn starting_price_near(&self) -> Option<&Price> {
239 self.starting_price_near.as_ref()
240 }
241
242 #[must_use]
243 pub const fn starting_price_far(&self) -> Option<&Price> {
244 self.starting_price_far.as_ref()
245 }
246
247 #[must_use]
248 pub const fn handicap(&self) -> Option<F64Ord> {
249 self.handicap
250 }
251
252 #[must_use]
253 pub const fn definition(&self) -> Option<&RunnerDefinition> {
254 self.definition.as_ref()
255 }
256}
257
258#[cfg(test)]
259mod tests {
260
261 #[test]
262 const fn test_update_traded() {}
263}