bet 0.1.2.2 → 0.1.2.3
raw patch · 4 files changed
+377/−148 lines, 4 filesdep +binarydep +http-clientdep −pipesdep −pipes-httpdep ~semigroupoidsdep ~time
Dependencies added: binary, http-client
Dependencies removed: pipes, pipes-http
Dependency ranges changed: semigroupoids, time
Files
- bet.cabal +5/−5
- src/Data/Bet.hs +17/−4
- src/Network/Betfair.hs +50/−37
- src/Network/Betfair/Types.hs +305/−102
bet.cabal view
@@ -1,5 +1,5 @@ name: bet-version: 0.1.2.2+version: 0.1.2.3 synopsis: Betfair API bindings. Bet on sports on betting exchanges. description: This library contains Haskell bindings to the Betfair API.@@ -53,19 +53,19 @@ build-depends: aeson >=0.8.0.2 && <1.0 ,base >=4.7 && <5.0 ,bifunctors >=4.2 && <5.0+ ,binary >=0.7.1 && <1.0 ,bytestring >=0.10 && <1.0 ,containers >=0.5 && <1.0 ,exceptions >=0.6 && <1.0 ,HsOpenSSL >=0.11 && <1.0+ ,http-client >=0.4.16 && <1.0 ,http-client-openssl >=0.2 && <1.0 ,lens >=4.6 && <5.0 ,mtl >=2.1 && <3.0- ,pipes >=4.1.3 && <5.0- ,pipes-http >=1.0.1 && <2.0 ,semigroups >=0.15.4 && <1.0- ,semigroupoids >=4.2 && <5.0+ ,semigroupoids >=4.2 && <6.0 ,text >=1.2 && <2.0- ,time >=1.4 && <1.5+ ,time >=1.4 && <2.0 ghc-options: -Wall hs-source-dirs: src default-language: Haskell2010
src/Data/Bet.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE GADTs #-}@@ -46,19 +47,23 @@ import Control.Lens import Data.Aeson import Data.Bifoldable+import Data.Binary ( Binary ) import Data.Bitraversable+import Data.Data import Data.Foldable import Data.Semigroup import Data.Semigroup.Foldable import Data.Semigroup.Bifoldable import Data.Traversable-import Data.Typeable+import GHC.Generics -- | A bet type. In a betting exchange, you usually can choose if you want to -- make a back or lay bet. With traditional bookmakers, you usually only back. data BetType = Back | Lay- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary BetType+ -- | An `Iso` from `BetType` to `Bool`. betBool :: Iso' BetType Bool betBool = iso (\case@@ -96,8 +101,12 @@ , Read , Show , Ord- , Eq )+ , Eq+ , Data+ , Generic ) +instance (Binary a, Binary b) => Binary (Bet a b)+ instance Foldable1 (Bet odds) instance Bifoldable1 Bet @@ -122,7 +131,11 @@ , Read , Show , Ord- , Eq )+ , Eq+ , Data+ , Generic )++instance (Binary a, Binary b) => Binary (BetFlipped a b) instance Functor (BetFlipped money) where fmap f (getFlipped -> Bet t o m) = BetFlipped $ Bet t (f o) m
src/Network/Betfair.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE LambdaCase #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-}@@ -80,23 +81,22 @@ import Control.Monad.Catch import Control.Monad.State.Strict import Data.Aeson-import Data.ByteString ( ByteString )+import Data.Binary hiding ( get, put, encode, decode )+import qualified Data.Binary as B import qualified Data.ByteString as B-import qualified Data.ByteString.Builder as BL import qualified Data.ByteString.Lazy as BL-import Data.IORef+import Data.Data import Data.Monoid-import Data.Proxy import Data.Text ( Text ) import qualified Data.Text as T import qualified Data.Text.Encoding as T-import Data.Typeable+import GHC.Generics import Network.Betfair.Internal import Network.Betfair.Types+import Network.HTTP.Client hiding ( Proxy, Request )+import qualified Network.HTTP.Client as PH import Network.HTTP.Client.OpenSSL import OpenSSL.Session-import Pipes hiding ( Proxy )-import Pipes.HTTP as PH hiding ( Proxy ) import System.Mem.Weak -- | Login credentials.@@ -106,9 +106,23 @@ , _certificatePrivateKeyFile :: FilePath , _certificateCertificateFile :: FilePath , _apiKey :: Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) makeClassy ''Credentials +instance Binary Credentials where+ put (Credentials{..}) = do+ B.put (T.unpack _username)+ B.put (T.unpack _password)+ B.put _certificatePrivateKeyFile+ B.put _certificateCertificateFile+ B.put (T.unpack _apiKey)+ get = Credentials <$>+ (T.pack <$> B.get) <*>+ (T.pack <$> B.get) <*>+ B.get <*>+ B.get <*>+ (T.pack <$> B.get)+ data Work = Work !Url !JsonRPCQuery !(MVar (Either SomeException BL.ByteString)) deriving ( Eq, Typeable ) @@ -120,6 +134,7 @@ -- The type of all JSON-based queries received newtype JsonRPC a = JsonRPC (Either APIException a)+ deriving ( Eq, Show, Typeable ) data BetfairHandle = BetfairHandle { _betfairThread :: !ThreadId@@ -188,16 +203,17 @@ Nothing -> throwM BetfairIsClosed Just bhandle -> action bhandle -work :: (FromJSON a) => Betfair -> Url -> JsonRPCQuery -> IO a+work :: forall a. (FromJSON a) => Betfair -> Url -> JsonRPCQuery -> IO a work bf url query = withBetfair bf $ \handle -> do result <- newEmptyMVar putMVar (_workChannel handle) $ Work url query result takeMVar result >>= \case Left exc -> throwM exc- Right result -> case decode result of- Nothing -> throwM $ ParsingFailure $ "Betfair behaved in unexpected way. Received raw string: " <> (T.pack $ show result)- Just (JsonRPC (Left exc)) -> throwM exc- Just (JsonRPC (Right x)) -> return x+ Right result -> case eitherDecode result of+ Left err ->+ throwM $ ParsingFailure $ "Betfair behaved in unexpected way. Error: " <> T.pack err <> " Received raw string: " <> (T.pack $ show result)+ Right (JsonRPC (Left exc)) -> throwM exc+ Right (JsonRPC (Right x)) -> return x betfairConnection :: Credentials -> MVar (Either SomeException ())@@ -226,6 +242,22 @@ finally (restore $ workLoop session_key credentials m work_mvar) (killThread keep_alive_tid) +withResponseBody :: PH.Request -> Manager -> (B.ByteString -> IO a) -> IO a+withResponseBody request m action =+ withResponse request m $ \body_reader -> do+ let body = responseBody body_reader+ bs <- readUpToNBytes 50000000 body+ action bs+ where+ readUpToNBytes bytes body = recursive bytes body mempty+ where+ recursive 0 _ result = return result+ recursive n requestor result = do+ bs <- body+ if B.null bs+ then return result+ else recursive (n - B.length bs) requestor (result <> bs)+ workLoop :: SessionKey -> Credentials -> Manager -> MVar Work -> IO () workLoop session_key credentials m work_mvar = forever $ do work <- takeMVar work_mvar@@ -238,9 +270,8 @@ -- second or we incur Betfair charges request <- betfairRequest session_key credentials sending url- withHTTP request m $ \response -> do- body <- readBodyLimited 50000000 response- putMVar result_mvar (Right body)+ withResponseBody request m $ \body ->+ putMVar result_mvar (Right $ BL.fromStrict body) betfairRequest :: SessionKey -> Credentials@@ -263,12 +294,11 @@ [ ("Accept", "application/json") , ("X-Application", T.encodeUtf8 _apiKey) , ("X-Authentication", T.encodeUtf8 session_key) ] }- withHTTP req m $ \response -> do+ withResponseBody req m $ \_ -> -- maybe it works, maybe it does not? I'm not sure what would be the -- sensible thing to do if keep-alive request fails. User probably -- still can continue to use the API as long as the session key is -- valid (which it will be for 12 hours).- _ <- readBodyLimited 100000 response return () obtainSessionKey :: Credentials@@ -281,29 +311,12 @@ ,("password", T.encodeUtf8 _password)] $ req' { requestHeaders = requestHeaders req' <> [ ("X-Application", T.encodeUtf8 _apiKey) ] }- withHTTP req m $ \response -> do- b <- readBodyLimited 1000000 response- case decode b of+ withResponseBody req m $ \b ->+ case decode $ BL.fromStrict b of Nothing -> throwM $ ParsingFailure "session key" Just login_response -> case login_response of LoginFailed reason -> throwM $ LoginFailure reason LoginSuccessful session_key -> return session_key--readBodyLimited :: Int- -> Response (Producer ByteString IO ())- -> IO BL.ByteString-readBodyLimited max_bytes response = do- accumRef <- newIORef mempty- runEffect $ responseBody response >-> accumulator accumRef 0- BL.toLazyByteString <$> readIORef accumRef- where- accumulator accumRef builder_length = do- block <- await- accum <- liftIO $ readIORef accumRef- when (B.length block + builder_length > max_bytes) $- liftIO $ throwM TooMuchHTTPData- liftIO $ writeIORef accumRef (accum <> BL.byteString block)- accumulator accumRef (builder_length + B.length block) -- | The type of exceptions that can happen with Betfair. data BetfairException
src/Network/Betfair/Types.hs view
@@ -5,7 +5,9 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE QuasiQuotes #-} -- | This module defines most data types in the betting API of Betfair API,@@ -45,16 +47,20 @@ module Network.Betfair.Types where +import Control.Applicative import Control.Monad.Catch import Control.Lens import Data.Aeson import Data.Aeson.TH import Data.Bet+import Data.Binary ( Binary, get, put )+import Data.Data import Data.Text ( Text )+import qualified Data.Text.Encoding as T import Data.Time-import Data.Typeable import qualified Data.Set as S import qualified Data.Map.Lazy as M+import GHC.Generics import Network.Betfair.Internal import Network.Betfair.Types.TH import Prelude hiding ( filter, id )@@ -66,15 +72,19 @@ | ASomeBetsNotCancelled | ACancellationRequestError | ACancellationStatusUnknown- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary ActionPerformed+ data BetStatus = Settled | Voided | Lapsed | Cancelled- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary BetStatus+ data ExecutionReportErrorCode = RErrorInMatcher | RProcessedWithErrors@@ -93,23 +103,29 @@ | RNoActionRequired | RServiceUnavailable | RRejectedByRegulator- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary ExecutionReportErrorCode+ data ExecutionReportStatus = ESuccess | EFailure | EProcessedWithErrors | ETimeout- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary ExecutionReportStatus+ data GroupBy = GBEventType | GBEvent | GBMarket | GBSide | GBBet- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary GroupBy+ data InstructionReportErrorCode = InvalidBetSize | InvalidRunner@@ -131,14 +147,18 @@ | CancelledNotPlaced | RelatedActionFailed | NoActionRequired- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary InstructionReportErrorCode+ data InstructionReportStatus = Success | Failure | Timeout- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary InstructionReportStatus+ data MarketBettingType = Odds | Line@@ -146,8 +166,10 @@ | AsianHandicapDoubleLine | AsianHandicapSingleLine | FixedOdds- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary MarketBettingType+ data MarketProjection = Competition | Event@@ -156,8 +178,10 @@ | MarketDescription | RunnerDescription | RunnerMetadata- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary MarketProjection+ data MarketSort = MinimumTraded | MaximumTraded@@ -165,21 +189,27 @@ | MaximumAvailable | FirstToStart | LastToStart- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary MarketSort+ data MarketStatus = Inactive | Open | Suspended | Closed- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary MarketStatus+ data MatchProjection = NoRollup | RolledUpByPrice | RolledUpByAvgPrice- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary MatchProjection+ data OrderBy = ByBet | ByMarket@@ -187,46 +217,60 @@ | ByPlaceTime | BySettledTime | ByVoidTime- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary OrderBy+ data OrderProjection = OpAll | OpExecutable | OpExecutionComplete- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary OrderProjection+ data OrderStatus = ExecutionComplete | Executable- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary OrderStatus+ data OrderType = Limit | LimitOnClose | MarketOnClose- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary OrderType+ data PersistenceType = PtLapse | PtPersist | PtMarketOnClose- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary PersistenceType+ data PriceData = SpAvailable | SpTraded | ExBestOffers | ExAllOffers | ExTraded- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary PriceData+ data RollupModel = Stake | Payout | ManagedLiability | None- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary RollupModel+ data RunnerStatus = Active | Winner@@ -234,59 +278,86 @@ | RemovedVacant | Removed | Hidden- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary RunnerStatus+ type Side = BetType data SortDir = EarliestToLatest | LatestToEarliest- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary SortDir+ data TimeGranularity = Days | Hours | Minutes- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) +instance Binary TimeGranularity newtype BetId = BetId { getBetId :: Text }- deriving ( Eq, Ord, Show, Read, Typeable, FromJSON, ToJSON )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic, FromJSON, ToJSON ) newtype Country = Country { getCountry :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) +instance Binary Country where+ put (Country txt) = put $ WrappedText txt+ get = Country . unwrapText <$> get+ newtype CompetitionId = CompetitionId { getCompetitionId :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) +instance Binary CompetitionId where+ put (CompetitionId txt) = put $ WrappedText txt+ get = CompetitionId . unwrapText <$> get+ newtype EventId = EventId { getEventId :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) +instance Binary EventId where+ put (EventId txt) = put $ WrappedText txt+ get = EventId . unwrapText <$> get+ newtype EventTypeId = EventTypeId { getEventTypeId :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) +instance Binary EventTypeId where+ put (EventTypeId txt) = put $ WrappedText txt+ get = EventTypeId . unwrapText <$> get+ newtype MarketId = MarketId { getMarketId :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) +instance Binary MarketId where+ put (MarketId mid) = put $ T.encodeUtf8 mid+ get = MarketId . T.decodeUtf8 <$> get+ newtype MarketTypeCode = MarketTypeCode { getMarketTypeCode :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) newtype MatchId = MatchId { getMatchId :: Text }- deriving ( Eq, Ord, Show, Read, Typeable, FromJSON, ToJSON )+ deriving ( Eq, Ord, Show, Read, Typeable, FromJSON, ToJSON, Data, Generic ) newtype SelectionId = SelectionId { getSelectionId :: Int } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) +instance Binary SelectionId+ newtype Venue = Venue { getVenue :: Text } deriving ( Eq, Ord, Show, Read, Typeable- , FromJSON, ToJSON )+ , FromJSON, ToJSON, Data, Generic ) data CancelExecutionReport = CancelExecutionReportC { ceCustomerRef :: Maybe Text@@ -294,12 +365,12 @@ , ceErrorCode :: Maybe ExecutionReportErrorCode , ceMarketId :: Maybe MarketId , ceInstructionReports :: [CancelInstructionReport] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data CancelInstruction = CancelInstructionC { ciBetId :: BetId , ciSizeReduction :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data CancelInstructionReport = CancelInstructionReportC { ciStatus :: InstructionReportStatus@@ -307,13 +378,13 @@ , ciInstruction :: Maybe CancelInstruction , ciSizeCancelled :: Double , ciCancelledDate :: Maybe UTCTime }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data CancelOrders = CancelOrdersC { caMarketId :: Maybe MarketId , caInstructions :: Maybe [CancelInstruction] , caCustomerRef :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ClearedOrderSummary = ClearedOrderSummaryC { coEventTypeId :: EventTypeId@@ -336,28 +407,36 @@ , coSizeSettled :: Maybe Double , coProfit :: Double , coSizeCancelled :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data Competition = CompetitionC { cId :: CompetitionId , cName :: Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary Competition where+ put (CompetitionC{..}) = do+ put cId+ put (WrappedText cName)+ get = CompetitionC <$>+ get <*>+ (unwrapText <$> get)+ data CompetitionResult = CompetitionResultC { cCompetition :: Competition , cMarketCount :: Int , cCompetitionRegion :: Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data CountryCodeResult = CountryCodeResultC { ccCountryCode :: Text , ccMarketCount :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ClearedOrderSummaryReport = ClearedOrderSummaryReportC { coClearedOrders :: [ClearedOrderSummary] , coMoreAvailable :: Bool }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data CurrentOrderSummary = CurrentOrderSummaryC { cBetId :: BetId@@ -380,12 +459,12 @@ , cSizeVoided :: Maybe Double , cRegulatorAuthCode :: Maybe Text , cRegulatorCode :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data CurrentOrderSummaryReport = CurrentOrderSummaryReportC { cCurrentOrders :: [CurrentOrderSummary] , cMoreAvailable :: Bool }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ExBestOffersOverrides = ExBestOffersOverridesC { ebbestPricesDepth :: Maybe Int@@ -393,13 +472,13 @@ , ebRollupLimit :: Maybe Int , ebRollupLiabilityThreshold :: Maybe Double , ebRollupLiabilityFactor :: Maybe Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ExchangePrices = ExchangePricesC { epAvailableToBack :: Maybe [PriceSize] , epAvailableToLay :: Maybe [PriceSize] , epTradedVolume :: Maybe [PriceSize] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data Event = EventC { eId :: EventId@@ -408,31 +487,59 @@ , eTimezone :: Text , eVenue :: Maybe Text , eOpenDate :: UTCTime }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary Event where+ put (EventC{..}) = do+ put eId+ put (WrappedText eName)+ put eCountryCode+ put (WrappedText eTimezone)+ put (fmap WrappedText eVenue)+ put (WrappedUTCTime eOpenDate)+ get = EventC <$>+ get <*>+ (unwrapText <$> get) <*>+ get <*>+ (unwrapText <$> get) <*>+ (fmap unwrapText <$> get) <*>+ (unwrapUTCTime <$> get)+ data EventResult = EventResultC { erEvent :: Event , erMarketCount :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data EventType = EventTypeC { etId :: EventTypeId , etName :: Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary EventType where+ put (EventTypeC {..}) = do+ put etId+ put (WrappedText etName)+ get = EventTypeC <$>+ get <*>+ (unwrapText <$> get)+ data EventTypeResult = EventTypeResultC { etrEventType :: EventType , etrMarketCount :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary EventTypeResult+ newtype Heartbeat = HeartbeatC { hPreferredTimeoutSeconds :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary Heartbeat+ data HeartbeatReport = HeartbeatReportC { hActionPerformed :: ActionPerformed , hActualTimeoutSeconds :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ItemDescription = ItemDescriptionC { iEventTypeDesc :: Maybe Text@@ -441,28 +548,28 @@ , iMarketStartTime :: Maybe UTCTime , iRunnerDesc :: Maybe Text , iNumberOfWinners :: Maybe Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data LimitOnCloseOrder = LimitOnCloseOrderC { loLiability :: Double , loPrice :: Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data LimitOrder = LimitOrderC { lSize :: Double , lPrice :: Double , lPersistenceType :: PersistenceType }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListCompetitions = ListCompetitionsC { lcFilter :: MarketFilter , lcLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListCountries = ListCountriesC { lcsFilter :: MarketFilter , lcsLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListCurrentOrders = ListCurrentOrdersC { lcoBetIds :: Maybe (S.Set BetId)@@ -473,7 +580,7 @@ , lcoSortDir :: Maybe SortDir , lcoFromRecord :: Maybe Int , lcoRecordCount :: Maybe Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListClearedOrders = ListClearedOrdersC { lcrBetStatus :: BetStatus@@ -489,17 +596,17 @@ , lcrLocale :: Maybe Text , lcrFromRecord :: Maybe Int , lcrRecordCount :: Maybe Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListEvents = ListEventsC { leFilter :: MarketFilter , leLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListEventTypes = ListEventTypesC { letFilter :: MarketFilter , letLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListMarketBook = ListMarketBookC { lmbMarketIds :: [MarketId]@@ -508,7 +615,7 @@ , lmbMatchProjection :: Maybe MatchProjection , lmbCurrencyCode :: Maybe Text , lmbLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListMarketCatalogue = ListMarketCatalogueC { lmcFilter :: MarketFilter@@ -516,29 +623,29 @@ , lmcSort :: Maybe MarketSort , lmcMaxResults :: Int , lmcLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListMarketProfitAndLoss = ListMarketProfitAndLossC { lmMarketIds :: S.Set MarketId , lmIncludeSettledBets :: Maybe Bool , lmIncludeBspBets :: Maybe Bool , lmNetOfCommission :: Maybe Bool }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListMarketTypes = ListMarketTypesC { lmtFilter :: MarketFilter , lmtLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListTimeRanges = ListTimeRangesC { ltFilter :: MarketFilter , ltGranularity :: TimeGranularity }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ListVenues = ListVenuesC { lvFilter :: MarketFilter , lvLocale :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data MarketBook = MarketBookC { mbMarketId :: MarketId@@ -558,7 +665,7 @@ , mbRunnersVoidable :: Maybe Bool , mbVersion :: Maybe Int , mbRunners :: [Runner] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data MarketCatalogue = MarketCatalogueC { mcMarketId :: MarketId@@ -570,8 +677,54 @@ , mcEventType :: Maybe EventType , mcCompetition :: Maybe Competition , mcEvent :: Maybe Event }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +-- | A newtype wrapper `Text`. This exists because we don't want to introduce an+-- orphan instance `Binary` for `Text`.+newtype WrappedText = WrappedText { unwrapText :: Text }++instance Binary WrappedText where+ put (WrappedText txt) = put $ T.encodeUtf8 txt+ get = WrappedText . T.decodeUtf8 <$> get++-- | A newtype wrapper around `UTCTime`. This exists because we don't want to+-- introduce an orphan instance `Binary` for `UTCTime`.+newtype WrappedUTCTime = WrappedUTCTime { unwrapUTCTime :: UTCTime }++instance Binary WrappedUTCTime where+ put (WrappedUTCTime (UTCTime (ModifiedJulianDay jl) dt)) = do+ put jl+ put (toRational dt)++ get = do+ u <- UTCTime <$>+ (ModifiedJulianDay <$> get) <*>+ (fromRational <$> get)+ return $ WrappedUTCTime u++instance Binary MarketCatalogue where+ put (MarketCatalogueC{..}) = do+ put mcMarketId+ put (T.encodeUtf8 mcMarketName)+ put (WrappedUTCTime <$> mcMarketStartTime)+ put mcDescription+ put mcTotalMatched+ put mcRunners+ put mcEventType+ put mcCompetition+ put mcEventType++ get = MarketCatalogueC <$>+ get <*>+ (T.decodeUtf8 <$> get) <*>+ (fmap unwrapUTCTime <$> get) <*>+ get <*>+ get <*>+ get <*>+ get <*>+ get <*>+ get+ data MarketDescription = MarketDescriptionC { mdPersistenceEnabled :: Bool , mdBspMarket :: Bool@@ -588,8 +741,42 @@ , mdRules :: Maybe Text , mdRulesHasDate :: Maybe Bool , mdClarifications :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary MarketDescription where+ put (MarketDescriptionC{..}) = do+ put mdPersistenceEnabled+ put mdBspMarket+ put (WrappedUTCTime mdMarketTime)+ put (WrappedUTCTime mdSuspendTime)+ put (WrappedUTCTime <$> mdSettleTime)+ put mdBettingType+ put mdTurnInPlayEnabled+ put (WrappedText mdMarketType)+ put (WrappedText mdRegulator)+ put mdMarketBaseRate+ put mdDiscountAllowed+ put (WrappedText <$> mdWallet)+ put (WrappedText <$> mdRules)+ put mdRulesHasDate+ put (WrappedText <$> mdClarifications)+ get = MarketDescriptionC <$>+ get <*>+ get <*>+ (unwrapUTCTime <$> get) <*>+ (unwrapUTCTime <$> get) <*>+ (fmap unwrapUTCTime <$> get) <*>+ get <*>+ get <*>+ (unwrapText <$> get) <*>+ (unwrapText <$> get) <*>+ get <*>+ get <*>+ (fmap unwrapText <$> get) <*>+ (fmap unwrapText <$> get) <*>+ get <*>+ (fmap unwrapText <$> get)+ data MarketFilter = MarketFilterC { mfTextQuery :: Maybe String , mfEventTypeIds :: Maybe (S.Set EventTypeId)@@ -605,22 +792,22 @@ , mfMarketTypeCodes :: Maybe (S.Set MarketTypeCode) , mfMarketStartTime :: Maybe TimeRange , mfWithOrders :: Maybe (S.Set OrderStatus) }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) newtype MarketOnCloseOrder = MarketOnCloseOrderC { mLiability :: Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data MarketProfitAndLoss = MarketProfitAndLossC { mpMarketId :: Maybe MarketId , mpCommissionApplied :: Maybe Double , mpProfitAndLosses :: Maybe [RunnerProfitAndLoss] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data MarketTypeResult = MarketTypeResultC { mtMarketType :: Text , mtMarketCount :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data Match = MatchC { mBetId :: Maybe BetId@@ -629,7 +816,7 @@ , mPrice :: Double , mSize :: Double , mMatchDate :: Maybe UTCTime }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data Order = OrderC { oBetId :: BetId@@ -647,7 +834,7 @@ , oSizeLapsed :: Maybe Double , oSizeCancelled :: Maybe Double , oSizeVoided :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data PlaceExecutionReport = PlaceExecutionReportC { peCustomerRef :: Maybe Text@@ -655,7 +842,7 @@ , peErrorCode :: Maybe ExecutionReportErrorCode , peMarketId :: Maybe MarketId , peInstructionReports :: Maybe [PlaceInstructionReport] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data PlaceInstruction = PlaceInstructionC { pOrderType :: OrderType@@ -665,7 +852,7 @@ , pLimitOrder :: Maybe LimitOrder , pLimitOnCloseOrder :: Maybe LimitOnCloseOrder , pMarketOnCloseOrder :: Maybe MarketOnCloseOrder }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data PlaceInstructionReport = PlaceInstructionReportC { piStatus :: InstructionReportStatus@@ -675,51 +862,53 @@ , piPlacedDate :: Maybe UTCTime , piAveragePriceMatched :: Maybe Double , piSizeMatched :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data PlaceOrders = PlaceOrdersC { pMarketId :: MarketId , pInstructions :: [PlaceInstruction] , pCustomerRef :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data PriceProjection = PriceProjectionC { ppPriceData :: Maybe (S.Set PriceData) , ppExBestOffersOverrides :: Maybe ExBestOffersOverrides , ppVirtualize :: Maybe Bool , ppRolloverStakes :: Maybe Bool }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data PriceSize = PriceSizeC { psPrice :: Double , psSize :: Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary PriceSize+ data ReplaceExecutionReport = ReplaceExecutionReportC { reCustomerRef :: Maybe Text , reStatus :: ExecutionReportStatus , reErrorCode :: Maybe ExecutionReportErrorCode , reMarketId :: Maybe Text , reInstructionReports :: Maybe [ReplaceInstructionReport] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ReplaceInstruction = ReplaceInstructionC { rBetId :: BetId , rNewPrice :: Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ReplaceInstructionReport = ReplaceInstructionReportC { riStatus :: InstructionReportStatus , riErrorCode :: Maybe InstructionReportErrorCode , riCancelInstructionReport :: Maybe CancelInstructionReport , riPlaceInstructionReport :: Maybe PlaceInstructionReport }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data ReplaceOrders = ReplaceOrdersC { rMarketId :: MarketId , rInstructions :: [ReplaceInstruction] , rCustomerRef :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data Runner = RunnerC { rSelectionId :: SelectionId@@ -735,27 +924,41 @@ , rEx :: Maybe ExchangePrices , rOrders :: Maybe [Order] , rMatches :: Maybe [Match] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data RunnerCatalog = RunnerCatalogC { rcSelectionId :: SelectionId , rcRunnerName :: Text , rcHandicap :: Double- , rcSortPriority :: Int- , rcMetadata :: M.Map Text Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ , rcSortPriority :: Maybe Int+ , rcMetadata :: Maybe (M.Map Text Text) }+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) +instance Binary RunnerCatalog where+ put (RunnerCatalogC{..}) = do+ put rcSelectionId+ put (WrappedText rcRunnerName)+ put rcHandicap+ put rcSortPriority+ put (M.map WrappedText . M.mapKeysMonotonic WrappedText <$> rcMetadata)+ get = RunnerCatalogC <$>+ get <*>+ (unwrapText <$> get) <*>+ get <*>+ get <*>+ (fmap (M.map unwrapText . M.mapKeysMonotonic unwrapText) <$> get)+ data RunnerId = RunnerIdC { riMarketId :: MarketId , riSelectionId :: SelectionId , riHandicap :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data RunnerProfitAndLoss = RunnerProfitAndLossC { rpSelectionId :: Maybe SelectionId , rpIfWin :: Maybe Double , rpIfLose :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data StartingPrices = StartingPricesC { spNearPrice :: Maybe Double@@ -763,17 +966,17 @@ , spBackStakeTaken :: Maybe [PriceSize] , spLayLiabilityTaken :: Maybe [PriceSize] , spActualSP :: Maybe Double }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data TimeRange = TimeRangeC { tFrom :: UTCTime , tTo :: UTCTime }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data TimeRangeResult = TimeRangeResultC { tTimeRange :: TimeRange , tMarketCount :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data UpdateExecutionReport = UpdateExecutionReportC { ueCustomerRef :: Maybe Text@@ -781,33 +984,33 @@ , ueErrorCode :: Maybe ExecutionReportErrorCode , ueMarketId :: Maybe Text , ueInstructionReports :: Maybe [UpdateInstructionReport] }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data UpdateInstruction = UpdateInstructionC { uBetId :: BetId , uNewPersistenceType :: PersistenceType }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data UpdateInstructionReport = UpdateInstructionReportC { uiStatus :: InstructionReportStatus , uiErrorCode :: Maybe InstructionReportErrorCode , uiInstruction :: UpdateInstruction }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data UpdateOrders = UpdateOrdersC { uMarketId :: MarketId , uInstructions :: [UpdateInstruction] , uCustomerRef :: Maybe Text }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data VenueResult = VenueResultC { vVenue :: Text , vMarketCount :: Int }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) data APIException = APIException { exceptionDetails :: Text , exceptionCode :: APIExceptionCode }- deriving ( Eq, Ord, Show, Read, Typeable )+ deriving ( Eq, Ord, Show, Read, Typeable, Data, Generic ) instance Exception APIException @@ -828,7 +1031,7 @@ | TimeoutError | RequestSizeExceedsLimit | AccessDenied- deriving ( Eq, Ord, Show, Read, Typeable, Enum )+ deriving ( Eq, Ord, Show, Read, Typeable, Enum, Data, Generic ) makeLensesWith abbreviatedFields ''CancelExecutionReport makeLensesWith abbreviatedFields ''CancelInstruction