{-# LANGUAGE DeriveGeneric, DefaultSignatures, QuasiQuotes, OverloadedStrings, DataKinds, MultiParamTypeClasses #-} ----------------------------------------------------------------------------- -- | -- Module : Network.Bitcoin.BitX.Types -- Copyright : No Rights Reserved -- License : Public Domain -- -- Maintainer : Tebello Thejane <zyxoas+hackage@gmail.com> -- Stability : Experimental -- Portability : non-portable (GHC Extensions) -- -- The types used for the various BitX API calls. -- -- Note that these are all `record` types, as provided by Nikita Volkov's -- "Record" library. The main motivation for using the @record@ library was -- to avoid using record field prefixes and other awkward hacks to get around -- the fact that Haskell does not yet have a real records' system. -- -- For example, the declaration of `BitXAuth` is -- -- @ -- type BitXAuth = -- ['record'| -- {id :: 'Text', -- secret :: 'Text'} |] -- @ -- -- To declare a BitXAuth, one might use -- -- @ -- myAuth :: BitXAuth -- myAuth = -- [record| -- {id = "46793", -- secret = "387ffBd56eEAA7C59"} |] -- @ -- -- and to read the fields you would use -- -- @ -- theID = 'view' ['lens'| id |] myAuth -- @ -- -- Note that all uses of Volkov's `record`s requires importing "Record" and -- enabling the 'DataKinds' and 'QuasiQuotes' extensions. -- -- See <http://nikita-volkov.github.io/record/> -- ----------------------------------------------------------------------------- module Network.Bitcoin.BitX.Types ( Ticker, CcyPair(..), Orderbook, Order, Bid, Ask, Trade, BitXAuth, PrivateOrder, OrderID, OrderType(..), RequestStatus(..), OrderRequest, RequestSuccess, BitXError, PrivateOrderWithTrades, AccountID, Asset(..), Balance, FundingAddress, WithdrawalRequest, NewWithdrawal, WithdrawalType(..), BitcoinSendRequest, QuoteRequest, OrderQuote, QuoteType(..), BitXClientAuth, Transaction, Account ) where import Data.Aeson (FromJSON(..)) import Data.Text (Text) import Data.Time.Clock import Record import GHC.Generics (Generic) import Data.Scientific (Scientific) -- | A possible error which the BitX API might return, -- instead of returning the requested data. Note that as yet there is no -- exhaustive list of error codes available, so comparisons will have to be -- done via Text comparisons (as opposed to typed pattern matching). Sorry... -- -- @ --type BitXError = -- [record| -- {error :: 'Text', -- errorCode :: 'Text'} |] -- @ type BitXError = [record| {error :: Text, errorCode :: Text} |] -- | The state of a single market, identified by the currency pair. -- As usual, the ask\/sell price is the price of the last filled ask order, and the bid\/buy price is -- the price of the last filled bid order. Necessarily @bid <= ask.@ -- -- @ --type Ticker = -- [record| -- {ask :: 'Scientific', -- timestamp :: 'UTCTime', -- bid :: 'Scientific', -- rolling24HourVolume :: 'Scientific', -- lastTrade :: 'Scientific', -- pair :: 'CcyPair'} |] -- @ type Ticker = [record| {ask :: Scientific, timestamp :: UTCTime, bid :: Scientific, rolling24HourVolume :: Scientific, lastTrade :: Scientific, pair :: CcyPair} |] -- | 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 deriving (Show, Generic, Eq) -- | 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 deriving (Show, Generic, Eq) -- | The current state of the publically accessible orderbook. -- Bid orders are requests to buy, ask orders are requests to sell. -- -- @ --type Orderbook = -- [record| -- {timestamp :: 'UTCTime', -- bids :: ['Bid'], -- asks :: ['Ask']} |] -- @ type Orderbook = [record| {timestamp :: UTCTime, bids :: [Bid], asks :: [Ask]} |] -- | A single placed order in the orderbook -- -- @ --type Order = -- [record| -- {volume :: 'Scientific', -- price :: 'Scientific'} |] -- @ type Order = [record| {volume :: Scientific, price :: Scientific} |] -- | Convenient type alias for a bid order type Bid = Order -- | Convenient type alias for an ask order type Ask = Order type Trade = [record| {volume :: Scientific, timestamp :: UTCTime, price :: Scientific} |] -- | An auth type used by all private API calls, after authorisation. -- -- @ --type BitXAuth = -- [record| -- {id :: 'Text', -- secret :: 'Text'} |] -- @ type BitXAuth = [record| {id :: Text, secret :: Text} |] type BitXClientAuth = BitXAuth -- | A recently placed (private) order, containing a lot more information than is available on the -- public order book. -- -- @ --type PrivateOrder = -- [record| -- {base :: 'Scientific', -- counter :: 'Scientific', -- creationTimestamp :: 'UTCTime', -- expirationTimestamp :: 'UTCTime', -- feeBase :: 'Scientific', -- feeCounter :: 'Scientific', -- limitPrice :: 'Scientific', -- limitVolume :: 'Scientific', -- id :: 'OrderID', -- pair :: 'CcyPair', -- state :: 'RequestStatus', -- type :: 'OrderType' } |] -- @ type PrivateOrder = [record| {base :: Scientific, counter :: Scientific, creationTimestamp :: UTCTime, expirationTimestamp :: UTCTime, feeBase :: Scientific, feeCounter :: Scientific, limitPrice :: Scientific, limitVolume :: Scientific, id :: OrderID, pair :: CcyPair, state :: RequestStatus, type :: OrderType } |] -- | A recently placed (private) order, containing a lot more information than is available on the -- public order book, together with details of any trades which have (partially) filled it. -- -- @ --type PrivateOrderWithTrades = -- [record| -- {base :: 'Scientific', -- counter :: 'Scientific', -- creationTimestamp :: 'UTCTime', -- expirationTimestamp :: 'UTCTime', -- feeBase :: 'Scientific', -- feeCounter :: 'Scientific', -- limitPrice :: 'Scientific', -- limitVolume :: 'Scientific', -- id :: 'OrderID', -- pair :: 'CcyPair', -- state :: 'RequestStatus', -- type :: 'OrderType', -- trades :: ['Trade'] } |] -- @ type PrivateOrderWithTrades = [record| {base :: Scientific, counter :: Scientific, creationTimestamp :: UTCTime, expirationTimestamp :: UTCTime, feeBase :: Scientific, feeCounter :: Scientific, limitPrice :: Scientific, limitVolume :: Scientific, id :: OrderID, pair :: CcyPair, state :: RequestStatus, type :: OrderType, trades :: [Trade] } |] -- | A transaction on a private user account. -- -- @ --type Transaction = -- [record| -- {rowIndex :: 'Int', -- timestamp :: 'UTCTime', -- balance :: 'Scientific', -- available :: 'Scientific', -- balanceDelta :: 'Scientific', -- availableDelta :: 'Scientific', -- currency :: 'Asset', -- description :: 'Text'}|] -- @ type Transaction = [record| {rowIndex :: Int, timestamp :: UTCTime, balance :: Scientific, available :: Scientific, balanceDelta :: Scientific, availableDelta :: Scientific, currency :: Asset, description :: Text}|] type OrderID = Text -- | The type of a placed order. data OrderType = ASK -- ^ A request to sell | BID -- ^ A request to buy deriving (Show, Generic, Eq) -- | The state of a (private) placed request -- either an order or a withdrawal request. data RequestStatus = PENDING -- ^ Not yet completed. An order will stay in 'PENDING' state even as it is partially -- filled, and will move to 'COMPLETE' once it has been completely filled. | COMPLETE -- ^ Completed. | CANCELLED -- ^ Cancelled. Note that an order cannot be in 'CANCELLED' state, since cancelling -- an order removes it from the orderbook. deriving (Show, Generic, Eq) -- | A request to place an order. -- -- @ --type OrderRequest = -- [record| -- {pair :: 'CcyPair', -- type :: 'OrderType', -- volume :: 'Scientific', -- price :: 'Scientific' } |] -- @ type OrderRequest = [record| {pair :: CcyPair, type :: OrderType, volume :: Scientific, price :: Scientific } |] type AccountID = Text -- | The current balance of a private account. -- -- @ --type Balance = -- [record| -- {id :: 'AccountID', -- asset :: 'Asset', -- balance :: 'Scientific', -- reserved :: 'Scientific', -- unconfirmed :: 'Scientific' } |] -- @ type Balance = [record| {id :: AccountID, asset :: Asset, balance :: Scientific, reserved :: Scientific, unconfirmed :: Scientific } |] -- | A registered address for an acocunt. -- -- @ --type FundingAddress = -- [record| -- {asset :: 'Asset', -- address :: 'Text', -- totalReceived :: 'Scientific', -- totalUnconfirmed :: 'Scientific'} |] -- @ type FundingAddress = [record| {asset :: Asset, address :: Text, totalReceived :: Scientific, totalUnconfirmed :: Scientific} |] -- | The state of a request to withdraw from an account. -- -- @ --type WithdrawalRequest = -- [record| -- {status :: 'RequestStatus', -- id :: 'Text' } |] -- @ type WithdrawalRequest = [record| {status :: RequestStatus, id :: Text } |] -- | A request to withdraw from an account. -- -- @ --type NewWithdrawal = -- [record| -- {type :: 'WithdrawalType', -- amount :: 'Scientific' } |] -- @ type NewWithdrawal = [record| {type :: WithdrawalType, amount :: Scientific } |] -- | A request to send bitcoin to a bitcoin address or email address. -- -- @ --type BitcoinSendRequest = -- [record| -- {amount :: 'Scientific', -- currency :: 'Asset', -- address :: 'Text', -- description :: 'Maybe' 'Text', -- message :: 'Maybe' 'Text'} |] -- @ type BitcoinSendRequest = [record| {amount :: Scientific, currency :: Asset, address :: Text, description :: Maybe Text, message :: Maybe Text} |] -- | A request to lock in a quote. -- -- @ --type QuoteRequest = -- [record| -- {type :: 'QuoteType', -- pair :: 'CcyPair', -- baseAmount :: 'Scientific'} |] -- @ type QuoteRequest = [record| {type :: QuoteType, pair :: CcyPair, baseAmount :: Scientific} |] -- | A temporarily locked in quote. -- -- @ --type OrderQuote = -- [record| -- {id :: 'Text', -- type :: 'QuoteType', -- pair :: 'CcyPair', -- baseAmount :: 'Scientific', -- counterAmount :: 'Scientific', -- createdAt :: 'UTCTime', -- expiresAt :: 'UTCTime', -- discarded :: 'Bool', -- exercised :: 'Bool'} |] -- @ type OrderQuote = [record| {id :: Text, type :: QuoteType, pair :: CcyPair, baseAmount :: Scientific, counterAmount :: Scientific, createdAt :: UTCTime, expiresAt :: UTCTime, discarded :: Bool, exercised :: Bool} |] -- | A registered account. -- -- @ --type Account = -- [record| -- {id :: Text, -- name :: Text, -- currency :: Asset} |] -- @ type Account = [record| {id :: Text, name :: Text, currency :: Asset} |] -- | The type of a withdrawal request. data WithdrawalType = ZAR_EFT -- ^ ZAR by Electronic Funds Transfer | NAD_EFT -- ^ Namibian Dollar by EFT | KES_MPESA -- ^ Kenyan Shilling by Vodafone MPESA | MYR_IBG -- ^ Malaysian Ringgit by Interbank GIRO (?) | IDR_LLG -- ^ Indonesian Rupiah by Lalu Lintas Giro (??) deriving (Show, Generic, Eq) data QuoteType = BUY | SELL deriving (Show, Generic, Eq) type RequestSuccess = Bool instance FromJSON CcyPair instance FromJSON Asset instance FromJSON OrderType instance FromJSON WithdrawalType instance FromJSON QuoteType