Skip to main content

value_metrics/
lib.rs

1//! # value-metrics
2//!
3//! Core equity valuation ratios used to screen for deep-value stocks: price-to-earnings,
4//! price-to-book, earnings yield, EV/EBIT, and dividend yield. Pure Rust, no deps. Same
5//! signals behind the [DeepValueRadar](https://deepvalueradar.com/) value screener.
6//!
7//! ```
8//! use value_metrics::*;
9//! assert!((price_to_earnings(100.0, 5.0) - 20.0).abs() < 1e-9);
10//! assert!((earnings_yield(5.0, 100.0) - 0.05).abs() < 1e-9);
11//! ```
12
13/// Price-to-earnings ratio = price / earnings per share.
14pub fn price_to_earnings(price: f64, eps: f64) -> f64 {
15    if eps <= 0.0 { f64::INFINITY } else { price / eps }
16}
17
18/// Price-to-book ratio = price / book value per share.
19pub fn price_to_book(price: f64, book_value_per_share: f64) -> f64 {
20    if book_value_per_share <= 0.0 { f64::INFINITY } else { price / book_value_per_share }
21}
22
23/// Earnings yield = EPS / price (the reciprocal of P/E).
24pub fn earnings_yield(eps: f64, price: f64) -> f64 {
25    if price <= 0.0 { 0.0 } else { eps / price }
26}
27
28/// EV/EBIT = enterprise value / EBIT.
29pub fn ev_to_ebit(enterprise_value: f64, ebit: f64) -> f64 {
30    if ebit <= 0.0 { f64::INFINITY } else { enterprise_value / ebit }
31}
32
33/// Dividend yield = annual dividend per share / price.
34pub fn dividend_yield(dividend_per_share: f64, price: f64) -> f64 {
35    if price <= 0.0 { 0.0 } else { dividend_per_share / price }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    #[test]
42    fn pe_basic() { assert!((price_to_earnings(100.0, 5.0) - 20.0).abs() < 1e-9); }
43    #[test]
44    fn pe_zero_eps_is_inf() { assert!(price_to_earnings(100.0, 0.0).is_infinite()); }
45    #[test]
46    fn earnings_yield_reciprocal() {
47        let pe = price_to_earnings(100.0, 5.0);
48        let ey = earnings_yield(5.0, 100.0);
49        assert!((pe * ey - 1.0).abs() < 1e-9);
50    }
51    #[test]
52    fn pb_basic() { assert!((price_to_book(50.0, 25.0) - 2.0).abs() < 1e-9); }
53    #[test]
54    fn div_yield_pct() { assert!((dividend_yield(4.0, 100.0) - 0.04).abs() < 1e-9); }
55    #[test]
56    fn ev_ebit() { assert!((ev_to_ebit(1_000_000.0, 100_000.0) - 10.0).abs() < 1e-9); }
57}