Class: Financier::Rate

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/financier/rate.rb

Constant Summary collapse

TYPES =

Accepted rate types

{ :apr       => "effective",
  :apy       => "effective",
  :effective => "effective",
  :nominal   => "nominal"
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rate, type, opts = {}) ⇒ Rate

create a new Rate instance

Examples:

create a 3.5% APR rate

Rate.new(0.035, :apr) #=> Rate(0.035, :apr)

Parameters:

  • rate (Numeric)

    the decimal value of the interest rate

  • type (Symbol)

    a valid rate type

  • opts (optional, Hash) (defaults to: {})

    set optional attributes

Options Hash (opts):

  • :duration (String)

    a time interval for which the rate is valid

  • :compounds (String) — default: :monthly

    the number of compounding periods per year

See Also:



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/financier/rate.rb', line 103

def initialize(rate, type, opts={})
  # Default monthly compounding.
  opts = { :compounds => :monthly }.merge opts

  # Set optional attributes..
  opts.each do |key, value|
    send("#{key}=", value)
  end

  # Set the rate in the proper way, based on the value of type.
  begin
    send("#{TYPES.fetch(type)}=", Flt::DecNum.new(rate.to_s))
  rescue KeyError
    raise ArgumentError, "type must be one of #{TYPES.keys.join(', ')}", caller
  end
end

Instance Attribute Details

#durationInteger

Returns the duration for which the rate is valid, in months.

Returns:

  • (Integer)

    the duration for which the rate is valid, in months



32
33
34
# File 'lib/financier/rate.rb', line 32

def duration
  @duration
end

#effectiveDecNum

Returns the effective interest rate.

Returns:

  • (DecNum)

    the effective interest rate



35
36
37
# File 'lib/financier/rate.rb', line 35

def effective
  @effective
end

#nominalDecNum

Returns the nominal interest rate.

Returns:

  • (DecNum)

    the nominal interest rate



38
39
40
# File 'lib/financier/rate.rb', line 38

def nominal
  @nominal
end

Class Method Details

.to_effective(rate, periods) ⇒ Object



4
5
6
7
8
9
10
# File 'lib/financier/rate.rb', line 4

def to_effective(rate, periods)
  rate, periods = Flt::DecNum.new(rate.to_s), Flt::DecNum.new(periods.to_s)

  return rate.exp - 1 if periods.infinite?

  (1 + rate / periods) ** periods - 1
end

.to_nominal(rate, periods) ⇒ Object



12
13
14
15
16
17
18
# File 'lib/financier/rate.rb', line 12

def to_nominal(rate, periods)
  rate, periods = Flt::DecNum.new(rate.to_s), Flt::DecNum.new(periods.to_s)

  return (rate + 1).log if periods.infinite?

  periods * ((1 + rate) ** (1 / periods) - 1)
end

Instance Method Details

#<=>(rate) ⇒ Numeric

compare two Rates, using the effective rate

Examples:

Which is better, a nominal rate of 15% compounded monthly, or 15.5% compounded semiannually?

r1 = Rate.new(0.15, :nominal) #=> Rate.new(0.160755, :apr)
r2 = Rate.new(0.155, :nominal, :compounds => :semiannually) #=> Rate.new(0.161006, :apr)
r1 <=> r2 #=> -1

Parameters:

  • rate (Rate)

    the comparison Rate

Returns:



48
49
50
# File 'lib/financier/rate.rb', line 48

def <=>(rate)
  @effective <=> rate.effective
end

#aprDecNum

Returns the effective interest rate.

Returns:

  • (DecNum)

    the effective interest rate



54
55
56
# File 'lib/financier/rate.rb', line 54

def apr
  self.effective
end

#apyDecNum

Returns the effective interest rate.

Returns:

  • (DecNum)

    the effective interest rate



60
61
62
# File 'lib/financier/rate.rb', line 60

def apy
  self.effective
end

#compounds=(input) ⇒ 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.

a convenience method which sets the value of @periods

Parameters:

  • input (Symbol, Numeric)

    the compounding frequency

Returns:

  • none

Raises:

  • (ArgumentError)

    if input is not an accepted keyword or Numeric



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/financier/rate.rb', line 69

def compounds=(input)
  @periods = case input
             when :annually     then Flt::DecNum.new(1)
             when :continuously then Flt::DecNum.infinity
             when :daily        then Flt::DecNum.new(365)
             when :monthly      then Flt::DecNum.new(12)
             when :quarterly    then Flt::DecNum.new(4)
             when :semiannually then Flt::DecNum.new(2)
             when Numeric       then Flt::DecNum.new(input.to_s)
             else raise ArgumentError
             end
end

#dailyObject



134
135
136
137
# File 'lib/financier/rate.rb', line 134

def daily
  # TODO - Add spec
  (self.effective / 360).round(15)
end

#inspectObject



120
121
122
# File 'lib/financier/rate.rb', line 120

def inspect
  "Rate.new(#{self.apr.round(6)}, :apr)"
end

#monthlyDecNum

Returns the monthly effective interest rate.

Examples:

rate = Rate.new(0.15, :nominal)
rate.apr.round(6) #=> DecNum('0.160755')
rate.monthly.round(6) #=> DecNum('0.013396')

Returns:

  • (DecNum)

    the monthly effective interest rate



130
131
132
# File 'lib/financier/rate.rb', line 130

def monthly
  (self.effective / 12).round(15)
end