# Class: Finance::Amortization

Inherits:
Object
• Object
show all
Defined in:
lib/finance/amortization.rb

## Overview

Note:

There are two ways to create an amortization. The first example uses the amortize method for the Numeric class. The second calls Amortization.new directly.

the Amortization class provides an interface for working with loan amortizations.

Examples:

Borrow \$250,000 under a 30 year, fixed-rate loan with a 4.25% APR

``````rate = Rate.new(0.0425, :apr, :duration => (30 * 12))
amortization = 250000.amortize(rate)``````

Borrow \$250,000 under a 30 year, adjustable rate loan, with an APR starting at 4.25%, and increasing by 1% every five years

``````values = %w{ 0.0425 0.0525 0.0625 0.0725 0.0825 0.0925 }
rates = values.collect { |value| Rate.new( value, :apr, :duration = (5 * 12) ) }
arm = Amortization.new(250000, *rates)``````

Borrow \$250,000 under a 30 year, fixed-rate loan with a 4.25% APR, but pay \$150 extra each month

``````rate = Rate.new(0.0425, :apr, :duration => (5 * 12))
extra_payments = 250000.amortize(rate){ |period| period.payment - 150 }``````

## Instance Attribute Summary collapse

The balance of the loan at the end of the amortization period (usually zero).

The required monthly payment.

The principal amount of the loan.

The interest rates used for calculating the amortization.

## Class Method Summary collapse

• The periodic payment due on a loan.

## Instance Method Summary collapse

• compare two Amortization instances.

• The amount of any additional payments in each period.

• private

amortize the balance of loan with the given interest rate.

• private

compute the amortization of the principal.

• The time required to pay off the loan, in months.

• constructor

create a new Amortization instance.

• The amount of interest charged in each period.

• The amount of the payment in each period.

## Constructor Details

### #initialize(principal, *rates, &block) ⇒ Amortization

create a new Amortization instance

Parameters:

• principal (DecNum)

the initial amount of the loan or investment

• rates (Rate)

the applicable interest rates

• block (Proc)
 ``` 132 133 134 135 136 137 138 139 140 141 142``` ```# File 'lib/finance/amortization.rb', line 132 def initialize(principal, *rates, &block) @principal = Flt::DecNum.new(principal.to_s) @rates = rates @block = block # compute the total duration from all of the rates. @periods = (rates.collect { |r| r.duration }).sum @period = 0 compute end```

## Instance Attribute Details

Returns the balance of the loan at the end of the amortization period (usually zero).

Returns:

• (DecNum)

the balance of the loan at the end of the amortization period (usually zero)

 ``` 24 25 26``` ```# File 'lib/finance/amortization.rb', line 24 def balance @balance end```

Returns the required monthly payment. For loans with more than one rate, returns nil.

Returns:

• (DecNum)

the required monthly payment. For loans with more than one rate, returns nil

 ``` 27 28 29``` ```# File 'lib/finance/amortization.rb', line 27 def payment @payment end```

Returns the principal amount of the loan.

Returns:

• (DecNum)

the principal amount of the loan

 ``` 30 31 32``` ```# File 'lib/finance/amortization.rb', line 30 def principal @principal end```

Returns the interest rates used for calculating the amortization.

Returns:

• (Array)

the interest rates used for calculating the amortization

 ``` 33 34 35``` ```# File 'lib/finance/amortization.rb', line 33 def rates @rates end```

## Class Method Details

### .payment(principal, rate, periods) ⇒ DecNum

Note:

in most cases, you will probably want to use rate.monthly when calling this function outside of an Amortization instance.

Returns the periodic payment due on a loan.

Examples:

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
rate.duration #=> 360
Amortization.payment(200000, rate.monthly, rate.duration) #=> DecNum('-926.23')``````

Parameters:

• principal (DecNum)

the initial amount of the loan or investment

• rate (Rate)

the applicable interest rate (per period)

• periods (Integer)

the number of periods needed for repayment

Returns:

• (DecNum)

the periodic payment due on a loan

 ``` 174 175 176 177 178 179 180 181``` ```# File 'lib/finance/amortization.rb', line 174 def Amortization.payment(principal, rate, periods) if rate.zero? # simplified formula to avoid division-by-zero when interest rate is zero return -(principal / periods).round(2) else return -(principal * (rate + (rate / ((1 + rate) ** periods - 1)))).round(2) end end```

