Module: Refinance::Annuities

Defined in:
lib/refinance/annuities.rb

Overview

This module contains methods for calculating the basic properties of annuities. Annuities are assumed to be an annuities immediate (that is, interest is accumulated before the payment).

The floating-point numbers you pass in as arguments can be instances of Float or BigDecimal. Actually, thanks to duck typing, they can be any objects that support the necessary operations.

Class Method Summary collapse

Class Method Details

.effective_interest_rate(nair, cppy) ⇒ Object

Determines the effective interest rate, given:

  • The nominal annual interest rate

  • The number of compounding periods per year



95
96
97
# File 'lib/refinance/annuities.rb', line 95

def self.effective_interest_rate(nair, cppy)
  (((nair / cppy) + 1) ** cppy) - 1
end

.improve_interest_rate(payment, periods, principal, guess) ⇒ Object

Iteratively improve an approximated interest rate for an annuity using the Newton-Raphson method. This method is used by ::interest_rate.



47
48
49
50
51
52
53
# File 'lib/refinance/annuities.rb', line 47

def self.improve_interest_rate(payment, periods, principal, guess)
  top = payment - (payment * ((guess + 1) ** -periods)) -
    (principal * guess)
  bottom = (periods * payment * ((guess + 1) ** (-periods - 1))) -
    principal
  guess - (top / bottom)
end

.interest_rate(payment, periods, principal, initial_guess = 0.1, precision = 0.0001, max_decimals = 8, max_iterations = 10) ⇒ Object

Determine an annuity’s interest rate over some period, given:

  • Periodic payment amount

  • Number of payment periods

  • Principal

This has no closed-form solution, so the answer is iteratively approximated with the Newton-Raphson method. After each improvement, the guess will be rounded; max_decimals is the number of decimal places to keep (if you set this high, the algorithm will be slow). max_iterations is the maximum number of iterations that will be attempted. It will stop iterating if the last improvement was less than precision in magnitude.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/refinance/annuities.rb', line 28

def self.interest_rate(payment, periods, principal, initial_guess = 0.1,
  precision = 0.0001, max_decimals = 8, max_iterations = 10)
  guess = initial_guess

  max_iterations.times do
    new_guess = improve_interest_rate(payment, periods, principal, guess).
      round(max_decimals)
    difference = (guess - new_guess).abs
    guess = new_guess
    break if difference < precision
  end

  guess
end

.payment(interest_rate, periods, principal) ⇒ Object

Determine an annuity’s periodic payment amount, given:

  • Interest rate over a period

  • Number of payment periods

  • Principal



62
63
64
# File 'lib/refinance/annuities.rb', line 62

def self.payment(interest_rate, periods, principal)
  (interest_rate * principal) / (1 - ((interest_rate + 1) ** -periods))
end

.periods(interest_rate, payment, principal) ⇒ Object

Determine the number of payment periods for an annuity, given:

  • Interest rate over a period

  • Periodic payment amount

  • Principal



73
74
75
76
# File 'lib/refinance/annuities.rb', line 73

def self.periods(interest_rate, payment, principal)
  -Math.log(1 - ((interest_rate * principal) / payment)) /
    Math.log(interest_rate + 1)
end

.principal(interest_rate, payment, periods) ⇒ Object

Determine an annuity’s principal, given:

  • Interest rate over a period

  • Periodic payment amount

  • Number of payment periods



85
86
87
# File 'lib/refinance/annuities.rb', line 85

def self.principal(interest_rate, payment, periods)
  (payment / interest_rate) * (1 - ((interest_rate + 1) ** -periods))
end