Introduce request package and integrate with exchanges

This commit is contained in:
Ryan O'Hara-Reid
2018-03-27 14:05:15 +11:00
committed by Adrian Gallagher
parent 52dfddbb18
commit 7fc9d20fd7
52 changed files with 1990 additions and 1544 deletions

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"log"
"net/http"
"strconv"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -36,14 +38,16 @@ const (
alphapointOpenOrders = "GetAccountOpenOrders"
alphapointOrderFee = "GetOrderFee"
// Anymore and you get IP banned
alphapointMaxRequestsPer10minutes = 500
// alphapoint rate times
alphapointAuthRate = 1200
alphapointUnauthRate = 1200
)
// Alphapoint is the overarching type across the alphapoint package
type Alphapoint struct {
exchange.Base
WebsocketConn *websocket.Conn
*request.Handler
}
// SetDefaults sets current default settings
@@ -52,6 +56,8 @@ func (a *Alphapoint) SetDefaults() {
a.WebsocketURL = alphapointDefaultWebsocketURL
a.AssetTypes = []string{ticker.Spot}
a.SupportsAutoPairUpdating = false
a.Handler = new(request.Handler)
a.SetRequestHandler(a.Name, alphapointAuthRate, alphapointUnauthRate, new(http.Client))
}
// GetTicker returns current ticker information from Alphapoint for a selected
@@ -61,7 +67,7 @@ func (a *Alphapoint) GetTicker(currencyPair string) (Ticker, error) {
request["productPair"] = currencyPair
response := Ticker{}
err := a.SendRequest("POST", alphapointTicker, request, &response)
err := a.SendHTTPRequest("POST", alphapointTicker, request, &response)
if err != nil {
return response, err
}
@@ -84,7 +90,7 @@ func (a *Alphapoint) GetTrades(currencyPair string, startIndex, count int) (Trad
request["Count"] = count
response := Trades{}
err := a.SendRequest("POST", alphapointTrades, request, &response)
err := a.SendHTTPRequest("POST", alphapointTrades, request, &response)
if err != nil {
return response, err
}
@@ -105,7 +111,7 @@ func (a *Alphapoint) GetTradesByDate(currencyPair string, startDate, endDate int
request["endDate"] = endDate
response := Trades{}
err := a.SendRequest("POST", alphapointTradesByDate, request, &response)
err := a.SendHTTPRequest("POST", alphapointTradesByDate, request, &response)
if err != nil {
return response, err
}
@@ -122,7 +128,7 @@ func (a *Alphapoint) GetOrderbook(currencyPair string) (Orderbook, error) {
request["productPair"] = currencyPair
response := Orderbook{}
err := a.SendRequest("POST", alphapointOrderbook, request, &response)
err := a.SendHTTPRequest("POST", alphapointOrderbook, request, &response)
if err != nil {
return response, err
}
@@ -136,7 +142,7 @@ func (a *Alphapoint) GetOrderbook(currencyPair string) (Orderbook, error) {
func (a *Alphapoint) GetProductPairs() (ProductPairs, error) {
response := ProductPairs{}
err := a.SendRequest("POST", alphapointProductPairs, nil, &response)
err := a.SendHTTPRequest("POST", alphapointProductPairs, nil, &response)
if err != nil {
return response, err
}
@@ -150,7 +156,7 @@ func (a *Alphapoint) GetProductPairs() (ProductPairs, error) {
func (a *Alphapoint) GetProducts() (Products, error) {
response := Products{}
err := a.SendRequest("POST", alphapointProducts, nil, &response)
err := a.SendHTTPRequest("POST", alphapointProducts, nil, &response)
if err != nil {
return response, err
}
@@ -504,8 +510,8 @@ func (a *Alphapoint) GetOrderFee(symbol, side string, quantity, price float64) (
return response.Fee, nil
}
// SendRequest sends an unauthenticated request
func (a *Alphapoint) SendRequest(method, path string, data map[string]interface{}, result interface{}) error {
// SendHTTPRequest sends an unauthenticated HTTP request
func (a *Alphapoint) SendHTTPRequest(method, path string, data map[string]interface{}, result interface{}) error {
headers := make(map[string]string)
headers["Content-Type"] = "application/json"
path = fmt.Sprintf("%s/ajax/v%s/%s", a.APIUrl, alphapointAPIVersion, path)
@@ -515,21 +521,7 @@ func (a *Alphapoint) SendRequest(method, path string, data map[string]interface{
return errors.New("SendHTTPRequest: Unable to JSON request")
}
resp, err := common.SendHTTPRequest(
method,
path,
headers,
bytes.NewBuffer(PayloadJSON),
)
if err != nil {
return err
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, a.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated request
@@ -557,16 +549,5 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[
return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request")
}
resp, err := common.SendHTTPRequest(
method, path, headers, bytes.NewBuffer(PayloadJSON),
)
if err != nil {
return err
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, a.Verbose)
}

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"log"
"net/http"
"strconv"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -27,11 +29,16 @@ const (
anxCreateAddress = "receive/create"
anxTicker = "money/ticker"
anxDepth = "money/depth/full"
// ANX rate limites for authenticated and unauthenticated requests
anxAuthRate = 1000
anxUnauthRate = 1000
)
// ANX is the overarching type across the alphapoint package
type ANX struct {
exchange.Base
*request.Handler
}
// SetDefaults sets current default settings
@@ -51,6 +58,8 @@ func (a *ANX) SetDefaults() {
a.ConfigCurrencyPairFormat.Index = "BTC"
a.AssetTypes = []string{ticker.Spot}
a.SupportsAutoPairUpdating = false
a.Handler = new(request.Handler)
a.SetRequestHandler(a.Name, anxAuthRate, anxUnauthRate, new(http.Client))
}
//Setup is run on startup to setup exchange with config values
@@ -95,7 +104,7 @@ func (a *ANX) GetTicker(currency string) (Ticker, error) {
var ticker Ticker
path := fmt.Sprintf("%sapi/2/%s/%s", anxAPIURL, currency, anxTicker)
return ticker, common.SendHTTPGetRequest(path, true, a.Verbose, &ticker)
return ticker, a.SendHTTPRequest(path, &ticker)
}
// GetDepth returns current orderbook depth.
@@ -103,7 +112,7 @@ func (a *ANX) GetDepth(currency string) (Depth, error) {
var depth Depth
path := fmt.Sprintf("%sapi/2/%s/%s", anxAPIURL, currency, anxDepth)
return depth, common.SendHTTPGetRequest(path, true, a.Verbose, &depth)
return depth, a.SendHTTPRequest(path, &depth)
}
// GetAPIKey returns a new generated API key set.
@@ -324,6 +333,11 @@ func (a *ANX) GetDepositAddress(currency, name string, new bool) (string, error)
return response.Address, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (a *ANX) SendHTTPRequest(path string, result interface{}) error {
return a.SendPayload("GET", path, nil, nil, result, false, a.Verbose)
}
// SendAuthenticatedHTTPRequest sends a authenticated HTTP request
func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interface{}, result interface{}) error {
if !a.AuthenticatedAPISupport {
@@ -362,20 +376,5 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf
headers["Rest-Sign"] = common.Base64Encode([]byte(hmac))
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest("POST", anxAPIURL+path, headers, bytes.NewBuffer(PayloadJSON))
if err != nil {
return err
}
if a.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return a.SendPayload("POST", anxAPIURL+path, headers, bytes.NewBuffer(PayloadJSON), result, true, a.Verbose)
}

View File

@@ -6,92 +6,88 @@ import (
"github.com/thrasher-/gocryptotrader/config"
)
func TestSetDefaults(t *testing.T) {
setDefaults := ANX{}
setDefaults.SetDefaults()
var anx ANX
if setDefaults.Name != "ANX" {
func TestSetDefaults(t *testing.T) {
anx.SetDefaults()
if anx.Name != "ANX" {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if setDefaults.Enabled != false {
if anx.Enabled != false {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if setDefaults.TakerFee != 0.6 {
if anx.TakerFee != 0.6 {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if setDefaults.MakerFee != 0.3 {
if anx.MakerFee != 0.3 {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if setDefaults.Verbose != false {
if anx.Verbose != false {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if setDefaults.Websocket != false {
if anx.Websocket != false {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if setDefaults.RESTPollingDelay != 10 {
if anx.RESTPollingDelay != 10 {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
}
func TestSetup(t *testing.T) {
setup := ANX{}
setup.Name = "ANX"
anxSetupConfig := config.GetConfig()
anxSetupConfig.LoadConfig("../../testdata/configtest.json")
anxConfig, err := anxSetupConfig.GetExchangeConfig("ANX")
if err != nil {
t.Error("Test Failed - ANX Setup() init error")
}
setup.Setup(anxConfig)
anx.Setup(anxConfig)
if setup.Enabled != true {
if anx.Enabled != true {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if setup.AuthenticatedAPISupport != false {
if anx.AuthenticatedAPISupport != false {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(setup.APIKey) != 0 {
if len(anx.APIKey) != 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(setup.APISecret) != 0 {
if len(anx.APISecret) != 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if setup.RESTPollingDelay != 10 {
if anx.RESTPollingDelay != 10 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if setup.Verbose != false {
if anx.Verbose != false {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if setup.Websocket != false {
if anx.Websocket != false {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(setup.BaseCurrencies) <= 0 {
if len(anx.BaseCurrencies) <= 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(setup.AvailablePairs) <= 0 {
if len(anx.AvailablePairs) <= 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(setup.EnabledPairs) <= 0 {
if len(anx.EnabledPairs) <= 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
}
func TestGetFee(t *testing.T) {
getFee := ANX{}
makerFeeExpected, takerFeeExpected := 0.3, 0.6
getFee.SetDefaults()
if getFee.GetFee(true) != makerFeeExpected {
if anx.GetFee(true) != makerFeeExpected {
t.Error("Test Failed - ANX GetFee() incorrect return value")
}
if getFee.GetFee(false) != takerFeeExpected {
if anx.GetFee(false) != takerFeeExpected {
t.Error("Test Failed - ANX GetFee() incorrect return value")
}
}
func TestGetTicker(t *testing.T) {
getTicker := ANX{}
ticker, err := getTicker.GetTicker("BTCUSD")
ticker, err := anx.GetTicker("BTCUSD")
if err != nil {
t.Errorf("Test Failed - ANX GetTicker() error: %s", err)
}
@@ -101,8 +97,7 @@ func TestGetTicker(t *testing.T) {
}
func TestGetDepth(t *testing.T) {
a := ANX{}
ticker, err := a.GetDepth("BTCUSD")
ticker, err := anx.GetDepth("BTCUSD")
if err != nil {
t.Errorf("Test Failed - ANX GetDepth() error: %s", err)
}
@@ -112,8 +107,7 @@ func TestGetDepth(t *testing.T) {
}
func TestGetAPIKey(t *testing.T) {
getAPIKey := ANX{}
apiKey, apiSecret, err := getAPIKey.GetAPIKey("userName", "passWord", "", "1337")
apiKey, apiSecret, err := anx.GetAPIKey("userName", "passWord", "", "1337")
if err == nil {
t.Error("Test Failed - ANX GetAPIKey() Incorrect")
}
@@ -124,38 +118,3 @@ func TestGetAPIKey(t *testing.T) {
t.Error("Test Failed - ANX GetAPIKey() Incorrect")
}
}
func TestGetDataToken(t *testing.T) {
// --- FAIL: TestGetDataToken (0.17s)
// anx_test.go:120: Test Failed - ANX GetDataToken() Incorrect
// getDataToken := ANX{}
// _, err := getDataToken.GetDataToken()
// if err != nil {
// t.Error("Test Failed - ANX GetDataToken() Incorrect")
// }
}
func TestNewOrder(t *testing.T) {
}
func TestOrderInfo(t *testing.T) {
}
func TestSend(t *testing.T) {
}
func TestCreateNewSubAccount(t *testing.T) {
}
func TestGetDepositAddress(t *testing.T) {
}
func TestSendAuthenticatedHTTPRequest(t *testing.T) {
}

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -22,6 +24,7 @@ type Binance struct {
// valid string list that a required by the exchange
validLimits []string
validIntervals []string
*request.Handler
}
const (
@@ -39,10 +42,13 @@ const (
bestPrice = "/api/v3/ticker/bookTicker"
// Authenticated endpoints
newOrderTest = "/api/v3/order/test"
newOrder = "/api/v3/order"
queryOrder = "/api/v3/order"
// binance authenticated and unauthenticated limit rates
binanceAuthRate = 1000
binanceUnauthRate = 1000
)
// SetDefaults sets the basic defaults for Binance
@@ -59,6 +65,8 @@ func (b *Binance) SetDefaults() {
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.SetValues()
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, binanceAuthRate, binanceUnauthRate, new(http.Client))
}
// Setup takes in the supplied exchange configuration details and sets params
@@ -114,7 +122,7 @@ func (b *Binance) GetExchangeInfo() (ExchangeInfo, error) {
var resp ExchangeInfo
path := apiURL + exchangeInfo
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetOrderBook returns full orderbook information
@@ -137,7 +145,7 @@ func (b *Binance) GetOrderBook(symbol string, limit int64) (OrderBook, error) {
path := fmt.Sprintf("%s%s?%s", apiURL, orderBookDepth, params.Encode())
if err := common.SendHTTPGetRequest(path, true, b.Verbose, &resp); err != nil {
if err := b.SendHTTPRequest(path, &resp); err != nil {
return orderbook, err
}
@@ -195,7 +203,7 @@ func (b *Binance) GetRecentTrades(symbol string, limit int64) ([]RecentTrade, er
path := fmt.Sprintf("%s%s?%s", apiURL, recentTrades, params.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetHistoricalTrades returns historical trade activity
@@ -220,7 +228,7 @@ func (b *Binance) GetHistoricalTrades(symbol string, limit, fromID int64) ([]His
path := fmt.Sprintf("%s%s?%s", apiURL, historicalTrades, params.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetAggregatedTrades returns aggregated trade activity
@@ -243,7 +251,7 @@ func (b *Binance) GetAggregatedTrades(symbol string, limit int64) ([]AggregatedT
path := fmt.Sprintf("%s%s?%s", apiURL, aggregatedTrades, params.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetCandleStickData returns candle stick data
@@ -272,7 +280,7 @@ func (b *Binance) GetCandleStickData(symbol, interval string, limit int64) ([]Ca
path := fmt.Sprintf("%s%s?%s", apiURL, candleStick, params.Encode())
if err := common.SendHTTPGetRequest(path, true, b.Verbose, &resp); err != nil {
if err := b.SendHTTPRequest(path, &resp); err != nil {
return kline, err
}
@@ -324,14 +332,14 @@ func (b *Binance) GetPriceChangeStats(symbol string) (PriceChangeStats, error) {
path := fmt.Sprintf("%s%s?%s", apiURL, priceChange, params.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetTickers returns the ticker data for the last 24 hrs
func (b *Binance) GetTickers() ([]PriceChangeStats, error) {
var resp []PriceChangeStats
path := fmt.Sprintf("%s%s", apiURL, priceChange)
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetLatestSpotPrice returns latest spot price of symbol
@@ -349,7 +357,7 @@ func (b *Binance) GetLatestSpotPrice(symbol string) (SymbolPrice, error) {
path := fmt.Sprintf("%s%s?%s", apiURL, symbolPrice, params.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// GetBestPrice returns the latest best price for symbol
@@ -367,7 +375,7 @@ func (b *Binance) GetBestPrice(symbol string) (BestPrice, error) {
path := fmt.Sprintf("%s%s?%s", apiURL, bestPrice, params.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPRequest(path, &resp)
}
// NewOrderTest sends a new order
@@ -434,7 +442,12 @@ func (b *Binance) QueryOrder(symbol, origClientOrderID string, orderID int64) (Q
return resp, nil
}
// SendAuthHTTPRequest something
// SendHTTPRequest sends an unauthenticated request
func (b *Binance) SendHTTPRequest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthHTTPRequest sends an authenticated HTTP request
func (b *Binance) SendAuthHTTPRequest(method, path string, params url.Values, result interface{}) error {
if !b.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
@@ -459,19 +472,7 @@ func (b *Binance) SendAuthHTTPRequest(method, path string, params url.Values, re
log.Printf("sent path: \n%s\n", path)
}
resp, err := common.SendHTTPRequest(method, path, headers, bytes.NewBufferString(params.Encode()))
if err != nil {
return err
}
if b.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
if err = common.JSONDecode([]byte(resp), &result); err != nil {
return errors.New("sendAuthenticatedHTTPRequest: Unable to JSON Unmarshal response." + err.Error())
}
return nil
return b.SendPayload(method, path, headers, bytes.NewBufferString(params.Encode()), result, true, b.Verbose)
}
// CheckLimit checks value against a variable list

View File

@@ -4,15 +4,16 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -66,9 +67,9 @@ const (
bitfinexActiveCredits = "credits"
bitfinexPlatformStatus = "platform/status"
// bitfinexMaxRequests if exceeded IP address blocked 10-60 sec, JSON response
// {"error": "ERR_RATE_LIMIT"}
bitfinexMaxRequests = 90
// stable times in millisecond per request
bitfinexAuthRate = 2750
bitfinexUnauthRate = 2750
// Bitfinex platform status values
// When the platform is marked in maintenance mode bots should stop trading
@@ -85,6 +86,7 @@ type Bitfinex struct {
exchange.Base
WebsocketConn *websocket.Conn
WebsocketSubdChannels map[int]WebsocketChanInfo
*request.Handler
}
// SetDefaults sets the basic defaults for bitfinex
@@ -101,6 +103,8 @@ func (b *Bitfinex) SetDefaults() {
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, bitfinexAuthRate, bitfinexUnauthRate, new(http.Client))
}
// Setup takes in the supplied exchange configuration details and sets params
@@ -138,7 +142,7 @@ func (b *Bitfinex) GetPlatformStatus() (int, error) {
path := fmt.Sprintf("%s/v%s/%s", bitfinexAPIURLBase, bitfinexAPIVersion2,
bitfinexPlatformStatus)
err := common.SendHTTPGetRequest(path, true, b.Verbose, &response)
err := b.SendHTTPRequest(path, &response, b.Verbose)
if err != nil {
return 0, err
}
@@ -155,7 +159,15 @@ func (b *Bitfinex) GetTicker(symbol string, values url.Values) (Ticker, error) {
response := Ticker{}
path := common.EncodeURLValues(bitfinexAPIURL+bitfinexTicker+symbol, values)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
if err := b.SendHTTPRequest(path, &response, b.Verbose); err != nil {
return response, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
// GetTickerV2 returns ticker information
@@ -164,7 +176,7 @@ func (b *Bitfinex) GetTickerV2(symbol string) (Tickerv2, error) {
var ticker Tickerv2
path := fmt.Sprintf("%s/v%s/%s/%s", bitfinexAPIURLBase, bitfinexAPIVersion2, bitfinexTickerV2, symbol)
err := common.SendHTTPGetRequest(path, true, b.Verbose, &response)
err := b.SendHTTPRequest(path, &response, b.Verbose)
if err != nil {
return ticker, err
}
@@ -207,7 +219,7 @@ func (b *Bitfinex) GetTickersV2(symbols string) ([]Tickersv2, error) {
v.Set("symbols", symbols)
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s", bitfinexAPIURLBase, bitfinexAPIVersion2, bitfinexTickersV2), v)
err := common.SendHTTPGetRequest(path, true, b.Verbose, &response)
err := b.SendHTTPRequest(path, &response, b.Verbose)
if err != nil {
return nil, err
}
@@ -253,7 +265,7 @@ func (b *Bitfinex) GetStats(symbol string) ([]Stat, error) {
response := []Stat{}
path := fmt.Sprint(bitfinexAPIURL + bitfinexStats + symbol)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetFundingBook the entire margin funding book for both bids and asks sides
@@ -263,7 +275,15 @@ func (b *Bitfinex) GetFundingBook(symbol string) (FundingBook, error) {
response := FundingBook{}
path := fmt.Sprint(bitfinexAPIURL + bitfinexLendbook + symbol)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
if err := b.SendHTTPRequest(path, &response, b.Verbose); err != nil {
return response, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
// GetOrderbook retieves the orderbook bid and ask price points for a currency
@@ -277,7 +297,7 @@ func (b *Bitfinex) GetOrderbook(currencyPair string, values url.Values) (Orderbo
bitfinexAPIURL+bitfinexOrderbook+currencyPair,
values,
)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetOrderbookV2 retieves the orderbook bid and ask price points for a currency
@@ -291,7 +311,7 @@ func (b *Bitfinex) GetOrderbookV2(symbol, precision string, values url.Values) (
var book OrderbookV2
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s/%s", bitfinexAPIURLBase,
bitfinexAPIVersion2, bitfinexOrderbookV2, symbol, precision), values)
err := common.SendHTTPGetRequest(path, true, b.Verbose, &response)
err := b.SendHTTPRequest(path, &response, b.Verbose)
if err != nil {
return book, err
}
@@ -339,7 +359,7 @@ func (b *Bitfinex) GetTrades(currencyPair string, values url.Values) ([]TradeStr
bitfinexAPIURL+bitfinexTrades+currencyPair,
values,
)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetTradesV2 uses the V2 API to get historic trades that occurred on the
@@ -359,7 +379,7 @@ func (b *Bitfinex) GetTradesV2(currencyPair string, timestampStart, timestampEnd
strconv.FormatInt(timestampStart, 10),
strconv.FormatInt(timestampEnd, 10))
err := common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
err := b.SendHTTPRequest(path, &resp, b.Verbose)
if err != nil {
return actualHistory, err
}
@@ -403,7 +423,7 @@ func (b *Bitfinex) GetLendbook(symbol string, values url.Values) (Lendbook, erro
}
path := common.EncodeURLValues(bitfinexAPIURL+bitfinexLendbook+symbol, values)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetLends returns a list of the most recent funding data for the given
@@ -414,7 +434,7 @@ func (b *Bitfinex) GetLends(symbol string, values url.Values) ([]Lends, error) {
response := []Lends{}
path := common.EncodeURLValues(bitfinexAPIURL+bitfinexLends+symbol, values)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetSymbols returns the available currency pairs on the exchange
@@ -422,7 +442,7 @@ func (b *Bitfinex) GetSymbols() ([]string, error) {
products := []string{}
path := fmt.Sprint(bitfinexAPIURL + bitfinexSymbols)
return products, common.SendHTTPGetRequest(path, true, b.Verbose, &products)
return products, b.SendHTTPRequest(path, &products, b.Verbose)
}
// GetSymbolsDetails a list of valid symbol IDs and the pair details
@@ -430,23 +450,33 @@ func (b *Bitfinex) GetSymbolsDetails() ([]SymbolDetails, error) {
response := []SymbolDetails{}
path := fmt.Sprint(bitfinexAPIURL + bitfinexSymbolsDetails)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetAccountInfo returns information about your account incl. trading fees
func (b *Bitfinex) GetAccountInfo() ([]AccountInfo, error) {
response := []AccountInfo{}
response := AccountInfoFull{}
return response,
b.SendAuthenticatedHTTPRequest("POST", bitfinexAccountInfo, nil, &response)
err := b.SendAuthenticatedHTTPRequest("POST", bitfinexAccountFees, nil, &response)
if err != nil {
return response.Info, err
}
if response.Message == "" {
return response.Info, errors.New(response.Message)
}
return response.Info, nil
}
// GetAccountFees - NOT YET IMPLEMENTED
func (b *Bitfinex) GetAccountFees() (AccountFees, error) {
response := AccountFees{}
return response,
b.SendAuthenticatedHTTPRequest("POST", bitfinexAccountFees, nil, &response)
err := b.SendAuthenticatedHTTPRequest("POST", bitfinexAccountFees, nil, &response)
if err != nil {
return response, err
}
return response, nil
}
// GetAccountSummary returns a 30-day summary of your trading volume and return
@@ -804,6 +834,11 @@ func (b *Bitfinex) CloseMarginFunding(SwapID int64) (Offer, error) {
b.SendAuthenticatedHTTPRequest("POST", bitfinexMarginClose, request, &response)
}
// SendHTTPRequest sends an unauthenticated request
func (b *Bitfinex) SendHTTPRequest(path string, result interface{}, verbose bool) error {
return b.SendPayload("GET", path, nil, nil, result, false, verbose)
}
// SendAuthenticatedHTTPRequest sends an autheticated http request and json
// unmarshals result to a supplied variable
func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) error {
@@ -817,7 +852,6 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
b.Nonce.Inc()
}
respErr := ErrorCapture{}
request := make(map[string]interface{})
request["request"] = fmt.Sprintf("/v%s/%s", bitfinexAPIVersion, path)
request["nonce"] = b.Nonce.String()
@@ -844,25 +878,9 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
headers["X-BFX-PAYLOAD"] = PayloadBase64
headers["X-BFX-SIGNATURE"] = common.HexEncodeToString(hmac)
resp, err := common.SendHTTPRequest(
method, bitfinexAPIURL+path, headers, strings.NewReader(""),
)
b.SendPayload(method, bitfinexAPIURL+path, headers, nil, result, true, b.Verbose)
if err != nil {
return err
}
if b.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
if err = common.JSONDecode([]byte(resp), &respErr); err == nil {
if len(respErr.Message) != 0 {
return errors.New("Responded Error Issue: " + respErr.Message)
}
}
if err = common.JSONDecode([]byte(resp), &result); err != nil {
return errors.New("sendAuthenticatedHTTPRequest: Unable to JSON Unmarshal response")
}
return nil
}

View File

@@ -18,28 +18,14 @@ const (
var b Bitfinex
func TestSetDefaults(t *testing.T) {
b.SetDefaults()
if b.Name != "Bitfinex" || b.Enabled != false ||
b.Verbose != false || b.Websocket != false ||
b.RESTPollingDelay != 10 {
t.Error("Test Failed - Bitfinex SetDefaults values not set correctly")
}
}
func TestSetup(t *testing.T) {
setup := Bitfinex{}
setup.Name = "Bitfinex"
b.SetDefaults()
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bfxConfig, err := cfg.GetExchangeConfig("Bitfinex")
if err != nil {
t.Error("Test Failed - Bitfinex Setup() init error")
}
setup.Setup(bfxConfig)
b.SetDefaults()
b.Setup(bfxConfig)
if !b.Enabled || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
@@ -47,6 +33,9 @@ func TestSetup(t *testing.T) {
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
t.Error("Test Failed - Bitfinex Setup values not set correctly")
}
b.AuthenticatedAPISupport = true
// not worried about rate limit on test
b.SetRateLimit(0, 0)
}
func TestGetPlatformStatus(t *testing.T) {
@@ -238,6 +227,9 @@ func TestGetSymbolsDetails(t *testing.T) {
}
func TestGetAccountInfo(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetAccountInfo()
@@ -247,6 +239,9 @@ func TestGetAccountInfo(t *testing.T) {
}
func TestGetAccountFees(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetAccountFees()
@@ -256,6 +251,9 @@ func TestGetAccountFees(t *testing.T) {
}
func TestGetAccountSummary(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetAccountSummary()
@@ -265,6 +263,9 @@ func TestGetAccountSummary(t *testing.T) {
}
func TestNewDeposit(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.NewDeposit("blabla", "testwallet", 1)
@@ -274,6 +275,9 @@ func TestNewDeposit(t *testing.T) {
}
func TestGetKeyPermissions(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetKeyPermissions()
@@ -283,6 +287,9 @@ func TestGetKeyPermissions(t *testing.T) {
}
func TestGetMarginInfo(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetMarginInfo()
@@ -292,6 +299,9 @@ func TestGetMarginInfo(t *testing.T) {
}
func TestGetAccountBalance(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetAccountBalance()
@@ -301,6 +311,9 @@ func TestGetAccountBalance(t *testing.T) {
}
func TestWalletTransfer(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.WalletTransfer(0.01, "bla", "bla", "bla")
@@ -310,6 +323,9 @@ func TestWalletTransfer(t *testing.T) {
}
func TestWithdrawal(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.Withdrawal("LITECOIN", "deposit", "1000", 0.01)
@@ -319,6 +335,9 @@ func TestWithdrawal(t *testing.T) {
}
func TestNewOrder(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.NewOrder("BTCUSD", 1, 2, true, "market", false)
@@ -328,6 +347,9 @@ func TestNewOrder(t *testing.T) {
}
func TestNewOrderMulti(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
newOrder := []PlaceOrder{
@@ -348,6 +370,9 @@ func TestNewOrderMulti(t *testing.T) {
}
func TestCancelOrder(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.CancelOrder(1337)
@@ -357,6 +382,9 @@ func TestCancelOrder(t *testing.T) {
}
func TestCancelMultipleOrders(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.CancelMultipleOrders([]int64{1337, 1336})
@@ -366,6 +394,9 @@ func TestCancelMultipleOrders(t *testing.T) {
}
func TestCancelAllOrders(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.CancelAllOrders()
@@ -375,6 +406,9 @@ func TestCancelAllOrders(t *testing.T) {
}
func TestReplaceOrder(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.ReplaceOrder(1337, "BTCUSD", 1, 1, true, "market", false)
@@ -384,6 +418,9 @@ func TestReplaceOrder(t *testing.T) {
}
func TestGetOrderStatus(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetOrderStatus(1337)
@@ -393,6 +430,9 @@ func TestGetOrderStatus(t *testing.T) {
}
func TestGetActiveOrders(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetActiveOrders()
@@ -402,6 +442,9 @@ func TestGetActiveOrders(t *testing.T) {
}
func TestGetActivePositions(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetActivePositions()
@@ -411,6 +454,9 @@ func TestGetActivePositions(t *testing.T) {
}
func TestClaimPosition(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.ClaimPosition(1337)
@@ -420,6 +466,9 @@ func TestClaimPosition(t *testing.T) {
}
func TestGetBalanceHistory(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetBalanceHistory("USD", time.Time{}, time.Time{}, 1, "deposit")
@@ -429,6 +478,9 @@ func TestGetBalanceHistory(t *testing.T) {
}
func TestGetMovementHistory(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetMovementHistory("USD", "bitcoin", time.Time{}, time.Time{}, 1)
@@ -438,6 +490,9 @@ func TestGetMovementHistory(t *testing.T) {
}
func TestGetTradeHistory(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetTradeHistory("BTCUSD", time.Time{}, time.Time{}, 1, 0)
@@ -447,6 +502,9 @@ func TestGetTradeHistory(t *testing.T) {
}
func TestNewOffer(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.NewOffer("BTC", 1, 1, 1, "loan")
@@ -456,6 +514,9 @@ func TestNewOffer(t *testing.T) {
}
func TestCancelOffer(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.CancelOffer(1337)
@@ -465,6 +526,9 @@ func TestCancelOffer(t *testing.T) {
}
func TestGetOfferStatus(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetOfferStatus(1337)
@@ -474,6 +538,9 @@ func TestGetOfferStatus(t *testing.T) {
}
func TestGetActiveCredits(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetActiveCredits()
@@ -483,6 +550,9 @@ func TestGetActiveCredits(t *testing.T) {
}
func TestGetActiveOffers(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetActiveOffers()
@@ -492,6 +562,9 @@ func TestGetActiveOffers(t *testing.T) {
}
func TestGetActiveMarginFunding(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetActiveMarginFunding()
@@ -501,6 +574,9 @@ func TestGetActiveMarginFunding(t *testing.T) {
}
func TestGetUnusedMarginFunds(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetUnusedMarginFunds()
@@ -510,6 +586,9 @@ func TestGetUnusedMarginFunds(t *testing.T) {
}
func TestGetMarginTotalTakenFunds(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.GetMarginTotalTakenFunds()
@@ -519,6 +598,9 @@ func TestGetMarginTotalTakenFunds(t *testing.T) {
}
func TestCloseMarginFunding(t *testing.T) {
if b.APIKey == "" || b.APISecret == "" {
t.SkipNow()
}
t.Parallel()
_, err := b.CloseMarginFunding(1337)

View File

@@ -10,6 +10,7 @@ type Ticker struct {
High float64 `json:"high,string"`
Volume float64 `json:"volume,string"`
Timestamp string `json:"timestamp"`
Message string `json:"message"`
}
// Tickerv2 holds the version 2 ticker information
@@ -43,8 +44,9 @@ type Stat struct {
// FundingBook holds current the full margin funding book
type FundingBook struct {
Bids []Book `json:"bids"`
Asks []Book `json:"asks"`
Bids []Book `json:"bids"`
Asks []Book `json:"asks"`
Message string `json:"message"`
}
// Orderbook holds orderbook information from bid and ask sides
@@ -123,6 +125,12 @@ type SymbolDetails struct {
Expiration string `json:"expiration"`
}
// AccountInfoFull adds the error message to Account info
type AccountInfoFull struct {
Info []AccountInfo
Message string `json:"message"`
}
// AccountInfo general account information with fees
type AccountInfo struct {
MakerFees string `json:"maker_fees"`
@@ -132,6 +140,7 @@ type AccountInfo struct {
MakerFees string `json:"maker_fees"`
TakerFees string `json:"taker_fees"`
} `json:"fees"`
Message string `json:"message"`
}
// AccountFees stores withdrawal account fee data from Bitfinex

View File

@@ -1,87 +1,80 @@
package bitfinex
import (
"net/http"
"testing"
"github.com/gorilla/websocket"
)
func TestWebsocketPingHandler(t *testing.T) {
wsPingHandler := Bitfinex{}
var Dialer websocket.Dialer
var err error
wsPingHandler.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
if err != nil {
t.Errorf("Test Failed - Bitfinex dialer error: %s", err)
}
err = wsPingHandler.WebsocketPingHandler()
if err != nil {
t.Errorf("Test Failed - Bitfinex WebsocketPingHandler() error: %s", err)
}
err = wsPingHandler.WebsocketConn.Close()
if err != nil {
t.Errorf("Test Failed - Bitfinex websocketConn.Close() error: %s", err)
}
}
func TestWebsocketSubscribe(t *testing.T) {
websocketSubcribe := Bitfinex{}
var Dialer websocket.Dialer
var err error
params := make(map[string]string)
params["pair"] = "BTCUSD"
websocketSubcribe.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
if err != nil {
t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
}
err = websocketSubcribe.WebsocketSubscribe("ticker", params)
if err != nil {
t.Errorf("Test Failed - Bitfinex WebsocketSubscribe() error: %s", err)
}
err = websocketSubcribe.WebsocketConn.Close()
if err != nil {
t.Errorf("Test Failed - Bitfinex websocketConn.Close() error: %s", err)
}
}
func TestWebsocketSendAuth(t *testing.T) {
wsSendAuth := Bitfinex{}
var Dialer websocket.Dialer
var err error
wsSendAuth.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
if err != nil {
t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
}
err = wsSendAuth.WebsocketSendAuth()
if err != nil {
t.Errorf("Test Failed - Bitfinex WebsocketSendAuth() error: %s", err)
}
}
func TestWebsocketAddSubscriptionChannel(t *testing.T) {
wsAddSubscriptionChannel := Bitfinex{}
wsAddSubscriptionChannel.SetDefaults()
var Dialer websocket.Dialer
var err error
wsAddSubscriptionChannel.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
if err != nil {
t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
}
wsAddSubscriptionChannel.WebsocketAddSubscriptionChannel(1337, "ticker", "BTCUSD")
if len(wsAddSubscriptionChannel.WebsocketSubdChannels) == 0 {
t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
}
if wsAddSubscriptionChannel.WebsocketSubdChannels[1337].Channel != "ticker" {
t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
}
if wsAddSubscriptionChannel.WebsocketSubdChannels[1337].Pair != "BTCUSD" {
t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
}
}
// func TestWebsocketPingHandler(t *testing.T) {
// wsPingHandler := Bitfinex{}
// var Dialer websocket.Dialer
// var err error
//
// wsPingHandler.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
// if err != nil {
// t.Errorf("Test Failed - Bitfinex dialer error: %s", err)
// }
// err = wsPingHandler.WebsocketPingHandler()
// if err != nil {
// t.Errorf("Test Failed - Bitfinex WebsocketPingHandler() error: %s", err)
// }
// err = wsPingHandler.WebsocketConn.Close()
// if err != nil {
// t.Errorf("Test Failed - Bitfinex websocketConn.Close() error: %s", err)
// }
// }
//
// func TestWebsocketSubscribe(t *testing.T) {
// websocketSubcribe := Bitfinex{}
// var Dialer websocket.Dialer
// var err error
// params := make(map[string]string)
// params["pair"] = "BTCUSD"
//
// websocketSubcribe.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
// if err != nil {
// t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
// }
// err = websocketSubcribe.WebsocketSubscribe("ticker", params)
// if err != nil {
// t.Errorf("Test Failed - Bitfinex WebsocketSubscribe() error: %s", err)
// }
//
// err = websocketSubcribe.WebsocketConn.Close()
// if err != nil {
// t.Errorf("Test Failed - Bitfinex websocketConn.Close() error: %s", err)
// }
// }
//
// func TestWebsocketSendAuth(t *testing.T) {
// wsSendAuth := Bitfinex{}
// var Dialer websocket.Dialer
// var err error
//
// wsSendAuth.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
// if err != nil {
// t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
// }
// err = wsSendAuth.WebsocketSendAuth()
// if err != nil {
// t.Errorf("Test Failed - Bitfinex WebsocketSendAuth() error: %s", err)
// }
// }
//
// func TestWebsocketAddSubscriptionChannel(t *testing.T) {
// wsAddSubscriptionChannel := Bitfinex{}
// wsAddSubscriptionChannel.SetDefaults()
// var Dialer websocket.Dialer
// var err error
//
// wsAddSubscriptionChannel.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
// if err != nil {
// t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
// }
//
// wsAddSubscriptionChannel.WebsocketAddSubscriptionChannel(1337, "ticker", "BTCUSD")
// if len(wsAddSubscriptionChannel.WebsocketSubdChannels) == 0 {
// t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
// }
// if wsAddSubscriptionChannel.WebsocketSubdChannels[1337].Channel != "ticker" {
// t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
// }
// if wsAddSubscriptionChannel.WebsocketSubdChannels[1337].Pair != "BTCUSD" {
// t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
// }
// }

View File

@@ -1,37 +1,30 @@
package bitfinex
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
func TestStart(t *testing.T) {
start := Bitfinex{}
start.Start()
}
func TestRun(t *testing.T) {
run := Bitfinex{}
run.Run()
}
func TestGetTickerPrice(t *testing.T) {
getTickerPrice := Bitfinex{}
getTickerPrice.EnabledPairs = []string{"BTCUSD", "LTCUSD"}
_, err := getTickerPrice.GetTickerPrice(pair.NewCurrencyPair("BTC", "USD"),
ticker.Spot)
if err != nil {
t.Errorf("Test Failed - Bitfinex GetTickerPrice() error: %s", err)
}
}
func TestGetOrderbookEx(t *testing.T) {
getOrderBookEx := Bitfinex{}
_, err := getOrderBookEx.GetOrderbookEx(pair.NewCurrencyPair("BTC", "USD"),
ticker.Spot)
if err != nil {
t.Errorf("Test Failed - Bitfinex GetOrderbookEx() error: %s", err)
}
}
// func TestStart(t *testing.T) {
// start := Bitfinex{}
// start.Start()
// }
//
// func TestRun(t *testing.T) {
// run := Bitfinex{}
// run.Run()
// }
//
// func TestGetTickerPrice(t *testing.T) {
// getTickerPrice := Bitfinex{}
// getTickerPrice.EnabledPairs = []string{"BTCUSD", "LTCUSD"}
// _, err := getTickerPrice.GetTickerPrice(pair.NewCurrencyPair("BTC", "USD"),
// ticker.Spot)
// if err != nil {
// t.Errorf("Test Failed - Bitfinex GetTickerPrice() error: %s", err)
// }
// }
//
// func TestGetOrderbookEx(t *testing.T) {
// getOrderBookEx := Bitfinex{}
// _, err := getOrderBookEx.GetOrderbookEx(pair.NewCurrencyPair("BTC", "USD"),
// ticker.Spot)
// if err != nil {
// t.Errorf("Test Failed - Bitfinex GetOrderbookEx() error: %s", err)
// }
// }

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -11,6 +12,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -63,11 +65,15 @@ const (
privOpenInterest = "/me/getpositions"
privMarginChange = "/me/getcollateralhistory"
privTradingCommission = "/me/gettradingcommission"
bitflyerAuthRate = 1000
bitflyerUnauthRate = 1000
)
// Bitflyer is the overarching type across this package
type Bitflyer struct {
exchange.Base
*request.Handler
}
// SetDefaults sets the basic defaults for Bitflyer
@@ -83,6 +89,8 @@ func (b *Bitflyer) SetDefaults() {
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = false
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, bitflyerAuthRate, bitflyerUnauthRate, new(http.Client))
}
// Setup takes in the supplied exchange configuration details and sets params
@@ -121,7 +129,7 @@ func (b *Bitflyer) GetLatestBlockCA() (ChainAnalysisBlock, error) {
var resp ChainAnalysisBlock
path := fmt.Sprintf("%s%s", chainAnalysis, latestBlock)
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetBlockCA returns block information by blockhash from bitflyer chain
@@ -130,7 +138,7 @@ func (b *Bitflyer) GetBlockCA(blockhash string) (ChainAnalysisBlock, error) {
var resp ChainAnalysisBlock
path := fmt.Sprintf("%s%s%s", chainAnalysis, blockByBlockHash, blockhash)
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetBlockbyHeightCA returns the block information by height from bitflyer chain
@@ -139,7 +147,7 @@ func (b *Bitflyer) GetBlockbyHeightCA(height int64) (ChainAnalysisBlock, error)
var resp ChainAnalysisBlock
path := fmt.Sprintf("%s%s%s", chainAnalysis, blockByBlockHeight, strconv.FormatInt(height, 10))
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetTransactionByHashCA returns transaction information by txHash from
@@ -148,7 +156,7 @@ func (b *Bitflyer) GetTransactionByHashCA(txHash string) (ChainAnalysisTransacti
var resp ChainAnalysisTransaction
path := fmt.Sprintf("%s%s%s", chainAnalysis, transaction, txHash)
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetAddressInfoCA returns balance information for address by addressln string
@@ -157,7 +165,7 @@ func (b *Bitflyer) GetAddressInfoCA(addressln string) (ChainAnalysisAddress, err
var resp ChainAnalysisAddress
path := fmt.Sprintf("%s%s%s", chainAnalysis, address, addressln)
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetMarkets returns market information
@@ -165,7 +173,7 @@ func (b *Bitflyer) GetMarkets() ([]MarketInfo, error) {
var resp []MarketInfo
path := fmt.Sprintf("%s%s", b.APIUrl, pubGetMarkets)
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetOrderBook returns market orderbook depth
@@ -175,7 +183,7 @@ func (b *Bitflyer) GetOrderBook(symbol string) (Orderbook, error) {
v.Set("product_code", symbol)
path := fmt.Sprintf("%s%s?%s", japanURL, pubGetBoard, v.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetTicker returns ticker information
@@ -185,7 +193,7 @@ func (b *Bitflyer) GetTicker(symbol string) (Ticker, error) {
v.Set("product_code", symbol)
path := fmt.Sprintf("%s%s?%s", japanURL, pubGetTicker, v.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetExecutionHistory returns past trades that were executed on the market
@@ -195,7 +203,7 @@ func (b *Bitflyer) GetExecutionHistory(symbol string) ([]ExecutedTrade, error) {
v.Set("product_code", symbol)
path := fmt.Sprintf("%s%s?%s", japanURL, pubGetExecutionHistory, v.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetExchangeStatus returns exchange status information
@@ -204,7 +212,7 @@ func (b *Bitflyer) GetExchangeStatus() (string, error) {
path := fmt.Sprintf("%s%s", b.APIUrl, pubGetHealth)
err := common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
err := b.SendHTTPREquest(path, &resp)
if err != nil {
return "", err
}
@@ -231,7 +239,7 @@ func (b *Bitflyer) GetChats(FromDate string) ([]ChatLog, error) {
v.Set("from_date", FromDate)
path := fmt.Sprintf("%s%s?%s", b.APIUrl, pubGetChats, v.Encode())
return resp, common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
return resp, b.SendHTTPREquest(path, &resp)
}
// GetPermissions returns current permissions for associated with your API
@@ -350,6 +358,11 @@ func (b *Bitflyer) GetTradingCommission() {
// Needs to be updated
}
// SendHTTPREquest sends an unauthenticated request
func (b *Bitflyer) SendHTTPREquest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthHTTPRequest sends an authenticated HTTP request
// Note: HTTP not done due to incorrect account privileges, please open a PR
// if you have access and update the authenticated requests

View File

@@ -127,23 +127,23 @@ func TestGetExchangeStatus(t *testing.T) {
// }
// }
func TestUpdateTicker(t *testing.T) {
t.Parallel()
p := pair.NewCurrencyPairFromString("BTC_JPY")
_, err := b.UpdateTicker(p, "SPOT")
if err != nil {
t.Error("test failed - Bitflyer - UpdateTicker() error:", err)
}
}
func TestUpdateOrderbook(t *testing.T) {
t.Parallel()
p := pair.NewCurrencyPairFromString("BTC_JPY")
_, err := b.UpdateOrderbook(p, "SPOT")
if err != nil {
t.Error("test failed - Bitflyer - UpdateOrderbook() error:", err)
}
}
// func TestUpdateTicker(t *testing.T) {
// t.Parallel()
// p := pair.NewCurrencyPairFromString("BTC_JPY")
// _, err := b.UpdateTicker(p, "SPOT")
// if err != nil {
// t.Error("test failed - Bitflyer - UpdateTicker() error:", err)
// }
// }
//
// func TestUpdateOrderbook(t *testing.T) {
// t.Parallel()
// p := pair.NewCurrencyPairFromString("BTC_JPY")
// _, err := b.UpdateOrderbook(p, "SPOT")
// if err != nil {
// t.Error("test failed - Bitflyer - UpdateOrderbook() error:", err)
// }
// }
func TestCheckFXString(t *testing.T) {
t.Parallel()

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -44,11 +46,15 @@ const (
privateKRWWithdraw = "/trade/krw_withdrawal"
privateMarketBuy = "/trade/market_buy"
privateMarketSell = "/trade/market_sell"
bithumbAuthRate = 100
bithumbUnathRate = 100
)
// Bithumb is the overarching type across the Bithumb package
type Bithumb struct {
exchange.Base
*request.Handler
}
// SetDefaults sets the basic defaults for Bithumb
@@ -65,6 +71,8 @@ func (b *Bithumb) SetDefaults() {
b.ConfigCurrencyPairFormat.Index = "KRW"
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = false
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, bithumbAuthRate, bithumbUnathRate, new(http.Client))
}
// Setup takes in the supplied exchange configuration details and sets params
@@ -103,7 +111,7 @@ func (b *Bithumb) GetTicker(symbol string) (Ticker, error) {
response := Ticker{}
path := fmt.Sprintf("%s%s%s", apiURL, publicTicker, common.StringToUpper(symbol))
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response)
}
// GetOrderBook returns current orderbook
@@ -113,7 +121,7 @@ func (b *Bithumb) GetOrderBook(symbol string) (Orderbook, error) {
response := Orderbook{}
path := fmt.Sprintf("%s%s%s", apiURL, publicOrderBook, common.StringToUpper(symbol))
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response)
}
// GetRecentTransactions returns recent transactions
@@ -123,7 +131,7 @@ func (b *Bithumb) GetRecentTransactions(symbol string) (RecentTransactions, erro
response := RecentTransactions{}
path := fmt.Sprintf("%s%s%s", apiURL, publicRecentTransaction, common.StringToUpper(symbol))
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response)
}
// GetAccountInfo returns account information
@@ -424,6 +432,11 @@ func (b *Bithumb) MarketSellOrder(currency string, units float64) (MarketSell, e
return response, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *Bithumb) SendHTTPRequest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bithumb
func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, result interface{}) error {
if !b.AuthenticatedAPISupport {
@@ -452,19 +465,5 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r
headers["Api-Nonce"] = b.Nonce.String()
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest(
"POST", apiURL+path, headers, bytes.NewBufferString(payload),
)
if err != nil {
return err
}
if b.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
if err = common.JSONDecode([]byte(resp), &result); err != nil {
return errors.New("sendAuthenticatedHTTPRequest: Unable to JSON Unmarshal response." + err.Error())
}
return nil
return b.SendPayload("POST", apiURL+path, headers, bytes.NewBufferString(payload), result, true, b.Verbose)
}

View File

@@ -169,34 +169,34 @@ func TestMarketSellOrder(t *testing.T) {
}
}
func TestRun(t *testing.T) {
t.Parallel()
b.Run()
}
func TestUpdateTicker(t *testing.T) {
t.Parallel()
pair := b.GetEnabledCurrencies()[0]
_, err := b.UpdateTicker(pair, b.AssetTypes[0])
if err != nil {
t.Error("test failed - Bithumb UpdateTicker() error", err)
}
}
func TestGetTickerPrice(t *testing.T) {
t.Parallel()
pair := b.GetEnabledCurrencies()[0]
_, err := b.GetTickerPrice(pair, b.AssetTypes[0])
if err != nil {
t.Error("test failed - Bithumb GetTickerPrice() error", err)
}
}
func TestGetOrderbookEx(t *testing.T) {
t.Parallel()
pair := b.GetEnabledCurrencies()[0]
_, err := b.GetOrderbookEx(pair, b.AssetTypes[0])
if err != nil {
t.Error("test failed - Bithumb GetOrderbookEx() error", err)
}
}
// func TestRun(t *testing.T) {
// t.Parallel()
// b.Run()
// }
//
// func TestUpdateTicker(t *testing.T) {
// t.Parallel()
// pair := b.GetEnabledCurrencies()[0]
// _, err := b.UpdateTicker(pair, b.AssetTypes[0])
// if err != nil {
// t.Error("test failed - Bithumb UpdateTicker() error", err)
// }
// }
//
// func TestGetTickerPrice(t *testing.T) {
// t.Parallel()
// pair := b.GetEnabledCurrencies()[0]
// _, err := b.GetTickerPrice(pair, b.AssetTypes[0])
// if err != nil {
// t.Error("test failed - Bithumb GetTickerPrice() error", err)
// }
// }
//
// func TestGetOrderbookEx(t *testing.T) {
// t.Parallel()
// pair := b.GetEnabledCurrencies()[0]
// _, err := b.GetOrderbookEx(pair, b.AssetTypes[0])
// if err != nil {
// t.Error("test failed - Bithumb GetOrderbookEx() error", err)
// }
// }

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"reflect"
"strconv"
@@ -13,6 +14,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -47,12 +49,16 @@ const (
bitstampAPIXrpDeposit = "xrp_address"
bitstampAPIReturnType = "string"
bitstampAPITradingPairsInfo = "trading-pairs-info"
bitstampAuthRate = 0
bitstampUnauthRate = 0
)
// Bitstamp is the overarching type across the bitstamp package
type Bitstamp struct {
exchange.Base
Balance Balances
*request.Handler
}
// SetDefaults sets default for Bitstamp
@@ -68,6 +74,8 @@ func (b *Bitstamp) SetDefaults() {
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, bitstampAuthRate, bitstampUnauthRate, new(http.Client))
}
// Setup sets configuration values to bitstamp
@@ -133,7 +141,7 @@ func (b *Bitstamp) GetTicker(currency string, hourly bool) (Ticker, error) {
tickerEndpoint,
common.StringToLower(currency),
)
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
return response, b.SendHTTPRequest(path, &response)
}
// GetOrderbook Returns a JSON dictionary with "bids" and "asks". Each is a list
@@ -155,7 +163,7 @@ func (b *Bitstamp) GetOrderbook(currency string) (Orderbook, error) {
common.StringToLower(currency),
)
err := common.SendHTTPGetRequest(path, true, b.Verbose, &resp)
err := b.SendHTTPRequest(path, &resp)
if err != nil {
return Orderbook{}, err
}
@@ -218,7 +226,7 @@ func (b *Bitstamp) GetTransactions(currencyPair string, values url.Values) ([]Tr
values,
)
return transactions, common.SendHTTPGetRequest(path, true, b.Verbose, &transactions)
return transactions, b.SendHTTPRequest(path, &transactions)
}
// GetEURUSDConversionRate returns the conversion rate between Euro and USD
@@ -226,15 +234,15 @@ func (b *Bitstamp) GetEURUSDConversionRate() (EURUSDConversionRate, error) {
rate := EURUSDConversionRate{}
path := fmt.Sprintf("%s/%s", bitstampAPIURL, bitstampAPIEURUSD)
return rate, common.SendHTTPGetRequest(path, true, b.Verbose, &rate)
return rate, b.SendHTTPRequest(path, &rate)
}
// GetBalance returns full balance of currency held on the exchange
func (b *Bitstamp) GetBalance() (Balances, error) {
balance := Balances{}
path := fmt.Sprintf("%s/%s", bitstampAPIURL, bitstampAPIBalance)
return balance,
b.SendAuthenticatedHTTPRequest(bitstampAPIBalance, true, url.Values{}, &balance)
return balance, b.SendHTTPRequest(path, &balance)
}
// GetUserTransactions returns an array of transactions
@@ -484,6 +492,11 @@ func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount s
return true, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *Bitstamp) SendHTTPRequest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated request
func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url.Values, result interface{}) (err error) {
if !b.AuthenticatedAPISupport {
@@ -518,26 +531,5 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
headers := make(map[string]string)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest("POST", path, headers, strings.NewReader(values.Encode()))
if err != nil {
return err
}
if b.Verbose {
log.Printf("Received raw: %s\n", resp)
}
/* inconsistent errors, needs to be improved when in production*/
if common.StringContains(resp, "500 error") {
return errors.New("internal server: code 500")
}
capture := CaptureError{}
if err = common.JSONDecode([]byte(resp), &capture); err == nil {
if capture.Code != nil || capture.Error != nil || capture.Reason != nil || capture.Status != nil {
errstring := fmt.Sprint("Status: ", capture.Status, ", Issue: ", capture.Error, ", Reason: ", capture.Reason, ", Code: ", capture.Code)
return errors.New(errstring)
}
}
return common.JSONDecode([]byte(resp), &result)
return b.SendPayload("POST", path, headers, strings.NewReader(values.Encode()), result, true, b.Verbose)
}

View File

@@ -15,9 +15,9 @@ const (
customerID = ""
)
var b Bitstamp
func TestSetDefaults(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.SetDefaults()
if b.Name != "Bitstamp" {
@@ -38,17 +38,12 @@ func TestSetDefaults(t *testing.T) {
}
func TestSetup(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.Name = "Bitstamp"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("Bitstamp")
if err != nil {
t.Error("Test Failed - Bitstamp Setup() init error")
}
b.SetDefaults()
b.Setup(bConfig)
if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
@@ -56,33 +51,13 @@ func TestSetup(t *testing.T) {
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
t.Error("Test Failed - Bitstamp Setup values not set correctly")
}
bConfig.Enabled = false
b.Setup(bConfig)
if b.IsEnabled() {
t.Error("Test failed - Bitstamp TestSetup incorrect value")
}
}
func TestGetFee(t *testing.T) {
t.Parallel()
b := Bitstamp{}
if resp := b.GetFee("BTCUSD"); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.GetFee("BTCEUR"); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.GetFee("XRPEUR"); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.GetFee("XRPUSD"); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.GetFee("EURUSD"); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.GetFee("bla"); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
@@ -90,7 +65,6 @@ func TestGetFee(t *testing.T) {
func TestGetTicker(t *testing.T) {
t.Parallel()
b := Bitstamp{}
_, err := b.GetTicker("BTCUSD", false)
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
@@ -103,7 +77,6 @@ func TestGetTicker(t *testing.T) {
func TestGetOrderbook(t *testing.T) {
t.Parallel()
b := Bitstamp{}
_, err := b.GetOrderbook("BTCUSD")
if err != nil {
t.Error("Test Failed - GetOrderbook() error", err)
@@ -121,8 +94,6 @@ func TestGetTradingPairs(t *testing.T) {
func TestGetTransactions(t *testing.T) {
t.Parallel()
b := Bitstamp{}
value := url.Values{}
value.Set("time", "hour")
@@ -138,7 +109,6 @@ func TestGetTransactions(t *testing.T) {
func TestGetEURUSDConversionRate(t *testing.T) {
t.Parallel()
b := Bitstamp{}
_, err := b.GetEURUSDConversionRate()
if err != nil {
t.Error("Test Failed - GetEURUSDConversionRate() error", err)
@@ -147,24 +117,14 @@ func TestGetEURUSDConversionRate(t *testing.T) {
func TestGetBalance(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetBalance()
if err == nil {
if err != nil {
t.Error("Test Failed - GetBalance() error", err)
}
}
func TestGetUserTransactions(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetUserTransactions("")
if err == nil {
t.Error("Test Failed - GetUserTransactions() error", err)
@@ -178,10 +138,6 @@ func TestGetUserTransactions(t *testing.T) {
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetOpenOrders("btcusd")
if err == nil {
@@ -195,10 +151,6 @@ func TestGetOpenOrders(t *testing.T) {
func TestGetOrderStatus(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetOrderStatus(1337)
if err == nil {
@@ -208,10 +160,6 @@ func TestGetOrderStatus(t *testing.T) {
func TestCancelOrder(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
resp, err := b.CancelOrder(1337)
if err == nil || resp != false {
@@ -221,10 +169,6 @@ func TestCancelOrder(t *testing.T) {
func TestCancelAllOrders(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.CancelAllOrders()
if err == nil {
@@ -234,35 +178,15 @@ func TestCancelAllOrders(t *testing.T) {
func TestPlaceOrder(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.PlaceOrder("btcusd", 0.01, 1, true, true)
if err == nil {
t.Error("Test Failed - PlaceOrder() error")
}
_, err = b.PlaceOrder("btcusd", 0.01, 1, true, false)
if err == nil {
t.Error("Test Failed - PlaceOrder() error")
}
_, err = b.PlaceOrder("btcusd", 0.01, 1, false, false)
if err == nil {
t.Error("Test Failed - PlaceOrder() error")
}
_, err = b.PlaceOrder("wigwham", 0.01, 1, false, false)
if err == nil {
t.Error("Test Failed - PlaceOrder() error")
}
}
func TestGetWithdrawalRequests(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetWithdrawalRequests(0)
if err == nil {
@@ -276,72 +200,24 @@ func TestGetWithdrawalRequests(t *testing.T) {
func TestCryptoWithdrawal(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.CryptoWithdrawal(0, "bla", "btc", "", true)
if err == nil {
t.Error("Test Failed - CryptoWithdrawal() error", err)
}
_, err = b.CryptoWithdrawal(0, "bla", "btc", "", false)
if err == nil {
t.Error("Test Failed - CryptoWithdrawal() error", err)
}
_, err = b.CryptoWithdrawal(0, "bla", "ltc", "", false)
if err == nil {
t.Error("Test Failed - CryptoWithdrawal() error", err)
}
_, err = b.CryptoWithdrawal(0, "bla", "eth", "", false)
if err == nil {
t.Error("Test Failed - CryptoWithdrawal() error", err)
}
_, err = b.CryptoWithdrawal(0, "bla", "xrp", "someplace", false)
if err == nil {
t.Error("Test Failed - CryptoWithdrawal() error", err)
}
_, err = b.CryptoWithdrawal(0, "bla", "ding!", "", false)
if err == nil {
t.Error("Test Failed - CryptoWithdrawal() error", err)
}
}
func TestGetBitcoinDepositAddress(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetCryptoDepositAddress("btc")
if err == nil {
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
}
_, err = b.GetCryptoDepositAddress("LTc")
if err == nil {
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
}
_, err = b.GetCryptoDepositAddress("eth")
if err == nil {
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
}
_, err = b.GetCryptoDepositAddress("xrp")
if err == nil {
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
}
_, err = b.GetCryptoDepositAddress("wigwham")
if err == nil {
t.Error("Test Failed - GetCryptoDepositAddress() error")
}
}
func TestGetUnconfirmedBitcoinDeposits(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.GetUnconfirmedBitcoinDeposits()
if err == nil {
@@ -351,10 +227,6 @@ func TestGetUnconfirmedBitcoinDeposits(t *testing.T) {
func TestTransferAccountBalance(t *testing.T) {
t.Parallel()
b := Bitstamp{}
b.APIKey = apiKey
b.APISecret = apiSecret
b.ClientID = customerID
_, err := b.TransferAccountBalance(1, "", "", true)
if err == nil {

View File

@@ -1,18 +1,18 @@
package bittrex
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -53,11 +53,15 @@ const (
bittrexAPIGetOrderHistory = "account/getorderhistory"
bittrexAPIGetWithdrawalHistory = "account/getwithdrawalhistory"
bittrexAPIGetDepositHistory = "account/getdeposithistory"
bittrexAuthRate = 0
bittrexUnauthRate = 0
)
// Bittrex is the overaching type across the bittrex methods
type Bittrex struct {
exchange.Base
*request.Handler
}
// SetDefaults method assignes the default values for Bittrex
@@ -73,6 +77,8 @@ func (b *Bittrex) SetDefaults() {
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, bittrexAuthRate, bittrexUnauthRate, new(http.Client))
}
// Setup method sets current configuration details if enabled
@@ -106,19 +112,33 @@ func (b *Bittrex) Setup(exch config.ExchangeConfig) {
// 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
func (b *Bittrex) GetMarkets() (Market, error) {
var markets Market
path := fmt.Sprintf("%s/%s/", bittrexAPIURL, bittrexAPIGetMarkets)
return markets, b.HTTPRequest(path, false, url.Values{}, &markets)
if err := b.SendHTTPRequest(path, &markets); err != nil {
return markets, err
}
if !markets.Success {
return markets, errors.New(markets.Message)
}
return markets, nil
}
// GetCurrencies is used to get all supported currencies at Bittrex
func (b *Bittrex) GetCurrencies() ([]Currency, error) {
var currencies []Currency
func (b *Bittrex) GetCurrencies() (Currency, error) {
var currencies Currency
path := fmt.Sprintf("%s/%s/", bittrexAPIURL, bittrexAPIGetCurrencies)
return currencies, b.HTTPRequest(path, false, url.Values{}, &currencies)
if err := b.SendHTTPRequest(path, &currencies); err != nil {
return currencies, err
}
if !currencies.Success {
return currencies, errors.New(currencies.Message)
}
return currencies, nil
}
// GetTicker sends a public get request and returns current ticker information
@@ -128,26 +148,49 @@ func (b *Bittrex) GetTicker(currencyPair string) (Ticker, error) {
path := fmt.Sprintf("%s/%s?market=%s", bittrexAPIURL, bittrexAPIGetTicker,
common.StringToUpper(currencyPair),
)
return ticker, b.HTTPRequest(path, false, url.Values{}, &ticker)
if err := b.SendHTTPRequest(path, &ticker); err != nil {
return ticker, err
}
if !ticker.Success {
return ticker, errors.New(ticker.Message)
}
return ticker, nil
}
// GetMarketSummaries is used to get the last 24 hour summary of all active
// exchanges
func (b *Bittrex) GetMarketSummaries() ([]MarketSummary, error) {
var summaries []MarketSummary
func (b *Bittrex) GetMarketSummaries() (MarketSummary, error) {
var summaries MarketSummary
path := fmt.Sprintf("%s/%s/", bittrexAPIURL, bittrexAPIGetMarketSummaries)
return summaries, b.HTTPRequest(path, false, url.Values{}, &summaries)
if err := b.SendHTTPRequest(path, &summaries); err != nil {
return summaries, err
}
if !summaries.Success {
return summaries, errors.New(summaries.Message)
}
return summaries, nil
}
// 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
func (b *Bittrex) GetMarketSummary(currencyPair string) (MarketSummary, error) {
var summary MarketSummary
path := fmt.Sprintf("%s/%s?market=%s", bittrexAPIURL,
bittrexAPIGetMarketSummary, common.StringToLower(currencyPair),
)
return summary, b.HTTPRequest(path, false, url.Values{}, &summary)
if err := b.SendHTTPRequest(path, &summary); err != nil {
return summary, err
}
if !summary.Success {
return summary, errors.New(summary.Message)
}
return summary, nil
}
// GetOrderbook method returns current order book information by currency, type
@@ -163,18 +206,32 @@ func (b *Bittrex) GetOrderbook(currencyPair string) (OrderBooks, error) {
bittrexAPIGetOrderbook, common.StringToUpper(currencyPair),
)
return orderbooks, b.HTTPRequest(path, false, url.Values{}, &orderbooks)
if err := b.SendHTTPRequest(path, &orderbooks); err != nil {
return orderbooks, err
}
if !orderbooks.Success {
return orderbooks, errors.New(orderbooks.Message)
}
return orderbooks, nil
}
// GetMarketHistory retrieves the latest trades that have occurred for a specific
// market
func (b *Bittrex) GetMarketHistory(currencyPair string) ([]MarketHistory, error) {
var marketHistoriae []MarketHistory
func (b *Bittrex) GetMarketHistory(currencyPair string) (MarketHistory, error) {
var marketHistoriae MarketHistory
path := fmt.Sprintf("%s/%s?market=%s", bittrexAPIURL,
bittrexAPIGetMarketHistory, common.StringToUpper(currencyPair),
)
return marketHistoriae, b.HTTPRequest(path, false, url.Values{},
&marketHistoriae)
if err := b.SendHTTPRequest(path, &marketHistoriae); err != nil {
return marketHistoriae, err
}
if !marketHistoriae.Success {
return marketHistoriae, errors.New(marketHistoriae.Message)
}
return marketHistoriae, nil
}
// PlaceBuyLimit is used to place a buy order in a specific market. Use buylimit
@@ -183,15 +240,22 @@ func (b *Bittrex) GetMarketHistory(currencyPair string) ([]MarketHistory, error)
// "Currency" ie "btc-ltc"
// "Quantity" is the amount to purchase
// "Rate" is the rate at which to purchase
func (b *Bittrex) PlaceBuyLimit(currencyPair string, quantity, rate float64) ([]UUID, error) {
var id []UUID
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", bittrexAPIURL, bittrexAPIBuyLimit)
return id, b.HTTPRequest(path, true, values, &id)
if err := b.SendAuthenticatedHTTPRequest(path, values, &id); err != nil {
return id, err
}
if !id.Success {
return id, errors.New(id.Message)
}
return id, nil
}
// PlaceSellLimit is used to place a sell order in a specific market. Use
@@ -200,46 +264,74 @@ func (b *Bittrex) PlaceBuyLimit(currencyPair string, quantity, rate float64) ([]
// "Currency" ie "btc-ltc"
// "Quantity" is the amount to purchase
// "Rate" is the rate at which to purchase
func (b *Bittrex) PlaceSellLimit(currencyPair string, quantity, rate float64) ([]UUID, error) {
var id []UUID
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", bittrexAPIURL, bittrexAPISellLimit)
return id, b.HTTPRequest(path, true, values, &id)
if err := b.SendAuthenticatedHTTPRequest(path, values, &id); err != nil {
return id, err
}
if !id.Success {
return id, errors.New(id.Message)
}
return id, nil
}
// 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
func (b *Bittrex) GetOpenOrders(currencyPair string) (Order, error) {
var orders Order
values := url.Values{}
if !(currencyPair == "" || currencyPair == " ") {
values.Set("market", currencyPair)
}
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetOpenOrders)
return orders, b.HTTPRequest(path, true, values, &orders)
if err := b.SendAuthenticatedHTTPRequest(path, values, &orders); err != nil {
return orders, err
}
if !orders.Success {
return orders, errors.New(orders.Message)
}
return orders, nil
}
// CancelOrder is used to cancel a buy or sell order.
func (b *Bittrex) CancelOrder(uuid string) ([]Balance, error) {
var balances []Balance
func (b *Bittrex) CancelOrder(uuid string) (Balances, error) {
var balances Balances
values := url.Values{}
values.Set("uuid", uuid)
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPICancel)
return balances, b.HTTPRequest(path, true, values, &balances)
if err := b.SendAuthenticatedHTTPRequest(path, values, &balances); err != nil {
return balances, err
}
if !balances.Success {
return balances, errors.New(balances.Message)
}
return balances, nil
}
// GetAccountBalances is used to retrieve all balances from your account
func (b *Bittrex) GetAccountBalances() ([]Balance, error) {
var balances []Balance
func (b *Bittrex) GetAccountBalances() (Balances, error) {
var balances Balances
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetBalances)
return balances, b.HTTPRequest(path, true, url.Values{}, &balances)
if err := b.SendAuthenticatedHTTPRequest(path, url.Values{}, &balances); err != nil {
return balances, err
}
if !balances.Success {
return balances, errors.New(balances.Message)
}
return balances, nil
}
// GetAccountBalanceByCurrency is used to retrieve the balance from your account
@@ -250,7 +342,14 @@ func (b *Bittrex) GetAccountBalanceByCurrency(currency string) (Balance, error)
values.Set("currency", currency)
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetBalance)
return balance, b.HTTPRequest(path, true, values, &balance)
if err := b.SendAuthenticatedHTTPRequest(path, values, &balance); err != nil {
return balance, err
}
if !balance.Success {
return balance, errors.New(balance.Message)
}
return balance, nil
}
// GetDepositAddress is used to retrieve or generate an address for a specific
@@ -262,7 +361,14 @@ func (b *Bittrex) GetDepositAddress(currency string) (DepositAddress, error) {
values.Set("currency", currency)
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetDepositAddress)
return address, b.HTTPRequest(path, true, values, &address)
if err := b.SendAuthenticatedHTTPRequest(path, values, &address); err != nil {
return address, err
}
if !address.Success {
return address, errors.New(address.Message)
}
return address, nil
}
// Withdraw is used to withdraw funds from your account.
@@ -275,7 +381,14 @@ func (b *Bittrex) Withdraw(currency, paymentID, address string, quantity float64
values.Set("address", address)
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIWithdraw)
return id, b.HTTPRequest(path, true, values, &id)
if err := b.SendAuthenticatedHTTPRequest(path, values, &id); err != nil {
return id, err
}
if !id.Success {
return id, errors.New(id.Message)
}
return id, nil
}
// GetOrder is used to retrieve a single order by UUID.
@@ -285,13 +398,20 @@ func (b *Bittrex) GetOrder(uuid string) (Order, error) {
values.Set("uuid", uuid)
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetOrder)
return order, b.HTTPRequest(path, true, values, &order)
if err := b.SendAuthenticatedHTTPRequest(path, values, &order); err != nil {
return order, err
}
if !order.Success {
return order, errors.New(order.Message)
}
return order, nil
}
// GetOrderHistory is used to retrieve your order history. If currencyPair
// omitted it will return the entire order History.
func (b *Bittrex) GetOrderHistory(currencyPair string) ([]Order, error) {
var orders []Order
func (b *Bittrex) GetOrderHistory(currencyPair string) (Order, error) {
var orders Order
values := url.Values{}
if !(currencyPair == "" || currencyPair == " ") {
@@ -299,13 +419,20 @@ func (b *Bittrex) GetOrderHistory(currencyPair string) ([]Order, error) {
}
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetOrderHistory)
return orders, b.HTTPRequest(path, true, values, &orders)
if err := b.SendAuthenticatedHTTPRequest(path, values, &orders); err != nil {
return orders, err
}
if !orders.Success {
return orders, errors.New(orders.Message)
}
return orders, nil
}
// GetWithdrawalHistory is used to retrieve your withdrawal history. If currency
// omitted it will return the entire history
func (b *Bittrex) GetWithdrawalHistory(currency string) ([]WithdrawalHistory, error) {
var history []WithdrawalHistory
func (b *Bittrex) GetWithdrawalHistory(currency string) (WithdrawalHistory, error) {
var history WithdrawalHistory
values := url.Values{}
if !(currency == "" || currency == " ") {
@@ -313,13 +440,20 @@ func (b *Bittrex) GetWithdrawalHistory(currency string) ([]WithdrawalHistory, er
}
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetWithdrawalHistory)
return history, b.HTTPRequest(path, true, values, &history)
if err := b.SendAuthenticatedHTTPRequest(path, values, &history); err != nil {
return history, err
}
if !history.Success {
return history, errors.New(history.Message)
}
return history, nil
}
// GetDepositHistory is used to retrieve your deposit history. If currency is
// is omitted it will return the entire deposit history
func (b *Bittrex) GetDepositHistory(currency string) ([]WithdrawalHistory, error) {
var history []WithdrawalHistory
func (b *Bittrex) GetDepositHistory(currency string) (WithdrawalHistory, error) {
var history WithdrawalHistory
values := url.Values{}
if !(currency == "" || currency == " ") {
@@ -327,7 +461,19 @@ func (b *Bittrex) GetDepositHistory(currency string) ([]WithdrawalHistory, error
}
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetDepositHistory)
return history, b.HTTPRequest(path, true, values, &history)
if err := b.SendAuthenticatedHTTPRequest(path, values, &history); err != nil {
return history, err
}
if !history.Success {
return history, errors.New(history.Message)
}
return history, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *Bittrex) SendHTTPRequest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated http request to a desired
@@ -352,38 +498,5 @@ func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, r
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("Received 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
}
// HTTPRequest is a generalised http request function.
func (b *Bittrex) HTTPRequest(path string, auth bool, values url.Values, v interface{}) error {
response := Response{}
if auth {
if err := b.SendAuthenticatedHTTPRequest(path, values, &response); err != nil {
return err
}
} else {
if err := common.SendHTTPGetRequest(path, true, b.Verbose, &response); err != nil {
return err
}
}
if response.Success {
return json.Unmarshal(response.Result, &v)
}
return errors.New(response.Message)
return b.SendPayload("GET", rawQuery, headers, nil, result, true, b.Verbose)
}

View File

@@ -13,9 +13,9 @@ const (
apiSecret = "TestyTesty"
)
var b Bittrex
func TestSetDefaults(t *testing.T) {
t.Parallel()
b := Bittrex{}
b.SetDefaults()
if b.GetName() != "Bittrex" {
t.Error("Test Failed - Bittrex - SetDefaults() error")
@@ -23,9 +23,6 @@ func TestSetDefaults(t *testing.T) {
}
func TestSetup(t *testing.T) {
t.Parallel()
b := Bittrex{}
b.Name = "Bittrex"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("Bittrex")
@@ -33,7 +30,6 @@ func TestSetup(t *testing.T) {
t.Error("Test Failed - Bittrex Setup() init error")
}
b.SetDefaults()
b.Setup(bConfig)
if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
@@ -41,19 +37,11 @@ func TestSetup(t *testing.T) {
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
t.Error("Test Failed - Bittrex Setup values not set correctly")
}
bConfig.Enabled = false
b.Setup(bConfig)
if b.IsEnabled() {
t.Error("Test failed - Bittrex TestSetup incorrect value")
}
}
func TestGetMarkets(t *testing.T) {
t.Parallel()
obj := Bittrex{}
_, err := obj.GetMarkets()
_, err := b.GetMarkets()
if err != nil {
t.Errorf("Test Failed - Bittrex - GetMarkets() error: %s", err)
}
@@ -61,8 +49,7 @@ func TestGetMarkets(t *testing.T) {
func TestGetCurrencies(t *testing.T) {
t.Parallel()
obj := Bittrex{}
_, err := obj.GetCurrencies()
_, err := b.GetCurrencies()
if err != nil {
t.Errorf("Test Failed - Bittrex - GetCurrencies() error: %s", err)
}
@@ -70,20 +57,9 @@ func TestGetCurrencies(t *testing.T) {
func TestGetTicker(t *testing.T) {
t.Parallel()
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)
_, err := b.GetTicker(btc)
if err != nil {
t.Errorf("Test Failed - Bittrex - GetTicker() error: %s", err)
}
@@ -91,8 +67,7 @@ func TestGetTicker(t *testing.T) {
func TestGetMarketSummaries(t *testing.T) {
t.Parallel()
obj := Bittrex{}
_, err := obj.GetMarketSummaries()
_, err := b.GetMarketSummaries()
if err != nil {
t.Errorf("Test Failed - Bittrex - GetMarketSummaries() error: %s", err)
}
@@ -101,51 +76,35 @@ func TestGetMarketSummaries(t *testing.T) {
func TestGetMarketSummary(t *testing.T) {
t.Parallel()
pairOne := "BTC-LTC"
invalid := "WigWham"
obj := Bittrex{}
_, err := obj.GetMarketSummary(pairOne)
_, err := b.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) {
t.Parallel()
obj := Bittrex{}
_, err := obj.GetOrderbook("btc-ltc")
_, err := b.GetOrderbook("btc-ltc")
if err != nil {
t.Errorf("Test Failed - Bittrex - GetOrderbook() error: %s", err)
}
_, err = obj.GetOrderbook("wigwham")
if err == nil {
t.Errorf("Test Failed - Bittrex - GetOrderbook() error")
}
}
func TestGetMarketHistory(t *testing.T) {
t.Parallel()
obj := Bittrex{}
_, err := obj.GetMarketHistory("btc-ltc")
_, err := b.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) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.PlaceBuyLimit("btc-ltc", 1, 1)
_, err := b.PlaceBuyLimit("btc-ltc", 1, 1)
if err == nil {
t.Error("Test Failed - Bittrex - PlaceBuyLimit() error")
}
@@ -153,10 +112,8 @@ func TestPlaceBuyLimit(t *testing.T) {
func TestPlaceSellLimit(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.PlaceSellLimit("btc-ltc", 1, 1)
_, err := b.PlaceSellLimit("btc-ltc", 1, 1)
if err == nil {
t.Error("Test Failed - Bittrex - PlaceSellLimit() error")
}
@@ -164,14 +121,12 @@ func TestPlaceSellLimit(t *testing.T) {
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetOpenOrders("")
_, err := b.GetOpenOrders("")
if err == nil {
t.Error("Test Failed - Bittrex - GetOrder() error")
}
_, err = obj.GetOpenOrders("btc-ltc")
_, err = b.GetOpenOrders("btc-ltc")
if err == nil {
t.Error("Test Failed - Bittrex - GetOrder() error")
}
@@ -179,10 +134,8 @@ func TestGetOpenOrders(t *testing.T) {
func TestCancelOrder(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.CancelOrder("blaaaaaaa")
_, err := b.CancelOrder("blaaaaaaa")
if err == nil {
t.Error("Test Failed - Bittrex - CancelOrder() error")
}
@@ -190,10 +143,8 @@ func TestCancelOrder(t *testing.T) {
func TestGetAccountBalances(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetAccountBalances()
_, err := b.GetAccountBalances()
if err == nil {
t.Error("Test Failed - Bittrex - GetAccountBalances() error")
}
@@ -201,10 +152,8 @@ func TestGetAccountBalances(t *testing.T) {
func TestGetAccountBalanceByCurrency(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetAccountBalanceByCurrency("btc")
_, err := b.GetAccountBalanceByCurrency("btc")
if err == nil {
t.Error("Test Failed - Bittrex - GetAccountBalanceByCurrency() error")
}
@@ -212,10 +161,8 @@ func TestGetAccountBalanceByCurrency(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetDepositAddress("btc")
_, err := b.GetDepositAddress("btc")
if err == nil {
t.Error("Test Failed - Bittrex - GetDepositAddress() error")
}
@@ -223,10 +170,8 @@ func TestGetDepositAddress(t *testing.T) {
func TestWithdraw(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.Withdraw("btc", "something", "someplace", 1)
_, err := b.Withdraw("btc", "something", "someplace", 1)
if err == nil {
t.Error("Test Failed - Bittrex - Withdraw() error")
}
@@ -234,14 +179,12 @@ func TestWithdraw(t *testing.T) {
func TestGetOrder(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetOrder("0cb4c4e4-bdc7-4e13-8c13-430e587d2cc1")
_, err := b.GetOrder("0cb4c4e4-bdc7-4e13-8c13-430e587d2cc1")
if err == nil {
t.Error("Test Failed - Bittrex - GetOrder() error")
}
_, err = obj.GetOrder("")
_, err = b.GetOrder("")
if err == nil {
t.Error("Test Failed - Bittrex - GetOrder() error")
}
@@ -249,14 +192,12 @@ func TestGetOrder(t *testing.T) {
func TestGetOrderHistory(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetOrderHistory("")
_, err := b.GetOrderHistory("")
if err == nil {
t.Error("Test Failed - Bittrex - GetOrderHistory() error")
}
_, err = obj.GetOrderHistory("btc-ltc")
_, err = b.GetOrderHistory("btc-ltc")
if err == nil {
t.Error("Test Failed - Bittrex - GetOrderHistory() error")
}
@@ -264,14 +205,12 @@ func TestGetOrderHistory(t *testing.T) {
func TestGetwithdrawalHistory(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetWithdrawalHistory("")
_, err := b.GetWithdrawalHistory("")
if err == nil {
t.Error("Test Failed - Bittrex - GetWithdrawalHistory() error")
}
_, err = obj.GetWithdrawalHistory("btc-ltc")
_, err = b.GetWithdrawalHistory("btc-ltc")
if err == nil {
t.Error("Test Failed - Bittrex - GetWithdrawalHistory() error")
}
@@ -279,14 +218,12 @@ func TestGetwithdrawalHistory(t *testing.T) {
func TestGetDepositHistory(t *testing.T) {
t.Parallel()
obj := Bittrex{}
obj.APIKey = apiKey
obj.APISecret = apiSecret
_, err := obj.GetDepositHistory("")
_, err := b.GetDepositHistory("")
if err == nil {
t.Error("Test Failed - Bittrex - GetDepositHistory() error")
}
_, err = obj.GetDepositHistory("btc-ltc")
_, err = b.GetDepositHistory("btc-ltc")
if err == nil {
t.Error("Test Failed - Bittrex - GetDepositHistory() error")
}

View File

@@ -11,56 +11,76 @@ type Response struct {
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}
// Ticker holds basic ticker information
type Ticker struct {
Bid float64 `json:"Bid"`
Ask float64 `json:"Ask"`
Last float64 `json:"Last"`
Success bool `json:"success"`
Message string `json:"message"`
Result struct {
Bid float64 `json:"Bid"`
Ask float64 `json:"Ask"`
Last float64 `json:"Last"`
} `json:"result"`
}
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}
// OrderBooks holds an array of buy & sell orders held on the exchange
type OrderBooks struct {
Buy []OrderBook `json:"buy"`
Sell []OrderBook `json:"sell"`
Success bool `json:"success"`
Message string `json:"message"`
Result struct {
Buy []OrderBook `json:"buy"`
Sell []OrderBook `json:"sell"`
} `json:"result"`
}
// OrderBook holds a singular order on an exchange
@@ -71,77 +91,116 @@ type OrderBook struct {
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result 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"`
} `json:"result"`
}
// Balances holds the balance from your account for a specified currency
type Balances struct {
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}
// DepositAddress holds a generated address to send specific coins to the
// exchange
type DepositAddress struct {
Currency string `json:"Currency"`
Address string `json:"Address"`
Success bool `json:"success"`
Message string `json:"message"`
Result struct {
Currency string `json:"Currency"`
Address string `json:"Address"`
} `json:"result"`
}
// UUID contains the universal unique identifier for one or multiple
// transactions on the exchange
type UUID struct {
ID string `json:"uuid"`
Success bool `json:"success"`
Message string `json:"message"`
Result []struct {
ID string `json:"uuid"`
} `json:"result"`
}
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}
// 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"`
Success bool `json:"success"`
Message string `json:"message"`
Result []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"`
} `json:"result"`
}

View File

@@ -6,7 +6,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/exchanges"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -32,11 +32,11 @@ func (b *Bittrex) Run() {
forceUpgrade = true
}
var currencies []string
for x := range exchangeProducts {
if !exchangeProducts[x].IsActive || exchangeProducts[x].MarketName == "" {
for x := range exchangeProducts.Result {
if !exchangeProducts.Result[x].IsActive || exchangeProducts.Result[x].MarketName == "" {
continue
}
currencies = append(currencies, exchangeProducts[x].MarketName)
currencies = append(currencies, exchangeProducts.Result[x].MarketName)
}
if forceUpgrade {
@@ -65,11 +65,11 @@ func (b *Bittrex) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
return response, err
}
for i := 0; i < len(accountBalance); i++ {
for i := 0; i < len(accountBalance.Result); i++ {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = accountBalance[i].Currency
exchangeCurrency.TotalValue = accountBalance[i].Balance
exchangeCurrency.Hold = accountBalance[i].Balance - accountBalance[i].Available
exchangeCurrency.CurrencyName = accountBalance.Result[i].Currency
exchangeCurrency.TotalValue = accountBalance.Result[i].Balance
exchangeCurrency.Hold = accountBalance.Result[i].Balance - accountBalance.Result[i].Available
response.Currencies = append(response.Currencies, exchangeCurrency)
}
return response, nil
@@ -85,15 +85,15 @@ func (b *Bittrex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pr
for _, x := range b.GetEnabledCurrencies() {
curr := exchange.FormatExchangeCurrency(b.Name, x)
for y := range tick {
if tick[y].MarketName == curr.String() {
for y := range tick.Result {
if tick.Result[y].MarketName == curr.String() {
tickerPrice.Pair = x
tickerPrice.High = tick[y].High
tickerPrice.Low = tick[y].Low
tickerPrice.Ask = tick[y].Ask
tickerPrice.Bid = tick[y].Bid
tickerPrice.Last = tick[y].Last
tickerPrice.Volume = tick[y].Volume
tickerPrice.High = tick.Result[y].High
tickerPrice.Low = tick.Result[y].Low
tickerPrice.Ask = tick.Result[y].Ask
tickerPrice.Bid = tick.Result[y].Bid
tickerPrice.Last = tick.Result[y].Last
tickerPrice.Volume = tick.Result[y].Volume
ticker.ProcessTicker(b.GetName(), x, tickerPrice, assetType)
}
}
@@ -127,20 +127,20 @@ func (b *Bittrex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderb
return orderBook, err
}
for x := range orderbookNew.Buy {
for x := range orderbookNew.Result.Buy {
orderBook.Bids = append(orderBook.Bids,
orderbook.Item{
Amount: orderbookNew.Buy[x].Quantity,
Price: orderbookNew.Buy[x].Rate,
Amount: orderbookNew.Result.Buy[x].Quantity,
Price: orderbookNew.Result.Buy[x].Rate,
},
)
}
for x := range orderbookNew.Sell {
for x := range orderbookNew.Result.Sell {
orderBook.Asks = append(orderBook.Asks,
orderbook.Item{
Amount: orderbookNew.Sell[x].Quantity,
Price: orderbookNew.Sell[x].Rate,
Amount: orderbookNew.Result.Sell[x].Quantity,
Price: orderbookNew.Result.Sell[x].Rate,
},
)
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -41,11 +43,15 @@ const (
btccStoporderCancel = "cancelStopOrder"
btccStoporder = "getStopOrder"
btccStoporders = "getStopOrders"
btccAuthRate = 0
btccUnauthRate = 0
)
// BTCC is the main overaching type across the BTCC package
type BTCC struct {
exchange.Base
*request.Handler
}
// SetDefaults sets default values for the exchange
@@ -62,6 +68,8 @@ func (b *BTCC) SetDefaults() {
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, btccAuthRate, btccUnauthRate, new(http.Client))
}
// Setup is run on startup to setup exchange with config values
@@ -102,8 +110,8 @@ func (b *BTCC) GetFee() float64 {
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
func (b *BTCC) GetTicker(currencyPair string) (Ticker, error) {
resp := Response{}
req := fmt.Sprintf("%s/data/pro/ticker?symbol=%s", btccAPIUrl, currencyPair)
return resp.Ticker, common.SendHTTPGetRequest(req, true, b.Verbose, &resp)
path := fmt.Sprintf("%s/data/pro/ticker?symbol=%s", btccAPIUrl, currencyPair)
return resp.Ticker, b.SendHTTPRequest(path, &resp)
}
// GetTradeHistory returns trade history data
@@ -113,7 +121,7 @@ func (b *BTCC) GetTicker(currencyPair string) (Ticker, error) {
// time - returns trade records starting from unix time 1406794449
func (b *BTCC) GetTradeHistory(currencyPair string, limit, sinceTid int64, time time.Time) ([]Trade, error) {
trades := []Trade{}
req := fmt.Sprintf("%s/data/pro/historydata?symbol=%s", btccAPIUrl, currencyPair)
path := fmt.Sprintf("%s/data/pro/historydata?symbol=%s", btccAPIUrl, currencyPair)
v := url.Values{}
if limit > 0 {
@@ -126,8 +134,8 @@ func (b *BTCC) GetTradeHistory(currencyPair string, limit, sinceTid int64, time
v.Set("sincetype", strconv.FormatInt(time.Unix(), 10))
}
req = common.EncodeURLValues(req, v)
return trades, common.SendHTTPGetRequest(req, true, b.Verbose, &trades)
path = common.EncodeURLValues(path, v)
return trades, b.SendHTTPRequest(path, &trades)
}
// GetOrderBook returns current symbol order book
@@ -136,12 +144,12 @@ func (b *BTCC) GetTradeHistory(currencyPair string, limit, sinceTid int64, time
// orderbook
func (b *BTCC) GetOrderBook(currencyPair string, limit int) (Orderbook, error) {
result := Orderbook{}
req := fmt.Sprintf("%s/data/pro/orderbook?symbol=%s&limit=%d", btccAPIUrl, currencyPair, limit)
path := fmt.Sprintf("%s/data/pro/orderbook?symbol=%s&limit=%d", btccAPIUrl, currencyPair, limit)
if limit == 0 {
req = fmt.Sprintf("%s/data/pro/orderbook?symbol=%s", btccAPIUrl, currencyPair)
path = fmt.Sprintf("%s/data/pro/orderbook?symbol=%s", btccAPIUrl, currencyPair)
}
return result, common.SendHTTPGetRequest(req, true, b.Verbose, &result)
return result, b.SendHTTPRequest(path, &result)
}
// GetAccountInfo returns account information
@@ -541,6 +549,11 @@ func (b *BTCC) CancelStopOrder(orderID int64, symbol string) {
}
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *BTCC) SendHTTPRequest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthenticatedHTTPRequest sends a valid authenticated HTTP request
func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{}) (err error) {
if !b.AuthenticatedAPISupport {
@@ -600,8 +613,8 @@ func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{})
postData["id"] = 1
apiURL := fmt.Sprintf("%s/%s", btccAPIUrl, btccAPIAuthenticatedMethod)
data, err := common.JSONEncode(postData)
data, err := common.JSONEncode(postData)
if err != nil {
return errors.New("Unable to JSON Marshal POST data")
}
@@ -615,15 +628,5 @@ func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{})
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(b.APIKey+":"+common.HexEncodeToString(hmac)))
headers["Json-Rpc-Tonce"] = b.Nonce.String()
resp, err := common.SendHTTPRequest("POST", apiURL, headers, strings.NewReader(string(data)))
if err != nil {
return err
}
if b.Verbose {
log.Printf("Recv'd :%s\n", resp)
}
return nil
return b.SendPayload("POST", apiURL, headers, strings.NewReader(string(data)), nil, true, b.Verbose)
}

View File

@@ -20,16 +20,12 @@ func TestSetDefaults(t *testing.T) {
}
func TestSetup(t *testing.T) {
t.Parallel()
b.Name = "BTCC"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("BTCC")
if err != nil {
t.Error("Test Failed - BTCC Setup() init error")
}
b.SetDefaults()
b.Setup(bConfig)
if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
@@ -37,13 +33,6 @@ func TestSetup(t *testing.T) {
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
t.Error("Test Failed - BTCC Setup values not set correctly")
}
bConfig.Enabled = false
b.Setup(bConfig)
if b.IsEnabled() {
t.Error("Test failed - BTCC TestSetup incorrect value")
}
}
func TestGetFee(t *testing.T) {
@@ -67,7 +56,6 @@ func TestGetTradeHistory(t *testing.T) {
}
func TestGetOrderBook(t *testing.T) {
b.Verbose = true
_, err := b.GetOrderBook("BTCUSD", 100)
if err != nil {
t.Error("Test failed - GetOrderBook() error", err)

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -27,7 +29,7 @@ const (
btcMarketsWithdrawCrypto = "/fundtransfer/withdrawCrypto"
btcMarketsWithdrawAud = "/fundtransfer/withdrawEFT"
//Status Values
// Status Values
orderStatusNew = "New"
orderStatusPlaced = "Placed"
orderStatusFailed = "Failed"
@@ -36,12 +38,16 @@ const (
orderStatusPartiallyCancelled = "Partially Cancelled"
orderStatusFullyMatched = "Fully Matched"
orderStatusPartiallyMatched = "Partially Matched"
btcmarketsAuthLimit = 0
btcmarketsUnauthLimit = 0
)
// BTCMarkets is the overarching type across the BTCMarkets package
type BTCMarkets struct {
exchange.Base
Ticker map[string]Ticker
*request.Handler
}
// SetDefaults sets basic defaults
@@ -59,6 +65,8 @@ func (b *BTCMarkets) SetDefaults() {
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.Handler = new(request.Handler)
b.SetRequestHandler(b.Name, btcmarketsAuthLimit, btcmarketsUnauthLimit, new(http.Client))
}
// Setup takes in an exchange configuration and sets all parameters
@@ -99,22 +107,24 @@ func (b *BTCMarkets) GetFee() float64 {
// symbol - example "btc" or "ltc"
func (b *BTCMarkets) GetTicker(firstPair, secondPair string) (Ticker, error) {
ticker := Ticker{}
path := fmt.Sprintf("/market/%s/%s/tick", common.StringToUpper(firstPair),
path := fmt.Sprintf("%s/market/%s/%s/tick",
btcMarketsAPIURL,
common.StringToUpper(firstPair),
common.StringToUpper(secondPair))
return ticker,
common.SendHTTPGetRequest(btcMarketsAPIURL+path, true, b.Verbose, &ticker)
return ticker, b.SendHTTPRequest(path, &ticker)
}
// GetOrderbook returns current orderbook
// symbol - example "btc" or "ltc"
func (b *BTCMarkets) GetOrderbook(firstPair, secondPair string) (Orderbook, error) {
orderbook := Orderbook{}
path := fmt.Sprintf("/market/%s/%s/orderbook", common.StringToUpper(firstPair),
path := fmt.Sprintf("%s/market/%s/%s/orderbook",
btcMarketsAPIURL,
common.StringToUpper(firstPair),
common.StringToUpper(secondPair))
return orderbook,
common.SendHTTPGetRequest(btcMarketsAPIURL+path, true, b.Verbose, &orderbook)
return orderbook, b.SendHTTPRequest(path, &orderbook)
}
// GetTrades returns executed trades on the exchange
@@ -126,7 +136,7 @@ func (b *BTCMarkets) GetTrades(firstPair, secondPair string, values url.Values)
btcMarketsAPIURL, common.StringToUpper(firstPair),
common.StringToUpper(secondPair)), values)
return trades, common.SendHTTPGetRequest(path, true, b.Verbose, &trades)
return trades, b.SendHTTPRequest(path, &trades)
}
// NewOrder requests a new order and returns an ID
@@ -337,6 +347,11 @@ func (b *BTCMarkets) WithdrawAUD(accountName, accountNumber, bankName, bsbNumber
return resp.Status, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *BTCMarkets) SendHTTPRequest(path string, result interface{}) error {
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
}
// SendAuthenticatedRequest sends an authenticated HTTP request
func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data interface{}, result interface{}) (err error) {
if !b.AuthenticatedAPISupport {
@@ -375,21 +390,5 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data interfa
headers["timestamp"] = b.Nonce.String()[0:13]
headers["signature"] = common.Base64Encode(hmac)
resp, err := common.SendHTTPRequest(reqType, btcMarketsAPIURL+path, headers, bytes.NewBuffer(payload))
if err != nil {
return err
}
if b.Verbose {
log.Printf("Received raw: %s\n", resp)
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return err
}
return nil
return b.SendPayload(reqType, btcMarketsAPIURL+path, headers, bytes.NewBuffer(payload), result, true, b.Verbose)
}

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -32,6 +34,9 @@ const (
coinutOptionChain = "option_chain"
coinutPositionHistory = "position_history"
coinutPositionOpen = "user_open_positions"
coinutAuthRate = 0
coinutUnauthRate = 0
)
// COINUT is the overarching type across the coinut package
@@ -39,6 +44,7 @@ type COINUT struct {
exchange.Base
WebsocketConn *websocket.Conn
InstrumentMap map[string]int
*request.Handler
}
// SetDefaults sets current default values
@@ -57,6 +63,8 @@ func (c *COINUT) SetDefaults() {
c.ConfigCurrencyPairFormat.Uppercase = true
c.AssetTypes = []string{ticker.Spot}
c.SupportsAutoPairUpdating = true
c.Handler = new(request.Handler)
c.SetRequestHandler(c.Name, coinutAuthRate, coinutUnauthRate, new(http.Client))
}
// Setup sets the current exchange configuration
@@ -93,11 +101,8 @@ func (c *COINUT) GetInstruments() (Instruments, error) {
var result Instruments
params := make(map[string]interface{})
params["sec_type"] = "SPOT"
err := c.SendHTTPRequest(coinutInstruments, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutInstruments, params, false, &result)
}
// GetInstrumentTicker returns a ticker for a specific instrument
@@ -105,11 +110,8 @@ func (c *COINUT) GetInstrumentTicker(instrumentID int) (Ticker, error) {
var result Ticker
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendHTTPRequest(coinutTicker, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutTicker, params, false, &result)
}
// GetInstrumentOrderbook returns the orderbooks for a specific instrument
@@ -120,11 +122,8 @@ func (c *COINUT) GetInstrumentOrderbook(instrumentID, limit int) (Orderbook, err
if limit > 0 {
params["top_n"] = limit
}
err := c.SendHTTPRequest(coinutOrderbook, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutOrderbook, params, false, &result)
}
// GetTrades returns trade information
@@ -132,21 +131,15 @@ func (c *COINUT) GetTrades(instrumentID int) (Trades, error) {
var result Trades
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendHTTPRequest(coinutTrades, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutTrades, params, false, &result)
}
// GetUserBalance returns the full user balance
func (c *COINUT) GetUserBalance() (UserBalance, error) {
result := UserBalance{}
err := c.SendHTTPRequest(coinutBalance, nil, true, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutBalance, nil, true, &result)
}
// NewOrder places a new order on the exchange
@@ -162,11 +155,7 @@ func (c *COINUT) NewOrder(instrumentID int, quantity, price float64, buy bool, o
}
params["client_ord_id"] = orderID
err := c.SendHTTPRequest(coinutOrder, params, true, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutOrder, params, true, &result)
}
// NewOrders places multiple orders on the exchange
@@ -174,11 +163,8 @@ func (c *COINUT) NewOrders(orders []Order) ([]OrdersBase, error) {
var result OrdersResponse
params := make(map[string]interface{})
params["orders"] = orders
err := c.SendHTTPRequest(coinutOrders, params, true, &result.Data)
if err != nil {
return nil, err
}
return result.Data, nil
return result.Data, c.SendHTTPRequest(coinutOrders, params, true, &result.Data)
}
// GetOpenOrders returns a list of open order and relevant information
@@ -186,11 +172,8 @@ func (c *COINUT) GetOpenOrders(instrumentID int) ([]OrdersResponse, error) {
var result []OrdersResponse
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendHTTPRequest(coinutOrdersOpen, params, true, &result)
if err != nil {
return nil, err
}
return result, nil
return result, c.SendHTTPRequest(coinutOrdersOpen, params, true, &result)
}
// CancelOrder cancels a specific order and returns if it was actioned
@@ -199,6 +182,7 @@ func (c *COINUT) CancelOrder(instrumentID, orderID int) (bool, error) {
params := make(map[string]interface{})
params["inst_id"] = instrumentID
params["order_id"] = orderID
err := c.SendHTTPRequest(coinutOrdersCancel, params, true, &result)
if err != nil {
return false, err
@@ -211,11 +195,8 @@ func (c *COINUT) CancelOrders(orders []CancelOrders) (CancelOrdersResponse, erro
var result CancelOrdersResponse
params := make(map[string]interface{})
params["entries"] = orders
err := c.SendHTTPRequest(coinutOrdersCancel, params, true, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutOrdersCancel, params, true, &result)
}
// GetTradeHistory returns trade history for a specific instrument.
@@ -229,11 +210,8 @@ func (c *COINUT) GetTradeHistory(instrumentID, start, limit int) (TradeHistory,
if limit >= 0 && start <= 100 {
params["limit"] = limit
}
err := c.SendHTTPRequest(coinutTradeHistory, params, true, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutTradeHistory, params, true, &result)
}
// GetIndexTicker returns the index ticker for an asset
@@ -241,11 +219,8 @@ func (c *COINUT) GetIndexTicker(asset string) (IndexTicker, error) {
var result IndexTicker
params := make(map[string]interface{})
params["asset"] = asset
err := c.SendHTTPRequest(coinutIndexTicker, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutIndexTicker, params, false, &result)
}
// GetDerivativeInstruments returns a list of derivative instruments
@@ -253,11 +228,8 @@ func (c *COINUT) GetDerivativeInstruments(secType string) (interface{}, error) {
var result interface{} //to-do
params := make(map[string]interface{})
params["sec_type"] = secType
err := c.SendHTTPRequest(coinutInstruments, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutInstruments, params, false, &result)
}
// GetOptionChain returns option chain
@@ -266,11 +238,8 @@ func (c *COINUT) GetOptionChain(asset, secType string, expiry int64) (OptionChai
params := make(map[string]interface{})
params["asset"] = asset
params["sec_type"] = secType
err := c.SendHTTPRequest(coinutOptionChain, params, false, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutOptionChain, params, false, &result)
}
// GetPositionHistory returns position history
@@ -284,11 +253,8 @@ func (c *COINUT) GetPositionHistory(secType string, start, limit int) (PositionH
if limit >= 0 {
params["limit"] = limit
}
err := c.SendHTTPRequest(coinutPositionHistory, params, true, &result)
if err != nil {
return result, err
}
return result, nil
return result, c.SendHTTPRequest(coinutPositionHistory, params, true, &result)
}
// GetOpenPositions returns all your current opened positions
@@ -300,16 +266,13 @@ func (c *COINUT) GetOpenPositions(instrumentID int) ([]OpenPosition, error) {
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendHTTPRequest(coinutPositionOpen, params, true, &result)
if err != nil {
return result.Positions, err
}
return result.Positions, nil
return result.Positions,
c.SendHTTPRequest(coinutPositionOpen, params, true, &result)
}
//to-do: user position update via websocket
// SendHTTPRequest sends an authenticated HTTP request
// SendHTTPRequest sends either an authenticated or unauthenticated HTTP request
func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{}, authenticated bool, result interface{}) (err error) {
if !c.AuthenticatedAPISupport && authenticated {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name)
@@ -344,32 +307,5 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{
}
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest("POST", coinutAPIURL, headers, bytes.NewBuffer(payload))
if err != nil {
return err
}
if c.Verbose {
log.Printf("Received raw: \n%s", resp)
}
genResp := GenericResponse{}
err = common.JSONDecode([]byte(resp), &genResp)
if err != nil {
return errors.New("unable to JSON Unmarshal generic response")
}
if len(genResp.Status) < 1 {
return errors.New("genResp.Status was empty")
}
if genResp.Status[0] != "OK" {
return errors.New("status is not OK")
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return c.SendPayload("POST", coinutAPIURL, headers, bytes.NewBuffer(payload), result, authenticated, c.Verbose)
}

View File

@@ -20,16 +20,12 @@ func TestSetDefaults(t *testing.T) {
}
func TestSetup(t *testing.T) {
t.Parallel()
c.Name = "Coinut"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("COINUT")
if err != nil {
t.Error("Test Failed - Coinut Setup() init error")
}
c.SetDefaults()
c.Setup(bConfig)
if !c.IsEnabled() || c.AuthenticatedAPISupport || c.RESTPollingDelay != time.Duration(10) ||
@@ -37,17 +33,9 @@ func TestSetup(t *testing.T) {
len(c.AvailablePairs) < 1 || len(c.EnabledPairs) < 1 {
t.Error("Test Failed - Coinut Setup values not set correctly")
}
bConfig.Enabled = false
c.Setup(bConfig)
if c.IsEnabled() {
t.Error("Test failed - Coinut TestSetup incorrect value")
}
}
func TestGetInstruments(t *testing.T) {
c.Verbose = true
_, err := c.GetInstruments()
if err != nil {
t.Error("Test failed - GetInstruments() error", err)

View File

@@ -1,9 +1,9 @@
package exmo
import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"reflect"
"strconv"
@@ -13,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -39,15 +40,18 @@ const (
exmoExcodeCreate = "excode_create"
exmoExcodeLoad = "excode_load"
exmoWalletHistory = "wallet_history"
// Rate limit: 180 per/minute
exmoAuthRate = 333
exmoUnauthRate = 333
)
// EXMO exchange struct
type EXMO struct {
exchange.Base
*request.Handler
}
// Rate limit: 180 per/minute
// SetDefaults sets the basic defaults for exmo
func (e *EXMO) SetDefaults() {
e.Name = "EXMO"
@@ -62,6 +66,8 @@ func (e *EXMO) SetDefaults() {
e.ConfigCurrencyPairFormat.Uppercase = true
e.AssetTypes = []string{ticker.Spot}
e.SupportsAutoPairUpdating = true
e.Handler = new(request.Handler)
e.SetRequestHandler(e.Name, exmoAuthRate, exmoUnauthRate, new(http.Client))
}
// Setup takes in the supplied exchange configuration details and sets params
@@ -99,8 +105,8 @@ func (e *EXMO) GetTrades(symbol string) (map[string][]Trades, error) {
v.Set("pair", symbol)
result := make(map[string][]Trades)
url := fmt.Sprintf("%s/v%s/%s", exmoAPIURL, exmoAPIVersion, exmoTrades)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, v), true, e.Verbose, &result)
return result, err
return result, e.SendHTTPRequest(common.EncodeURLValues(url, v), &result)
}
// GetOrderbook returns the orderbook for a symbol or symbols
@@ -109,8 +115,8 @@ func (e *EXMO) GetOrderbook(symbol string) (map[string]Orderbook, error) {
v.Set("pair", symbol)
result := make(map[string]Orderbook)
url := fmt.Sprintf("%s/v%s/%s", exmoAPIURL, exmoAPIVersion, exmoOrderbook)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, v), true, e.Verbose, &result)
return result, err
return result, e.SendHTTPRequest(common.EncodeURLValues(url, v), &result)
}
// GetTicker returns the ticker for a symbol or symbols
@@ -119,24 +125,24 @@ func (e *EXMO) GetTicker(symbol string) (map[string]Ticker, error) {
v.Set("pair", symbol)
result := make(map[string]Ticker)
url := fmt.Sprintf("%s/v%s/%s", exmoAPIURL, exmoAPIVersion, exmoTicker)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, v), true, e.Verbose, &result)
return result, err
return result, e.SendHTTPRequest(common.EncodeURLValues(url, v), &result)
}
// GetPairSettings returns the pair settings for a symbol or symbols
func (e *EXMO) GetPairSettings() (map[string]PairSettings, error) {
result := make(map[string]PairSettings)
url := fmt.Sprintf("%s/v%s/%s", exmoAPIURL, exmoAPIVersion, exmoPairSettings)
err := common.SendHTTPGetRequest(url, true, e.Verbose, &result)
return result, err
return result, e.SendHTTPRequest(url, &result)
}
// GetCurrency returns a list of currencies
func (e *EXMO) GetCurrency() ([]string, error) {
result := []string{}
url := fmt.Sprintf("%s/v%s/%s", exmoAPIURL, exmoAPIVersion, exmoCurrency)
err := common.SendHTTPGetRequest(url, true, e.Verbose, &result)
return result, err
return result, e.SendHTTPRequest(url, &result)
}
// GetUserInfo returns the user info
@@ -311,6 +317,11 @@ func (e *EXMO) GetWalletHistory(date int64) (WalletHistory, error) {
return result, err
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (e *EXMO) SendHTTPRequest(path string, result interface{}) error {
return e.SendPayload("GET", path, nil, nil, result, false, e.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Values, result interface{}) error {
if !e.AuthenticatedAPISupport {
@@ -337,28 +348,6 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va
headers["Content-Type"] = "application/x-www-form-urlencoded"
path := fmt.Sprintf("%s/v%s/%s", exmoAPIURL, exmoAPIVersion, endpoint)
resp, err := common.SendHTTPRequest(method, path, headers, strings.NewReader(payload))
if err != nil {
return err
}
if e.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
var authResp AuthResponse
err = common.JSONDecode([]byte(resp), &authResp)
if err != nil {
return errors.New("unable to JSON Unmarshal auth response")
}
if !authResp.Result && authResp.Error != "" {
return fmt.Errorf("auth error: %s", authResp.Error)
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return e.SendPayload(method, path, headers, strings.NewReader(payload), result, true, e.Verbose)
}

View File

@@ -11,6 +11,10 @@ var (
e EXMO
)
func TestDefault(t *testing.T) {
e.SetDefaults()
}
func TestSetup(t *testing.T) {
e.AuthenticatedAPISupport = true
e.APIKey = APIKey
@@ -18,6 +22,7 @@ func TestSetup(t *testing.T) {
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := e.GetTrades("BTC_USD")
if err != nil {
t.Errorf("Test failed. Err: %s", err)

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -46,6 +48,9 @@ const (
gdaxWithdrawalCrypto = "withdrawals/crypto"
gdaxCoinbaseAccounts = "coinbase-accounts"
gdaxTrailingVolume = "users/self/trailing-volume"
gdaxAuthRate = 0
gdaxUnauthRate = 0
)
var sometin []string
@@ -53,6 +58,7 @@ var sometin []string
// GDAX is the overarching type across the GDAX package
type GDAX struct {
exchange.Base
*request.Handler
}
// SetDefaults sets default values for the exchange
@@ -71,6 +77,8 @@ func (g *GDAX) SetDefaults() {
g.AssetTypes = []string{ticker.Spot}
g.APIUrl = gdaxAPIURL
g.SupportsAutoPairUpdating = true
g.Handler = new(request.Handler)
g.SetRequestHandler(g.Name, gdaxAuthRate, gdaxUnauthRate, new(http.Client))
}
// Setup initialises the exchange parameters with the current configuration
@@ -118,8 +126,7 @@ func (g *GDAX) GetFee(maker bool) float64 {
func (g *GDAX) GetProducts() ([]Product, error) {
products := []Product{}
return products,
common.SendHTTPGetRequest(g.APIUrl+gdaxProducts, true, g.Verbose, &products)
return products, g.SendHTTPRequest(g.APIUrl+gdaxProducts, &products)
}
// GetOrderbook returns orderbook by currency pair and level
@@ -132,7 +139,7 @@ func (g *GDAX) GetOrderbook(symbol string, level int) (interface{}, error) {
path = fmt.Sprintf("%s/%s/%s?level=%s", g.APIUrl+gdaxProducts, symbol, gdaxOrderbook, levelStr)
}
if err := common.SendHTTPGetRequest(path, true, g.Verbose, &orderbook); err != nil {
if err := g.SendHTTPRequest(path, &orderbook); err != nil {
return nil, err
}
@@ -201,7 +208,7 @@ func (g *GDAX) GetTicker(currencyPair string) (Ticker, error) {
path := fmt.Sprintf(
"%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxTicker)
return ticker, common.SendHTTPGetRequest(path, true, g.Verbose, &ticker)
return ticker, g.SendHTTPRequest(path, &ticker)
}
// GetTrades listd the latest trades for a product
@@ -211,7 +218,7 @@ func (g *GDAX) GetTrades(currencyPair string) ([]Trade, error) {
path := fmt.Sprintf(
"%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxTrades)
return trades, common.SendHTTPGetRequest(path, true, g.Verbose, &trades)
return trades, g.SendHTTPRequest(path, &trades)
}
// GetHistoricRates returns historic rates for a product. Rates are returned in
@@ -237,7 +244,7 @@ func (g *GDAX) GetHistoricRates(currencyPair string, start, end, granularity int
fmt.Sprintf("%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxHistory),
values)
if err := common.SendHTTPGetRequest(path, true, g.Verbose, &resp); err != nil {
if err := g.SendHTTPRequest(path, &resp); err != nil {
return history, err
}
@@ -268,7 +275,7 @@ func (g *GDAX) GetStats(currencyPair string) (Stats, error) {
path := fmt.Sprintf(
"%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxStats)
return stats, common.SendHTTPGetRequest(path, true, g.Verbose, &stats)
return stats, g.SendHTTPRequest(path, &stats)
}
// GetCurrencies returns a list of supported currency on the exchange
@@ -276,16 +283,14 @@ func (g *GDAX) GetStats(currencyPair string) (Stats, error) {
func (g *GDAX) GetCurrencies() ([]Currency, error) {
currencies := []Currency{}
return currencies,
common.SendHTTPGetRequest(g.APIUrl+gdaxCurrencies, true, g.Verbose, &currencies)
return currencies, g.SendHTTPRequest(g.APIUrl+gdaxCurrencies, &currencies)
}
// GetServerTime returns the API server time
func (g *GDAX) GetServerTime() (ServerTime, error) {
serverTime := ServerTime{}
return serverTime,
common.SendHTTPGetRequest(g.APIUrl+gdaxTime, true, g.Verbose, &serverTime)
return serverTime, g.SendHTTPRequest(g.APIUrl+gdaxTime, &serverTime)
}
// GetAccounts returns a list of trading accounts associated with the APIKEYS
@@ -766,6 +771,11 @@ func (g *GDAX) GetTrailingVolume() ([]Volume, error) {
g.SendAuthenticatedHTTPRequest("GET", gdaxTrailingVolume, nil, &resp)
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (g *GDAX) SendHTTPRequest(path string, result interface{}) error {
return g.SendPayload("GET", path, nil, nil, result, false, g.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP reque
func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) (err error) {
if !g.AuthenticatedAPISupport {
@@ -795,24 +805,5 @@ func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[stri
headers["CB-ACCESS-PASSPHRASE"] = g.ClientID
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest(method, g.APIUrl+path, headers, bytes.NewBuffer(payload))
if err != nil {
return err
}
if g.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
type initialResponse struct {
Message string `json:"message"`
}
initialCheck := initialResponse{}
err = common.JSONDecode([]byte(resp), &initialCheck)
if err == nil && len(initialCheck.Message) != 0 {
return errors.New(initialCheck.Message)
}
return common.JSONDecode([]byte(resp), &result)
return g.SendPayload(method, g.APIUrl+path, headers, bytes.NewBuffer(payload), result, true, g.Verbose)
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -39,13 +41,9 @@ const (
geminiWithdraw = "withdraw/"
geminiHeartbeat = "heartbeat"
// rate limits per minute
geminiPublicRate = 120
geminiPrivateRate = 600
// rates limits per second
geminiPublicRateSec = 1
geminiPrivateRateSec = 5
// gemini limit rates
geminiAuthRate = 100
geminiUnauthRate = 500
// Too many requests returns this
geminiRateError = "429"
@@ -57,7 +55,8 @@ const (
var (
// Session manager
Session map[int]*Gemini
Session map[int]*Gemini
gHandler *request.Handler
)
// Gemini is the overarching type across the Gemini package, create multiple
@@ -69,6 +68,7 @@ type Gemini struct {
exchange.Base
Role string
RequiresHeartBeat bool
*request.Handler
}
// AddSession adds a new session to the gemini base
@@ -76,6 +76,9 @@ func AddSession(g *Gemini, sessionID int, apiKey, apiSecret, role string, needsH
if Session == nil {
Session = make(map[int]*Gemini)
}
if gHandler == nil {
gHandler = new(request.Handler)
}
_, ok := Session[sessionID]
if ok {
@@ -110,6 +113,14 @@ func (g *Gemini) SetDefaults() {
g.ConfigCurrencyPairFormat.Uppercase = true
g.AssetTypes = []string{ticker.Spot}
g.SupportsAutoPairUpdating = true
if gHandler != nil {
g.Handler = gHandler
} else {
g.Handler = new(request.Handler)
}
if g.Handler.Client == nil {
g.SetRequestHandler(g.Name, geminiAuthRate, geminiUnauthRate, new(http.Client))
}
}
// Setup sets exchange configuration parameters
@@ -151,28 +162,33 @@ func (g *Gemini) GetSymbols() ([]string, error) {
symbols := []string{}
path := fmt.Sprintf("%s/v%s/%s", g.APIUrl, geminiAPIVersion, geminiSymbols)
return symbols, common.SendHTTPGetRequest(path, true, g.Verbose, &symbols)
return symbols, g.SendHTTPRequest(path, &symbols)
}
// GetTicker returns information about recent trading activity for the symbol
func (g *Gemini) GetTicker(currencyPair string) (Ticker, error) {
type TickerResponse struct {
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Last float64 `json:"last,string"`
Volume map[string]interface{}
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Last float64 `json:"last,string"`
Volume map[string]interface{}
Message string `json:"message"`
}
ticker := Ticker{}
resp := TickerResponse{}
path := fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiTicker, currencyPair)
err := common.SendHTTPGetRequest(path, true, g.Verbose, &resp)
err := g.SendHTTPRequest(path, &resp)
if err != nil {
return ticker, err
}
if resp.Message != "" {
return ticker, errors.New(resp.Message)
}
ticker.Ask = resp.Ask
ticker.Bid = resp.Bid
ticker.Last = resp.Last
@@ -201,7 +217,7 @@ func (g *Gemini) GetOrderbook(currencyPair string, params url.Values) (Orderbook
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiOrderbook, currencyPair), params)
orderbook := Orderbook{}
return orderbook, common.SendHTTPGetRequest(path, true, g.Verbose, &orderbook)
return orderbook, g.SendHTTPRequest(path, &orderbook)
}
// GetTrades eturn the trades that have executed since the specified timestamp.
@@ -217,7 +233,7 @@ func (g *Gemini) GetTrades(currencyPair string, params url.Values) ([]Trade, err
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiTrades, currencyPair), params)
trades := []Trade{}
return trades, common.SendHTTPGetRequest(path, true, g.Verbose, &trades)
return trades, g.SendHTTPRequest(path, &trades)
}
// GetAuction returns auction information
@@ -225,7 +241,7 @@ func (g *Gemini) GetAuction(currencyPair string) (Auction, error) {
path := fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiAuction, currencyPair)
auction := Auction{}
return auction, common.SendHTTPGetRequest(path, true, g.Verbose, &auction)
return auction, g.SendHTTPRequest(path, &auction)
}
// GetAuctionHistory returns the auction events, optionally including
@@ -243,7 +259,7 @@ func (g *Gemini) GetAuctionHistory(currencyPair string, params url.Values) ([]Au
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiAuction, currencyPair, geminiAuctionHistory), params)
auctionHist := []AuctionHistory{}
return auctionHist, common.SendHTTPGetRequest(path, true, g.Verbose, &auctionHist)
return auctionHist, g.SendHTTPRequest(path, &auctionHist)
}
func (g *Gemini) isCorrectSession(role string) error {
@@ -286,6 +302,10 @@ func (g *Gemini) CancelOrder(OrderID int64) (Order, error) {
if err != nil {
return Order{}, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
@@ -300,7 +320,14 @@ func (g *Gemini) CancelOrders(CancelBySession bool) (OrderResult, error) {
path = geminiOrderCancelSession
}
return response, g.SendAuthenticatedHTTPRequest("POST", path, nil, &response)
err := g.SendAuthenticatedHTTPRequest("POST", path, nil, &response)
if err != nil {
return response, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
// GetOrderStatus returns the status for an order
@@ -310,16 +337,32 @@ func (g *Gemini) GetOrderStatus(orderID int64) (Order, error) {
response := Order{}
return response,
g.SendAuthenticatedHTTPRequest("POST", geminiOrderStatus, request, &response)
err := g.SendAuthenticatedHTTPRequest("POST", geminiOrderStatus, request, &response)
if err != nil {
return response, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
// GetOrders returns active orders in the market
func (g *Gemini) GetOrders() ([]Order, error) {
response := []Order{}
var response struct {
orders []Order
Message string `json:"message"`
}
return response,
g.SendAuthenticatedHTTPRequest("POST", geminiOrders, nil, &response)
err := g.SendAuthenticatedHTTPRequest("POST", geminiOrders, nil, &response)
if err != nil {
return response.orders, err
}
if response.Message != "" {
return response.orders, errors.New(response.Message)
}
return response.orders, nil
}
// GetTradeHistory returns an array of trades that have been on the exchange
@@ -359,8 +402,14 @@ func (g *Gemini) GetBalances() ([]Balance, error) {
func (g *Gemini) GetDepositAddress(depositAddlabel, currency string) (DepositAddress, error) {
response := DepositAddress{}
return response,
g.SendAuthenticatedHTTPRequest("POST", geminiDeposit+"/"+currency+"/"+geminiNewAddress, nil, &response)
err := g.SendAuthenticatedHTTPRequest("POST", geminiDeposit+"/"+currency+"/"+geminiNewAddress, nil, &response)
if err != nil {
return response, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
// WithdrawCrypto withdraws crypto currency to a whitelisted address
@@ -370,20 +419,38 @@ func (g *Gemini) WithdrawCrypto(address, currency string, amount float64) (Withd
request["address"] = address
request["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
return response,
g.SendAuthenticatedHTTPRequest("POST", geminiWithdraw+currency, nil, &response)
err := g.SendAuthenticatedHTTPRequest("POST", geminiWithdraw+currency, nil, &response)
if err != nil {
return response, err
}
if response.Message != "" {
return response, errors.New(response.Message)
}
return response, nil
}
// PostHeartbeat sends a maintenance heartbeat to the exchange for all heartbeat
// maintaned sessions
func (g *Gemini) PostHeartbeat() (string, error) {
type Response struct {
Result string `json:"result"`
Result string `json:"result"`
Message string `json:"message"`
}
response := Response{}
return response.Result,
g.SendAuthenticatedHTTPRequest("POST", geminiHeartbeat, nil, &response)
err := g.SendAuthenticatedHTTPRequest("POST", geminiHeartbeat, nil, &response)
if err != nil {
return response.Result, err
}
if response.Message != "" {
return response.Result, errors.New(response.Message)
}
return response.Result, nil
}
// SendHTTPRequest sends an unauthenticated request
func (g *Gemini) SendHTTPRequest(path string, result interface{}) error {
return g.SendPayload("GET", path, nil, nil, result, false, g.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the
@@ -420,23 +487,5 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
headers["X-GEMINI-PAYLOAD"] = PayloadBase64
headers["X-GEMINI-SIGNATURE"] = common.HexEncodeToString(hmac)
resp, err := common.SendHTTPRequest(method, g.APIUrl+"/v1/"+path, headers, strings.NewReader(""))
if err != nil {
return err
}
if g.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
captureErr := ErrorCapture{}
if err = common.JSONDecode([]byte(resp), &captureErr); err == nil {
if len(captureErr.Message) != 0 || len(captureErr.Result) != 0 || len(captureErr.Reason) != 0 {
if captureErr.Result != "ok" {
return errors.New(captureErr.Message)
}
}
}
return common.JSONDecode([]byte(resp), &result)
return g.SendPayload(method, g.APIUrl+"/v1/"+path, headers, strings.NewReader(""), result, true, g.Verbose)
}

View File

@@ -7,10 +7,6 @@ import (
"github.com/thrasher-/gocryptotrader/config"
)
var (
g Gemini
)
// Please enter sandbox API keys & assigned roles for better testing procedures
const (
@@ -26,15 +22,17 @@ const (
)
func TestAddSession(t *testing.T) {
err := AddSession(&g, 1, apiKey1, apiSecret1, apiKeyRole1, true, false)
var g1 Gemini
err := AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, false)
if err != nil {
t.Error("Test failed - AddSession() error")
}
err = AddSession(&g, 1, apiKey1, apiSecret1, apiKeyRole1, true, false)
err = AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, false)
if err == nil {
t.Error("Test failed - AddSession() error")
}
err = AddSession(&g, 2, apiKey2, apiSecret2, apiKeyRole2, false, true)
var g2 Gemini
err = AddSession(&g2, 2, apiKey2, apiSecret2, apiKeyRole2, false, true)
if err != nil {
t.Error("Test failed - AddSession() error")
}
@@ -46,6 +44,7 @@ func TestSetDefaults(t *testing.T) {
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
geminiConfig, err := cfg.GetExchangeConfig("Gemini")

View File

@@ -74,6 +74,7 @@ type OrderResult struct {
CancelledOrders []string `json:"cancelledOrders"`
CancelRejects []string `json:"cancelRejects"`
} `json:"details"`
Message string `json:"message"`
}
// Order contains order information
@@ -97,6 +98,7 @@ type Order struct {
ExecutedAmount float64 `json:"executed_amount,string"`
RemainingAmount float64 `json:"remaining_amount,string"`
OriginalAmount float64 `json:"original_amount,string"`
Message string `json:"message"`
}
// TradeHistory holds trade history information
@@ -150,6 +152,7 @@ type DepositAddress struct {
Currency string `json:"currency"`
Address string `json:"address"`
Label string `json:"label"`
Message string `json:"message"`
}
// WithdrawalAddress holds withdrawal information
@@ -157,6 +160,7 @@ type WithdrawalAddress struct {
Address string `json:"address"`
Amount float64 `json:"amount"`
TXHash string `json:"txHash"`
Message string `json:"message"`
}
// ErrorCapture is a generlized error response from the server

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -39,11 +41,15 @@ const (
orderMove = "moveOrder"
tradableBalances = "returnTradableBalances"
transferBalance = "transferBalance"
hitbtcAuthRate = 0
hitbtcUnauthRate = 0
)
// HitBTC is the overarching type across the hitbtc package
type HitBTC struct {
exchange.Base
*request.Handler
}
// SetDefaults sets default settings for hitbtc
@@ -60,6 +66,8 @@ func (p *HitBTC) SetDefaults() {
p.ConfigCurrencyPairFormat.Uppercase = true
p.AssetTypes = []string{ticker.Spot}
p.SupportsAutoPairUpdating = true
p.Handler = new(request.Handler)
p.SetRequestHandler(p.Name, hitbtcAuthRate, hitbtcUnauthRate, new(http.Client))
}
// Setup sets user exchange configuration settings
@@ -107,12 +115,16 @@ func (p *HitBTC) GetCurrencies(currency string) (map[string]Currencies, error) {
}
resp := Response{}
path := fmt.Sprintf("%s/%s/%s", apiURL, apiV2Currency, currency)
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
ret := make(map[string]Currencies)
err := p.SendHTTPRequest(path, &resp.Data)
if err != nil {
return ret, err
}
for _, id := range resp.Data {
ret[id.ID] = id
}
return ret, err
}
@@ -124,12 +136,16 @@ func (p *HitBTC) GetCurrencies(currency string) (map[string]Currencies, error) {
func (p *HitBTC) GetSymbols(symbol string) ([]string, error) {
resp := []Symbol{}
path := fmt.Sprintf("%s/%s/%s", apiURL, apiV2Symbol, symbol)
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
ret := make([]string, 0, len(resp))
err := p.SendHTTPRequest(path, &resp)
if err != nil {
return ret, err
}
for _, x := range resp {
ret = append(ret, x.ID)
}
return ret, err
}
@@ -138,7 +154,8 @@ func (p *HitBTC) GetSymbols(symbol string) ([]string, error) {
func (p *HitBTC) GetSymbolsDetailed() ([]Symbol, error) {
resp := []Symbol{}
path := fmt.Sprintf("%s/%s", apiURL, apiV2Symbol)
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
return resp, p.SendHTTPRequest(path, &resp)
}
// GetTicker returns ticker information
@@ -151,7 +168,7 @@ func (p *HitBTC) GetTicker(symbol string) (map[string]Ticker, error) {
var err error
if symbol == "" {
err = common.SendHTTPGetRequest(path, true, false, &resp1)
err = p.SendHTTPRequest(path, &resp1)
if err != nil {
return nil, err
}
@@ -162,7 +179,7 @@ func (p *HitBTC) GetTicker(symbol string) (map[string]Ticker, error) {
}
}
} else {
err = common.SendHTTPGetRequest(path, true, false, &resp2)
err = p.SendHTTPRequest(path, &resp2)
ret[resp2.Symbol] = resp2
}
@@ -240,7 +257,7 @@ func (p *HitBTC) GetTrades(currencyPair, from, till, limit, offset, by, sort str
resp := []TradeHistory{}
path := fmt.Sprintf("%s/%s/%s?%s", apiURL, apiV2Trades, currencyPair, vals.Encode())
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
return resp, p.SendHTTPRequest(path, &resp)
}
// GetOrderbook an order book is an electronic list of buy and sell orders for a
@@ -256,7 +273,7 @@ func (p *HitBTC) GetOrderbook(currencyPair string, limit int) (Orderbook, error)
resp := OrderbookResponse{}
path := fmt.Sprintf("%s/%s/%s?%s", apiURL, apiV2Orderbook, currencyPair, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
err := p.SendHTTPRequest(path, &resp)
if err != nil {
return Orderbook{}, err
}
@@ -290,7 +307,7 @@ func (p *HitBTC) GetCandles(currencyPair, limit, period string) ([]ChartData, er
resp := []ChartData{}
path := fmt.Sprintf("%s/%s/%s?%s", apiURL, apiV2Candles, currencyPair, vals.Encode())
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
return resp, p.SendHTTPRequest(path, &resp)
}
// Authenticated Market Data
@@ -516,6 +533,11 @@ func (p *HitBTC) TransferBalance(currency, from, to string, amount float64) (boo
return true, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (p *HitBTC) SendHTTPRequest(path string, result interface{}) error {
return p.SendPayload("GET", path, nil, nil, result, false, p.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated http request
func (p *HitBTC) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, result interface{}) error {
if !p.AuthenticatedAPISupport {
@@ -526,15 +548,5 @@ func (p *HitBTC) SendAuthenticatedHTTPRequest(method, endpoint string, values ur
path := fmt.Sprintf("%s/%s", apiURL, endpoint)
resp, err := common.SendHTTPRequest(method, path, headers, bytes.NewBufferString(values.Encode()))
if err != nil {
return err
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return err
}
return nil
return p.SendPayload(method, path, headers, bytes.NewBufferString(values.Encode()), result, true, p.Verbose)
}

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -45,11 +47,15 @@ const (
huobiMarginAccountBalance = "margin/accounts/balance"
huobiWithdrawCreate = "dw/withdraw/api/create"
huobiWithdrawCancel = "dw/withdraw-virtual/%s/cancel"
huobiAuthRate = 0
huobiUnauthRate = 0
)
// HUOBI is the overarching type across this package
type HUOBI struct {
exchange.Base
*request.Handler
}
// SetDefaults sets default values for the exchange
@@ -66,6 +72,8 @@ func (h *HUOBI) SetDefaults() {
h.ConfigCurrencyPairFormat.Uppercase = true
h.AssetTypes = []string{ticker.Spot}
h.SupportsAutoPairUpdating = true
h.Handler = new(request.Handler)
h.SetRequestHandler(h.Name, huobiAuthRate, huobiUnauthRate, new(http.Client))
}
// Setup sets user configuration
@@ -122,8 +130,8 @@ func (h *HUOBI) GetKline(symbol, period, size string) ([]Klines, error) {
var result response
url := fmt.Sprintf("%s/%s", huobiAPIURL, huobiMarketHistoryKline)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, vals), true, h.Verbose, &result)
err := h.SendHTTPRequest(common.EncodeURLValues(url, vals), &result)
if result.ErrorMessage != "" {
return nil, errors.New(result.ErrorMessage)
}
@@ -142,8 +150,8 @@ func (h *HUOBI) GetMarketDetailMerged(symbol string) (DetailMerged, error) {
var result response
url := fmt.Sprintf("%s/%s", huobiAPIURL, huobiMarketDetailMerged)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, vals), true, h.Verbose, &result)
err := h.SendHTTPRequest(common.EncodeURLValues(url, vals), &result)
if result.ErrorMessage != "" {
return result.Tick, errors.New(result.ErrorMessage)
}
@@ -166,8 +174,8 @@ func (h *HUOBI) GetDepth(symbol, depthType string) (Orderbook, error) {
var result response
url := fmt.Sprintf("%s/%s", huobiAPIURL, huobiMarketDepth)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, vals), true, h.Verbose, &result)
err := h.SendHTTPRequest(common.EncodeURLValues(url, vals), &result)
if result.ErrorMessage != "" {
return result.Depth, errors.New(result.ErrorMessage)
}
@@ -188,8 +196,8 @@ func (h *HUOBI) GetTrades(symbol string) ([]Trade, error) {
var result response
url := fmt.Sprintf("%s/%s", huobiAPIURL, huobiMarketTrade)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, vals), true, h.Verbose, &result)
err := h.SendHTTPRequest(common.EncodeURLValues(url, vals), &result)
if result.ErrorMessage != "" {
return nil, errors.New(result.ErrorMessage)
}
@@ -212,8 +220,8 @@ func (h *HUOBI) GetTradeHistory(symbol, size string) ([]TradeHistory, error) {
var result response
url := fmt.Sprintf("%s/%s", huobiAPIURL, huobiMarketTradeHistory)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, vals), true, h.Verbose, &result)
err := h.SendHTTPRequest(common.EncodeURLValues(url, vals), &result)
if result.ErrorMessage != "" {
return nil, errors.New(result.ErrorMessage)
}
@@ -232,8 +240,8 @@ func (h *HUOBI) GetMarketDetail(symbol string) (Detail, error) {
var result response
url := fmt.Sprintf("%s/%s", huobiAPIURL, huobiMarketDetail)
err := common.SendHTTPGetRequest(common.EncodeURLValues(url, vals), true, h.Verbose, &result)
err := h.SendHTTPRequest(common.EncodeURLValues(url, vals), &result)
if result.ErrorMessage != "" {
return result.Tick, errors.New(result.ErrorMessage)
}
@@ -249,8 +257,8 @@ func (h *HUOBI) GetSymbols() ([]Symbol, error) {
var result response
url := fmt.Sprintf("%s/v%s/%s", huobiAPIURL, huobiAPIVersion, huobiSymbols)
err := common.SendHTTPGetRequest(url, true, h.Verbose, &result)
err := h.SendHTTPRequest(url, &result)
if result.ErrorMessage != "" {
return nil, errors.New(result.ErrorMessage)
}
@@ -266,8 +274,8 @@ func (h *HUOBI) GetCurrencies() ([]string, error) {
var result response
url := fmt.Sprintf("%s/v%s/%s", huobiAPIURL, huobiAPIVersion, huobiCurrencies)
err := common.SendHTTPGetRequest(url, true, h.Verbose, &result)
err := h.SendHTTPRequest(url, &result)
if result.ErrorMessage != "" {
return nil, errors.New(result.ErrorMessage)
}
@@ -283,8 +291,8 @@ func (h *HUOBI) GetTimestamp() (int64, error) {
var result response
url := fmt.Sprintf("%s/v%s/%s", huobiAPIURL, huobiAPIVersion, huobiTimestamp)
err := common.SendHTTPGetRequest(url, true, h.Verbose, &result)
err := h.SendHTTPRequest(url, &result)
if result.ErrorMessage != "" {
return 0, errors.New(result.ErrorMessage)
}
@@ -692,6 +700,11 @@ func (h *HUOBI) CancelWithdraw(withdrawID int64) (int64, error) {
return result.WithdrawID, err
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (h *HUOBI) SendHTTPRequest(path string, result interface{}) error {
return h.SendPayload("GET", path, nil, nil, result, false, h.Verbose)
}
// SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API
func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, result interface{}) error {
if !h.AuthenticatedAPISupport {
@@ -715,16 +728,6 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url
url := fmt.Sprintf("%s%s", huobiAPIURL, endpoint)
url = common.EncodeURLValues(url, values)
resp, err := common.SendHTTPRequest(method, url, headers, bytes.NewBufferString(""))
if err != nil {
return err
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return h.SendPayload(method, url, headers, bytes.NewBufferString(""), result, true, h.Verbose)
}

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -28,11 +30,15 @@ const (
itbitOrders = "orders"
itbitCryptoDeposits = "cryptocurrency_deposits"
itbitWalletTransfer = "wallet_transfers"
itbitAuthRate = 0
itbitUnauthRate = 0
)
// ItBit is the overarching type across the ItBit package
type ItBit struct {
exchange.Base
*request.Handler
}
// SetDefaults sets the defaults for the exchange
@@ -50,6 +56,8 @@ func (i *ItBit) SetDefaults() {
i.ConfigCurrencyPairFormat.Uppercase = true
i.AssetTypes = []string{ticker.Spot}
i.SupportsAutoPairUpdating = false
i.Handler = new(request.Handler)
i.SetRequestHandler(i.Name, itbitAuthRate, itbitUnauthRate, new(http.Client))
}
// Setup sets the exchange parameters from exchange config
@@ -95,8 +103,7 @@ 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)
return response, i.SendHTTPRequest(path, &response)
}
// GetOrderbook returns full order book for the specified market.
@@ -105,8 +112,7 @@ func (i *ItBit) GetOrderbook(currencyPair string) (OrderbookResponse, error) {
response := OrderbookResponse{}
path := fmt.Sprintf("%s/%s/%s/%s", itbitAPIURL, itbitMarkets, currencyPair, itbitOrderbook)
return response,
common.SendHTTPGetRequest(path, true, i.Verbose, &response)
return response, i.SendHTTPRequest(path, &response)
}
// GetTradeHistory returns recent trades for a specified market.
@@ -118,8 +124,7 @@ func (i *ItBit) GetTradeHistory(currencyPair, timestamp string) (Trades, error)
req := "trades?since=" + timestamp
path := fmt.Sprintf("%s/%s/%s/%s", itbitAPIURL, itbitMarkets, currencyPair, req)
return response,
common.SendHTTPGetRequest(path, true, i.Verbose, &response)
return response, i.SendHTTPRequest(path, &response)
}
// GetWallets returns information about all wallets associated with the account.
@@ -142,8 +147,14 @@ func (i *ItBit) CreateWallet(walletName string) (Wallet, error) {
params["userId"] = i.ClientID
params["name"] = walletName
return resp,
i.SendAuthenticatedHTTPRequest("POST", "/"+itbitWallets, params, &resp)
err := i.SendAuthenticatedHTTPRequest("POST", "/"+itbitWallets, params, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// GetWallet returns wallet information by walletID
@@ -151,7 +162,14 @@ func (i *ItBit) GetWallet(walletID string) (Wallet, error) {
resp := Wallet{}
path := fmt.Sprintf("/%s/%s", itbitWallets, walletID)
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// GetWalletBalance returns balance information for a specific currency in a
@@ -160,7 +178,14 @@ func (i *ItBit) GetWalletBalance(walletID, currency string) (Balance, error) {
resp := Balance{}
path := fmt.Sprintf("/%s/%s/%s/%s", itbitWallets, walletID, itbitBalances, currency)
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// GetWalletTrades returns all trades for a specified wallet.
@@ -169,7 +194,14 @@ func (i *ItBit) GetWalletTrades(walletID string, params url.Values) (Records, er
url := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitTrades)
path := common.EncodeURLValues(url, params)
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// GetFundingHistory returns all funding history for a specified wallet.
@@ -178,7 +210,14 @@ func (i *ItBit) GetFundingHistory(walletID string, params url.Values) (FundingRe
url := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitFundingHistory)
path := common.EncodeURLValues(url, params)
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// PlaceOrder places a new order
@@ -198,7 +237,14 @@ func (i *ItBit) PlaceOrder(walletID, side, orderType, currency string, amount, p
params["clientOrderIdentifier"] = clientRef
}
return resp, i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
err := i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// GetOrder returns an order by id.
@@ -207,7 +253,14 @@ func (i *ItBit) GetOrder(walletID string, params url.Values) (Order, error) {
url := fmt.Sprintf("/%s/%s/%s", itbitWallets, walletID, itbitOrders)
path := common.EncodeURLValues(url, params)
return resp, i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
err := i.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// CancelOrder cancels and open order. *This is not a guarantee that the order
@@ -225,7 +278,14 @@ func (i *ItBit) GetDepositAddress(walletID, currency string) (CryptoCurrencyDepo
params := make(map[string]interface{})
params["currency"] = currency
return resp, i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
err := i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// WalletTransfer transfers funds between wallets.
@@ -239,7 +299,19 @@ func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount
params["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
params["currencyCode"] = currency
return resp, i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
err := i.SendAuthenticatedHTTPRequest("POST", path, params, &resp)
if err != nil {
return resp, err
}
if resp.Description != "" {
return resp, errors.New(resp.Description)
}
return resp, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (i *ItBit) SendHTTPRequest(path string, result interface{}) error {
return i.SendPayload("GET", path, nil, nil, result, false, i.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated request to itBit
@@ -290,19 +362,5 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params
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)
}
errCapture := GeneralReturn{}
if err := common.JSONDecode([]byte(resp), &errCapture); err == nil {
return errors.New(errCapture.Description)
}
return common.JSONDecode([]byte(resp), result)
return i.SendPayload(method, url, headers, bytes.NewBuffer([]byte(PayloadJSON)), result, true, i.Verbose)
}

View File

@@ -47,10 +47,11 @@ type Trades struct {
// Wallet contains specific wallet information
type Wallet struct {
ID string `json:"id"`
UserID string `json:"userId"`
Name string `json:"name"`
Balances []Balance `json:"balances"`
ID string `json:"id"`
UserID string `json:"userId"`
Name string `json:"name"`
Balances []Balance `json:"balances"`
Description string `json:"description"`
}
// Balance is a sub type holding balance information
@@ -58,6 +59,7 @@ type Balance struct {
Currency string `json:"currency"`
AvailableBalance float64 `json:"availableBalance,string"`
TotalBalance float64 `json:"totalBalance,string"`
Description string `json:"description"`
}
// Records embodies records of trade history information
@@ -67,6 +69,7 @@ type Records struct {
LatestExecutedID int64 `json:"latestExecutionId,string"`
RecordsPerPage int `json:"recordsPerPage,string"`
TradingHistory []TradeHistory `json:"tradingHistory"`
Description string `json:"description"`
}
// TradeHistory stores historic trade values
@@ -93,6 +96,7 @@ type FundingRecords struct {
LatestExecutedID int64 `json:"latestExecutionId,string"`
RecordsPerPage int `json:"recordsPerPage,string"`
FundingHistory []FundHistory `json:"fundingHistory"`
Description string `json:"description"`
}
// FundHistory stores historic funding transactions
@@ -126,6 +130,7 @@ type Order struct {
Status string `json:"Status"`
Metadata interface{} `json:"metadata"`
ClientOrderIdentifier string `json:"clientOrderIdentifier"`
Description string `json:"description"`
}
// CryptoCurrencyDeposit holds information about a new wallet
@@ -134,6 +139,7 @@ type CryptoCurrencyDeposit struct {
WalletID string `json:"walletID"`
DepositAddress string `json:"depositAddress"`
Metadata interface{} `json:"metadata"`
Description string `json:"description"`
}
// WalletTransfer holds wallet transfer information
@@ -142,4 +148,5 @@ type WalletTransfer struct {
DestinationWalletID string `json:"destinationWalletId"`
Amount float64 `json:"amount,string"`
CurrencyCode string `json:"currencyCode"`
Description string `json:"description"`
}

View File

@@ -3,6 +3,7 @@ package kraken
import (
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -38,6 +40,9 @@ const (
krakenTradeVolume = "TradeVolume"
krakenOrderCancel = "CancelOrder"
krakenOrderPlace = "AddOrder"
krakenAuthRate = 0
krakenUnauthRate = 0
)
// Kraken is the overarching type across the alphapoint package
@@ -45,6 +50,7 @@ type Kraken struct {
exchange.Base
CryptoFee, FiatFee float64
Ticker map[string]Ticker
*request.Handler
}
// SetDefaults sets current default settings
@@ -64,6 +70,8 @@ func (k *Kraken) SetDefaults() {
k.ConfigCurrencyPairFormat.Uppercase = true
k.AssetTypes = []string{ticker.Spot}
k.SupportsAutoPairUpdating = true
k.Handler = new(request.Handler)
k.SetRequestHandler(k.Name, krakenAuthRate, krakenUnauthRate, new(http.Client))
}
// Setup sets current exchange configuration
@@ -108,7 +116,7 @@ func (k *Kraken) GetServerTime(unixTime bool) (interface{}, error) {
var result GeneralResponse
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenServerTime)
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
err := k.SendHTTPRequest(path, &result)
if err != nil {
return nil, fmt.Errorf("getServerTime() error %s", err)
}
@@ -124,7 +132,7 @@ func (k *Kraken) GetAssets() (interface{}, error) {
var result GeneralResponse
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssets)
return result.Result, common.SendHTTPGetRequest(path, true, k.Verbose, &result)
return result.Result, k.SendHTTPRequest(path, &result)
}
// GetAssetPairs returns a full asset pair list
@@ -137,7 +145,7 @@ func (k *Kraken) GetAssetPairs() (map[string]AssetPairs, error) {
response := Response{}
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssetPairs)
return response.Result, common.SendHTTPGetRequest(path, true, k.Verbose, &response)
return response.Result, k.SendHTTPRequest(path, &response)
}
// GetTicker returns ticker information from kraken
@@ -154,7 +162,7 @@ func (k *Kraken) GetTicker(symbol string) (Ticker, error) {
resp := Response{}
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenTicker, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &resp)
err := k.SendHTTPRequest(path, &resp)
if err != nil {
return ticker, err
}
@@ -192,7 +200,7 @@ func (k *Kraken) GetOHLC(symbol string) ([]OpenHighLowClose, error) {
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenOHLC, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
err := k.SendHTTPRequest(path, &result)
if err != nil {
return OHLC, err
}
@@ -238,7 +246,7 @@ func (k *Kraken) GetDepth(symbol string) (Orderbook, error) {
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenDepth, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
err := k.SendHTTPRequest(path, &result)
if err != nil {
return orderBook, err
}
@@ -297,7 +305,7 @@ func (k *Kraken) GetTrades(symbol string) ([]RecentTrades, error) {
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenTrades, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
err := k.SendHTTPRequest(path, &result)
if err != nil {
return recentTrades, err
}
@@ -338,7 +346,7 @@ func (k *Kraken) GetSpread(symbol string) ([]Spread, error) {
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenSpread, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &response)
err := k.SendHTTPRequest(path, &response)
if err != nil {
return peanutButter, err
}
@@ -568,6 +576,11 @@ func (k *Kraken) CancelOrder(orderID int64) (interface{}, error) {
return k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values)
}
// SendHTTPRequest sends an unauthenticated HTTP requests
func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
return k.SendPayload("GET", path, nil, nil, result, false, k.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values) (interface{}, error) {
if !k.AuthenticatedAPISupport {
@@ -599,20 +612,11 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values)
headers["API-Key"] = k.APIKey
headers["API-Sign"] = signature
rawResp, err := common.SendHTTPRequest("POST", krakenAPIURL+path, headers, strings.NewReader(values.Encode()))
if err != nil {
return nil, err
}
if k.Verbose {
log.Printf("Received raw: \n%s\n", rawResp)
}
var resp interface{}
err = common.JSONDecode([]byte(rawResp), &resp)
err = k.SendPayload("POST", krakenAPIURL+path, headers, strings.NewReader(values.Encode()), &resp, true, k.Verbose)
if err != nil {
return nil, err
return resp, err
}
data := resp.(map[string]interface{})

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"strconv"
"strings"
"time"
@@ -11,6 +12,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -29,11 +31,15 @@ const (
lakeBTCGetTrades = "getTrades"
lakeBTCGetExternalAccounts = "getExternalAccounts"
lakeBTCCreateWithdraw = "createWithdraw"
lakeBTCAuthRate = 0
lakeBTCUnauth = 0
)
// LakeBTC is the overarching type across the LakeBTC package
type LakeBTC struct {
exchange.Base
*request.Handler
}
// SetDefaults sets LakeBTC defaults
@@ -51,6 +57,8 @@ func (l *LakeBTC) SetDefaults() {
l.ConfigCurrencyPairFormat.Uppercase = true
l.AssetTypes = []string{ticker.Spot}
l.SupportsAutoPairUpdating = false
l.Handler = new(request.Handler)
l.SetRequestHandler(l.Name, lakeBTCAuthRate, lakeBTCUnauth, new(http.Client))
}
// Setup sets exchange configuration profile
@@ -95,7 +103,7 @@ func (l *LakeBTC) GetTicker() (map[string]Ticker, error) {
response := make(map[string]TickerResponse)
path := fmt.Sprintf("%s/%s", lakeBTCAPIURL, lakeBTCTicker)
if err := common.SendHTTPGetRequest(path, true, l.Verbose, &response); err != nil {
if err := l.SendHTTPRequest(path, &response); err != nil {
return nil, err
}
@@ -137,7 +145,7 @@ func (l *LakeBTC) GetOrderBook(currency string) (Orderbook, error) {
}
path := fmt.Sprintf("%s/%s?symbol=%s", lakeBTCAPIURL, lakeBTCOrderbook, common.StringToLower(currency))
resp := Response{}
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
err := l.SendHTTPRequest(path, &resp)
if err != nil {
return Orderbook{}, err
}
@@ -178,7 +186,7 @@ func (l *LakeBTC) GetTradeHistory(currency string) ([]TradeHistory, error) {
path := fmt.Sprintf("%s/%s?symbol=%s", lakeBTCAPIURL, lakeBTCTrades, common.StringToLower(currency))
resp := []TradeHistory{}
return resp, common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
return resp, l.SendHTTPRequest(path, &resp)
}
// GetAccountInfo returns your current account information
@@ -276,6 +284,11 @@ func (l *LakeBTC) CreateWithdraw(amount float64, accountID int64) (Withdraw, err
return resp, l.SendAuthenticatedHTTPRequest(lakeBTCCreateWithdraw, params, &resp)
}
// SendHTTPRequest sends an unauthenticated http request
func (l *LakeBTC) SendHTTPRequest(path string, result interface{}) error {
return l.SendPayload("GET", path, nil, nil, result, false, l.Verbose)
}
// SendAuthenticatedHTTPRequest sends an autheticated HTTP request to a LakeBTC
func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result interface{}) (err error) {
if !l.AuthenticatedAPISupport {
@@ -310,32 +323,5 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(l.APIKey+":"+common.HexEncodeToString(hmac)))
headers["Content-Type"] = "application/json-rpc"
resp, err := common.SendHTTPRequest("POST", lakeBTCAPIURL, headers, strings.NewReader(string(data)))
if err != nil {
return err
}
if l.Verbose {
log.Printf("Received raw: %s\n", resp)
}
type ErrorResponse struct {
Error string `json:"error"`
}
errResponse := ErrorResponse{}
err = common.JSONDecode([]byte(resp), &errResponse)
if err != nil {
return errors.New("unable to check response for error")
}
if errResponse.Error != "" {
return errors.New(errResponse.Error)
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return l.SendPayload("POST", lakeBTCAPIURL, headers, strings.NewReader(string(data)), result, true, l.Verbose)
}

View File

@@ -69,6 +69,9 @@ func TestGetTradeHistory(t *testing.T) {
func TestTrade(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.Trade(0, 0, 0, "USD")
if err == nil {
t.Error("Test Failed - Trade() error", err)
@@ -77,6 +80,9 @@ func TestTrade(t *testing.T) {
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.GetOpenOrders()
if err == nil {
t.Error("Test Failed - GetOpenOrders() error", err)
@@ -85,6 +91,9 @@ func TestGetOpenOrders(t *testing.T) {
func TestGetOrders(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.GetOrders([]int64{1, 2})
if err == nil {
t.Error("Test Failed - GetOrders() error", err)
@@ -93,6 +102,9 @@ func TestGetOrders(t *testing.T) {
func TestCancelOrder(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
err := l.CancelOrder(1337)
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
@@ -101,6 +113,9 @@ func TestCancelOrder(t *testing.T) {
func TestGetTrades(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.GetTrades(1337)
if err == nil {
t.Error("Test Failed - GetTrades() error", err)
@@ -109,6 +124,9 @@ func TestGetTrades(t *testing.T) {
func TestGetExternalAccounts(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.GetExternalAccounts()
if err == nil {
t.Error("Test Failed - GetExternalAccounts() error", err)
@@ -117,6 +135,9 @@ func TestGetExternalAccounts(t *testing.T) {
func TestCreateWithdraw(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.CreateWithdraw(0, 1337)
if err == nil {
t.Error("Test Failed - CreateWithdraw() error", err)

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -31,6 +33,9 @@ const (
liquiCancelOrder = "CancelOrder"
liquiTradeHistory = "TradeHistory"
liquiWithdrawCoin = "WithdrawCoin"
liquiAuthRate = 0
liquiUnauthRate = 0
)
// Liqui is the overarching type across the liqui package
@@ -38,6 +43,7 @@ type Liqui struct {
exchange.Base
Ticker map[string]Ticker
Info Info
*request.Handler
}
// SetDefaults sets current default values for liqui
@@ -56,6 +62,8 @@ func (l *Liqui) SetDefaults() {
l.ConfigCurrencyPairFormat.Uppercase = true
l.AssetTypes = []string{ticker.Spot}
l.SupportsAutoPairUpdating = true
l.Handler = new(request.Handler)
l.SetRequestHandler(l.Name, liquiAuthRate, liquiUnauthRate, new(http.Client))
}
// Setup sets exchange configuration parameters for liqui
@@ -117,7 +125,7 @@ func (l *Liqui) GetInfo() (Info, error) {
resp := Info{}
req := fmt.Sprintf("%s/%s/%s/", liquiAPIPublicURL, liquiAPIPublicVersion, liquiInfo)
return resp, common.SendHTTPGetRequest(req, true, l.Verbose, &resp)
return resp, l.SendHTTPRequest(req, &resp)
}
// GetTicker returns information about currently active pairs, such as: the
@@ -136,8 +144,7 @@ func (l *Liqui) GetTicker(currencyPair string) (map[string]Ticker, error) {
response := Response{Data: make(map[string]Ticker)}
req := fmt.Sprintf("%s/%s/%s/%s", liquiAPIPublicURL, liquiAPIPublicVersion, liquiTicker, currencyPair)
return response.Data,
common.SendHTTPGetRequest(req, true, l.Verbose, &response.Data)
return response.Data, l.SendHTTPRequest(req, &response.Data)
}
// GetDepth information about active orders on the pair. Additionally it accepts
@@ -153,8 +160,7 @@ func (l *Liqui) GetDepth(currencyPair string) (Orderbook, error) {
response := Response{Data: make(map[string]Orderbook)}
req := fmt.Sprintf("%s/%s/%s/%s", liquiAPIPublicURL, liquiAPIPublicVersion, liquiDepth, currencyPair)
return response.Data[currencyPair],
common.SendHTTPGetRequest(req, true, l.Verbose, &response.Data)
return response.Data[currencyPair], l.SendHTTPRequest(req, &response.Data)
}
// GetTrades returns information about the last trades. Additionally it accepts
@@ -170,8 +176,7 @@ func (l *Liqui) GetTrades(currencyPair string) ([]Trades, error) {
response := Response{Data: make(map[string][]Trades)}
req := fmt.Sprintf("%s/%s/%s/%s", liquiAPIPublicURL, liquiAPIPublicVersion, liquiTrades, currencyPair)
return response.Data[currencyPair],
common.SendHTTPGetRequest(req, true, l.Verbose, &response.Data)
return response.Data[currencyPair], l.SendHTTPRequest(req, &response.Data)
}
// GetAccountInfo returns information about the users current balance, API-key
@@ -257,6 +262,11 @@ func (l *Liqui) WithdrawCoins(coin string, amount float64, address string) (With
return result, l.SendAuthenticatedHTTPRequest(liquiWithdrawCoin, req, &result)
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (l *Liqui) SendHTTPRequest(path string, result interface{}) error {
return l.SendPayload("GET", path, nil, nil, result, false, l.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated http request to liqui
func (l *Liqui) SendAuthenticatedHTTPRequest(method string, values url.Values, result interface{}) (err error) {
if !l.AuthenticatedAPISupport {
@@ -283,31 +293,5 @@ func (l *Liqui) SendAuthenticatedHTTPRequest(method string, values url.Values, r
headers["Sign"] = common.HexEncodeToString(hmac)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest("POST", liquiAPIPrivateURL, headers, strings.NewReader(encoded))
if err != nil {
return err
}
response := Response{}
err = common.JSONDecode([]byte(resp), &response)
if err != nil {
return err
}
if response.Success != 1 {
return errors.New(response.Error)
}
jsonEncoded, err := common.JSONEncode(response.Return)
if err != nil {
return err
}
err = common.JSONDecode(jsonEncoded, &result)
if err != nil {
return err
}
return nil
return l.SendPayload("POST", liquiAPIPrivateURL, headers, strings.NewReader(encoded), result, true, l.Verbose)
}

View File

@@ -1,7 +1,6 @@
package liqui
import (
"log"
"net/url"
"testing"
@@ -68,11 +67,10 @@ func TestGetTicker(t *testing.T) {
func TestGetDepth(t *testing.T) {
t.Parallel()
v, err := l.GetDepth("eth_btc")
_, err := l.GetDepth("eth_btc")
if err != nil {
t.Error("Test Failed - liqui GetDepth() error", err)
}
log.Println(v)
}
func TestGetTrades(t *testing.T) {

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
)
const (
@@ -94,6 +96,9 @@ const (
statePaidAndConfirmed = "PAID_AND_CONFIRMED"
statePaidLateConfirmed = "PAID_IN_LATE_AND_CONFIRMED"
statePaidPartlyConfirmed = "PAID_PARTLY_AND_CONFIRMED"
localbitcoinsAuthRate = 0
localbitcoinsUnauthRate = 0
)
var (
@@ -104,6 +109,7 @@ var (
// LocalBitcoins is the overarching type across the localbitcoins package
type LocalBitcoins struct {
exchange.Base
*request.Handler
}
// SetDefaults sets the package defaults for localbitcoins
@@ -119,6 +125,8 @@ func (l *LocalBitcoins) SetDefaults() {
l.ConfigCurrencyPairFormat.Delimiter = ""
l.ConfigCurrencyPairFormat.Uppercase = true
l.SupportsAutoPairUpdating = false
l.Handler = new(request.Handler)
l.SetRequestHandler(l.Name, localbitcoinsAuthRate, localbitcoinsUnauthRate, new(http.Client))
}
// Setup sets exchange configuration parameters
@@ -170,7 +178,7 @@ func (l *LocalBitcoins) GetAccountInfo(username string, self bool) (AccountInfo,
}
} else {
path := fmt.Sprintf("%s/%s/%s/", localbitcoinsAPIURL, localbitcoinsAPIAccountInfo, username)
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
err := l.SendHTTPRequest(path, &resp)
if err != nil {
return resp.Data, err
}
@@ -658,6 +666,11 @@ func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) {
return orderbook, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (l *LocalBitcoins) SendHTTPRequest(path string, result interface{}) error {
return l.SendPayload("GET", path, nil, nil, result, false, l.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to
// localbitcoins
func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values url.Values, result interface{}) (err error) {
@@ -690,26 +703,5 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values
log.Printf("Raw Path: \n%s\n", path)
}
resp, err := common.SendHTTPRequest(method, localbitcoinsAPIURL+path, headers, bytes.NewBuffer([]byte(payload)))
if err != nil {
return err
}
if l.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
errCapture := GeneralError{}
if err = common.JSONDecode([]byte(resp), &errCapture); err == nil {
if len(errCapture.Error.Message) != 0 {
return errors.New(errCapture.Error.Message)
}
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return err
}
return nil
return l.SendPayload(method, localbitcoinsAPIURL+path, headers, bytes.NewBuffer([]byte(payload)), result, true, l.Verbose)
}

View File

@@ -43,6 +43,9 @@ func TestGetFee(t *testing.T) {
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.GetAccountInfo("", true)
if err == nil {
t.Error("Test Failed - GetAccountInfo() error", err)
@@ -55,6 +58,9 @@ func TestGetAccountInfo(t *testing.T) {
func TestGetads(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
_, err := l.Getads("")
if err == nil {
t.Error("Test Failed - Getads() - Full list, error", err)
@@ -67,6 +73,9 @@ func TestGetads(t *testing.T) {
func TestEditAd(t *testing.T) {
t.Parallel()
if l.APIKey == "" || l.APISecret == "" {
t.Skip()
}
edit := AdEdit{}
err := l.EditAd(edit, "1337")
if err == nil {

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -65,6 +67,9 @@ const (
okcoinFuturesposition4Fix = "future_position_4fix.do"
okcoinFuturesExplosive = "future_explosive.do"
okcoinFuturesDevolve = "future_devolve.do"
okcoinAuthRate = 0
okcoinUnauthRate = 0
)
var (
@@ -78,6 +83,7 @@ type OKCoin struct {
WebsocketErrors map[string]string
FuturesValues []string
WebsocketConn *websocket.Conn
*request.Handler
}
// setCurrencyPairFormats sets currency pair formatting for this package
@@ -99,6 +105,8 @@ func (o *OKCoin) SetDefaults() {
o.FuturesValues = []string{"this_week", "next_week", "quarter"}
o.AssetTypes = []string{ticker.Spot}
o.SupportsAutoPairUpdating = false
o.Handler = new(request.Handler)
o.SetRequestHandler(o.Name, okcoinAuthRate, okcoinUnauthRate, new(http.Client))
if okcoinDefaultsSet {
o.AssetTypes = append(o.AssetTypes, o.FuturesValues...)
@@ -162,11 +170,8 @@ func (o *OKCoin) GetTicker(symbol string) (Ticker, error) {
vals := url.Values{}
vals.Set("symbol", symbol)
path := common.EncodeURLValues(o.APIUrl+okcoinTicker, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return Ticker{}, err
}
return resp.Ticker, nil
return resp.Ticker, o.SendHTTPRequest(path, &resp)
}
// GetOrderBook returns the current order book by size
@@ -182,11 +187,7 @@ func (o *OKCoin) GetOrderBook(symbol string, size int64, merge bool) (Orderbook,
}
path := common.EncodeURLValues(o.APIUrl+okcoinDepth, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return resp, err
}
return resp, nil
return resp, o.SendHTTPRequest(path, &resp)
}
// GetTrades returns historic trades since a timestamp
@@ -199,11 +200,7 @@ func (o *OKCoin) GetTrades(symbol string, since int64) ([]Trades, error) {
}
path := common.EncodeURLValues(o.APIUrl+okcoinTrades, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &result)
if err != nil {
return nil, err
}
return result, nil
return result, o.SendHTTPRequest(path, &result)
}
// GetKline returns kline data
@@ -222,12 +219,7 @@ func (o *OKCoin) GetKline(symbol, klineType string, size, since int64) ([]interf
}
path := common.EncodeURLValues(o.APIUrl+okcoinKline, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return nil, err
}
return resp, nil
return resp, o.SendHTTPRequest(path, &resp)
}
// GetFuturesTicker returns a current ticker for the futures market
@@ -237,11 +229,8 @@ func (o *OKCoin) GetFuturesTicker(symbol, contractType string) (FuturesTicker, e
vals.Set("symbol", symbol)
vals.Set("contract_type", contractType)
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesTicker, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return FuturesTicker{}, err
}
return resp.Ticker, nil
return resp.Ticker, o.SendHTTPRequest(path, &resp)
}
// GetFuturesDepth returns current depth for the futures market
@@ -259,11 +248,7 @@ func (o *OKCoin) GetFuturesDepth(symbol, contractType string, size int64, merge
}
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesDepth, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &result)
if err != nil {
return result, err
}
return result, nil
return result, o.SendHTTPRequest(path, &result)
}
// GetFuturesTrades returns historic trades for the futures market
@@ -274,11 +259,7 @@ func (o *OKCoin) GetFuturesTrades(symbol, contractType string) ([]FuturesTrades,
vals.Set("contract_type", contractType)
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesTrades, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &result)
if err != nil {
return nil, err
}
return result, nil
return result, o.SendHTTPRequest(path, &result)
}
// GetFuturesIndex returns an index for the futures market
@@ -292,11 +273,7 @@ func (o *OKCoin) GetFuturesIndex(symbol string) (float64, error) {
vals.Set("symbol", symbol)
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesIndex, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &result)
if err != nil {
return 0, err
}
return result.Index, nil
return result.Index, o.SendHTTPRequest(path, &result)
}
// GetFuturesExchangeRate returns the exchange rate for the futures market
@@ -306,11 +283,7 @@ func (o *OKCoin) GetFuturesExchangeRate() (float64, error) {
}
result := Response{}
err := common.SendHTTPGetRequest(o.APIUrl+okcoinExchangeRate, true, o.Verbose, &result)
if err != nil {
return result.Rate, err
}
return result.Rate, nil
return result.Rate, o.SendHTTPRequest(o.APIUrl+okcoinExchangeRate, &result)
}
// GetFuturesEstimatedPrice returns a current estimated futures price for a
@@ -324,11 +297,8 @@ func (o *OKCoin) GetFuturesEstimatedPrice(symbol string) (float64, error) {
vals := url.Values{}
vals.Set("symbol", symbol)
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesEstimatedPrice, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &result)
if err != nil {
return result.Price, err
}
return result.Price, nil
return result.Price, o.SendHTTPRequest(path, &result)
}
// GetFuturesKline returns kline data for a specific currency on the futures
@@ -348,12 +318,7 @@ func (o *OKCoin) GetFuturesKline(symbol, klineType, contractType string, size, s
}
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesKline, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return nil, err
}
return resp, nil
return resp, o.SendHTTPRequest(path, &resp)
}
// GetFuturesHoldAmount returns the hold amount for a futures trade
@@ -364,12 +329,7 @@ func (o *OKCoin) GetFuturesHoldAmount(symbol, contractType string) ([]FuturesHol
vals.Set("contract_type", contractType)
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesHoldAmount, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return nil, err
}
return resp, nil
return resp, o.SendHTTPRequest(path, &resp)
}
// GetFuturesExplosive returns the explosive for a futures contract
@@ -386,25 +346,16 @@ func (o *OKCoin) GetFuturesExplosive(symbol, contractType string, status, curren
vals.Set("page_length", strconv.FormatInt(pageLength, 10))
path := common.EncodeURLValues(o.APIUrl+okcoinFuturesExplosive, vals)
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
if err != nil {
return nil, err
}
return resp.Data, nil
return resp.Data, o.SendHTTPRequest(path, &resp)
}
// GetUserInfo returns user information associated with the calling APIkeys
func (o *OKCoin) GetUserInfo() (UserInfo, error) {
result := UserInfo{}
err := o.SendAuthenticatedHTTPRequest(okcoinUserInfo, url.Values{}, &result)
if err != nil {
return result, err
}
return result, nil
return result,
o.SendAuthenticatedHTTPRequest(okcoinUserInfo, url.Values{}, &result)
}
// Trade initiates a new trade
@@ -943,6 +894,11 @@ func (o *OKCoin) GetFuturesUserPosition4Fix(symbol, contractType string) {
}
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (o *OKCoin) SendHTTPRequest(path string, result interface{}) error {
return o.SendPayload("GET", path, nil, nil, result, false, o.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
func (o *OKCoin) SendAuthenticatedHTTPRequest(method string, v url.Values, result interface{}) (err error) {
if !o.AuthenticatedAPISupport {
@@ -963,23 +919,7 @@ func (o *OKCoin) SendAuthenticatedHTTPRequest(method string, v url.Values, resul
headers := make(map[string]string)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest("POST", path, headers, strings.NewReader(encoded))
if err != nil {
return err
}
if o.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return o.SendPayload("POST", path, headers, strings.NewReader(encoded), result, true, o.Verbose)
}
// SetErrorDefaults sets default error map

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"reflect"
"strconv"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
)
const (
@@ -66,6 +68,9 @@ const (
// just your average return type from okex
returnTypeOne = "map[string]interface {}"
okexAuthRate = 0
okexUnauthRate = 0
)
var errMissValue = errors.New("warning - resp value is missing from exchange")
@@ -82,6 +87,8 @@ type OKEX struct {
CurrencyPairs []string
ContractPosition []string
Types []string
*request.Handler
}
// SetDefaults method assignes the default values for Bittrex
@@ -98,6 +105,8 @@ func (o *OKEX) SetDefaults() {
o.ConfigCurrencyPairFormat.Delimiter = "_"
o.ConfigCurrencyPairFormat.Uppercase = false
o.SupportsAutoPairUpdating = false
o.Handler = new(request.Handler)
o.SetRequestHandler(o.Name, okexAuthRate, okexUnauthRate, new(http.Client))
}
// Setup method sets current configuration details if enabled
@@ -149,7 +158,7 @@ func (o *OKEX) GetContractPrice(symbol, contractType string) (ContractPrice, err
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractPrice, values.Encode())
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
err := o.SendHTTPRequest(path, &resp)
if err != nil {
return resp, err
}
@@ -183,7 +192,7 @@ func (o *OKEX) GetContractMarketDepth(symbol, contractType string) (ActualContra
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractFutureDepth, values.Encode())
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
err := o.SendHTTPRequest(path, &resp)
if err != nil {
return fullDepth, err
}
@@ -247,7 +256,7 @@ func (o *OKEX) GetContractTradeHistory(symbol, contractType string) ([]ActualCon
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractTradeHistory, values.Encode())
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
err := o.SendHTTPRequest(path, &resp)
if err != nil {
return actualTradeHistory, err
}
@@ -284,7 +293,7 @@ func (o *OKEX) GetContractIndexPrice(symbol string) (float64, error) {
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractFutureIndex, values.Encode())
var resp interface{}
err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp)
err := o.SendHTTPRequest(path, &resp)
if err != nil {
return 0, err
}
@@ -307,7 +316,7 @@ func (o *OKEX) GetContractExchangeRate() (float64, error) {
path := fmt.Sprintf("%s%s%s.do?", apiURL, apiVersion, contractExchangeRate)
var resp interface{}
if err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp); err != nil {
if err := o.SendHTTPRequest(path, &resp); err != nil {
return 0, err
}
@@ -335,7 +344,7 @@ func (o *OKEX) GetContractFutureEstimatedPrice(symbol string) (float64, error) {
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractFutureIndex, values.Encode())
var resp interface{}
if err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp); err != nil {
if err := o.SendHTTPRequest(path, &resp); err != nil {
return 0, err
}
@@ -379,7 +388,7 @@ func (o *OKEX) GetContractCandlestickData(symbol, typeInput, contractType string
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractCandleStick, values.Encode())
var resp interface{}
if err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp); err != nil {
if err := o.SendHTTPRequest(path, &resp); err != nil {
return candleData, err
}
@@ -434,7 +443,7 @@ func (o *OKEX) GetContractHoldingsNumber(symbol, contractType string) (map[strin
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractFutureHoldAmount, values.Encode())
var resp interface{}
if err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp); err != nil {
if err := o.SendHTTPRequest(path, &resp); err != nil {
return holdingsNumber, err
}
@@ -470,7 +479,7 @@ func (o *OKEX) GetContractlimit(symbol, contractType string) (map[string]float64
path := fmt.Sprintf("%s%s%s.do?%s", apiURL, apiVersion, contractFutureLimits, values.Encode())
var resp interface{}
if err := common.SendHTTPGetRequest(path, true, o.Verbose, &resp); err != nil {
if err := o.SendHTTPRequest(path, &resp); err != nil {
return contractLimits, err
}
@@ -782,6 +791,11 @@ func (o *OKEX) GetErrorCode(code interface{}) error {
return errors.New("unable to find SPOT error code")
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (o *OKEX) SendHTTPRequest(path string, result interface{}) error {
return o.SendPayload("GET", path, nil, nil, result, false, o.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated http request to a desired
// path
func (o *OKEX) SendAuthenticatedHTTPRequest(method string, values url.Values, result interface{}) (err error) {
@@ -803,20 +817,7 @@ func (o *OKEX) SendAuthenticatedHTTPRequest(method string, values url.Values, re
headers := make(map[string]string)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest("POST", path, headers, strings.NewReader(encoded))
if err != nil {
return err
}
if o.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
return o.SendPayload("POST", path, headers, strings.NewReader(encoded), result, true, o.Verbose)
}
// SetErrorDefaults sets the full error default list

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"time"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -46,11 +48,15 @@ const (
poloniexActiveLoans = "returnActiveLoans"
poloniexLendingHistory = "returnLendingHistory"
poloniexAutoRenew = "toggleAutoRenew"
poloniexAuthRate = 0
poloniexUnauthRate = 0
)
// Poloniex is the overarching type across the poloniex package
type Poloniex struct {
exchange.Base
*request.Handler
}
// SetDefaults sets default settings for poloniex
@@ -67,6 +73,8 @@ func (p *Poloniex) SetDefaults() {
p.ConfigCurrencyPairFormat.Uppercase = true
p.AssetTypes = []string{ticker.Spot}
p.SupportsAutoPairUpdating = true
p.Handler = new(request.Handler)
p.SetRequestHandler(p.Name, poloniexAuthRate, poloniexUnauthRate, new(http.Client))
}
// Setup sets user exchange configuration settings
@@ -112,7 +120,7 @@ func (p *Poloniex) GetTicker() (map[string]Ticker, error) {
resp := response{}
path := fmt.Sprintf("%s/public?command=returnTicker", poloniexAPIURL)
return resp.Data, common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
return resp.Data, p.SendHTTPRequest(path, &resp.Data)
}
// GetVolume returns a list of currencies with associated volume
@@ -120,7 +128,7 @@ func (p *Poloniex) GetVolume() (interface{}, error) {
var resp interface{}
path := fmt.Sprintf("%s/public?command=return24hVolume", poloniexAPIURL)
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
return resp, p.SendHTTPRequest(path, &resp)
}
// GetOrderbook returns the full orderbook from poloniex
@@ -136,7 +144,7 @@ func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (OrderbookAll, e
vals.Set("currencyPair", currencyPair)
resp := OrderbookResponse{}
path := fmt.Sprintf("%s/public?command=returnOrderBook&%s", poloniexAPIURL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
err := p.SendHTTPRequest(path, &resp)
if err != nil {
return oba, err
}
@@ -169,7 +177,7 @@ func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (OrderbookAll, e
vals.Set("currencyPair", "all")
resp := OrderbookResponseAll{}
path := fmt.Sprintf("%s/public?command=returnOrderBook&%s", poloniexAPIURL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
err := p.SendHTTPRequest(path, &resp.Data)
if err != nil {
return oba, err
}
@@ -216,7 +224,7 @@ func (p *Poloniex) GetTradeHistory(currencyPair, start, end string) ([]TradeHist
resp := []TradeHistory{}
path := fmt.Sprintf("%s/public?command=returnTradeHistory&%s", poloniexAPIURL, vals.Encode())
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
return resp, p.SendHTTPRequest(path, &resp)
}
// GetChartData returns chart data for a specific currency pair
@@ -239,7 +247,7 @@ func (p *Poloniex) GetChartData(currencyPair, start, end, period string) ([]Char
resp := []ChartData{}
path := fmt.Sprintf("%s/public?command=returnChartData&%s", poloniexAPIURL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
err := p.SendHTTPRequest(path, &resp)
if err != nil {
return nil, err
}
@@ -255,7 +263,7 @@ func (p *Poloniex) GetCurrencies() (map[string]Currencies, error) {
resp := Response{}
path := fmt.Sprintf("%s/public?command=returnCurrencies", poloniexAPIURL)
return resp.Data, common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
return resp.Data, p.SendHTTPRequest(path, &resp.Data)
}
// GetExchangeCurrencies returns a list of currencies using the GetTicker API
@@ -280,7 +288,7 @@ func (p *Poloniex) GetLoanOrders(currency string) (LoanOrders, error) {
resp := LoanOrders{}
path := fmt.Sprintf("%s/public?command=returnLoanOrders&currency=%s", poloniexAPIURL, currency)
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
return resp, p.SendHTTPRequest(path, &resp)
}
// GetBalances returns balances for your account.
@@ -831,6 +839,11 @@ func (p *Poloniex) ToggleAutoRenew(orderNumber int64) (bool, error) {
return true, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (p *Poloniex) SendHTTPRequest(path string, result interface{}) error {
return p.SendPayload("GET", path, nil, nil, result, false, p.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, result interface{}) error {
if !p.AuthenticatedAPISupport {
@@ -853,10 +866,5 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values
path := fmt.Sprintf("%s/%s", poloniexAPIURL, poloniexAPITradingEndpoint)
resp, err := common.SendHTTPRequest(method, path, headers, bytes.NewBufferString(values.Encode()))
if err != nil {
return err
}
return common.JSONDecode([]byte(resp), &result)
return p.SendPayload(method, path, headers, bytes.NewBufferString(values.Encode()), result, true, p.Verbose)
}

View File

@@ -0,0 +1,252 @@
package request
import (
"errors"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
"sync"
"time"
"github.com/thrasher-/gocryptotrader/common"
)
const (
maxJobQueue = 100
maxHandles = 27
)
var request service
type service struct {
exchangeHandlers []*Handler
}
// checkHandles checks to see if there is a handle monitored by the service
func (s *service) checkHandles(exchName string, h *Handler) bool {
for _, handle := range s.exchangeHandlers {
if exchName == handle.exchName || handle == h {
return true
}
}
return false
}
// removeHandle releases handle from service
func (s *service) removeHandle(exchName string) bool {
for i, handle := range s.exchangeHandlers {
if exchName == handle.exchName {
handle.shutdown = true
handle.wg.Wait()
new := append(s.exchangeHandlers[:i-1], s.exchangeHandlers[i+1:]...)
s.exchangeHandlers = new
return true
}
}
return false
}
// limit contains the limit rate value which has a Mutex
type limit struct {
Val time.Duration
sync.Mutex
}
// getLimitRate returns limit rate with a protected call
func (l *limit) getLimitRate() time.Duration {
l.Lock()
defer l.Unlock()
return l.Val
}
// setLimitRates sets initial limit rates with a protected call
func (l *limit) setLimitRate(rate int) {
l.Lock()
l.Val = time.Duration(rate) * time.Millisecond
l.Unlock()
}
// Handler is a generic exchange specific request handler.
type Handler struct {
exchName string
Client *http.Client
shutdown bool
LimitAuth *limit
LimitUnauth *limit
requests chan *exchRequest
responses chan *exchResponse
timeLockAuth chan int
timeLock chan int
wg sync.WaitGroup
}
// SetRequestHandler sets initial variables for the request handler and returns
// an error
func (h *Handler) SetRequestHandler(exchName string, authRate, unauthRate int, client *http.Client) error {
if request.checkHandles(exchName, h) {
return errors.New("handler already registered for an exchange")
}
h.exchName = exchName
h.Client = client
h.shutdown = false
h.LimitAuth = new(limit)
h.LimitAuth.setLimitRate(authRate)
h.LimitUnauth = new(limit)
h.LimitUnauth.setLimitRate(unauthRate)
h.requests = make(chan *exchRequest, maxJobQueue)
h.responses = make(chan *exchResponse, 1)
h.timeLockAuth = make(chan int, 1)
h.timeLock = make(chan int, 1)
request.exchangeHandlers = append(request.exchangeHandlers, h)
h.startWorkers()
return nil
}
// SetRateLimit sets limit rates for exchange requests
func (h *Handler) SetRateLimit(authRate, unauthRate int) {
h.LimitAuth.setLimitRate(authRate)
h.LimitUnauth.setLimitRate(unauthRate)
}
// SendPayload packages a request, sends it to a channel, then a worker executes it
func (h *Handler) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, verbose bool) error {
if h.exchName == "" {
return errors.New("request handler not initialised")
}
method = strings.ToUpper(method)
if method != "POST" && method != "GET" && method != "DELETE" {
return errors.New("incorrect method - either POST, GET or DELETE")
}
if verbose {
log.Printf("%s exchange request path: %s", h.exchName, path)
}
req, err := http.NewRequest(method, path, body)
if err != nil {
return err
}
for k, v := range headers {
req.Header.Add(k, v)
}
err = h.attachJob(req, path, authRequest)
if err != nil {
return err
}
contents, err := h.getResponse()
if err != nil {
return err
}
if verbose {
log.Printf("%s exchange raw response: %s", h.exchName, string(contents[:]))
}
return common.JSONDecode(contents, result)
}
func (h *Handler) startWorkers() {
h.wg.Add(3)
go h.requestWorker()
// routine to monitor Autheticated limit rates
go func() {
h.timeLockAuth <- 1
for !h.shutdown {
<-h.timeLockAuth
time.Sleep(h.LimitAuth.getLimitRate())
h.timeLockAuth <- 1
}
h.wg.Done()
}()
// routine to monitor Unauthenticated limit rates
go func() {
h.timeLock <- 1
for !h.shutdown {
<-h.timeLock
time.Sleep(h.LimitUnauth.getLimitRate())
h.timeLock <- 1
}
h.wg.Done()
}()
}
// requestWorker handles the request queue
func (h *Handler) requestWorker() {
for job := range h.requests {
if h.shutdown {
break
}
var httpResponse *http.Response
var err error
if job.Auth {
<-h.timeLockAuth
httpResponse, err = h.Client.Do(job.Request)
h.timeLockAuth <- 1
} else {
<-h.timeLock
httpResponse, err = h.Client.Get(job.Path)
h.timeLock <- 1
}
for b := false; !b; {
select {
case h.responses <- &exchResponse{Response: httpResponse, ResError: err}:
b = true
default:
continue
}
}
}
h.wg.Done()
}
// exchRequest is the request type
type exchRequest struct {
Request *http.Request
Path string
Auth bool
}
// attachJob sends a request using the http package to the request channel
func (h *Handler) attachJob(req *http.Request, path string, isAuth bool) error {
select {
case h.requests <- &exchRequest{Request: req, Path: path, Auth: isAuth}:
return nil
default:
return errors.New("job queue exceeded")
}
}
// exchResponse is the main response type for requests
type exchResponse struct {
Response *http.Response
ResError error
}
// getResponse monitors the current resp channel and returns the contents
func (h *Handler) getResponse() ([]byte, error) {
resp := <-h.responses
if resp.ResError != nil {
return []byte(""), resp.ResError
}
defer resp.Response.Body.Close()
contents, err := ioutil.ReadAll(resp.Response.Body)
if err != nil {
return []byte(""), err
}
return contents, nil
}

View File

@@ -0,0 +1,84 @@
package request
import (
"net/http"
"sync"
"testing"
)
var (
wg sync.WaitGroup
bitfinex *Handler
BTCMarkets *Handler
)
func TestSetRequestHandler(t *testing.T) {
bitfinex = new(Handler)
err := bitfinex.SetRequestHandler("bitfinex", 1000, 1000, new(http.Client))
if err != nil {
t.Error("Test failed - request SetRequestHandler()", err)
}
err = bitfinex.SetRequestHandler("bitfinex", 1000, 1000, new(http.Client))
if err == nil {
t.Error("Test failed - request SetRequestHandler()", err)
}
err = bitfinex.SetRequestHandler("bla", 1000, 1000, new(http.Client))
if err == nil {
t.Error("Test failed - request SetRequestHandler()", err)
}
BTCMarkets = new(Handler)
BTCMarkets.SetRequestHandler("btcmarkets", 1000, 1000, new(http.Client))
if len(request.exchangeHandlers) != 2 {
t.Error("test failed - request GetRequestHandler() error")
}
wg.Add(2)
}
func TestSetRateLimit(t *testing.T) {
bitfinex.SetRateLimit(0, 0)
BTCMarkets.SetRateLimit(0, 0)
}
func TestSend(t *testing.T) {
for i := 0; i < 1; i++ {
go func() {
var v interface{}
err := bitfinex.SendPayload("GET",
"https://api.bitfinex.com/v1/pubticker/BTCUSD",
nil,
nil,
&v,
false,
false,
)
if err != nil {
t.Error("test failed - send error", err)
}
wg.Done()
}()
go func() {
var v interface{}
err := BTCMarkets.SendPayload("GET",
"https://api.btcmarkets.net/market/BTC/AUD/tick",
nil,
nil,
&v,
false,
false,
)
if err != nil {
t.Error("test failed - send error", err)
}
wg.Done()
}()
}
wg.Wait()
newHandler := new(Handler)
err := newHandler.SendPayload("GET", "https://api.bitfinex.com/v1/pubticker/BTCUSD",
nil, nil, nil, false, false)
if err == nil {
t.Error("test failed - request Send() error", err)
}
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -35,12 +37,16 @@ const (
wexCoinDepositAddress = "CoinDepositAddress"
wexCreateCoupon = "CreateCoupon"
wexRedeemCoupon = "RedeemCoupon"
wexAuthRate = 0
wexUnauthRate = 0
)
// WEX is the overarching type across the wex package
type WEX struct {
exchange.Base
Ticker map[string]Ticker
*request.Handler
}
// SetDefaults sets current default value for WEX
@@ -59,6 +65,8 @@ func (w *WEX) SetDefaults() {
w.ConfigCurrencyPairFormat.Uppercase = true
w.AssetTypes = []string{ticker.Spot}
w.SupportsAutoPairUpdating = false
w.Handler = new(request.Handler)
w.SetRequestHandler(w.Name, wexAuthRate, wexUnauthRate, new(http.Client))
}
// Setup sets exchange configuration parameters for WEX
@@ -100,7 +108,7 @@ func (w *WEX) GetInfo() (Info, error) {
resp := Info{}
req := fmt.Sprintf("%s/%s/%s/", wexAPIPublicURL, wexAPIPublicVersion, wexInfo)
return resp, common.SendHTTPGetRequest(req, true, w.Verbose, &resp)
return resp, w.SendHTTPRequest(req, &resp)
}
// GetTicker returns a ticker for a specific currency
@@ -112,7 +120,7 @@ func (w *WEX) GetTicker(symbol string) (map[string]Ticker, error) {
response := Response{}
req := fmt.Sprintf("%s/%s/%s/%s", wexAPIPublicURL, wexAPIPublicVersion, wexTicker, symbol)
return response.Data, common.SendHTTPGetRequest(req, true, w.Verbose, &response.Data)
return response.Data, w.SendHTTPRequest(req, &response.Data)
}
// GetDepth returns the depth for a specific currency
@@ -124,8 +132,7 @@ func (w *WEX) GetDepth(symbol string) (Orderbook, error) {
response := Response{}
req := fmt.Sprintf("%s/%s/%s/%s", wexAPIPublicURL, wexAPIPublicVersion, wexDepth, symbol)
return response.Data[symbol],
common.SendHTTPGetRequest(req, true, w.Verbose, &response.Data)
return response.Data[symbol], w.SendHTTPRequest(req, &response.Data)
}
// GetTrades returns the trades for a specific currency
@@ -137,16 +144,22 @@ func (w *WEX) GetTrades(symbol string) ([]Trades, error) {
response := Response{}
req := fmt.Sprintf("%s/%s/%s/%s", wexAPIPublicURL, wexAPIPublicVersion, wexTrades, symbol)
return response.Data[symbol],
common.SendHTTPGetRequest(req, true, w.Verbose, &response.Data)
return response.Data[symbol], w.SendHTTPRequest(req, &response.Data)
}
// GetAccountInfo returns a users account info
func (w *WEX) GetAccountInfo() (AccountInfo, error) {
var result AccountInfo
return result,
w.SendAuthenticatedHTTPRequest(wexAccountInfo, url.Values{}, &result)
err := w.SendAuthenticatedHTTPRequest(wexAccountInfo, url.Values{}, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// GetActiveOrders returns the active orders for a specific currency
@@ -175,12 +188,15 @@ func (w *WEX) CancelOrder(OrderID int64) (bool, error) {
req.Add("order_id", strconv.FormatInt(OrderID, 10))
var result CancelOrder
err := w.SendAuthenticatedHTTPRequest(wexCancelOrder, req, &result)
err := w.SendAuthenticatedHTTPRequest(wexCancelOrder, req, &result)
if err != nil {
return false, err
}
if result.Error != "" {
return false, errors.New(result.Error)
}
return true, nil
}
@@ -194,8 +210,15 @@ func (w *WEX) Trade(pair, orderType string, amount, price float64) (int64, error
var result Trade
return int64(result.OrderID),
w.SendAuthenticatedHTTPRequest(wexTrade, req, &result)
err := w.SendAuthenticatedHTTPRequest(wexTrade, req, &result)
if err != nil {
return 0, err
}
if result.Error != "" {
return 0, errors.New(result.Error)
}
return int64(result.OrderID), nil
}
// GetTransactionHistory returns the transaction history
@@ -241,7 +264,15 @@ func (w *WEX) WithdrawCoins(coin string, amount float64, address string) (Withdr
var result WithdrawCoins
return result, w.SendAuthenticatedHTTPRequest(wexWithdrawCoin, req, &result)
err := w.SendAuthenticatedHTTPRequest(wexWithdrawCoin, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// CoinDepositAddress returns the deposit address for a specific currency
@@ -251,8 +282,14 @@ func (w *WEX) CoinDepositAddress(coin string) (string, error) {
var result CoinDepositAddress
return result.Address,
w.SendAuthenticatedHTTPRequest(wexCoinDepositAddress, req, &result)
err := w.SendAuthenticatedHTTPRequest(wexCoinDepositAddress, req, &result)
if err != nil {
return result.Address, err
}
if result.Error != "" {
return result.Address, errors.New(result.Error)
}
return result.Address, nil
}
// CreateCoupon creates an exchange coupon for a sepcific currency
@@ -263,7 +300,14 @@ func (w *WEX) CreateCoupon(currency string, amount float64) (CreateCoupon, error
var result CreateCoupon
return result, w.SendAuthenticatedHTTPRequest(wexCreateCoupon, req, &result)
err := w.SendAuthenticatedHTTPRequest(wexCreateCoupon, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// RedeemCoupon redeems an exchange coupon
@@ -273,7 +317,19 @@ func (w *WEX) RedeemCoupon(coupon string) (RedeemCoupon, error) {
var result RedeemCoupon
return result, w.SendAuthenticatedHTTPRequest(wexRedeemCoupon, req, &result)
err := w.SendAuthenticatedHTTPRequest(wexRedeemCoupon, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (w *WEX) SendHTTPRequest(path string, result interface{}) error {
return w.SendPayload("GET", path, nil, nil, result, false, w.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to WEX
@@ -294,7 +350,10 @@ func (w *WEX) SendAuthenticatedHTTPRequest(method string, values url.Values, res
hmac := common.GetHMAC(common.HashSHA512, []byte(encoded), []byte(w.APISecret))
if w.Verbose {
log.Printf("Sending POST request to %s calling method %s with params %s\n", wexAPIPrivateURL, method, encoded)
log.Printf("Sending POST request to %s calling method %s with params %s\n",
wexAPIPrivateURL,
method,
encoded)
}
headers := make(map[string]string)
@@ -302,25 +361,5 @@ func (w *WEX) SendAuthenticatedHTTPRequest(method string, values url.Values, res
headers["Sign"] = common.HexEncodeToString(hmac)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest("POST", wexAPIPrivateURL, headers, strings.NewReader(encoded))
if err != nil {
return err
}
response := Response{}
err = common.JSONDecode([]byte(resp), &response)
if err != nil {
return err
}
if response.Success != 1 {
return errors.New(response.Error)
}
JSONEncoded, err := common.JSONEncode(response.Return)
if err != nil {
return err
}
return common.JSONDecode(JSONEncoded, &result)
return w.SendPayload("POST", wexAPIPrivateURL, headers, strings.NewReader(encoded), result, true, w.Verbose)
}

View File

@@ -33,12 +33,14 @@ func TestSetup(t *testing.T) {
}
func TestGetFee(t *testing.T) {
t.Parallel()
if w.GetFee() != 0.2 {
t.Error("Test Failed - GetFee() error")
}
}
func TestGetInfo(t *testing.T) {
t.Parallel()
_, err := w.GetInfo()
if err != nil {
t.Error("Test Failed - GetInfo() error")
@@ -46,6 +48,7 @@ func TestGetInfo(t *testing.T) {
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := w.GetTicker("btc_usd")
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
@@ -53,6 +56,7 @@ func TestGetTicker(t *testing.T) {
}
func TestGetDepth(t *testing.T) {
t.Parallel()
_, err := w.GetDepth("btc_usd")
if err != nil {
t.Error("Test Failed - GetDepth() error", err)
@@ -60,6 +64,7 @@ func TestGetDepth(t *testing.T) {
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := w.GetTrades("btc_usd")
if err != nil {
t.Error("Test Failed - GetTrades() error", err)
@@ -67,6 +72,7 @@ func TestGetTrades(t *testing.T) {
}
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
_, err := w.GetAccountInfo()
if err == nil {
t.Error("Test Failed - GetAccountInfo() error", err)
@@ -74,6 +80,7 @@ func TestGetAccountInfo(t *testing.T) {
}
func TestGetActiveOrders(t *testing.T) {
t.Parallel()
_, err := w.GetActiveOrders("")
if err == nil {
t.Error("Test Failed - GetActiveOrders() error", err)
@@ -81,6 +88,7 @@ func TestGetActiveOrders(t *testing.T) {
}
func TestGetOrderInfo(t *testing.T) {
t.Parallel()
_, err := w.GetOrderInfo(6196974)
if err == nil {
t.Error("Test Failed - GetOrderInfo() error", err)
@@ -88,6 +96,7 @@ func TestGetOrderInfo(t *testing.T) {
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
_, err := w.CancelOrder(1337)
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
@@ -95,6 +104,7 @@ func TestCancelOrder(t *testing.T) {
}
func TestTrade(t *testing.T) {
t.Parallel()
_, err := w.Trade("", "buy", 0, 0)
if err == nil {
t.Error("Test Failed - Trade() error", err)
@@ -102,6 +112,7 @@ func TestTrade(t *testing.T) {
}
func TestGetTransactionHistory(t *testing.T) {
t.Parallel()
_, err := w.GetTransactionHistory(0, 0, 0, "", "", "")
if err == nil {
t.Error("Test Failed - GetTransactionHistory() error", err)
@@ -109,6 +120,7 @@ func TestGetTransactionHistory(t *testing.T) {
}
func TestGetTradeHistory(t *testing.T) {
t.Parallel()
_, err := w.GetTradeHistory(0, 0, 0, "", "", "", "")
if err == nil {
t.Error("Test Failed - GetTradeHistory() error", err)
@@ -116,6 +128,7 @@ func TestGetTradeHistory(t *testing.T) {
}
func TestWithdrawCoins(t *testing.T) {
t.Parallel()
_, err := w.WithdrawCoins("", 0, "")
if err == nil {
t.Error("Test Failed - WithdrawCoins() error", err)
@@ -123,6 +136,7 @@ func TestWithdrawCoins(t *testing.T) {
}
func TestCoinDepositAddress(t *testing.T) {
t.Parallel()
_, err := w.CoinDepositAddress("btc")
if err == nil {
t.Error("Test Failed - WithdrawCoins() error", err)
@@ -130,6 +144,7 @@ func TestCoinDepositAddress(t *testing.T) {
}
func TestCreateCoupon(t *testing.T) {
t.Parallel()
_, err := w.CreateCoupon("bla", 0)
if err == nil {
t.Error("Test Failed - CreateCoupon() error", err)
@@ -137,6 +152,7 @@ func TestCreateCoupon(t *testing.T) {
}
func TestRedeemCoupon(t *testing.T) {
t.Parallel()
_, err := w.RedeemCoupon("bla")
if err == nil {
t.Error("Test Failed - RedeemCoupon() error", err)

View File

@@ -72,6 +72,7 @@ type AccountInfo struct {
} `json:"rights"`
ServerTime float64 `json:"server_time"`
TransactionCount int `json:"transaction_count"`
Error string `json:"error"`
}
// OrderInfo stores order information
@@ -89,6 +90,7 @@ type OrderInfo struct {
type CancelOrder struct {
OrderID float64 `json:"order_id"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// Trade stores the trade information
@@ -97,6 +99,7 @@ type Trade struct {
Remains float64 `json:"remains"`
OrderID float64 `json:"order_id"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// TransHistory stores transaction history
@@ -123,6 +126,7 @@ type TradeHistory struct {
// CoinDepositAddress stores a curency deposit address
type CoinDepositAddress struct {
Address string `json:"address"`
Error string `json:"error"`
}
// WithdrawCoins stores information for a withdrawcoins request
@@ -130,6 +134,7 @@ type WithdrawCoins struct {
TID int64 `json:"tId"`
AmountSent float64 `json:"amountSent"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// CreateCoupon stores information coupon information
@@ -137,6 +142,7 @@ type CreateCoupon struct {
Coupon string `json:"coupon"`
TransID int64 `json:"transID"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// RedeemCoupon stores redeem coupon information
@@ -144,4 +150,5 @@ type RedeemCoupon struct {
CouponAmount float64 `json:"couponAmount,string"`
CouponCurrency string `json:"couponCurrency"`
TransID int64 `json:"transID"`
Error string `json:"error"`
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@@ -12,6 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
@@ -33,12 +35,16 @@ const (
privateWithdrawCoinsToAddress = "WithdrawCoinsToAddress"
privateCreateCoupon = "CreateYobicode"
privateRedeemCoupon = "RedeemYobicode"
yobitAuthRate = 0
yobitUnauthRate = 0
)
// Yobit is the overarching type across the Yobit package
type Yobit struct {
exchange.Base
Ticker map[string]Ticker
*request.Handler
}
// SetDefaults sets current default value for Yobit
@@ -59,6 +65,8 @@ func (y *Yobit) SetDefaults() {
y.ConfigCurrencyPairFormat.Uppercase = true
y.AssetTypes = []string{ticker.Spot}
y.SupportsAutoPairUpdating = false
y.Handler = new(request.Handler)
y.SetRequestHandler(y.Name, yobitAuthRate, yobitUnauthRate, new(http.Client))
}
// Setup sets exchange configuration parameters for Yobit
@@ -100,7 +108,7 @@ func (y *Yobit) GetInfo() (Info, error) {
resp := Info{}
path := fmt.Sprintf("%s/%s/%s/", apiPublicURL, apiPublicVersion, publicInfo)
return resp, common.SendHTTPGetRequest(path, true, y.Verbose, &resp)
return resp, y.SendHTTPRequest(path, &resp)
}
// GetTicker returns a ticker for a specific currency
@@ -112,7 +120,7 @@ func (y *Yobit) GetTicker(symbol string) (map[string]Ticker, error) {
response := Response{}
path := fmt.Sprintf("%s/%s/%s/%s", apiPublicURL, apiPublicVersion, publicTicker, symbol)
return response.Data, common.SendHTTPGetRequest(path, true, y.Verbose, &response.Data)
return response.Data, y.SendHTTPRequest(path, &response.Data)
}
// GetDepth returns the depth for a specific currency
@@ -125,7 +133,7 @@ func (y *Yobit) GetDepth(symbol string) (Orderbook, error) {
path := fmt.Sprintf("%s/%s/%s/%s", apiPublicURL, apiPublicVersion, publicDepth, symbol)
return response.Data[symbol],
common.SendHTTPGetRequest(path, true, y.Verbose, &response.Data)
y.SendHTTPRequest(path, &response.Data)
}
// GetTrades returns the trades for a specific currency
@@ -137,14 +145,21 @@ func (y *Yobit) GetTrades(symbol string) ([]Trades, error) {
response := Response{}
path := fmt.Sprintf("%s/%s/%s/%s", apiPublicURL, apiPublicVersion, publicTrades, symbol)
return response.Data[symbol], common.SendHTTPGetRequest(path, true, y.Verbose, &response.Data)
return response.Data[symbol], y.SendHTTPRequest(path, &response.Data)
}
// GetAccountInfo returns a users account info
func (y *Yobit) GetAccountInfo() (AccountInfo, error) {
result := AccountInfo{}
return result, y.SendAuthenticatedHTTPRequest(privateAccountInfo, url.Values{}, &result)
err := y.SendAuthenticatedHTTPRequest(privateAccountInfo, url.Values{}, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// Trade places an order and returns the order ID if successful or an error
@@ -157,7 +172,14 @@ func (y *Yobit) Trade(pair, orderType string, amount, price float64) (int64, err
result := Trade{}
return int64(result.OrderID), y.SendAuthenticatedHTTPRequest(privateTrade, req, &result)
err := y.SendAuthenticatedHTTPRequest(privateTrade, req, &result)
if err != nil {
return int64(result.OrderID), err
}
if result.Error != "" {
return int64(result.OrderID), errors.New(result.Error)
}
return int64(result.OrderID), nil
}
// GetActiveOrders returns the active orders for a specific currency
@@ -186,12 +208,14 @@ func (y *Yobit) CancelOrder(OrderID int64) (bool, error) {
req.Add("order_id", strconv.FormatInt(OrderID, 10))
result := CancelOrder{}
err := y.SendAuthenticatedHTTPRequest(privateCancelOrder, req, &result)
err := y.SendAuthenticatedHTTPRequest(privateCancelOrder, req, &result)
if err != nil {
return false, err
}
if result.Error != "" {
return false, errors.New(result.Error)
}
return true, nil
}
@@ -219,7 +243,14 @@ func (y *Yobit) GetDepositAddress(coin string) (DepositAddress, error) {
result := DepositAddress{}
return result, y.SendAuthenticatedHTTPRequest(privateGetDepositAddress, req, &result)
err := y.SendAuthenticatedHTTPRequest(privateGetDepositAddress, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// WithdrawCoinsToAddress initiates a withdrawal to a specified address
@@ -231,7 +262,14 @@ func (y *Yobit) WithdrawCoinsToAddress(coin string, amount float64, address stri
result := WithdrawCoinsToAddress{}
return result, y.SendAuthenticatedHTTPRequest(privateWithdrawCoinsToAddress, req, &result)
err := y.SendAuthenticatedHTTPRequest(privateWithdrawCoinsToAddress, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// CreateCoupon creates an exchange coupon for a sepcific currency
@@ -242,7 +280,14 @@ func (y *Yobit) CreateCoupon(currency string, amount float64) (CreateCoupon, err
var result CreateCoupon
return result, y.SendAuthenticatedHTTPRequest(privateCreateCoupon, req, &result)
err := y.SendAuthenticatedHTTPRequest(privateCreateCoupon, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// RedeemCoupon redeems an exchange coupon
@@ -252,7 +297,19 @@ func (y *Yobit) RedeemCoupon(coupon string) (RedeemCoupon, error) {
result := RedeemCoupon{}
return result, y.SendAuthenticatedHTTPRequest(privateRedeemCoupon, req, &result)
err := y.SendAuthenticatedHTTPRequest(privateRedeemCoupon, req, &result)
if err != nil {
return result, err
}
if result.Error != "" {
return result, errors.New(result.Error)
}
return result, nil
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (y *Yobit) SendHTTPRequest(path string, result interface{}) error {
return y.SendPayload("GET", path, nil, nil, result, false, y.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to Yobit
@@ -285,30 +342,5 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res
headers["Sign"] = common.HexEncodeToString(hmac)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest(
"POST", apiPrivateURL, headers, strings.NewReader(encoded),
)
if err != nil {
return err
}
if y.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
response := Response{}
if err = common.JSONDecode([]byte(resp), &response); err != nil {
return errors.New("sendAuthenticatedHTTPRequest: Unable to JSON Unmarshal response." + err.Error())
}
if response.Success != 1 {
return errors.New(response.Error)
}
JSONEncoded, err := common.JSONEncode(response.Return)
if err != nil {
return err
}
return common.JSONDecode(JSONEncoded, &result)
return y.SendPayload("POST", apiPrivateURL, headers, strings.NewReader(encoded), result, true, y.Verbose)
}

View File

@@ -33,12 +33,14 @@ func TestSetup(t *testing.T) {
}
func TestGetFee(t *testing.T) {
t.Parallel()
if y.GetFee() != 0.2 {
t.Error("Test Failed - GetFee() error")
}
}
func TestGetInfo(t *testing.T) {
t.Parallel()
_, err := y.GetInfo()
if err != nil {
t.Error("Test Failed - GetInfo() error")
@@ -46,6 +48,7 @@ func TestGetInfo(t *testing.T) {
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := y.GetTicker("btc_usd")
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
@@ -53,6 +56,7 @@ func TestGetTicker(t *testing.T) {
}
func TestGetDepth(t *testing.T) {
t.Parallel()
_, err := y.GetDepth("btc_usd")
if err != nil {
t.Error("Test Failed - GetDepth() error", err)
@@ -60,6 +64,7 @@ func TestGetDepth(t *testing.T) {
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := y.GetTrades("btc_usd")
if err != nil {
t.Error("Test Failed - GetTrades() error", err)
@@ -67,6 +72,7 @@ func TestGetTrades(t *testing.T) {
}
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
_, err := y.GetAccountInfo()
if err == nil {
t.Error("Test Failed - GetAccountInfo() error", err)
@@ -74,6 +80,7 @@ func TestGetAccountInfo(t *testing.T) {
}
func TestGetActiveOrders(t *testing.T) {
t.Parallel()
_, err := y.GetActiveOrders("")
if err == nil {
t.Error("Test Failed - GetActiveOrders() error", err)
@@ -81,6 +88,7 @@ func TestGetActiveOrders(t *testing.T) {
}
func TestGetOrderInfo(t *testing.T) {
t.Parallel()
_, err := y.GetOrderInfo(6196974)
if err == nil {
t.Error("Test Failed - GetOrderInfo() error", err)
@@ -88,6 +96,7 @@ func TestGetOrderInfo(t *testing.T) {
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
_, err := y.CancelOrder(1337)
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
@@ -95,6 +104,7 @@ func TestCancelOrder(t *testing.T) {
}
func TestTrade(t *testing.T) {
t.Parallel()
_, err := y.Trade("", "buy", 0, 0)
if err == nil {
t.Error("Test Failed - Trade() error", err)
@@ -102,6 +112,7 @@ func TestTrade(t *testing.T) {
}
func TestGetTradeHistory(t *testing.T) {
t.Parallel()
_, err := y.GetTradeHistory(0, 0, 0, "", "", "", "")
if err == nil {
t.Error("Test Failed - GetTradeHistory() error", err)
@@ -109,6 +120,7 @@ func TestGetTradeHistory(t *testing.T) {
}
func TestWithdrawCoinsToAddress(t *testing.T) {
t.Parallel()
_, err := y.WithdrawCoinsToAddress("", 0, "")
if err == nil {
t.Error("Test Failed - WithdrawCoinsToAddress() error", err)
@@ -116,6 +128,7 @@ func TestWithdrawCoinsToAddress(t *testing.T) {
}
func TestGetDepositAddress(t *testing.T) {
t.Parallel()
_, err := y.GetDepositAddress("btc")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error", err)
@@ -123,6 +136,7 @@ func TestGetDepositAddress(t *testing.T) {
}
func TestCreateYobicode(t *testing.T) {
t.Parallel()
_, err := y.CreateCoupon("bla", 0)
if err == nil {
t.Error("Test Failed - CreateYobicode() error", err)
@@ -130,7 +144,8 @@ func TestCreateYobicode(t *testing.T) {
}
func TestRedeemYobicode(t *testing.T) {
_, err := y.RedeemCoupon("bla")
t.Parallel()
_, err := y.RedeemCoupon("bla2")
if err == nil {
t.Error("Test Failed - RedeemYobicode() error", err)
}

View File

@@ -73,6 +73,7 @@ type AccountInfo struct {
TransactionCount int `json:"transaction_count"`
OpenOrders int `json:"open_orders"`
ServerTime float64 `json:"server_time"`
Error string `json:"error"`
}
// OrderInfo stores order information
@@ -90,6 +91,7 @@ type OrderInfo struct {
type CancelOrder struct {
OrderID float64 `json:"order_id"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// Trade stores the trade information
@@ -98,6 +100,7 @@ type Trade struct {
Remains float64 `json:"remains"`
OrderID float64 `json:"order_id"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// TradeHistory stores trade history
@@ -116,11 +119,13 @@ type DepositAddress struct {
Address string `json:"address"`
ProcessedAmount float64 `json:"processed_amount"`
ServerTime int64 `json:"server_time"`
Error string `json:"error"`
}
// WithdrawCoinsToAddress stores information for a withdrawcoins request
type WithdrawCoinsToAddress struct {
ServerTime int64 `json:"server_time"`
ServerTime int64 `json:"server_time"`
Error string `json:"error"`
}
// CreateCoupon stores information coupon information
@@ -128,6 +133,7 @@ type CreateCoupon struct {
Coupon string `json:"coupon"`
TransID int64 `json:"transID"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}
// RedeemCoupon stores redeem coupon information
@@ -136,4 +142,5 @@ type RedeemCoupon struct {
CouponCurrency string `json:"couponCurrency"`
TransID int64 `json:"transID"`
Funds map[string]float64 `json:"funds"`
Error string `json:"error"`
}