bitx-bitcoin 0.6.0.0 → 0.7.0.0
raw patch · 9 files changed
+78/−53 lines, 9 filesdep +QuickCheckPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck
API changes (from Hackage documentation)
+ Network.Bitcoin.BitX: aesToRec :: BitXAesRecordConvert recd => Aes recd -> recd
+ Network.Bitcoin.BitX: class FromJSON (Aes recd) => BitXAesRecordConvert recd where type family Aes recd
+ Network.Bitcoin.BitX.Types: IDR :: Asset
+ Network.Bitcoin.BitX.Types: IDRXBT :: CcyPair
+ Network.Bitcoin.BitX.Types: XBTIDR :: CcyPair
+ Network.Bitcoin.BitX.Types: [tradeIsBuy] :: Trade -> Bool
+ Network.Bitcoin.BitX.Types: class HasIsBuy s a | s -> a
+ Network.Bitcoin.BitX.Types: instance GHC.Generics.Constructor Network.Bitcoin.BitX.Types.C1_10CcyPair
+ Network.Bitcoin.BitX.Types: instance GHC.Generics.Constructor Network.Bitcoin.BitX.Types.C1_11CcyPair
+ Network.Bitcoin.BitX.Types: instance GHC.Generics.Constructor Network.Bitcoin.BitX.Types.C1_6Asset
+ Network.Bitcoin.BitX.Types: instance Network.Bitcoin.BitX.Types.HasIsBuy Network.Bitcoin.BitX.Types.Trade GHC.Types.Bool
+ Network.Bitcoin.BitX.Types: isBuy :: HasIsBuy s a => Lens' s a
- Network.Bitcoin.BitX.Public: getTrades :: CcyPair -> IO (BitXAPIResponse [Trade])
+ Network.Bitcoin.BitX.Public: getTrades :: Maybe UTCTime -> CcyPair -> IO (BitXAPIResponse [Trade])
- Network.Bitcoin.BitX.Types: Trade :: UTCTime -> Scientific -> Int -> Trade
+ Network.Bitcoin.BitX.Types: Trade :: UTCTime -> Scientific -> Int -> Bool -> Trade
Files
- CHANGES +5/−2
- bitx-bitcoin.cabal +2/−1
- src/Network/Bitcoin/BitX/Public.hs +5/−2
- src/Network/Bitcoin/BitX/Types.hs +7/−2
- src/Network/Bitcoin/BitX/Types/Internal.hs +47/−32
- test/Doctests.hs +1/−1
- test/Network/Bitcoin/BitX/Spec/Specs/AesonRecordSpec.hs +7/−10
- test/Network/Bitcoin/BitX/Spec/Specs/LensSpec.hs +3/−2
- test/Network/Bitcoin/BitX/Spec/Specs/NetSpec.hs +1/−1
CHANGES view
@@ -1,3 +1,8 @@+v0.7.0.0+* Added new "since" option to public trades' endpoint. BREAKING CHANGE.+* Added is_buy field for trade record.+* Added Indonesian Rupiah.+ v0.6.0.0 * Added the new endpoint for creating market (spot) orders. * Replaced http-conduit with http-client and http-client-tls.@@ -5,8 +10,6 @@ v0.5.0.1 * A few more major bugfixes w.r.t. to BitX number formatting.--v0.5.0.1 * Fixed issue due to BitX's handling of ints as decimal. v0.5.0.0
bitx-bitcoin.cabal view
@@ -1,5 +1,5 @@ name: bitx-bitcoin-version: 0.6.0.0+version: 0.7.0.0 synopsis: A Haskell library for working with the BitX bitcoin exchange. description:@@ -67,6 +67,7 @@ time, bytestring, network,+ QuickCheck >= 2.8, split >= 0.2.0.0, scientific, http-client >= 0.4.6.1,
src/Network/Bitcoin/BitX/Public.hs view
@@ -47,7 +47,9 @@ import Network.Bitcoin.BitX.Internal import Network.Bitcoin.BitX.Types+import Network.Bitcoin.BitX.Types.Internal import Network.Bitcoin.BitX.Response+import Data.Time.Clock (UTCTime) {- | Returns the latest ticker indicators. -} @@ -69,5 +71,6 @@ {- | Returns a list of the most recent trades -} -getTrades :: CcyPair -> IO (BitXAPIResponse [Trade])-getTrades cyp = simpleBitXGet_ $ "trades?pair=" ++ show cyp+getTrades :: Maybe UTCTime -> CcyPair -> IO (BitXAPIResponse [Trade])+getTrades Nothing cyp = simpleBitXGet_ $ "trades?pair=" ++ show cyp+getTrades (Just since) cyp = simpleBitXGet_ $ "trades?pair=" ++ show cyp ++ "since=" ++ show (timeToTimestamp since)
src/Network/Bitcoin/BitX/Types.hs view
@@ -123,7 +123,8 @@ HasExpiresAt(..), HasDiscarded(..), HasExercised(..),- HasName(..)+ HasName(..),+ HasIsBuy(..) ) where import Data.Aeson (FromJSON(..))@@ -176,6 +177,8 @@ | 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 deriving (Show, Generic, Eq) -- | The state of a single market, identified by the currency pair.@@ -200,6 +203,7 @@ | KES -- ^ Kenyan Shilling | MYR -- ^ Malaysian Ringgit | NGN -- ^ Nigerian Naira+ | IDR -- ^ Indonesian Rupiah deriving (Show, Generic, Eq) -- | The type of a withdrawal request.@@ -242,7 +246,8 @@ data Trade = Trade { tradeTimestamp :: UTCTime, tradeVolume :: Scientific,- tradePrice :: Int+ tradePrice :: Int,+ tradeIsBuy :: Bool } deriving (Eq, Show) makeFields ''Trade
src/Network/Bitcoin/BitX/Types/Internal.hs view
@@ -1,12 +1,13 @@ {-# LANGUAGE QuasiQuotes, OverloadedStrings, TemplateHaskell, TypeFamilies, FlexibleContexts,- FlexibleInstances, DataKinds, CPP, RecordWildCards #-}+ FlexibleInstances, DataKinds, CPP, RecordWildCards, GeneralizedNewtypeDeriving #-} module Network.Bitcoin.BitX.Types.Internal ( BitXAesRecordConvert(..), POSTEncodeable(..), Transaction_(..),- pendingTransactionsToTransactions+ pendingTransactionsToTransactions,+ timeToTimestamp ) where @@ -18,7 +19,7 @@ import qualified Data.Text.Encoding as Txt import Data.Text (Text) import Data.Time.Clock (UTCTime)-import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds) import Lens.Micro ((^.)) #if __GLASGOW_HASKELL__ >= 710 -- base 4.8+ (GHC 7.10+) re-exports Monoid and its functions/constants@@ -32,18 +33,33 @@ #if __GLASGOW_HASKELL__ >= 708 import Data.Coerce #endif+import Test.QuickCheck {-# ANN module ("HLint: ignore Use camelCase" :: String) #-} +newtype UnixStampMS = UnixStampMS {unUnixStampMS_ :: Integer} deriving (Eq, Ord, Show, Num, Integral, Real, Enum)++instance Arbitrary UnixStampMS where+ arbitrary = do+ k <- choose (1225497600000, 32782406400000) -- 1 Nov 2008 00:00:00 to 1 Nov 3008 00:00:00+ return $ UnixStampMS k+ timestampParse_ :: Integer -> UTCTime timestampParse_ = posixSecondsToUTCTime . realToFrac . ( / 1000) . (fromIntegral :: Integer -> Scientific) ---class (FromJSON aes) => BitXAesRecordConvert recd aes | recd -> aes where--- aesToRec :: aes -> recd+timeToTimestamp :: UTCTime -> Integer+timeToTimestamp = truncate . (* 1000). utcTimeToPOSIXSeconds +-- $setup+-- >>> import Test.QuickCheck++-- |+-- prop> \ n -> (timeToTimestamp $ timestampParse_ $ unUnixStampMS_ n) == unUnixStampMS_ n+--+ class FromJSON (Aes recd) => BitXAesRecordConvert recd where type Aes recd aesToRec :: Aes recd -> recd@@ -55,9 +71,6 @@ showableToBytestring_ :: Show a => a -> ByteString showableToBytestring_ = Txt.encodeUtf8 . Txt.pack . show ---realToDecimalByteString_ :: Real a => a -> ByteString---realToDecimalByteString_ k = pack . reverse . dropWhile (== '0') . reverse $ (showFFloat (Just 6) . (fromRational :: Rational -> Double) . toRational $ k) ""- -- | Wrappers around Scientific and Int, and FromJSON instance, to facilitate automatic JSON instances newtype QuotedScientific = QuotedScientific Scientific deriving (Read, Show)@@ -149,7 +162,7 @@ instance BitXAesRecordConvert Types.Ticker where type Aes Types.Ticker = Ticker_- aesToRec (Ticker_ {..}) =+ aesToRec Ticker_ {..} = Types.Ticker {tickerTimestamp = tsmsToUTCTime ticker'timestamp, tickerBid = qiToInt ticker'bid, tickerAsk = qiToInt ticker'ask,@@ -168,7 +181,7 @@ instance BitXAesRecordConvert [Types.Ticker] where type Aes [Types.Ticker] = Tickers_- aesToRec (Tickers_ {..}) =+ aesToRec Tickers_ {..} = map aesToRec tickers'tickers -------------------------------------------- BitXError type ----------------------------------------@@ -182,7 +195,7 @@ instance BitXAesRecordConvert Types.BitXError where type Aes Types.BitXError = BitXError_- aesToRec (BitXError_ {..}) =+ aesToRec BitXError_ {..} = Types.BitXError { bitXErrorError = bitXError'error, bitXErrorErrorCode = bitXError'error_code} -------------------------------------------- Order type --------------------------------------------@@ -196,7 +209,7 @@ instance BitXAesRecordConvert Types.Order where type Aes Types.Order = Order_- aesToRec (Order_ {..}) =+ aesToRec Order_ {..} = Types.Order {orderVolume = qsToScientific order'volume, orderPrice = qiToInt order'price} @@ -216,7 +229,7 @@ instance BitXAesRecordConvert Types.Orderbook where type Aes Types.Orderbook = Orderbook_- aesToRec (Orderbook_ {..}) =+ aesToRec Orderbook_ {..} = Types.Orderbook {orderbookTimestamp = tsmsToUTCTime orderbook'timestamp, orderbookBids = map aesToRec orderbook'bids, orderbookAsks = map aesToRec orderbook'asks}@@ -227,6 +240,7 @@ { trade'volume :: QuotedScientific , trade'timestamp :: TimestampMS , trade'price :: QuotedInt+ , trade'is_buy :: Bool } $(AesTH.deriveFromJSON AesTH.defaultOptions{AesTH.fieldLabelModifier = last . splitOn "'"}@@ -234,10 +248,11 @@ instance BitXAesRecordConvert Types.Trade where type Aes Types.Trade = Trade_- aesToRec (Trade_ {..}) =+ aesToRec Trade_ {..} = Types.Trade { tradeTimestamp = tsmsToUTCTime trade'timestamp, tradeVolume = qsToScientific trade'volume,- tradePrice = qiToInt trade'price }+ tradePrice = qiToInt trade'price,+ tradeIsBuy = trade'is_buy} ----------------------------------------- PublicTrades type ---------------------------------------- @@ -250,7 +265,7 @@ instance BitXAesRecordConvert [Types.Trade] where type Aes [Types.Trade] = PublicTrades_- aesToRec (PublicTrades_ {..}) =+ aesToRec PublicTrades_ {..} = map aesToRec publicTrades'trades ------------------------------------------ PrivateOrder type ---------------------------------------@@ -275,7 +290,7 @@ instance BitXAesRecordConvert Types.PrivateOrder where type Aes Types.PrivateOrder = PrivateOrder_- aesToRec (PrivateOrder_ {..}) =+ aesToRec PrivateOrder_ {..} = Types.PrivateOrder {privateOrderBase = qsToScientific privateOrder'base, privateOrderCounter = qsToScientific privateOrder'counter, privateOrderCreationTimestamp = tsmsToUTCTime privateOrder'creation_timestamp,@@ -300,7 +315,7 @@ instance BitXAesRecordConvert [Types.PrivateOrder] where type Aes [Types.PrivateOrder] = PrivateOrders_- aesToRec (PrivateOrders_ {..}) =+ aesToRec PrivateOrders_ {..} = map aesToRec privateOrders'orders ------------------------------------------ OrderRequest type ---------------------------------------@@ -323,7 +338,7 @@ instance BitXAesRecordConvert Types.OrderID where type Aes Types.OrderID = OrderIDRec_- aesToRec (OrderIDRec_ {..}) =+ aesToRec OrderIDRec_ {..} = orderIDResponse'order_id instance POSTEncodeable Types.OrderID where@@ -341,7 +356,7 @@ instance BitXAesRecordConvert Types.RequestSuccess where type Aes Types.RequestSuccess = RequestSuccess_- aesToRec (RequestSuccess_ {..}) =+ aesToRec RequestSuccess_ {..} = requestSuccess'success ------------------------------------- PrivateOrderWithTrades type ----------------------------------@@ -367,7 +382,7 @@ instance BitXAesRecordConvert Types.PrivateOrderWithTrades where type Aes Types.PrivateOrderWithTrades = PrivateOrderWithTrades_- aesToRec (PrivateOrderWithTrades_ {..}) =+ aesToRec PrivateOrderWithTrades_ {..} = Types.PrivateOrderWithTrades {privateOrderWithTradesBase = qsToScientific privateOrderWithTrades'base, privateOrderWithTradesCounter = qsToScientific privateOrderWithTrades'counter, privateOrderWithTradesCreationTimestamp = tsmsToUTCTime privateOrderWithTrades'creation_timestamp,@@ -397,7 +412,7 @@ instance BitXAesRecordConvert Types.Balance where type Aes Types.Balance = Balance_- aesToRec (Balance_ {..}) =+ aesToRec Balance_ {..} = Types.Balance {balanceId = balance'account_id, balanceAsset = balance'asset, balanceBalance = qsToScientific balance'balance,@@ -415,7 +430,7 @@ instance BitXAesRecordConvert [Types.Balance] where type Aes [Types.Balance] = Balances_- aesToRec (Balances_ {..}) =+ aesToRec Balances_ {..} = map aesToRec balances'balance ----------------------------------------- FundingAddress type --------------------------------------@@ -432,7 +447,7 @@ instance BitXAesRecordConvert Types.FundingAddress where type Aes Types.FundingAddress = FundingAddress_- aesToRec (FundingAddress_ {..}) =+ aesToRec FundingAddress_ {..} = Types.FundingAddress {fundingAddressAsset = fundingAdress'asset, fundingAddressAddress = fundingAdress'address, fundingAddressTotalReceived = qsToScientific fundingAdress'total_received,@@ -456,7 +471,7 @@ instance BitXAesRecordConvert Types.WithdrawalRequest where type Aes Types.WithdrawalRequest = WithdrawalRequest_- aesToRec (WithdrawalRequest_ {..}) =+ aesToRec WithdrawalRequest_ {..} = Types.WithdrawalRequest {withdrawalRequestStatus = requestStatusParse withdrawalRequest'status, withdrawalRequestId = withdrawalRequest'id} @@ -471,7 +486,7 @@ instance BitXAesRecordConvert [Types.WithdrawalRequest] where type Aes [Types.WithdrawalRequest] = WithdrawalRequests_- aesToRec (WithdrawalRequests_ {..}) =+ aesToRec WithdrawalRequests_ {..} = map aesToRec withdrawalRequests'withdrawals ----------------------------------------- NewWithdrawal type ---------------------------------------@@ -521,7 +536,7 @@ instance BitXAesRecordConvert Types.OrderQuote where type Aes Types.OrderQuote = OrderQuote_- aesToRec (OrderQuote_ {..}) =+ aesToRec OrderQuote_ {..} = Types.OrderQuote {orderQuoteId = orderQuote'id, orderQuoteQuoteType = orderQuote'type, orderQuotePair = orderQuote'pair,@@ -544,7 +559,7 @@ instance BitXAesRecordConvert Types.BitXAuth where type Aes Types.BitXAuth = BitXAuth_- aesToRec (BitXAuth_ {..}) =+ aesToRec BitXAuth_ {..} = Types.BitXAuth {bitXAuthId = bitXAuth'api_key_id, bitXAuthSecret = bitXAuth'api_key_secret} @@ -566,7 +581,7 @@ instance BitXAesRecordConvert Types.Transaction where type Aes Types.Transaction = Transaction_- aesToRec (Transaction_ {..}) =+ aesToRec Transaction_ {..} = Types.Transaction {transactionRowIndex = transaction'row_index, transactionTimestamp = tsmsToUTCTime transaction'timestamp, transactionBalance = qsToScientific transaction'balance,@@ -587,7 +602,7 @@ instance BitXAesRecordConvert [Types.Transaction] where type Aes [Types.Transaction] = Transactions_- aesToRec (Transactions_ {..}) =+ aesToRec Transactions_ {..} = map aesToRec transactions'transactions @@ -600,7 +615,7 @@ instance BitXAesRecordConvert PendingTransactions__ where type Aes PendingTransactions__ = PendingTransactions_- aesToRec (PendingTransactions_ {..}) =+ aesToRec PendingTransactions_ {..} = PendingTransactions__ {pendingTransactions__transactions = map aesToRec transactions'pending} data PendingTransactions__ = PendingTransactions__@@ -622,7 +637,7 @@ instance BitXAesRecordConvert Types.Account where type Aes Types.Account = Account_- aesToRec (Account_ {..}) =+ aesToRec Account_ {..} = Types.Account {accountId = account'id, accountName = account'name, accountCurrency = account'currency}
test/Doctests.hs view
@@ -1,3 +1,3 @@ import Test.DocTest -main = doctest ["-isrc", "src/Network/Bitcoin/BitX/Types/Internal/Decimal.hs"]+main = doctest ["-isrc", "src/Network/Bitcoin/BitX/Types/Internal/Decimal.hs","src/Network/Bitcoin/BitX/Types/Internal.hs"]
test/Network/Bitcoin/BitX/Spec/Specs/AesonRecordSpec.hs view
@@ -64,16 +64,12 @@ orderbookAsks = [orderInner]} it "Trade is parsed properly" $ recordAesCheck- "{\"timestamp\":1431811395699,\"volume\":\"6754.09\",\"price\":\"5327.00\"}"+ "{\"timestamp\":1431811395699,\"volume\":\"6754.09\",\"price\":\"5327.00\", \"is_buy\": true}" Trade {tradeTimestamp = posixSecondsToUTCTime 1431811395.699, tradeVolume = 6754.09,- tradePrice = 5327}- it "PublicTrades is parsed properly" $- recordAesCheck- "{\"trades\":[{\"timestamp\":1431811395699,\"volume\":\"6754.09\",\- \ \"price\":\"5327.00\"}],\"currency\":\"ZAR\"}"- [tradeInner]+ tradePrice = 5327,+ tradeIsBuy = True} it "PrivateOrder is parsed properly" $ recordAesCheck "{\"base\":\"568.7\", \"counter\":3764.2,\"creation_timestamp\":478873467, \@@ -106,7 +102,7 @@ ("57983" :: OrderID) it "PublicTrades is parsed properly" $ recordAesCheck- "{\"trades\":[{\"timestamp\":1431811395699,\"volume\":\"6754.09\",\"price\":\"5327.00\"}], \+ "{\"trades\":[{\"timestamp\":1431811395699,\"volume\":\"6754.09\",\"price\":\"5327.00\",\"is_buy\":false}], \ \ \"currency\":\"ZAR\"}" [tradeInner] it "RequestSuccess is parsed properly" $@@ -119,7 +115,7 @@ \ \"expiration_timestamp\":8768834222, \"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\", \"trades\":[{\"timestamp\":1431811395699, \- \ \"volume\":\"6754.09\",\"price\":\"5327.00\"}]}"+ \ \"volume\":\"6754.09\",\"price\":\"5327.00\",\"is_buy\":false}]}" PrivateOrderWithTrades {privateOrderWithTradesBase = 568.7, privateOrderWithTradesCounter = 3764.2,@@ -188,7 +184,8 @@ Trade { tradeTimestamp = posixSecondsToUTCTime 1431811395.699, tradeVolume = 6754.09,- tradePrice = 5327}+ tradePrice = 5327,+ tradeIsBuy = False} privateOrderInner :: PrivateOrder privateOrderInner =
test/Network/Bitcoin/BitX/Spec/Specs/LensSpec.hs view
@@ -56,10 +56,11 @@ _trade :: Maybe Int _trade = do- let x = BitX.Trade (posixSecondsToUTCTime 0) 0 0+ let x = BitX.Trade (posixSecondsToUTCTime 0) 0 0 False let _ = x ^. BitX.timestamp let _ = x ^. BitX.volume let _ = x ^. BitX.price+ let _ = x ^. BitX.isBuy Nothing _bitXAuth :: Maybe Int@@ -88,7 +89,7 @@ _privateOrderWithTrades :: Maybe Int _privateOrderWithTrades = do- let x = BitX.PrivateOrderWithTrades 0 0 (posixSecondsToUTCTime 0) (posixSecondsToUTCTime 0) 0 0 0 0 "" XBTZAR PENDING ASK [BitX.Trade (posixSecondsToUTCTime 0) 0 0]+ let x = BitX.PrivateOrderWithTrades 0 0 (posixSecondsToUTCTime 0) (posixSecondsToUTCTime 0) 0 0 0 0 "" XBTZAR PENDING ASK [BitX.Trade (posixSecondsToUTCTime 0) 0 0 False] let _ = x ^. BitX.base let _ = x ^. BitX.counter let _ = x ^. BitX.creationTimestamp
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 XBTKES+ connectsAndParsesOkay $ getTrades Nothing XBTKES connectsAndParsesOkay :: IO (BitXAPIResponse recd) -> Bool connectsAndParsesOkay = isValidResponse . unsafePerformIO