## Instance Method Details

### #==(amortization) ⇒ Numeric

compare two Amortization instances

Parameters:

Returns:

 ``` 39 40 41``` ```# File 'lib/finance/amortization.rb', line 39 def ==(amortization) self.principal == amortization.principal and self.rates == amortization.rates and self.payments == amortization.payments end```

Returns the amount of any additional payments in each period.

Examples:

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
amt = 300000.amortize(rate){ |payment| payment.amount-100}
amt.additional_payments #=> [DecNum('-100.00'), DecNum('-100.00'), ... ]``````

Returns:

• (Array)

the amount of any additional payments in each period

 ``` 49 50 51``` ```# File 'lib/finance/amortization.rb', line 49 def additional_payments @transactions.find_all(&:payment?).collect{ |p| p.difference } end```

### #amortize(rate) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

amortize the balance of loan with the given interest rate

Parameters:

• rate (Rate)

the interest rate to use in the amortization

Returns:

• none

 ``` 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84``` ```# File 'lib/finance/amortization.rb', line 57 def amortize(rate) # For the purposes of calculating a payment, the relevant time # period is the remaining number of periods in the loan, not # necessarily the duration of the rate itself. periods = @periods - @period amount = Amortization.payment @balance, rate.monthly, periods pmt = Payment.new(amount, :period => @period) if @block then pmt.modify(&@block) end rate.duration.to_i.times do # Do this first in case the balance is zero already. if @balance.zero? then break end # Compute and record interest on the outstanding balance. int = (@balance * rate.monthly).round(2) interest = Interest.new(int, :period => @period) @balance += interest.amount @transactions << interest.dup # Record payment. Don't pay more than the outstanding balance. if pmt.amount.abs > @balance then pmt.amount = -@balance end @transactions << pmt.dup @balance += pmt.amount @period += 1 end end```

### #compute ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

compute the amortization of the principal

Returns:

• none

 ``` 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110``` ```# File 'lib/finance/amortization.rb', line 89 def compute @balance = @principal @transactions = [] @rates.each do |rate| amortize(rate) end # Add any remaining balance due to rounding error to the last payment. unless @balance.zero? @transactions.find_all(&:payment?)[-1].amount -= @balance @balance = 0 end if @rates.length == 1 @payment = self.payments else @payment = nil end @transactions.freeze end```

### #duration ⇒ Integer

Returns the time required to pay off the loan, in months.

Examples:

In most cases, the duration is equal to the total duration of all rates

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
amt = 300000.amortize(rate)
amt.duration #=> 360``````

Extra payments may reduce the duration

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
amt = 300000.amortize(rate){ |payment| payment.amount-100}
amt.duration #=> 319``````

Returns:

• (Integer)

the time required to pay off the loan, in months

 ``` 122 123 124``` ```# File 'lib/finance/amortization.rb', line 122 def duration self.payments.length end```

### #inspect ⇒ Object

 ``` 145 146 147``` ```# File 'lib/finance/amortization.rb', line 145 def inspect "Amortization.new(#{@principal})" end```

### #interest ⇒ Array

Returns the amount of interest charged in each period.

Examples:

find the total cost of interest for a loan

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
amt = 300000.amortize(rate)
amt.interest.sum #=> DecNum('200163.94')``````

find the total interest charges in the first six months

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
amt = 300000.amortize(rate)
amt.interest[0,6].sum #=> DecNum('5603.74')``````

Returns:

• (Array)

the amount of interest charged in each period

 ``` 159 160 161``` ```# File 'lib/finance/amortization.rb', line 159 def interest @transactions.find_all(&:interest?).collect{ |p| p.amount } end```

### #payments ⇒ Array

Returns the amount of the payment in each period.

Examples:

find the total payments for a loan

``````rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
amt = 300000.amortize(rate)
amt.payments.sum #=> DecNum('-500163.94')``````

Returns:

• (Array)

the amount of the payment in each period

 ``` 189 190 191``` ```# File 'lib/finance/amortization.rb', line 189 def payments @transactions.find_all(&:payment?).collect{ |p| p.amount } end```