Class: Apy::Interest

Inherits:
Object
  • Object
show all
Includes:
Calculable
Defined in:
lib/apy/interest.rb

Overview

An interest object; Given an apy & date range, prepares various methods to calculate with

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Calculable

#compound, #dca_compound, #weighted_harmonic_mean

Constructor Details

#initialize(apy:, start_date: Date.today, end_date: Date.today.next_year, days_per_term: 365) ⇒ Interest

Returns a new instance of Interest.

Examples:

A 10% APY, intended to be used in calculations over 2y:

d1 = Date.parse "2020-01-01"
d2 = Date.parse "2022-01-01"
Interest.new(apy: 0.1, start_date: d1, end_date: d2)

An interest object _yielding 10% over the course of 2y_:

d1 = Date.parse "2020-01-01"
d2 = Date.parse "2022-01-01"
Interest.new(apy: 0.1, start_date: d1, end_date: d2, days_per_term: 730)

The above example, but instantiated with an apy of 5%:

d1 = Date.parse "2020-01-01"
d2 = Date.parse "2022-01-01"
Interest.new(apy: 0.05, start_date: d1, end_date: d2)

Parameters:

  • apy (Float)

    Annual/Average Percent Yield – an expected pct return over the course of a year

  • start_date (Date) (defaults to: Date.today)

    The beginning of the interest period; Defaults to today

  • end_date (Date) (defaults to: Date.today.next_year)

    The end of the interest period; Defaults to 1y from today

  • days_per_term (Integer) (defaults to: 365)

    Days per compound interest term; Defaults to 365 days



30
31
32
33
34
35
# File 'lib/apy/interest.rb', line 30

def initialize(apy:, start_date: Date.today, end_date: Date.today.next_year, days_per_term: 365)
  fail(ArgumentError, "apy must be a positive Float") unless apy.positive? && apy.is_a?(Float)

  @apy = apy
  @terms = Interest.get_term_size(start_date, end_date, days_per_term)
end

Instance Attribute Details

#apyObject (readonly)

Returns the value of attribute apy.



11
12
13
# File 'lib/apy/interest.rb', line 11

def apy
  @apy
end

Class Method Details

.get_term_size(start_date, end_date, days_per_term) ⇒ Integer

Returns The actual number of terms completed.

Parameters:

  • days_per_term (Integer)

    Number of days that pass before an entire term ends. Defaults to 365

Returns:

  • (Integer)

    The actual number of terms completed



40
41
42
# File 'lib/apy/interest.rb', line 40

def get_term_size(start_date, end_date, days_per_term)
  ((end_date - start_date) / days_per_term).round
end

Instance Method Details

#dca(in_per_split, times: 1) ⇒ Object

Note:

This assumes you wish to maximize dca returns; the in_per_split is deposited before the interest is calculated

Note:

If this method is too inflexible for your use case, you should use the Calculable module directly

Given a series of investments, calculate the DCA return

Examples:

Investing 3.29 everyday for a year:

Apy::Interest.new(apy: 0.1).dca(3.29, times: 365) == 1263.12

Investing 23.08 every week for a year:

Apy::Interest.new(apy: 0.1).dca(23.08, times: 52) == 1263.43

Investing 100 every month for a year:

Apy::Interest.new(apy: 0.1).dca(23.08, times: 12) == 1267.29

Investing 300 every quarter for a year:

Apy::Interest.new(apy: 0.1).dca(300, times: 4) == 1277.64

Investing 600 semi-annualy for a year:

Apy::Interest.new(apy: 0.1).dca(600, times: 2) == 1292.66

Parameters:

  • in_per_split (Numeric)

    Value of newly invested funds per term; Will be zipped with #apy & term size

  • times (Integer) (defaults to: 1)

    The number of times per term interest is accrued; Defaults to 1 (flat rate)

See Also:



69
70
71
72
73
74
75
# File 'lib/apy/interest.rb', line 69

def dca(in_per_split, times: 1)
  split = @terms * times
  adjusted_apy = apy / times
  range = split.times.map { [in_per_split, adjusted_apy] }

  dca_compound(range, times: times)
end

#total(principal, times: 1) ⇒ Object

Given a principal amount, return the ending balance

Parameters:

  • principal (Numeric)

    Initial investment

  • times (Integer) (defaults to: 1)

    The number of times per term interest is accrued; Defaults to 1 (flat rate)

See Also:



49
50
51
# File 'lib/apy/interest.rb', line 49

def total(principal, times: 1)
  compound(principal, rate: apy, times: times, terms: @terms)
end