packages feed

HQu-0.0.0.0: src/Q/ContingentClaim.hs

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RankNTypes, ApplicativeDo #-}

module Q.ContingentClaim where

import Control.Monad.Reader
import Control.Monad.Writer.Strict
import Q.Types
import Data.Time
import qualified Data.Map as M

-- | A cash flow is a time and amount.
data CashFlow = CashFlow {
    cfTime :: LocalTime -- ^ The cash flow time.
  , cfAmount :: Double  -- ^ The cash flow amount.
} deriving (Show, Eq)

-- | Stop at time t and potentially apply n payouts up to the monitoring time.
data CCProcessor a = CCProcessor {
    monitorTime :: LocalTime                   -- ^ Stopping time.
  , payouts  :: [M.Map LocalTime a -> CashFlow] -- ^ list of payout functions at the stopping time.
}

-- | A claim contingent on some observable a.
newtype ContingentClaim a = ContingentClaim { unCC :: [CCProcessor a] }
-- ^ An example of an observable is a spot driven asset, such as a stock.

instance Monoid (ContingentClaim a) where
  mempty  = ContingentClaim []

-- | multipley a contingent claim by its notional.
multiplier :: Double -> ContingentClaim a -> ContingentClaim a
multiplier notional (ContingentClaim ccProcessors) = ContingentClaim $ map scale ccProcessors where
  scale CCProcessor{ .. } = CCProcessor monitorTime (map scaledPayout payouts)
  scaledPayout payout = fmap (\ (CashFlow t v) -> CashFlow t (notional * v)) payout

-- | Change direction of the portfolio
short :: ContingentClaim a -> ContingentClaim a
short = multiplier (-1)


instance Semigroup (ContingentClaim a) where
  c1 <> c2 = ContingentClaim $ combine (unCC c1) (unCC c2)
    where combine (cc1:ccs1) (cc2:ccs2)
            | monitorTime cc1 == monitorTime cc2 = let
                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 cs1 cs2 = cs1 ++ cs2

type CCBuilder w r a =  WriterT w (Reader r) a

-- | Monitor an observable at the given time t.
monitor :: LocalTime -> CCBuilder (ContingentClaim a) (M.Map LocalTime a) a
monitor t = do
  tell $ ContingentClaim [CCProcessor t []] -- This step maintains the monitoring times.
  m <- ask                                   -- This step gets the market data
  return $ m M.! t                          -- This step evaluate the market data at time t.

-- | Pay an amount at a given time
pay :: forall a. LocalTime -> CCBuilder (ContingentClaim a) (M.Map LocalTime a) CashFlow -> ContingentClaim a
pay t x = stoppingTimes <> ContingentClaim [CCProcessor t [payout]] where
  stoppingTimes = runReader (execWriterT x) M.empty
  payout = let r = fst <$> runWriterT x
           in runReader r