module BondDiscrete = struct (* Create a discrete cash flow object. (Payment, Time) record *) type cash_flow = { value : float ; time : float } (************** 4.1 **************) let rec bonds_price_discrete (cash_flows : cash_flow list) (r : float) : float = List.fold_left (fun accum flow -> accum +. flow.value /. (1.0 +. r)**flow.time) 0. cash_flows (************** 4.2 **************) module YieldToMaturityDetail = struct let rec find_top cash_flows top bond_price = if (bonds_price_discrete cash_flows top) > bond_price then find_top cash_flows (top *. 2.0) bond_price else top;; let rec find_r iteration cash_flows bottom top r bond_price accuracy = if iteration == 0 then r else let diff = (bonds_price_discrete cash_flows r) -. bond_price in if abs_float(diff) < accuracy then r else if diff > 0.0 then find_r (iteration-1) cash_flows r top (0.5 *. (top +. r)) bond_price accuracy else find_r (iteration-1) cash_flows bottom r (0.5 *. (r +. bottom)) bond_price accuracy;; let bonds_yield_to_maturity_discrete ?(max_iterations=200) ?(accuracy=0.00005) (cash_flows : cash_flow list) (bond_price : float) : float = let bottom = 0.0 in let top = (find_top cash_flows 1.0 bond_price) in let r = (0.5 *. (top +. bottom)) in find_r max_iterations cash_flows bottom top r bond_price accuracy;; end let bonds_yield_to_maturity_discrete = YieldToMaturityDetail.bonds_yield_to_maturity_discrete;; (************** 4.3 **************) (* Bond duration using discrete, annual compounding and a flat term structure *) let bonds_duration_discrete (cash_flows : cash_flow list) (r : float) : float = let rec solve cash_flows b d = match cash_flows with [] -> d /. b | h::t -> let dd = d +. h.time *. h.value /. (1.0 +. r) ** h.time in let bb = b +. h.value /. (1.0 +. r) ** h.time in solve t bb dd in solve cash_flows 0.0 0.0;; (************** 4.4 **************) (* Calculating the Macaulay duration of a bond *) let bonds_duration_macaulay_discrete (cash_flows : cash_flow list) (bond_price : float) : float = let y = (bonds_yield_to_maturity_discrete cash_flows bond_price) in bonds_duration_discrete cash_flows y;; (************** 4.5 **************) let bonds_duration_modified_discrete (cash_flows : cash_flow list) (bond_price : float) : float = let y = (bonds_yield_to_maturity_discrete cash_flows bond_price) in let d = bonds_duration_discrete cash_flows y in d /. (1.0 +. y);; (************** 4.6 **************) let bonds_convexity_discrete (cash_flows : cash_flow list) (r : float) : float = let rec solve_cx cash_flows cx = match cash_flows with [] -> cx | h::t -> let ncx = cx +. h.value *. h.time *. (h.time +. 1.0) /. ((1.0 +. r)**h.time) in solve_cx t ncx in let b = bonds_price_discrete cash_flows r in let cx = solve_cx cash_flows 0.0 in (cx /. (1.0 +. r)**2.0) /. b;; (* Example use: let cash_flows = {value=10.0; time=1.0}::{value=10.0; time=2.0}::{value=10.0; time=3.0}::[];; let r = 0.09;; let bond_price = (bonds_price_discrete cash_flows r);; Printf.printf "Bond price, 9 percent discretely compounded interest = %f\n" bond_price;; Printf.printf "Bond duration = %f\n" (bonds_duration_discrete cash_flows r);; Printf.printf "Bond macaulay = %f\n" (bonds_duration_macaulay_discrete cash_flows bond_price);; Printf.printf "Bond duration modified = %f\n" (bonds_duration_modified_discrete cash_flows bond_price);; Printf.printf "Bond convexity = %f\n" (bonds_convexity_discrete cash_flows r);; Printf.printf "New bond price = %f\n" (bonds_price_discrete cash_flows 0.1);; *) end