packages feed

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

module QuantLib.Example.IsdaCds
  (
    Result(..)
  , run
  ) where
import Data.Time.Calendar

import QuantLib.Currency
import QuantLib.Instrument
import QuantLib.Instrument.Credit
import QuantLib.Index.InterestRate hiding(dayCounter, currency)
import QuantLib.Math
import QuantLib.Quote
import QuantLib.PricingEngine
import QuantLib.Settings
import QuantLib.TermStructure.Credit
import QuantLib.TermStructure.Yield
import QuantLib.Time.Date
import QuantLib.Time.Calendar
import QuantLib.Time.Schedule

newtype Result = Result { conventionalUpfrontR :: Double }

-- |Single case (first: termDate\/spread\/recovery combination) of upstream's
-- @testIsdaEngine@ (@test-suite\/creditdefaultswap.cpp@), which pins 'isdaCdsEngine'
-- against a cached Markit-published upfront value rather than a self-consistency check.
-- All builder defaults below are transcribed from @ql\/instruments\/makecds.cpp@'s
-- @MakeCreditDefaultSwap@ (both trades there go through the upfront+running-spread
-- constructor, hence 'creditDefaultSwap'' rather than 'creditDefaultSwap').
run :: IO Result
run = do
  weekendsOnly <- calendar WeekendsOnly
  let tradeDate = 21 `may` 2009
  setEvaluationDate $ Just tradeDate

  act360 <- dayCounter (Actual360 False)
  act360IncludeLast <- dayCounter (Actual360 True)
  act365Fixed <- dayCounter Actual365FixedStandard
  thirty360bb <- dayCounter Thirty360BondBasis
  usd <- currency USD

  let depTenors = [1, 2, 3, 6, 9, 12 :: Int]
      depQuotes = [0.003081, 0.005525, 0.007163, 0.012413, 0.014, 0.015488]
  depositHelpers <- mapM
    (\(t, q) -> simpleQuote q >>= \sq -> depositRateHelper sq (t, Months) 2 weekendsOnly ModifiedFollowing False act360)
    (zip depTenors depQuotes)

  isdaIbor <- iborIndex (Ibor "IsdaIbor" (3, Months) 2 usd weekendsOnly ModifiedFollowing False act360) Nothing

  let swapTenors = [2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25, 30 :: Int]
      swapQuotes = [ 0.011907, 0.01699, 0.021198, 0.02444, 0.026937, 0.028967, 0.030504
                   , 0.031719, 0.03279, 0.034535, 0.036217, 0.036981, 0.037246, 0.037605 ]
  swapHelpers <- mapM
    (\(t, q) -> simpleQuote q >>= \sq -> swapRateHelper' sq (t, Years) weekendsOnly Semiannual ModifiedFollowing
        thirty360bb isdaIbor Nothing (0, Days) Nothing Nothing LastRelevantDate Nothing False Nothing Nothing Nothing)
    (zip swapTenors swapQuotes)

  swapHelpers' <- mapM asRateHelper swapHelpers
  discountCurve <- piecewiseYieldCurve' 0 weekendsOnly (depositHelpers ++ swapHelpers')
    act365Fixed [] Discount LogLinear False

  let termDate = fromGregorian 2010 6 20
      spread = 0.001
      recovery = 0.2
      notional = 10000000.0
      protectionStart = tradeDate
  upfrontDate <- advance weekendsOnly tradeDate (3, Days) Following False
  sched <- schedule (Just protectionStart) termDate (3, Months) weekendsOnly Following Unadjusted CDS False Nothing Nothing

  quotedTrade <- creditDefaultSwap' Buyer notional 0.0 spread sched Following act360 True True
    (Just protectionStart) (Just upfrontDate) FaceValue act360IncludeLast True (Just tradeDate) 3

  h <- impliedHazardRate quotedTrade 0.0 discountCurve act365Fixed recovery 1e-10 ISDA
  hq <- simpleQuote h
  probabilityCurve <- flatHazardRate' 0 weekendsOnly hq act365Fixed

  engine <- isdaCdsEngine probabilityCurve recovery discountCurve Nothing NumericalFixTaylor HalfDayBias Piecewise

  conventionalTrade <- creditDefaultSwap' Buyer notional 0.0 0.01 sched Following act360 True True
    (Just protectionStart) (Just upfrontDate) FaceValue act360IncludeLast True (Just tradeDate) 3
  asInstrument conventionalTrade >>= (`setPricingEngine` engine)
  upfront <- fairUpfront conventionalTrade

  return Result { conventionalUpfrontR = notional * upfront }

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