Skip to main content

paft_fundamentals/
statistics.rs

1//! Key statistics: slow-moving valuation, dividend, and risk metrics
2//! associated with an instrument.
3//!
4//! These fields are typically derived from a mix of market data (price-driven,
5//! refreshes intraday) and fundamentals (earnings, share counts, dividend
6//! history). They are not part of a snapshot quote — see
7//! [`paft_market::market::quote::Quote`](https://docs.rs/paft-market) for
8//! point-in-time price data — and they are not part of a statement row
9//! either, because they aggregate across periods. They live here, alongside
10//! the other instrument-attached fundamentals types.
11
12use chrono::{DateTime, NaiveDate, Utc};
13#[cfg(feature = "dataframe")]
14use df_derive_macros::ToDataFrame;
15use paft_decimal::Decimal;
16use paft_money::{Money, Price};
17use serde::{Deserialize, Serialize};
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
20#[cfg_attr(feature = "dataframe", derive(ToDataFrame))]
21/// Slow-moving valuation, dividend, and risk metrics for an instrument.
22///
23/// All fields are optional because providers expose different subsets and
24/// some metrics are undefined for certain asset classes (e.g. dividend
25/// yield on a non-dividend-paying stock).
26pub struct KeyStatistics {
27    /// Timestamp at which these statistics were observed. Useful when
28    /// snapshotting price-driven values like `market_cap` that move
29    /// intraday.
30    #[serde(default, with = "chrono::serde::ts_milliseconds_option")]
31    pub as_of: Option<DateTime<Utc>>,
32
33    // ---- Valuation ----
34    /// Market capitalisation (price × shares outstanding).
35    pub market_cap: Option<Money>,
36    /// Shares outstanding.
37    pub shares_outstanding: Option<u64>,
38
39    // ---- Earnings (trailing) ----
40    /// Earnings per share over the trailing twelve months.
41    pub eps_trailing_twelve_months: Option<Price>,
42    /// Price-to-earnings ratio computed against trailing-twelve-month EPS.
43    #[serde(default, with = "paft_decimal::serde::option_canonical_str")]
44    pub pe_trailing_twelve_months: Option<Decimal>,
45
46    // ---- Dividends ----
47    /// Forward (declared / expected) dividend per share.
48    pub dividend_per_share_forward: Option<Price>,
49    /// Trailing twelve-month dividend yield expressed as a fraction
50    /// (e.g. 0.025 for 2.5%).
51    #[serde(default, with = "paft_decimal::serde::option_canonical_str")]
52    pub dividend_yield_trailing: Option<Decimal>,
53    /// Forward dividend yield expressed as a fraction.
54    #[serde(default, with = "paft_decimal::serde::option_canonical_str")]
55    pub dividend_yield_forward: Option<Decimal>,
56    /// Next or most recent ex-dividend calendar date.
57    #[serde(default)]
58    pub ex_dividend_date: Option<NaiveDate>,
59
60    // ---- 52-week range ----
61    /// 52-week high price.
62    pub fifty_two_week_high: Option<Price>,
63    /// 52-week low price.
64    pub fifty_two_week_low: Option<Price>,
65
66    // ---- Volume statistic ----
67    /// Average daily traded volume over the last three months.
68    pub average_daily_volume_3m: Option<u64>,
69
70    // ---- Risk ----
71    /// Market beta. The calculation period and frequency are not
72    /// standardised across providers (Yahoo uses 5y monthly; Bloomberg
73    /// is configurable); consumers comparing values across sources
74    /// should account for this.
75    #[serde(default, with = "paft_decimal::serde::option_canonical_str")]
76    pub beta: Option<Decimal>,
77}