packages feed

simfin-1.0.0: src/SimFin/Types/Prices.hs

{-|
Module      : SimFin.Types.Prices
Description : Types to represent SimFin price results.
Copyright   : (c) Owen Shepherd, 2022
License     : MIT
Maintainer  : owen@owen.cafe
-}

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}

module SimFin.Types.Prices
  ( PricesRow(..)
  , PricesKeyed(..)
  ) where

import Data.Aeson
import Data.Text (Text)
import Data.Time.Calendar (Day)

import SimFin.Types.StringFrac
import SimFin.Internal

-- | Prices of a company over a single day. 

data PricesRow a
  = PricesRow
  { simFinId :: Int
  , ticker :: Text
  , date :: Maybe Day
  , open :: a
  , high :: a
  , low :: a
  , close :: a
  , adjClose :: a
  , volume :: Integer
  , dividend :: Maybe a
  , commonSharesOutstanding :: Maybe Integer
  } deriving (Functor, Show)

instance (Read a, RealFrac a) => FromJSON (PricesRow a) where
  parseJSON = withObject "PricesRow" $ \v -> fmap (fmap unStringFrac) $ PricesRow
    <$> v .: "SimFinId"
    <*> v .: "Ticker"
    <*> v .: "Date"
    <*> v .: "Open"
    <*> v .: "High"
    <*> v .: "Low"
    <*> v .: "Close"
    <*> v .: "Adj. Close"
    <*> v .: "Volume"
    <*> v .: "Dividend"
    <*> v .: "Common Shares Outstanding"

-- | Wrapper to parse a PricesRow record from SimFin's JSON format.

newtype PricesKeyed a = PricesKeyed { unKeyPrices :: [PricesRow a] }

instance (Read a, RealFrac a) => FromJSON (PricesKeyed a) where
  parseJSON o = PricesKeyed <$> (traverse parseJSON =<< createKeyedRows o)