using System; using EvoCalculator.Core.Models.Calculation.Interfaces; using EvoCalculator.Core.Models.Calculation.Models; namespace EvoCalculator.Core.FinanceFormulas { public class XIRR : IFinanceFormula { private readonly Flow[] _flows; private readonly double _guess = 0.1; public XIRR(Flow[] flows) { _flows = flows; } public XIRR(Flow[] flows, double guess) { _flows = flows; _guess = guess; } public double GetResult() { var x1 = 0.0; var x2 = _guess; var f1 = new XNPV(_flows, x1).GetResult(); var f2 = new XNPV(_flows, x2).GetResult(); for (var i = 0; i < 100; i++) { if (f1 * f2 < 0.0) break; if (Math.Abs(f1) < Math.Abs(f2)) { x1 += 1.6 * (x1 - x2); f1 = new XNPV(_flows, x1).GetResult(); } else { x2 += 1.6 * (x2 - x1); f2 = new XNPV(_flows, x2).GetResult(); } } if (f1 * f2 > 0.0) return 0; var f = new XNPV(_flows, x1).GetResult(); var dx = 0.0; var rtb = 0.0; if (f < 0.0) { rtb = x1; dx = x2 - x1; } else { rtb = x2; dx = x1 - x2; } for (var i = 0; i < 100; i++) { dx *= 0.5; var xMid = rtb + dx; var fMid = new XNPV(_flows, xMid).GetResult(); if (fMid <= 0.0) rtb = xMid; if (Math.Abs(fMid) < 1.0e-6 || Math.Abs(dx) < 1.0e-6) return xMid; } return 0; } } }