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}