hasquant-0.5.0.2: test/example/QuantLib/Example/InflationCurve.hs
module QuantLib.Example.InflationCurve
(
Result(..)
, run
) where
import Control.Monad(forM_)
import qualified QuantLib.InterestRate as IR
import QuantLib.Index(addFixing)
import QuantLib.Index.Inflation
import QuantLib.Math(Interpolation(..))
import QuantLib.Quote(simpleQuote)
import QuantLib.Settings(setEvaluationDate)
import QuantLib.Instrument.Swap(zcisFairRate, yoyFairRate)
import QuantLib.TermStructure.Inflation
import QuantLib.TermStructure.Yield(flatForward, PillarChoice(..))
import QuantLib.Time.Calendar
import QuantLib.Time.Date hiding(today)
import QuantLib.Time.Schedule(dayCounter, DayCounterConstructor(..), Frequency(..), TimeUnit(..))
data Result = Result
{ zeroRate1Y :: Double
, zeroRate2Y :: Double
, yoyRate1Y :: Double
, yoyRate2Y :: Double
, zcisHelperFairRate :: Double -- ^fair rate of the swap 'zeroCouponInflationSwapHelperSwap' pulls out of h1
, yoyHelperFairRate :: Double -- ^likewise, via 'yearOnYearInflationSwapHelperSwap' on hy1
} deriving Show
run :: IO Result
run = do
setEvaluationDate $ Just today
dc <- dayCounter Actual365FixedStandard
cal <- calendar Null
-- UKRPI needs a fixing at every month up to the reference date, not just at
-- baseDate, or the bootstrap fails with "Missing UK RPI fixing for ...".
fixingDates <- mapM (\n -> advance cal (1 `january` 2022) (n, Months) Unadjusted False) [0 .. 24 :: Int]
zii <- zeroInflationIndex UKRPI
forM_ (zip [1 :: Double ..] fixingDates) $ \(i, d) -> addFixing zii d (260.0 + i) False
q1 <- simpleQuote flatRate
q2 <- simpleQuote flatRate
h1 <- zeroCouponInflationSwapHelper q1 obsLag maturity1 cal Unadjusted dc zii CPILinear LastRelevantDate Nothing
h2 <- zeroCouponInflationSwapHelper q2 obsLag maturity2 cal Unadjusted dc zii CPILinear LastRelevantDate Nothing
zeroCurve <- piecewiseZeroInflationCurve today baseDate Monthly dc [h1, h2] Linear
z1 <- zeroRate zeroCurve maturity1 True
z2 <- zeroRate zeroCurve maturity2 True
-- the helper builds its swap internally, so this accessor is the only way to reach it;
-- once the curve is bootstrapped the swap must reprice to the quote it was built from
zcisFair <- zcisFairRate =<< zeroCouponInflationSwapHelperSwap h1
yii <- yoyInflationIndex YYUKRPI
forM_ (zip [1 :: Double ..] fixingDates) $ \(i, d) -> addFixing yii d (flatRate + i * 0.0001) False
nominalQ <- simpleQuote 0.02
nominalCurve <- flatForward today nominalQ dc IR.Continuous Annual
qy1 <- simpleQuote flatRate
qy2 <- simpleQuote flatRate
hy1 <- yearOnYearInflationSwapHelper qy1 obsLag maturity1 cal Unadjusted dc yii CPILinear nominalCurve LastRelevantDate Nothing
hy2 <- yearOnYearInflationSwapHelper qy2 obsLag maturity2 cal Unadjusted dc yii CPILinear nominalCurve LastRelevantDate Nothing
yoyCurve <- piecewiseYoYInflationCurve today baseDate flatRate Monthly dc [hy1, hy2] Linear
y1 <- yoyRate yoyCurve maturity1 True
y2 <- yoyRate yoyCurve maturity2 True
yoyFair <- yoyFairRate =<< yearOnYearInflationSwapHelperSwap hy1
return Result
{ zeroRate1Y = z1
, zeroRate2Y = z2
, yoyRate1Y = y1
, yoyRate2Y = y2
, zcisHelperFairRate = zcisFair
, yoyHelperFairRate = yoyFair
}
where
today = 2 `january` 2024
baseDate = 1 `october` 2023
obsLag = (3, Months)
maturity1 = 2 `january` 2025
maturity2 = 2 `january` 2026
flatRate = 0.03
-- vim: set ft=haskell ff=unix ts=8 sts=2 sw=2 et: