Discount/Zero Curve Construction in F# – Part 1 (The End)
F# seems to read better from right to left and from bottom to top, so we’ll start with what might be the final step in building an interest rate discount curve, and work back from there:
let curve = [ (curveDate, 1.0) ] |> bootstrap spotPoints |> bootstrapCash spotDate cashPoints |> bootstrapFutures futuresStartDate futuresPoints |> bootstrapSwaps spotDate USD swapPoints |> Seq.sortBy (fun (d, _) -> d)
What goes in?
Let’s look at what feeds the process. The curve date would typically be today’s date:
let curveDate = Date.Today
let spotDate = rollBy 2 RollRule.Following USD curveDate
A collection of quotes would be something like the list below. For illustration purposes we’ll use cash deposits out to three months, a small range of futures and swaps for the rest of the curve out to thirty years:
let quotes = [ (Overnight, 0.045); (TomorrowNext, 0.045); (Cash (tenor "1W"), 0.0462); (Cash (tenor "2W"), 0.0464); (Cash (tenor "3W"), 0.0465); (Cash (tenor "1M"), 0.0467); (Cash (tenor "3M"), 0.0493); (Futures (contract "Jun2009"), 95.150); (Futures (contract "Sep2009"), 95.595); (Futures (contract "Dec2009"), 95.795); (Futures (contract "Mar2010"), 95.900); (Futures (contract "Jun2010"), 95.910); (Swap (tenor "2Y"), 0.04404); (Swap (tenor "3Y"), 0.04474); (Swap (tenor "4Y"), 0.04580); (Swap (tenor "5Y"), 0.04686); (Swap (tenor "6Y"), 0.04772); (Swap (tenor "7Y"), 0.04857); (Swap (tenor "8Y"), 0.04924); (Swap (tenor "9Y"), 0.04983); (Swap (tenor "10Y"), 0.0504); (Swap (tenor "12Y"), 0.05119); (Swap (tenor "15Y"), 0.05201); (Swap (tenor "20Y"), 0.05276); (Swap (tenor "25Y"), 0.05294); (Swap (tenor "30Y"), 0.05306) ]
All of these quotes are tuples, with a second value of type float, representing the market quote itself. The type of the first value in the tuple we make a discriminated union, to distinguish the different types of instrument:
type QuoteType = | Overnight // the overnight rate (one day period) | TomorrowNext // the one day period starting "tomorrow" | Cash of Tenor // cash deposit period in days, weeks, months | Futures of FuturesContract // year and month of futures contract expiry | Swap of Tenor // swap period in years
type Date = System.DateTime type FuturesContract = Date type Tenor = { years:int; months:int; days:int }
let date d = System.DateTime.Parse(d) let contract d = date d let tenor t = let regex s = new Regex(s) let pattern = regex ("(?<weeks>[0-9]+)W" + "|(?<years>[0-9]+)Y(?<months>[0-9]+)M(?<days>[0-9]+)D" + "|(?<years>[0-9]+)Y(?<months>[0-9]+)M" + "|(?<months>[0-9]+)M(?<days>[0-9]+)D" + "|(?<years>[0-9]+)Y" + "|(?<months>[0-9]+)M" + "|(?<days>[0-9]+)D") let m = pattern.Match(t) if m.Success then { new Tenor with years = (if m.Groups.["years"].Success then int m.Groups.["years"].Value else 0) and months = (if m.Groups.["months"].Success then int m.Groups.["months"].Value else 0) and days = (if m.Groups.["days"].Success then int m.Groups.["days"].Value else if m.Groups.["weeks"].Success then int m.Groups.["weeks"].Value * 7 else 0) } else failwith "Invalid tenor format. Valid formats include 1Y 3M 7D 2W 1Y6M, etc"
Reader Comments