use serde::Deserialize;
use crate::utils::dec::{Dec, Round};
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PerpCtx {
pub mark_px: Dec,
#[serde(default)]
pub mid_px: Option<Dec>,
pub oracle_px: Dec,
pub prev_day_px: Dec,
pub funding: Dec,
pub open_interest: Dec,
pub day_ntl_vlm: Dec,
#[serde(default)]
pub day_base_vlm: Option<Dec>,
#[serde(default)]
pub premium: Option<Dec>,
#[serde(default)]
pub impact_pxs: Option<Vec<Dec>>,
}
impl PerpCtx {
#[must_use]
pub fn reference(&self) -> Dec {
self.mid_px.unwrap_or(self.mark_px)
}
#[must_use]
pub fn day_change(&self) -> Option<Dec> {
let then = Some(self.prev_day_px).filter(|then| then.is_positive())?;
self.mark_px.checked_sub(then)?.checked_mul(Dec::from_int(100))?.checked_div(then, 2, Round::Nearest)
}
#[must_use]
pub fn open_interest_value(&self) -> Option<Dec> {
self.open_interest.checked_mul(self.mark_px)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpotCtx {
pub coin: String,
pub mark_px: Dec,
#[serde(default)]
pub mid_px: Option<Dec>,
pub prev_day_px: Dec,
pub day_ntl_vlm: Dec,
#[serde(default)]
pub day_base_vlm: Option<Dec>,
pub circulating_supply: Dec,
#[serde(default)]
pub total_supply: Option<Dec>,
}
impl SpotCtx {
#[must_use]
pub fn reference(&self) -> Dec {
self.mid_px.unwrap_or(self.mark_px)
}
}
#[cfg(test)]
#[path = "tests/context.rs"]
mod tests;