packages feed

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

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

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

module SimFin.Types.Derived
  ( DerivedRow(..)
  , DerivedRowsKeyed(..)
  ) where

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

import SimFin.Types.StringFrac
import SimFin.Types.FiscalPeriod
import SimFin.Internal

-- | Cash flow statement for general companies. 

data DerivedRow a
  = DerivedRow
  { simFinId :: Int
  , ticker :: Text
  , fiscalPeriod :: FiscalPeriod
  , fiscalYear :: Int
  , reportDate :: Day
  , publishDate :: Day
  , restatedDate :: Day
  , source :: Text
  , tTM :: Bool
  , valueCheck :: Bool
  , eBITDA :: Maybe a
  , totalDebt :: Maybe a
  , freeCashFlow :: Maybe a
  , grossProfitMargin :: Maybe a
  , operatingMargin :: Maybe a
  , netProfitMargin :: Maybe a
  , returnOnEquity :: Maybe a
  , returnOnAssets :: Maybe a
  , freeCashFlowToNetIncome :: Maybe a
  , currentRatio :: Maybe a
  , liabilitiesToEquityRatio :: Maybe a
  , debtRatio :: Maybe a
  , earningsPerShareBasic :: Maybe a
  , earningsPerShareDiluted :: Maybe a
  , salesPerShare :: Maybe a
  , equityPerShare :: Maybe a
  , freeCashFlowPerShare :: Maybe a
  , dividendsPerShare :: Maybe a
  , piotroskiFScore :: Maybe Int
  , returnOnInvestedCapital :: Maybe a
  , cashReturnOnInvestedCapital :: Maybe a
  , dividendPayoutRatio :: Maybe a
  , netDebtEBITDA :: Maybe a
  , netDebtEBIT :: Maybe a
  } deriving (Functor, Show)

instance (Read a, RealFrac a) => FromJSON (DerivedRow a) where
  parseJSON = withObject "DerivedRow" $ \v -> fmap (fmap unStringFrac) $ DerivedRow
    <$> v .: "SimFinId"
    <*> v .: "Ticker"
    <*> v .: "Fiscal Period"
    <*> v .: "Fiscal Year"
    <*> v .: "Report Date"
    <*> v .: "Publish Date"
    <*> v .: "Restated Date"
    <*> v .: "Source"
    <*> v .: "TTM"
    <*> v .: "Value Check"
    <*> v .: "EBITDA"
    <*> v .: "Total Debt"
    <*> v .: "Free Cash Flow"
    <*> v .: "Gross Profit Margin"
    <*> v .: "Operating Margin"
    <*> v .: "Net Profit Margin"
    <*> v .: "Return on Equity"
    <*> v .: "Return on Assets"
    <*> v .: "Free Cash Flow to Net Income"
    <*> v .: "Current Ratio"
    <*> v .: "Liabilities to Equity Ratio"
    <*> v .: "Debt Ratio"
    <*> v .: "Earnings Per Share, Basic"
    <*> v .: "Earnings Per Share, Diluted"
    <*> v .: "Sales Per Share"
    <*> v .: "Equity Per Share"
    <*> v .: "Free Cash Flow Per Share"
    <*> v .: "Dividends Per Share"
    <*> v .: "Piotroski F-Score"
    <*> v .: "Return On Invested Capital"
    <*> v .: "Cash Return On Invested Capital"
    <*> v .: "Dividend Payout Ratio"
    <*> v .: "Net Debt / EBITDA"
    <*> v .: "Net Debt / EBIT"

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

newtype DerivedRowsKeyed a = DerivedRowsKeyed { unDerivedRows :: [DerivedRow a] }

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