1use crate::error::PredictionError;
4use crate::identifiers::{
5 PredictionEventId, PredictionMarketId, PredictionOutcomeId, PredictionSeriesId, PredictionVenue,
6};
7use serde::{Deserialize, Deserializer, Serialize, de};
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[cfg_attr(feature = "dataframe", derive(df_derive_macros::ToDataFrame))]
13pub struct PredictionSeriesKey {
14 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
16 pub venue: PredictionVenue,
17 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
19 pub series_id: PredictionSeriesId,
20}
21
22impl PredictionSeriesKey {
23 #[must_use]
25 pub const fn from_parts(venue: PredictionVenue, series_id: PredictionSeriesId) -> Self {
26 Self { venue, series_id }
27 }
28
29 pub fn new(venue: &str, series_id: &str) -> Result<Self, PredictionError> {
35 Ok(Self {
36 venue: venue.parse()?,
37 series_id: PredictionSeriesId::new(series_id)?,
38 })
39 }
40
41 #[must_use]
43 pub fn unique_key(&self) -> String {
44 component_key(self.venue.as_str(), "series", self.series_id.as_str())
45 }
46}
47
48impl fmt::Display for PredictionSeriesKey {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}:{}", self.venue, self.series_id)
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
56#[cfg_attr(feature = "dataframe", derive(df_derive_macros::ToDataFrame))]
57pub struct PredictionEventKey {
58 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
60 pub venue: PredictionVenue,
61 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
63 pub event_id: PredictionEventId,
64}
65
66impl PredictionEventKey {
67 #[must_use]
69 pub const fn from_parts(venue: PredictionVenue, event_id: PredictionEventId) -> Self {
70 Self { venue, event_id }
71 }
72
73 pub fn new(venue: &str, event_id: &str) -> Result<Self, PredictionError> {
79 Ok(Self {
80 venue: venue.parse()?,
81 event_id: PredictionEventId::new(event_id)?,
82 })
83 }
84
85 #[must_use]
87 pub fn unique_key(&self) -> String {
88 component_key(self.venue.as_str(), "event", self.event_id.as_str())
89 }
90}
91
92impl fmt::Display for PredictionEventKey {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "{}:{}", self.venue, self.event_id)
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
100#[cfg_attr(feature = "dataframe", derive(df_derive_macros::ToDataFrame))]
101pub struct PredictionMarketKey {
102 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
104 pub venue: PredictionVenue,
105 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
107 pub market_id: PredictionMarketId,
108}
109
110impl PredictionMarketKey {
111 #[must_use]
113 pub const fn from_parts(venue: PredictionVenue, market_id: PredictionMarketId) -> Self {
114 Self { venue, market_id }
115 }
116
117 pub fn new(venue: &str, market_id: &str) -> Result<Self, PredictionError> {
123 Ok(Self {
124 venue: venue.parse()?,
125 market_id: PredictionMarketId::new(market_id)?,
126 })
127 }
128
129 #[must_use]
131 pub fn unique_key(&self) -> String {
132 component_key(self.venue.as_str(), "market", self.market_id.as_str())
133 }
134}
135
136impl fmt::Display for PredictionMarketKey {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 write!(f, "{}:{}", self.venue, self.market_id)
139 }
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
144#[cfg_attr(feature = "dataframe", derive(df_derive_macros::ToDataFrame))]
145pub struct BinaryMarketKey {
146 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
148 pub venue: PredictionVenue,
149 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
151 pub market_id: PredictionMarketId,
152}
153
154impl BinaryMarketKey {
155 #[must_use]
157 pub const fn from_parts(venue: PredictionVenue, market_id: PredictionMarketId) -> Self {
158 Self { venue, market_id }
159 }
160
161 pub fn new(venue: &str, market_id: &str) -> Result<Self, PredictionError> {
167 Ok(Self {
168 venue: venue.parse()?,
169 market_id: PredictionMarketId::new(market_id)?,
170 })
171 }
172
173 #[must_use]
175 pub fn to_market_key(&self) -> PredictionMarketKey {
176 PredictionMarketKey {
177 venue: self.venue.clone(),
178 market_id: self.market_id.clone(),
179 }
180 }
181
182 #[must_use]
189 pub fn synthetic_yes_instrument(&self) -> OutcomeInstrument {
190 self.synthetic_outcome_instrument("YES")
191 }
192
193 #[must_use]
200 pub fn synthetic_no_instrument(&self) -> OutcomeInstrument {
201 self.synthetic_outcome_instrument("NO")
202 }
203
204 fn synthetic_outcome_instrument(&self, outcome_id: &'static str) -> OutcomeInstrument {
205 OutcomeInstrument {
206 venue: self.venue.clone(),
207 market_id: self.market_id.clone(),
208 outcome_id: PredictionOutcomeId::from_static_unchecked(outcome_id),
209 }
210 }
211
212 #[must_use]
214 pub fn unique_key(&self) -> String {
215 component_key(self.venue.as_str(), "market", self.market_id.as_str())
216 }
217}
218
219impl fmt::Display for BinaryMarketKey {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 write!(f, "{}:{}", self.venue, self.market_id)
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
227#[cfg_attr(feature = "dataframe", derive(df_derive_macros::ToDataFrame))]
228pub struct OutcomeInstrument {
229 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
231 pub venue: PredictionVenue,
232 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
234 pub market_id: PredictionMarketId,
235 #[cfg_attr(feature = "dataframe", df_derive(as_str))]
237 pub outcome_id: PredictionOutcomeId,
238}
239
240impl OutcomeInstrument {
241 #[must_use]
243 pub const fn from_parts(
244 venue: PredictionVenue,
245 market_id: PredictionMarketId,
246 outcome_id: PredictionOutcomeId,
247 ) -> Self {
248 Self {
249 venue,
250 market_id,
251 outcome_id,
252 }
253 }
254
255 pub fn new(venue: &str, market_id: &str, outcome_id: &str) -> Result<Self, PredictionError> {
261 Ok(Self {
262 venue: venue.parse()?,
263 market_id: PredictionMarketId::new(market_id)?,
264 outcome_id: PredictionOutcomeId::new(outcome_id)?,
265 })
266 }
267
268 #[must_use]
270 pub fn market_key(&self) -> PredictionMarketKey {
271 PredictionMarketKey {
272 venue: self.venue.clone(),
273 market_id: self.market_id.clone(),
274 }
275 }
276
277 #[must_use]
279 pub fn unique_key(&self) -> String {
280 let venue = self.venue.as_str();
281 let market = self.market_id.as_str();
282 let outcome = self.outcome_id.as_str();
283 format!(
284 "venue:{}:{}|market:{}:{}|outcome:{}:{}",
285 venue.len(),
286 venue,
287 market.len(),
288 market,
289 outcome.len(),
290 outcome
291 )
292 }
293}
294
295impl fmt::Display for OutcomeInstrument {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 write!(f, "{}:{}/{}", self.venue, self.market_id, self.outcome_id)
298 }
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
303pub struct BinaryOutcomeInstruments {
304 yes: OutcomeInstrument,
306 no: OutcomeInstrument,
308}
309
310impl BinaryOutcomeInstruments {
311 pub fn new(yes: OutcomeInstrument, no: OutcomeInstrument) -> Result<Self, PredictionError> {
320 if yes.venue != no.venue || yes.market_id != no.market_id {
321 return Err(PredictionError::MismatchedOutcomeInstrumentMarket {
322 yes_venue: yes.venue.to_string(),
323 yes_market_id: yes.market_id.to_string(),
324 no_venue: no.venue.to_string(),
325 no_market_id: no.market_id.to_string(),
326 });
327 }
328
329 if yes.outcome_id == no.outcome_id {
330 return Err(PredictionError::DuplicateBinaryOutcomeInstrument {
331 venue: yes.venue.to_string(),
332 market_id: yes.market_id.to_string(),
333 outcome_id: yes.outcome_id.to_string(),
334 });
335 }
336
337 Ok(Self { yes, no })
338 }
339
340 #[must_use]
342 pub const fn yes(&self) -> &OutcomeInstrument {
343 &self.yes
344 }
345
346 #[must_use]
348 pub const fn no(&self) -> &OutcomeInstrument {
349 &self.no
350 }
351
352 #[must_use]
354 pub fn into_parts(self) -> (OutcomeInstrument, OutcomeInstrument) {
355 (self.yes, self.no)
356 }
357
358 #[must_use]
364 pub fn synthetic_for_market(key: &BinaryMarketKey) -> Self {
365 Self {
366 yes: key.synthetic_yes_instrument(),
367 no: key.synthetic_no_instrument(),
368 }
369 }
370}
371
372impl<'de> Deserialize<'de> for BinaryOutcomeInstruments {
373 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
374 where
375 D: Deserializer<'de>,
376 {
377 #[derive(Deserialize)]
378 struct BinaryOutcomeInstrumentsShadow {
379 yes: OutcomeInstrument,
380 no: OutcomeInstrument,
381 }
382
383 let shadow = BinaryOutcomeInstrumentsShadow::deserialize(deserializer)?;
384 Self::new(shadow.yes, shadow.no).map_err(de::Error::custom)
385 }
386}
387
388fn component_key(venue: &str, role: &str, id: &str) -> String {
389 format!(
390 "venue:{}:{}|{}:{}:{}",
391 venue.len(),
392 venue,
393 role,
394 id.len(),
395 id
396 )
397}