use crate::rate::cagr;
use crate::tvm::{fv, pv};
use crate::FloatLike;
pub fn mirr<T: FloatLike>(cash_flows: &[T], finance_rate: T, reinvest_rate: T) -> T {
let n = cash_flows.len() - 1;
let mut npv_neg = T::zero();
let mut fv_pos = T::zero();
for (i, &cf) in cash_flows.iter().enumerate() {
if cf < T::zero() {
npv_neg += pv(finance_rate, T::from_usize(i), T::zero(), Some(cf), None);
} else {
fv_pos -= fv(reinvest_rate, T::from_usize(n - i), T::zero(), Some(cf), None);
}
}
npv_neg = npv_neg.abs(); cagr(
npv_neg,
fv_pos,
T::from_usize(n),
)
}
pub fn xmirr<T: FloatLike>(flow_table: &[(T, i32)], finance_rate: T, reinvest_rate: T) -> T {
let init_date = flow_table.first().unwrap().1;
let n = T::from_i32(flow_table.last().unwrap().1);
let mut npv_neg = T::zero();
let mut fv_pos = T::zero();
for &(cf, date) in flow_table {
if cf < T::zero() {
npv_neg += pv(
finance_rate,
T::from_i32(date - init_date) / T::from_u16(365),
T::zero(),
Some(cf),
None,
);
} else {
fv_pos -= fv(
reinvest_rate,
(n - T::from_i32(date)) / T::from_u16(365),
T::zero(),
Some(cf),
None,
);
}
}
npv_neg.abs(); cagr(
npv_neg,
fv_pos,
n / T::from_u16(365), )
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(feature = "std"))]
extern crate std;
#[cfg(not(feature = "std"))]
use std::{assert, vec};
#[test]
fn test_mirr() {
let cash_flows = vec![-100.0, -20.0, 20.0, 20.0, 20.0];
let finance_rate = 0.1;
let reinvest_rate = 0.05;
let result = mirr(&cash_flows, finance_rate, reinvest_rate);
let expected: f64 = -0.14536;
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Cash flows of -100, -20, 20, 20, 20, finance rate of 0.1, reinvestment rate of 0.05",
expected,
result
);
}
#[test]
fn test_xmirr() {
let finance_rate = 0.1;
let reinvest_rate = 0.05;
let flow_table = vec![(-100.0, 0), (-20.0, 365), (20.0, 730), (20.0, 1095), (20.0, 1460)];
let result = xmirr(&flow_table, finance_rate, reinvest_rate);
let expected: f64 = -0.14536;
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Cash flows of -100, -20, 20, 20, 20, finance rate of 0.1, reinvestment rate of 0.05",
expected,
result
);
let flow_table = vec![(-100.0, 0), (-20.0, 359), (20.0, 400), (20.0, 1000), (20.0, 2000)];
let result = xmirr(&flow_table, finance_rate, reinvest_rate);
let expected: f64 = -0.09689;
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Cash flows of -100, -20, 20, 20, 20, at 0, 359, 400, 1000, 2000 days,
finance rate of 0.1, reinvestment rate of 0.05",
expected,
result
);
}
}