In the common package added JSONDecode error check. Added verbosity in SendHTTPGetRequest. Updated Nonce package function. Fixed issues in ItBit package and expanded test coverage.

This commit is contained in:
Ryan O'Hara-Reid
2017-09-12 08:37:18 +10:00
parent 939ce3ab21
commit e8c7bf9af4
24 changed files with 601 additions and 241 deletions

View File

@@ -16,14 +16,26 @@ import (
)
const (
ITBIT_API_URL = "https://api.itbit.com/v1"
ITBIT_API_VERSION = "1"
itbitAPIURL = "https://api.itbit.com/v1"
itbitAPIVersion = "1"
itbitMarkets = "markets"
itbitOrderbook = "order_book"
itbitTicker = "ticker"
itbitWallets = "wallets"
itbitBalances = "balances"
itbitTrades = "trades"
itbitFundingHistory = "funding_history"
itbitOrders = "orders"
itbitCryptoDeposits = "cryptocurrency_deposits"
itbitWalletTransfer = "wallet_transfers"
)
// ItBit is the overarching type across the ItBit package
type ItBit struct {
exchange.Base
}
// SetDefaults sets the defaults for the exchange
func (i *ItBit) SetDefaults() {
i.Name = "ITBIT"
i.Enabled = false
@@ -39,6 +51,7 @@ func (i *ItBit) SetDefaults() {
i.AssetTypes = []string{ticker.Spot}
}
// Setup sets the exchange paramaters from exchange config
func (i *ItBit) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
i.SetEnabled(false)
@@ -63,6 +76,7 @@ func (i *ItBit) Setup(exch config.ExchangeConfig) {
}
}
// GetFee returns the maker or taker fee
func (i *ItBit) GetFee(maker bool) float64 {
if maker {
return i.MakerFee
@@ -70,98 +84,103 @@ func (i *ItBit) GetFee(maker bool) float64 {
return i.TakerFee
}
func (i *ItBit) GetTicker(currency string) (Ticker, error) {
path := ITBIT_API_URL + "/markets/" + currency + "/ticker"
var itbitTicker Ticker
err := common.SendHTTPGetRequest(path, true, &itbitTicker)
if err != nil {
return Ticker{}, err
}
return itbitTicker, nil
// GetTicker returns ticker info for a specified market.
// currencyPair - example "XBTUSD" "XBTSGD" "XBTEUR"
func (i *ItBit) GetTicker(currencyPair string) (Ticker, error) {
var response Ticker
path := fmt.Sprintf("%s/%s/%s/%s", itbitAPIURL, itbitMarkets, currencyPair, itbitTicker)
return response,
common.SendHTTPGetRequest(path, true, i.Verbose, &response)
}
func (i *ItBit) GetOrderbook(currency string) (OrderbookResponse, error) {
// GetOrderbook returns full order book for the specified market.
// currencyPair - example "XBTUSD" "XBTSGD" "XBTEUR"
func (i *ItBit) GetOrderbook(currencyPair string) (OrderbookResponse, error) {
response := OrderbookResponse{}
path := ITBIT_API_URL + "/markets/" + currency + "/order_book"
err := common.SendHTTPGetRequest(path, true, &response)
if err != nil {
return OrderbookResponse{}, err
}
return response, nil
path := fmt.Sprintf("%s/%s/%s/%s", itbitAPIURL, itbitMarkets, currencyPair, itbitOrderbook)
return response,
common.SendHTTPGetRequest(path, true, i.Verbose, &response)
}
func (i *ItBit) GetTradeHistory(currency, timestamp string) bool {
req := "/trades?since=" + timestamp
err := common.SendHTTPGetRequest(ITBIT_API_URL+"markets/"+currency+req, true, nil)
if err != nil {
log.Println(err)
return false
}
return true
// GetTradeHistory returns recent trades for a specified market.
//
// currencyPair - example "XBTUSD" "XBTSGD" "XBTEUR"
// timestamp - matchNumber, only executions after this will be returned
func (i *ItBit) GetTradeHistory(currencyPair, timestamp string) (Trades, error) {
response := Trades{}
req := "trades?since=" + timestamp
path := fmt.Sprintf("%s/%s/%s/%s", itbitAPIURL, itbitMarkets, currencyPair, req)
return response,
common.SendHTTPGetRequest(path, true, i.Verbose, &response)
}
func (i *ItBit) GetWallets(params url.Values) {
// GetWallets returns information about all wallets associated with the account.
//
// params --
// page - [optional] page to return example 1. default 1
// perPage - [optional] items per page example 50, default 50 max 50
func (i *ItBit) GetWallets(params url.Values) ([]Wallet, error) {
resp := []Wallet{}
params.Set("userId", i.ClientID)
path := "/wallets?" + params.Encode()
path := fmt.Sprintf("/%s?%s", itbitWallets, params.Encode())
err := i.SendAuthenticatedHTTPRequest("GET", path, nil)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (i *ItBit) CreateWallet(walletName string) {
path := "/wallets"
// CreateWallet creates a new wallet with a specified name.
func (i *ItBit) CreateWallet(walletName string) (Wallet, error) {
resp := Wallet{}
params := make(map[string]interface{})
params["userId"] = i.ClientID
params["name"] = walletName
err := i.SendAuthenticatedHTTPRequest("POST", path, params)
if err != nil {
log.Println(err)
}
return resp,
i.SendAuthenticatedHTTPRequest("POST", "/"+itbitWallets, params, &resp)
}
func (i *ItBit) GetWallet(walletID string) {
path := "/wallets/" + walletID
err := i.SendAuthenticatedHTTPRequest("GET", path, nil)
// GetWallet returns wallet information by walletID
func (i *ItBit) GetWallet(walletID string) (Wallet, error) {
resp := Wallet{}
path := fmt.Sprintf("/%s/%s", itbitWallets, walletID)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (i *ItBit) GetWalletBalance(walletID, currency string) {
path := "/wallets/ " + walletID + "/balances/" + currency
err := i.SendAuthenticatedHTTPRequest("GET", path, nil)
// GetWalletBalance returns balance information for a specific currency in a
// wallet.
func (i *ItBit) GetWalletBalance(walletID, currency string) (Balance, error) {
resp := Balance{}
path := fmt.Sprintf("/%s/%s/%s/%s", itbitWallets, walletID, itbitBalances, currency)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (i *ItBit) GetWalletTrades(walletID string, params url.Values) {
path := common.EncodeURLValues("/wallets/"+walletID+"/trades", params)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil)
// GetWalletTrades returns all trades for a specified wallet.
func (i *ItBit) GetWalletTrades(walletID string, params url.Values) (Records, error) {
resp := Records{}
url := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitTrades)
path := common.EncodeURLValues(url, params)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (i *ItBit) GetWalletOrders(walletID string, params url.Values) {
path := common.EncodeURLValues("/wallets/"+walletID+"/orders", params)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil)
// GetFundingHistory returns all funding history for a specified wallet.
func (i *ItBit) GetFundingHistory(walletID string, params url.Values) (FundingRecords, error) {
resp := FundingRecords{}
url := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitFundingHistory)
path := common.EncodeURLValues(url, params)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (i *ItBit) PlaceWalletOrder(walletID, side, orderType, currency string, amount, price float64, instrument string, clientRef string) {
path := "/wallets/" + walletID + "/orders"
// PlaceOrder places a new order
func (i *ItBit) PlaceOrder(walletID, side, orderType, currency string, amount, price float64, instrument, clientRef string) (Order, error) {
resp := Order{}
path := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitOrders)
params := make(map[string]interface{})
params["side"] = side
params["type"] = orderType
@@ -174,85 +193,58 @@ func (i *ItBit) PlaceWalletOrder(walletID, side, orderType, currency string, amo
params["clientOrderIdentifier"] = clientRef
}
err := i.SendAuthenticatedHTTPRequest("POST", path, params)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
}
func (i *ItBit) GetWalletOrder(walletID, orderID string) {
path := "/wallets/" + walletID + "/orders/" + orderID
err := i.SendAuthenticatedHTTPRequest("GET", path, nil)
// GetOrder returns an order by id.
func (i *ItBit) GetOrder(walletID string, params url.Values) (Order, error) {
resp := Order{}
url := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitOrders)
path := common.EncodeURLValues(url, params)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (i *ItBit) CancelWalletOrder(walletID, orderID string) {
path := "/wallets/" + walletID + "/orders/" + orderID
err := i.SendAuthenticatedHTTPRequest("DELETE", path, nil)
// CancelOrder cancels and open order. *This is not a guarantee that the order
// has been cancelled!*
func (i *ItBit) CancelOrder(walletID, orderID string) error {
path := fmt.Sprintf("/%s/%s/%s/%s", itbitWallets, walletID, itbitOrders, orderID)
if err != nil {
log.Println(err)
}
return i.SendAuthenticatedHTTPRequest("DELETE", path, nil, nil)
}
func (i *ItBit) PlaceWithdrawalRequest(walletID, currency, address string, amount float64) {
path := "/wallets/" + walletID + "/cryptocurrency_withdrawals"
params := make(map[string]interface{})
params["currency"] = currency
params["amount"] = amount
params["address"] = address
err := i.SendAuthenticatedHTTPRequest("POST", path, params)
if err != nil {
log.Println(err)
}
}
func (i *ItBit) GetDepositAddress(walletID, currency string) {
path := "/wallets/" + walletID + "/cryptocurrency_deposits"
// GetDepositAddress returns a deposit address to send cryptocurrency to.
func (i *ItBit) GetDepositAddress(walletID, currency string) (CryptoCurrencyDeposit, error) {
resp := CryptoCurrencyDeposit{}
path := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitCryptoDeposits)
params := make(map[string]interface{})
params["currency"] = currency
err := i.SendAuthenticatedHTTPRequest("POST", path, params)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
}
func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount float64, currency string) {
path := "/wallets/" + walletID + "/wallet_transfers"
// WalletTransfer transfers funds between wallets.
func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount float64, currency string) (WalletTransfer, error) {
resp := WalletTransfer{}
path := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitWalletTransfer)
params := make(map[string]interface{})
params["sourceWalletId"] = sourceWallet
params["destinationWalletId"] = destWallet
params["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
params["currencyCode"] = currency
err := i.SendAuthenticatedHTTPRequest("POST", path, params)
if err != nil {
log.Println(err)
}
return resp, i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
}
func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params map[string]interface{}) (err error) {
// SendAuthenticatedHTTPRequest sends an authenticated request to itBit
func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params map[string]interface{}, result interface{}) error {
if !i.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, i.Name)
}
if i.Nonce.Get() == 0 {
i.Nonce.Set(time.Now().UnixNano())
} else {
i.Nonce.Inc()
}
request := make(map[string]interface{})
url := ITBIT_API_URL + path
url := itbitAPIURL + path
if params != nil {
for key, value := range params {
@@ -261,12 +253,13 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params
}
PayloadJSON := []byte("")
var err error
if params != nil {
PayloadJSON, err = common.JSONEncode(request)
PayloadJSON, err = common.JSONEncode(request)
if err != nil {
return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON Marshal request")
return err
}
if i.Verbose {
@@ -274,26 +267,37 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params
}
}
message, err := common.JSONEncode([]string{method, url, string(PayloadJSON), i.Nonce.String(), i.Nonce.String()[0:13]})
nonce := i.Nonce.GetValue(i.Name, false).String()
timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
message, err := common.JSONEncode([]string{method, url, string(PayloadJSON), nonce, timestamp})
if err != nil {
log.Println(err)
return
return err
}
hash := common.GetSHA256([]byte(i.Nonce.String() + string(message)))
hash := common.GetSHA256([]byte(nonce + string(message)))
hmac := common.GetHMAC(common.HashSHA512, []byte(url+string(hash)), []byte(i.APISecret))
signature := common.Base64Encode(hmac)
headers := make(map[string]string)
headers["Authorization"] = i.ClientID + ":" + signature
headers["X-Auth-Timestamp"] = i.Nonce.String()[0:13]
headers["X-Auth-Nonce"] = i.Nonce.String()
headers["X-Auth-Timestamp"] = timestamp
headers["X-Auth-Nonce"] = nonce
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest(method, url, headers, bytes.NewBuffer([]byte(PayloadJSON)))
if err != nil {
return err
}
if i.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
return nil
errCapture := GeneralReturn{}
if err := common.JSONDecode([]byte(resp), &errCapture); err == nil {
return errors.New(errCapture.Description)
}
return common.JSONDecode([]byte(resp), result)
}