People think I’m joking when I say something should only take 20 lines of code. More often than not it is possible if you understand how to strip away unnecessary complexity. This example shows how to calculate the theoretical swap rate for an interest rate swap given its terms. What’s nice about this example is that it demonstrates the value of attributes and pattern matching to facilitate reasoning about the program.

The first step is to create a type constructor for an interest rate swap. This type constructor has two clauses. The first supports reading in the terms from a file, while the second actually creates the type. This pattern is very common in lambda.r as it enforces separation of concerns between model logic and data management. All to often the conflation of these tasks prevents code from being re-usable, not to mention a bear to understand.

IRSwap(notional, terms) %::% a : character : data.frame
IRSwap(notional, terms) %as% IRSwap(notional, read.csv(terms))

IRSwap(notional, terms) %::% a : data.frame : data.frame
IRSwap(notional, terms) %when% {
  terms %hasa% period
  terms %hasa% days
  terms %hasa% fwd.1y
} %as% {
  terms@notional <- notional

With the type constructor out of the way, here are the core pieces of the model. To calculate the swap rate you need to know the present value of the floating and fixed legs. Again, this is a great example of a multipart function definition that separates the two implementations using simple pattern matching.

pv(swap, 'floating') %as%
  forward.rate <- swap$fwd.1y * swap$days / 360
  float.rate <- swap@notional * forward.rate
  fn <- function(x) prod(1 + forward.rate[1:x])
  discount.factor <- 1 / sapply(swap$period, fn)
  float.rate * discount.factor

pv(swap, 'fixed') %as%
  forward.rate <- swap$fwd.1y * swap$days / 360
  fn <- function(x) prod(1 + forward.rate[1:x])
  discount.factor <- 1 / sapply(swap$period, fn)
  swap@notional * swap$days / 360 * discount.factor

rate(swap) %::% IRSwap : numeric
rate(swap) %as% {
  sum(pv(swap, 'floating')) / sum(pv(swap, 'fixed'))

Now to use the code:

terms <- data.frame(period=1:6, days=180,
  fwd.1y=c(0.04, 0.0425, 0.045, 0.0475, 0.05, 0.0525))
swap <- IRSwap(100000000, terms)
[1] 0.04607914

In a follow-up post I will show how to create a simple trading system using lambda.r that is similarly small.