{-# LANGUAGE DefaultSignatures,RecordWildCards,DeriveGeneric
,LambdaCase,ScopedTypeVariables #-}
-- | Module      : Model
-- Description : Modeling the EURUSD prediction problem.
module Model (NewTick(..),X(..),Y(..),Prediction(..)) where
import Data.Default.Class
import GHC.Generics
import qualified Data.MessagePack.Types.Class as MTC
  (toObject, fromObject,MessagePack(..))
import Data.MessagePack.Types.Option (Option(..))

-- | Type for a new incoming tick
data NewTick = NewTick
  { newOpen    :: Double  -- Open of the current bar
  , lastClose  :: Double  -- Close of the previous bar
  , lastHigh   :: Double  -- High of the previous bar
  , lastLow    :: Double  -- Low of the previous bar
  , lastVolume :: Double  -- Volume of the previous bar
  } deriving Generic
-- | x^t
data X = X { lastpticks :: [NewTick] } deriving Generic --Learner input x^t
instance Default X           --We'll need this for automating model dimensionality

-- | y^t
data Y = Y { high :: Double } --Learner target y^t

-- | Prediction output: either 'Prediction' y^t, or 'Ingested', which
-- means the data point was aggregated, but no prediction was
-- produced.
data Prediction = Prediction
     { prediction :: Double } --Learner output \widehat{y^t}
   | Ingested  -- Sometimes, the aggregator takes the value but no
               -- prediction happens.

instance Show Prediction where
  show Ingested = "Ingested"
  show Prediction{..} = "Prediction " ++ show prediction
instance MTC.MessagePack Prediction where
  toObject = let (n::Option Double) = None
    in \case
      Ingested -> MTC.toObject n
      Prediction p -> MTC.toObject $ Some p
  fromObject t = MTC.fromObject t >>= \case
     Some t' -> return $ Prediction t'
     None -> return Ingested

instance MTC.MessagePack NewTick where
  toObject NewTick{..} =
    MTC.toObject (newOpen,lastClose,lastHigh,lastLow,lastVolume)
  fromObject t = do
    (newOpen,lastClose,lastHigh,lastLow,lastVolume) <- MTC.fromObject t
    return $ NewTick newOpen lastClose lastHigh lastLow lastVolume