pub struct M2Measure { /* private fields */ }Expand description
M² (Modigliani–Modigliani) measure over a trailing window of period returns.
Sharpe = (mean(returns) − risk_free) / stddev(returns)
M² = risk_free + Sharpe · benchmark_stddevThe SharpeRatio is dimensionless, which makes it hard to
communicate: “0.8” means little to a client. M² rescales the Sharpe ratio back
into return units by levering (or de-levering) the portfolio to the
benchmark’s volatility. The result answers a concrete question: “if this
strategy had run at the market’s risk level, what return would it have
produced?” Two portfolios can then be ranked on the same risk-adjusted scale,
and M² preserves the Sharpe ordering while being quoted as a percentage.
stddev is the sample standard deviation (Bessel’s n − 1).
risk_free is the per-period risk-free rate and benchmark_stddev the
per-period volatility of the benchmark, both supplied by the caller at the
return frequency. A flat window has zero volatility and the Sharpe ratio is
undefined; the indicator returns 0.0 in that case rather than producing NaN.
Each update is O(1) — running sums maintain Σr and Σr² as the window slides.
§Example
use wickra_core::{Indicator, M2Measure};
let mut indicator = M2Measure::new(20, 0.0, 0.02).unwrap();
let mut last = None;
for i in 0..40 {
last = indicator.update(0.001 + (f64::from(i) * 0.1).sin() * 0.01);
}
assert!(last.is_some());Implementations§
Source§impl M2Measure
impl M2Measure
Sourcepub fn new(period: usize, risk_free: f64, benchmark_stddev: f64) -> Result<Self>
pub fn new(period: usize, risk_free: f64, benchmark_stddev: f64) -> Result<Self>
Construct an M² measure over period returns with the given per-period
risk-free rate and benchmark standard deviation.
§Errors
Returns Error::InvalidPeriod if period < 2, or
Error::InvalidParameter if risk_free is not finite or
benchmark_stddev is negative or not finite.
Sourcepub const fn benchmark_stddev(&self) -> f64
pub const fn benchmark_stddev(&self) -> f64
Configured per-period benchmark standard deviation.
Trait Implementations§
Source§impl Indicator for M2Measure
impl Indicator for M2Measure
Source§fn update(&mut self, ret: f64) -> Option<f64>
fn update(&mut self, ret: f64) -> Option<f64>
None if the indicator is still warming up.Source§fn reset(&mut self)
fn reset(&mut self)
Source§fn warmup_period(&self) -> usize
fn warmup_period(&self) -> usize
None output can be produced.Auto Trait Implementations§
impl Freeze for M2Measure
impl RefUnwindSafe for M2Measure
impl Send for M2Measure
impl Sync for M2Measure
impl Unpin for M2Measure
impl UnsafeUnpin for M2Measure
impl UnwindSafe for M2Measure
Blanket Implementations§
Source§impl<T> BatchExt for Twhere
T: Indicator,
impl<T> BatchExt for Twhere
T: Indicator,
Source§fn batch(&mut self, inputs: &[Self::Input]) -> Vec<Option<Self::Output>>
fn batch(&mut self, inputs: &[Self::Input]) -> Vec<Option<Self::Output>>
None during warmup) per input.Source§impl<T> BatchNanExt for T
impl<T> BatchNanExt for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more