packages feed

hasquant-0.5.0.2: test/example/QuantLib/Example/CallableBond.hs

{-# LANGUAGE TemplateHaskell #-}
module QuantLib.Example.CallableBond
  (
    Result(..)
  , run
  ) where
import Control.Monad(mapAndUnzipM)
import Data.Time.Calendar

import QuantLib.Instrument
import QuantLib.InterestRate
import QuantLib.Instrument.Bond
import QuantLib.Model
import QuantLib.Quote
import QuantLib.PricingEngine
import QuantLib.Settings
import QuantLib.TermStructure.Yield
import QuantLib.Time.Calendar
import QuantLib.Time.Date
import QuantLib.Time.Schedule
import QuantLib.Syntax

data Result = Result
  { pricesR :: [Double]
  , yieldsR :: [Double]
  }

run :: IO Result
run = do
  setEvaluationDate $ Just tod
  bbdc <- dayCounter ActualActualBond
  q <- simpleQuote 0.055
  flatRate <- flatForward tod q bbdc Compounded Semiannual

  callDates <- (firstCallDate :) <$> buildSchedule 23 firstCallDate
  let callSchedule = map (Callability (100.0, Clean) CallabilityCall) callDates

  cal <- calendar UnitedStatesGovernmentBond
  sch <- schedule (Just $ 16 `september` 2004) (15 `september` 2012) (3, Months) cal Unadjusted Unadjusted Backward False Nothing Nothing

  b <- callableFixedRateBond 3 100.0 sch [0.0465] bbdc Unadjusted 100.0 (Just $ 16 `september` 2004) callSchedule (0, Days) cal Unadjusted False

  (ps, ys) <- mapAndUnzipM (priceBond flatRate bbdc b) [epsilon, 0.01, 0.03, 0.06, 0.12]

  return Result {
    pricesR = ps
  , yieldsR = ys
  }
  where tod = 16 `october` 2007
        firstCallDate = 15 `september` 2006

        -- the k call dates following `prev`, each 3 months after the one before.
        -- Replaces a foldM over a prepending accumulator, which needed a
        -- `buildSchedule [] _ = error "Impossible happened"` clause to be total and
        -- a final `reverse` to get back into ascending order.
        buildSchedule :: Int -> Day -> IO [Day]
        buildSchedule 0 _ = pure []
        buildSchedule k prev = do
          n <- calendar Null >>= $(free1st 'advance) prev (3, Months) Following False
          (n :) <$> buildSchedule (k - 1) n

        priceBond ts dc b sigma = do
          hw <- hullWhite ts 0.03 sigma >>= asOneFactorAffineModel >>= asShortRateModel
          engine <- treeCallableFixedRateBondEngine hw 40 Nothing
          asInstrument b >>= (`QuantLib.Instrument.setPricingEngine` engine)
          cp <- currentCleanPrice b
          y <- yield b dc Compounded Quarterly 1.0e-8 1000 (0.05, Clean)
          return (cp, 100 * y)

-- vim: set ft=haskell ff=unix ts=8 sts=2 sw=2 et: