HQu-0.0.0.0: src/Q/Stochastic/Process.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module Q.Stochastic.Process
where
import Control.Monad
import Control.Monad.State
import Data.List (foldl')
import Data.RVar
import Data.Random
import Numeric.LinearAlgebra
rwalkState :: RVarT (State Double) Double
rwalkState = do
prev <- lift get
change <- rvarT StdNormal
let new = prev + change
lift (put new)
return new
type Time = Double
-- Dont know why this wasn't done.
-- Is there an easier way to do this where we either lift or return?
instance (Num a) => Num (RVarT m a) where
(+) = liftM2 (+)
(-) = liftM2 (-)
(*) = liftM2 (*)
abs = liftM abs
signum = liftM signum
fromInteger x = return $ fromInteger x
-- |Discretization of stochastic process over given interval
class (Num b) => Discretize d b where
-- |Discretization of the drift process.
dDrift :: (StochasticProcess a b) => a -> d -> (Time, b) -> RVar b
-- |Discretization of the diffusion process.
dDiff :: (StochasticProcess a b) => a -> d -> (Time, b) -> RVar b
-- |dt used.
dDt :: (StochasticProcess a b) => a -> d -> (Time, b) -> Time
-- |A stochastic process of the form \(dX_t = \mu(X_t, t)dt + \sigma(S_t, t)dB_t \)
class (Num b) => StochasticProcess a b where
-- |The process drift.
pDrift :: a -> (Time, b) -> RVar b
-- |The process diffusion.
pDiff :: a -> (Time, b) -> RVar b
-- |Evolve a process from a given state to a given time.
pEvolve :: (Discretize d b) => a -- ^The process
-> d -- ^Discretization scheme
-> (Time, b) -- ^Initial state
-> Time -- ^Target time t.
-> RVar b -- ^\(dB_i\).
-> RVar b -- ^\(X(t)\).
pEvolve p disc s0@(t0, x0) t dw = do
if t0 >= t then return x0 else do
s'@(t', b') <- pEvolve' p disc s0 dw
if t' >= t then return b' else pEvolve p disc s' t dw
-- |Similar to evolve, but evolves the process with the discretization scheme \(dt\).
pEvolve' :: (Discretize d b, Num b) => a -> d -> (Time, b) -> RVar b -> RVar (Time, b)
pEvolve' process discr s@(t, b) dw = do
let !newT = t + dDt process discr s
!newX = do
drift <- dDrift process discr s
diff <- dDiff process discr s
dw' <- dw
return $ b + drift + diff * dw'
newX :: RVar b
(newT,) <$> newX
-- |Geometric Brownian motion
data GeometricBrownian = GeometricBrownian {
gbDrift :: Double -- ^Drift
, gbDiff :: Double -- ^Vol
} deriving (Show)
instance StochasticProcess GeometricBrownian Double where
-- pDrift :: GeometricBrownian -> (Time, Double) -> RVar Double
pDrift p (_, x) = return $ gbDrift p * x -- drift is prpotional to the spot.
pDiff p (_, x) = return $ gbDiff p * x -- diffisuion is also prportional to the spot.
-- | Ito process
data ItoProcess = ItoProcess {
ipDrift :: (Time, Double) -> Double,
ipDiff :: (Time, Double) -> Double
}