Class: Finrb::Amortization
- Inherits:
-
Object
- Object
- Finrb::Amortization
- Defined in:
- lib/finrb/amortization.rb
Overview
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.
Instance Attribute Summary collapse
-
#balance ⇒ Flt::DecNum
readonly
The balance of the loan at the end of the amortization period (usually zero).
-
#payment ⇒ Flt::DecNum
readonly
The required monthly payment.
-
#principal ⇒ Flt::DecNum
readonly
The principal amount of the loan.
-
#rates ⇒ Array
readonly
The interest rates used for calculating the amortization.
Class Method Summary collapse
-
.payment(principal, rate, periods) ⇒ Flt::DecNum
The periodic payment due on a loan.
Instance Method Summary collapse
-
#==(other) ⇒ Numeric
compare two Amortization instances.
-
#additional_payments ⇒ Array
The amount of any additional payments in each period.
-
#amortize(rate) ⇒ Object
private
amortize the balance of loan with the given interest rate.
-
#compute ⇒ Object
private
compute the amortization of the principal.
-
#duration ⇒ Integer
The time required to pay off the loan, in months.
-
#initialize(principal, *rates, &block) ⇒ Amortization
constructor
create a new Amortization instance.
- #inspect ⇒ Object
-
#interest ⇒ Array
The amount of interest charged in each period.
-
#payments ⇒ Array
The amount of the payment in each period.
Constructor Details
#initialize(principal, *rates, &block) ⇒ Amortization
create a new Amortization instance
63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/finrb/amortization.rb', line 63 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.sum(&:duration) @period = 0 compute end |
Instance Attribute Details
#balance ⇒ Flt::DecNum (readonly)
Returns the balance of the loan at the end of the amortization period (usually zero).
26 27 28 |
# File 'lib/finrb/amortization.rb', line 26 def balance @balance end |
#payment ⇒ Flt::DecNum (readonly)
Returns the required monthly payment. For loans with more than one rate, returns nil.
29 30 31 |
# File 'lib/finrb/amortization.rb', line 29 def payment @payment end |
#principal ⇒ Flt::DecNum (readonly)
Returns the principal amount of the loan.
32 33 34 |
# File 'lib/finrb/amortization.rb', line 32 def principal @principal end |
#rates ⇒ Array (readonly)
Returns the interest rates used for calculating the amortization.
35 36 37 |
# File 'lib/finrb/amortization.rb', line 35 def rates @rates end |
Class Method Details
.payment(principal, rate, periods) ⇒ Flt::DecNum
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.
48 49 50 51 52 53 54 55 |
# File 'lib/finrb/amortization.rb', line 48 def self.payment(principal, rate, periods) if rate.zero? # simplified formula to avoid division-by-zero when interest rate is zero -(principal / periods).round(2) else -(principal * (rate + (rate / (((rate + 1)**periods) - 1)))).round(2) end end |
Instance Method Details
#==(other) ⇒ Numeric
compare two Amortization instances
79 80 81 |
# File 'lib/finrb/amortization.rb', line 79 def ==(other) (principal == other.principal) && (rates == other.rates) && (payments == other.payments) end |
#additional_payments ⇒ Array
Returns the amount of any additional payments in each period.
89 90 91 |
# File 'lib/finrb/amortization.rb', line 89 def additional_payments @transactions.filter_map { |trans| trans.difference if trans.payment? } 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
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/finrb/amortization.rb', line 97 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) pmt.modify(&@block) if @block rate.duration.to_i.times do # Do this first in case the balance is zero already. break if @balance.zero? # 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. pmt.amount = -@balance if pmt.amount.abs > @balance @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
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/finrb/amortization.rb', line 129 def compute @balance = @principal @transactions = [] @rates.each do |rate| amortize(rate) end # Add any remaining balance due to rounding error to the last payment. if @balance.nonzero? @transactions.reverse.find(&:payment?).amount -= @balance @balance = 0 end @payment = (payments[0] if @rates.length == 1) @transactions.freeze end |
#duration ⇒ Integer
Returns the time required to pay off the loan, in months.
158 159 160 |
# File 'lib/finrb/amortization.rb', line 158 def duration payments.length end |
#inspect ⇒ Object
163 164 165 |
# File 'lib/finrb/amortization.rb', line 163 def inspect "Amortization.new(#{@principal})" end |
#interest ⇒ Array
Returns the amount of interest charged in each period.
177 178 179 |
# File 'lib/finrb/amortization.rb', line 177 def interest @transactions.filter_map { |trans| trans.amount if trans.interest? } end |
#payments ⇒ Array
Returns the amount of the payment in each period.
187 188 189 |
# File 'lib/finrb/amortization.rb', line 187 def payments @transactions.filter_map { |trans| trans.amount if trans.payment? } end |