packages feed

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

{-# LANGUAGE OverloadedLists #-}
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.Context
import QuantLib.TermStructure.Yield
import QuantLib.Time.Calendar
import QuantLib.Time.Date
import QuantLib.Time.Schedule

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

run :: IO Result
run = do
  setEvaluationDate $ Just evalDate
  bbdc <- dayCounter ActualActualBond
  q <- simpleQuote 0.055
  flatRate <- flatForward (ReferenceDate evalDate) 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 evalDate = 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 >>= \cal -> advance cal 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 (TimeSteps 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: