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