Module: Finrb::Yields

Defined in:
lib/finrb/yields.rb,
sig/finrb.rbs

Overview

Money-market yield and interest-rate conversion calculations.

Class Method Summary collapse

Class Method Details

.bdy(d:, f:, t:) ⇒ decimal

Computing bank discount yield (BDY) for a T-bill

Examples:

Finrb::Yields.bdy(d=1500,f=100000,t=120)

Parameters:

  • d

    the dollar discount, which is equal to the difference between the face value of the bill and the purchase price

  • f

    the face value (par value) of the bill

  • t

    number of days remaining until maturity

  • d: (number)
  • f: (number)
  • t: (number)

Returns:

  • (decimal)


17
18
19
20
21
22
23
# File 'lib/finrb/yields.rb', line 17

def self.bdy(d:, f:, t:)
  d = Validation.decimal(d, name: 'dollar discount')
  f = Validation.positive_decimal(f, name: 'face value', error: DomainError)
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)

  (d * 360 / f / t)
end

.bdy2mmy(bdy:, t:) ⇒ decimal

Computing money market yield (MMY) for a T-bill

Examples:

Finrb::Yields.bdy2mmy(bdy=0.045,t=120)

Parameters:

  • bdy

    bank discount yield

  • t

    number of days remaining until maturity

  • bdy: (number)
  • t: (number)

Returns:

  • (decimal)

Raises:



31
32
33
34
35
36
37
38
# File 'lib/finrb/yields.rb', line 31

def self.bdy2mmy(bdy:, t:)
  bdy = Validation.decimal(bdy, name: 'bank discount yield')
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)
  denominator = 360 - (t * bdy)
  raise(DomainError, 'Bank discount yield and time to maturity must imply a positive purchase price.') unless denominator.positive?

  (bdy * 360 / denominator)
end

.ear(r:, m:) ⇒ decimal

Convert stated annual rate to the effective annual rate

Examples:

Finrb::Yields.ear(r=0.12,m=12)
Finrb::Yields.ear(0.04,365)

Parameters:

  • r

    stated annual rate

  • m

    number of compounding periods per year

  • r: (number)
  • m: (number)

Returns:

  • (decimal)


49
50
51
52
53
54
# File 'lib/finrb/yields.rb', line 49

def self.ear(r:, m:)
  r = Validation.decimal(r, name: 'stated annual rate')
  m = Validation.positive_decimal(m, name: 'compounding periods', error: DomainError)

  ((compounding_base(r, m)**m) - 1)
end

.ear2bey(ear:) ⇒ decimal

bond-equivalent yield (BEY), 2 x the semiannual discount rate

Examples:

Finrb::Yields.ear2bey(ear=0.08)

Parameters:

  • ear

    effective annual rate

  • ear: (number)

Returns:

  • (decimal)


75
76
77
78
79
# File 'lib/finrb/yields.rb', line 75

def self.ear2bey(ear:)
  ear = Validation.decimal_at_least(ear, minimum: -1, name: 'effective annual rate', error: DomainError)

  (((ear + 1).sqrt - 1) * 2)
end

.ear2hpr(ear:, t:) ⇒ decimal

Computing HPR, the holding period return

Examples:

Finrb::Yields.ear2hpr(ear=0.05039,t=150)

Parameters:

  • ear

    effective annual rate

  • t

    number of days remaining until maturity

  • ear: (number)
  • t: (number)

Returns:

  • (decimal)


87
88
89
90
91
92
# File 'lib/finrb/yields.rb', line 87

def self.ear2hpr(ear:, t:)
  ear = Validation.decimal_at_least(ear, minimum: -1, name: 'effective annual rate', error: DomainError)
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)

  (((ear + 1)**(t / 365)) - 1)
end

.ear_continuous(r:) ⇒ decimal

Convert stated annual rate to the effective annual rate with continuous compounding

Examples:

Finrb::Yields.ear_continuous(r=0.1)
Finrb::Yields.ear_continuous(0.03)

Parameters:

  • r

    stated annual rate

  • r: (number)

Returns:

  • (decimal)


64
65
66
67
68
# File 'lib/finrb/yields.rb', line 64

def self.ear_continuous(r:)
  r = Validation.decimal(r, name: 'stated annual rate')

  (r.exp - 1)
end

.eir(r:, n: 1, p: 12, type: 'e') ⇒ decimal

Note:

An interest rate to be applied n times p.a. can be converted to an equivalent rate to be applied p times p.a.

Equivalent/proportional Interest Rates

Examples:

# monthly interest rat equivalent to 5% compounded per year
Finrb::Yields.eir(r=0.05,n=1,p=12)
# monthly interest rat equivalent to 5% compounded per half year
Finrb::Yields.eir(r=0.05,n=2,p=12)
# monthly interest rat equivalent to 5% compounded per quarter
Finrb::Yields.eir(r=0.05,n=4,p=12)
# annual interest rate equivalent to 5% compounded per month
Finrb::Yields.eir(r=0.05,n=12,p=1)
# this is equivalent to
Finrb::Yields.ear(r=0.05,m=12)
# quarter interest rate equivalent to 5% compounded per year
Finrb::Yields.eir(r=0.05,n=1,p=4)
# quarter interest rate equivalent to 5% compounded per month
Finrb::Yields.eir(r=0.05,n=12,p=4)
# monthly proportional interest rate which is equivalent to a simple annual interest
Finrb::Yields.eir(r=0.05,p=12,type='p')

