hasquant-0.5.0.2: test/example/QuantLib/Example/EquityOption.hs
{-# LANGUAGE TemplateHaskell #-}
module QuantLib.Example.EquityOption
(
Result(..)
, run
) where
import Data.Time.Calendar
import QuantLib.Instrument
import QuantLib.InterestRate
import QuantLib.Instrument.Option
import QuantLib.Math
import QuantLib.Model
import QuantLib.PricingEngine
import QuantLib.Process
import QuantLib.Quote
import QuantLib.Settings
import QuantLib.Time.Calendar
import QuantLib.Time.Date
import QuantLib.Time.Schedule
import QuantLib.TermStructure.Volatility
import QuantLib.TermStructure.Yield
import QuantLib.Syntax
data Result = Result
{ analyticEuroR :: [Double]
, analyticHestonR :: [Double]
, batesR :: [Double]
, bawR :: [Double]
, bjsR :: [Double]
, binR :: [[Double]]
, intR :: [Double]
, fdR :: [Double]
, mcR :: (Double, Double, Double)
}
-- Each of these prices the same shared 'europeanOpt'/'americanOpt' handle by
-- attaching a fresh engine and reading 'npv' -- the QuantLib objects are pure
-- value-holders whose only "state" is the currently attached engine, so each
-- helper is self-contained even though it mutates a handle built in 'run'.
analyticEuropeanNpv :: GeneralizedBlackScholesProcess -> VanillaOption -> IO Double
analyticEuropeanNpv bsmProc europeanOpt = do
analyticEuropeanEngine bsmProc Nothing >>= QuantLib.Instrument.setPricingEngine europeanOpt
npv europeanOpt
hestonNpv :: YieldTermStructure -> YieldTermStructure -> SimpleQuote -> Double -> VanillaOption -> IO Double
hestonNpv ts divTS underQ vol europeanOpt = do
hestonProc <- hestonProcess ts (Just divTS) underQ (vol*vol) 1.0 (vol*vol) 0.001 0.0 QuadraticExponentialMartingale
hestonMod <- hestonModel hestonProc
hestonEng <- analyticHestonEngine' hestonMod 144
QuantLib.Instrument.setPricingEngine europeanOpt hestonEng
npv europeanOpt
batesNpv :: YieldTermStructure -> YieldTermStructure -> SimpleQuote -> Double -> VanillaOption -> IO Double
batesNpv ts divTS underQ vol europeanOpt = do
batesEng <- batesProcess ts divTS underQ (vol*vol) 1.0 (vol*vol) 0.001 0.0 1.0e-14 1.0e-14 1.0e-14 HestonFullTruncation >>= batesModel >>= (`batesEngine` 144)
QuantLib.Instrument.setPricingEngine europeanOpt batesEng
npv europeanOpt
baroneAdesiWhaleyNpv :: GeneralizedBlackScholesProcess -> VanillaOption -> IO Double
baroneAdesiWhaleyNpv bsmProc americanOpt = do
bawEng <- baroneAdesiWhaleyApproximationEngine bsmProc
QuantLib.Instrument.setPricingEngine americanOpt bawEng
npv americanOpt
bjerksundStenslandNpv :: GeneralizedBlackScholesProcess -> VanillaOption -> IO Double
bjerksundStenslandNpv bsmProc americanOpt = do
bsEng <- bjerksundStenslandApproximationEngine bsmProc
QuantLib.Instrument.setPricingEngine americanOpt bsEng
npv americanOpt
integralNpv :: GeneralizedBlackScholesProcess -> VanillaOption -> IO Double
integralNpv bsmProc europeanOpt = do
iEng <- integralEngine bsmProc
QuantLib.Instrument.setPricingEngine europeanOpt iEng
npv europeanOpt
fdSweep :: GeneralizedBlackScholesProcess -> [OneAssetOption] -> IO [Double]
fdSweep bsmProc = mapM (\i -> do
eng <- fdBlackScholesVanillaEngine bsmProc 801 800 0 Douglas False 0.0 CashDividendSpot
QuantLib.Instrument.setPricingEngine i eng
npv i)
binomialPrice :: GeneralizedBlackScholesProcess -> [OneAssetOption] -> Word -> BinomialTree -> IO [Double]
binomialPrice proc inst timeSteps tree = do
eng <- binomialVanillaEngine tree proc timeSteps
mapM (\i -> QuantLib.Instrument.setPricingEngine i eng >> npv i) inst
monteCarloNpvs :: GeneralizedBlackScholesProcess -> VanillaOption -> VanillaOption -> IO (Double, Double, Double)
monteCarloNpvs bsmProc europeanOpt americanOpt = do
mceEng <- mcEuropeanEngine PseudoRandom bsmProc (Just 1) Nothing False False Nothing (Just 0.02) Nothing 42
QuantLib.Instrument.setPricingEngine europeanOpt mceEng
mcE <- npv europeanOpt
mceEng2 <- mcEuropeanEngine LowDiscrepancy bsmProc (Just 1) Nothing False False (Just 32768) Nothing Nothing 0
QuantLib.Instrument.setPricingEngine europeanOpt mceEng2
mcE2 <- npv europeanOpt
mcaEng <- mcAmericanEngine PseudoRandom bsmProc (Just 100) Nothing True False Nothing (Just 0.02) Nothing 42 2 Monomial (Just 4096) Nothing Nothing
QuantLib.Instrument.setPricingEngine americanOpt mcaEng
mcA <- npv americanOpt
return (mcE, mcE2, mcA)
run :: IO Result
run = do
setEvaluationDate $ Just tod
dc <- dayCounter Actual365FixedStandard
let europeanEx = European $ EuropeanExercise maturity
bermudanEx = Bermudan $ BermudanExercise exDates False
americanEx = American Nothing maturity False
underQ <- simpleQuote under
riskFreeQ <- simpleQuote riskFreeRate
ts <- flatForward settl riskFreeQ dc Continuous Annual
divQ <- simpleQuote dividend
divTS <- flatForward settl divQ dc Continuous Annual
volQ <- simpleQuote vol
volTS <- calendar TARGET >>= $(free2nd 'blackConstantVol) settl volQ dc
let payoff = PlainVanilla $ PlainVanillaPayoff optType strike
bsmProc <- blackScholesMertonProcess underQ divTS ts volTS EulerDiscretization False
europeanOpt <- vanillaOption payoff europeanEx
bermudanOpt <- vanillaOption payoff bermudanEx
americanOpt <- vanillaOption payoff americanEx
europeanInst <- asOneAssetOption europeanOpt
americanInst <- asOneAssetOption americanOpt
bermudanInst <- asOneAssetOption bermudanOpt
analyticEuro <- analyticEuropeanNpv bsmProc europeanOpt
analyticHeston <- hestonNpv ts divTS underQ vol europeanOpt
bates <- batesNpv ts divTS underQ vol europeanOpt
baw <- baroneAdesiWhaleyNpv bsmProc americanOpt
bjs <- bjerksundStenslandNpv bsmProc americanOpt
int <- integralNpv bsmProc europeanOpt
fd <- fdSweep bsmProc [europeanInst, bermudanInst, americanInst]
bin <- mapM (binomialPrice bsmProc [europeanInst, bermudanInst, americanInst] timeSteps)
[JarrowRudd, CoxRossRubinstein, AdditiveEQPBinomialTree, Trigeorgis, Tian, LeisenReimer, Joshi4]
(mcE, mcE2, mcA) <- monteCarloNpvs bsmProc europeanOpt americanOpt
return Result {
analyticEuroR = [analyticEuro]
, analyticHestonR = [analyticHeston]
, batesR = [bates]
, bawR = [baw]
, bjsR = [bjs]
, binR = bin
, intR = [int]
, fdR = fd
, mcR = (mcE, mcE2, mcA)
}
where tod = 15 `may` 1998
settl = 17 `may` 1998
under = 36
strike = 40
dividend = 0.0
riskFreeRate = 0.06
vol = 0.20
maturity = 17 `may` 1999
optType = Put
months = [1 .. 4]
exDates = map (\i -> addGregorianMonthsClip (3*i) settl) months
timeSteps = 801
-- vim: set ft=haskell ff=unix ts=8 sts=2 sw=2 et: