packages feed

bitx-bitcoin 0.11.0.1 → 0.12.0.0

raw patch · 13 files changed

+107/−128 lines, 13 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Network.Bitcoin.BitX.Types: IDRXBT :: CcyPair
- Network.Bitcoin.BitX.Types: KES :: Asset
- Network.Bitcoin.BitX.Types: KESXBT :: CcyPair
- Network.Bitcoin.BitX.Types: MYRXBT :: CcyPair
- Network.Bitcoin.BitX.Types: NAD :: Asset
- Network.Bitcoin.BitX.Types: NADXBT :: CcyPair
- Network.Bitcoin.BitX.Types: NGN :: Asset
- Network.Bitcoin.BitX.Types: NGNXBT :: CcyPair
- Network.Bitcoin.BitX.Types: SGD :: Asset
- Network.Bitcoin.BitX.Types: SGDXBT :: CcyPair
- Network.Bitcoin.BitX.Types: XBTKES :: CcyPair
- Network.Bitcoin.BitX.Types: XBTNAD :: CcyPair
- Network.Bitcoin.BitX.Types: XBTSGD :: CcyPair
- Network.Bitcoin.BitX.Types: ZARXBT :: CcyPair
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasAsk Network.Bitcoin.BitX.Types.Ticker (GHC.Base.Maybe GHC.Types.Int)
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasBid Network.Bitcoin.BitX.Types.Ticker (GHC.Base.Maybe GHC.Types.Int)
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasCompletedTimestamp Network.Bitcoin.BitX.Types.PrivateOrder Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasCreatedAt Network.Bitcoin.BitX.Types.OrderQuote Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasCreationTimestamp Network.Bitcoin.BitX.Types.PrivateOrder Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasExpirationTimestamp Network.Bitcoin.BitX.Types.PrivateOrder Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasExpiresAt Network.Bitcoin.BitX.Types.OrderQuote Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasLastTrade Network.Bitcoin.BitX.Types.Ticker (GHC.Base.Maybe GHC.Types.Int)
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasLimitPrice Network.Bitcoin.BitX.Types.PrivateOrder GHC.Types.Int
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.Order GHC.Types.Int
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.OrderRequest GHC.Types.Int
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.PrivateTrade GHC.Types.Int
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.Trade GHC.Types.Int
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Orderbook Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.PrivateTrade Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Ticker Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Trade Data.Time.Clock.UTC.UTCTime
- Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Transaction Data.Time.Clock.UTC.UTCTime
+ Network.Bitcoin.BitX.Types: BCH :: Asset
+ Network.Bitcoin.BitX.Types: ETH :: Asset
+ Network.Bitcoin.BitX.Types: ETHXBT :: CcyPair
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasAsk Network.Bitcoin.BitX.Types.Ticker (GHC.Base.Maybe Data.Scientific.Scientific)
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasBid Network.Bitcoin.BitX.Types.Ticker (GHC.Base.Maybe Data.Scientific.Scientific)
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasCompletedTimestamp Network.Bitcoin.BitX.Types.PrivateOrder Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasCreatedAt Network.Bitcoin.BitX.Types.OrderQuote Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasCreationTimestamp Network.Bitcoin.BitX.Types.PrivateOrder Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasExpirationTimestamp Network.Bitcoin.BitX.Types.PrivateOrder Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasExpiresAt Network.Bitcoin.BitX.Types.OrderQuote Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasLastTrade Network.Bitcoin.BitX.Types.Ticker (GHC.Base.Maybe Data.Scientific.Scientific)
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasLimitPrice Network.Bitcoin.BitX.Types.PrivateOrder Data.Scientific.Scientific
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.Order Data.Scientific.Scientific
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.OrderRequest Data.Scientific.Scientific
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.PrivateTrade Data.Scientific.Scientific
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasPrice Network.Bitcoin.BitX.Types.Trade Data.Scientific.Scientific
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Orderbook Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.PrivateTrade Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Ticker Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Trade Data.Time.Clock.Internal.UTCTime.UTCTime
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasTimestamp Network.Bitcoin.BitX.Types.Transaction Data.Time.Clock.Internal.UTCTime.UTCTime
- Network.Bitcoin.BitX.Types: Order :: Scientific -> Int -> Order
+ Network.Bitcoin.BitX.Types: Order :: Scientific -> Scientific -> Order
- Network.Bitcoin.BitX.Types: OrderRequest :: CcyPair -> OrderType -> Scientific -> Int -> OrderRequest
+ Network.Bitcoin.BitX.Types: OrderRequest :: CcyPair -> OrderType -> Scientific -> Scientific -> OrderRequest
- Network.Bitcoin.BitX.Types: PrivateOrder :: Scientific -> Scientific -> UTCTime -> UTCTime -> UTCTime -> Scientific -> Scientific -> Int -> Scientific -> OrderID -> CcyPair -> RequestStatus -> OrderType -> PrivateOrder
+ Network.Bitcoin.BitX.Types: PrivateOrder :: Scientific -> Scientific -> UTCTime -> UTCTime -> UTCTime -> Scientific -> Scientific -> Scientific -> Scientific -> OrderID -> CcyPair -> RequestStatus -> OrderType -> PrivateOrder
- Network.Bitcoin.BitX.Types: PrivateTrade :: Scientific -> Scientific -> Scientific -> Scientific -> Bool -> Text -> CcyPair -> Int -> UTCTime -> OrderType -> Scientific -> PrivateTrade
+ Network.Bitcoin.BitX.Types: PrivateTrade :: Scientific -> Scientific -> Scientific -> Scientific -> Bool -> Text -> CcyPair -> Scientific -> UTCTime -> OrderType -> Scientific -> PrivateTrade
- Network.Bitcoin.BitX.Types: Ticker :: UTCTime -> Maybe Int -> Maybe Int -> Maybe Int -> Scientific -> CcyPair -> Ticker
+ Network.Bitcoin.BitX.Types: Ticker :: UTCTime -> Maybe Scientific -> Maybe Scientific -> Maybe Scientific -> Scientific -> CcyPair -> Ticker
- Network.Bitcoin.BitX.Types: Trade :: UTCTime -> Scientific -> Int -> Bool -> Trade
+ Network.Bitcoin.BitX.Types: Trade :: UTCTime -> Scientific -> Scientific -> Bool -> Trade
- Network.Bitcoin.BitX.Types: [orderPrice] :: Order -> Int
+ Network.Bitcoin.BitX.Types: [orderPrice] :: Order -> Scientific
- Network.Bitcoin.BitX.Types: [orderRequestPrice] :: OrderRequest -> Int
+ Network.Bitcoin.BitX.Types: [orderRequestPrice] :: OrderRequest -> Scientific
- Network.Bitcoin.BitX.Types: [privateOrderLimitPrice] :: PrivateOrder -> Int
+ Network.Bitcoin.BitX.Types: [privateOrderLimitPrice] :: PrivateOrder -> Scientific
- Network.Bitcoin.BitX.Types: [privateTradePrice] :: PrivateTrade -> Int
+ Network.Bitcoin.BitX.Types: [privateTradePrice] :: PrivateTrade -> Scientific
- Network.Bitcoin.BitX.Types: [tickerAsk] :: Ticker -> Maybe Int
+ Network.Bitcoin.BitX.Types: [tickerAsk] :: Ticker -> Maybe Scientific
- Network.Bitcoin.BitX.Types: [tickerBid] :: Ticker -> Maybe Int
+ Network.Bitcoin.BitX.Types: [tickerBid] :: Ticker -> Maybe Scientific
- Network.Bitcoin.BitX.Types: [tickerLastTrade] :: Ticker -> Maybe Int
+ Network.Bitcoin.BitX.Types: [tickerLastTrade] :: Ticker -> Maybe Scientific
- Network.Bitcoin.BitX.Types: [tradePrice] :: Trade -> Int
+ Network.Bitcoin.BitX.Types: [tradePrice] :: Trade -> Scientific

