Fixed minor linter issues in coinut. Fixed linter issues, increased code cov & expanded functionality in gdax. Added new function in nonce package.

This commit is contained in:
Ryan O'Hara-Reid
2017-08-31 16:01:28 +10:00
parent 3240a1657e
commit f27472269c
8 changed files with 1261 additions and 346 deletions

View File

@@ -15,31 +15,33 @@ import (
)
const (
COINUT_API_URL = "https://api.coinut.com"
COINUT_API_VERSION = "1"
COINUT_INSTRUMENTS = "inst_list"
COINUT_TICKER = "inst_tick"
COINUT_ORDERBOOK = "inst_order_book"
COINUT_TRADES = "inst_trade"
COINUT_BALANCE = "user_balance"
COINUT_ORDER = "new_order"
COINUT_ORDERS = "new_orders"
COINUT_ORDERS_OPEN = "user_open_orders"
COINUT_ORDER_CANCEL = "cancel_order"
COINUT_ORDERS_CANCEL = "cancel_orders"
COINUT_TRADE_HISTORY = "trade_history"
COINUT_INDEX_TICKER = "index_tick"
COINUT_OPTION_CHAIN = "option_chain"
COINUT_POSITION_HISTORY = "position_history"
COINUT_POSITION_OPEN = "user_open_positions"
coinutAPIURL = "https://api.coinut.com"
coinutAPIVersion = "1"
coinutInstruments = "inst_list"
coinutTicker = "inst_tick"
coinutOrderbook = "inst_order_book"
coinutTrades = "inst_trade"
coinutBalance = "user_balance"
coinutOrder = "new_order"
coinutOrders = "new_orders"
coinutOrdersOpen = "user_open_orders"
coinutOrderCancel = "cancel_order"
coinutOrdersCancel = "cancel_orders"
coinutTradeHistory = "trade_history"
coinutIndexTicker = "index_tick"
coinutOptionChain = "option_chain"
coinutPositionHistory = "position_history"
coinutPositionOpen = "user_open_positions"
)
// COINUT is the overarching type across the coinut package
type COINUT struct {
exchange.Base
WebsocketConn *websocket.Conn
InstrumentMap map[string]int
}
// SetDefaults sets current default values
func (c *COINUT) SetDefaults() {
c.Name = "COINUT"
c.Enabled = false
@@ -56,6 +58,7 @@ func (c *COINUT) SetDefaults() {
c.AssetTypes = []string{ticker.Spot}
}
// Setup sets the current exchange configuration
func (c *COINUT) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
c.SetEnabled(false)
@@ -80,11 +83,12 @@ func (c *COINUT) Setup(exch config.ExchangeConfig) {
}
}
// GetInstruments returns instruments
func (c *COINUT) GetInstruments() (CoinutInstruments, error) {
var result CoinutInstruments
params := make(map[string]interface{})
params["sec_type"] = "SPOT"
err := c.SendAuthenticatedHTTPRequest(COINUT_INSTRUMENTS, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutInstruments, params, &result)
if err != nil {
return result, err
}
@@ -95,7 +99,7 @@ func (c *COINUT) GetInstrumentTicker(instrumentID int) (CoinutTicker, error) {
var result CoinutTicker
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendAuthenticatedHTTPRequest(COINUT_TICKER, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutTicker, params, &result)
if err != nil {
return result, err
}
@@ -109,7 +113,7 @@ func (c *COINUT) GetInstrumentOrderbook(instrumentID, limit int) (CoinutOrderboo
if limit > 0 {
params["top_n"] = limit
}
err := c.SendAuthenticatedHTTPRequest(COINUT_ORDERBOOK, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutOrderbook, params, &result)
if err != nil {
return result, err
}
@@ -120,7 +124,7 @@ func (c *COINUT) GetTrades(instrumentID int) (CoinutTrades, error) {
var result CoinutTrades
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendAuthenticatedHTTPRequest(COINUT_TRADES, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutTrades, params, &result)
if err != nil {
return result, err
}
@@ -129,7 +133,7 @@ func (c *COINUT) GetTrades(instrumentID int) (CoinutTrades, error) {
func (c *COINUT) GetUserBalance() (CoinutUserBalance, error) {
result := CoinutUserBalance{}
err := c.SendAuthenticatedHTTPRequest(COINUT_BALANCE, nil, &result)
err := c.SendAuthenticatedHTTPRequest(coinutBalance, nil, &result)
if err != nil {
return result, err
}
@@ -148,7 +152,7 @@ func (c *COINUT) NewOrder(instrumentID int, quantity, price float64, buy bool, o
}
params["client_ord_id"] = orderID
err := c.SendAuthenticatedHTTPRequest(COINUT_ORDER, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutOrder, params, &result)
if err != nil {
return result, err
}
@@ -159,7 +163,7 @@ func (c *COINUT) NewOrders(orders []CoinutOrder) ([]CoinutOrdersBase, error) {
var result CoinutOrdersResponse
params := make(map[string]interface{})
params["orders"] = orders
err := c.SendAuthenticatedHTTPRequest(COINUT_ORDERS, params, &result.Data)
err := c.SendAuthenticatedHTTPRequest(coinutOrders, params, &result.Data)
if err != nil {
return nil, err
}
@@ -170,7 +174,7 @@ func (c *COINUT) GetOpenOrders(instrumentID int) ([]CoinutOrdersResponse, error)
var result []CoinutOrdersResponse
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendAuthenticatedHTTPRequest(COINUT_ORDERS_OPEN, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutOrdersOpen, params, &result)
if err != nil {
return nil, err
}
@@ -182,7 +186,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.SendAuthenticatedHTTPRequest(COINUT_ORDERS_CANCEL, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutOrdersCancel, params, &result)
if err != nil {
return false, err
}
@@ -193,7 +197,7 @@ func (c *COINUT) CancelOrders(orders []CoinutCancelOrders) (CoinutCancelOrdersRe
var result CoinutCancelOrdersResponse
params := make(map[string]interface{})
params["entries"] = orders
err := c.SendAuthenticatedHTTPRequest(COINUT_ORDERS_CANCEL, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutOrdersCancel, params, &result)
if err != nil {
return result, err
}
@@ -210,7 +214,7 @@ func (c *COINUT) GetTradeHistory(instrumentID, start, limit int) (CoinutTradeHis
if limit >= 0 && start <= 100 {
params["limit"] = limit
}
err := c.SendAuthenticatedHTTPRequest(COINUT_TRADE_HISTORY, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutTradeHistory, params, &result)
if err != nil {
return result, err
}
@@ -221,7 +225,7 @@ func (c *COINUT) GetIndexTicker(asset string) (CoinutIndexTicker, error) {
var result CoinutIndexTicker
params := make(map[string]interface{})
params["asset"] = asset
err := c.SendAuthenticatedHTTPRequest(COINUT_INDEX_TICKER, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutIndexTicker, params, &result)
if err != nil {
return result, err
}
@@ -232,7 +236,7 @@ func (c *COINUT) GetDerivativeInstruments(secType string) (interface{}, error) {
var result interface{} //to-do
params := make(map[string]interface{})
params["sec_type"] = secType
err := c.SendAuthenticatedHTTPRequest(COINUT_INSTRUMENTS, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutInstruments, params, &result)
if err != nil {
return result, err
}
@@ -244,7 +248,7 @@ func (c *COINUT) GetOptionChain(asset, secType string, expiry int64) (CoinutOpti
params := make(map[string]interface{})
params["asset"] = asset
params["sec_type"] = secType
err := c.SendAuthenticatedHTTPRequest(COINUT_OPTION_CHAIN, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutOptionChain, params, &result)
if err != nil {
return result, err
}
@@ -261,7 +265,7 @@ func (c *COINUT) GetPositionHistory(secType string, start, limit int) (CoinutPos
if limit >= 0 {
params["limit"] = limit
}
err := c.SendAuthenticatedHTTPRequest(COINUT_POSITION_HISTORY, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutPositionHistory, params, &result)
if err != nil {
return result, err
}
@@ -276,7 +280,7 @@ func (c *COINUT) GetOpenPosition(instrumentID int) ([]CoinutOpenPosition, error)
params := make(map[string]interface{})
params["inst_id"] = instrumentID
err := c.SendAuthenticatedHTTPRequest(COINUT_POSITION_OPEN, params, &result)
err := c.SendAuthenticatedHTTPRequest(coinutPositionOpen, params, &result)
if err != nil {
return result.Positions, err
}
@@ -319,7 +323,10 @@ func (c *COINUT) SendAuthenticatedHTTPRequest(apiRequest string, params map[stri
headers["X-SIGNATURE"] = common.HexEncodeToString(hmac)
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest("POST", COINUT_API_URL, headers, bytes.NewBuffer(payload))
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)

View File

@@ -0,0 +1,37 @@
package coinut
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
const (
apiKey = ""
apiSecret = ""
)
var c COINUT
func TestSetDefaults(t *testing.T) {
c.SetDefaults()
}
func TestSetup(t *testing.T) {
exch := config.ExchangeConfig{}
c.Setup(exch)
exch.Enabled = true
exch.APIKey = apiKey
exch.APISecret = apiSecret
c.Setup(exch)
}
// func TestGetInstruments(t *testing.T) {
// c.Verbose = true
// resp, err := c.GetInstruments()
// if err == nil {
// t.Error("Test failed - GetInstruments() error", err)
// }
// log.Println(resp)
// }

View File

@@ -7,7 +7,6 @@ import (
"log"
"net/url"
"strconv"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
@@ -16,28 +15,46 @@ import (
)
const (
GDAX_API_URL = "https://api.gdax.com/"
GDAX_API_VERSION = "0"
GDAX_PRODUCTS = "products"
GDAX_ORDERBOOK = "book"
GDAX_TICKER = "ticker"
GDAX_TRADES = "trades"
GDAX_HISTORY = "candles"
GDAX_STATS = "stats"
GDAX_CURRENCIES = "currencies"
GDAX_ACCOUNTS = "accounts"
GDAX_LEDGER = "ledger"
GDAX_HOLDS = "holds"
GDAX_ORDERS = "orders"
GDAX_FILLS = "fills"
GDAX_TRANSFERS = "transfers"
GDAX_REPORTS = "reports"
gdaxAPIURL = "https://api.gdax.com/"
gdaxAPIVersion = "0"
gdaxProducts = "products"
gdaxOrderbook = "book"
gdaxTicker = "ticker"
gdaxTrades = "trades"
gdaxHistory = "candles"
gdaxStats = "stats"
gdaxCurrencies = "currencies"
gdaxAccounts = "accounts"
gdaxLedger = "ledger"
gdaxHolds = "holds"
gdaxOrders = "orders"
gdaxFills = "fills"
gdaxTransfers = "transfers"
gdaxReports = "reports"
gdaxTime = "time"
gdaxMarginTransfer = "profiles/margin-transfer"
gdaxFunding = "funding"
gdaxFundingRepay = "funding/repay"
gdaxPosition = "position"
gdaxPositionClose = "position/close"
gdaxPaymentMethod = "payment-methods"
gdaxPaymentMethodDeposit = "deposits/payment-method"
gdaxDepositCoinbase = "deposits/coinbase-account"
gdaxWithdrawalPaymentMethod = "withdrawals/payment-method"
gdaxWithdrawalCoinbase = "withdrawals/coinbase"
gdaxWithdrawalCrypto = "withdrawals/crypto"
gdaxCoinbaseAccounts = "coinbase-accounts"
gdaxTrailingVolume = "users/self/trailing-volume"
)
var sometin []string
// GDAX is the overarching type across the GDAX package
type GDAX struct {
exchange.Base
}
// SetDefaults sets default values for the exchange
func (g *GDAX) SetDefaults() {
g.Name = "GDAX"
g.Enabled = false
@@ -54,6 +71,7 @@ func (g *GDAX) SetDefaults() {
g.AssetTypes = []string{ticker.Spot}
}
// Setup initialises the exchange paramaters with the current configuration
func (g *GDAX) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
g.SetEnabled(false)
@@ -78,42 +96,39 @@ func (g *GDAX) Setup(exch config.ExchangeConfig) {
}
}
// GetFee returns the current fee for the exchange
func (g *GDAX) GetFee(maker bool) float64 {
if maker {
return g.MakerFee
} else {
return g.TakerFee
}
return g.TakerFee
}
func (g *GDAX) GetProducts() ([]GDAXProduct, error) {
products := []GDAXProduct{}
err := common.SendHTTPGetRequest(GDAX_API_URL+GDAX_PRODUCTS, true, &products)
// GetProducts returns supported currency pairs on the exchange with specific
// information about the pair
func (g *GDAX) GetProducts() ([]Product, error) {
products := []Product{}
if err != nil {
return nil, err
}
return products, nil
return products,
common.SendHTTPGetRequest(gdaxAPIURL+gdaxProducts, true, &products)
}
// GetOrderbook returns orderbook by currency pair and level
func (g *GDAX) GetOrderbook(symbol string, level int) (interface{}, error) {
orderbook := GDAXOrderbookResponse{}
path := ""
orderbook := OrderbookResponse{}
path := fmt.Sprintf("%s/%s/%s", gdaxAPIURL+gdaxProducts, symbol, gdaxOrderbook)
if level > 0 {
levelStr := strconv.Itoa(level)
path = fmt.Sprintf("%s/%s/%s?level=%s", GDAX_API_URL+GDAX_PRODUCTS, symbol, GDAX_ORDERBOOK, levelStr)
} else {
path = fmt.Sprintf("%s/%s/%s", GDAX_API_URL+GDAX_PRODUCTS, symbol, GDAX_ORDERBOOK)
path = fmt.Sprintf("%s/%s/%s?level=%s", gdaxAPIURL+gdaxProducts, symbol, gdaxOrderbook, levelStr)
}
err := common.SendHTTPGetRequest(path, true, &orderbook)
if err != nil {
if err := common.SendHTTPGetRequest(path, true, &orderbook); err != nil {
return nil, err
}
if level == 3 {
ob := GDAXOrderbookL3{}
ob := OrderbookL3{}
ob.Sequence = orderbook.Sequence
for _, x := range orderbook.Asks {
price, err := strconv.ParseFloat((x[0].(string)), 64)
@@ -125,7 +140,7 @@ func (g *GDAX) GetOrderbook(symbol string, level int) (interface{}, error) {
continue
}
ob.Asks = append(ob.Asks, GDAXOrderL3{Price: price, Amount: amount, OrderID: x[2].(string)})
ob.Asks = append(ob.Asks, OrderL3{Price: price, Amount: amount, OrderID: x[2].(string)})
}
for _, x := range orderbook.Bids {
price, err := strconv.ParseFloat((x[0].(string)), 64)
@@ -137,64 +152,65 @@ func (g *GDAX) GetOrderbook(symbol string, level int) (interface{}, error) {
continue
}
ob.Bids = append(ob.Bids, GDAXOrderL3{Price: price, Amount: amount, OrderID: x[2].(string)})
}
return ob, nil
} else {
ob := GDAXOrderbookL1L2{}
ob.Sequence = orderbook.Sequence
for _, x := range orderbook.Asks {
price, err := strconv.ParseFloat((x[0].(string)), 64)
if err != nil {
continue
}
amount, err := strconv.ParseFloat((x[1].(string)), 64)
if err != nil {
continue
}
ob.Asks = append(ob.Asks, GDAXOrderL1L2{Price: price, Amount: amount, NumOrders: x[2].(float64)})
}
for _, x := range orderbook.Bids {
price, err := strconv.ParseFloat((x[0].(string)), 64)
if err != nil {
continue
}
amount, err := strconv.ParseFloat((x[1].(string)), 64)
if err != nil {
continue
}
ob.Bids = append(ob.Bids, GDAXOrderL1L2{Price: price, Amount: amount, NumOrders: x[2].(float64)})
ob.Bids = append(ob.Bids, OrderL3{Price: price, Amount: amount, OrderID: x[2].(string)})
}
return ob, nil
}
}
ob := OrderbookL1L2{}
ob.Sequence = orderbook.Sequence
for _, x := range orderbook.Asks {
price, err := strconv.ParseFloat((x[0].(string)), 64)
if err != nil {
continue
}
amount, err := strconv.ParseFloat((x[1].(string)), 64)
if err != nil {
continue
}
func (g *GDAX) GetTicker(symbol string) (GDAXTicker, error) {
ticker := GDAXTicker{}
path := fmt.Sprintf("%s/%s/%s", GDAX_API_URL+GDAX_PRODUCTS, symbol, GDAX_TICKER)
err := common.SendHTTPGetRequest(path, true, &ticker)
if err != nil {
return ticker, err
ob.Asks = append(ob.Asks, OrderL1L2{Price: price, Amount: amount, NumOrders: x[2].(float64)})
}
return ticker, nil
}
for _, x := range orderbook.Bids {
price, err := strconv.ParseFloat((x[0].(string)), 64)
if err != nil {
continue
}
amount, err := strconv.ParseFloat((x[1].(string)), 64)
if err != nil {
continue
}
func (g *GDAX) GetTrades(symbol string) ([]GDAXTrade, error) {
trades := []GDAXTrade{}
path := fmt.Sprintf("%s/%s/%s", GDAX_API_URL+GDAX_PRODUCTS, symbol, GDAX_TRADES)
err := common.SendHTTPGetRequest(path, true, &trades)
if err != nil {
return nil, err
ob.Bids = append(ob.Bids, OrderL1L2{Price: price, Amount: amount, NumOrders: x[2].(float64)})
}
return trades, nil
return ob, nil
}
func (g *GDAX) GetHistoricRates(symbol string, start, end, granularity int64) ([]GDAXHistory, error) {
history := []GDAXHistory{}
// GetTicker returns ticker by currency pair
// currencyPair - example "BTC-USD"
func (g *GDAX) GetTicker(currencyPair string) (Ticker, error) {
ticker := Ticker{}
path := fmt.Sprintf(
"%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxTicker)
log.Println(path)
return ticker, common.SendHTTPGetRequest(path, true, &ticker)
}
// GetTrades listd the latest trades for a product
// currencyPair - example "BTC-USD"
func (g *GDAX) GetTrades(currencyPair string) ([]Trade, error) {
trades := []Trade{}
path := fmt.Sprintf(
"%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxTrades)
return trades, common.SendHTTPGetRequest(path, true, &trades)
}
// GetHistoricRates returns historic rates for a product. Rates are returned in
// grouped buckets based on requested granularity.
func (g *GDAX) GetHistoricRates(currencyPair string, start, end, granularity int64) ([]History, error) {
var resp [][]interface{}
history := []History{}
values := url.Values{}
if start > 0 {
@@ -209,97 +225,137 @@ func (g *GDAX) GetHistoricRates(symbol string, start, end, granularity int64) ([
values.Set("granularity", strconv.FormatInt(granularity, 10))
}
path := common.EncodeURLValues(fmt.Sprintf("%s/%s/%s", GDAX_API_URL+GDAX_PRODUCTS, symbol, GDAX_HISTORY), values)
err := common.SendHTTPGetRequest(path, true, &history)
path := common.EncodeURLValues(
fmt.Sprintf("%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxHistory),
values)
if err != nil {
return nil, err
if err := common.SendHTTPGetRequest(path, true, &resp); err != nil {
return history, err
}
for _, single := range resp {
s := History{
Time: int64(single[0].(float64)),
Low: single[1].(float64),
High: single[2].(float64),
Open: single[3].(float64),
Close: single[4].(float64),
Volume: single[5].(float64),
}
history = append(history, s)
}
return history, nil
}
func (g *GDAX) GetStats(symbol string) (GDAXStats, error) {
stats := GDAXStats{}
path := fmt.Sprintf("%s/%s/%s", GDAX_API_URL+GDAX_PRODUCTS, symbol, GDAX_STATS)
err := common.SendHTTPGetRequest(path, true, &stats)
// GetStats returns a 24 hr stat for the product. Volume is in base currency
// units. open, high, low are in quote currency units.
func (g *GDAX) GetStats(currencyPair string) (Stats, error) {
stats := Stats{}
path := fmt.Sprintf(
"%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxStats)
if err != nil {
return stats, err
}
return stats, nil
return stats, common.SendHTTPGetRequest(path, true, &stats)
}
func (g *GDAX) GetCurrencies() ([]GDAXCurrency, error) {
currencies := []GDAXCurrency{}
err := common.SendHTTPGetRequest(GDAX_API_URL+GDAX_CURRENCIES, true, &currencies)
// GetCurrencies returns a list of supported currency on the exchange
// Warning: Not all currencies may be currently in use for trading.
func (g *GDAX) GetCurrencies() ([]Currency, error) {
currencies := []Currency{}
if err != nil {
return nil, err
}
return currencies, nil
return currencies,
common.SendHTTPGetRequest(gdaxAPIURL+gdaxCurrencies, true, &currencies)
}
func (g *GDAX) GetAccounts() ([]GDAXAccountResponse, error) {
resp := []GDAXAccountResponse{}
err := g.SendAuthenticatedHTTPRequest("GET", GDAX_ACCOUNTS, nil, &resp)
if err != nil {
return nil, err
}
return resp, nil
// GetServerTime returns the API server time
func (g *GDAX) GetServerTime() (ServerTime, error) {
serverTime := ServerTime{}
return serverTime,
common.SendHTTPGetRequest(gdaxAPIURL+gdaxTime, true, &serverTime)
}
func (g *GDAX) GetAccount(account string) (GDAXAccountResponse, error) {
resp := GDAXAccountResponse{}
path := fmt.Sprintf("%s/%s", GDAX_ACCOUNTS, account)
err := g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
}
return resp, nil
// GetAccounts returns a list of trading accounts associated with the APIKEYS
func (g *GDAX) GetAccounts() ([]AccountResponse, error) {
resp := []AccountResponse{}
return resp,
g.SendAuthenticatedHTTPRequest("GET", gdaxAccounts, nil, &resp)
}
func (g *GDAX) GetAccountHistory(accountID string) ([]GDAXAccountLedgerResponse, error) {
resp := []GDAXAccountLedgerResponse{}
path := fmt.Sprintf("%s/%s/%s", GDAX_ACCOUNTS, accountID, GDAX_LEDGER)
err := g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return nil, err
}
return resp, nil
// GetAccount returns information for a single account. Use this endpoint when
// account_id is known
func (g *GDAX) GetAccount(accountID string) (AccountResponse, error) {
resp := AccountResponse{}
path := fmt.Sprintf("%s/%s", gdaxAccounts, accountID)
return resp, g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (g *GDAX) GetHolds(accountID string) ([]GDAXAccountHolds, error) {
resp := []GDAXAccountHolds{}
path := fmt.Sprintf("%s/%s/%s", GDAX_ACCOUNTS, accountID, GDAX_HOLDS)
err := g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return nil, err
}
return resp, nil
// GetAccountHistory returns a list of account activity. Account activity either
// increases or decreases your account balance. Items are paginated and sorted
// latest first.
func (g *GDAX) GetAccountHistory(accountID string) ([]AccountLedgerResponse, error) {
resp := []AccountLedgerResponse{}
path := fmt.Sprintf("%s/%s/%s", gdaxAccounts, accountID, gdaxLedger)
return resp, g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (g *GDAX) PlaceOrder(clientRef string, price, amount float64, side string, productID, stp string) (string, error) {
// GetHolds returns the holds that are placed on an account for any active
// orders or pending withdraw requests. As an order is filled, the hold amount
// is updated. If an order is canceled, any remaining hold is removed. For a
// withdraw, once it is completed, the hold is removed.
func (g *GDAX) GetHolds(accountID string) ([]AccountHolds, error) {
resp := []AccountHolds{}
path := fmt.Sprintf("%s/%s/%s", gdaxAccounts, accountID, gdaxHolds)
return resp, g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
// PlaceLimitOrder places a new limit order. Orders can only be placed if the
// account has sufficient funds. Once an order is placed, account funds
// will be put on hold for the duration of the order. How much and which funds
// are put on hold depends on the order type and parameters specified.
//
// GENERAL PARAMS
// clientRef - [optional] Order ID selected by you to identify your order
// side - buy or sell
// productID - A valid product id
// stp - [optional] Self-trade prevention flag
//
// LIMIT ORDER PARAMS
// price - Price per bitcoin
// amount - Amount of BTC to buy or sell
// timeInforce - [optional] GTC, GTT, IOC, or FOK (default is GTC)
// cancelAfter - [optional] min, hour, day * Requires time_in_force to be GTT
// postOnly - [optional] Post only flag Invalid when time_in_force is IOC or FOK
func (g *GDAX) PlaceLimitOrder(clientRef string, price, amount float64, side, timeInforce, cancelAfter, productID, stp string, postOnly bool) (string, error) {
resp := GeneralizedOrderResponse{}
request := make(map[string]interface{})
if clientRef != "" {
request["client_oid"] = clientRef
}
request["type"] = "limit"
request["price"] = strconv.FormatFloat(price, 'f', -1, 64)
request["size"] = strconv.FormatFloat(amount, 'f', -1, 64)
request["side"] = side
request["product_id"] = productID
if cancelAfter != "" {
request["cancel_after"] = cancelAfter
}
if timeInforce != "" {
request["time_in_foce"] = timeInforce
}
if clientRef != "" {
request["client_oid"] = clientRef
}
if stp != "" {
request["stp"] = stp
}
type OrderResponse struct {
ID string `json:"id"`
if postOnly {
request["post_only"] = postOnly
}
resp := OrderResponse{}
err := g.SendAuthenticatedHTTPRequest("POST", GDAX_ORDERS, request, &resp)
err := g.SendAuthenticatedHTTPRequest("POST", gdaxOrders, request, &resp)
if err != nil {
return "", err
}
@@ -307,98 +363,406 @@ func (g *GDAX) PlaceOrder(clientRef string, price, amount float64, side string,
return resp.ID, nil
}
// PlaceMarketOrder places a new market order.
// Orders can only be placed if the account has sufficient funds. Once an order
// is placed, account funds will be put on hold for the duration of the order.
// How much and which funds are put on hold depends on the order type and
// parameters specified.
//
// GENERAL PARAMS
// clientRef - [optional] Order ID selected by you to identify your order
// side - buy or sell
// productID - A valid product id
// stp - [optional] Self-trade prevention flag
//
// MARKET ORDER PARAMS
// size - [optional]* Desired amount in BTC
// funds [optional]* Desired amount of quote currency to use
// * One of size or funds is required.
func (g *GDAX) PlaceMarketOrder(clientRef string, size, funds float64, side string, productID, stp string) (string, error) {
resp := GeneralizedOrderResponse{}
request := make(map[string]interface{})
request["side"] = side
request["product_id"] = productID
request["type"] = "market"
if size != 0 {
request["size"] = strconv.FormatFloat(size, 'f', -1, 64)
}
if funds != 0 {
request["funds"] = strconv.FormatFloat(funds, 'f', -1, 64)
}
if clientRef != "" {
request["client_oid"] = clientRef
}
if stp != "" {
request["stp"] = stp
}
err := g.SendAuthenticatedHTTPRequest("POST", gdaxOrders, request, &resp)
if err != nil {
return "", err
}
return resp.ID, nil
}
// PlaceMarginOrder places a new market order.
// Orders can only be placed if the account has sufficient funds. Once an order
// is placed, account funds will be put on hold for the duration of the order.
// How much and which funds are put on hold depends on the order type and
// parameters specified.
//
// GENERAL PARAMS
// clientRef - [optional] Order ID selected by you to identify your order
// side - buy or sell
// productID - A valid product id
// stp - [optional] Self-trade prevention flag
//
// MARGIN ORDER PARAMS
// size - [optional]* Desired amount in BTC
// funds - [optional]* Desired amount of quote currency to use
func (g *GDAX) PlaceMarginOrder(clientRef string, size, funds float64, side string, productID, stp string) (string, error) {
resp := GeneralizedOrderResponse{}
request := make(map[string]interface{})
request["side"] = side
request["product_id"] = productID
request["type"] = "margin"
if size != 0 {
request["size"] = strconv.FormatFloat(size, 'f', -1, 64)
}
if funds != 0 {
request["funds"] = strconv.FormatFloat(funds, 'f', -1, 64)
}
if clientRef != "" {
request["client_oid"] = clientRef
}
if stp != "" {
request["stp"] = stp
}
err := g.SendAuthenticatedHTTPRequest("POST", gdaxOrders, request, &resp)
if err != nil {
return "", err
}
return resp.ID, nil
}
// CancelOrder cancels order by orderID
func (g *GDAX) CancelOrder(orderID string) error {
path := fmt.Sprintf("%s/%s", GDAX_ORDERS, orderID)
err := g.SendAuthenticatedHTTPRequest("DELETE", path, nil, nil)
if err != nil {
return err
}
return nil
path := fmt.Sprintf("%s/%s", gdaxOrders, orderID)
return g.SendAuthenticatedHTTPRequest("DELETE", path, nil, nil)
}
func (g *GDAX) GetOrders(params url.Values) ([]GDAXOrdersResponse, error) {
path := common.EncodeURLValues(GDAX_API_URL+GDAX_ORDERS, params)
resp := []GDAXOrdersResponse{}
err := g.SendAuthenticatedHTTPRequest("GET", common.GetURIPath(path), nil, &resp)
if err != nil {
return nil, err
// CancelAllOrders cancels all open orders on the exchange and returns and array
// of order IDs
// currencyPair - [optional] all orders for a currencyPair string will be
// canceled
func (g *GDAX) CancelAllOrders(currencyPair string) ([]string, error) {
var resp []string
request := make(map[string]interface{})
if len(currencyPair) != 0 {
request["product_id"] = currencyPair
}
return resp, nil
return resp, g.SendAuthenticatedHTTPRequest("DELETE", gdaxOrders, request, &resp)
}
func (g *GDAX) GetOrder(orderID string) (GDAXOrderResponse, error) {
path := fmt.Sprintf("%s/%s", GDAX_ORDERS, orderID)
resp := GDAXOrderResponse{}
err := g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
if err != nil {
return resp, err
// GetOrders lists current open orders. Only open or un-settled orders are
// returned. As soon as an order is no longer open and settled, it will no
// longer appear in the default request.
// status - can be a range of "open", "pending", "done" or "active"
// currencyPair - [optional] for example "BTC-USD"
func (g *GDAX) GetOrders(status []string, currencyPair string) ([]GeneralizedOrderResponse, error) {
resp := []GeneralizedOrderResponse{}
params := url.Values{}
for _, individualStatus := range status {
params.Add("status", individualStatus)
}
return resp, nil
if len(currencyPair) != 0 {
params.Set("product_id", currencyPair)
}
path := common.EncodeURLValues(gdaxAPIURL+gdaxOrders, params)
path = common.GetURIPath(path)
return resp,
g.SendAuthenticatedHTTPRequest("GET", path[1:], nil, &resp)
}
func (g *GDAX) GetFills(params url.Values) ([]GDAXFillResponse, error) {
path := common.EncodeURLValues(GDAX_API_URL+GDAX_FILLS, params)
resp := []GDAXFillResponse{}
err := g.SendAuthenticatedHTTPRequest("GET", common.GetURIPath(path), nil, &resp)
if err != nil {
return nil, err
}
return resp, nil
// GetOrder returns a single order by order id.
func (g *GDAX) GetOrder(orderID string) (GeneralizedOrderResponse, error) {
resp := GeneralizedOrderResponse{}
path := fmt.Sprintf("%s/%s", gdaxOrders, orderID)
return resp, g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
func (g *GDAX) Transfer(transferType string, amount float64, accountID string) error {
// GetFills returns a list of recent fills
func (g *GDAX) GetFills(orderID, currencyPair string) ([]FillResponse, error) {
resp := []FillResponse{}
params := url.Values{}
if len(orderID) != 0 {
params.Set("order_id", orderID)
}
if len(currencyPair) != 0 {
params.Set("product_id", currencyPair)
}
if len(params.Get("order_id")) == 0 && len(params.Get("product_id")) == 0 {
return resp, errors.New("no paramaters set")
}
path := common.EncodeURLValues(gdaxAPIURL+gdaxFills, params)
uri := common.GetURIPath(path)
return resp,
g.SendAuthenticatedHTTPRequest("GET", uri[1:], nil, &resp)
}
// GetFundingRecords every order placed with a margin profile that draws funding
// will create a funding record.
//
// status - "outstanding", "settled", or "rejected"
func (g *GDAX) GetFundingRecords(status string) ([]Funding, error) {
resp := []Funding{}
params := url.Values{}
params.Set("status", status)
path := common.EncodeURLValues(gdaxAPIURL+gdaxFunding, params)
uri := common.GetURIPath(path)
return resp,
g.SendAuthenticatedHTTPRequest("GET", uri[1:], nil, &resp)
}
////////////////////////// Not receiving reply from server /////////////////
// RepayFunding repays the older funding records first
//
// amount - amount of currency to repay
// currency - currency, example USD
// func (g *GDAX) RepayFunding(amount, currency string) (Funding, error) {
// resp := Funding{}
// params := make(map[string]interface{})
// params["amount"] = amount
// params["currency"] = currency
//
// return resp,
// g.SendAuthenticatedHTTPRequest("POST", gdaxFundingRepay, params, &resp)
// }
// MarginTransfer sends funds between a standard/default profile and a margin
// profile.
// A deposit will transfer funds from the default profile into the margin
// profile. A withdraw will transfer funds from the margin profile to the
// default profile. Withdraws will fail if they would set your margin ratio
// below the initial margin ratio requirement.
//
// amount - the amount to transfer between the default and margin profile
// transferType - either "deposit" or "withdraw"
// profileID - The id of the margin profile to deposit or withdraw from
// currency - currency to transfer, currently on "BTC" or "USD"
func (g *GDAX) MarginTransfer(amount float64, transferType, profileID, currency string) (MarginTransfer, error) {
resp := MarginTransfer{}
request := make(map[string]interface{})
request["type"] = transferType
request["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
request["GDAX_account_id"] = accountID
request["currency"] = currency
request["margin_profile_id"] = profileID
err := g.SendAuthenticatedHTTPRequest("POST", GDAX_TRANSFERS, request, nil)
if err != nil {
return err
}
return nil
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxMarginTransfer, request, &resp)
}
func (g *GDAX) GetReport(reportType, startDate, endDate string) (GDAXReportResponse, error) {
// GetPosition returns an overview of account profile.
func (g *GDAX) GetPosition() (AccountOverview, error) {
resp := AccountOverview{}
return resp,
g.SendAuthenticatedHTTPRequest("GET", gdaxPosition, nil, &resp)
}
// ClosePosition closes a position and allowing you to repay position as well
// repayOnly - allows the position to be repaid
func (g *GDAX) ClosePosition(repayOnly bool) (AccountOverview, error) {
resp := AccountOverview{}
request := make(map[string]interface{})
request["repay_only"] = repayOnly
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxPositionClose, request, &resp)
}
// GetPayMethods returns a full list of payment methods
func (g *GDAX) GetPayMethods() ([]PaymentMethod, error) {
resp := []PaymentMethod{}
return resp,
g.SendAuthenticatedHTTPRequest("GET", gdaxPaymentMethod, nil, &resp)
}
// DepositViaPaymentMethod deposits funds from a payment method. See the Payment
// Methods section for retrieving your payment methods.
//
// amount - The amount to deposit
// currency - The type of currency
// paymentID - ID of the payment method
func (g *GDAX) DepositViaPaymentMethod(amount float64, currency, paymentID string) (DepositWithdrawalInfo, error) {
resp := DepositWithdrawalInfo{}
req := make(map[string]interface{})
req["amount"] = amount
req["currency"] = currency
req["payment_method_id"] = paymentID
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxPaymentMethodDeposit, req, &resp)
}
// DepositViaCoinbase deposits funds from a coinbase account. Move funds between
// a Coinbase account and GDAX trading account within daily limits. Moving
// funds between Coinbase and GDAX is instant and free. See the Coinbase
// Accounts section for retrieving your Coinbase accounts.
//
// amount - The amount to deposit
// currency - The type of currency
// accountID - ID of the coinbase account
func (g *GDAX) DepositViaCoinbase(amount float64, currency, accountID string) (DepositWithdrawalInfo, error) {
resp := DepositWithdrawalInfo{}
req := make(map[string]interface{})
req["amount"] = amount
req["currency"] = currency
req["coinbase_account_id"] = accountID
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxDepositCoinbase, req, &resp)
}
// WithdrawViaPaymentMethod withdraws funds to a payment method
//
// amount - The amount to withdraw
// currency - The type of currency
// paymentID - ID of the payment method
func (g *GDAX) WithdrawViaPaymentMethod(amount float64, currency, paymentID string) (DepositWithdrawalInfo, error) {
resp := DepositWithdrawalInfo{}
req := make(map[string]interface{})
req["amount"] = amount
req["currency"] = currency
req["payment_method_id"] = paymentID
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxWithdrawalPaymentMethod, req, &resp)
}
///////////////////////// NO ROUTE FOUND ERROR ////////////////////////////////
// WithdrawViaCoinbase withdraws funds to a coinbase account.
//
// amount - The amount to withdraw
// currency - The type of currency
// accountID - ID of the coinbase account
// func (g *GDAX) WithdrawViaCoinbase(amount float64, currency, accountID string) (DepositWithdrawalInfo, error) {
// resp := DepositWithdrawalInfo{}
// req := make(map[string]interface{})
// req["amount"] = amount
// req["currency"] = currency
// req["coinbase_account_id"] = accountID
//
// return resp,
// g.SendAuthenticatedHTTPRequest("POST", gdaxWithdrawalCoinbase, req, &resp)
// }
// WithdrawCrypto withdraws funds to a crypto address
//
// amount - The amount to withdraw
// currency - The type of currency
// cryptoAddress - A crypto address of the recipient
func (g *GDAX) WithdrawCrypto(amount float64, currency, cryptoAddress string) (DepositWithdrawalInfo, error) {
resp := DepositWithdrawalInfo{}
req := make(map[string]interface{})
req["amount"] = amount
req["currency"] = currency
req["crypto_address"] = cryptoAddress
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxWithdrawalCrypto, req, &resp)
}
// GetCoinbaseAccounts returns a list of coinbase accounts
func (g *GDAX) GetCoinbaseAccounts() ([]CoinbaseAccounts, error) {
resp := []CoinbaseAccounts{}
return resp,
g.SendAuthenticatedHTTPRequest("GET", gdaxCoinbaseAccounts, nil, &resp)
}
// GetReport returns batches of historic information about your account in
// various human and machine readable forms.
//
// reportType - "fills" or "account"
// startDate - Starting date for the report (inclusive)
// endDate - Ending date for the report (inclusive)
// currencyPair - ID of the product to generate a fills report for.
// E.g. BTC-USD. *Required* if type is fills
// accountID - ID of the account to generate an account report for. *Required*
// if type is account
// format - pdf or csv (defualt is pdf)
// email - [optional] Email address to send the report to
func (g *GDAX) GetReport(reportType, startDate, endDate, currencyPair, accountID, format, email string) (Report, error) {
resp := Report{}
request := make(map[string]interface{})
request["type"] = reportType
request["start_date"] = startDate
request["end_date"] = endDate
request["format"] = "pdf"
resp := GDAXReportResponse{}
err := g.SendAuthenticatedHTTPRequest("POST", GDAX_REPORTS, request, &resp)
if err != nil {
return resp, err
if len(currencyPair) != 0 {
request["product_id"] = currencyPair
}
return resp, nil
if len(accountID) != 0 {
request["account_id"] = accountID
}
if format == "csv" {
request["format"] = format
}
if len(email) != 0 {
request["email"] = email
}
return resp,
g.SendAuthenticatedHTTPRequest("POST", gdaxReports, request, &resp)
}
func (g *GDAX) GetReportStatus(reportID string) (GDAXReportResponse, error) {
path := fmt.Sprintf("%s/%s", GDAX_REPORTS, reportID)
resp := GDAXReportResponse{}
err := g.SendAuthenticatedHTTPRequest("POST", path, nil, &resp)
if err != nil {
return resp, err
}
return resp, nil
// GetReportStatus once a report request has been accepted for processing, the
// status is available by polling the report resource endpoint.
func (g *GDAX) GetReportStatus(reportID string) (Report, error) {
resp := Report{}
path := fmt.Sprintf("%s/%s", gdaxReports, reportID)
return resp, g.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
}
// GetTrailingVolume this request will return your 30-day trailing volume for
// all products.
func (g *GDAX) GetTrailingVolume() ([]Volume, error) {
resp := []Volume{}
return resp,
g.SendAuthenticatedHTTPRequest("GET", gdaxTrailingVolume, nil, &resp)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP reque
func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) (err error) {
if !g.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, g.Name)
}
if g.Nonce.Get() == 0 {
g.Nonce.Set(time.Now().Unix())
} else {
g.Nonce.Inc()
}
payload := []byte("")
if params != nil {
payload, err = common.JSONEncode(params)
if err != nil {
return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request")
}
@@ -408,26 +772,34 @@ func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[stri
}
}
message := g.Nonce.String() + method + "/" + path + string(payload)
nonce := g.Nonce.Evaluate()
message := nonce + method + "/" + path + string(payload)
hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(g.APISecret))
headers := make(map[string]string)
headers["CB-ACCESS-SIGN"] = common.Base64Encode([]byte(hmac))
headers["CB-ACCESS-TIMESTAMP"] = g.Nonce.String()
headers["CB-ACCESS-TIMESTAMP"] = nonce
headers["CB-ACCESS-KEY"] = g.APIKey
headers["CB-ACCESS-PASSPHRASE"] = g.ClientID
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest(method, GDAX_API_URL+path, headers, bytes.NewBuffer(payload))
resp, err := common.SendHTTPRequest(method, gdaxAPIURL+path, headers, bytes.NewBuffer(payload))
if err != nil {
return err
}
if g.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
err = common.JSONDecode([]byte(resp), &result)
type initialResponse struct {
Message string `json:"message"`
}
initialCheck := initialResponse{}
if err != nil {
return errors.New("unable to JSON Unmarshal response")
err = common.JSONDecode([]byte(resp), &initialCheck)
if err == nil && len(initialCheck.Message) != 0 {
return errors.New(initialCheck.Message)
}
return nil
return common.JSONDecode([]byte(resp), &result)
}

300
exchanges/gdax/gdax_test.go Normal file
View File

@@ -0,0 +1,300 @@
package gdax
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var g GDAX
// Please supply your APIKeys here for better testing
const (
apiKey = ""
apiSecret = ""
clientID = "" //passphrase you made at API CREATION
)
func TestSetDefaults(t *testing.T) {
g.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
gdxConfig, err := cfg.GetExchangeConfig("Bitfinex")
if err != nil {
t.Error("Test Failed - GDAX Setup() init error")
}
g.Setup(gdxConfig)
}
func TestGetFee(t *testing.T) {
t.Parallel()
if g.GetFee(false) == 0 {
t.Error("Test failed - GetFee() error")
}
if g.GetFee(true) != 0 {
t.Error("Test failed - GetFee() error")
}
}
func TestGetProducts(t *testing.T) {
t.Parallel()
_, err := g.GetProducts()
if err != nil {
t.Error("Test failed - GetProducts() error")
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := g.GetTicker("BTC-USD")
if err != nil {
t.Error("Test failed - GetTicker() error", err)
}
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := g.GetTrades("BTC-USD")
if err != nil {
t.Error("Test failed - GetTrades() error", err)
}
}
func TestGetHistoricRates(t *testing.T) {
t.Parallel()
_, err := g.GetHistoricRates("BTC-USD", 0, 0, 0)
if err != nil {
t.Error("Test failed - GetHistoricRates() error", err)
}
}
func TestGetStats(t *testing.T) {
t.Parallel()
_, err := g.GetStats("BTC-USD")
if err != nil {
t.Error("Test failed - GetStats() error", err)
}
}
func TestGetCurrencies(t *testing.T) {
t.Parallel()
_, err := g.GetCurrencies()
if err != nil {
t.Error("Test failed - GetCurrencies() error", err)
}
}
func TestGetServerTime(t *testing.T) {
t.Parallel()
_, err := g.GetServerTime()
if err != nil {
t.Error("Test failed - GetServerTime() error", err)
}
}
func TestGetAccounts(t *testing.T) {
t.Parallel()
_, err := g.GetAccounts()
if err == nil {
t.Error("Test failed - GetAccounts() error", err)
}
}
func TestGetAccount(t *testing.T) {
t.Parallel()
_, err := g.GetAccount("234cb213-ac6f-4ed8-b7b6-e62512930945")
if err == nil {
t.Error("Test failed - GetAccount() error", err)
}
}
func TestGetAccountHistory(t *testing.T) {
t.Parallel()
_, err := g.GetAccountHistory("234cb213-ac6f-4ed8-b7b6-e62512930945")
if err == nil {
t.Error("Test failed - GetAccountHistory() error", err)
}
}
func TestGetHolds(t *testing.T) {
t.Parallel()
_, err := g.GetHolds("234cb213-ac6f-4ed8-b7b6-e62512930945")
if err == nil {
t.Error("Test failed - GetHolds() error", err)
}
}
func TestPlaceLimitOrder(t *testing.T) {
t.Parallel()
_, err := g.PlaceLimitOrder("", 0, 0, "buy", "", "", "BTC-USD", "", false)
if err == nil {
t.Error("Test failed - PlaceLimitOrder() error", err)
}
}
func TestPlaceMarketOrder(t *testing.T) {
t.Parallel()
_, err := g.PlaceMarketOrder("", 1, 0, "buy", "BTC-USD", "")
if err == nil {
t.Error("Test failed - PlaceMarketOrder() error", err)
}
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
err := g.CancelOrder("1337")
if err == nil {
t.Error("Test failed - CancelOrder() error", err)
}
}
func TestCancelAllOrders(t *testing.T) {
t.Parallel()
_, err := g.CancelAllOrders("BTC-USD")
if err == nil {
t.Error("Test failed - CancelAllOrders() error", err)
}
}
func TestGetOrders(t *testing.T) {
t.Parallel()
_, err := g.GetOrders([]string{"open", "done"}, "BTC-USD")
if err == nil {
t.Error("Test failed - GetOrders() error", err)
}
}
func TestGetOrder(t *testing.T) {
t.Parallel()
_, err := g.GetOrder("1337")
if err == nil {
t.Error("Test failed - GetOrders() error", err)
}
}
func TestGetFills(t *testing.T) {
t.Parallel()
_, err := g.GetFills("1337", "BTC-USD")
if err == nil {
t.Error("Test failed - GetFills() error", err)
}
_, err = g.GetFills("", "")
if err == nil {
t.Error("Test failed - GetFills() error", err)
}
}
func TestGetFundingRecords(t *testing.T) {
t.Parallel()
_, err := g.GetFundingRecords("rejected")
if err == nil {
t.Error("Test failed - GetFundingRecords() error", err)
}
}
// func TestRepayFunding(t *testing.T) {
// g.Verbose = true
// _, err := g.RepayFunding("1", "BTC")
// if err != nil {
// t.Error("Test failed - RepayFunding() error", err)
// }
// }
func TestMarginTransfer(t *testing.T) { //invalid sig issue
t.Parallel()
_, err := g.MarginTransfer(1, "withdraw", "45fa9e3b-00ba-4631-b907-8a98cbdf21be", "BTC")
if err == nil {
t.Error("Test failed - MarginTransfer() error", err)
}
}
func TestGetPosition(t *testing.T) {
t.Parallel()
_, err := g.GetPosition()
if err == nil {
t.Error("Test failed - GetPosition() error", err)
}
}
func TestClosePosition(t *testing.T) {
t.Parallel()
_, err := g.ClosePosition(false)
if err == nil {
t.Error("Test failed - ClosePosition() error", err)
}
}
func TestGetPayMethods(t *testing.T) {
t.Parallel()
_, err := g.GetPayMethods()
if err == nil {
t.Error("Test failed - GetPayMethods() error", err)
}
}
func TestDepositViaPaymentMethod(t *testing.T) {
t.Parallel()
_, err := g.DepositViaPaymentMethod(1, "BTC", "1337")
if err == nil {
t.Error("Test failed - DepositViaPaymentMethod() error", err)
}
}
func TestDepositViaCoinbase(t *testing.T) {
t.Parallel()
_, err := g.DepositViaCoinbase(1, "BTC", "1337")
if err == nil {
t.Error("Test failed - DepositViaCoinbase() error", err)
}
}
func TestWithdrawViaPaymentMethod(t *testing.T) {
t.Parallel()
_, err := g.WithdrawViaPaymentMethod(1, "BTC", "1337")
if err == nil {
t.Error("Test failed - WithdrawViaPaymentMethod() error", err)
}
}
// func TestWithdrawViaCoinbase(t *testing.T) { // No Route found error
// _, err := g.WithdrawViaCoinbase(1, "BTC", "c13cd0fc-72ca-55e9-843b-b84ef628c198")
// if err != nil {
// t.Error("Test failed - WithdrawViaCoinbase() error", err)
// }
// }
func TestWithdrawCrypto(t *testing.T) {
t.Parallel()
_, err := g.WithdrawCrypto(1, "BTC", "1337")
if err == nil {
t.Error("Test failed - WithdrawViaCoinbase() error", err)
}
}
func TestGetCoinbaseAccounts(t *testing.T) {
t.Parallel()
_, err := g.GetCoinbaseAccounts()
if err == nil {
t.Error("Test failed - GetCoinbaseAccounts() error", err)
}
}
func TestGetReportStatus(t *testing.T) {
t.Parallel()
_, err := g.GetReportStatus("1337")
if err == nil {
t.Error("Test failed - GetReportStatus() error", err)
}
}
func TestGetTrailingVolume(t *testing.T) {
t.Parallel()
_, err := g.GetTrailingVolume()
if err == nil {
t.Error("Test failed - GetTrailingVolume() error", err)
}
}

View File

@@ -1,13 +1,7 @@
package gdax
type GDAXTicker struct {
TradeID int64 `json:"trade_id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Time string `json:"time"`
}
type GDAXProduct struct {
// Product holds product information
type Product struct {
ID string `json:"id"`
BaseCurrency string `json:"base_currency"`
QuoteCurrency string `json:"quote_currency"`
@@ -17,37 +11,16 @@ type GDAXProduct struct {
DisplayName string `json:"string"`
}
type GDAXOrderL1L2 struct {
Price float64
Amount float64
NumOrders float64
// Ticker holds basic ticker information
type Ticker struct {
TradeID int64 `json:"trade_id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Time string `json:"time"`
}
type GDAXOrderL3 struct {
Price float64
Amount float64
OrderID string
}
type GDAXOrderbookL1L2 struct {
Sequence int64 `json:"sequence"`
Bids []GDAXOrderL1L2 `json:"bids"`
Asks []GDAXOrderL1L2 `json:"asks"`
}
type GDAXOrderbookL3 struct {
Sequence int64 `json:"sequence"`
Bids []GDAXOrderL3 `json:"bids"`
Asks []GDAXOrderL3 `json:"asks"`
}
type GDAXOrderbookResponse struct {
Sequence int64 `json:"sequence"`
Bids [][]interface{} `json:"bids"`
Asks [][]interface{} `json:"asks"`
}
type GDAXTrade struct {
// Trade holds executed trade information
type Trade struct {
TradeID int64 `json:"trade_id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
@@ -55,37 +28,52 @@ type GDAXTrade struct {
Side string `json:"side"`
}
type GDAXStats struct {
// History holds historic rate information
type History struct {
Time int64 `json:"time"`
Low float64 `json:"low"`
High float64 `json:"high"`
Open float64 `json:"open"`
Close float64 `json:"close"`
Volume float64 `json:"volume"`
}
// Stats holds last 24 hr data for gdax
type Stats struct {
Open float64 `json:"open,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Volume float64 `json:"volume,string"`
}
type GDAXCurrency struct {
// Currency holds singular currency product information
type Currency struct {
ID string
Name string
MinSize float64 `json:"min_size,string"`
}
type GDAXHistory struct {
Time int64
Low float64
High float64
Open float64
Close float64
Volume float64
// ServerTime holds current requested server time information
type ServerTime struct {
ISO string `json:"iso"`
Epoch float64 `json:"epoch"`
}
type GDAXAccountResponse struct {
ID string `json:"id"`
Balance float64 `json:"balance,string"`
Hold float64 `json:"hold,string"`
Available float64 `json:"available,string"`
Currency string `json:"currency"`
// AccountResponse holds the details for the trading accounts
type AccountResponse struct {
ID string `json:"id"`
Currency string `json:"currency"`
Balance float64 `json:"balance,string"`
Available float64 `json:"available,string"`
Hold float64 `json:"hold,string"`
ProfileID string `json:"profile_id"`
MarginEnabled bool `json:"margin_enabled"`
FundedAmount float64 `json:"funded_amount,string"`
DefaultAmount float64 `json:"default_amount,string"`
}
type GDAXAccountLedgerResponse struct {
// AccountLedgerResponse holds account history information
type AccountLedgerResponse struct {
ID string `json:"id"`
CreatedAt string `json:"created_at"`
Amount float64 `json:"amount,string"`
@@ -94,7 +82,8 @@ type GDAXAccountLedgerResponse struct {
Details interface{} `json:"details"`
}
type GDAXAccountHolds struct {
// AccountHolds contains the hold information about an account
type AccountHolds struct {
ID string `json:"id"`
AccountID string `json:"account_id"`
CreatedAt string `json:"created_at"`
@@ -104,48 +93,182 @@ type GDAXAccountHolds struct {
Reference string `json:"ref"`
}
type GDAXOrdersResponse struct {
ID string `json:"id"`
Size float64 `json:"size,string"`
Price float64 `json:"price,string"`
ProductID string `json:"product_id"`
Status string `json:"status"`
FilledSize float64 `json:"filled_size,string"`
FillFees float64 `json:"fill_fees,string"`
Settled bool `json:"settled"`
Side string `json:"side"`
CreatedAt string `json:"created_at"`
// GeneralizedOrderResponse is the generalized return type across order
// placement and information collation
type GeneralizedOrderResponse struct {
ID string `json:"id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
ProductID string `json:"product_id"`
Side string `json:"side"`
Stp string `json:"stp"`
Type string `json:"type"`
TimeInForce string `json:"time_in_force"`
PostOnly bool `json:"post_only"`
CreatedAt string `json:"created_at"`
FillFees float64 `json:"fill_fees,string"`
FilledSize float64 `json:"filled_size,string"`
ExecutedValue float64 `json:"executed_value,string"`
Status string `json:"status"`
Settled bool `json:"settled"`
Funds float64 `json:"funds,string"`
SpecifiedFunds float64 `json:"specified_funds,string"`
DoneReason string `json:"done_reason"`
DoneAt string `json:"done_at"`
}
type GDAXOrderResponse struct {
ID string `json:"id"`
Size float64 `json:"size,string"`
Price float64 `json:"price,string"`
DoneReason string `json:"done_reason"`
Status string `json:"status"`
Settled bool `json:"settled"`
FilledSize float64 `json:"filled_size,string"`
ProductID string `json:"product_id"`
FillFees float64 `json:"fill_fees,string"`
Side string `json:"side"`
CreatedAt string `json:"created_at"`
DoneAt string `json:"done_at"`
// Funding holds funding data
type Funding struct {
ID string `json:"id"`
OrderID string `json:"order_id"`
ProfileID string `json:"profile_id"`
Amount float64 `json:"amount,string"`
Status string `json:"status"`
CreatedAt string `json:"created_at"`
Currency string `json:"currency"`
RepaidAmount float64 `json:"repaid_amount"`
DefaultAmount float64 `json:"default_amount,string"`
RepaidDefault bool `json:"repaid_default"`
}
type GDAXFillResponse struct {
TradeID int `json:"trade_id"`
ProductID string `json:"product_id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
OrderID string `json:"order_id"`
CreatedAt string `json:"created_at"`
Liquidity string `json:"liquidity"`
Fee float64 `json:"fee,string"`
Settled bool `json:"settled"`
Side string `json:"side"`
// MarginTransfer holds margin transfer details
type MarginTransfer struct {
CreatedAt string `json:"created_at"`
ID string `json:"id"`
UserID string `json:"user_id"`
ProfileID string `json:"profile_id"`
MarginProfileID string `json:"margin_profile_id"`
Type string `json:"type"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
AccountID string `json:"account_id"`
MarginAccountID string `json:"margin_account_id"`
MarginProductID string `json:"margin_product_id"`
Status string `json:"status"`
Nonce int `json:"nonce"`
}
type GDAXReportResponse struct {
// AccountOverview holds account information returned from position
type AccountOverview struct {
Status string `json:"status"`
Funding struct {
MaxFundingValue float64 `json:"max_funding_value,string"`
FundingValue float64 `json:"funding_value,string"`
OldestOutstanding struct {
ID string `json:"id"`
OrderID string `json:"order_id"`
CreatedAt string `json:"created_at"`
Currency string `json:"currency"`
AccountID string `json:"account_id"`
Amount float64 `json:"amount,string"`
} `json:"oldest_outstanding"`
} `json:"funding"`
Accounts struct {
LTC Account `json:"LTC"`
ETH Account `json:"ETH"`
USD Account `json:"USD"`
BTC Account `json:"BTC"`
} `json:"accounts"`
MarginCall struct {
Active bool `json:"active"`
Price float64 `json:"price,string"`
Side string `json:"side"`
Size float64 `json:"size,string"`
Funds float64 `json:"funds,string"`
} `json:"margin_call"`
UserID string `json:"user_id"`
ProfileID string `json:"profile_id"`
Position struct {
Type string `json:"type"`
Size float64 `json:"size,string"`
Complement float64 `json:"complement,string"`
MaxSize float64 `json:"max_size,string"`
} `json:"position"`
ProductID string `json:"product_id"`
}
// Account is a sub-type for account overview
type Account struct {
ID string `json:"id"`
Balance float64 `json:"balance,string"`
Hold float64 `json:"hold,string"`
FundedAmount float64 `json:"funded_amount,string"`
DefaultAmount float64 `json:"default_amount,string"`
}
// PaymentMethod holds payment method information
type PaymentMethod struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Currency string `json:"currency"`
PrimaryBuy bool `json:"primary_buy"`
PrimarySell bool `json:"primary_sell"`
AllowBuy bool `json:"allow_buy"`
AllowSell bool `json:"allow_sell"`
AllowDeposits bool `json:"allow_deposits"`
AllowWithdraw bool `json:"allow_withdraw"`
Limits struct {
Buy []LimitInfo `json:"buy"`
InstantBuy []LimitInfo `json:"instant_buy"`
Sell []LimitInfo `json:"sell"`
Deposit []LimitInfo `json:"deposit"`
} `json:"limits"`
}
// LimitInfo is a sub-type for payment method
type LimitInfo struct {
PeriodInDays int `json:"period_in_days"`
Total struct {
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
} `json:"total"`
}
// DepositWithdrawalInfo holds returned deposit information
type DepositWithdrawalInfo struct {
ID string `json:"id"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
PayoutAt string `json:"payout_at"`
}
// CoinbaseAccounts holds coinbase account information
type CoinbaseAccounts struct {
ID string `json:"id"`
Name string `json:"name"`
Balance float64 `json:"balance,string"`
Currency string `json:"currency"`
Type string `json:"type"`
Primary bool `json:"primary"`
Active bool `json:"active"`
WireDepositInformation struct {
AccountNumber string `json:"account_number"`
RoutingNumber string `json:"routing_number"`
BankName string `json:"bank_name"`
BankAddress string `json:"bank_address"`
BankCountry struct {
Code string `json:"code"`
Name string `json:"name"`
} `json:"bank_country"`
AccountName string `json:"account_name"`
AccountAddress string `json:"account_address"`
Reference string `json:"reference"`
} `json:"wire_deposit_information"`
SepaDepositInformation struct {
Iban string `json:"iban"`
Swift string `json:"swift"`
BankName string `json:"bank_name"`
BankAddress string `json:"bank_address"`
BankCountryName string `json:"bank_country_name"`
AccountName string `json:"account_name"`
AccountAddress string `json:"account_address"`
Reference string `json:"reference"`
} `json:"sep_deposit_information"`
}
// Report holds historical information
type Report struct {
ID string `json:"id"`
Type string `json:"type"`
Status string `json:"status"`
@@ -159,12 +282,71 @@ type GDAXReportResponse struct {
} `json:"params"`
}
type GDAXWebsocketSubscribe struct {
// Volume type contains trailing volume information
type Volume struct {
ProductID string `json:"product_id"`
ExchangeVolume float64 `json:"exchange_volume,string"`
Volume float64 `json:"volume,string"`
RecordedAt string `json:"recorded_at"`
}
// OrderL1L2 is a type used in layer conversion
type OrderL1L2 struct {
Price float64
Amount float64
NumOrders float64
}
// OrderL3 is a type used in layer conversion
type OrderL3 struct {
Price float64
Amount float64
OrderID string
}
// OrderbookL1L2 holds level 1 and 2 order book information
type OrderbookL1L2 struct {
Sequence int64 `json:"sequence"`
Bids []OrderL1L2 `json:"bids"`
Asks []OrderL1L2 `json:"asks"`
}
// OrderbookL3 holds level 3 order book information
type OrderbookL3 struct {
Sequence int64 `json:"sequence"`
Bids []OrderL3 `json:"bids"`
Asks []OrderL3 `json:"asks"`
}
// OrderbookResponse is a generalized response for order books
type OrderbookResponse struct {
Sequence int64 `json:"sequence"`
Bids [][]interface{} `json:"bids"`
Asks [][]interface{} `json:"asks"`
}
// FillResponse contains fill information from the exchange
type FillResponse struct {
TradeID int `json:"trade_id"`
ProductID string `json:"product_id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
OrderID string `json:"order_id"`
CreatedAt string `json:"created_at"`
Liquidity string `json:"liquidity"`
Fee float64 `json:"fee,string"`
Settled bool `json:"settled"`
Side string `json:"side"`
}
// WebsocketSubscribe takes in subscription information
type WebsocketSubscribe struct {
Type string `json:"type"`
ProductID string `json:"product_id"`
}
type GDAXWebsocketReceived struct {
// WebsocketReceived holds websocket received values
type WebsocketReceived struct {
Type string `json:"type"`
Time string `json:"time"`
Sequence int `json:"sequence"`
@@ -174,7 +356,8 @@ type GDAXWebsocketReceived struct {
Side string `json:"side"`
}
type GDAXWebsocketOpen struct {
// WebsocketOpen collates open orders
type WebsocketOpen struct {
Type string `json:"type"`
Time string `json:"time"`
Sequence int `json:"sequence"`
@@ -184,7 +367,8 @@ type GDAXWebsocketOpen struct {
Side string `json:"side"`
}
type GDAXWebsocketDone struct {
// WebsocketDone holds finished order information
type WebsocketDone struct {
Type string `json:"type"`
Time string `json:"time"`
Sequence int `json:"sequence"`
@@ -195,7 +379,8 @@ type GDAXWebsocketDone struct {
RemainingSize float64 `json:"remaining_size,string"`
}
type GDAXWebsocketMatch struct {
// WebsocketMatch holds match information
type WebsocketMatch struct {
Type string `json:"type"`
TradeID int `json:"trade_id"`
Sequence int `json:"sequence"`
@@ -207,7 +392,8 @@ type GDAXWebsocketMatch struct {
Side string `json:"side"`
}
type GDAXWebsocketChange struct {
// WebsocketChange holds change information
type WebsocketChange struct {
Type string `json:"type"`
Time string `json:"time"`
Sequence int `json:"sequence"`

View File

@@ -13,7 +13,7 @@ const (
)
func (g *GDAX) WebsocketSubscribe(product string, conn *websocket.Conn) error {
subscribe := GDAXWebsocketSubscribe{"subscribe", product}
subscribe := WebsocketSubscribe{"subscribe", product}
json, err := common.JSONEncode(subscribe)
if err != nil {
return err
@@ -82,35 +82,35 @@ func (g *GDAX) WebsocketClient() {
log.Println(string(resp))
break
case "received":
received := GDAXWebsocketReceived{}
received := WebsocketReceived{}
err := common.JSONDecode(resp, &received)
if err != nil {
log.Println(err)
continue
}
case "open":
open := GDAXWebsocketOpen{}
open := WebsocketOpen{}
err := common.JSONDecode(resp, &open)
if err != nil {
log.Println(err)
continue
}
case "done":
done := GDAXWebsocketDone{}
done := WebsocketDone{}
err := common.JSONDecode(resp, &done)
if err != nil {
log.Println(err)
continue
}
case "match":
match := GDAXWebsocketMatch{}
match := WebsocketMatch{}
err := common.JSONDecode(resp, &match)
if err != nil {
log.Println(err)
continue
}
case "change":
change := GDAXWebsocketChange{}
change := WebsocketChange{}
err := common.JSONDecode(resp, &change)
if err != nil {
log.Println(err)

View File

@@ -113,7 +113,7 @@ func (g *GDAX) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook
return orderBook, err
}
obNew := orderbookNew.(GDAXOrderbookL1L2)
obNew := orderbookNew.(OrderbookL1L2)
for x := range obNew.Bids {
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: obNew.Bids[x].Amount, Price: obNew.Bids[x].Price})

View File

@@ -3,6 +3,7 @@ package nonce
import (
"strconv"
"sync"
"time"
)
// Nonce struct holds the nonce value
@@ -47,3 +48,15 @@ func (n *Nonce) String() string {
n.mtx.Unlock()
return result
}
// Evaluate returns a nonce while evaluating in a single locked call
func (n *Nonce) Evaluate() string {
n.mtx.Lock()
defer n.mtx.Unlock()
if n.n == 0 {
n.n = time.Now().Unix()
return strconv.FormatInt(n.n, 10)
}
n.n = n.n + 1
return strconv.FormatInt(n.n, 10)
}