1. Using recursive functions to value an asset

List processing is an integral part of functional programming and it has widespread application in the field of finance. As an example, when computing the value of a government bond, we would first list its payments, filter out those which have elapsed, and then sum the discounted value of the remaining ones. The discounting accounts for the erosion in value due to interest rate and inflation effects, as well as the risk of the issuer defaulting on its payments.

In order to perform such a computation using conventional "imperative" algorithms, we might use a "for loop" to traverse through the list of payments. In an alternative recursive version of the algorithm, the list may be treated as two components: the head which holds the next payment, and the tail which holds the remaining ones. The algorithm proceeds by recursively taking the head and adding it's eroded value to the running total. This total is passed to the next recursion, along with the remaining tail. Once the tail is empty, the valuation is complete and the running total represents the discounted value of all the payments i.e. the gross price of the bond.

 case class Payment(date: LocalDate, amount: Double)
  def years(from:LocalDate, to:LocalDate) : Double = {
    from.until(to, ChronoUnit.DAYS)/365.0
  }

  def presentValue( runninTotal:Double,
                    payments:List[Payment],
                    rate:Double,
                    today:LocalDate):Double={
    payments match {
      case Nil => runningTotal
      case Payment(date, amount) :: tail => {
        val df = Math.exp(-rate * years(today, date))
        presentValue(runningTotal+amount*df, tail, rate, today)
      }
    }
  }

  def main(args: Array[String]) = {
    val payments = List(
      Payment(LocalDate.of(2025, 6, 7), 5000),
      Payment(LocalDate.of(2025, 12, 7), 105000)
    )
    println(presentValue(0, payments, 0.055, LocalDate.of(2024, 6, 7)))
  } 

In the algorithm presented above, we have made a number of simplifying assumptions. We have ignored the risk of default and have used a single rate to represent the 'blended' effect of interest rates and inflation. Furthermore, the rate (r) is assumed to be constant over time and is quoted on a continuously compounded basis; meaning that one pound today is worth exp(rT) in T years from now.

Despite the simplification, the structure of the solution resembles that of a typical real world implementation. The solution has several qualities: all the variables are immutable and the function is referentially transparent i.e. the result returned is determined by inputs alone and is not influenced by additional state variables. In a traditional implementation, we may choose to hold the running total of the valuation in a mutable variable. The net effect of our particular set of choices is a solution which has clarity and can be reasoned about for correctness more easily.

Last updated