Class: Finance::Loan

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

Constant Summary collapse

PAYMENT_TYPE_MAPPING =
{ end: 0.0, beginning: 1.0 }.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**options) ⇒ Loan

Create a new Loan instance.



44
45
46
47
48
49
50
51
52
53
# File 'lib/finance/loan.rb', line 44

def initialize(**options)
  initialize_payment_type(options[:ptype])
  @nominal_rate  = options.fetch(:nominal_rate, 0).to_f
  @duration      = options.fetch(:duration, 1).to_f
  @amount        = options.fetch(:amount, 0).to_f
  @future_value  = options.fetch(:future_value, 0).to_f
  @period        = options[:period]
  @payment       = options[:payment]
  @monthly_rate  = @nominal_rate / 12
end

Instance Attribute Details

#amountFloat

Returns The amount of loan request (I.e. a present value) You can use #pv method to calculate value if param is not defined. Defaults to 0.

Returns:

  • (Float)

    The amount of loan request (I.e. a present value) You can use #pv method to calculate value if param is not defined. Defaults to 0.



10
11
12
# File 'lib/finance/loan.rb', line 10

def amount
  @amount
end

#durationFloat

Returns The number of periods to be compounded for. (I.e. Nper()) Defaults to 1. You can use #nper method to calculate value if param is not defined.

Returns:

  • (Float)

    The number of periods to be compounded for. (I.e. Nper()) Defaults to 1. You can use #nper method to calculate value if param is not defined.



29
30
31
# File 'lib/finance/loan.rb', line 29

def duration
  @duration
end

#future_valueFloat

Returns Future value. You can use #fv method to calculate value if param is not defined. Defaults to 0.

Returns:

  • (Float)

    Future value. You can use #fv method to calculate value if param is not defined. Defaults to 0.



34
35
36
# File 'lib/finance/loan.rb', line 34

def future_value
  @future_value
end

#monthly_rateFloat (readonly)

Returns The monthly rate is the nominal annual rate divided by 12. Defaults to 0.

Returns:

  • (Float)

    The monthly rate is the nominal annual rate divided by 12. Defaults to 0.



24
25
26
# File 'lib/finance/loan.rb', line 24

def monthly_rate
  @monthly_rate
end

#nominal_rateFloat

Returns The nominal annual rate of interest as decimal (not per cent). (e.g., 13% -> 0.13) Defaults to 0.

Returns:

  • (Float)

    The nominal annual rate of interest as decimal (not per cent). (e.g., 13% -> 0.13) Defaults to 0.



20
21
22
# File 'lib/finance/loan.rb', line 20

def nominal_rate
  @nominal_rate
end

#paymentFloat

Returns The (fixed) periodic payment. You can use #pmt method to calculate value if param is not defined.

Returns:

  • (Float)

    The (fixed) periodic payment. You can use #pmt method to calculate value if param is not defined.



38
39
40
# File 'lib/finance/loan.rb', line 38

def payment
  @payment
end

#periodFloat

Returns Period under consideration.

Returns:

  • (Float)

    Period under consideration.



41
42
43
# File 'lib/finance/loan.rb', line 41

def period
  @period
end

#ptypeInteger

Returns Specification of whether payment is made at the beginning (ptype = 1) or the end (ptype = 0) of each period. Defaults to 0.

Returns:

  • (Integer)

    Specification of whether payment is made at the beginning (ptype = 1) or the end (ptype = 0) of each period. Defaults to 0.



15
16
17
# File 'lib/finance/loan.rb', line 15

def ptype
  @ptype
end

Instance Method Details

#fv(payment: nil) ⇒ Float

Fv computes future value at the end of some periods (duration).

Required Loan arguments: nominal_rate, duration, payment, amount*

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 0.05, duration: 120, amount: -100, payment: -200).fv
#=> 15692.928894335748

Parameters:

  • payment (Float) (defaults to: nil)

    The (fixed) periodic payment. In case you don’t want to modify the original loan, use this parameter to recalculate fv.

