iexcloud (empty) → 0.0.0.1
raw patch · 28 files changed
+1660/−0 lines, 28 filesdep +HUnitdep +aesondep +basesetup-changed
Dependencies added: HUnit, aeson, base, bytestring, containers, http-conduit, semigroups, stocks, unordered-containers
Files
- LICENSE +30/−0
- README.md +71/−0
- Setup.hs +2/−0
- Tests/Main.hs +124/−0
- iexcloud.cabal +49/−0
- src/Net/IEX/Book.hs +32/−0
- src/Net/IEX/Chart.hs +66/−0
- src/Net/IEX/Company.hs +30/−0
- src/Net/IEX/DelayedQuote.hs +20/−0
- src/Net/IEX/Dividend.hs +30/−0
- src/Net/IEX/Earnings.hs +39/−0
- src/Net/IEX/EffectiveSpread.hs +19/−0
- src/Net/IEX/Financials.hs +41/−0
- src/Net/IEX/IntraDayStats.hs +26/−0
- src/Net/IEX/Market.hs +22/−0
- src/Net/IEX/NewsItem.hs +19/−0
- src/Net/IEX/OHLC.hs +19/−0
- src/Net/IEX/Previous.hs +24/−0
- src/Net/IEX/PriceTime.hs +15/−0
- src/Net/IEX/Quote.hs +53/−0
- src/Net/IEX/RecentStats.hs +20/−0
- src/Net/IEX/RecordStats.hs +27/−0
- src/Net/IEX/Relevant.hs +15/−0
- src/Net/IEX/Split.hs +20/−0
- src/Net/IEX/Stats.hs +73/−0
- src/Net/IEX/TimeSeries.hs +25/−0
- src/Net/IEX/VolumeByVenue.hs +19/−0
- src/Net/Stocks.hs +730/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright David Bouchare, Kristian Sällberg (c) 2018++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,71 @@+# Haskell iexcloud client++# This project is based on the legacy iex API client [stocks](https://github.com/dabcoder/stocks)++[](https://travis-ci.org/dabcoder/stocks)++Haskell library for the IEX trading API.++Example:++```haskell+stack build && stack ghci++getQuote :: AuthAndSymbol -> IO (Maybe IEXQuote.Quote)+> getQuote ("pk_myAPItoken", "msft")++Just (Quote {symbol = "MSFT",+ companyName = "Microsoft Corp.",+ primaryExchange = Nothing,+ sector = Nothing,+ calculationPrice = "tops",+ open = 128.9,+ ...+ })++getCompany :: AuthAndSymbol -> IO (Maybe IEXCompany.Company)+> getCompany ("pk_myAPItoken", "aapl")++Just (Company {symbol = "AAPL",+ companyName = "Apple Inc.",+ exchange = "Nasdaq Global Select",+ industry = "Computer Hardware",+ website = "http://www.apple.com",+ description = "Apple Inc is designs ...",+ ceo = "Timothy D. Cook",+ issueType = "cs",+ sector = "Technology"})++getPrice :: AuthAndSymbol -> IO (Maybe Double)+> getPrice ("pk_myAPItoken", "msft")++Just 131.56+```++Please see the HUnit test for a complete example+of all API calls.++## How to run test suite+```+stack test+```++## Contribute++For any problems, comments, or feedback please create an+issue [here on GitHub](https://github.com/dabcoder/stocks/issues).++### Attribution+If you redistribute our API data:++* Cite IEX using the following text and link: “Data provided for free by [IEX](https://iextrading.com/developer).”+* Provide a link to https://iextrading.com/api-exhibit-a in your terms of service.++# Before uploading to hackage++* Make sure that all dependencies in 'iexcloud.cabal' are version bound. Also:++1. Hackage is intended to be a permanent record. Therefore uploads cannot be changed or removed.+2. Only upload things that work, are useful to other people, and that you intend to maintain.+3. Use `cabal gen-bounds` to put PVP-compliant version bounds (lower AND upper) on ALL your unique dependencies so your package will still be buildable years down the road. One important thing to note is that you only need to include version bounds once. For example, if you depend on the same package in your library and your test suite, you only need to put the version bounds for that dependency in one place. This keeps the dependency bounds information DRY.+4. Package candidates CAN be changed, so use them to test things out and get everything right before you publish permanently to the main index.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Tests/Main.hs view
@@ -0,0 +1,124 @@+module Main where++import Net.IEX.Previous+import Test.HUnit+import Net.Stocks++import qualified Data.ByteString.Lazy.Char8 as L8+import qualified Net.IEX.Stats as XS++main :: IO Counts+main = runTestTT tests++tests = TestList [TestLabel "" testChart,+ TestLabel "" testCompany,+ TestLabel "" testDelayedQuote,+ TestLabel "" testDelayedDividend,+ TestLabel "" testEarnings,+ TestLabel "" testEffectiveSpread,+ TestLabel "" testFinancials,+ TestLabel "" testStats,+ TestLabel "" testNewsItem,+ TestLabel "" testOHLC,+ TestLabel "" testPeers,+ TestLabel "" testPrevious,+ TestLabel "" testPrice,+ TestLabel "" testQuote,+ TestLabel "" testRelevant,+ TestLabel "" testSplit,+ TestLabel "" testVolumeByVenue,+ TestLabel "" testTypeQuery1,+ TestLabel "" testBatch,+ TestLabel "" testMultiBatch1,+ TestLabel "" testMultiBatch2,+ TestLabel "" testCorrectCompanyName,+ TestLabel "" testMarket,+ TestLabel "" testIntraDayStats,+ TestLabel "" testRecentStats,+ TestLabel "" testRecordStats,+ -- TestLabel "" testHistDailyStats+ TestLabel "" testBook,+ TestLabel "" testTS+ ]++testChart = TestCase (do result <- getChart "aapl"+ assertBool "desc" (result /= Nothing))+testCompany = TestCase (do result <- getCompany "aapl"+ assertBool "desc" (result /= Nothing))+testDelayedQuote = TestCase (do result <- getDelayedQuote "aapl"+ assertBool "desc" (result /= Nothing))+testDelayedDividend = TestCase (do result <- getDelayedDividend "aapl"+ assertBool "desc" (result /= Nothing))+testEarnings = TestCase (do result <- getEarnings "aapl"+ assertBool "desc" (result /= Nothing))+testEffectiveSpread = TestCase (do result <- getEffectiveSpread "aapl"+ assertBool "desc" (result /= Nothing))+testFinancials = TestCase (do result <- getFinancials "aapl"+ assertBool "desc" (result /= Nothing))+testStats = TestCase (do result <- getStats "aapl"+ assertBool "desc" (result /= Nothing))+testNewsItem = TestCase (do result <- getNewsItem "aapl"+ assertBool "desc" (result /= Nothing))+testOHLC = TestCase (do result <- getOHLC "aapl"+ assertBool "desc" (result /= Nothing))+testPeers = TestCase+ (do (Just result) <- getPeers "aapl"+ assertEqual "get the correct peers for AAPL" result+ (L8.pack "[\"MSFT\",\"NOK\",\"IBM\",\"HPQ\",\"GOOGL\",\"BB\",\"XLK\"]"))+testPrevious = TestCase (do result <- getPrevious "aapl"+ assertBool "desc" (result /= Nothing))+testPrice = TestCase (do result <- getPrice "aapl"+ assertBool "" (result /= Nothing))+testQuote = TestCase (do result <- getQuote "aapl"+ assertBool "desc" (result /= Nothing))+testRelevant = TestCase (do result <- getRelevant "aapl"+ assertBool "desc" (result /= Nothing))+testSplit = TestCase (do result <- getSplit "aapl"+ assertBool "desc" (result /= Nothing))+testVolumeByVenue = TestCase (do result <- getVolumeByVenue "aapl"+ assertBool "desc" (result /= Nothing))+testTypeQuery1 = TestCase (assertEqual "" "types=news,ohlc"+ (typeQuery [NewsQuery, OHLCQuery]))+testBatch = TestCase+ (do result <- getBatchCompany "aapl" [StatsQuery, NewsQuery, CompanyQuery]+ assertBool "" (result /= Nothing))++testMultiBatch1 = TestCase+ (do result <- getBatch ["fb"] [OHLCQuery]+ assertBool "" (result /= Nothing))++testMultiBatch2 = TestCase+ (do result <- getBatch ["dps", "fb"] [OHLCQuery, CompanyQuery]+ assertBool "" (result /= Nothing))++-- fail+testCorrectCompanyName = TestCase+ (do result <- getBatchCompany "aapl" [StatsQuery, NewsQuery, CompanyQuery]+ assertEqual "" (pickCompanyName result) "Apple Inc.")++pickCompanyName :: Maybe Batch -> String+pickCompanyName (Just (Batch {stats = st})) = pickCompanyName' st++pickCompanyName' :: Maybe XS.Stats -> String+pickCompanyName' (Just (XS.Stats {XS.companyName = cname})) = cname++testMarket = TestCase (do result <- getMarket+ assertBool "" (result /= Nothing))++testIntraDayStats = TestCase (do result <- getIntraDayStats+ assertBool "" (result /= Nothing))++testRecentStats = TestCase (do result <- getRecentStats+ assertBool "" (result /= Nothing))++testRecordStats = TestCase (do result <- getRecordStats+ assertBool "" (result /= Nothing))++testBook = TestCase (do result <- getBook "aapl"+ assertBool "" (result /= Nothing))++testTS = TestCase (do result <- getTS "aapl"+ assertBool "" (result /= Nothing))++-- testHistDailyStats = TestCase (do result <- getHistoricalDailyStats+-- assertBool "" (result /= Nothing))
+ iexcloud.cabal view
@@ -0,0 +1,49 @@+name: iexcloud+version: 0.0.0.1+synopsis: Library for the IEX Trading API+description: Simple library for interacting with the IEX Trading API+homepage: https://github.com/ksallberg/iexcloud+license: BSD3+license-file: LICENSE+author: David Bouchare, Kristian Sällberg+maintainer: David Bouchare, Kristian Sällberg+copyright: 2018-2019 David Bouchare, Kristian Sällberg+category: Net+build-type: Simple+cabal-version: >=1.10+extra-source-files: README.md++library+ exposed-modules: Net.Stocks, Net.IEX.Stats,+ Net.IEX.Chart, Net.IEX.Company,+ Net.IEX.Earnings, Net.IEX.DelayedQuote,+ Net.IEX.Dividend, Net.IEX.EffectiveSpread,+ Net.IEX.Financials, Net.IEX.NewsItem,+ Net.IEX.OHLC, Net.IEX.Previous,+ Net.IEX.PriceTime, Net.IEX.Quote,+ Net.IEX.Relevant, Net.IEX.Split,+ Net.IEX.VolumeByVenue, Net.IEX.Market,+ Net.IEX.IntraDayStats, Net.IEX.RecentStats,+ Net.IEX.RecordStats, Net.IEX.Book, Net.IEX.TimeSeries+ build-depends: base == 4.*+ , http-conduit == 2.2.4+ , aeson == 1.2.4.0+ , bytestring == 0.10.8.2+ , containers == 0.5.10.2+ , unordered-containers == 0.2.8.0+ , semigroups == 0.18.4+ hs-source-dirs: src+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/ksallberg/iexcloud.git++Test-Suite test-hspec+ type: exitcode-stdio-1.0+ main-is: Tests/Main.hs+ build-depends: base,+ stocks,+ bytestring,+ HUnit+ default-language: Haskell2010
+ src/Net/IEX/Book.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Book (Book(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics+import Net.IEX.Quote (Quote)++data Book = Book {+ quote :: Quote,+ bids :: Maybe [Trade], -- FIXME: not sure of this type+ asks :: Maybe [Trade], -- FIXME: not sure of this type+ trades :: Maybe [Trade]+} deriving (Generic, Show, Eq)++data Trade = Trade {+ price :: Double,+ size :: Integer,+ tradeId :: Integer,+ isISO :: Bool,+ isOddLot :: Bool,+ isOutsideRegularHours :: Bool,+ isSinglePriceCross :: Bool,+ isTradeThroughExempt :: Bool,+ timestamp :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON Book+instance ToJSON Trade+instance FromJSON Book+instance FromJSON Trade
+ src/Net/IEX/Chart.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Chart (Chart(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Chart = Chart {+ -- is only available on 1d chart.+ minute :: Maybe String,+ -- is only available on 1d chart. 15 minute delayed+ marketAverage :: Maybe Double,+ -- is only available on 1d chart. 15 minute delayed+ marketNotional :: Maybe Double,+ -- is only available on 1d chart. 15 minute delayed+ marketNumberOfTrades :: Maybe Double,+ -- is only available on 1d chart. 15 minute delayed+ marketHigh :: Maybe Double,+ -- is only available on 1d chart. 15 minute delayed+ marketLow :: Maybe Double,+ -- is only available on 1d chart. 15 minute delayed+ marketVolume :: Maybe Double,+ -- is only available on 1d chart. Percent change+ -- of each interval relative to first value. 15 minute delayed+ marketChangeOverTime :: Maybe Double,+ -- is only available on 1d chart.+ average :: Maybe Double,+ -- is only available on 1d chart.+ notional :: Maybe Double,+ -- is only available on 1d chart.+ numberOfTrades :: Maybe Double,+ -- is only available on 1d chart, and only when chartSimplify is true.+ -- The first element is the original number of points.+ -- Second element is how many remain after simplification.+ simplifyFactor :: Maybe [Integer],+ -- is available on all charts.+ high :: Double,+ -- is available on all charts.+ low :: Double,+ -- is available on all charts.+ volume :: Integer,+ -- is available on all charts. A variable formatted version of+ -- the date depending on the range. Optional convienience field.+ label :: String,+ -- is available on all charts. Percent change of each interval+ -- relative to first value. Useful for comparing multiple stocks.+ changeOverTime :: Double,+ -- is not available on 1d chart.+ date :: Maybe String,+ -- is not available on 1d chart.+ open :: Maybe Double,+ -- is not available on 1d chart.+ close :: Maybe Double,+ -- is not available on 1d chart.+ unadjustedVolume :: Maybe Integer,+ -- is not available on 1d chart.+ change :: Maybe Double,+ -- is not available on 1d chart.+ changePercent :: Maybe Double,+ -- is not available on 1d chart.+ vwap :: Maybe Double+} deriving (Generic, Show, Eq)++instance ToJSON Chart+instance FromJSON Chart
+ src/Net/IEX/Company.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Company (Company(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Company = Company {+ symbol :: String,+ companyName :: String,+ exchange :: String,+ industry :: String,+ website :: String,+ description :: String,+ ceo :: String,+ issueType :: String,+ sector :: String+} deriving (Generic, Show, Eq)++customOptionsCompany =+ defaultOptions {+ fieldLabelModifier = let f "ceo" = "CEO"+ f other = other+ in f+ }++instance ToJSON Company+instance FromJSON Company where+ parseJSON = genericParseJSON customOptionsCompany
+ src/Net/IEX/DelayedQuote.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.DelayedQuote (DelayedQuote(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data DelayedQuote = DelayedQuote {+ symbol :: String,+ delayedPrice :: Double,+ high :: Double,+ low :: Double,+ delayedSize :: Double,+ delayedPriceTime :: Integer,+ processedTime :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON DelayedQuote+instance FromJSON DelayedQuote
+ src/Net/IEX/Dividend.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Dividend (Dividend(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Dividend = Dividend {+ exDate :: String,+ paymentDate :: String,+ recordDate :: String,+ declaredDate :: String,+ amount :: Double,+ flag :: String,+ dtype :: String,+ qualified :: String,+ indicated :: String+} deriving (Generic, Show, Eq)++customOptionsDividend =+ defaultOptions {+ fieldLabelModifier = let f "dtype" = "type"+ f other = other+ in f+ }++instance ToJSON Dividend+instance FromJSON Dividend where+ parseJSON = genericParseJSON customOptionsDividend
+ src/Net/IEX/Earnings.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Earnings (Earning(..),+ Earnings(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Earning = Earning {+ actualEPS :: Double,+ consensusEPS :: Double,+ estimatedEPS :: Double,+ announceTime :: String,+ numberOfEstimates :: Integer,+ epsSurpriseDollar :: Double,+ epsReportDate :: String,+ fiscalPeriod :: String,+ fiscalEndDate :: String+} deriving (Generic, Show, Eq)++data Earnings = Earnings {+ symbol :: String,+ earnings :: [Earning]+} deriving (Generic, Show, Eq)++customOptionsEarning =+ defaultOptions {+ fieldLabelModifier = let f "epsSurpriseDollar" = "EPSSurpriseDollar"+ f "epsReportDate" = "EPSReportDate"+ f other = other+ in f+ }++instance ToJSON Earnings+instance ToJSON Earning+instance FromJSON Earnings+instance FromJSON Earning where+ parseJSON = genericParseJSON customOptionsEarning
+ src/Net/IEX/EffectiveSpread.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.EffectiveSpread (EffectiveSpread(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data EffectiveSpread = EffectiveSpread {+ volume :: Integer,+ venue :: String,+ venueName :: String,+ effectiveSpread :: Double,+ effectiveQuoted :: Double,+ priceImprovement :: Double+} deriving (Generic, Show, Eq)++instance ToJSON EffectiveSpread+instance FromJSON EffectiveSpread
+ src/Net/IEX/Financials.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Financials (Financials(..),+ Financial(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Financial = Financial {+ reportDate :: String,+ grossProfit :: Integer,+ costOfRevenue :: Integer,+ operatingRevenue :: Integer,+ totalRevenue :: Integer,+ operatingIncome :: Integer,+ netIncome :: Integer,+ researchAndDevelopment :: Integer,+ operatingExpense :: Integer,+ currentAssets :: Integer,+ totalAssets :: Integer,+ totalLiabilities :: Maybe Integer,+ currentCash :: Integer,+ currentDebt :: Integer,+ totalCash :: Integer,+ totalDebt :: Integer,+ shareholderEquity :: Integer,+ cashChange :: Integer,+ cashFlow :: Integer,+ operatingGainsLosses :: Maybe String+} deriving (Generic, Show, Eq)++data Financials = Financials {+ symbol :: String,+ financials :: [Financial]+} deriving (Generic, Show, Eq)++instance ToJSON Financial+instance ToJSON Financials+instance FromJSON Financial+instance FromJSON Financials
+ src/Net/IEX/IntraDayStats.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.IntraDayStats (IntraDayStats(..),+ IntraDaySub(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data IntraDayStats = IntraDayStats {+ volume :: IntraDaySub,+ symbolsTraded :: IntraDaySub,+ routedVolume :: IntraDaySub,+ notional :: IntraDaySub,+ marketShare :: IntraDaySub+} deriving (Generic, Show, Eq)++data IntraDaySub = IntraDaySub {+ value :: Maybe Double,+ lastUpdated :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON IntraDayStats+instance ToJSON IntraDaySub+instance FromJSON IntraDayStats+instance FromJSON IntraDaySub
+ src/Net/IEX/Market.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Market (Market(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Market = Market {+ mic :: String,+ tapeId :: String,+ venueName :: String,+ volume :: Integer,+ tapeA :: Integer,+ tapeB :: Integer,+ tapeC :: Integer,+ marketPercent :: Double,+ lastUpdated :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON Market+instance FromJSON Market
+ src/Net/IEX/NewsItem.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.NewsItem (NewsItem(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data NewsItem = NewsItem {+ datetime :: String,+ headline :: String,+ source :: String,+ url :: String,+ summary :: String,+ related :: String+} deriving (Generic, Show, Eq)++instance ToJSON NewsItem+instance FromJSON NewsItem
+ src/Net/IEX/OHLC.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.OHLC (OHLC(..)) where++import Net.IEX.PriceTime++import Data.Maybe+import Data.Aeson+import GHC.Generics++data OHLC = OHLC {+ open :: PriceTime,+ close :: PriceTime,+ high :: Double,+ low :: Double+} deriving (Generic, Show, Eq)++instance ToJSON OHLC+instance FromJSON OHLC
+ src/Net/IEX/Previous.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Previous (Previous(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Previous = Previous {+ symbol :: String,+ date :: String,+ open :: Double,+ high :: Double,+ low :: Double,+ close :: Double,+ volume :: Integer,+ unadjustedVolume :: Integer,+ change :: Double,+ changePercent :: Double,+ vwap :: Double+} deriving (Generic, Show, Eq)++instance ToJSON Previous+instance FromJSON Previous
+ src/Net/IEX/PriceTime.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.PriceTime (PriceTime(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data PriceTime = PriceTime {+ price :: Double,+ time :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON PriceTime+instance FromJSON PriceTime
+ src/Net/IEX/Quote.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Quote (Quote(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Quote = Quote {+ symbol :: String,+ companyName :: String,+ primaryExchange :: Maybe String,+ sector :: Maybe String,+ calculationPrice :: String,+ open :: Double,+ openTime :: Integer,+ close :: Double,+ closeTime :: Integer,+ high :: Double,+ low :: Double,+ latestPrice :: Double,+ latestSource :: String,+ latestTime :: String,+ latestUpdate :: Integer,+ latestVolume :: Integer,+ iexRealtimePrice :: Maybe Double,+ iexRealtimeSize :: Maybe Integer,+ iexLastUpdated :: Maybe Integer,+ delayedPrice :: Double,+ delayedPriceTime :: Integer,+ extendedPrice :: Double,+ extendedChange :: Double,+ extendedChangePercent :: Double,+ extendedPriceTime :: Integer,+ previousClose :: Double,+ change :: Double,+ changePercent :: Double,+ iexMarketPercent :: Maybe Double,+ iexVolume :: Maybe Integer,+ avgTotalVolume :: Integer,+ iexBidPrice :: Maybe Double,+ iexBidSize :: Maybe Integer,+ iexAskPrice :: Maybe Double,+ iexAskSize :: Maybe Integer,+ marketCap :: Integer,+ peRatio :: Double,+ week52High :: Double,+ week52Low :: Double,+ ytdChange :: Double+} deriving (Generic, Show, Eq)++instance ToJSON Quote+instance FromJSON Quote
+ src/Net/IEX/RecentStats.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.RecentStats (RecentStats(..)) where++import Data.Either+import Data.Maybe+import Data.Aeson+import GHC.Generics++data RecentStats = RecentStats {+ date :: String,+ volume :: Integer,+ routedVolume :: Integer,+ marketShare :: Double,+ isHalfday :: Bool,+ litVolume :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON RecentStats+instance FromJSON RecentStats
+ src/Net/IEX/RecordStats.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.RecordStats (RecordStats(..),+ RecordStatsSub(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data RecordStats = RecordStats {+ volume :: RecordStatsSub,+ symbolsTraded :: RecordStatsSub,+ routedVolume :: RecordStatsSub,+ notional :: RecordStatsSub+} deriving (Generic, Show, Eq)++data RecordStatsSub = RecordStatsSub {+ recordValue :: Double,+ recordDate :: String,+ previousDayValue :: Double,+ avg30Value :: Double+} deriving (Generic, Show, Eq)++instance ToJSON RecordStats+instance ToJSON RecordStatsSub+instance FromJSON RecordStats+instance FromJSON RecordStatsSub
+ src/Net/IEX/Relevant.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Relevant (Relevant(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Relevant = Relevant {+ peers :: Bool,+ symbols :: [String]+} deriving (Generic, Show, Eq)++instance ToJSON Relevant+instance FromJSON Relevant
+ src/Net/IEX/Split.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Split (Split(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Split = Split {+ exDate :: String,+ declaredDate :: String,+ recordDate :: String,+ paymentDate :: String,+ ratio :: Double,+ toFactor :: Integer,+ forFactor :: Integer+} deriving (Generic, Show, Eq)++instance ToJSON Split+instance FromJSON Split
+ src/Net/IEX/Stats.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.Stats (Stats (..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data Stats = Stats {+ companyName :: String,+ marketcap :: Integer,+ beta :: Double,+ week52high :: Double,+ week52low :: Double,+ week52change :: Double,+ shortInterest :: Integer,+ shortDate :: String,+ dividendRate :: Double,+ dividendYield :: Double,+ exDividendDate :: String,+ latestEPS :: Double,+ latestEPSDate :: String,+ sharesOutstanding :: Integer,+ float :: Integer,+ returnOnEquity :: Double,+ consensusEPS :: Double,+ numberOfEstimates :: Integer,+ epsSurpriseDollar :: Maybe Double,+ epsSurprisePercent :: Maybe Double,+ symbol :: String,+ ebitda :: Integer,+ revenue :: Integer,+ grossProfit :: Integer,+ cash :: Integer,+ debt :: Integer,+ ttmEPS :: Double,+ revenuePerShare :: Integer,+ revenuePerEmployee :: Integer,+ peRatioHigh :: Double,+ peRatioLow :: Double,+ returnOnAssets :: Double,+ returnOnCapital :: Maybe Double,+ profitMargin :: Double,+ priceToSales :: Double,+ priceToBook :: Double,+ day200MovingAvg :: Double,+ day50MovingAvg :: Double,+ institutionPercent :: Double,+ insiderPercent :: Maybe Double,+ shortRatio :: Maybe Double,+ year5ChangePercent :: Double,+ year2ChangePercent :: Double,+ year1ChangePercent :: Double,+ ytdChangePercent :: Double,+ month6ChangePercent :: Double,+ month3ChangePercent :: Double,+ month1ChangePercent :: Double,+ day5ChangePercent :: Double,+ day30ChangePercent :: Double+} deriving (Generic, Show, Eq)++customOptionsStats =+ defaultOptions {+ fieldLabelModifier = let f "epsSurpriseDollar" = "EPSSurpriseDollar"+ f "epsSurprisePercent" = "EPSSurprisePercent"+ f "ebitda" = "EBITDA"+ f other = other+ in f+ }++instance ToJSON Stats+instance FromJSON Stats where+ parseJSON = genericParseJSON customOptionsStats
+ src/Net/IEX/TimeSeries.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.TimeSeries (TimeSeries(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data TimeSeries = TimeSeries {+ date :: String,+ open :: Double,+ high :: Double,+ low :: Double,+ close :: Double,+ volume :: Integer,+ unadjustedVolume :: Integer,+ change :: Double,+ changePercent :: Double,+ vwap :: Double,+ label :: String,+ changeOverTime :: Double+} deriving (Generic, Show, Eq)++instance ToJSON TimeSeries+instance FromJSON TimeSeries
+ src/Net/IEX/VolumeByVenue.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveGeneric #-}++module Net.IEX.VolumeByVenue (VolumeByVenue(..)) where++import Data.Maybe+import Data.Aeson+import GHC.Generics++data VolumeByVenue = VolumeByVenue {+ volume :: Integer,+ venue :: String,+ venueName :: String,+ date :: Maybe String,+ marketPercent :: Double,+ avgMarketPercent :: Double+} deriving (Generic, Show, Eq)++instance ToJSON VolumeByVenue+instance FromJSON VolumeByVenue
+ src/Net/Stocks.hs view
@@ -0,0 +1,730 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TemplateHaskell #-}++module Net.Stocks+ (+ getChart,+ getChart5y,+ getChart2y,+ getChart1y,+ getChart6m,+ getChart3m,+ getChart1m,+ getCompany,+ getBook,+ getDelayedQuote,+ getDelayedDividend,+ getEarnings,+ getEffectiveSpread,+ getFinancials,+ getStats,+ getNewsItem,+ getOHLC,+ getPrevious,+ getPeers,+ getPrice,+ getQuote,+ getRelevant,+ getSplit,+ getVolumeByVenue,+ getTS,+ getBatch,+ getBatchCompany,+ getMarket,+ getIntraDayStats,+ getRecentStats,+ getRecordStats,+ getHistoricalStats,+ -- getHistoricalDailyStats,+ typeQuery,+ getChart',+ getChart5y',+ getChart2y',+ getChart1y',+ getChart6m',+ getChart3m',+ getChart1m',+ getCompany',+ getBook',+ getDelayedQuote',+ getDelayedDividend',+ getEarnings',+ getEffectiveSpread',+ getFinancials',+ getStats',+ getNewsItem',+ getOHLC',+ getPrevious',+ getPeers',+ getPrice',+ getQuote',+ getRelevant',+ getSplit',+ getVolumeByVenue',+ getTS',+ Batch (..),+ BatchQuery (..)+ ) where++import System.IO+import GHC.Generics+import Control.Exception+import Data.Aeson+import Data.Char+import Data.HashMap.Strict+import Data.Maybe+import Network.HTTP.Conduit++import qualified Data.ByteString.Lazy.Char8 as L8+import qualified Data.List as DL+import qualified Data.Map as DM++import qualified Net.IEX.Chart as IEXChart+import qualified Net.IEX.Company as IEXCompany+import qualified Net.IEX.Stats as IEXStats+import qualified Net.IEX.Earnings as IEXEarnings+import qualified Net.IEX.NewsItem as IEXNewsItem+import qualified Net.IEX.DelayedQuote as IEXDelayedQuote+import qualified Net.IEX.Dividend as IEXDividend+import qualified Net.IEX.EffectiveSpread as IEXEffectiveSpread+import qualified Net.IEX.Financials as IEXFinancials+import qualified Net.IEX.OHLC as IEXOHLC+import qualified Net.IEX.PriceTime as IEXPriceTime+import qualified Net.IEX.Previous as IEXPrevious+import qualified Net.IEX.Quote as IEXQuote+import qualified Net.IEX.Split as IEXSplit+import qualified Net.IEX.VolumeByVenue as IEXVolumeByVenue+import qualified Net.IEX.Relevant as IEXRelevant+import qualified Net.IEX.Market as IEXMarket+import qualified Net.IEX.IntraDayStats as IEXIntraDayStats+import qualified Net.IEX.RecentStats as IEXRecentStats+import qualified Net.IEX.RecordStats as IEXRecordStats+import qualified Net.IEX.Book as IEXBook+import qualified Net.IEX.TimeSeries as IEXTimeSeries++type Symbol = String+type AuthAndSymbol = (String, Symbol)++data BatchQuery = NewsQuery |+ ChartQuery |+ CompanyQuery |+ DelayedQuoteQuery |+ DividendQuery |+ EarningsQuery |+ EffectiveSpreadQuery |+ FinancialsQuery |+ StatsQuery |+ OHLCQuery |+ PriceTimeQuery |+ PreviousQuery |+ QuoteQuery |+ SplitQuery |+ VolumeByVenueQuery++batchQueryToStr :: BatchQuery -> String+batchQueryToStr NewsQuery = "news"+batchQueryToStr ChartQuery = "chart"+batchQueryToStr CompanyQuery = "company"+batchQueryToStr DelayedQuoteQuery = "delayedquote"+batchQueryToStr DividendQuery = "dividends"+batchQueryToStr EarningsQuery = "earnings"+batchQueryToStr EffectiveSpreadQuery = "effectivespread"+batchQueryToStr FinancialsQuery = "financials"+batchQueryToStr StatsQuery = "stats"+batchQueryToStr OHLCQuery = "ohlc"+batchQueryToStr PriceTimeQuery = "price"+batchQueryToStr QuoteQuery = "quote"+batchQueryToStr SplitQuery = "split"+batchQueryToStr VolumeByVenueQuery = "volumebyvenue"++data Batch = Batch {+ news :: Maybe [IEXNewsItem.NewsItem],+ chart :: Maybe [IEXChart.Chart],+ company :: Maybe IEXCompany.Company,+ delayedQuote :: Maybe IEXDelayedQuote.DelayedQuote,+ dividend :: Maybe [IEXDividend.Dividend],+ earnings :: Maybe IEXEarnings.Earnings,+ effectiveSpread :: Maybe [IEXEffectiveSpread.EffectiveSpread],+ financials :: Maybe IEXFinancials.Financials,+ stats :: Maybe IEXStats.Stats,+ ohlc :: Maybe IEXOHLC.OHLC,+ priceTime :: Maybe Integer,+ previous :: Maybe IEXPrevious.Previous,+ quote :: Maybe IEXQuote.Quote,+ split :: Maybe [IEXSplit.Split],+ volumeByVenue :: Maybe [IEXVolumeByVenue.VolumeByVenue]+} deriving (Generic, Show, Eq)++-- ToJSON means taking a haskell data structure and making a JSON string+instance ToJSON Batch++-- FromJSON means parsing the text into a haskell data structure+instance FromJSON Batch++baseURL :: String+baseURL = "https://cloud.iexapis.com/stable/stock/"++sandboxURL :: String+sandboxURL = "https://sandbox.iexapis.com/stable/stock/"++marketURL :: String+marketURL = "https://api.iextrading.com/1.0/market"++intraDayURL :: String+intraDayURL = "https://api.iextrading.com/1.0/stats/intraday"++statsURL :: String+statsURL = "https://api.iextrading.com/1.0/stats/"++lowerString :: Symbol -> String+lowerString = DL.map toLower++tokenize :: String -> String+tokenize auth = "?token=" ++ auth++getChart :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart5y :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart5y (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart/5y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart2y :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart2y (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart/2y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart1y :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart1y (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart/1y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart6m :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart6m (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart/6m" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart3m :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart3m (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart/3m" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart1m :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart1m (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/chart/1m" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getCompany :: AuthAndSymbol -> IO (Maybe IEXCompany.Company)+getCompany (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/company" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getBook :: AuthAndSymbol -> IO (Maybe IEXBook.Book)+getBook (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/book" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getDelayedQuote :: AuthAndSymbol -> IO (Maybe IEXDelayedQuote.DelayedQuote)+getDelayedQuote (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/delayed-quote" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getDelayedDividend :: AuthAndSymbol -> IO (Maybe [IEXDividend.Dividend])+getDelayedDividend (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/dividends/5y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getEarnings :: AuthAndSymbol -> IO (Maybe IEXEarnings.Earnings)+getEarnings (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/earnings" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getEffectiveSpread :: AuthAndSymbol -> IO (Maybe [IEXEffectiveSpread.EffectiveSpread])+getEffectiveSpread (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/effective-spread" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getFinancials :: AuthAndSymbol -> IO (Maybe IEXFinancials.Financials)+getFinancials (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/financials" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getStats :: AuthAndSymbol -> IO (Maybe IEXStats.Stats)+getStats (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/stats" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getNewsItem :: AuthAndSymbol -> IO (Maybe [IEXNewsItem.NewsItem])+getNewsItem (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/news/last/1" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getOHLC :: AuthAndSymbol -> IO (Maybe IEXOHLC.OHLC)+getOHLC (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/ohlc" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getPeers :: AuthAndSymbol -> IO (Maybe L8.ByteString)+getPeers (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/peers" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ Just bytestr++getPrevious :: AuthAndSymbol -> IO (Maybe IEXPrevious.Previous)+getPrevious (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/previous" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++-- FIXME: do not json parse an int+getPrice :: AuthAndSymbol -> IO (Maybe Double)+getPrice (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/price" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getQuote :: AuthAndSymbol -> IO (Maybe IEXQuote.Quote)+getQuote (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/quote" ++ tokenize auth)+ case obj of+ Left _ -> do+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getRelevant :: AuthAndSymbol -> IO (Maybe IEXRelevant.Relevant)+getRelevant (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/relevant" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getSplit :: AuthAndSymbol -> IO (Maybe [IEXSplit.Split])+getSplit (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/splits/5y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getVolumeByVenue :: AuthAndSymbol -> IO (Maybe [IEXVolumeByVenue.VolumeByVenue])+getVolumeByVenue (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/volume-by-venue" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getTS :: AuthAndSymbol -> IO (Maybe [IEXTimeSeries.TimeSeries])+getTS (auth, symb) = do+ obj <- getNonJSONData (baseURL ++ lowerString symb ++ "/time-series" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++-- get a list of parts we want in a batch request, and translate that+-- to HTTP parameters to provide to the API call+typeQuery :: [BatchQuery] -> String+typeQuery [] = ""+typeQuery inp =+ "types=" ++ (concat $ DL.intersperse "," (fmap batchQueryToStr inp))++symbolQuery :: [Symbol] -> String+symbolQuery [] = ""+symbolQuery inp = "symbols=" ++ (concat $ DL.intersperse "," inp)++questionMark :: [BatchQuery] -> String+questionMark [] = ""+questionMark _ = "?"++getBatch :: [Symbol] -> [BatchQuery] -> IO (Maybe (DM.Map String Batch))+getBatch symbs queryParams =+ let urlPt = baseURL ++ "market/batch?"+ fullQuery = urlPt ++ symbolQuery symbs ++ "&" ++ typeQuery queryParams+ in do+ obj <- getNonJSONData fullQuery+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++-- batch query of a *single* company+getBatchCompany :: Symbol -> [BatchQuery] -> IO (Maybe Batch)+getBatchCompany symb queryParams =+ let urlPt = (baseURL ++ lowerString symb ++ "/batch/")+ fullQuery = urlPt ++ (questionMark queryParams) ++ (typeQuery queryParams)+ in do+ obj <- getNonJSONData fullQuery+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getMarket :: IO (Maybe [IEXMarket.Market])+getMarket = do+ obj <- getNonJSONData marketURL+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getIntraDayStats :: IO (Maybe IEXIntraDayStats.IntraDayStats)+getIntraDayStats = do+ obj <- getNonJSONData intraDayURL+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getRecentStats :: IO (Maybe [IEXRecentStats.RecentStats])+getRecentStats = do+ obj <- getNonJSONData (statsURL ++ "recent")+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getRecordStats :: IO (Maybe IEXRecordStats.RecordStats)+getRecordStats = do+ obj <- getNonJSONData (statsURL ++ "records")+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getHistoricalStats :: IO (Maybe [IEXRecentStats.RecentStats])+getHistoricalStats = undefined++-- currently does not work due to inconsitency in+-- IEX API. isHalfDay is Bool in one API call and Int in another++-- getHistoricalDailyStats :: IO (Maybe [IEXRecentStats.RecentStats])+-- getHistoricalDailyStats = do+-- obj <- getNonJSONData (statsURL ++ "historical/daily")+-- return $ decode obj++getNonJSONData :: String -> IO (Either SomeException L8.ByteString)+getNonJSONData query = do+ putStrLn query+ try $ simpleHttp query++-- | Functions to work with the sandbox+--+getChart' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart5y' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart5y' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart/5y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart2y' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart2y' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart/2y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart1y' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart1y' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart/1y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart6m' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart6m' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart/6m" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart3m' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart3m' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart/3m" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getChart1m' :: AuthAndSymbol -> IO (Maybe [IEXChart.Chart])+getChart1m' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/chart/1m" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right str ->+ return $ decode str++getCompany' :: AuthAndSymbol -> IO (Maybe IEXCompany.Company)+getCompany' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/company" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getBook' :: AuthAndSymbol -> IO (Maybe IEXBook.Book)+getBook' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/book" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getDelayedQuote' :: AuthAndSymbol -> IO (Maybe IEXDelayedQuote.DelayedQuote)+getDelayedQuote' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/delayed-quote" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getDelayedDividend' :: AuthAndSymbol -> IO (Maybe [IEXDividend.Dividend])+getDelayedDividend' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/dividends/5y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getEarnings' :: AuthAndSymbol -> IO (Maybe IEXEarnings.Earnings)+getEarnings' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/earnings" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getEffectiveSpread' :: AuthAndSymbol -> IO (Maybe [IEXEffectiveSpread.EffectiveSpread])+getEffectiveSpread' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/effective-spread" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getFinancials' :: AuthAndSymbol -> IO (Maybe IEXFinancials.Financials)+getFinancials' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/financials" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getStats' :: AuthAndSymbol -> IO (Maybe IEXStats.Stats)+getStats' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/stats" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getNewsItem' :: AuthAndSymbol -> IO (Maybe [IEXNewsItem.NewsItem])+getNewsItem' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/news/last/1" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getOHLC' :: AuthAndSymbol -> IO (Maybe IEXOHLC.OHLC)+getOHLC' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/ohlc" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getPeers' :: AuthAndSymbol -> IO (Maybe L8.ByteString)+getPeers' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/peers" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ Just bytestr++getPrevious' :: AuthAndSymbol -> IO (Maybe IEXPrevious.Previous)+getPrevious' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/previous" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++-- FIXME: do not json parse an int+getPrice' :: AuthAndSymbol -> IO (Maybe Double)+getPrice' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/price" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getQuote' :: AuthAndSymbol -> IO (Maybe IEXQuote.Quote)+getQuote' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/quote" ++ tokenize auth)+ case obj of+ Left _ -> do+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getRelevant' :: AuthAndSymbol -> IO (Maybe IEXRelevant.Relevant)+getRelevant' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/relevant" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getSplit' :: AuthAndSymbol -> IO (Maybe [IEXSplit.Split])+getSplit' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/splits/5y" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getVolumeByVenue' :: AuthAndSymbol -> IO (Maybe [IEXVolumeByVenue.VolumeByVenue])+getVolumeByVenue' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/volume-by-venue" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr++getTS' :: AuthAndSymbol -> IO (Maybe [IEXTimeSeries.TimeSeries])+getTS' (auth, symb) = do+ obj <- getNonJSONData (sandboxURL ++ lowerString symb ++ "/time-series" ++ tokenize auth)+ case obj of+ Left _ ->+ return Nothing+ Right bytestr ->+ return $ decode bytestr