fts_core/models/outcome.rs
1use serde::{Deserialize, Serialize};
2use time::OffsetDateTime;
3use utoipa::ToSchema;
4
5/// An outcome represents the result of an auction for a particular auth or product.
6///
7/// An outcome contains:
8/// - A `price` at which the asset was cleared in the auction
9/// - A `trade` amount representing the quantity that was traded
10/// - Optional implementation-dependent `data` for additional context
11///
12/// The sign convention for trades follows the flow trading standard:
13/// - Positive values indicate buying
14/// - Negative values indicate selling
15#[derive(Serialize, Deserialize, Debug, ToSchema)]
16pub struct Outcome<T> {
17 /// The clearing price determined by the auction solver
18 #[serde(with = "safe_f64")]
19 pub price: f64,
20 /// The trade amount (positive for buying, negative for selling)
21 pub trade: f64,
22 /// Optional implementation-specific data related to the outcome
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub data: Option<T>,
25}
26
27/// Provides temporal context for an outcome by associating it with
28/// a specific auction time interval.
29///
30/// This structure embeds an `Outcome` with the time range (`from` and `thru`)
31/// of the auction that produced it, allowing for tracking outcomes across
32/// multiple consecutive auctions.
33#[derive(Serialize, Deserialize, Debug, ToSchema)]
34pub struct AuctionOutcome<T = ()> {
35 /// The starting time of the auction interval
36 #[serde(with = "time::serde::rfc3339")]
37 pub from: OffsetDateTime,
38 /// The ending time of the auction interval
39 #[serde(with = "time::serde::rfc3339")]
40 pub thru: OffsetDateTime,
41 /// The actual outcome (price and trade) from the auction
42 #[serde(flatten)]
43 pub outcome: Outcome<T>,
44}
45
46mod safe_f64 {
47 use serde::{Deserialize as _, Deserializer, Serializer};
48
49 pub fn serialize<S: Serializer>(value: &f64, serializer: S) -> Result<S::Ok, S::Error> {
50 if value.is_finite() {
51 serializer.serialize_some(value)
52 } else {
53 serializer.serialize_none()
54 }
55 }
56
57 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<f64, D::Error> {
58 Ok(Option::<f64>::deserialize(deserializer)?.unwrap_or(f64::NAN))
59 }
60}