packages feed

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

{-# LANGUAGE TemplateHaskell #-}
module QuantLib.Example.Repo
  (
    Result(..)
  , run
  ) where

import Control.Monad(void, when)
import System.Mem(performGC)
import System.IO (hPutStrLn, stderr)
import Control.Concurrent (threadDelay)

import QuantLib.Instrument
import QuantLib.Instrument.Bond
import QuantLib.Instrument.Forward
import qualified QuantLib.InterestRate as IR
import QuantLib.PricingEngine(discountingBondEngine)
import QuantLib.Quote(setValue, simpleQuote, SimpleQuote)
import QuantLib.Settings(setEvaluationDate)
import QuantLib.TermStructure.Yield
import QuantLib.Time.Calendar
import QuantLib.Time.Date
import QuantLib.Time.Schedule
import QuantLib.Syntax

-- run tests with stack test --ta '--match /Repo'
data Result = Result
  { cleanPriceR :: Double
  , dirtyPriceR :: Double
  , accruedAmountSettlement :: Double
  , accruedAmountDelivery :: Double
  , spotIncomeR :: Double
  , fwdIncomeR :: Double
  , strike :: Double
  , npvR :: Double
  , cleanForwardPriceR :: Double
  , forwardPriceR :: Double
  , impliedYieldR :: Double
  , zeroRateR :: Double
  } deriving Show

run :: Bool -> IO Result
run gc = do
  repoDayCountConvention <- dayCounter (Actual360 False)
  bondCalendar <- calendar Null
  bondDayCountConvention <- dayCounter Thirty360BondBasis
  setEvaluationDate $ Just repoSettlementDate
  bondQuote <- simpleQuote 0.01
  bondCurve <- flatForward repoSettlementDate bondQuote bondDayCountConvention IR.Compounded bondCouponFrequency
  bondSchedule <- schedule (Just bondDatedDate) bondMaturityDate
    (6, Months) bondCalendar bondBusinessDayConvention bondBusinessDayConvention Backward False
    Nothing Nothing
  (fwd, clP, accr1, accr2, clF, fP, dp) <- doBond bondCalendar bondSchedule bondQuote repoDayCountConvention bondDayCountConvention bondCurve
  when gc (performGC >> threadDelay 1000000 >> performGC >> threadDelay 1000000 >> hPutStrLn stderr "GC complete")
  repoCurve <- simpleQuote repoRate >>=
        $(free2nd 'flatForward) repoSettlementDate repoDayCountConvention repoCompounding repoCompoundFreq
  spotInc <- spotIncome fwd repoCurve
  disc <- discount' repoCurve repoDeliveryDate False
  np <- npv fwd

  impR <- impliedYield fwd dp dummyStrike repoSettlementDate
    repoCompounding repoDayCountConvention

  z <- zeroRate' repoCurve repoDeliveryDate repoDayCountConvention
    repoCompounding repoCompoundFreq False

  return Result {
      cleanPriceR = clP
    , dirtyPriceR = dp
    , accruedAmountSettlement = accr1
    , accruedAmountDelivery = accr2
    , spotIncomeR = spotInc
    , fwdIncomeR = spotInc / disc
    , strike = dummyStrike
    , npvR = np
    , cleanForwardPriceR = clF
    , forwardPriceR = fP
    , impliedYieldR = IR.rate impR
    , zeroRateR = IR.rate z
    }
  where repoSettlementDate = 14 `february` 2000
        repoDeliveryDate = 15 `august` 2000
        repoRate = 0.05
        repoSettlementDays = 0
        repoCompounding = IR.Simple
        repoCompoundFreq = Annual
        bondIssueDate = 15 `september` 1995
        bondDatedDate = 15 `september` 1995
        bondMaturityDate = 15 `september` 2005
        bondCoupon = 0.08
        bondCouponFrequency = Semiannual
        bondSettlementDays = 0
        bondBusinessDayConvention = Unadjusted
        bondCleanPrice = 89.97693786
        bondRedemption = 100.0
        faceAmount = 100.0
        dummyStrike = 91.5745
        fwdType = Long

        -- make sure bond forward reference is scoped (for GC checks)
        doBond :: Calendar -> Schedule -> SimpleQuote -> DayCounter -> DayCounter -> YieldTermStructure -> IO (Forward, Double, Double, Double, Double, Double, Double)
        doBond bondCalendar bondSchedule bondQuote repoDayCountConvention bondDayCountConvention bondCurve = do
          b <- fixedRateBond bondSettlementDays faceAmount bondSchedule [bondCoupon]
            bondDayCountConvention bondBusinessDayConvention bondRedemption (Just bondIssueDate) bondCalendar
            (0, Days) bondCalendar Unadjusted False bondDayCountConvention
          -- liftM2 setPricingEngine (asInstrument b) (discountingBondEngine bondCurve Nothing)]
          discountingBondEngine bondCurve Nothing >>= setPricingEngine b
          void $ yieldFromPrice b (bondCleanPrice, Clean) bondDayCountConvention IR.Compounded bondCouponFrequency repoSettlementDate 1e-8 100 >>= setValue bondQuote
          repoCurve <- simpleQuote repoRate >>=
            $(free2nd 'flatForward) repoSettlementDate repoDayCountConvention repoCompounding repoCompoundFreq
          bondFwd <- bondForward repoSettlementDate repoDeliveryDate fwdType dummyStrike
            repoSettlementDays
            repoDayCountConvention bondCalendar bondBusinessDayConvention b
            (Just repoCurve) (Just repoCurve)

          clP <- cleanPrice b bondCurve repoSettlementDate
          accr1 <- accruedAmount b repoSettlementDate
          let dp = clP + accr1
          accr2 <- accruedAmount b repoDeliveryDate
          fwd <- asForward bondFwd
          clF <- cleanForwardPrice bondFwd
          fP <- forwardPrice bondFwd

          return (fwd, clP, accr1, accr2, clF, fP, dp)
-- vim: set ft=haskell ff=unix ts=8 sts=2 sw=2 et: