Discount/Zero Curve Construction in F# – Part 3 (Bootstrapping)


In Part 1, the first lines of code we saw formed the final step in the construction of the discount curve:

let discs = [ (curveDate, 1.0) ]
            |> bootstrap spotPoints 
            |> bootstrapCash spotDate cashPoints
            |> bootstrapFutures futuresStartDate futuresPoints
            |> bootstrapSwaps spotDate USD swapPoints
            |> Seq.sortBy (fun (qDate, _) -> qDate)

The curve begins with today’s discount factor of 1.0 in a one-element list, which is passed to the bootstrap function along with the spot quotes.

let rec bootstrap quotes discountCurve =
    match quotes with
      quote :: tail -> 
        let newDf = computeDf (List.hd discountCurve) quote
        bootstrap tail (newDf :: discountCurve)
    | [] -> discountCurve

This tail recursion works through the given quotes, computing the discount factor for each based on the previous discount factor in the curve (the details of this we’ll cover in Part 4), and places that new discount factor at the head of a new curve, that is used to continue the recursion. When there are no more quotes, the discount curve is returned, ending the recursion. After bootstrapping the spot quotes, the curve looks like this:



Cash quotes are bootstrapped with respect to the spot discount factor, rather than their previous cash point:

let rec bootstrapCash spotDate quotes discountCurve =
    match quotes with
      quote :: tail -> 
        let spotDf = (spotDate, findDf logarithmic spotDate discountCurve)
        let newDf = computeDf spotDf quote
        bootstrapCash spotDate tail (newDf :: discountCurve)
    | [] -> discountCurve
Here we find the discount factor at the spot date (more about findDf in Part4), tail recurse to compute each cash quote’s corresponding discount factor with respect to the spot discount factor, and prepend that new factor to the discount curve in a similar fashion to the standard bootstrap function. After the cash points are all computed, the curve will be as follows:


Once again, the futures offer a twist, albeit a minor one this time:

let bootstrapFutures futuresStartDate quotes discountCurve =
    match futuresStartDate with
    | Some d ->
        bootstrap (Seq.to_list quotes) 
                  ((d, findDf logarithmic d discountCurve) :: discountCurve)
    | None -> discountCurve
The futures are bootstrapped starting from the beginning of the futures schedule – this is the reason why we calculated futuresStartDate in Part2. For the discount factor at this point, we interpolate using the curve we’ve built thus far. Once that first futures discount point is established, we can place that at the head of a new curve that is subsequently used to bootstrap the futures quotes using the standard approach we employed previously for spot quotes (i.e. each factor is with respect to the last). After the futures, we have this curve:


Note that these aren’t in date order at this point, since we bootstrapped from the futures start date of Jun 17th, but that’s OK for our purposes – it won’t affect the accuracy of the final curve once we sort it chronologically.

Now to the swaps -- this time it’s the swaps that complicate the procedure. With the assumption that the swap quotes are fair market rates (present value zero), we use a root solver (in this case Newton’s method) to find the discount factor of each swap, pricing them using the curve we’ve built thus far:

let rec bootstrapSwaps spotDate calendar swapQuotes discountCurve =
    match swapQuotes with
      (qDate, qQuote) :: tail ->
        // build the schedule for this swap                
        let swapDates = schedule semiAnnual { startDate = spotDate; endDate = qDate }
        let rolledSwapDates = Seq.map (fun (d:Date) -> roll RollRule.Following calendar d) 
        let swapPeriods = Seq.to_list (Seq.map (fun (s, e) -> { startDate = s; endDate = e }) 
                                      (Seq.pairwise rolledSwapDates))
        // solve
        let accuracy = 1e-12
        let spotFactor = findDf logarithmic spotDate discountCurve
        let f = computeSwapDf dayCount spotDate (qDate, qQuote) discountCurve swapPeriods 
        let newDf = solveNewton f accuracy spotFactor                   

        bootstrapSwaps spotDate calendar tail ((qDate, newDf) :: discountCurve)
    | [] -> discountCurve

For each swap we build a semi-annual schedule from spot to swap maturity using the schedule function, which recursively builds a sequence of dates six months apart:

let rec schedule frequency period =
    seq {
        yield period.startDate
        let next = frequency period.startDate
        if (next <= period.endDate) then
            yield! schedule frequency { startDate = next; endDate = period.endDate }
Where frequency (in this case semiAnnual) is a function in its own right, that does – guess what?
let semiAnnual (from:Date) = from.AddMonths(6)
Each of the schedule dates in the sequence is then rolled according to the Following rolling rule, and then taken pairwise to generate a schedule of unbroken start and end dates for each period. This schedule is used to calculate both the discount factor and the first derivative of each swap quote, which in turn feed Newton’s method along with our desired accuracy of twelve decimals. Each result is placed at the head of our growing discount curve which will be used to compute the next swap discount factor. In the end our complete curve looks like this:




In Part 4, we’ll dive into to (relatively simple) math functions that underpin the bootstrapping calculations.


No State Machines in Windows Workflow 4.0?

After learning that Workflow Foundation 4.0 is likely to be missing StateMachineActivity, I think I’m going to hold off on any more research into lifecycle-of-OTC-derivative-as-Workflow, until 4.0 is released. Which is a shame, because in 3.5 I actually liked what I saw so far and was formulating some interesting posts on this.


Convert Word Documents to PDF with an MSBuild Task

I needed to convert a lot of Microsoft Word documents to PDF format, as one step in a continuous integration build of a Visual Studio project. To save a lot of build time, an incremental build of this project needs to only spend time converting the Word documents that actually changed since the last build. Rather than write a Powershell script, or other such out-of-band mechanism, a simple custom MSBuild task does the trick nicely.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Office.Interop.Word;

namespace MSBuild.Tasks {
  public class Doc2Pdf : Microsoft.Build.Utilities.Task {

    private static object missing = Type.Missing;

    public ITaskItem[] Inputs { get; set; }

    public ITaskItem[] Outputs { get; set; }

    public ITaskItem[] ConvertedFiles { get; set; }

    public override bool Execute() {
      _Application word = (_Application) new Application();
      _Document doc = null;

      try {
        List<ITaskItem> convertedFiles = new List<ITaskItem>();

        for (int i = 0; i < Inputs.Length; i++ ) {
          ITaskItem docFile = Inputs[i];
          ITaskItem pdfFile = Outputs[i];

                           "DOC2PDF: Converting {0} -> {1}", 
                           docFile.ItemSpec, pdfFile.ItemSpec));

          FileInfo docFileInfo = new FileInfo(docFile.ItemSpec);
          if (!docFileInfo.Exists) {
            throw new FileNotFoundException("No such file", docFile.ItemSpec);

          object docFileName = docFileInfo.FullName;

          FileInfo pdfFileInfo = new FileInfo(pdfFile.ItemSpec);

          object pdfFileName = pdfFileInfo.FullName;

          word.Visible = false;
          doc = word.Documents.Open(ref docFileName, 
                    ref missing, ref missing, ref missing, ref missing, ref missing, 
                    ref missing, ref missing, ref missing, ref missing, ref missing, 
                    ref missing, ref missing, ref missing, ref missing, ref missing);

          object fileFormat = 17;
          doc.SaveAs(ref pdfFileName, ref fileFormat, 
                     ref missing, ref missing, ref missing, ref missing, ref missing, 
                     ref missing, ref missing, ref missing, ref missing, ref missing, 
                     ref missing, ref missing, ref missing, ref missing);


        return true;
      catch (Exception ex) {
        return false;
      finally {
        object saveChanges = false;
        if (doc != null)
          doc.Close(ref saveChanges, ref missing, ref missing);
        word.Quit(ref saveChanges, ref missing, ref missing);

The Office interop APIs make this code messier than it needs to be, with all the optional parameters that we don’t care about in this case. Fortunately this story gets better in C#4.0 with the new optional parameters feature.

Assuming you build the above into an assembly called Doc2PdfTask.dll, and put the assembly in the MSBuild extensions directory, you can then set up your project file to do something like this:

<Project DefaultTargets="Build"
  <UsingTask AssemblyFile="$(MSBuildExtensionsPath)\Doc2PdfTask.dll"
             TaskName="MSBuild.Tasks.Doc2Pdf" />
  <Target Name="Build"
          DependsOnTargets="Convert" />
  <Target Name="Convert"
    <Doc2Pdf Inputs="%(WordDocuments.Identity)"
      <Output TaskParameter="ConvertedFiles"
              ItemName="PdfDocuments" />
    <WordDocuments Include="**\*.doc" />
    <WordDocuments Include="**\*.docx" />

All Word documents under the project directory (recursively), will be converted if necessary. Obviously, you’ll need Microsoft Word installed for this to work (I have Office 2007).


Project Vector? You mean like “attack” vector?

It’s been a few years since I’ve done any appreciable amount of work in Java, and I’m sure JavaFX is as secure a technology as any other mass-code-deployment-scheme out there, but I had something of a visceral reaction to a post I ran across on Jonathan Schwartz’s blog regarding the upcoming Java Store (codename “Project Vector”):

“Remember, when apps are distributed through the Java Store, they're distributed directly to the desktop - JavaFX enables developers, businesses and content owners to bypass potentially hostile browsers.”

Now, I happen to agree with Schwartz when it comes to being able to deliver a much better user experience with a smartly-deployed desktop application over a typical AJAX web application, and real “desktop” applications are surely a lot easier to maintain, debug, test and assure the quality thereof (in my humble opinion), but something about this statement makes me nervous. Rich Internet Applications, whatever your development platform of choice, still rely on a platform, and the browser is still just a platform in this respect.

As far as I’m concerned, the Browser/JVM/CLR had better be hostile to any code that could potentially compromise the security of my customer’s client machines, otherwise I’m not going to be able to sell them software, because they won’t trust it.

And while we’re on the subject, I hope that the Java Store won’t bug me constantly to download the latest New Shiny Thing – my system tray is already lit up like a Christmas tree, thanks very much.


Discount/Zero Curve Construction in F# – Part 2 (Rolling Dates)

In part 1, we used the rollBy function to find the spot date from the curve date:

let spotDate = rollBy 2 RollRule.Following USD curveDate

Unsurprisingly, this rolls by two business days; according to the following roll rule; accounting for business holidays in the United States; the curve date. I guess there are several ways to implement this function – recursively is one way:

let rec rollBy n rule calendar (date:Date) =
    match n with
    | 0 -> date
    | x -> 
        match rule with
        | RollRule.Actual -> date.AddDays(float x)

        | RollRule.Following -> dayAfter date
                                |> roll rule calendar
                                |> rollBy (x - 1) rule calendar

        | _ -> failwith "Invalid RollRule"

Here there are two examples of pattern matching: firstly to determine when to end the recursion (when there are no more days by which we need to roll), and then to roll appropriately depending on the rule (just two rules are shown here for brevity). rollBy in turn makes use of the more basic functions dayAfter and roll:
let dayAfter (date:Date) = date.AddDays(1.0)
let rec roll rule calendar date =
    if isBusinessDay date calendar then
        match rule with
        | RollRule.Actual -> date
        | RollRule.Following -> dayAfter date |> roll rule calendar
        | _ -> failwith "Invalid RollRule"

Where dayAfter is not much more than an alias for readability, and roll is a function that rolls any day that happens to be a holiday or weekend. The real decision about the “goodness” of a business day is handled by the isBusinessDay function, a simple lookup into the calendar:
let isBusinessDay (date:Date) calendar = 
    not (calendar.weekendDays.Contains date.DayOfWeek || calendar.holidays.Contains date)

And to save space I’ll use a US holiday calendar for only 2009:
let USD = { weekendDays = Set [ System.DayOfWeek.Saturday; System.DayOfWeek.Sunday ]; 
            holidays = Set [ date "2009-01-01"; 
                             date "2009-01-19"; 
                             date "2009-02-16"; 
                             date "2009-05-25"; 
                             date "2009-07-03"; 
                             date "2009-09-07"; 
                             date "2009-10-12"; 
                             date "2009-11-11"; 
                             date "2009-11-26"; 
                             date "2009-12-25" ] }

Discount Dates

Now we have our quotes, and some routines to handle rolling to good business days, we can begin to establish the benchmark dates that will form the discount curve. First, we can pull out the quotes up to spot, and roll each quote by an appropriate number of days:
let spotPoints = quotes
                 |> List.choose (fun (t, q) -> 
                        match t with
                        | Overnight _ -> Some (rollBy 1 RollRule.Following USD curveDate, q)
                        | TomorrowNext _ -> Some (rollBy 2 RollRule.Following USD curveDate, q)
                        | _ -> None)
                 |> List.sortBy (fun (d, _) -> d)
This is our first look at list functions. Our quotes form a list, and List.choose is a function that allows us to iterate through the list, making a decision on each item as to whether or not we want to include it (the Some option), or exclude it (the None option) – exactly what we need to pull out the overnight and tomnext quotes, and roll the curve date appropriately in order to establish each discount point’s date:

Cash quotes get similar treatment, except that now, instead of rolling from the curve date, we’re offsetting from the spot date (and rolling if necessary):
let cashPoints = quotes
                 |> List.choose (fun (t, q) -> 
                        match t with
                        | Cash c -> Some (offset c spotDate |> roll RollRule.Following USD, q)
                        | _ -> None)
                 |> List.sortBy (fun (d, _) -> d)

Where offset simply adds the relevant number of days, months and/or years to a date:
let offset tenor (date:Date) = 
    date.AddDays(float tenor.days)

Swaps – same story:
let swapPoints = quotes
                 |> List.choose (fun (t, q) -> 
                        match t with
                        | Swap s -> Some (offset s spotDate |> roll RollRule.Following USD, q)
                        | _ -> None)
                 |> List.sortBy (fun (d, _) -> d)

Futures – not nearly so simple. The June 2009 Eurodollar contract covers the three month period starting on the 3rd Wednesday in June, and ending on the 3rd Wednesday in September, so the quotes actually correspond to discount dates represented by the next futures contract in the schedule. This means we will interpolate the discount point for June (the start of the futures schedule), and add an extra point after the last quote (the end of the futures schedule):
let (sc, _) = List.hd futuresQuotes
let (ec, _) = futuresQuotes.[futuresQuotes.Length - 1]   
let futuresStartDate = findNthWeekDay 3 System.DayOfWeek.Wednesday sc 
                       |> roll RollRule.ModifiedFollowing USD
let futuresEndDate = (new Date(ec.Year, ec.Month, 1)).AddMonths(3)

// "invent" an additional contract to capture the end of the futures schedule
let endContract = (futuresEndDate, 0.0)
First we find the first and last futures quotes, and compute dates of the start and end of the futures schedule. Then we create the extra point covering the final contract. I’ve omitted findNthWeekDay, but it’s not complicated and fairly self-explanatory. Now for the real work:
let futuresPoints = Seq.append futuresQuotes [endContract]
                    |> Seq.pairwise
                    |> Seq.map (fun ((_, q1), (c2, _)) -> 
                        (findNthWeekDay 3 System.DayOfWeek.Wednesday c2 
                         |> roll RollRule.ModifiedFollowing USD, (100.0 - q1) / 100.0))
                    |> Seq.to_list
This pipeline operates on a sequence, which is the F# equivalent of IEnumerable<T>. Here we first append our extra contract, then use the Seq.pairwise function to iterate through the sequence two-by-two. This pairing allows us to take the value of the quote from the first of each pair, and combine it with the contract of the quote from the second of the pair. The effect is to “shift” the quote values down the schedule to their subsequent contract. At the same time, we find the correct contract date (and roll it if necessary), and convert the quote to a rate. At the end of this dance we have the following futures points ready for bootstrapping (in part 3).