Returns:

  • (Float)

    The value at the end of the ‘duration` periods.

Raises:

  • (ArgumentError)

See Also:



171
172
173
174
175
176
177
178
179
180
# File 'lib/finance/loan.rb', line 171

def fv(payment: nil)
  raise ArgumentError, 'no payment given' if self.payment.nil? && payment.nil?

  final_payment = payment || self.payment

  factor = (1.0 + monthly_rate)**duration
  second_factor = (factor - 1) * (1 + monthly_rate * ptype) / monthly_rate

  -((amount * factor) + (final_payment.to_f * second_factor))
end

#ipmtFloat

IPmt computes interest payment for a loan under a given period.

Required Loan arguments: period, nominal_rate, duration, amount, future_value*

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1).ipmt
#=> -17.166666666666668

Returns:

  • (Float)

    The interest payment for a loan.

Raises:

  • (ArgumentError)

See Also:



104
105
106
107
108
109
110
111
112
113
# File 'lib/finance/loan.rb', line 104

def ipmt
  raise ArgumentError, 'no period given' if period.nil?

  ipmt_val = remaining_balance * monthly_rate
  if ptype == PAYMENT_TYPE_MAPPING[:beginning]
    period == 1 ? 0.0 : (ipmt_val / 1 + monthly_rate)
  else
    ipmt_val
  end
end

#nperFloat

Nper computes the number of periodic payments.

Required Loan arguments: payment, nominal_rate, period, amount, future_value*

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 0.07, amount: 8000, payment: -150).nper
#=> 64.0733487706618586

Returns:

  • (Float)

    The number of periodic payments.



146
147
148
149
150
# File 'lib/finance/loan.rb', line 146

def nper
  z = payment * (1.0 + monthly_rate * ptype) / monthly_rate

  Math.log(-future_value + z / (amount + z)) / Math.log(1.0 + monthly_rate)
end

#pmtNumeric

Pmt computes the payment against a loan principal plus interest (future_value = 0).

It can also be used to calculate the recurring payments needed to achieve
a certain future value given an initial deposit,
a fixed periodically compounded interest rate, and the total number of periods.

Required Loan arguments: nominal_rate, duration, amount, future_value*

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 0.1, duration: 12, amount: 1000, ptype: :end).pmt
#=> 87.9158872300099

Returns:

  • (Numeric)

    The (fixed) periodic payment.

See Also:



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/finance/loan.rb', line 75

def pmt
  factor = (1.0 + monthly_rate)**duration
  second_factor =
    if monthly_rate.zero?
      duration
    else
      (factor - 1) * (1 + monthly_rate * ptype) / monthly_rate
    end

  -((future_value + amount * factor) / second_factor)
end

#ppmtFloat

PPmt computes principal payment for a loan under a given period.

Required Loan arguments: period, nominal_rate, duration, amount, future_value*

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1).ppmt
#=> -200.58192368678277

Returns:

  • (Float)

    The principal payment for a loan under a given period.

See Also:



132
133
134
# File 'lib/finance/loan.rb', line 132

def ppmt
  pmt - ipmt
end

#pvFloat

Pv computes present value.

Required Loan arguments: nominal_rate, duration, payment, future_value, *ptype

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 0.24, duration: 12, future_value: 1000, payment: -300, ptype: :ending).pv
#=> 2384.1091906935

Returns:

  • (Float)

    The present value.

See Also:



198
199
200
201
202
203
# File 'lib/finance/loan.rb', line 198

def pv
  factor = (1.0 + monthly_rate)**duration
  second_factor = (factor - 1) * (1 + monthly_rate * ptype) / monthly_rate

  -(future_value + (payment.to_f * second_factor)) / factor
end

#rate(tolerance: 1e-6, iterations: 100, initial_guess: 0.1) ⇒ Float

Rate computes the interest rate per period

by running Newton Rapson to find an approximate value.

Examples:

require 'finance_rb'
Finance::Loan.new(nominal_rate: 10, amount: -3500, payment: 0, duration: 10, future_value: 10000).rate
#=> 0.11069085371426901

Parameters:

  • tolerance (Float) (defaults to: 1e-6)

    Required tolerance for the solution.

  • initial_guess (Float) (defaults to: 0.1)

    Starting guess for solving the rate of interest.

  • iterations (Integer) (defaults to: 100)

    Maximum iterations in finding the solution.

Returns:

  • (Float)

    The interest rate.

See Also:



225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/finance/loan.rb', line 225

def rate(tolerance: 1e-6, iterations: 100, initial_guess: 0.1)
  next_iteration_rate = nil
  current_iteration_rate = initial_guess

  (0..iterations).each do |iteration|
    next_iteration_rate = current_iteration_rate - rate_ratio(current_iteration_rate)
    break if (next_iteration_rate - current_iteration_rate).abs <= tolerance
    current_iteration_rate = next_iteration_rate
  end

  next_iteration_rate
end