packages feed

bitx-bitcoin 0.7.0.2 → 0.8.0.0

raw patch · 12 files changed

+93/−59 lines, 12 files

Files

CHANGES view
@@ -1,3 +1,9 @@+v0.8.0.0+* Added Singapore Dollar.+* The UnparseableResponse now provides the Aeson error. BREAKING CHANGE.+* Last_trade and Bid and Ask prices don't always appear in the Ticker type. BREAKING CHANGE.+* GHC 8.0 is now officially supported.+ v0.7.0.2 * Forgot to export "status" lens, 
README.md view
@@ -8,8 +8,6 @@ BitX exchange, do the following:  ```haskell-{-# LANGUAGE DataKinds #-}- import Control.Lens ((^.)) import Network.Bitcoin.BitX (BitXAPIResponse(..), getTicker, CcyPair(..)) import qualified Network.Bitcoin.BitX as BitX@@ -21,12 +19,15 @@ main = do   bitXResponse <- getTicker XBTZAR   case bitXResponse of-    ValidResponse tic        -> print (tic ^. BitX.ask)+    ValidResponse tic        ->+      case tic ^. BitX.ask of+        Nothing              ->  putStrLn "The BTC-ZAR exchange not currently have an ask price..."+        Just p               ->  putStrLn ("1 bitcoin will set you back ZAR" ++ show p ++ ".00.")     ErrorResponse err        ->         error $ "BitX error received: \"" ++ unpack (err ^. BitX.error) ++ "\""     ExceptionResponse ex     ->         error $ "Exception was thrown: \"" ++ show ex ++ "\""-    UnparseableResponse resp ->+    UnparseableResponse _ resp ->         error $ "Bad HTTP response; HTTP status code was: \"" ++ (show . statusCode . responseStatus $ resp) ++ "\"" ``` 
bitx-bitcoin.cabal view
@@ -1,5 +1,5 @@ name:                bitx-bitcoin-version:             0.7.0.2+version:             0.8.0.0 synopsis:            A Haskell library for working with the BitX bitcoin exchange.  description:@@ -11,7 +11,7 @@     the code of the author of this library, or BitX's code. This is just common sense.     .     If you need to make sure that nothing funny happens in the code, apart from reading-    the source yourself, you should also perform a few test transations with very small+    the source yourself, you should also perform a few test transactions with very small     denominations, as I will strive to do every time before releasing a new version.     .     For a very small usage example, see "Network.Bitcoin.BitX.Public".
src/Network/Bitcoin/BitX/Internal.hs view
@@ -18,20 +18,20 @@ import Network.HTTP.Types (status503) import Network.HTTP.Client (Response(..), Request(..)) import Control.Exception (try)-import qualified Data.Aeson as Aeson (decode)+import qualified Data.Aeson as Aeson (decode, eitherDecode) import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString as BS import Data.Maybe (fromJust) import Network (withSocketsDo) import qualified Data.Text.Encoding as Txt import Network.Bitcoin.BitX.Response-import Control.Applicative ((<|>)) import Lens.Micro ((^.)) import Control.Concurrent (threadDelay) #if __GLASGOW_HASKELL__ >= 710 -- <$> is in base since 4.8 (GHC 7.10) due to the AMP+import Control.Applicative ((<|>)) #else-import Control.Applicative ((<$>))+import Control.Applicative ((<|>), (<$>)) #endif  bitXAPIPrefix :: String@@ -106,10 +106,20 @@ bitXErrorOrPayload :: BitXAesRecordConvert recd => Response BL.ByteString -> BitXAPIResponse recd bitXErrorOrPayload resp = fromJust $         ErrorResponse . aesToRec <$> Aeson.decode body -- is it a BitX error?-    <|> ValidResponse . aesToRec <$> Aeson.decode body-    <|> Just (UnparseableResponse  resp)+    <|> ValidResponse . aesToRec <$> eitherToMaybe respBody -- I can't get the typechecker to work if I use "Aeson.decode body" here+    <|> Just (UnparseableResponse aesonErr resp)     where+        aesonErr = fromLeft respBody+        respBody = Aeson.eitherDecode body         body = NetCon.responseBody resp++fromLeft :: Either a b -> a+fromLeft (Left a) = a+fromLeft     _    = Prelude.error "fromLeft called on Right value. This is not supposed to happen..."++eitherToMaybe :: Either a b -> Maybe b+eitherToMaybe (Left _) = Nothing+eitherToMaybe (Right b) = Just b  isRateLimited :: Either NetCon.HttpException a -> Bool isRateLimited (Left  (NetCon.StatusCodeException st _ _)) = st == status503
src/Network/Bitcoin/BitX/Private.hs view
@@ -180,7 +180,7 @@ getPendingTransactions auth accid = liftM imebPendingTransactionsToimebTransactions $ simpleBitXGetAuth_ auth $     "accounts/" ++ Txt.unpack accid ++ "/pending"     where-        imebPendingTransactionsToimebTransactions (ValidResponse v)       = ValidResponse $ pendingTransactionsToTransactions v-        imebPendingTransactionsToimebTransactions (ExceptionResponse x)   = ExceptionResponse x-        imebPendingTransactionsToimebTransactions (ErrorResponse e)       = ErrorResponse e-        imebPendingTransactionsToimebTransactions (UnparseableResponse u) = UnparseableResponse u+        imebPendingTransactionsToimebTransactions (ValidResponse v)         = ValidResponse $ pendingTransactionsToTransactions v+        imebPendingTransactionsToimebTransactions (ExceptionResponse x)     = ExceptionResponse x+        imebPendingTransactionsToimebTransactions (ErrorResponse e)         = ErrorResponse e+        imebPendingTransactionsToimebTransactions (UnparseableResponse a u) = UnparseableResponse a u
src/Network/Bitcoin/BitX/Public.hs view
@@ -13,25 +13,26 @@ -- As a small example, to get the current selling price of bitcoin on the BitX exchange, do the following: -- -- @---{-\# LANGUAGE DataKinds \#-}
---
---import Control.Lens ((^.))
---import Network.Bitcoin.BitX (BitXAPIResponse(..), getTicker, CcyPair(..))
---import qualified Network.Bitcoin.BitX as BitX
---import Data.Text (unpack)
---import Network.HTTP.Types.Status (Status(..))
---import Network.HTTP.Conduit (responseStatus)
---
---main :: IO ()
---main = do
---  bitXResponse <- getTicker XBTZAR
---  case bitXResponse of
---    ValidResponse tic        -> print (tic ^. BitX.ask)
---    ErrorResponse err        ->
---        error $ "BitX error received: \\"" ++ unpack (err ^. BitX.error) ++ "\\""
---    ExceptionResponse ex     ->
---        error $ "Exception was thrown: \\"" ++ show ex ++ "\\""
---    UnparseableResponse resp ->
+--import Control.Lens ((^.))+--import Network.Bitcoin.BitX (BitXAPIResponse(..), getTicker, CcyPair(..))+--import qualified Network.Bitcoin.BitX as BitX+--import Data.Text (unpack)+--import Network.HTTP.Types.Status (Status(..))+--import Network.HTTP.Conduit (responseStatus)+--+--main :: IO ()+--main = do+--  bitXResponse <- getTicker XBTZAR+--  case bitXResponse of+--    ValidResponse tic+--      case tic ^. BitX.ask of+--        Nothing              ->  putStrLn "The BTC-ZAR exchange not currently have an ask price..."+--        Just p               ->  putStrLn ("1 bitcoin will set you back ZAR" ++ show p ++ ".00.")+--    ErrorResponse err        ->+--        error $ "BitX error received: \\"" ++ unpack (err ^. BitX.error) ++ "\\""+--    ExceptionResponse ex     ->+--        error $ "Exception was thrown: \\"" ++ show ex ++ "\\""+--    UnparseableResponse _ resp -> --        error $ "Bad HTTP response; HTTP status code was: \\"" ++ (show . statusCode . responseStatus $ resp) ++ "\\"" -- @ --
src/Network/Bitcoin/BitX/Response.hs view
@@ -30,7 +30,9 @@     | ErrorResponse BitXError -- ^ BitX returned an error record instead of returning the data we                               -- were expecting.     | ValidResponse recd -- ^ We received the data type we were expecting.-    | UnparseableResponse (Response ByteString) -- ^ BitX retuned data which couldn't be parsed,-                                                -- such as some text which was probably not JSON format.+    | UnparseableResponse String (Response ByteString) -- ^ BitX retuned data which couldn't be parsed,+                                                       -- such as some text which was probably not JSON format.+                                                       -- The first value is the error given by Aeson upon trying+                                                       -- to parse the response body.  deriving instance Show recd => Show (BitXAPIResponse recd)
src/Network/Bitcoin/BitX/Types.hs view
@@ -181,6 +181,8 @@     | NGNXBT -- ^ Nigerian Naira vs. Bitcoin     | XBTIDR -- ^ Bitcoin vs. Indonesian Rupiah     | IDRXBT -- ^ Indonesian Rupiah vs. Bitcoin+    | XBTSGD -- ^ Bitcoin vs. Singapore Dollar+    | SGDXBT -- ^ Singapore Dollar vs. Bitcoin   deriving (Show, Generic, Eq)  -- | The state of a single market, identified by the currency pair.@@ -188,9 +190,9 @@ -- the price of the last filled bid order. Necessarily @bid <= ask.@ data Ticker = Ticker {     tickerTimestamp :: UTCTime,-    tickerBid :: Int,-    tickerAsk :: Int,-    tickerLastTrade :: Int,+    tickerBid :: Maybe Int,+    tickerAsk :: Maybe Int,+    tickerLastTrade :: Maybe Int,     tickerRolling24HourVolume :: Scientific,     tickerPair :: CcyPair     } deriving (Eq, Show)@@ -206,6 +208,7 @@     | MYR -- ^ Malaysian Ringgit     | NGN -- ^ Nigerian Naira     | IDR -- ^ Indonesian Rupiah+    | SGD -- ^ Singapore Dollar   deriving (Show, Generic, Eq)  -- | The type of a withdrawal request.
src/Network/Bitcoin/BitX/Types/Internal.hs view
@@ -37,7 +37,7 @@  {-# ANN module ("HLint: ignore Use camelCase" :: String) #-} -newtype UnixStampMS = UnixStampMS {unUnixStampMS_ :: Integer} deriving (Eq, Ord, Show, Num, Integral, Real, Enum)+newtype UnixStampMS = UnixStampMS {_unUnixStampMS :: Integer} deriving (Eq, Ord, Show, Num, Integral, Real, Enum)  instance Arbitrary UnixStampMS where     arbitrary = do@@ -57,7 +57,7 @@ -- >>> import Test.QuickCheck  -- |--- prop> \ n -> (timeToTimestamp $ timestampParse_ $ unUnixStampMS_ n) == unUnixStampMS_ n+-- prop> \ n -> (timeToTimestamp $ timestampParse_ $ _unUnixStampMS n) == _unUnixStampMS n --  class FromJSON (Aes recd) => BitXAesRecordConvert recd where@@ -150,9 +150,9 @@  data Ticker_ = Ticker_     { ticker'timestamp :: TimestampMS-    , ticker'bid :: QuotedInt-    , ticker'ask :: QuotedInt-    , ticker'last_trade :: QuotedInt+    , ticker'bid :: Maybe QuotedInt+    , ticker'ask :: Maybe QuotedInt+    , ticker'last_trade :: Maybe QuotedInt     , ticker'rolling_24_hour_volume :: QuotedScientific     , ticker'pair :: Types.CcyPair     }@@ -164,9 +164,9 @@     type Aes Types.Ticker = Ticker_     aesToRec Ticker_ {..} =         Types.Ticker {tickerTimestamp = tsmsToUTCTime ticker'timestamp,-                  tickerBid = qiToInt ticker'bid,-                  tickerAsk = qiToInt ticker'ask,-                  tickerLastTrade = qiToInt ticker'last_trade,+                  tickerBid = fmap qiToInt ticker'bid,+                  tickerAsk = fmap qiToInt ticker'ask,+                  tickerLastTrade = fmap qiToInt ticker'last_trade,                   tickerRolling24HourVolume = qsToScientific ticker'rolling_24_hour_volume,                   tickerPair = ticker'pair} 
test/Example.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE DataKinds #-}- import Lens.Micro ((^.)) import Network.Bitcoin.BitX (BitXAPIResponse(..), getTicker, CcyPair(..)) import qualified Network.Bitcoin.BitX as BitX@@ -11,11 +9,13 @@ main = do   bitXResponse <- getTicker XBTZAR   case bitXResponse of-    ValidResponse tic        -> putStrLn ("1 bitcoin will set you back ZAR" ++ show (tic ^. BitX.ask) ++ ".00.")+    ValidResponse tic        ->+      case tic ^. BitX.ask of+        Nothing              -> putStrLn "The BTC-ZAR exchange not currently have an ask price..."+        Just p               -> putStrLn ("1 bitcoin will set you back ZAR" ++ show p ++ ".00.")     ErrorResponse err        ->         error $ "BitX error received: \"" ++ unpack (err ^. BitX.error) ++ "\""     ExceptionResponse ex     ->         error $ "Exception was thrown: \"" ++ show ex ++ "\""-    UnparseableResponse resp ->+    UnparseableResponse _ resp ->         error $ "Bad HTTP response; HTTP status code was: \"" ++ (show . statusCode . responseStatus $ resp) ++ "\""-
test/Network/Bitcoin/BitX/Spec/Specs/AesonRecordSpec.hs view
@@ -23,11 +23,22 @@             \ \"last_trade\":\"3116.00\",\"rolling_24_hour_volume\":\"19.776608\",\"pair\":\"XBTZAR\"}"         Ticker {              tickerTimestamp = posixSecondsToUTCTime 1431811395.699,-             tickerBid = 3083,-             tickerAsk = 3115,-             tickerLastTrade = 3116,+             tickerBid = Just 3083,+             tickerAsk = Just 3115,+             tickerLastTrade = Just 3116,              tickerRolling24HourVolume = 19.776608,              tickerPair = XBTZAR}+    it "Ticker with missing fields is parsed properly" $+      recordAesCheck+        "{\"timestamp\":1431811395699,\"bid\":\"3083.00\",\+            \ \"last_trade\":\"3116.00\",\"rolling_24_hour_volume\":\"19.776608\",\"pair\":\"XBTZAR\"}"+        Ticker {+             tickerTimestamp = posixSecondsToUTCTime 1431811395.699,+             tickerBid = Just 3083,+             tickerAsk = Nothing,+             tickerLastTrade = Just 3116,+             tickerRolling24HourVolume = 19.776608,+             tickerPair = XBTZAR}     it "Balance is parsed properly" $       recordAesCheck         "{\"account_id\":\"314159\",\"asset\":\"ZAR\",\"balance\":\"2159.15\",\"reserved\":\"320.43\",\@@ -171,9 +182,9 @@ tickerInner :: Ticker tickerInner =     Ticker (posixSecondsToUTCTime 1431811395.699)-        3083-        3115-        3116+        (Just 3083)+        (Just 3115)+        (Just 3116)         19.776608         XBTZAR 
test/Network/Bitcoin/BitX/Spec/Specs/LensSpec.hs view
@@ -30,7 +30,7 @@  _ticker :: Maybe Int _ticker = do-    let x = BitX.Ticker (posixSecondsToUTCTime 0) 0 0 0 0 XBTZAR+    let x = BitX.Ticker (posixSecondsToUTCTime 0) Nothing Nothing Nothing 0 XBTZAR     let _ = x ^. BitX.timestamp     let _ = x ^. BitX.bid     let _ = x ^. BitX.ask