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}