packages feed

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 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