Skip to main content

df_hyperliquid_core/markets/
context.rs

1//! Asset contexts: what a market is doing now. [`PerpCtx`] for a perp on any dex, [`SpotCtx`] for a
2//! spot pair or an outcome side, each the same shape from `/info` and from the socket.
3
4use serde::Deserialize;
5
6use crate::utils::dec::{Dec, Round};
7
8/// What a perp is doing now. The venue writes `midPx`, `premium` and `impactPxs` as null on a
9/// market with no book.
10#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct PerpCtx {
13    pub mark_px: Dec,
14    #[serde(default)]
15    pub mid_px: Option<Dec>,
16    pub oracle_px: Dec,
17    pub prev_day_px: Dec,
18    /// Hourly, as a fraction of the position's value.
19    pub funding: Dec,
20    /// In the base asset.
21    pub open_interest: Dec,
22    /// Quote volume over the last day.
23    pub day_ntl_vlm: Dec,
24    /// Base volume over the last day.
25    #[serde(default)]
26    pub day_base_vlm: Option<Dec>,
27    #[serde(default)]
28    pub premium: Option<Dec>,
29    #[serde(default)]
30    pub impact_pxs: Option<Vec<Dec>>,
31}
32
33impl PerpCtx {
34    /// The price a market order is bounded from: the mid, else the mark.
35    #[must_use]
36    pub fn reference(&self) -> Dec {
37        self.mid_px.unwrap_or(self.mark_px)
38    }
39
40    /// The mark's change over the day in percent, to two places. `None` without a previous day's
41    /// price.
42    #[must_use]
43    pub fn day_change(&self) -> Option<Dec> {
44        let then = Some(self.prev_day_px).filter(|then| then.is_positive())?;
45        self.mark_px.checked_sub(then)?.checked_mul(Dec::from_int(100))?.checked_div(then, 2, Round::Nearest)
46    }
47
48    /// The open interest at the mark, in the quote.
49    #[must_use]
50    pub fn open_interest_value(&self) -> Option<Dec> {
51        self.open_interest.checked_mul(self.mark_px)
52    }
53}
54
55/// What a spot pair or an outcome side (`#<encoding>`) is doing now. An outcome side's open
56/// interest is its circulating supply.
57#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
58#[serde(rename_all = "camelCase")]
59pub struct SpotCtx {
60    /// The book name: `PURR/USDC`, `@107` or `#14730`.
61    pub coin: String,
62    pub mark_px: Dec,
63    #[serde(default)]
64    pub mid_px: Option<Dec>,
65    pub prev_day_px: Dec,
66    /// Quote volume over the last day.
67    pub day_ntl_vlm: Dec,
68    /// Base volume over the last day.
69    #[serde(default)]
70    pub day_base_vlm: Option<Dec>,
71    pub circulating_supply: Dec,
72    #[serde(default)]
73    pub total_supply: Option<Dec>,
74}
75
76impl SpotCtx {
77    /// The price a market order is bounded from: the mid, else the mark.
78    #[must_use]
79    pub fn reference(&self) -> Dec {
80        self.mid_px.unwrap_or(self.mark_px)
81    }
82}
83
84#[cfg(test)]
85#[path = "tests/context.rs"]
86mod tests;