class Xirr::Bisection
Methods that will be included in Cashflow
to calculate XIRR
Public Instance Methods
xirr(midpoint, options)
click to toggle source
Calculates yearly Internal Rate of Return @return [BigDecimal] @param midpoint [Float] An initial guess rate will override the {Cashflow#irr_guess}
# File lib/xirr/bisection.rb, line 11 def xirr(midpoint, options) # Initial values left = [BigDecimal(-0.99999999, Xirr::PRECISION), cf.irr_guess].min right = [BigDecimal(9.99999999, Xirr::PRECISION), cf.irr_guess + 1].max @original_right = right midpoint ||= cf.irr_guess midpoint, runs = loop_rates(left, midpoint, right, options[:iteration_limit]) get_answer(midpoint, options, runs) end
Private Instance Methods
bisection(left, midpoint, right)
click to toggle source
@param left [BigDecimal] @param midpoint [BigDecimal] @param right [BigDecimal] @return [Array] Calculates the Bisections
# File lib/xirr/bisection.rb, line 40 def bisection(left, midpoint, right) _left = xnpv(left).positive? _mid = xnpv(midpoint).positive? if _left && _mid return left, left, left, true if xnpv(right).positive? # Not Enough Precision in the left to find the IRR end if _left == _mid return midpoint, format_irr(midpoint, right), right, false # Result is to the Right else return left, format_irr(left, midpoint), midpoint, false # Result is to the Left end end
format_irr(left, right)
click to toggle source
@param left [Float] @param right [Float] @return [Float] IRR of the Cashflow
# File lib/xirr/bisection.rb, line 56 def format_irr(left, right) irr = (right+left) / 2 end
get_answer(midpoint, options, runs)
click to toggle source
# File lib/xirr/bisection.rb, line 60 def get_answer(midpoint, options, runs) if runs >= options[:iteration_limit] if options[:raise_exception] raise ArgumentError, "Did not converge after #{runs} tries." else nil end else midpoint.round Xirr::PRECISION end end
loop_rates(left, midpoint, right, iteration_limit)
click to toggle source
# File lib/xirr/bisection.rb, line 72 def loop_rates(left, midpoint, right, iteration_limit) runs = 0 while (right - left).abs > Xirr::EPS && runs < iteration_limit do runs += 1 left, midpoint, right, should_stop = bisection(left, midpoint, right) break if should_stop if right_limit_reached?(midpoint) right *= 2 @original_right *= 2 end end return midpoint, runs end
right_limit_reached?(midpoint)
click to toggle source
@param midpoint [BigDecimal] @return [Boolean] Checks if result is the right limit.
# File lib/xirr/bisection.rb, line 31 def right_limit_reached?(midpoint) (@original_right - midpoint).abs < Xirr::EPS end