class Bondie::Issue
Constants
- DEFAULT_APPROXIMATION_ERROR
Public Class Methods
new(coupon: nil, maturity_date: nil, coupon_frequency: nil)
click to toggle source
# File lib/bondie/issue.rb, line 8 def initialize(coupon: nil, maturity_date: nil, coupon_frequency: nil) @coupon = coupon @maturity_date = maturity_date @coupon_frequency = coupon_frequency end
Public Instance Methods
interest_payments(from_date)
click to toggle source
# File lib/bondie/issue.rb, line 18 def interest_payments(from_date) payments = [] date = @maturity_date while date >= from_date payments << date date = date.prev_month(12/@coupon_frequency) end payments.sort end
price(ytm, date, fees: 0)
click to toggle source
# File lib/bondie/issue.rb, line 14 def price(ytm, date, fees: 0) price_for_irr(irr_from_ytm(ytm), date, fees: fees) end
ytm(date, price: 100, fees: 0, approximation_error: DEFAULT_APPROXIMATION_ERROR)
click to toggle source
# File lib/bondie/issue.rb, line 28 def ytm(date, price: 100, fees: 0, approximation_error: DEFAULT_APPROXIMATION_ERROR) ytm_down, ytm_up = ytm_limits(price, date, fees: fees) approximate_ytm(ytm_down, ytm_up, price, date, fees: fees, approximation_error: approximation_error) end
Private Instance Methods
approximate_ytm(ytm_down, ytm_up, price, date, fees: 0, approximation_error: DEFAULT_APPROXIMATION_ERROR)
click to toggle source
# File lib/bondie/issue.rb, line 41 def approximate_ytm(ytm_down, ytm_up, price, date, fees: 0, approximation_error: DEFAULT_APPROXIMATION_ERROR) approx_ytm = (ytm_up + ytm_down) / 2.0 return approx_ytm if ((ytm_up - approx_ytm)/approx_ytm).abs <= approximation_error p = price(approx_ytm, date, fees: fees) ytm_down, ytm_up = p < price ? [ytm_down, approx_ytm] : [approx_ytm, ytm_up] approximate_ytm(ytm_down, ytm_up, price, date, fees: fees, approximation_error: approximation_error) end
irr_from_ytm(ytm)
click to toggle source
# File lib/bondie/issue.rb, line 36 def irr_from_ytm(ytm) (ytm/@coupon_frequency.to_f + 1) ** @coupon_frequency - 1 end
price_for_irr(irr, date, fees: 0)
click to toggle source
# File lib/bondie/issue.rb, line 57 def price_for_irr(irr, date, fees: 0) raise "Date is after maturity_date!" if date > @maturity_date last = date interest_payments(date).map do |payday| interest = @coupon * 100 * ((payday-last)/365) interest += 100 if payday == @maturity_date last = payday interest / ((1+irr) ** ((payday-date)/365)) end.inject(:+) / (1+fees) end
ytm_limits(price, date, fees: 0)
click to toggle source
# File lib/bondie/issue.rb, line 49 def ytm_limits(price, date, fees: 0) ytm_up = 0.1 ytm_up *= 10 while price(ytm_up, date, fees: fees) > price # IRR will be never lower than -1, so YTM should be never lower than -coupon_frequency (see irr_from_ytm) ytm_down = price(0, date, fees: fees) > price ? 0.0 : -@coupon_frequency.to_f [ytm_down, ytm_up] end