bittrex (empty) → 0.1.0.0
raw patch · 9 files changed
+797/−0 lines, 9 filesdep +SHAdep +aesondep +basesetup-changed
Dependencies added: SHA, aeson, base, bytestring, http-client-tls, lens, lens-aeson, scientific, split, text, time, wreq
Files
- ChangeLog.md +5/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- bittrex.cabal +39/−0
- src/Bittrex.hs +9/−0
- src/Bittrex/API.hs +296/−0
- src/Bittrex/Internal.hs +67/−0
- src/Bittrex/Types.hs +343/−0
- src/Bittrex/Util.hs +6/−0
+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for bittrex++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, David Johnson++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of David Johnson nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bittrex.cabal view
@@ -0,0 +1,39 @@+name: bittrex+version: 0.1.0.0+synopsis: API bindings to bittrex.com+description: Haskell bindings to the Bittrex exchange+homepage: https://github.com/dmjio/bittrex+license: BSD3+license-file: LICENSE+author: David Johnson+maintainer: djohnson.m@gmail.com+copyright: David Johnson (c) 2017+category: Web+build-type: Simple+extra-source-files: ChangeLog.md+cabal-version: >=1.10++library+ exposed-modules: Bittrex+ Bittrex.API+ Bittrex.Types+ Bittrex.Util+ other-modules: Bittrex.Internal+ hs-source-dirs: src+ default-language: Haskell2010+ build-depends: aeson+ , base < 5+ , bytestring+ , http-client-tls+ , lens+ , lens-aeson+ , scientific+ , SHA+ , split+ , text+ , time+ , wreq++source-repository head+ type: git+ location: git://github.com/dmjio/bittrex.git
+ src/Bittrex.hs view
@@ -0,0 +1,9 @@+module Bittrex+ ( module Bittrex.API+ , module Bittrex.Types+ , module Bittrex.Util+ ) where++import Bittrex.API+import Bittrex.Types+import Bittrex.Util
+ src/Bittrex/API.hs view
@@ -0,0 +1,296 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveGeneric #-}+module Bittrex.API+ (+ -- * Overview+ -- $intro++ -- * Public+ getMarkets+ , getCurrencies+ , getTicker+ , getMarketSummaries+ , getMarketSummary+ , getOrderBook+ , getMarketHistory+ -- * Market+ , buyLimit+ , sellLimit+ , cancel+ , getOpenOrders+ -- * Account+ , getBalances+ , getBalance+ , getDepositAddress+ , withdraw+ , getOrder+ , getOrderHistory+ , getWithdrawalHistory+ , getDepositHistory+ ) where++import Data.Aeson+import Data.Monoid+import Data.Text (Text)+import qualified Data.Text as T+import Data.Scientific++import Bittrex.Types+import Bittrex.Util+import Bittrex.Internal++-- $intro+-- Bittrex provides a simple and powerful REST API to allow you to programatically perform nearly all actions you can from our web interface.+--+-- All requests use the application/json content type and go over https.+-- The base url is https://bittrex.com/api/{version}/.+--+-- All requests are GET requests and all responses come in a default response object with the result in the result field. Always check the success flag to ensure that your API call succeeded.+--+-- We are currently restricting orders to 500 open orders and 200,000 orders a day. We reserve the right to change these settings as we tune the system. If you are affected by these limits as an active trader, please email support@bittrex.com.+--+-- If you have any questions, feedback or recommendation for API support you can post a question in our support center.+--++-- | Used to get the open and available trading markets at Bittrex along with other meta data.+getMarkets+ :: IO (Either ErrorMessage [Market])+getMarkets = callAPI defOpts { path = "getmarkets" }++-- | Used to get all supported currencies at Bittrex along with other meta data.+getCurrencies+ :: IO (Either ErrorMessage [Currency])+getCurrencies = callAPI defOpts { path = "getcurrencies" }++-- | Used to get the current tick values for a market.+getTicker+ :: MarketName -- ^ a string literal for the market (ex: `BTC-LTC`)+ -> IO (Either ErrorMessage Ticker)+getTicker market =+ callAPI defOpts {+ qParams = [("market", show market)]+ , path = "getticker"+ }++-- | Used to get the last 24 hour summary of all active exchanges+getMarketSummaries+ :: IO (Either ErrorMessage Value)+getMarketSummaries =+ callAPI defOpts { path = "getmarketsummaries" }++-- | Used to get the last 24 hour summary of all active exchanges+getMarketSummary+ :: MarketName -- ^ a string literal for the market (ex: `BTC-LTC`)+ -> IO (Either ErrorMessage Value)+getMarketSummary market =+ callAPI defOpts {+ qParams = [("market", show market)]+ , path = "getmarketsummary"+ }++-- | Used to get retrieve the orderbook for a given market+getOrderBook+ :: MarketName -- ^ a string literal for the market (ex: `BTC-LTC`)+ -> OrderBookType -- ^ buy, sell or both to identify the type of orderbook to return.+ -> IO (Either ErrorMessage OrderBook)+getOrderBook market orderBookType =+ callAPI defOpts {+ path = "getorderbook"+ , qParams = [ ("market", show market)+ , ("type", show orderBookType)+ ]+ }++-- | Used to retrieve the latest trades that have occured for a specific market.+getMarketHistory+ :: MarketName -- ^ string literal for the market (ex: `BTC-LTC`)+ -> IO (Either ErrorMessage [MarketHistory])+getMarketHistory market =+ callAPI defOpts {+ path = "getmarkethistory"+ , qParams = pure ("market", show market)+ }++-- | Get all orders that you currently have opened. A specific market can be requested+getOpenOrders+ :: APIKeys -- ^ Bittrex API credentials+ -> MarketName -- ^ String literal for the market (ie. BTC-LTC)+ -> IO (Either ErrorMessage [OpenOrder])+getOpenOrders keys market =+ callAPI defOpts {+ path = "getopenorders"+ , apiType = MarketAPI+ , qParams = pure ("market", camelToDash $ show market)+ , keys = keys+ }++-- | Used to place a buy order in a specific market. Use buylimit to place limit orders. Make sure you have the proper permissions set on your API keys for this call to work+buyLimit+ :: APIKeys -- ^ Bittrex API credentials+ -> MarketName -- ^ A string literal for the market (ex: BTC-LTC)+ -> Quantity -- ^ The amount to purchase+ -> Rate -- ^ The rate at which to place the order.+ -> IO (Either ErrorMessage UUID)+buyLimit keys market quantity rate =+ callAPI defOpts {+ path = "buylimit"+ , keys = keys+ , apiType = MarketAPI+ , qParams = [ ("market", camelToDash $ show market )+ , ("quantity", formatScientific Fixed Nothing quantity )+ , ("rate", formatScientific Fixed Nothing rate )+ ]+ }++-- | Used to place an sell order in a specific market. Use selllimit to place limit orders.+-- Make sure you have the proper permissions set on your API keys for this call to workn+sellLimit+ :: APIKeys -- ^ Bittrex API credentials+ -> MarketName -- ^ A string literal for the market (ex: BTC-LTC)+ -> Quantity -- ^ The amount to purchase+ -> Rate -- ^ The rate at which to place the order+ -> IO (Either ErrorMessage UUID)+sellLimit keys market quantity rate =+ callAPI defOpts {+ path = "selllimit"+ , keys = keys+ , apiType = MarketAPI+ , qParams = [ ("market", camelToDash $ show market )+ , ("quantity", formatScientific Fixed Nothing quantity )+ , ("rate", formatScientific Fixed Nothing rate )+ ]+ }++-- | Used to cancel a buy or sell order.+cancel+ :: APIKeys -- ^ Bittrex API credentials+ -> UUID -- ^ uuid of buy or sell order+ -> IO (Either ErrorMessage (Maybe Text))+cancel keys (UUID uuid) =+ callAPI defOpts {+ path = "cancel"+ , keys = keys+ , apiType = MarketAPI+ , qParams = [ ("uuid", T.unpack uuid ) ]+ }++-- | Used to retrieve all balances from your account+getBalances+ :: APIKeys -- ^ Bittrex API credentials+ -> IO (Either ErrorMessage [Balance])+getBalances keys =+ callAPI defOpts {+ path = "getbalances"+ , keys = keys+ , apiType = AccountAPI+ }++-- | Used to retrieve the balance from your account for a specific currency.+getBalance+ :: APIKeys -- ^ Bittrex API credentials+ -> CurrencyName -- ^ a string literal for the currency (ex: LTC)+ -> IO (Either ErrorMessage Balance)+getBalance keys currency =+ callAPI defOpts {+ path = "getbalance"+ , keys = keys+ , apiType = AccountAPI+ , qParams = pure ("currency", T.unpack currency )+ }++-- | Used to retrieve or generate an address for a specific currency.+-- If one does not exist, the call will fail and return ADDRESS_GENERATING until one is available.+getDepositAddress+ :: APIKeys -- ^ Bittrex API credentials+ -> CurrencyName -- ^ a string literal for the currency (ie. BTC)+ -> IO (Either ErrorMessage DepositAddress)+getDepositAddress keys currency =+ callAPI defOpts {+ path = "getdepositaddress"+ , apiType = AccountAPI+ , keys = keys+ , qParams = pure ("currency", T.unpack currency )+ }++-- | Used to retrieve your withdrawal history.+getWithdrawalHistory+ :: APIKeys -- ^ Bittrex API credentials+ -> CurrencyName+ -> IO (Either ErrorMessage [WithdrawalHistory])+getWithdrawalHistory keys currency =+ callAPI defOpts {+ path = "getwithdrawalhistory"+ , apiType = AccountAPI+ , keys = keys+ , qParams = pure ( "currency"+ , show currency+ )+ }++-- | Used to retrieve your order history.+getOrderHistory+ :: APIKeys -- ^ Bittrex API credentials+ -> Maybe MarketName -- ^ a string literal for the market (ie. BTC-LTC). If ommited, will return for all markets+ -> IO (Either ErrorMessage [OrderHistory] )+getOrderHistory keys market =+ callAPI defOpts {+ path = "getorderhistory"+ , apiType = AccountAPI+ , keys = keys+ , qParams = [ ("market", camelToDash (show m) )+ | Just m <- pure market+ ]+ }++-- | Used to retrieve a single order by uuid.+getOrder+ :: APIKeys -- ^ Bittrex API credentials+ -> UUID -- ^ the uuid of the buy or sell order+ -> IO (Either ErrorMessage Order)+getOrder keys (UUID uuid) =+ callAPI defOpts {+ path = "getorder"+ , keys = keys+ , apiType = AccountAPI+ , qParams = [ ("uuid", T.unpack uuid) ]+ }++-- | Used to withdraw funds from your account. note: please account for txfee.+withdraw+ :: APIKeys -- ^ Bittrex API credentials+ -> CurrencyName -- ^ A string literal for the currency (ie. BTC)+ -> Quantity -- ^ The quantity of coins to withdraw+ -> Address -- ^ The address where to send the funds.+ -> Maybe PaymentId -- ^ used for CryptoNotes/BitShareX/Nxt optional field (memo/paymentid)+ -> IO (Either ErrorMessage UUID)+withdraw keys currency quantity address payment =+ callAPI defOpts {+ path = "withdraw"+ , keys = keys+ , apiType = AccountAPI+ , qParams = [ ("currency", T.unpack currency )+ , ("quantity", formatScientific Fixed Nothing quantity )+ , ("address", address )+ ] <> [ ("paymentid", show p )+ | Just p <- pure payment+ ]+ }++-- | Used to retrieve your deposit history.+getDepositHistory+ :: APIKeys+ -- ^ Bittrex API credentials+ -> Maybe CurrencyName+ -- ^ A string literal for the currecy (ie. BTC). If `Nothing`, will return for all currencies+ -> IO (Either ErrorMessage [DepositHistory])+getDepositHistory keys currency =+ callAPI defOpts {+ path = "getdeposithistory"+ , apiType = AccountAPI+ , keys = keys+ , qParams = [ ("currency", show c)+ | Just c <- pure currency+ ]+ }
+ src/Bittrex/Internal.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+module Bittrex.Internal where++import Control.Lens+import Data.Aeson+import Data.Aeson.Lens (key, nth)+import qualified Data.ByteString.Char8 as BC+import qualified Data.ByteString.Lazy as L+import Data.Char+import Data.Digest.Pure.SHA+import Data.List+import Data.List.Split (splitOn)+import Data.Monoid+import Data.Time.Clock.POSIX+import Network.Wreq+import Debug.Trace+import Bittrex.Types++-- | Default API options+defOpts :: APIOpts+defOpts = APIOpts PublicAPI [] "v1.1" mempty (APIKeys mempty mempty)++-- | Internal, used for dispatching an API call+callAPI+ :: FromJSON v+ => APIOpts+ -> IO (Either ErrorMessage v)+callAPI APIOpts {..} = do+ let APIKeys {..} = keys+ nonce <- head . splitOn "." . show <$> getPOSIXTime+ let addAuth = apiType `elem` [AccountAPI, MarketAPI]+ authParams = concat+ [ [ ("apikey", apiKey) | addAuth ]+ , [ ("nonce", nonce) | addAuth ]+ ]+ addHeader o =+ if addAuth+ then o & header "apisign" .~ [+ BC.pack $ showDigest $+ hmacSha512 (L.fromStrict (BC.pack secretKey)) $+ L.fromStrict (BC.pack urlForHash)+ ]+ else o+ urlForHash = init $+ mconcat [ url+ , "?"+ , go =<< do qParams ++ authParams+ ]+ go (k,v) = k <> "=" <> v <> "&"+ url = intercalate "/" [ "https://bittrex.com/api"+ , version+ , toLower <$> show apiType+ , path+ ]+ r <- getWith (addHeader defaults) urlForHash+ let Just (Bool success) = r ^? responseBody . key "success"+ Just result = r ^? responseBody . key "result"+ Just msg = r ^? responseBody . key "message"+ pure $ if success+ then case fromJSON result of+ Error s -> Left (DecodeFailure s result)+ Success m -> Right m+ else case fromJSON msg of+ Success m -> Left (BittrexError m)+ Error s -> Left (DecodeFailure s msg)+
+ src/Bittrex/Types.hs view
@@ -0,0 +1,343 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}+module Bittrex.Types where++import Data.Aeson+import Data.Aeson.Types+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import Data.Scientific+import Data.Text (Text)+import qualified Data.Text as T+import Data.Time+import GHC.Generics++type Params = [(String,String)]+type Rate = Scientific++data APIType+ = PublicAPI+ | AccountAPI+ | MarketAPI+ deriving (Eq)++instance Show APIType where+ show AccountAPI = "account"+ show PublicAPI = "public"+ show MarketAPI = "market"++data APIOpts+ = APIOpts+ { apiType :: APIType+ , qParams :: Params+ , version :: String+ , path :: String+ , keys :: APIKeys+ } deriving (Show, Eq)++data ErrorMessage+ = BittrexError BittrexError+ | DecodeFailure String Value+ deriving (Show, Eq, Generic)++data BittrexError+ = INVALID_MARKET+ | MARKET_NOT_PROVIDED+ | APIKEY_NOT_PROVIDED+ | APIKEY_INVALID+ | INVALID_SIGNATURE+ | NONCE_NOT_PROVIDED+ | INVALID_PERMISSION+ | INVALID_CURRENCY+ | WITHDRAWAL_TOO_SMALL+ | CURRENCY_DOES_NOT_EXIST+ deriving (Show, Eq, Generic)++instance FromJSON ErrorMessage+instance FromJSON BittrexError++data MarketName+ = BTC_ADA+ | BTC_LTC+ deriving (Show)++data Ticker = Ticker+ { bid :: Double+ , ask :: Double+ , last :: Double+ } deriving (Generic, Show)++instance FromJSON Ticker where+ parseJSON = withObject "Ticker" $ \o ->+ Ticker <$> o .: "Bid"+ <*> o .: "Ask"+ <*> o .: "Last"++data Market+ = Market+ { marketCurrency :: Text+ , baseCurrency :: Text+ , marketCurrencyLong :: Text+ , baseCurrencyLong :: Text+ , minTradeSize :: Double+ , marketName :: Text+ , isActive :: Bool+ , created :: Text+ } deriving (Show, Eq)++instance FromJSON Market where+ parseJSON = withObject "Market" $ \o ->+ Market <$> o .: "MarketCurrency"+ <*> o .: "BaseCurrency"+ <*> o .: "MarketCurrencyLong"+ <*> o .: "BaseCurrencyLong"+ <*> o .: "MinTradeSize"+ <*> o .: "MarketName"+ <*> o .: "IsActive"+ <*> o .: "Created"++data Currency+ = Currency+ { currency :: Text+ , currencyLong :: Text+ , minConfirmation :: Int+ , txFee :: Double+ , currencyIsActive :: Bool+ , coinType :: Text+ , baseAddress :: Maybe Text+ } deriving (Show, Eq)++instance FromJSON Currency where+ parseJSON = withObject "Currency" $ \o ->+ Currency+ <$> o .: "Currency"+ <*> o .: "CurrencyLong"+ <*> o .: "MinConfirmation"+ <*> o .: "TxFee"+ <*> o .: "IsActive"+ <*> o .: "CoinType"+ <*> o .: "BaseAddress"++data OrderBookType+ = Buy+ | Sell+ | Both+ deriving (Show, Eq)++data OrderBookEntry+ = OrderBookEntry+ { quantity :: Double+ , rate :: Double+ } deriving (Show, Eq)++instance FromJSON OrderBook where+ parseJSON = withObject "OrderBook" $ \o ->+ OrderBook <$> o .: "buy"+ <*> o .: "sell"++data OrderBook+ = OrderBook+ { buy :: [OrderBookEntry]+ , sell :: [OrderBookEntry]+ } deriving (Show, Eq)++instance FromJSON OrderBookEntry where+ parseJSON = withObject "OrderBookEntry" $ \o ->+ OrderBookEntry <$> o .: "Quantity"+ <*> o .: "Rate"++k :: ByteString+k = "{\"buy\":[{\"Quantity\":12.37000000,\"Rate\":0.02525000}],\"sell\":[{\"Quantity\":32.55412402,\"Rate\":0.02540000}]}"++Right m = eitherDecode (L.fromStrict k) :: Either String OrderBook++data MarketHistory+ = MarketHistory+ { marketHistoryId :: Integer+ , marketHistoryTimeStamp :: Text+ , marketHistoryQuantity :: Double+ , marketHistoryPrice :: Double+ , marketHistoryTotal :: Double+ , marketHistoryFillType :: Text+ , marketHistoryOrderType :: Text+ } deriving (Show, Eq)++instance FromJSON MarketHistory where+ parseJSON = withObject "MarketHistory" $ \o ->+ MarketHistory <$> o .: "Id"+ <*> o .: "TimeStamp"+ <*> o .: "Quantity"+ <*> o .: "Price"+ <*> o .: "Total"+ <*> o .: "FillType"+ <*> o .: "OrderType"++type Quantity = Scientific+type Address = String+type PaymentId = String++-- | API Keys+data APIKeys = APIKeys+ { apiKey :: String+ , secretKey :: String+ } deriving (Show, Eq)++data WithdrawalHistory+ = WithdrawalHistory+ { whPaymentUuid :: Text+ , whCurrency :: Text+ , whAmount :: Scientific+ , whAddress :: Text+ , whOpened :: Text+ , whAuthorized :: Bool+ , whPendingPayment :: Bool+ , whTxCost :: Scientific+ , whTxId :: Text+ , whCanceled :: Bool+ , whInvalidAddress :: Bool+ } deriving (Show, Eq, Generic)++instance FromJSON WithdrawalHistory where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 2+ }++data DepositHistory+ = DepositHistory+ { dhCurrency :: Text+ , dhAmount :: Scientific+ , dhLastUpdated :: Text+ , dhConfirmations :: Scientific+ , dhId :: Scientific+ , dhTxId :: Text+ , dhCryptoAddress :: Text+ } deriving (Show, Eq, Generic)++instance FromJSON DepositHistory where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 2+ }++type CurrencyName = Text++data DepositAddress+ = DepositAddress+ { daCurrency :: Text+ , daAddress :: Text+ } deriving (Show, Eq, Generic)++instance FromJSON DepositAddress where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 2+ }++newtype UUID = UUID Text+ deriving (Show, Eq)++instance FromJSON UUID where+ parseJSON = withObject "UUID" $ \o ->+ UUID <$> o .: "uuid"++data Balance+ = Balance+ { bCurrency :: Text+ , bBalance :: Scientific+ , bAvailable :: Scientific+ , bPending :: Scientific+ , bCryptoAddress :: Text+ , bUuid :: Maybe Text+ } deriving (Show, Eq, Generic)++instance FromJSON Balance where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 1+ }++data OrderType+ = SELL+ | BUY+ | LIMIT_SELL+ | LIMIT_BUY+ deriving (Show, Generic, Eq)++instance FromJSON OrderType++data OpenOrder+ = OpenOrder+ { ooUuid :: Maybe Text+ , ooOrderUuid :: Text+ , ooExchange :: Text+ , ooOrderType :: OrderType+ , ooQuantity :: Scientific+ , ooQuantityRemaining :: Scientific+ , ooLimit :: Scientific+ , ooCommissionPaid :: Scientific+ , ooPrice :: Scientific+ , ooPricePerUnit :: Maybe Scientific+ , ooOpened :: Text+ , ooClosed :: Maybe Text+ , ooCancelInitiated :: Bool+ , ooImmediateOrCancel :: Bool+ , ooIsConditional :: Bool+ , ooCondition :: Maybe Text+ , ooConditionTarget :: Maybe Text+ } deriving (Show, Eq, Generic)++instance FromJSON OpenOrder where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 2+ }++data OrderHistory+ = OrderHistory+ { ohOrderUuid :: Text+ , ohExchange :: Text+ , ohTimeStamp :: Text+ , ohOrderType :: OrderType+ , ohLimit :: Scientific+ , ohQuantity :: Scientific+ , ohQuantityRemaining :: Scientific+ , ohCommission :: Scientific+ , ohPrice :: Scientific+ , ohPricePerUnit :: Maybe Scientific+ , ohIsConditional :: Bool+ , ohImmediateOrCancel :: Bool+ } deriving (Show, Eq, Generic)++instance FromJSON OrderHistory where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 2+ }++data Order+ = Order+ { oAccountId :: Maybe Text+ , oOrderUuid :: Text+ , oExchange :: Text+ , oOrderType :: OrderType+ , oQuantity :: Scientific+ , oQuantityRemaining :: Scientific+ , oLimit :: Scientific+ , oReserved :: Scientific+ , oReservedRemaining :: Scientific+ , oCommissionReserved :: Scientific+ , oCommissionReserveRemaining :: Scientific+ , oCommissionPaid :: Scientific+ , oPrice :: Scientific+ , oPricePerUnit :: Maybe Scientific+ , oOpen :: Text+ , oIsOpen :: Bool+ , oSentinal :: Text+ , oTimeStamp :: Text+ , oCommission :: Scientific+ , oIsConditional :: Bool+ , oImmediateOrCancel :: Bool+ , oCancelInitiated :: Bool+ , oCondition :: Text+ } deriving (Show, Eq, Generic)++instance FromJSON Order where+ parseJSON = genericParseJSON defaultOptions {+ fieldLabelModifier = drop 1+ }
+ src/Bittrex/Util.hs view
@@ -0,0 +1,6 @@+module Bittrex.Util ( camelToDash ) where++camelToDash :: String -> String+camelToDash [] = []+camelToDash ('_':xs) = '-':camelToDash xs+camelToDash (x:xs) = x:camelToDash xs