packages feed

quantfin 0.1.0.2 → 0.2.0.0

raw patch · 17 files changed

+499/−173 lines, 17 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Quant.ContingentClaim: Observables :: [a] -> Observables a
- Quant.ContingentClaim: data Observables a
- Quant.ContingentClaim: instance Monoid ContingentClaim
- Quant.ContingentClaim: monitorByNum :: Int -> Time -> CCBuilder ContingentClaim MCMap Double
- Quant.ContingentClaim: obsGet :: Observables a -> [a]
- Quant.ContingentClaim: type MCObservables = Observables Double
- Quant.Models.Black: instance Discretize Black
- Quant.Models.Dupire: instance Discretize Dupire
- Quant.Models.Heston: instance Discretize Heston
- Quant.Models.Merton: instance Discretize Merton
- Quant.Models.Processes: procElapsed :: ProcessSpec -> Double
- Quant.Models.Processes: procGrowth :: ProcessSpec -> Double
- Quant.Models.Processes: procInit :: ProcessSpec -> Double
- Quant.MonteCarlo: discountState :: (Discretize a, Discretize a) => a -> Time -> MonteCarlo (MCObservables, Time) Double
- Quant.Types: Observables :: [a] -> Observables a
- Quant.Types: data Observables a
- Quant.Types: instance Show a => Show (Observables a)
- Quant.Types: obsGet :: Observables a -> [a]
- Quant.Types: type MCObservables = Observables Double
+ Quant.ContingentClaim: instance Monoid (ContingentClaim a)
+ Quant.ContingentClaim: monitor1 :: Obs1 a => Time -> CCBuilder (ContingentClaim a) (Map Time a) Double
+ Quant.ContingentClaim: monitor2 :: Obs2 a => Time -> CCBuilder (ContingentClaim a) (Map Time a) Double
+ Quant.ContingentClaim: monitor3 :: Obs3 a => Time -> CCBuilder (ContingentClaim a) (Map Time a) Double
+ Quant.ContingentClaim: monitor4 :: Obs4 a => Time -> CCBuilder (ContingentClaim a) (Map Time a) Double
+ Quant.ContingentClaim: monitor5 :: Obs5 a => Time -> CCBuilder (ContingentClaim a) (Map Time a) Double
+ Quant.ContingentClaim: type ContingentClaim4 = forall a. Obs4 a => ContingentClaim a
+ Quant.Math.Utilities: cotraverseVec :: (Unbox b1, Unbox b, Functor f) => (f b1 -> b) -> Int -> f (Vector b1) -> Vector b
+ Quant.Models.Black: instance Discretize Black Observables1
+ Quant.Models.Dupire: instance Discretize Dupire Observables1
+ Quant.Models.Heston: instance Discretize Heston Observables2
+ Quant.Models.Merton: instance Discretize Merton Observables1
+ Quant.Models.Processes: normal :: ProcessSpec -> Double -> Double -> Double
+ Quant.RNG.MWC64X: MWC64X :: {-# UNPACK #-} !Word64 -> MWC64X
+ Quant.RNG.MWC64X: data MWC64X
+ Quant.RNG.MWC64X: instance Eq MWC64X
+ Quant.RNG.MWC64X: instance RandomGen MWC64X
+ Quant.RNG.MWC64X: instance Show MWC64X
+ Quant.RNG.MWC64X: randomDouble :: MWC64X -> (Double, MWC64X)
+ Quant.RNG.MWC64X: randomInt :: MWC64X -> (Int, MWC64X)
+ Quant.RNG.MWC64X: randomInt64 :: MWC64X -> (Int64, MWC64X)
+ Quant.RNG.MWC64X: randomWord32 :: MWC64X -> (Word32, MWC64X)
+ Quant.RNG.MWC64X: randomWord64 :: MWC64X -> (Word64, MWC64X)
+ Quant.RNG.MWC64X: skip :: MWC64X -> Word64 -> MWC64X
+ Quant.Types: Observables1 :: {-# UNPACK #-} !Double -> Observables1
+ Quant.Types: Observables2 :: {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> Observables2
+ Quant.Types: Observables3 :: {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> Observables3
+ Quant.Types: Observables4 :: {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> Observables4
+ Quant.Types: Observables5 :: {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> Observables5
+ Quant.Types: class Obs1 a
+ Quant.Types: class Obs1 a => Obs2 a
+ Quant.Types: class Obs2 a => Obs3 a
+ Quant.Types: class Obs3 a => Obs4 a
+ Quant.Types: class Obs4 a => Obs5 a
+ Quant.Types: data Observables1
+ Quant.Types: data Observables2
+ Quant.Types: data Observables3
+ Quant.Types: data Observables4
+ Quant.Types: data Observables5
+ Quant.Types: get1 :: Obs1 a => a -> Double
+ Quant.Types: get2 :: Obs2 a => a -> Double
+ Quant.Types: get3 :: Obs3 a => a -> Double
+ Quant.Types: get4 :: Obs4 a => a -> Double
+ Quant.Types: get5 :: Obs5 a => a -> Double
+ Quant.Types: instance Obs1 Observables1
+ Quant.Types: instance Obs1 Observables2
+ Quant.Types: instance Obs1 Observables3
+ Quant.Types: instance Obs1 Observables4
+ Quant.Types: instance Obs1 Observables5
+ Quant.Types: instance Obs2 Observables2
+ Quant.Types: instance Obs2 Observables3
+ Quant.Types: instance Obs2 Observables4
+ Quant.Types: instance Obs2 Observables5
+ Quant.Types: instance Obs3 Observables3
+ Quant.Types: instance Obs3 Observables4
+ Quant.Types: instance Obs3 Observables5
+ Quant.Types: instance Obs4 Observables4
+ Quant.Types: instance Obs4 Observables5
+ Quant.Types: instance Obs5 Observables5
+ Quant.VectorOps: (*.) :: (Unbox a, Num a) => a -> Vector a -> Vector a
+ Quant.VectorOps: (+.) :: (Unbox a, Num a) => a -> Vector a -> Vector a
+ Quant.VectorOps: (-.) :: (Unbox a, Num a) => a -> Vector a -> Vector a
+ Quant.VectorOps: (.*) :: (Unbox a, Num a) => Vector a -> a -> Vector a
+ Quant.VectorOps: (.*.) :: (Unbox a, Num a) => Vector a -> Vector a -> Vector a
+ Quant.VectorOps: (.+) :: (Unbox a, Num a) => Vector a -> a -> Vector a
+ Quant.VectorOps: (.+.) :: (Unbox a, Num a) => Vector a -> Vector a -> Vector a
+ Quant.VectorOps: (.-) :: (Unbox a, Num a) => Vector a -> a -> Vector a
+ Quant.VectorOps: (.-.) :: (Unbox a, Num a) => Vector a -> Vector a -> Vector a
+ Quant.VectorOps: (./) :: (Unbox a, Fractional a) => Vector a -> a -> Vector a
+ Quant.VectorOps: (./.) :: (Unbox a, Fractional a) => Vector a -> Vector a -> Vector a
+ Quant.VectorOps: (/.) :: (Unbox a, Fractional a) => a -> Vector a -> Vector a
- Quant.ContingentClaim: CCProcessor :: Time -> Maybe [PayoffFunc CashFlow] -> CCProcessor
+ Quant.ContingentClaim: CCProcessor :: Time -> [Map Time a -> CashFlow] -> CCProcessor a
- Quant.ContingentClaim: ContingentClaim :: [CCProcessor] -> ContingentClaim
+ Quant.ContingentClaim: ContingentClaim :: [CCProcessor a] -> ContingentClaim a
- Quant.ContingentClaim: arithmeticAsianOption :: OptionType -> Double -> [Time] -> Time -> ContingentClaim
+ Quant.ContingentClaim: arithmeticAsianOption :: Obs1 a => OptionType -> Double -> [Time] -> Time -> ContingentClaim a
- Quant.ContingentClaim: binaryOption :: OptionType -> Double -> Double -> Time -> ContingentClaim
+ Quant.ContingentClaim: binaryOption :: Obs1 a => OptionType -> Double -> Double -> Time -> ContingentClaim a
- Quant.ContingentClaim: callSpread :: Double -> Double -> Time -> ContingentClaim
+ Quant.ContingentClaim: callSpread :: Obs1 a => Double -> Double -> Time -> ContingentClaim a
- Quant.ContingentClaim: combine :: ContingentClaim -> ContingentClaim -> ContingentClaim
+ Quant.ContingentClaim: combine :: ContingentClaim a -> ContingentClaim a -> ContingentClaim a
- Quant.ContingentClaim: data CCProcessor
+ Quant.ContingentClaim: data CCProcessor a
- Quant.ContingentClaim: fixedBond :: Double -> Double -> Double -> Int -> ContingentClaim
+ Quant.ContingentClaim: fixedBond :: Double -> Double -> Double -> Int -> ContingentClaim a
- Quant.ContingentClaim: forwardContract :: Time -> ContingentClaim
+ Quant.ContingentClaim: forwardContract :: Obs1 a => Time -> ContingentClaim a
- Quant.ContingentClaim: geometricAsianOption :: OptionType -> Double -> [Time] -> Time -> ContingentClaim
+ Quant.ContingentClaim: geometricAsianOption :: Obs1 a => OptionType -> Double -> [Time] -> Time -> ContingentClaim a
- Quant.ContingentClaim: monitor :: Time -> CCBuilder ContingentClaim MCMap Double
+ Quant.ContingentClaim: monitor :: Obs1 a => Time -> CCBuilder (ContingentClaim a) (Map Time a) Double
- Quant.ContingentClaim: monitorTime :: CCProcessor -> Time
+ Quant.ContingentClaim: monitorTime :: CCProcessor a -> Time
- Quant.ContingentClaim: multiplier :: Double -> ContingentClaim -> ContingentClaim
+ Quant.ContingentClaim: multiplier :: Double -> ContingentClaim a -> ContingentClaim a
- Quant.ContingentClaim: newtype ContingentClaim
+ Quant.ContingentClaim: newtype ContingentClaim a
- Quant.ContingentClaim: payoutFunc :: CCProcessor -> Maybe [PayoffFunc CashFlow]
+ Quant.ContingentClaim: payoutFunc :: CCProcessor a -> [Map Time a -> CashFlow]
- Quant.ContingentClaim: putSpread :: Double -> Double -> Time -> ContingentClaim
+ Quant.ContingentClaim: putSpread :: Obs1 a => Double -> Double -> Time -> ContingentClaim a
- Quant.ContingentClaim: short :: ContingentClaim -> ContingentClaim
+ Quant.ContingentClaim: short :: ContingentClaim a -> ContingentClaim a
- Quant.ContingentClaim: specify :: CCBuilder ContingentClaim MCMap CashFlow -> ContingentClaim
+ Quant.ContingentClaim: specify :: CCBuilder (ContingentClaim a) (Map Time a) CashFlow -> ContingentClaim a
- Quant.ContingentClaim: straddle :: Double -> Time -> ContingentClaim
+ Quant.ContingentClaim: straddle :: Obs1 a => Double -> Time -> ContingentClaim a
- Quant.ContingentClaim: terminalOnly :: Time -> (Double -> Double) -> ContingentClaim
+ Quant.ContingentClaim: terminalOnly :: Obs1 a => Time -> (Double -> Double) -> ContingentClaim a
- Quant.ContingentClaim: unCC :: ContingentClaim -> [CCProcessor]
+ Quant.ContingentClaim: unCC :: ContingentClaim a -> [CCProcessor a]
- Quant.ContingentClaim: vanillaOption :: OptionType -> Double -> Time -> ContingentClaim
+ Quant.ContingentClaim: vanillaOption :: Obs1 a => OptionType -> Double -> Time -> ContingentClaim a
- Quant.ContingentClaim: zcb :: Time -> Double -> ContingentClaim
+ Quant.ContingentClaim: zcb :: Time -> Double -> ContingentClaim a
- Quant.Models.Processes: ProcessSpec :: Double -> Double -> Double -> ProcessSpec
+ Quant.Models.Processes: ProcessSpec :: {-# UNPACK #-} !Double -> !Double -> !Double -> ProcessSpec
- Quant.MonteCarlo: class Discretize a where evolve mdl t2 anti = do { (_, t1) <- get; let ms = maxStep mdl; unless (t2 == t1) $ if timeDiff t1 t2 < ms then evolve' mdl t2 anti else do { evolve' mdl (timeOffset t1 ms) anti; evolve mdl t2 anti } } discountState m t = return $ discount m t maxStep _ = 1 / 250 simulateState modl (ContingentClaim ccb) trials anti = avg <$> replicateM trials singleTrial where singleTrial = initialize modl >> process (0 :: Double) empty ccb [] process discCFs obsMap c@(CCProcessor t mf : ccs) allcfs@(CashFlow cft amt : cfs) = if t > cft then do { evolve modl cft anti; d <- discountState modl cft; process (discCFs + d * amt) obsMap c cfs } else do { evolve modl t anti; obs <- gets fst; let obsMap' = insert t obs obsMap; case mf of { Nothing -> process discCFs obsMap' ccs allcfs Just f -> let newCFs = map ($ obsMap') f insertCFList xs cfList = foldl' (flip insertCF) cfList xs in process discCFs obsMap' ccs (insertCFList newCFs allcfs) } } process discCFs obsMap (CCProcessor t mf : ccs) [] = do { evolve modl t anti; obs <- gets fst; let obsMap' = insert t obs obsMap; case mf of { Nothing -> process discCFs obsMap' ccs [] Just f -> let newCFs = map ($ obsMap') f insertCFList xs cfList = foldl' (flip insertCF) cfList xs in process discCFs obsMap' ccs (insertCFList newCFs []) } } process discCFs obsMap [] (cf : cfs) = do { evolve modl (cfTime cf) anti; d <- discountState modl $ cfTime cf; process (discCFs + d * cfAmount cf) obsMap [] cfs } process discCFs _ _ _ = return $! discCFs insertCF (CashFlow t amt) (CashFlow t' amt' : cfs) | t > t' = CashFlow t' amt' : insertCF (CashFlow t amt) cfs | otherwise = CashFlow t amt : CashFlow t' amt' : cfs insertCF cf [] = [cf] avg v = sum v / fromIntegral trials runSimulation modl ccs seed trials anti = runMC run seed (Observables [], Time 0) where run = simulateState modl ccs trials anti runSimulationAnti modl ccs seed trials = (runSim True + runSim False) / 2 where runSim = runSimulation modl ccs seed (trials `div` 2) quickSim mdl opts trials = runSimulation mdl opts (pureMT 500) trials False quickSimAnti mdl opts trials = runSimulationAnti mdl opts (pureMT 500) trials
+ Quant.MonteCarlo: class Discretize a b | a -> b where evolve mdl t2 anti = do { (_, t1) <- get; let ms = maxStep mdl; unless (t2 == t1) $ if timeDiff t1 t2 < ms then evolve' mdl t2 anti else do { evolve' mdl (timeOffset t1 ms) anti; evolve mdl t2 anti } } maxStep _ = 1 / 250 simulateState modl (ContingentClaim ccb) trials anti = avg <$> replicateM trials singleTrial where singleTrial = initialize modl >> process (0 :: Double) empty ccb [] process discCFs obsMap c@(CCProcessor t mf : ccs) allcfs@(CashFlow cft amt : cfs) = if t > cft then do { evolve modl cft anti; d <- discount modl cft; process (discCFs + d * amt) obsMap c cfs } else do { evolve modl t anti; obs <- gets fst; let obsMap' = insert t obs obsMap newCFs = map ($ obsMap') mf insertCFList xs cfList = foldl' (flip insertCF) cfList xs; process discCFs obsMap' ccs (insertCFList newCFs allcfs) } process discCFs obsMap (CCProcessor t mf : ccs) [] = do { evolve modl t anti; obs <- gets fst; let obsMap' = insert t obs obsMap newCFs = map ($ obsMap') mf insertCFList xs cfList = foldl' (flip insertCF) cfList xs; process discCFs obsMap' ccs (insertCFList newCFs []) } process discCFs obsMap [] (cf : cfs) = do { evolve modl (cfTime cf) anti; d <- discount modl $ cfTime cf; process (discCFs + d * cfAmount cf) obsMap [] cfs } process discCFs _ _ _ = return $! discCFs insertCF (CashFlow t amt) (CashFlow t' amt' : cfs) | t > t' = CashFlow t' amt' : insertCF (CashFlow t amt) cfs | otherwise = CashFlow t amt : CashFlow t' amt' : cfs insertCF cf [] = [cf] avg v = sum v / fromIntegral trials
- Quant.MonteCarlo: discount :: (Discretize a, Discretize a) => a -> Time -> Double
+ Quant.MonteCarlo: discount :: (Discretize a b, Discretize a b) => a -> Time -> MonteCarlo (b, Time) Double
- Quant.MonteCarlo: evolve :: (Discretize a, Discretize a) => a -> Time -> Bool -> MonteCarlo (MCObservables, Time) ()
+ Quant.MonteCarlo: evolve :: (Discretize a b, Discretize a b) => a -> Time -> Bool -> MonteCarlo (b, Time) ()
- Quant.MonteCarlo: evolve' :: (Discretize a, Discretize a) => a -> Time -> Bool -> MonteCarlo (MCObservables, Time) ()
+ Quant.MonteCarlo: evolve' :: (Discretize a b, Discretize a b) => a -> Time -> Bool -> MonteCarlo (b, Time) ()
- Quant.MonteCarlo: forwardGen :: (Discretize a, Discretize a) => a -> Time -> MonteCarlo (MCObservables, Time) Double
+ Quant.MonteCarlo: forwardGen :: (Discretize a b, Discretize a b) => a -> Time -> MonteCarlo (b, Time) Double
- Quant.MonteCarlo: initialize :: (Discretize a, Discretize a) => a -> MonteCarlo (MCObservables, Time) ()
+ Quant.MonteCarlo: initialize :: (Discretize a b, Discretize a b) => a -> MonteCarlo (b, Time) ()
- Quant.MonteCarlo: maxStep :: (Discretize a, Discretize a) => a -> Double
+ Quant.MonteCarlo: maxStep :: (Discretize a b, Discretize a b) => a -> Double
- Quant.MonteCarlo: quickSim :: (Discretize a, Discretize a) => a -> ContingentClaim -> Int -> Double
+ Quant.MonteCarlo: quickSim :: Discretize a b => a -> ContingentClaim b -> Int -> Double
- Quant.MonteCarlo: quickSimAnti :: (Discretize a, Discretize a) => a -> ContingentClaim -> Int -> Double
+ Quant.MonteCarlo: quickSimAnti :: Discretize a b => a -> ContingentClaim b -> Int -> Double
- Quant.MonteCarlo: runSimulation :: (Discretize a, Discretize a, MonadRandom (StateT b Identity)) => a -> ContingentClaim -> b -> Int -> Bool -> Double
+ Quant.MonteCarlo: runSimulation :: (Discretize a b, MonadRandom (StateT c Identity)) => a -> ContingentClaim b -> c -> Int -> Bool -> Double
- Quant.MonteCarlo: runSimulationAnti :: (Discretize a, Discretize a, MonadRandom (StateT b Identity)) => a -> ContingentClaim -> b -> Int -> Double
+ Quant.MonteCarlo: runSimulationAnti :: (Discretize a b, MonadRandom (StateT c Identity)) => a -> ContingentClaim b -> c -> Int -> Double
- Quant.MonteCarlo: simulateState :: (Discretize a, Discretize a) => a -> ContingentClaim -> Int -> Bool -> MonteCarlo (MCObservables, Time) Double
+ Quant.MonteCarlo: simulateState :: (Discretize a b, Discretize a b) => a -> ContingentClaim b -> Int -> Bool -> MonteCarlo (b, Time) Double
- Quant.Time: Time :: Double -> Time
+ Quant.Time: Time :: {-# UNPACK #-} !Double -> Time
- Quant.VolSurf: FlatSurf :: Double -> FlatSurf
+ Quant.VolSurf: FlatSurf :: {-# UNPACK #-} !Double -> FlatSurf
- Quant.YieldCurve: FlatCurve :: Double -> FlatCurve
+ Quant.YieldCurve: FlatCurve :: {-# UNPACK #-} !Double -> FlatCurve

Files

Test.hs view
@@ -19,10 +19,10 @@ 			baseYC  --discount function
 
 --make a vanilla put, struck at 100, maturing at time 1
-vanopt :: ContingentClaim
+vanopt :: ContingentClaim1
 vanopt = vanillaOption Call 100 (Time 1) --built in function
 
-vanopt' :: ContingentClaim
+vanopt' :: ContingentClaim1
 vanopt' = specify $ do
 	x <- monitor (Time 1)
 	return $ CashFlow (Time 1) (max (x - 100) 0) --roll your own
@@ -31,8 +31,12 @@ vanoptPrice :: Double
 vanoptPrice = quickSim black vanopt 100000 
 
+vanoptPrice' :: Double
+vanoptPrice' = quickSim black vanopt' 100000 
+
+
 --Make a call spread with a 100 unit notional, using some handy combinators.
-cs :: ContingentClaim
+cs :: ContingentClaim1
 cs =  multiplier 100 
    $  vanillaOption Call 100 (Time 1) 
    <> short (vanillaOption Call 120 (Time 1)) 
@@ -68,29 +72,37 @@ csHeston = quickSimAnti heston cs 100000
 
 --create an option that pays off based on the square of its underlying
-squareOpt :: ContingentClaim
+squareOpt :: ContingentClaim1
 squareOpt = terminalOnly (Time 1) $ \x -> x*x  --using the built in function
+
+squareOpt' :: ContingentClaim1
 squareOpt' = specify $ do --roll your own
 	x <- monitor (Time 1)
 	return $ CashFlow (Time 1) $ x*x
 squareOptPrice :: Double
 squareOptPrice = quickSimAnti black squareOpt 100000
 
+squareOptPrice' :: Double
+squareOptPrice' = quickSimAnti black squareOpt' 100000
+
+
 --create an option with a bizarre payoff
-bizarre :: ContingentClaim
+bizarre :: ContingentClaim1
 bizarre = specify $ do
   x <- monitor (Time 1)   --check the price of asset 0 @ time 1
   y <- monitor (Time 2)   --check the price of asset 0 @ time 2
   z <- monitor (Time 3)   --check the price of asset 0 @ time 3
-  return $ CashFlow (Time 4) $ x ^ 3 / y ^ 2 - 3 * z --payoff @ time 4
+  return $ CashFlow (Time 4) $ sin x * cos y / (z ** sin x) --payoff @ time 4
 bizarrePrice :: Double
 bizarrePrice = quickSimAnti black bizarre 100000
 
 main :: IO ()
 main = do
 	print vanoptPrice
+	print vanoptPrice'
 	print csPrice
 	print callSpreadAnti
 	print csHeston
 	print squareOptPrice
+	print squareOptPrice'
 	print bizarrePrice
quantfin.cabal view
@@ -10,7 +10,7 @@ -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.1.0.2
+version:             0.2.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            Quant finance library in pure Haskell.
@@ -62,11 +62,12 @@                        Quant.Models.Dupire
                        Quant.Models.Heston
                        Quant.Models.Processes
-                       --Quant.RNG.MWC64X
+                       Quant.RNG.MWC64X
                        Quant.MonteCarlo
                        Quant.ContingentClaim
                        Quant.Types
                        Quant.Time
+                       Quant.VectorOps
   
   -- Modules included in this library but not exported.
   -- other-modules:       
src/Quant/ContingentClaim.hs view
@@ -1,9 +1,13 @@+{-# LANGUAGE RankNTypes #-}
+
 module Quant.ContingentClaim (
     -- * Types for modeling contingent claims.
     ContingentClaim (..)
+  , ContingentClaim1
+  , ContingentClaim2
+  , ContingentClaim3
+  , ContingentClaim4
   , CCProcessor (..)
-  , Observables (..)
-  , MCObservables
   , OptionType (..)
   , CashFlow (..)
   , CCBuilder
@@ -11,7 +15,11 @@   -- * Options and option combinators
   , specify
   , monitor
-  , monitorByNum
+  , monitor1
+  , monitor2
+  , monitor3
+  , monitor4
+  , monitor5
   , vanillaOption
   , binaryOption
   , straddle
@@ -35,44 +43,78 @@ import Quant.Time
 import qualified Data.Map as M
 
-type MCMap = M.Map Time MCObservables
-type PayoffFunc a = MCMap -> a
+-- | Key type for building contingent claims.
+--Monoid instance allows for trivial combinations of
+--contingent claims.
+newtype ContingentClaim a = ContingentClaim { unCC :: [CCProcessor a] }
 
+-- | Contingent claims with one observable.
+type ContingentClaim1 = forall a . Obs1 a => ContingentClaim a
+-- | Contingent claims with two observables.
+type ContingentClaim2 = forall a . Obs2 a => ContingentClaim a
+-- | Contingent claims with three observables.
+type ContingentClaim3 = forall a . Obs3 a => ContingentClaim a
+-- | Contingent claims with four observables.
+type ContingentClaim4 = forall a . Obs4 a => ContingentClaim a
 
-data CCProcessor = CCProcessor  {
-                      monitorTime      :: Time
-                    , payoutFunc       :: Maybe [PayoffFunc CashFlow]
-}
+instance Monoid (ContingentClaim a) where
+  mempty  = ContingentClaim []
+  mappend = combine
 
+-- |Basic element of a `ContingentClaim`.  Each element contains
+--a Time.  Each Time, the observables are stored in the map.
+--Also, optionally a payout function may be applied at any time step.
+data CCProcessor a = CCProcessor  {
+    monitorTime      :: Time
+  , payoutFunc       :: [M.Map Time a -> CashFlow]
+}
 
 type CCBuilder w r a = WriterT w (Reader r) a
 
-monitor :: Time -> CCBuilder ContingentClaim MCMap Double
-monitor = monitorByNum 0
+-- | 'monitor' gets the value of the first observable at a given time.
+monitor :: Obs1 a => Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitor = monitor1
 
-monitorByNum :: Int -> Time -> CCBuilder ContingentClaim MCMap Double
-monitorByNum idx t = do
-  tell $ ContingentClaim [CCProcessor t Nothing]
-  m <- lift ask
-  return $ obsGet (m M.! t) !! idx  --I know, I know.
+-- | 'monitor1' gets the value of the first observable at a given time.
+monitor1 :: Obs1 a => Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitor1 = monitorGeneric get1
 
-specify :: CCBuilder ContingentClaim MCMap CashFlow -> ContingentClaim
-specify x = w `mappend` ContingentClaim [CCProcessor (last0 w') (Just [f])]
+-- | 'monitor2' gets the value of the second observable at a given time.
+monitor2 :: Obs2 a => Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitor2 = monitorGeneric get2
+
+-- | 'monitor3' gets the value of the third observable at a given time.
+monitor3 :: Obs3 a => Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitor3 = monitorGeneric get3
+
+-- | 'monitor4' gets the value of the fourth observable at a given time.
+monitor4 :: Obs4 a => Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitor4 = monitorGeneric get4
+
+-- | 'monitor5' gets the value of the fifth observable at a given time.
+monitor5 :: Obs5 a => Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitor5 = monitorGeneric get5
+
+-- | 'monitorGeneric' applies any getter at a given time.
+monitorGeneric :: (a -> Double) -> Time -> CCBuilder (ContingentClaim a) (M.Map Time a) Double
+monitorGeneric f t = do
+  tell $ ContingentClaim [CCProcessor t []]
+  m <- ask
+  return $ f (m M.! t)
+
+-- | Pulls a ContingentClaim out of the CCBuilder monad.
+specify :: CCBuilder (ContingentClaim a) (M.Map Time a) CashFlow -> ContingentClaim a
+specify x = w `mappend` ContingentClaim [CCProcessor lastW [f]]
   where
     w  = runReader (execWriterT x) M.empty
     f  = runReader . liftM fst $ runWriterT x
-    w' = map monitorTime $ unCC w
+    lastW = last0 . map monitorTime $ unCC w
     -- Equivalent to Prelude's last, but with a default of zero
     last0 [] = Time 0
     last0 [y] = y
     last0 (_:ys) = last0 ys
 
-newtype ContingentClaim = ContingentClaim { unCC :: [CCProcessor] }
 
-instance Monoid ContingentClaim where
-  mempty  = ContingentClaim []
-  mappend = combine
-
 -- | Function to generate a vanilla put/call style payout.
 vanillaPayout :: OptionType  -- ^ Put or Call
               -> Double      -- ^ Strike
@@ -94,23 +136,23 @@ 
 -- | Takes a maturity time and a function and generates a ContingentClaim 
 --dependent only on the terminal value of the observable.
-terminalOnly :: Time -> (Double -> Double) -> ContingentClaim
+terminalOnly :: Obs1 a => Time -> (Double -> Double) -> ContingentClaim a
 terminalOnly t g = specify $ do
   x <- monitor t
   return $ CashFlow t $ g x
 
 -- | Takes an OptionType, a strike, and a time to maturity and generates a vanilla option.
-vanillaOption :: OptionType -> Double -> Time -> ContingentClaim
+vanillaOption :: Obs1 a => OptionType -> Double -> Time -> ContingentClaim a
 vanillaOption pc strike t = terminalOnly t $ vanillaPayout pc strike
 
 -- | Takes an OptionType, a strike, a payout amount and a time to 
 --maturity and generates a vanilla option.
-binaryOption :: OptionType -> Double -> Double -> Time -> ContingentClaim
+binaryOption :: Obs1 a => OptionType -> Double -> Double -> Time -> ContingentClaim a
 binaryOption pc strike amount t = terminalOnly t $ binaryPayout pc strike amount
 
 -- | Takes an OptionType, a strike, observation times, time to
 --maturity and generates an arithmetic Asian option.
-arithmeticAsianOption :: OptionType -> Double -> [Time] -> Time -> ContingentClaim
+arithmeticAsianOption :: Obs1 a => OptionType -> Double -> [Time] -> Time -> ContingentClaim a
 arithmeticAsianOption pc strike obsTimes t = specify $ do
   x <- mapM monitor obsTimes
   let avg = sum x / fromIntegral (length obsTimes)
@@ -118,70 +160,64 @@ 
 -- | Takes an OptionType, a strike, observation times, time to
 --maturity and generates an arithmetic Asian option.
-geometricAsianOption :: OptionType -> Double -> [Time] -> Time -> ContingentClaim
+geometricAsianOption :: Obs1 a => OptionType -> Double -> [Time] -> Time -> ContingentClaim a
 geometricAsianOption pc strike obsTimes t = specify $ do
   x <- mapM monitor obsTimes
   let avg = product x ** (1 / fromIntegral (length obsTimes))
   return $ CashFlow t $ vanillaPayout pc strike avg
 
 -- | Scales up a contingent claim by a multiplier.
-multiplier :: Double -> ContingentClaim -> ContingentClaim
+multiplier :: Double -> ContingentClaim a -> ContingentClaim a
 multiplier notional cs = ContingentClaim $ map f (unCC cs)
-    where f (CCProcessor t g) = CCProcessor t $ fmap (fmap (scale.)) g
+    where f (CCProcessor t g) = CCProcessor t $ (fmap (scale.)) g
           scale (CashFlow dt amt) = CashFlow dt (amt*notional)
 
 -- | Flips the signs in a contingent claim to make it a short position.
-short :: ContingentClaim -> ContingentClaim
+short :: ContingentClaim a -> ContingentClaim a
 short = multiplier (-1)
 
 -- | Takes an amount and a time and generates a fixed cash flow.
-zcb :: Time -> Double -> ContingentClaim
+zcb :: Time -> Double -> ContingentClaim a
 zcb t amt = specify $ return $ CashFlow t amt
 
 -- | Takes a face value, an interest rate, a payment frequency and makes a fixed bond
-fixedBond :: Double -> Double -> Double -> Int -> ContingentClaim
+fixedBond :: Double -> Double -> Double -> Int -> ContingentClaim a
 fixedBond faceVal intRate freq pmts = zcb (Time $ fromIntegral pmts * freq) faceVal 
                                    <> mconcat (map f [1..pmts])
   where
     f x = zcb (Time $ fromIntegral x * freq) (faceVal * intRate * freq) 
 
 -- | Takes a time to maturity and generates a forward contract.
-forwardContract :: Time -> ContingentClaim
+forwardContract :: Obs1 a => Time -> ContingentClaim a
 forwardContract t = specify $ do
   x <- monitor t
   return $ CashFlow t x
 
 -- | A call spread is a long position in a low-strike call
 --and a short position in a high strike call.
-callSpread :: Double -> Double -> Time -> ContingentClaim
+callSpread :: Obs1 a => Double -> Double -> Time -> ContingentClaim a
 callSpread lowStrike highStrike t = mappend (vanillaOption Call lowStrike t) 
                                             (short $ vanillaOption Call highStrike t)
 
 -- | A put spread is a long position in a high strike put
 --and a short position in a low strike put.
-putSpread :: Double -> Double -> Time -> ContingentClaim
+putSpread :: Obs1 a => Double -> Double -> Time -> ContingentClaim a
 putSpread lowStrike highStrike t = mappend (vanillaOption Put highStrike t) 
                                            (short $ vanillaOption Put lowStrike t)
 
 -- | A straddle is a put and a call with the same time to maturity / strike.
-straddle :: Double -> Time -> ContingentClaim
+straddle :: Obs1 a => Double -> Time -> ContingentClaim a
 straddle strike t = vanillaOption Put strike t <> vanillaOption Call strike t
 
 -- | Combines two contingent claims into one. 
-combine :: ContingentClaim -> ContingentClaim -> ContingentClaim
+combine :: ContingentClaim a -> ContingentClaim a -> ContingentClaim a
 combine (ContingentClaim x) (ContingentClaim y) = ContingentClaim $ combine' x y
   where
     combine' (cc1:ccs1) (cc2:ccs2)
       | monitorTime cc1 == monitorTime cc2 = let
-          (CCProcessor t mf)  = cc1
-          (CCProcessor _ mf') = cc2 in
-            case mf of
-              Nothing -> cc2 : combine' ccs1 ccs2
-              Just a  -> case mf' of
-                Nothing -> cc1 : combine' ccs1 ccs2
-                Just b  -> CCProcessor t (Just (a ++ b)) : combine' ccs1 ccs2
+            CCProcessor t mf  = cc1
+            CCProcessor _ mf' = cc2 in
+          CCProcessor t (mf++mf') : combine' ccs1 ccs2
       | monitorTime cc1 > monitorTime cc2 = cc2 : combine' (cc1:ccs1) ccs2
       | otherwise = cc1 : combine' ccs1 (cc2:ccs2)
-    combine' [] [] = []
-    combine' cs [] = cs
-    combine' [] cs = cs+    combine' cs1 cs2 = cs1 ++ cs2
src/Quant/Math/Interpolation.hs view
@@ -21,6 +21,7 @@           wt1 = (x2-x) / (x2-x1)
           wt2 = (x-x1) / (x2-x1)
 linearInterpolator _ [y] _ = y
+linearInterpolator _ _ _ = error "Empty interpolation list."
 {-# INLINE linearInterpolator #-}
 
 logLinearInterpolator :: Interpolator1d
@@ -56,4 +57,5 @@             term = x-x1
             h' = x2-x1
     evalSpline _ (y':_) _ = y'
+    evalSpline _ _ _ = error "Empty spline list."
 {-# INLINE cSplineInterpolator #-}
src/Quant/Math/Utilities.hs view
@@ -1,12 +1,15 @@ module Quant.Math.Utilities (
     tdmaSolver
+  , cotraverseVec
 ) where
 
 import Control.Monad
 import Control.Monad.ST
 import qualified Data.Vector.Mutable as M
 import qualified Data.Vector as V
+import qualified Data.Vector.Unboxed as U
 
+-- |Tridiagonal matrix solver.  Pretty simple.
 tdmaSolver :: (Fractional a, Ord a) => [a] -> [a] -> [a] -> [a] -> [a]
 tdmaSolver aL bL cL dL = V.toList $ 
     let [a,b,c,d] = map V.fromList [aL,bL,cL,dL] in 
@@ -38,4 +41,11 @@                 xi1 <- M.read xn $ x+1
                 M.write xn x $ di - ci*xi1
             V.unsafeFreeze xn
-{-# INLINE tdmaSolver #-}+{-# INLINE tdmaSolver #-}
+
+-- | Something similar to cotraverse in the Distributive package,
+--but specialized to unboxed vectors, which are not functors.
+cotraverseVec :: (U.Unbox b1, U.Unbox b, Functor f) =>
+                       (f b1 -> b) -> Int -> f (U.Vector b1) -> U.Vector b
+cotraverseVec f l m = U.map (\i -> f (fmap (U.!i) m)) (U.enumFromN 0 l)
+{-# INLINE cotraverseVec #-}
src/Quant/Models/Black.hs view
@@ -1,16 +1,17 @@ {-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 
 
 module Quant.Models.Black (
     Black (..)
 ) where
 
+import Quant.Types
 import Quant.Time
 import Quant.YieldCurve
 import Data.Random
 import Control.Monad.State
 import Quant.MonteCarlo
-import Quant.ContingentClaim
 
 -- | 'Black' represents a Black-Scholes model.
 data Black = forall a b  . (YieldCurve a, YieldCurve b) => Black {
@@ -28,24 +29,22 @@             --vol' = vol :+ 0
             --logs = log s :+ 0
 
-instance Discretize Black where
-    initialize (Black s _ _ _)  = put (Observables [s], Time 0)
+instance Discretize Black Observables1 where
+    initialize (Black s _ _ _)  = put (Observables1 s, Time 0)
     {-# INLINE initialize #-}
 
     evolve' b@(Black _ vol _ _) t2 anti = do
-        (Observables (stateVal:_), t1) <- get
+        (Observables1 stateVal, t1) <- get
         fwd <- forwardGen b t2
-        let  grwth = (fwd - vol*vol/2) * timeDiff t1 t2
-        postVal <- do
-             resid <- lift stdNormal
-             if anti then
-                return $ stateVal * exp (grwth - resid*vol)
-             else
-                return $ stateVal * exp (grwth + resid*vol)
-        put (Observables [postVal], t2)
+        let t = timeDiff t1 t2 
+            grwth = (fwd - vol*vol/2) * t
+        resid <- lift stdNormal
+        let resid' = if anti then -resid else resid
+            postVal = stateVal * exp (grwth + resid'*vol*sqrt t)
+        put (Observables1 postVal, t2)
     {-# INLINE evolve' #-}
 
-    discount (Black _ _ _ dsc) t = disc dsc t
+    discount (Black _ _ _ dsc) t = return $ disc dsc t
     {-# INLINE discount #-}
 
     forwardGen (Black _ _ fg _) t2 = do
src/Quant/Models/Dupire.hs view
@@ -1,13 +1,14 @@ {-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 
 module Quant.Models.Dupire (
     Dupire (..)
 ) where
 
 import Quant.Time
+import Quant.Types
 import Data.Random
 import Control.Monad.State
-import Quant.ContingentClaim
 import Quant.MonteCarlo
 import Quant.YieldCurve
 
@@ -18,22 +19,23 @@  , mertonForwardGen  ::  a  -- ^ 'YieldCurve' to generate forwards
  , mertonDiscounter  ::  b } -- ^ 'YieldCurve' to generate discount rates
 
-instance Discretize Dupire where
-    initialize (Dupire s _ _ _) = put (Observables [s], Time 0)
+instance Discretize Dupire Observables1 where
+    initialize (Dupire s _ _ _) = put (Observables1 s, Time 0)
     {-# INLINE initialize #-}
 
     evolve' d@(Dupire _ f _ _) t2 anti = do
-        (Observables (stateVal:_), t1) <- get
+        (Observables1 stateVal, t1) <- get
         fwd <- forwardGen d t2
         let vol   = f t1 stateVal
-            grwth = (fwd - vol * vol / 2) * timeDiff t1 t2
+            t     = timeDiff t1 t2
+            grwth = (fwd - vol * vol / 2) * t
         normResid <- lift stdNormal
-        let s' | anti      = stateVal * exp (grwth - normResid*vol)
-               | otherwise = stateVal * exp (grwth - normResid*vol)
-        put (Observables [s'], t2)
+        let s' | anti      = stateVal * exp (grwth - normResid*vol*sqrt t)
+               | otherwise = stateVal * exp (grwth - normResid*vol*sqrt t)
+        put (Observables1 s', t2)
     {-# INLINE evolve' #-}
 
-    discount (Dupire _ _ _ dsc) t = disc dsc t
+    discount (Dupire _ _ _ dsc) t = return $ disc dsc t
     {-# INLINE discount #-}
 
     forwardGen (Dupire _ _ fg _) t2 = do
src/Quant/Models/Heston.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 
 
 module Quant.Models.Heston (
@@ -6,11 +7,11 @@ ) where
 
 import Quant.Time
+import Quant.Types
 import Quant.YieldCurve
 import Data.Random
 import Control.Monad.State
 import Quant.MonteCarlo
-import Quant.ContingentClaim
 
 -- | 'Heston' represents a Heston model (i.e. stochastic volatility).
 data Heston = forall a b  . (YieldCurve a, YieldCurve b) => Heston {
@@ -23,12 +24,12 @@   , hestonForwardGen :: a       -- ^ 'YieldCurve' to generate forwards
   , hestonDisc       :: b }     -- ^ 'YieldCurve' to generate discounts
 
-instance Discretize Heston where
-    initialize (Heston s v0 _ _ _ _ _ _) = put (Observables [s, v0], Time 0)
+instance Discretize Heston Observables2 where
+    initialize (Heston s v0 _ _ _ _ _ _) = put (Observables2 s v0, Time 0)
     {-# INLINE initialize #-}
 
     evolve' h@(Heston _ _ vf l rho eta _ _) t2 anti = do
-        (Observables (sState:vState:_), t1) <- get
+        (Observables2 sState vState, t1) <- get
         fwd <- forwardGen h t2
         let grwth = (fwd - vState/2) * t
             t = timeDiff t1 t2
@@ -39,10 +40,10 @@           resid2 = rho * resid1 + sqrt (1-rho*rho) * resid2'
           v' = (sqrt vState `op` (eta/2.0*sqrt t* resid2))^(2 :: Int)-l*(vState-vf)*t-eta*eta*t/4.0
           s' = sState * exp (grwth `op` (resid1*sqrt (vState*t)))
-        put (Observables [s', abs v'], t2)
+        put (Observables2 s' (abs v'), t2)
     {-# INLINE evolve' #-}
 
-    discount (Heston _ _ _ _ _ _ _ d) t = disc d t
+    discount (Heston _ _ _ _ _ _ _ d) t = return $ disc d t
     {-# INLINE discount #-}
 
     forwardGen (Heston _ _ _ _ _ _ fg _) t2 = do
src/Quant/Models/Merton.hs view
@@ -1,15 +1,16 @@ {-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 
 module Quant.Models.Merton (
     Merton (..)
 ) where
 
 import Quant.Time
+import Quant.Types
 import Data.Random
 import Data.Random.Distribution.Poisson
 import Control.Monad.State
 import Quant.MonteCarlo
-import Quant.ContingentClaim
 import Quant.YieldCurve
 
 -- | 'Merton' represents a Merton model (Black-Scholes w/ jumps).
@@ -30,27 +31,27 @@           --  inner2 = exp $ i * k * (mu :+ 0) -  k*k*(sig :+ 0) * (sig :+ 0)/2
             --addon = exp $ (intensity * t :+ 0) * (-i*k*(inner1 - 1) + inner2 - 1)
 
-instance Discretize Merton where
-    initialize (Merton s _ _ _ _ _ _) = put (Observables [s], Time 0)
+instance Discretize Merton Observables1 where
+    initialize (Merton s _ _ _ _ _ _) = put (Observables1 s, Time 0)
     {-# INLINE initialize #-}
 
     evolve' m@(Merton _ vol intensity mu sig _ _) t2 anti = do
-        (Observables (stateVal:_), t1) <- get
+        (Observables1 stateVal, t1) <- get
         fwd <- forwardGen m t2
         let correction = exp (mu + sig*sig /2.0) - 1
             grwth = (fwd - vol*vol/2 - intensity * correction) * t
             t = timeDiff t1 t2
         normResid1 <- lift stdNormal
         normResid2 <- lift stdNormal
-        poissonResid <- lift $ integralPoisson (intensity * t) :: MonteCarlo (MCObservables, Time) Int
+        poissonResid <- lift $ integralPoisson (intensity * t) :: MonteCarlo (Observables1, Time) Int
         let  poisson' = fromIntegral poissonResid
              jumpterm = mu*poisson'+sig*sqrt poisson' * normResid2
-             s' | anti      = stateVal * exp (grwth - normResid1*vol + jumpterm)
-                | otherwise = stateVal * exp (grwth + normResid1*vol + jumpterm)
-        put (Observables [s'], t2)
+             s' | anti      = stateVal * exp (grwth - normResid1*vol*sqrt t + jumpterm)
+                | otherwise = stateVal * exp (grwth + normResid1*vol*sqrt t + jumpterm)
+        put (Observables1 s', t2)
     {-# INLINE evolve' #-}
 
-    discount (Merton _ _ _ _ _ _ dsc) t = disc dsc t
+    discount (Merton _ _ _ _ _ _ dsc) t = return $ disc dsc t
     {-# INLINE discount #-}
 
     forwardGen (Merton _ _ _ _ _ fg _) t2 = do
src/Quant/Models/Processes.hs view
@@ -1,14 +1,14 @@ 
 module Quant.Models.Processes (
     ProcessSpec (..)
+  , normal
   , lognormal
 ) where
 
-data ProcessSpec = ProcessSpec {
-    procInit    :: Double
-  , procGrowth  :: Double
-  , procElapsed :: Double
-}
+data ProcessSpec = ProcessSpec {-# UNPACK #-} !Double !Double !Double
+
+normal :: ProcessSpec -> Double -> Double -> Double
+normal (ProcessSpec initVal r t) vol normRand = initVal + vol * normRand + r * t
 
 lognormal :: ProcessSpec -> Double -> Double -> Double 
 lognormal (ProcessSpec initVal r t) vol normRand = initVal * exp ( g + sig * normRand )
src/Quant/MonteCarlo.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
 
 
 module Quant.MonteCarlo (
@@ -11,6 +13,11 @@   , Discretize(..)
   , OptionType(..)
 
+  , runSimulation
+  , runSimulationAnti
+  , quickSim
+  , quickSimAnti
+
   )
 where
 
@@ -45,17 +52,17 @@ 
 Minimal complete definition: 'initialize', 'discounter', 'forwardGen' and 'evolve''.
 -}
-class Discretize a where
+class Discretize a b | a -> b where
 
     -- | Initializes a Monte Carlo simulation for a given number of runs.
-    initialize :: Discretize a => a   -- ^ Model
-                               -> MonteCarlo (MCObservables, Time) ()
+    initialize :: Discretize a b => a   -- ^ Model
+                                 -> MonteCarlo (b, Time) ()
 
     -- | Evolves the internal states of the MC variables between two times.
-    evolve :: Discretize a => a            -- ^ Model
-                           -> Time         -- ^ time to evolve to
-                           -> Bool         -- whether or not to use flipped variates
-                           -> MonteCarlo (MCObservables, Time) ()
+    evolve :: Discretize a b => a            -- ^ Model
+                             -> Time         -- ^ time to evolve to
+                             -> Bool         -- whether or not to use flipped variates
+                             -> MonteCarlo (b, Time) ()
     evolve mdl t2 anti = do
         (_, t1) <- get
         let ms = maxStep mdl
@@ -66,35 +73,30 @@               evolve' mdl (timeOffset t1 ms) anti
               evolve mdl t2 anti
 
-    -- | Stateful discounting function, takes a model and a time, and returns a vector of results.
-    discountState :: Discretize a => a -> Time -> MonteCarlo (MCObservables, Time) Double
-    discountState m t = return $ discount m t
-    {-# INLINE discountState #-}
-
     -- | Non-stateful discounting function...might need to find a better place to put this.
-    discount :: Discretize a => a -> Time -> Double
+    discount :: Discretize a b => a -> Time -> MonteCarlo (b, Time) Double
 
     -- | Stateful forward generator for a given model at a certain time.
-    forwardGen :: Discretize a => a -> Time -> MonteCarlo (MCObservables, Time) Double
+    forwardGen :: Discretize a b => a -> Time -> MonteCarlo (b, Time) Double
 
     -- | Internal function to evolve a model to a given time.
-    evolve' :: Discretize a => a          -- ^ model
-                            -> Time       -- ^ time to evolve to
-                            -> Bool       -- ^ whether or not to use flipped variates
-                            -> MonteCarlo (MCObservables, Time) () -- ^ computation result
+    evolve' :: Discretize a b => a          -- ^ model
+                              -> Time       -- ^ time to evolve to
+                              -> Bool       -- ^ whether or not to use flipped variates
+                              -> MonteCarlo (b, Time) () -- ^ computation result
 
     -- | Determines the maximum size time-step for discretization purposes. Defaults to 1/250.
-    maxStep :: Discretize a => a -> Double
+    maxStep :: Discretize a b => a -> Double
     maxStep _ = 1/250
     {-# INLINE maxStep #-}
 
     -- | Perform a simulation of a compiled basket of contingent claims.
-    simulateState :: Discretize a => 
-           a                       -- ^ model
-        -> ContingentClaim         -- ^ compilied basket of claims
-        -> Int                     -- ^ number of trials
-        -> Bool                    -- ^ antithetic?
-        -> MonteCarlo (MCObservables, Time) Double -- ^ computation result
+    simulateState :: Discretize a b => 
+           a                              -- ^ model
+        -> ContingentClaim b              -- ^ compilied basket of claims
+        -> Int                            -- ^ number of trials
+        -> Bool                           -- ^ antithetic?
+        -> MonteCarlo (b, Time) Double -- ^ computation result
     simulateState modl (ContingentClaim ccb) trials anti = avg <$> replicateM trials singleTrial
           where 
             singleTrial = initialize modl >> 
@@ -104,31 +106,27 @@             process discCFs obsMap c@(CCProcessor t mf:ccs) allcfs@(CashFlow cft amt:cfs) = 
               if t > cft then do
                   evolve modl cft anti
-                  d <- discountState modl cft
+                  d <- discount modl cft
                   process (discCFs+d*amt) obsMap c cfs
               else do
                   evolve modl t anti
                   obs <- gets fst
                   let obsMap' = Map.insert t obs obsMap
-                  case mf of
-                    Nothing -> process discCFs obsMap' ccs allcfs
-                    Just f -> let newCFs = map ($obsMap') f
-                                  insertCFList xs cfList = foldl' (flip insertCF) cfList xs in
-                        process discCFs obsMap' ccs (insertCFList newCFs allcfs)
+                      newCFs = map ($obsMap') mf
+                      insertCFList xs cfList = foldl' (flip insertCF) cfList xs
+                  process discCFs obsMap' ccs (insertCFList newCFs allcfs)
 
             process discCFs obsMap (CCProcessor t mf:ccs) [] = do
               evolve modl t anti
               obs <- gets fst
               let obsMap' = Map.insert t obs obsMap
-              case mf of
-                Nothing -> process discCFs obsMap' ccs []
-                Just f -> let newCFs = map ($obsMap') f
-                              insertCFList xs cfList = foldl' (flip insertCF) cfList xs in
-                        process discCFs obsMap' ccs (insertCFList newCFs [])                       
+                  newCFs = map ($obsMap') mf
+                  insertCFList xs cfList = foldl' (flip insertCF) cfList xs
+              process discCFs obsMap' ccs (insertCFList newCFs [])
 
             process discCFs obsMap [] (cf:cfs) = do
               evolve modl (cfTime cf) anti
-              d <- discountState modl $ cfTime cf
+              d <- discount modl $ cfTime cf
               process (discCFs+d*cfAmount cf) obsMap [] cfs
 
             process discCFs _ _ _ = return $! discCFs
@@ -140,30 +138,34 @@ 
             avg v = sum v / fromIntegral trials
 
-    -- | Runs a simulation for a 'ContingentClaim'.
-    runSimulation :: (Discretize a,
-                             MonadRandom (StateT b Identity)) =>
-                                a                  -- ^ model
-                             -> ContingentClaim    -- ^ claims to value
-                             -> b                  -- ^ initial random state
-                             -> Int                -- ^ trials
-                             -> Bool               -- ^ whether to use antithetic variables
-                             -> Double             -- ^ final value
-    runSimulation modl ccs seed trials anti = runMC run seed (Observables [], Time 0)
-       where
-            run = simulateState modl ccs trials anti
+-- | Runs a simulation for a 'ContingentClaim'.
+runSimulation :: (Discretize a b,
+                         MonadRandom (StateT c Identity)) =>
+                            a                             -- ^ model
+                         -> ContingentClaim b             -- ^ claims to value
+                         -> c                             -- ^ initial random state
+                         -> Int                           -- ^ trials
+                         -> Bool                          -- ^ whether to use antithetic variables
+                         -> Double                        -- ^ final value
+runSimulation modl ccs seed trials anti = runMC run seed (undefined, Time 0)
+   where
+        run = simulateState modl ccs trials anti
+{-# INLINE runSimulation #-}
 
-    -- | Like 'runSimulation', but splits the trials in two and does antithetic variates.
-    runSimulationAnti :: (Discretize a,
-                             MonadRandom (StateT b Identity)) =>
-                            a -> ContingentClaim -> b -> Int -> Double
-    runSimulationAnti modl ccs seed trials = (runSim True + runSim False) / 2
-        where runSim = runSimulation modl ccs seed (trials `div` 2)
+-- | Like 'runSimulation', but splits the trials in two and does antithetic variates.
+runSimulationAnti :: (Discretize a b,
+                         MonadRandom (StateT c Identity)) =>
+                        a -> ContingentClaim b -> c -> Int -> Double
+runSimulationAnti modl ccs seed trials = (runSim True + runSim False) / 2
+    where runSim x = runSimulation modl ccs seed (trials `div` 2) x
+{-# INLINE runSimulationAnti #-}
 
-    -- | 'runSimulation' with a default random number generator.
-    quickSim :: Discretize a => a -> ContingentClaim -> Int -> Double
-    quickSim mdl opts trials = runSimulation mdl opts (pureMT 500) trials False
+-- | 'runSimulation' with a default random number generator.
+quickSim :: Discretize a b => a -> ContingentClaim b -> Int -> Double
+quickSim mdl opts trials = runSimulation mdl opts (pureMT 500) trials False
+{-# INLINE quickSim #-}
 
-    -- | 'runSimulationAnti' with a default random number generator.
-    quickSimAnti :: Discretize a => a -> ContingentClaim -> Int -> Double
-    quickSimAnti mdl opts trials = runSimulationAnti mdl opts (pureMT 500) trials+-- | 'runSimulationAnti' with a default random number generator.
+quickSimAnti :: Discretize a b => a -> ContingentClaim b -> Int -> Double
+quickSimAnti mdl opts trials = runSimulationAnti mdl opts (pureMT 500) trials
+{-# INLINE quickSimAnti #-}
+ src/Quant/RNG/MWC64X.hs view
@@ -0,0 +1,88 @@+module Quant.RNG.MWC64X (
+    MWC64X(..)
+  , randomWord32
+  , randomWord64
+  , randomInt
+  , randomDouble
+  , randomInt64
+  , skip
+) where
+
+import Data.Int
+import Data.Bits 
+import Data.Word 
+import Data.Random.Internal.Words
+import System.Random
+
+data MWC64X = MWC64X {-# UNPACK #-} !Word64 deriving (Eq,Show)
+
+randomWord32 :: MWC64X -> (Word32, MWC64X)
+randomWord32 (MWC64X state) = (x `xor` c, MWC64X state')
+    where c = fromIntegral $ state `shiftR` 32 :: Word32 
+          x = fromIntegral $ state .&. 0xFFFFFFFF :: Word32 
+          state' = fromIntegral x * aConst + fromIntegral c 
+
+randomInt :: MWC64X -> (Int,MWC64X)
+randomInt g = (fromIntegral i, g')
+        where (i, g') = randomWord64 g
+
+randomWord64 :: MWC64X -> (Word64, MWC64X) 
+randomWord64 x = (buildWord64'' y1 y2, x'') 
+    where (y1, x' )  = randomWord32 x 
+          (y2, x'') = randomWord32 x'
+
+randomDouble :: MWC64X -> (Double, MWC64X)
+randomDouble x = (fromIntegral (val `div` 2048) / 9007199254740992, x')
+    where (val, x') = randomWord64 x
+
+randomInt64 :: MWC64X -> (Int64,MWC64X)
+randomInt64 g = (fromIntegral i, g')
+        where (i, g') = randomWord64 g
+
+instance RandomGen MWC64X where
+    next g = (fromIntegral w, g')
+        where (w, g') = randomWord64 g
+    split g = (skip g skipConst, g)
+
+addMod64 :: Word64 -> Word64 -> Word64 -> Word64
+addMod64 a b m = (a+b) `mod` m
+
+--mulMod64 :: Word64 -> Word64 -> Word64 -> Word64
+--mulMod64 a b m = (a * b) `mod` m
+mulMod64 :: Word64 -> Word64 -> Word64 -> Word64
+mulMod64 a b m = f 0 a b
+    where f r a1 b1
+            | a1 == 0 = r
+            | otherwise = f r' a' b'
+                where r' = if a1 .&. 1 == 1 then addMod64 r b1 m else r
+                      b' = addMod64 b1 b1 m
+                      a' = a `shiftR` 1
+
+powMod64 :: Word64 -> Word64 -> Word64 -> Word64
+powMod64 a e m = f a 1 e
+    where f sqr acc e1
+            | e1 == 0 = acc
+            | otherwise = f sqr' acc' e' 
+                where acc' = if e1 .&. 1 == 1 then mulMod64 acc sqr m else acc
+                      sqr' = mulMod64 sqr sqr m
+                      e'   = e `shiftR` 1
+
+skip :: MWC64X -> Word64 -> MWC64X
+skip (MWC64X st) d = MWC64X st'
+    where
+        m   = powMod64 aConst d mConst
+        c   = st `shiftR` 32 
+        x   = st .&. 0xFFFFFFFF 
+        x'  = mulMod64 (x * aConst + c) m mConst
+        x'' = fromIntegral $ x' `div` aConst :: Word32
+        c'  = fromIntegral $ x' `mod` aConst :: Word32
+        st' = buildWord64'' c' x''
+
+mkWord64 :: Word32 -> Word32 -> Word64
+mkWord64 a b = (fromIntegral $ a `shiftL` 32) .&. fromIntegral b
+
+aConst, mConst, skipConst :: Word64
+aConst = 4294883355
+--bConst = 4077358422479273989
+mConst = 18446383549859758079
+skipConst = 1073741824
src/Quant/Time.hs view
@@ -6,7 +6,7 @@   , timeFromZero
   ) where
 
-data Time = Time Double deriving (Eq,Show,Ord)
+data Time = Time {-# UNPACK #-} !Double deriving (Eq,Show,Ord)
 
 timeDiff :: Time -> Time -> Double
 timeDiff (Time x) (Time y) = y - x
src/Quant/Types.hs view
@@ -1,24 +1,117 @@ 
 module Quant.Types (
     CashFlow(..)
-  , Observables(..)
-  , MCObservables
+  , Observables1(..)
+  , Observables2(..)
+  , Observables3(..)
+  , Observables4(..)
+  , Observables5(..)
   , OptionType(..)
+  , Obs1(..)
+  , Obs2(..)
+  , Obs3(..)
+  , Obs4(..)
+  , Obs5(..)
   ) where
 
 import Quant.Time
 
+-- | A CashFlow is just a time and an amount.
 data CashFlow = CashFlow {
     cfTime   :: Time
   , cfAmount :: Double
 }
 
--- | Observables are the observables available in a Monte Carlo simulation.
---Most basic MCs will have one observables (Black-Scholes) whereas more
---complex ones will have multiple (i.e. Heston-Hull-White).
-data Observables a = Observables { obsGet :: [a] } deriving (Show)
 
-type MCObservables = Observables Double
-
 -- | Type for Put or Calls
 data OptionType = Put | Call deriving (Eq,Show)
+
+-- | Single-observable container.
+data Observables1 = Observables1 {-# UNPACK #-} !Double
+-- | Two observable container.
+data Observables2 = Observables2 {-# UNPACK #-} !Double {-# UNPACK #-} !Double
+-- | Three observable container.
+data Observables3 = Observables3 {-# UNPACK #-} !Double {-# UNPACK #-} !Double 
+                                 {-# UNPACK #-} !Double
+-- | Four observable container.
+data Observables4 = Observables4 {-# UNPACK #-} !Double {-# UNPACK #-} !Double 
+                                 {-# UNPACK #-} !Double {-# UNPACK #-} !Double
+-- | Five observable container.
+data Observables5 = Observables5 {-# UNPACK #-} !Double {-# UNPACK #-} !Double 
+                                 {-# UNPACK #-} !Double {-# UNPACK #-} !Double 
+                                 {-# UNPACK #-} !Double
+
+class Obs1 a where
+    get1 :: a -> Double
+
+class (Obs1 a) => Obs2 a where
+	get2 :: a -> Double
+
+class (Obs2 a) => Obs3 a where
+	get3 :: a -> Double
+
+class (Obs3 a) => Obs4 a where
+	get4 :: a -> Double
+
+class (Obs4 a) => Obs5 a where
+	get5 :: a -> Double
+
+instance Obs1 Observables1 where
+	get1 (Observables1 x) = x
+	{-# INLINE get1 #-}
+
+instance Obs1 Observables2 where
+	get1 (Observables2 x _) = x
+	{-# INLINE get1 #-}
+
+instance Obs1 Observables3 where
+	get1 (Observables3 x _ _) = x
+	{-# INLINE get1 #-}
+
+instance Obs1 Observables4 where
+	get1 (Observables4 x _ _ _) = x
+	{-# INLINE get1 #-}
+
+instance Obs1 Observables5 where
+	get1 (Observables5 x _ _ _ _) = x
+	{-# INLINE get1 #-}
+
+instance Obs2 Observables2 where
+	get2 (Observables2 _ x) = x
+	{-# INLINE get2 #-}
+
+instance Obs2 Observables3 where
+	get2 (Observables3 _ x _) = x
+	{-# INLINE get2 #-}
+
+instance Obs2 Observables4 where
+	get2 (Observables4 _ x _ _) = x
+	{-# INLINE get2 #-}
+
+instance Obs2 Observables5 where
+	get2 (Observables5 _ x _ _ _) = x
+	{-# INLINE get2 #-}
+
+instance Obs3 Observables3 where
+	get3 (Observables3 _ _ x) = x
+	{-# INLINE get3 #-}
+
+instance Obs3 Observables4 where
+	get3 (Observables4 _ _ x _) = x
+	{-# INLINE get3 #-}
+
+instance Obs3 Observables5 where
+	get3 (Observables5 _ _ x _ _) = x
+	{-# INLINE get3 #-}
+
+instance Obs4 Observables4 where
+	get4 (Observables4 _ _ _ x) = x
+	{-# INLINE get4 #-}
+
+instance Obs4 Observables5 where
+	get4 (Observables5 _ _ _ x _) = x
+	{-# INLINE get4 #-}
+
+instance Obs5 Observables5 where
+	get5 (Observables5 _ _ _ _ x) = x
+	{-# INLINE get5 #-}
+ src/Quant/VectorOps.hs view
@@ -0,0 +1,77 @@+
+module Quant.VectorOps (
+    (.*.)
+  , (.*)
+  , (*.)
+  , (./.)
+  , (/.)
+  , (./)
+  , (.+.)
+  , (.+)
+  , (+.)
+  , (.-.)
+  , (.-)
+  , (-.)
+  ) where
+
+import qualified Data.Vector.Unboxed as U
+
+infixl 7 .*.
+(.*.) :: (U.Unbox a, Num a) => U.Vector a -> U.Vector a -> U.Vector a
+x .*. y = U.zipWith (*) x y
+{-# INLINE (.*.) #-}
+
+infixl 7 *.
+(*.) :: (U.Unbox a, Num a) => a -> U.Vector a -> U.Vector a
+x *. y = U.map (x*) y
+{-# INLINE (*.) #-}
+
+infixl 7 .*
+(.*) :: (U.Unbox a, Num a) => U.Vector a -> a -> U.Vector a
+x .* y = U.map (*y) x
+{-# INLINE (.*) #-}
+
+infixl 7 ./.
+(./.) :: (U.Unbox a, Fractional a) => U.Vector a -> U.Vector a -> U.Vector a
+x ./. y = U.zipWith (/) x y
+{-# INLINE (./.) #-}
+
+infixl 7 /.
+(/.) :: (U.Unbox a, Fractional a) => a -> U.Vector a -> U.Vector a
+x /. y = U.map (x/) y
+{-# INLINE (/.) #-}
+
+infixl 7 ./
+(./) :: (U.Unbox a, Fractional a) => U.Vector a -> a -> U.Vector a
+x ./ y = U.map (/y) x
+{-# INLINE (./) #-}
+
+infixl 6 .+.
+(.+.) :: (U.Unbox a, Num a) => U.Vector a -> U.Vector a -> U.Vector a
+x .+. y = U.zipWith (+) x y
+{-# INLINE (.+.) #-}
+
+infixl 6 +.
+(+.) :: (U.Unbox a, Num a) => a -> U.Vector a -> U.Vector a
+x +. y = U.map (x+) y
+{-# INLINE (+.) #-}
+
+infixl 6 .+
+(.+) :: (U.Unbox a, Num a) => U.Vector a -> a -> U.Vector a
+x .+ y = U.map (+y) x
+{-# INLINE (.+) #-}
+
+infixl 6 .-.
+(.-.) :: (U.Unbox a, Num a) => U.Vector a -> U.Vector a -> U.Vector a
+x .-. y = U.zipWith (-) x y
+{-# INLINE (.-.) #-}
+
+infixl 6 -.
+(-.) :: (U.Unbox a, Num a) => a -> U.Vector a -> U.Vector a
+x -. y = U.map (x-) y
+{-# INLINE (-.) #-}
+
+infixl 6 .-
+(.-) :: (U.Unbox a, Num a) => U.Vector a -> a -> U.Vector a
+x .- y = U.map (+negate y) x
+{-# INLINE (.-) #-}
src/Quant/VolSurf.hs view
@@ -57,7 +57,7 @@                 solution = dwdt/(1.0-y/w*dwdy+0.25*(-0.25-1.0/w+y*y/w/w)*dwdy*dwdy+0.5*d2wdy2)
 
 -- |A flat surface has one volatility at all times/maturities.
-data FlatSurf = FlatSurf Double
+data FlatSurf = FlatSurf {-# UNPACK #-} !Double
 
 instance VolSurf FlatSurf where
     vol (FlatSurf x) _ _ = x
src/Quant/YieldCurve.hs view
@@ -27,13 +27,15 @@ 
 -- |A flat curve is just a flat curve with one continuously 
 -- compounded rate at all points on the curve.
-data FlatCurve = FlatCurve Double
+data FlatCurve = FlatCurve {-# UNPACK #-} !Double
 
 instance YieldCurve FlatCurve where
     disc (FlatCurve r) t = exp (-r*timeFromZero t)
+    {-# INLINE disc #-}
 
 -- | 'YieldCurve' that represents the difference between two 'YieldCurve's.
 data NetYC a = NetYC a a
 
 instance YieldCurve a => YieldCurve (NetYC a) where
-    disc (NetYC yc1 yc2) t = disc yc1 t / disc yc2 t+    disc (NetYC yc1 yc2) t = disc yc1 t / disc yc2 t
+    {-# INLINE disc #-}