Parameters:

  • r

    interest rate to be applied n times per year (r is annual rate!)

  • n (defaults to: 1)

    times that the interest rate r were compounded per year

  • p (defaults to: 12)

    times that the equivalent rate were compounded per year

  • type (defaults to: 'e')

    equivalent interest rates ('e',default) or proportional interest rates ('p')

  • r: (number)
  • n: (number) (defaults to: 1)
  • p: (number) (defaults to: 12)
  • type: (String) (defaults to: 'e')

Returns:

  • (decimal)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/finrb/yields.rb', line 129

def self.eir(r:, n: 1, p: 12, type: 'e')
  r = Validation.decimal(r, name: 'annual rate')
  n = Validation.positive_decimal(n, name: 'source compounding periods', error: DomainError)
  p = Validation.positive_decimal(p, name: 'target compounding periods', error: DomainError)
  type = type.to_s

  case type
  when 'e'
    eir = (compounding_base(r, n)**(n / p)) - 1
  when 'p'
    eir = r / p
  else
    raise(ArgumentError, "conversion type must be 'e' (equivalent) or 'p' (proportional)")
  end
  eir
end

.hpr2bey(hpr:, t:) ⇒ decimal

bond-equivalent yield (BEY), 2 x the semiannual discount rate

Examples:

Finrb::Yields.hpr2bey(hpr=0.02,t=3)

Parameters:

  • hpr

    holding period return

  • t

    number of month remaining until maturity

  • hpr: (number)
  • t: (number)

Returns:

  • (decimal)


152
153
154
155
156
157
# File 'lib/finrb/yields.rb', line 152

def self.hpr2bey(hpr:, t:)
  hpr = Validation.decimal_at_least(hpr, minimum: -1, name: 'holding period return', error: DomainError)
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)

  ((((hpr + 1)**(6 / t)) - 1) * 2)
end

.hpr2ear(hpr:, t:) ⇒ decimal

Convert holding period return to the effective annual rate

Examples:

Finrb::Yields.hpr2ear(hpr=0.015228,t=120)

Parameters:

  • hpr

    holding period return

  • t

    number of days remaining until maturity

  • hpr: (number)
  • t: (number)

Returns:

  • (decimal)


165
166
167
168
169
170
# File 'lib/finrb/yields.rb', line 165

def self.hpr2ear(hpr:, t:)
  hpr = Validation.decimal_at_least(hpr, minimum: -1, name: 'holding period return', error: DomainError)
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)

  (((hpr + 1)**(365 / t)) - 1)
end

.hpr2mmy(hpr:, t:) ⇒ decimal

Computing money market yield (MMY) for a T-bill

Examples:

Finrb::Yields.hpr2mmy(hpr=0.01523,t=120)

Parameters:

  • hpr

    holding period return

  • t

    number of days remaining until maturity

  • hpr: (number)
  • t: (number)

Returns:

  • (decimal)


178
179
180
181
182
183
# File 'lib/finrb/yields.rb', line 178

def self.hpr2mmy(hpr:, t:)
  hpr = Validation.decimal(hpr, name: 'holding period return')
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)

  (hpr * 360 / t)
end

.mmy2hpr(mmy:, t:) ⇒ decimal

Computing HPR, the holding period return

Examples:

Finrb::Yields.mmy2hpr(mmy=0.04898,t=150)

Parameters:

  • mmy

    money market yield

  • t

    number of days remaining until maturity

  • mmy: (number)
  • t: (number)

Returns:

  • (decimal)


191
192
193
194
195
196
# File 'lib/finrb/yields.rb', line 191

def self.mmy2hpr(mmy:, t:)
  mmy = Validation.decimal(mmy, name: 'money market yield')
  t = Validation.positive_decimal(t, name: 'time to maturity', error: DomainError)

  (mmy * t / 360)
end

.r_continuous(r:, m:) ⇒ decimal

Convert a given norminal rate to a continuous compounded rate

Examples:

Finrb::Yields.r_continuous(r=0.03,m=4)

Parameters:

  • r

    norminal rate

  • m

    number of times compounded each year

  • r: (number)
  • m: (number)

Returns:

  • (decimal)


204
205
206
207
208
209
# File 'lib/finrb/yields.rb', line 204

def self.r_continuous(r:, m:)
  r = Validation.decimal(r, name: 'nominal rate')
  m = Validation.positive_decimal(m, name: 'compounding periods', error: DomainError)

  (m * compounding_base(r, m).log)
end

.r_norminal(rc:, m:) ⇒ decimal

Convert a given continuous compounded rate to a norminal rate

Examples:

Finrb::Yields.r_norminal(0.03,1)
Finrb::Yields.r_norminal(rc=0.03,m=4)

Parameters:

  • rc

    continuous compounded rate

  • m

    number of desired times compounded each year

  • rc: (number)
  • m: (number)

Returns:

  • (decimal)


220
221
222
223
224
225
# File 'lib/finrb/yields.rb', line 220

def self.r_norminal(rc:, m:)
  rc = Validation.decimal(rc, name: 'continuously compounded rate')
  m = Validation.positive_decimal(m, name: 'compounding periods', error: DomainError)

  (m * ((rc / m).exp - 1))
end