use crate::rate::cagr;
use crate::tvm::{fv, pv};
use crate::ZERO;
use rust_decimal::prelude::*;
use rust_decimal_macros::*;
pub fn mirr(cash_flows: &[Decimal], finance_rate: Decimal, reinvest_rate: Decimal) -> Decimal {
let n = cash_flows.len() - 1;
let mut npv_neg = ZERO;
let mut fv_pos = ZERO;
for (i, &cf) in cash_flows.iter().enumerate() {
if cf < ZERO {
npv_neg += pv(finance_rate, i.into(), ZERO, Some(cf), None);
} else {
fv_pos += fv(reinvest_rate, (n - i).into(), ZERO, Some(cf), None);
}
}
npv_neg.set_sign_positive(true);
cagr(
npv_neg,
fv_pos,
Decimal::from_usize(n).unwrap(),
)
}
pub fn xmirr(flow_table: &[(Decimal, i32)], finance_rate: Decimal, reinvest_rate: Decimal) -> Decimal {
let init_date = flow_table.first().unwrap().1;
let n = Decimal::from_i32(flow_table.last().unwrap().1).unwrap();
let mut npv_neg = ZERO;
let mut fv_pos = ZERO;
for &(cf, date) in flow_table {
if cf < ZERO {
npv_neg += pv(
finance_rate,
Decimal::from_i32(date - init_date).unwrap() / dec!(365),
ZERO,
Some(cf),
None,
);
} else {
fv_pos += fv(
reinvest_rate,
(n - Decimal::from_i32(date).unwrap()) / dec!(365),
ZERO,
Some(cf),
None,
);
}
}
npv_neg.set_sign_positive(true);
cagr(
npv_neg,
fv_pos,
n / dec!(365), )
}
#[cfg(test)]
mod tests {
#[cfg(not(feature = "std"))]
extern crate std;
use super::*;
#[cfg(not(feature = "std"))]
use std::prelude::v1::*;
#[cfg(not(feature = "std"))]
use std::{assert, vec};
#[test]
fn test_mirr() {
let cash_flows = vec![dec!(-100), dec!(-20), dec!(20), dec!(20), dec!(20)];
let finance_rate = dec!(0.1);
let reinvest_rate = dec!(0.05);
let result = mirr(&cash_flows, finance_rate, reinvest_rate);
let expected = dec!(-0.14536);
assert!(
(result - expected).abs() < dec!(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 = dec!(0.1);
let reinvest_rate = dec!(0.05);
let flow_table = vec![
(dec!(-100), 0),
(dec!(-20), 365),
(dec!(20), 730),
(dec!(20), 1095),
(dec!(20), 1460),
];
let result = xmirr(&flow_table, finance_rate, reinvest_rate);
let expected = dec!(-0.14536);
assert!(
(result - expected).abs() < dec!(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![
(dec!(-100), 0),
(dec!(-20), 359),
(dec!(20), 400),
(dec!(20), 1000),
(dec!(20), 2000),
];
let result = xmirr(&flow_table, finance_rate, reinvest_rate);
let expected = dec!(-0.09689);
assert!(
(result - expected).abs() < dec!(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
);
}
}