mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 15:09:51 +00:00
595
exchanges/bittrex/bittrex.go
Normal file
595
exchanges/bittrex/bittrex.go
Normal file
@@ -0,0 +1,595 @@
|
||||
package bittrex
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
const (
|
||||
bittrexAPIURL = "https://bittrex.com/api"
|
||||
bittrexAPIVersion = "v1.1"
|
||||
bittrexMaxOpenOrders = 500
|
||||
bittrexMaxOrderCountPerDay = 200000
|
||||
|
||||
// Returned messages from Bittrex API
|
||||
bittrexAddressGenerating = "ADDRESS_GENERATING"
|
||||
bittrexErrorMarketNotProvided = "MARKET_NOT_PROVIDED"
|
||||
bittrexErrorInvalidMarket = "INVALID_MARKET"
|
||||
bittrexErrorAPIKeyInvalid = "APIKEY_INVALID"
|
||||
|
||||
// Public requests
|
||||
bittrexAPIGetMarkets = "public/getmarkets"
|
||||
bittrexAPIGetCurrencies = "public/getcurrencies"
|
||||
bittrexAPIGetTicker = "public/getticker"
|
||||
bittrexAPIGetMarketSummaries = "public/getmarketsummaries"
|
||||
bittrexAPIGetMarketSummary = "public/getmarketsummary"
|
||||
bittrexAPIGetOrderbook = "public/getorderbook"
|
||||
bittrexAPIGetMarketHistory = "public/getmarkethistory"
|
||||
|
||||
// Market requests
|
||||
bittrexAPIBuyLimit = "market/buylimit"
|
||||
bittrexAPISellLimit = "market/selllimit"
|
||||
bittrexAPICancel = "market/cancel"
|
||||
bittrexAPIGetOpenOrders = "market/getopenorders"
|
||||
|
||||
// Account requests
|
||||
bittrexAPIGetBalances = "account/getbalances"
|
||||
bittrexAPIGetBalance = "account/getbalance"
|
||||
bittrexAPIGetDepositAddress = "account/getdepositaddress"
|
||||
bittrexAPIWithdraw = "account/withdraw"
|
||||
bittrexAPIGetOrder = "account/getorder"
|
||||
bittrexAPIGetOrderHistory = "account/getorderhistory"
|
||||
bittrexAPIGetWithdrawalHistory = "account/getwithdrawalhistory"
|
||||
bittrexAPIGetDepositHistory = "account/getdeposithistory"
|
||||
)
|
||||
|
||||
// Bittrex is amazeballs
|
||||
type Bittrex struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
// SetDefaults method assignes the default values for Bittrex
|
||||
func (b *Bittrex) SetDefaults() {
|
||||
b.Name = "Bittrex"
|
||||
b.Enabled = false
|
||||
b.Verbose = false
|
||||
b.Websocket = false
|
||||
b.RESTPollingDelay = 10
|
||||
}
|
||||
|
||||
// Setup method sets current configuration details if enabled
|
||||
func (b *Bittrex) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
b.SetEnabled(false)
|
||||
} else {
|
||||
b.Enabled = true
|
||||
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
||||
b.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, false)
|
||||
b.RESTPollingDelay = exch.RESTPollingDelay
|
||||
b.Verbose = exch.Verbose
|
||||
b.Websocket = exch.Websocket
|
||||
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
}
|
||||
}
|
||||
|
||||
// GetMarkets is used to get the open and available trading markets at Bittrex
|
||||
// along with other meta data.
|
||||
func (b *Bittrex) GetMarkets() ([]Market, error) {
|
||||
var markets []Market
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s/", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetMarkets,
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return markets, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &markets); err != nil {
|
||||
return markets, err
|
||||
}
|
||||
return markets, nil
|
||||
}
|
||||
return markets, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetCurrencies is used to get all supported currencies at Bittrex
|
||||
func (b *Bittrex) GetCurrencies() ([]Currency, error) {
|
||||
var currencies []Currency
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s/", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetCurrencies,
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return currencies, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, ¤cies); err != nil {
|
||||
return currencies, err
|
||||
}
|
||||
return currencies, nil
|
||||
}
|
||||
return currencies, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetTicker sends a public get request and returns current ticker information
|
||||
// on the supplied currency. Example currency input param "btc-ltc".
|
||||
func (b *Bittrex) GetTicker(currencyPair string) (Ticker, error) {
|
||||
ticker := Ticker{}
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s?market=%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetTicker,
|
||||
common.StringToLower(currencyPair),
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return ticker, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &ticker); err != nil {
|
||||
return Ticker{}, err
|
||||
}
|
||||
return ticker, nil
|
||||
}
|
||||
return ticker, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetMarketSummaries is used to get the last 24 hour summary of all active
|
||||
// exchanges
|
||||
func (b *Bittrex) GetMarketSummaries() ([]MarketSummary, error) {
|
||||
var summaries []MarketSummary
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s/", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetMarketSummaries,
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return summaries, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &summaries); err != nil {
|
||||
return summaries, err
|
||||
}
|
||||
return summaries, nil
|
||||
}
|
||||
return summaries, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetMarketSummary is used to get the last 24 hour summary of all active
|
||||
// exchanges by currency pair (btc-ltc).
|
||||
func (b *Bittrex) GetMarketSummary(currencyPair string) ([]MarketSummary, error) {
|
||||
var summary []MarketSummary
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s?market=%s", bittrexAPIURL, bittrexAPIVersion,
|
||||
bittrexAPIGetMarketSummary, common.StringToLower(currencyPair),
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return summary, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &summary); err != nil {
|
||||
return summary, err
|
||||
}
|
||||
return summary, nil
|
||||
}
|
||||
return summary, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetOrderbook method returns current order book information by currency, type
|
||||
// & depth.
|
||||
// "Currency Pair" ie btc-ltc
|
||||
// "category" either "buy", "sell" or "both"
|
||||
// "Depth" is 1 -> 50, 50 is max.
|
||||
func (b *Bittrex) GetOrderbook(currencyPair, category string, depth int) (OrderBooks, error) {
|
||||
var orderbooks OrderBooks
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s?market=%s&type=%s&depth=%d", bittrexAPIURL, bittrexAPIVersion,
|
||||
bittrexAPIGetOrderbook, common.StringToUpper(currencyPair),
|
||||
common.StringToLower(category), depth,
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return orderbooks, err
|
||||
}
|
||||
|
||||
if resp.Success {
|
||||
if category == "buy" {
|
||||
if err = json.Unmarshal(resp.Result, &orderbooks.Buy); err != nil {
|
||||
return orderbooks, err
|
||||
}
|
||||
} else if category == "sell" {
|
||||
if err = json.Unmarshal(resp.Result, &orderbooks.Sell); err != nil {
|
||||
return orderbooks, err
|
||||
}
|
||||
} else if category == "both" {
|
||||
if err = json.Unmarshal(resp.Result, &orderbooks); err != nil {
|
||||
return orderbooks, err
|
||||
}
|
||||
}
|
||||
return orderbooks, nil
|
||||
}
|
||||
return orderbooks, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetMarketHistory retrieves the latest trades that have occured for a specific
|
||||
// market
|
||||
func (b *Bittrex) GetMarketHistory(currencyPair string) ([]MarketHistory, error) {
|
||||
var marketHistoriae []MarketHistory
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s?market=%s", bittrexAPIURL, bittrexAPIVersion,
|
||||
bittrexAPIGetMarketHistory, common.StringToUpper(currencyPair),
|
||||
)
|
||||
resp := Response{}
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return marketHistoriae, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &marketHistoriae); err != nil {
|
||||
return marketHistoriae, err
|
||||
}
|
||||
return marketHistoriae, nil
|
||||
}
|
||||
return marketHistoriae, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// PlaceBuyLimit is 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.
|
||||
// "Currency" ie "btc-ltc"
|
||||
// "Quantity" is the ammount to purchase
|
||||
// "Rate" is the rate at which to purchase
|
||||
func (b *Bittrex) PlaceBuyLimit(currencyPair string, quantity, rate float64) ([]UUID, error) {
|
||||
var id []UUID
|
||||
values := url.Values{}
|
||||
values.Set("market", currencyPair)
|
||||
values.Set("quantity", strconv.FormatFloat(quantity, 'E', -1, 64))
|
||||
values.Set("rate", strconv.FormatFloat(rate, 'E', -1, 64))
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetBalances,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &id); err != nil {
|
||||
return id, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
return id, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// PlaceSellLimit is used to place a 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 work.
|
||||
// "Currency" ie "btc-ltc"
|
||||
// "Quantity" is the ammount to purchase
|
||||
// "Rate" is the rate at which to purchase
|
||||
func (b *Bittrex) PlaceSellLimit(currencyPair string, quantity, rate float64) ([]UUID, error) {
|
||||
var id []UUID
|
||||
values := url.Values{}
|
||||
values.Set("market", currencyPair)
|
||||
values.Set("quantity", strconv.FormatFloat(quantity, 'E', -1, 64))
|
||||
values.Set("rate", strconv.FormatFloat(rate, 'E', -1, 64))
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetBalances,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &id); err != nil {
|
||||
return id, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
return id, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetOpenOrders returns all orders that you currently have opened.
|
||||
// A specific market can be requested for example "btc-ltc"
|
||||
func (b *Bittrex) GetOpenOrders(currencyPair string) ([]Order, error) {
|
||||
var orders []Order
|
||||
values := url.Values{}
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetBalances,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return orders, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &orders); err != nil {
|
||||
return orders, err
|
||||
}
|
||||
return orders, nil
|
||||
}
|
||||
return orders, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// CancelOrder is used to cancel a buy or sell order.
|
||||
func (b *Bittrex) CancelOrder(uuid string) ([]Balance, error) {
|
||||
var balances []Balance
|
||||
values := url.Values{}
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetBalances,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return balances, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &balances); err != nil {
|
||||
return balances, err
|
||||
}
|
||||
return balances, nil
|
||||
}
|
||||
return balances, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetAccountBalances is used to retrieve all balances from your account
|
||||
func (b *Bittrex) GetAccountBalances() ([]Balance, error) {
|
||||
var balances []Balance
|
||||
values := url.Values{}
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetBalances,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return balances, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &balances); err != nil {
|
||||
return balances, err
|
||||
}
|
||||
return balances, nil
|
||||
}
|
||||
return balances, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetAccountBalanceByCurrency is used to retrieve the balance from your account
|
||||
// for a specific currency. ie. "btc" or "ltc"
|
||||
func (b *Bittrex) GetAccountBalanceByCurrency(currency string) (Balance, error) {
|
||||
var balance Balance
|
||||
values := url.Values{}
|
||||
values.Set("currency", currency)
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetBalance,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return balance, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &balance); err != nil {
|
||||
return balance, err
|
||||
}
|
||||
return balance, nil
|
||||
}
|
||||
return balance, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetDepositAddress is 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.
|
||||
func (b *Bittrex) GetDepositAddress(currency string) (DepositAddress, error) {
|
||||
var address DepositAddress
|
||||
values := url.Values{}
|
||||
values.Set("currency", currency)
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetDepositAddress,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return address, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &address); err != nil {
|
||||
return address, err
|
||||
}
|
||||
return address, nil
|
||||
}
|
||||
return address, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// Withdraw is used to withdraw funds from your account.
|
||||
// note: Please account for transaction fee.
|
||||
func (b *Bittrex) Withdraw(currency, paymentID, address string, quantity float64) (UUID, error) {
|
||||
var id UUID
|
||||
values := url.Values{}
|
||||
values.Set("currency", currency)
|
||||
values.Set("quantity", strconv.FormatFloat(quantity, 'E', -1, 64))
|
||||
values.Set("address", address)
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIWithdraw,
|
||||
)
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &id); err != nil {
|
||||
return id, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
return id, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetOrder is used to retrieve a single order by UUID.
|
||||
func (b *Bittrex) GetOrder(uuid string) (Order, error) {
|
||||
var order Order
|
||||
values := url.Values{}
|
||||
values.Set("uuid", uuid)
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetOrder,
|
||||
)
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return order, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &order); err != nil {
|
||||
return order, err
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
return order, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetOrderHistory is used to retrieve your order history. If currencyPair
|
||||
// ommited it will return the entire order History.
|
||||
func (b *Bittrex) GetOrderHistory(currencyPair string) ([]Order, error) {
|
||||
var orders []Order
|
||||
values := url.Values{}
|
||||
|
||||
if !(currencyPair == "" || currencyPair == " ") {
|
||||
values.Set("market", currencyPair)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetOrderHistory,
|
||||
)
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return orders, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &orders); err != nil {
|
||||
return orders, err
|
||||
}
|
||||
return orders, nil
|
||||
}
|
||||
return orders, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetWithdrawelHistory is used to retrieve your withdrawal history. If currency
|
||||
// ommited it will return the entire history
|
||||
func (b *Bittrex) GetWithdrawelHistory(currency string) ([]WithdrawalHistory, error) {
|
||||
var history []WithdrawalHistory
|
||||
values := url.Values{}
|
||||
|
||||
if !(currency == "" || currency == " ") {
|
||||
values.Set("currency", currency)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetOrderHistory,
|
||||
)
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return history, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &history); err != nil {
|
||||
return history, err
|
||||
}
|
||||
return history, nil
|
||||
}
|
||||
return history, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// GetDepositHistory is used to retrieve your deposit history. If currency is
|
||||
// is ommitted it will return the entire deposit history
|
||||
func (b *Bittrex) GetDepositHistory(currency string) ([]WithdrawalHistory, error) {
|
||||
var history []WithdrawalHistory
|
||||
values := url.Values{}
|
||||
|
||||
if !(currency == "" || currency == " ") {
|
||||
values.Set("currency", currency)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", bittrexAPIURL, bittrexAPIVersion, bittrexAPIGetOrderHistory,
|
||||
)
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(path, values, &resp)
|
||||
if err != nil {
|
||||
return history, err
|
||||
}
|
||||
if resp.Success {
|
||||
if err = json.Unmarshal(resp.Result, &history); err != nil {
|
||||
return history, err
|
||||
}
|
||||
return history, nil
|
||||
}
|
||||
return history, errors.New(resp.Message)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated http request to a desired
|
||||
// path
|
||||
func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
values.Set("apikey", b.APIKey)
|
||||
values.Set("apisecret", b.APISecret)
|
||||
values.Set("nonce", nonce)
|
||||
rawQuery := path + "?" + values.Encode()
|
||||
hmac := common.GetHMAC(
|
||||
common.HashSHA512, []byte(rawQuery), []byte(b.APISecret),
|
||||
)
|
||||
headers := make(map[string]string)
|
||||
headers["apisign"] = common.HexEncodeToString(hmac)
|
||||
|
||||
resp, err := common.SendHTTPRequest(
|
||||
"GET", rawQuery, headers, strings.NewReader(""),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if b.Verbose {
|
||||
log.Printf("Recieved raw: %s\n", resp)
|
||||
}
|
||||
|
||||
err = common.JSONDecode([]byte(resp), &result)
|
||||
if err != nil {
|
||||
return errors.New("Unable to JSON Unmarshal response." + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
280
exchanges/bittrex/bittrex_test.go
Normal file
280
exchanges/bittrex/bittrex_test.go
Normal file
@@ -0,0 +1,280 @@
|
||||
package bittrex
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
// Please supply you own test keys here to run better tests.
|
||||
const (
|
||||
apiKey = "TestKey"
|
||||
apiSecret = "TestKey"
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
b := Bittrex{}
|
||||
b.SetDefaults()
|
||||
if b.GetName() != "Bittrex" {
|
||||
t.Error("Test Failed - Bittrex - SetDefaults() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
exch := config.ExchangeConfig{
|
||||
Name: "Bittrex",
|
||||
APIKey: apiKey,
|
||||
}
|
||||
exch.Enabled = true
|
||||
b := Bittrex{}
|
||||
b.Setup(exch)
|
||||
if b.APIKey != apiKey {
|
||||
t.Error("Test Failed - Bittrex - Setup() error")
|
||||
}
|
||||
exch.Enabled = false
|
||||
b.Setup(exch)
|
||||
if b.IsEnabled() {
|
||||
t.Error("Test Failed - Bittrex - Setup() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMarkets(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarkets()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetMarkets() error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetCurrencies()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetCurrencies() error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
invalid := ""
|
||||
btc := "btc-ltc"
|
||||
doge := "btc-DOGE"
|
||||
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetTicker(invalid)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetTicker() error")
|
||||
}
|
||||
_, err = obj.GetTicker(btc)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetTicker() error: %s", err)
|
||||
}
|
||||
_, err = obj.GetTicker(doge)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetTicker() error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMarketSummaries(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarketSummaries()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetMarketSummaries() error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMarketSummary(t *testing.T) {
|
||||
pairOne := "BTC-LTC"
|
||||
invalid := "WigWham"
|
||||
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarketSummary(pairOne)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetMarketSummary() error: %s", err)
|
||||
}
|
||||
_, err = obj.GetMarketSummary(invalid)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetMarketSummary() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
value, err := obj.GetOrderbook("btc-ltc", "buy", 1)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrderbook() error: %s", err)
|
||||
}
|
||||
if len(value.Sell) > 0 {
|
||||
t.Error("Test Failed - Bittrex - GetOrderbook() error")
|
||||
}
|
||||
value, err = obj.GetOrderbook("btc-ltc", "sell", 1)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrderbook() error: %s", err)
|
||||
}
|
||||
if len(value.Buy) > 0 {
|
||||
t.Error("Test Failed - Bittrex - GetOrderbook() error")
|
||||
}
|
||||
_, err = obj.GetOrderbook("btc-ltc", "both", 1)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrderbook() error: %s", err)
|
||||
}
|
||||
_, err = obj.GetOrderbook("btc-ltc", "Whigwham", 1)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetOrderbook() error")
|
||||
}
|
||||
_, err = obj.GetOrderbook("btc-ltc", "Whigwham", 51)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetOrderbook() error")
|
||||
}
|
||||
_, err = obj.GetOrderbook("wiggy", "both", 1)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetOrderbook() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMarketHistory(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarketHistory("btc-ltc")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetMarketHistory() error: %s", err)
|
||||
}
|
||||
_, err = obj.GetMarketHistory("malum")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetMarketHistory() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceBuyLimit(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.PlaceBuyLimit("btc-ltc", 1, 1)
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - PlaceBuyLimit() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceSellLimit(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.PlaceSellLimit("btc-ltc", 1, 1)
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - PlaceSellLimit() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOpenOrders(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetOpenOrders("")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.CancelOrder("blaaaaaaa")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - CancelOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountBalances(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetAccountBalances()
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetAccountBalances() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountBalanceByCurrency(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetAccountBalanceByCurrency("btc")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetAccountBalanceByCurrency() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetDepositAddress("btc")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetDepositAddress() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.Withdraw("btc", "something", "someplace", 1)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - Withdraw() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrder(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetOrder("0cb4c4e4-bdc7-4e13-8c13-430e587d2cc1")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrder() error")
|
||||
}
|
||||
_, err = obj.GetOrder("")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetOrderHistory("")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrderHistory() error")
|
||||
}
|
||||
_, err = obj.GetOrderHistory("btc-ltc")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetOrderHistory() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetWithdrawelHistory(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetWithdrawelHistory("")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetWithdrawelHistory() error")
|
||||
}
|
||||
_, err = obj.GetWithdrawelHistory("btc-ltc")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetWithdrawelHistory() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositHistory(t *testing.T) {
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetDepositHistory("")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetDepositHistory() error")
|
||||
}
|
||||
_, err = obj.GetDepositHistory("btc-ltc")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - Bittrex - GetDepositHistory() error")
|
||||
}
|
||||
}
|
||||
147
exchanges/bittrex/bittrex_types.go
Normal file
147
exchanges/bittrex/bittrex_types.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package bittrex
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Response is the generalised response type for Bittrex
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Result json.RawMessage `json:"result"`
|
||||
}
|
||||
|
||||
// Market holds current market metadata
|
||||
type Market struct {
|
||||
MarketCurrency string `json:"MarketCurrency"`
|
||||
BaseCurrency string `json:"BaseCurrency"`
|
||||
MarketCurrencyLong string `json:"MarketCurrencyLong"`
|
||||
BaseCurrencyLong string `json:"BaseCurrencyLong"`
|
||||
MinTradeSize float64 `json:"MinTradeSize"`
|
||||
MarketName string `json:"MarketName"`
|
||||
IsActive bool `json:"IsActive"`
|
||||
Created string `json:"Created"`
|
||||
}
|
||||
|
||||
// Currency holds supported currency metadata
|
||||
type Currency struct {
|
||||
Currency string `json:"Currency"`
|
||||
CurrencyLong string `json:"CurrencyLong"`
|
||||
MinConfirmation int `json:"MinConfirmation"`
|
||||
TxFee float64 `json:"TxFee"`
|
||||
IsActive bool `json:"IsActive"`
|
||||
CoinType string `json:"CoinType"`
|
||||
BaseAddress string `json:"BaseAddress"`
|
||||
}
|
||||
|
||||
// Ticker holds basic ticker information
|
||||
type Ticker struct {
|
||||
Bid float64 `json:"Bid"`
|
||||
Ask float64 `json:"Ask"`
|
||||
Last float64 `json:"Last"`
|
||||
}
|
||||
|
||||
// MarketSummary holds last 24 hour metadata of an active exchange
|
||||
type MarketSummary struct {
|
||||
MarketName string `json:"MarketName"`
|
||||
High float64 `json:"High"`
|
||||
Low float64 `json:"Low"`
|
||||
Volume float64 `json:"Volume"`
|
||||
Last float64 `json:"Last"`
|
||||
BaseVolume float64 `json:"BaseVolume"`
|
||||
TimeStamp string `json:"TimeStamp"`
|
||||
Bid float64 `json:"Bid"`
|
||||
Ask float64 `json:"Ask"`
|
||||
OpenBuyOrders int `json:"OpenBuyOrders"`
|
||||
OpenSellOrders int `json:"OpenSellOrders"`
|
||||
PrevDay float64 `json:"PrevDay"`
|
||||
Created string `json:"Created"`
|
||||
DisplayMarketName string `json:"DisplayMarketName"`
|
||||
}
|
||||
|
||||
// OrderBooks holds an array of buy & sell orders held on the exchange
|
||||
type OrderBooks struct {
|
||||
Buy []OrderBook `json:"buy"`
|
||||
Sell []OrderBook `json:"sell"`
|
||||
}
|
||||
|
||||
// OrderBook holds a singular order on an exchange
|
||||
type OrderBook struct {
|
||||
Quantity float64 `json:"Quantity"`
|
||||
Rate float64 `json:"Rate"`
|
||||
}
|
||||
|
||||
// MarketHistory holds an executed trade's data for a market ie "BTC-LTC"
|
||||
type MarketHistory struct {
|
||||
ID int `json:"Id"`
|
||||
Timestamp string `json:"TimeStamp"`
|
||||
Quantity float64 `json:"Quantity"`
|
||||
Price float64 `json:"Price"`
|
||||
Total float64 `json:"Total"`
|
||||
FillType string `json:"FillType"`
|
||||
OrderType string `json:"OrderType"`
|
||||
}
|
||||
|
||||
// Balance holds the balance from your account for a specified currency
|
||||
type Balance struct {
|
||||
Currency string `json:"Currency"`
|
||||
Balance float64 `json:"Balance"`
|
||||
Available float64 `json:"Available"`
|
||||
Pending float64 `json:"Pending"`
|
||||
CryptoAddress string `json:"CryptoAddress"`
|
||||
Requested bool `json:"Requested"`
|
||||
UUID string `json:"Uuid"`
|
||||
}
|
||||
|
||||
// DepositAddress holds a generated address to send specific coins to the
|
||||
// exchange
|
||||
type DepositAddress struct {
|
||||
Currency string `json:"Currency"`
|
||||
Address string `json:"Address"`
|
||||
}
|
||||
|
||||
// UUID contains the universal unique identifier for one or multiple
|
||||
// transactions on the exchange
|
||||
type UUID struct {
|
||||
ID string `json:"uuid"`
|
||||
}
|
||||
|
||||
// Order holds the full order information associated with the UUID supplied
|
||||
type Order struct {
|
||||
AccountID string `json:"AccountId"`
|
||||
OrderUUID string `json:"OrderUuid"`
|
||||
Exchange string `json:"Exchange"`
|
||||
Type string `json:"Type"`
|
||||
Quantity float64 `json:"Quantity"`
|
||||
QuantityRemaining float64 `json:"QuantityRemaining"`
|
||||
Limit float64 `json:"Limit"`
|
||||
Reserved float64 `json:"Reserved"`
|
||||
ReserveRemaining float64 `json:"ReserveRemaining"`
|
||||
CommissionReserved float64 `json:"CommissionReserved"`
|
||||
CommissionReserveRemaining float64 `json:"CommissionReserveRemaining"`
|
||||
CommissionPaid float64 `json:"CommissionPaid"`
|
||||
Price float64 `json:"Price"`
|
||||
PricePerUnit float64 `json:"PricePerUnit"`
|
||||
Opened string `json:"Opened"`
|
||||
Closed string `json:"Closed"`
|
||||
IsOpen bool `json:"IsOpen"`
|
||||
Sentinel string `json:"Sentinel"`
|
||||
CancelInitiated bool `json:"CancelInitiated"`
|
||||
ImmediateOrCancel bool `json:"ImmediateOrCancel"`
|
||||
IsConditional bool `json:"IsConditional"`
|
||||
Condition string `json:"Condition"`
|
||||
ConditionTarget string `json:"ConditionTarget"`
|
||||
}
|
||||
|
||||
// WithdrawalHistory holds the Withdrawal history data
|
||||
type WithdrawalHistory struct {
|
||||
PaymentUUID string `json:"PaymentUuid"`
|
||||
Currency string `json:"Currency"`
|
||||
Amount float64 `json:"Amount"`
|
||||
Address string `json:"Address"`
|
||||
Opened string `json:"Opened"`
|
||||
Authorized bool `json:"Authorized"`
|
||||
PendingPayment bool `json:"PendingPayment"`
|
||||
TxCost float64 `json:"TxCost"`
|
||||
TxID string `json:"TxId"`
|
||||
Canceled bool `json:"Canceled"`
|
||||
InvalidAddress bool `json:"InvalidAddress"`
|
||||
}
|
||||
Reference in New Issue
Block a user