Files

CHANGES view
@@ -1,3 +1,10 @@+v0.12.0.0+* We now handle nulls properly when deserialising JSON arrays.+* Luno has added Ethereum and an ETHXBT currency pair.+* Prices (bid, ask, and spot) are now consistently Scientific, rather than Int. BREAKING CHANGE.+* We no longer create a brand new connection manager on every API call, significatly improving performance.+* Luno's rate-limiting is now much more harsh.+ v0.11.0.1 * Added new fee_info endpoint. @@ -73,4 +80,3 @@  v0.1.0.0 * Initial release!-
README.md view
@@ -2,10 +2,10 @@ [![Hackage](https://budueba.com/hackage/bitx-bitcoin)](https://hackage.haskell.org/package/bitx-bitcoin) [![BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](http://opensource.org/licenses/BSD-3-Clause) -(Hopefully useful) Haskell bindings to the [BitX](https://bitx.co/) bitcoin exchange's [API](https://bitx.co/api).+(Hopefully useful) Haskell bindings to the [Luno](https://www.luno.com/) (formerly BitX) cryptocurrency exchange's [API](https://www.luno.com/en/api). -As a minimal example, to get the current selling price (in South African Rand) of bitcoin on the-BitX exchange, do the following:+As a minimal example, to get the current selling price (in South African Rand) of Bitcoin on the+Luno exchange, do the following:  ```haskell import Control.Lens ((^.))@@ -22,7 +22,7 @@     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.")+        Just p               ->  putStrLn ("1 Bitcoin will set you back ZAR" ++ show p ++ ".")     ErrorResponse err        ->         error $ "BitX error received: \"" ++ unpack (err ^. BitX.error) ++ "\""     ExceptionResponse ex     ->@@ -37,5 +37,5 @@ [microlens](https://hackage.haskell.org/package/microlens)), and finally **bitx-bitcoin**.  This library is known to work on Windows, but if you wish to use it then you will have to do a bit-more work due to the ``Network`` library not building on Windows out of the box. See-[this blog post by Neil Mitchell](http://neilmitchell.blogspot.com/2010/12/installing-haskell-network-library-on.html).+more work due to the ``Network`` library not building on Windows out of the box. Your best bet might be to just+use Stack.
bitx-bitcoin.cabal view
@@ -1,14 +1,15 @@ name:                bitx-bitcoin-version:             0.11.0.1+version:             0.12.0.0 synopsis:            A Haskell library for working with the BitX bitcoin exchange.  description:-    Haskell bindings to the BitX REST API, as described here: <https://bitx.co/api>.+    Haskell bindings to the Luno (formerly BitX) REST API, as described here:+    <https://www.luno.com/en/api>.     .     Note that since this library interfaces directly with a financial API, great care     must be taken in its use. In particular, the author cannot be held accountable for any     financial losses as a result of programming error, whether that error is in your code,-    the code of the author of this library, or BitX's code. This is just common sense.+    the code of the author of this library, or Luno'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 transactions with very small@@ -20,7 +21,7 @@  license-file:        LICENSE -author:              Tebello Thejane+author:              Tebello Thejane, Tristan Seligmann  maintainer:          Tebello Thejane <zyxoas+hackage@gmail.com> @@ -36,7 +37,7 @@  homepage:            https://github.com/tebello-thejane/bitx.hs -tested-with:         GHC >=7.8.1 && <=8.0.1+tested-with:         GHC >=7.8.1 && <=8.2.2  -------------------------------------------------------------------------------- @@ -47,7 +48,6 @@     Network.Bitcoin.BitX.Private     Network.Bitcoin.BitX.Types     Network.Bitcoin.BitX.Private.Quote-  --  Network.Bitcoin.BitX.Private.Auth     Network.Bitcoin.BitX.Private.Order     Network.Bitcoin.BitX.Private.Withdrawal     Network.Bitcoin.BitX.Private.Fees
src/Network/Bitcoin/BitX.hs view
@@ -20,7 +20,6 @@     module Network.Bitcoin.BitX.Private,     module Network.Bitcoin.BitX.Public,     module Network.Bitcoin.BitX.Private.Quote,-    --module Network.Bitcoin.BitX.Private.Auth,     module Network.Bitcoin.BitX.Private.Order,     module Network.Bitcoin.BitX.Private.Withdrawal,     module Network.Bitcoin.BitX.Private.Fees,@@ -34,7 +33,6 @@ import Network.Bitcoin.BitX.Private import Network.Bitcoin.BitX.Public import Network.Bitcoin.BitX.Private.Quote---import Network.Bitcoin.BitX.Private.Auth import Network.Bitcoin.BitX.Private.Order import Network.Bitcoin.BitX.Private.Withdrawal import Network.Bitcoin.BitX.Private.Fees@@ -42,4 +40,3 @@ import Network.Bitcoin.BitX.Response  {-# ANN module "HLint: ignore Use import/export shortcut" #-}-
src/Network/Bitcoin/BitX/Internal.hs view
@@ -15,7 +15,7 @@ import Network.Bitcoin.BitX.Types.Internal import qualified Network.HTTP.Client as NetCon import qualified Network.HTTP.Client.TLS as NetCon-import Network.HTTP.Types.Status (status503, status429)+import Network.HTTP.Types.Status (status429) import Network.HTTP.Client (Response(..), Request(..)) import Control.Exception (try) import qualified Data.Aeson as Aeson (decode, eitherDecode)@@ -33,6 +33,7 @@ import Data.Text.Encoding (decodeUtf8) import Data.Monoid ((<>)) import Control.Monad.Catch (MonadThrow)+import System.IO.Unsafe (unsafePerformIO) #if __GLASGOW_HASKELL__ >= 710 -- <$> is in base since 4.8 (GHC 7.10) due to the AMP import Control.Applicative ((<|>))@@ -46,8 +47,9 @@ bitXAPIRoot :: Text bitXAPIRoot = bitXAPIPrefix <> "1/" -globalManager :: IO NetCon.Manager-globalManager = NetCon.newManager NetCon.tlsManagerSettings+globalManager :: NetCon.Manager+globalManager = unsafePerformIO (NetCon.newManager NetCon.tlsManagerSettings)+{-# NOINLINE globalManager #-}  psUrl :: MonadThrow m => String -> m Request #if MIN_VERSION_http_client(0,4,30)@@ -57,9 +59,8 @@ #endif  authConnect :: BitXAuth -> Request -> IO (Either NetCon.HttpException (Response BL.ByteString))-authConnect auth req = do-    manager <- globalManager-    try . flip NetCon.httpLbs manager . NetCon.applyBasicAuth userID userSecret $ req+authConnect auth =+    try . flip NetCon.httpLbs globalManager . NetCon.applyBasicAuth userID userSecret     where         userID = Txt.encodeUtf8 (auth ^. Types.id)         userSecret = Txt.encodeUtf8 (auth ^. Types.secret)@@ -88,10 +89,9 @@         consumeResponseIO  simpleBitXGet_ :: BitXAesRecordConvert recd => Text -> IO (BitXAPIResponse recd)-simpleBitXGet_ verb = withSocketsDo $ do-    manager <- globalManager+simpleBitXGet_ verb = withSocketsDo $     rateLimit-        (try . flip NetCon.httpLbs manager . fromJust . psUrl $ Txt.unpack (bitXAPIRoot <> verb))+        (try . flip NetCon.httpLbs globalManager . fromJust . psUrl $ Txt.unpack (bitXAPIRoot <> verb))         consumeResponseIO  rateLimit :: IO (Either NetCon.HttpException c) -> (Either NetCon.HttpException c -> IO d) -> IO d@@ -106,7 +106,7 @@                         threadDelay del                         go (incDelay del)             else act2 resp-        maxLimit = 5 * 1000 * 1000 -- 5 seconds probably means something else is wrong...+        maxLimit = 30 * 1000 * 1000 -- 30 seconds probably means something else is wrong...         incDelay = round . (* (1.5 :: Double)) . fromIntegral  consumeResponseIO :: BitXAesRecordConvert recd => Either NetCon.HttpException (NetCon.Response BL.ByteString)@@ -136,8 +136,8 @@  isRateLimited :: Either NetCon.HttpException a -> Bool #if MIN_VERSION_http_client(0,5,0)-isRateLimited (Left  (NetCon.HttpExceptionRequest _ (NetCon.StatusCodeException r _ )))  = (responseStatus r == status503) || (responseStatus r == status429)+isRateLimited (Left  (NetCon.HttpExceptionRequest _ (NetCon.StatusCodeException r _ )))  = responseStatus r == status429 #else-isRateLimited (Left  (NetCon.StatusCodeException st _ _)) = st == status503 || st == status429+isRateLimited (Left  (NetCon.StatusCodeException st _ _)) = st == status429 #endif isRateLimited _ = False
src/Network/Bitcoin/BitX/Private/Fees.hs view
@@ -13,7 +13,7 @@ -- Retrieving fee information. -- -- The BitX fee structure is cummulative-volume-based. The sole endpoint in--- this packagereturns the user's current fee structure and 30-day volume.+-- this package returns the user's current fee structure and 30-day volume. -- ----------------------------------------------------------------------------- 
src/Network/Bitcoin/BitX/Types.hs view
@@ -185,19 +185,10 @@ -- | A currency pair data CcyPair =     XBTZAR -- ^ Bitcoin vs. ZAR-    | XBTNAD -- ^ Bitcoin vs. Namibian Dollar-    | ZARXBT -- ^ ZAR vs. Namibian Dollar-    | NADXBT -- ^ Namibian Dollar vs. Bitcoin-    | XBTKES -- ^ Bitcoin vs. Kenyan Shilling-    | KESXBT -- ^ Kenyan Shilling vs Bitcoin     | XBTMYR -- ^ Bitcoin vs. Malaysian Ringgit-    | MYRXBT -- ^ Malaysian Ringgit vs. Bitcoin     | XBTNGN -- ^ Bitcoin vs. Nigerian Naira-    | 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+    | ETHXBT -- ^ Ether vs. Bitcoin   deriving (Show, Generic, Eq, Data, Typeable, Ord)  instance NFData CcyPair@@ -207,9 +198,9 @@ -- the price of the last filled bid order. Necessarily @bid <= ask.@ data Ticker = Ticker {     tickerTimestamp :: UTCTime,-    tickerBid :: Maybe Int,-    tickerAsk :: Maybe Int,-    tickerLastTrade :: Maybe Int,+    tickerBid :: Maybe Scientific,+    tickerAsk :: Maybe Scientific,+    tickerLastTrade :: Maybe Scientific,     tickerRolling24HourVolume :: Scientific,     tickerPair :: CcyPair     } deriving (Eq, Show, Generic, Data, Typeable, Ord)@@ -221,13 +212,11 @@ -- | A trade-able asset. Essentially, a currency. data Asset =     ZAR -- ^ South African Rand-    | NAD -- ^ Namibian Dollar     | XBT -- ^ Bitcoin-    | KES -- ^ Kenyan Shilling     | MYR -- ^ Malaysian Ringgit-    | NGN -- ^ Nigerian Naira     | IDR -- ^ Indonesian Rupiah-    | SGD -- ^ Singapore Dollar+    | BCH -- ^ Bitcoin Cash+    | ETH -- ^ Ether   deriving (Show, Generic, Eq, Data, Typeable, Ord)  instance NFData Asset@@ -252,7 +241,7 @@ -- | A single placed order in the orderbook data Order = Order {     orderVolume :: Scientific,-    orderPrice :: Int+    orderPrice :: Scientific     } deriving (Eq, Show, Generic, Data, Typeable, Ord)  instance NFData Order@@ -280,7 +269,7 @@ data Trade = Trade {     tradeTimestamp :: UTCTime,     tradeVolume :: Scientific,-    tradePrice :: Int,+    tradePrice :: Scientific,     tradeIsBuy :: Bool     } deriving (Eq, Show, Generic, Data, Typeable, Ord) @@ -326,7 +315,7 @@          privateOrderCompletedTimestamp :: UTCTime,          privateOrderFeeBase :: Scientific,          privateOrderFeeCounter :: Scientific,-         privateOrderLimitPrice :: Int,+         privateOrderLimitPrice :: Scientific,          privateOrderLimitVolume :: Scientific,          privateOrderId :: OrderID,          privateOrderPair :: CcyPair,@@ -357,15 +346,15 @@         {orderRequestPair :: CcyPair,          orderRequestOrderType :: OrderType,          orderRequestVolume :: Scientific,-         orderRequestPrice :: Int } deriving (Eq, Show, Generic, Data, Typeable, Ord)+         orderRequestPrice :: Scientific } deriving (Eq, Show, Generic, Data, Typeable, Ord)  instance NFData OrderRequest  makeFields ''OrderRequest --- |@mkOrderRequest = OrderRequest ZARXBT BID 0 0@+-- |@mkOrderRequest = OrderRequest XBTZAR BID 0 0@ mkOrderRequest :: OrderRequest-mkOrderRequest = OrderRequest ZARXBT BID 0 0+mkOrderRequest = OrderRequest XBTZAR BID 0 0  data MarketOrderRequest = MarketOrderRequest         {marketOrderRequestPair :: CcyPair,@@ -376,9 +365,9 @@  makeFields ''MarketOrderRequest --- |@mkMarketOrderRequest = MarketOrderRequest ZARXBT BID 0@+-- |@mkMarketOrderRequest = MarketOrderRequest XBTZAR BID 0@ mkMarketOrderRequest :: MarketOrderRequest-mkMarketOrderRequest = MarketOrderRequest ZARXBT BID 0+mkMarketOrderRequest = MarketOrderRequest XBTZAR BID 0  -- | The current balance of a private account. data Balance = Balance@@ -452,9 +441,9 @@  makeFields ''QuoteRequest --- |@mkQuoteRequest = QuoteRequest BUY ZARXBT 0@+-- |@mkQuoteRequest = QuoteRequest BUY XBTZAR 0@ mkQuoteRequest :: QuoteRequest-mkQuoteRequest = QuoteRequest BUY ZARXBT 0+mkQuoteRequest = QuoteRequest BUY XBTZAR 0  -- | A temporarily locked-in quote. data OrderQuote = OrderQuote@@ -496,7 +485,7 @@     privateTradeIsBuy :: Bool,     privateTradeOrderId :: Text,     privateTradePair :: CcyPair,-    privateTradePrice :: Int,+    privateTradePrice :: Scientific,     privateTradeTimestamp :: UTCTime,     privateTradeOrderType :: OrderType,     privateTradeVolume :: Scientific@@ -524,4 +513,3 @@ instance FromJSON WithdrawalType  instance FromJSON QuoteType-
src/Network/Bitcoin/BitX/Types/Internal.hs view
@@ -29,10 +29,10 @@ import Data.Scientific (Scientific) import Data.ByteString (ByteString) import Data.List.Split (splitOn)-import qualified Data.ByteString.Char8 as BS8 (pack) #if __GLASGOW_HASKELL__ >= 708 import Data.Coerce #endif+import Data.Maybe (fromMaybe) import Test.QuickCheck  {-# ANN module ("HLint: ignore Use camelCase" :: String) #-}@@ -78,18 +78,12 @@ -- | Wrappers around Scientific and Int, and FromJSON instance, to facilitate automatic JSON instances  newtype QuotedScientific = QuotedScientific Scientific deriving (Read, Show)-newtype QuotedInt = QuotedInt Int deriving (Read, Show)  instance FromJSON QuotedScientific where    parseJSON (String x) = return . QuotedScientific . read . Txt.unpack $ x    parseJSON (Number x) = return . QuotedScientific . read . show $ x    parseJSON _          = mempty -instance FromJSON QuotedInt where-   parseJSON (String x) = return . QuotedInt . (truncate :: Scientific -> Int) . read . Txt.unpack $ x-   parseJSON (Number x) = return . QuotedInt . (truncate :: Scientific -> Int) . read . show $ x-   parseJSON _          = mempty- qsToScientific :: QuotedScientific -> Scientific #if __GLASGOW_HASKELL__ >= 708 qsToScientific = coerce@@ -98,14 +92,6 @@ qsToScientific (QuotedScientific sci) = sci #endif -qiToInt :: QuotedInt -> Int-#if __GLASGOW_HASKELL__ >= 708-qiToInt = coerce-{-# INLINE qiToInt #-}-#else-qiToInt (QuotedInt i) = i-#endif- -- | Wrapper around UTCTime and FromJSON instance, to facilitate automatic JSON instances  newtype TimestampMS = TimestampMS Integer deriving (Read, Show)@@ -154,9 +140,9 @@  data Ticker_ = Ticker_     { ticker'timestamp :: TimestampMS-    , ticker'bid :: Maybe QuotedInt-    , ticker'ask :: Maybe QuotedInt-    , ticker'last_trade :: Maybe QuotedInt+    , ticker'bid :: Maybe QuotedScientific+    , ticker'ask :: Maybe QuotedScientific+    , ticker'last_trade :: Maybe QuotedScientific     , ticker'rolling_24_hour_volume :: QuotedScientific     , ticker'pair :: Types.CcyPair     }@@ -168,9 +154,9 @@     type Aes Types.Ticker = Ticker_     aesToRec Ticker_ {..} =         Types.Ticker {tickerTimestamp = tsmsToUTCTime ticker'timestamp,-                  tickerBid = fmap qiToInt ticker'bid,-                  tickerAsk = fmap qiToInt ticker'ask,-                  tickerLastTrade = fmap qiToInt ticker'last_trade,+                  tickerBid = fmap qsToScientific ticker'bid,+                  tickerAsk = fmap qsToScientific ticker'ask,+                  tickerLastTrade = fmap qsToScientific ticker'last_trade,                   tickerRolling24HourVolume = qsToScientific ticker'rolling_24_hour_volume,                   tickerPair = ticker'pair} @@ -206,7 +192,7 @@  data Order_ = Order_     { order'volume :: QuotedScientific,-      order'price :: QuotedInt+      order'price :: QuotedScientific     }  $(AesTH.deriveFromJSON AesTH.defaultOptions{AesTH.fieldLabelModifier = last . splitOn "'"} ''Order_)@@ -215,7 +201,7 @@     type Aes Types.Order = Order_     aesToRec Order_ {..} =         Types.Order {orderVolume = qsToScientific order'volume,-              orderPrice = qiToInt order'price}+              orderPrice = qsToScientific order'price}  -------------------------------------------- Orderbook type ---------------------------------------- @@ -243,7 +229,7 @@ data Trade_ = Trade_     { trade'volume :: QuotedScientific     , trade'timestamp :: TimestampMS-    , trade'price :: QuotedInt+    , trade'price :: QuotedScientific     , trade'is_buy :: Bool     } @@ -255,7 +241,7 @@     aesToRec Trade_ {..} =         Types.Trade { tradeTimestamp = tsmsToUTCTime trade'timestamp,             tradeVolume = qsToScientific trade'volume,-            tradePrice = qiToInt trade'price,+            tradePrice = qsToScientific trade'price,             tradeIsBuy = trade'is_buy}  ----------------------------------------- PublicTrades type ----------------------------------------@@ -282,7 +268,7 @@     , privateOrder'completed_timestamp :: TimestampMS     , privateOrder'fee_base :: QuotedScientific     , privateOrder'fee_counter :: QuotedScientific-    , privateOrder'limit_price :: QuotedInt+    , privateOrder'limit_price :: QuotedScientific     , privateOrder'limit_volume :: QuotedScientific     , privateOrder'order_id :: Types.OrderID     , privateOrder'pair :: Types.CcyPair@@ -303,7 +289,7 @@                   privateOrderCompletedTimestamp = tsmsToUTCTime privateOrder'completed_timestamp,                   privateOrderFeeBase = qsToScientific privateOrder'fee_base,                   privateOrderFeeCounter = qsToScientific privateOrder'fee_counter,-                  privateOrderLimitPrice = qiToInt privateOrder'limit_price,+                  privateOrderLimitPrice = qsToScientific privateOrder'limit_price,                   privateOrderLimitVolume = qsToScientific privateOrder'limit_volume,                   privateOrderId = privateOrder'order_id,                   privateOrderPair = privateOrder'pair,@@ -313,7 +299,7 @@ ------------------------------------------ PrivateOrders type --------------------------------------  data PrivateOrders_ = PrivateOrders_-    {privateOrders'orders :: [PrivateOrder_]+    {privateOrders'orders :: Maybe [PrivateOrder_]     }  $(AesTH.deriveFromJSON AesTH.defaultOptions{AesTH.fieldLabelModifier = last . splitOn "'"}@@ -322,7 +308,7 @@ instance BitXAesRecordConvert [Types.PrivateOrder] where     type Aes [Types.PrivateOrder] = PrivateOrders_     aesToRec PrivateOrders_ {..} =-        map aesToRec privateOrders'orders+        map aesToRec (fromMaybe [] privateOrders'orders)  ------------------------------------------ OrderRequest type --------------------------------------- @@ -331,7 +317,7 @@         [("pair", showableToBytestring_ (oreq ^. Types.pair)),          ("type", showableToBytestring_ (oreq ^. Types.orderType)),          ("volume", realToDecimalByteString_ (oreq ^. Types.volume)),-         ("price", BS8.pack . show $ (oreq ^. Types.price))]+         ("price", realToDecimalByteString_ (oreq ^. Types.price))]  -------------------------------------------- OrderIDRec type --------------------------------------- @@ -631,7 +617,7 @@     , privateTrade'is_buy :: Bool     , privateTrade'order_id :: Types.OrderID     , privateTrade'pair :: Types.CcyPair-    , privateTrade'price :: QuotedInt+    , privateTrade'price :: QuotedScientific     , privateTrade'timestamp :: TimestampMS     , privateTrade'type :: OrderType_     , privateTrade'volume :: QuotedScientific@@ -650,7 +636,7 @@                   privateTradeIsBuy = privateTrade'is_buy,                   privateTradeOrderId = privateTrade'order_id,                   privateTradePair = privateTrade'pair,-                  privateTradePrice = qiToInt privateTrade'price,+                  privateTradePrice = qsToScientific privateTrade'price,                   privateTradeTimestamp = tsmsToUTCTime privateTrade'timestamp,                   privateTradeOrderType = orderTypeParse privateTrade'type,                   privateTradeVolume = qsToScientific privateTrade'volume}@@ -658,7 +644,7 @@ ----------------------------------------- PrivateTrades type ----------------------------------------  data PrivateTrades_ = PrivateTrades_-    { privateTrades'trades :: [PrivateTrade_]+    { privateTrades'trades :: Maybe [PrivateTrade_]     }  $(AesTH.deriveFromJSON AesTH.defaultOptions{AesTH.fieldLabelModifier = last . splitOn "'"}@@ -667,7 +653,7 @@ instance BitXAesRecordConvert [Types.PrivateTrade] where     type Aes [Types.PrivateTrade] = PrivateTrades_     aesToRec PrivateTrades_ {..} =-        map aesToRec privateTrades'trades+        map aesToRec (fromMaybe [] privateTrades'trades)  -------------------------------------------- FeeInfo type ------------------------------------------- 
test/Example.hs view
@@ -12,7 +12,7 @@     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.")+        Just p               -> putStrLn ("1 bitcoin will set you back ZAR" ++ show p ++ ".")     ErrorResponse err        ->         error $ "BitX error received: \"" ++ unpack (err ^. BitX.error) ++ "\""     ExceptionResponse ex     ->
test/Network/Bitcoin/BitX/Spec/Specs/AesonRecordSpec.hs view
@@ -85,7 +85,7 @@       recordAesCheck         "{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \             \ \"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\-            \ \"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"NADXBT\",\+            \ \"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"XBTMYR\",\             \ \"state\":\"COMPLETE\",\"type\":\"BID\"}"         PrivateOrder             {privateOrderBase = 568.7,@@ -98,16 +98,21 @@              privateOrderLimitPrice = 765,              privateOrderLimitVolume = 55.2,              privateOrderId = "83YG",-             privateOrderPair = NADXBT,+             privateOrderPair = XBTMYR,              privateOrderState = COMPLETE,              privateOrderOrderType = BID}-    it "PrivateOrders is parsed properly" $-      recordAesCheck-        "{\"orders\":[{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \-            \ \"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\-            \ \"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"NADXBT\",\-            \ \"state\":\"COMPLETE\",\"type\":\"BID\"}]}"-        [privateOrderInner]+    describe "PrivateOrders" $ do+      it "PrivateOrders is parsed properly" $+        recordAesCheck+          "{\"orders\":[{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \+              \ \"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\+              \ \"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"XBTMYR\",\+              \ \"state\":\"COMPLETE\",\"type\":\"BID\"}]}"+          [privateOrderInner]+      it "parses null as an empty list" $+        recordAesCheck+          "{\"orders\":null}"+          ([] :: [PrivateOrder])     it "OrderID is parsed properly" $       recordAesCheck         "{\"order_id\":\"57983\"}"@@ -173,12 +178,17 @@              privateTradeTimestamp = posixSecondsToUTCTime 1467138492.909,              privateTradeOrderType = BID,              privateTradeVolume = 0.147741}-    it "PrivateTrades is parsed properly" $-      recordAesCheck-        "{\"trades\":[{\"base\": \"0.147741\", \"counter\": \"1549.950831\", \"fee_base\": \"0.90\", \"fee_counter\": \"0.00\", \-            \ \"is_buy\": false, \"order_id\": \"BXMC2CJ7HNB88U4\", \"pair\": \"XBTZAR\", \"price\": \"10491.00\", \-            \ \"timestamp\": 1467138492909, \"type\": \"BID\", \"volume\": \"0.147741\" }]}"-         [privateTradeInner]+    describe "PrivateTrades" $ do+      it "parses a canned example correctly" $+        recordAesCheck+          "{\"trades\":[{\"base\": \"0.147741\", \"counter\": \"1549.950831\", \"fee_base\": \"0.90\", \"fee_counter\": \"0.00\", \+              \ \"is_buy\": false, \"order_id\": \"BXMC2CJ7HNB88U4\", \"pair\": \"XBTZAR\", \"price\": \"10491.00\", \+              \ \"timestamp\": 1467138492909, \"type\": \"BID\", \"volume\": \"0.147741\" }]}"+           [privateTradeInner]+      it "parses null as an empty list" $+        recordAesCheck+          "{\"trades\":null}"+          ([] :: [PrivateTrade])     it "FeeInfo is parsed properly" $       recordAesCheck         "{\"maker_fee\": \"0.00\", \"taker_fee\": \"0.10\", \"thirty_day_volume\": \"0.894342\"}"@@ -221,7 +231,7 @@         privateOrderLimitPrice = 765,         privateOrderLimitVolume = 55.2,         privateOrderId = "83YG",-        privateOrderPair = NADXBT,+        privateOrderPair = XBTMYR,         privateOrderState = COMPLETE,         privateOrderOrderType = BID} 
test/Network/Bitcoin/BitX/Spec/Specs/JsonSpec.hs view
@@ -29,19 +29,11 @@       recordAesCheck         "{\"volume\":314159,\"price\":\"4321\"}"         (Order 314159 4321)-    it "QuotedInt is parsed when quoted" $-      recordAesCheck-        "{\"volume\":0,\"price\":\"4321.00\"}"-        (Order 0 4321)-    it "QuotedInt is parsed when not quoted" $-      recordAesCheck-        "{\"volume\":0,\"price\":4321.00}"-        (Order 0 4321)     it "OrderType BUY is parsed properly" $       recordAesCheck         "{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \             \\"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\-            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"NADXBT\",\+            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"XBTMYR\",\             \\"state\":\"COMPLETE\",\"type\":\"BUY\"}"         PrivateOrder             {privateOrderBase = 568.7,@@ -54,14 +46,14 @@              privateOrderLimitPrice = 765,              privateOrderLimitVolume = 55.2,              privateOrderId = "83YG",-             privateOrderPair = NADXBT,+             privateOrderPair = XBTMYR,              privateOrderState = COMPLETE,              privateOrderOrderType = BID }     it "OrderType BID is parsed properly" $       recordAesCheck         "{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \             \\"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\-            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"NADXBT\",\+            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"XBTMYR\",\             \\"state\":\"COMPLETE\",\"type\":\"BID\"}"         PrivateOrder             {privateOrderBase = 568.7,@@ -74,14 +66,14 @@              privateOrderLimitPrice = 765,              privateOrderLimitVolume = 55.2,              privateOrderId = "83YG",-             privateOrderPair = NADXBT,+             privateOrderPair = XBTMYR,              privateOrderState = COMPLETE,              privateOrderOrderType = BID }     it "OrderType ASK is parsed properly" $       recordAesCheck         "{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \             \\"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\-            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"NADXBT\",\+            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"XBTMYR\",\             \\"state\":\"COMPLETE\",\"type\":\"ASK\"}"         PrivateOrder             {privateOrderBase = 568.7,@@ -94,14 +86,14 @@              privateOrderLimitPrice = 765,              privateOrderLimitVolume = 55.2,              privateOrderId = "83YG",-             privateOrderPair = NADXBT,+             privateOrderPair = XBTMYR,              privateOrderState = COMPLETE,              privateOrderOrderType = ASK }     it "OrderType SELL is parsed properly" $       recordAesCheck         "{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \             \\"expiration_timestamp\":8768834222, \"completed_timestamp\":6511257825, \"fee_base\":\"3687.3\", \"fee_counter\":12.9,\-            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"NADXBT\",\+            \\"limit_price\":765.00,\"limit_volume\":55.2,\"order_id\":\"83YG\",\"pair\":\"XBTMYR\",\             \\"state\":\"COMPLETE\",\"type\":\"SELL\"}"         PrivateOrder             {privateOrderBase = 568.7,@@ -114,7 +106,7 @@              privateOrderLimitPrice = 765,              privateOrderLimitVolume = 55.2,              privateOrderId = "83YG",-             privateOrderPair = NADXBT,+             privateOrderPair = XBTMYR,              privateOrderState = COMPLETE,              privateOrderOrderType = ASK }     it "RequestStatus COMPLETE is parsed properly" $
test/Network/Bitcoin/BitX/Spec/Specs/NetSpec.hs view
@@ -22,7 +22,7 @@     it "getOrderBook connects to BitX and works" $       connectsAndParsesOkay $ getOrderBook XBTZAR     it "getTrades connects to BitX and works" $-      connectsAndParsesOkay $ getTrades Nothing XBTKES+      connectsAndParsesOkay $ getTrades Nothing XBTMYR  connectsAndParsesOkay :: IO (BitXAPIResponse recd) -> Bool connectsAndParsesOkay = isValidResponse . unsafePerformIO
test/Network/Bitcoin/BitX/Spec/Specs/PostSpec.hs view
@@ -64,11 +64,11 @@         postEncode           QuoteRequest             {quoteRequestQuoteType = BUY,-             quoteRequestPair = XBTKES,+             quoteRequestPair = XBTMYR,              quoteRequestBaseAmount = 566.76}       `shouldBe`         [("type", "BUY"),-         ("pair", "XBTKES"),+         ("pair", "XBTMYR"),          ("base_amount", "566.76")]     it "MarketOrderRequest for buy is post-encoded properly" $         postEncode