{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
module QuantLib.Stochastic.Process
( module QuantLib.Stochastic.Process )
where
import Data.List (foldl')
import QuantLib.Stochastic.Random (NormalGenerator (..))
class Discretize b where
dDrift :: StochasticProcess a => a->b->Dot->Double
dDiff :: StochasticProcess a => a->b->Dot->Double
dDt :: StochasticProcess a => a->b->Dot->Double
class StochasticProcess a where
drift :: a -> Dot -> Double
diff :: a -> Dot -> Double
evolve :: Discretize b=> b -> a -> Dot -> Double -> Dot
evolve discr p dot dw = Dot newT newX
where !newT = getT dot + dDt p discr dot
!newX = getX dot + dDrift p discr dot + dDiff p discr dot * dw
data Dot = Dot { getT :: {-# UNPACK #-} !Double, getX :: {-# UNPACK #-} !Double }
deriving (Show, Eq)
type Path = [Dot]
generatePath :: (StochasticProcess a, NormalGenerator b, Discretize c) => b->c->a->Int->Dot->Path
generatePath rnd discr sp steps x0 = reverse path
where
(!list, _) = foldl' generator ([], rnd) [1..steps]
!path = foldl' evolver [x0] list
evolver p dw = evolve discr sp (head p) dw : p
generator (l, r) _ = (p:l, newRnd)
where
(!p, newRnd) = ngGetNext r
data GeometricBrownian = GeometricBrownian {
gbDrift :: Double,
gbDiff :: Double
} deriving (Show)
instance StochasticProcess GeometricBrownian where
drift p (Dot _ x) = gbDrift p * x
diff p (Dot _ x) = gbDiff p * x
data ItoProcess = ItoProcess {
ipDrift :: Dot->Double,
ipDiff :: Dot->Double
}
instance StochasticProcess ItoProcess where
drift = ipDrift
diff = ipDiff
data SquareRootProcess = SquareRootProcess {
srpSpeed :: Double,
srpMean :: Double,
srpSigma :: Double
} deriving (Show)
instance StochasticProcess SquareRootProcess where
drift p (Dot _ x) = srpSpeed p * (srpMean p - x)
diff p (Dot _ x) = srpSigma p * sqrt x
data OrnsteinUhlenbeckProcess = OrnsteinUhlenbeckProcess {
oupSpeed :: Double,
oupLevel :: Double,
oupSigma :: Double
} deriving (Show)
instance StochasticProcess OrnsteinUhlenbeckProcess where
drift p (Dot _ x) = oupSpeed p * (oupLevel p - x)
diff p _ = oupSigma p
data BlackScholesProcess = BlackScholesProcess {
bspRiskFree :: Double->Double,
bspDividend :: Double->Double,
bspBlackVol :: Dot->Double
}
instance StochasticProcess BlackScholesProcess where
drift (BlackScholesProcess r q v) dot = r (getT dot) - q ( getT dot) - 0.5 * v dot ** 2
diff = bspBlackVol