mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-08 07:26:48 +00:00
Rename GDAX -> CoinbasePro
This commit is contained in:
47
exchanges/coinbasepro/README.md
Normal file
47
exchanges/coinbasepro/README.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# GoCryptoTrader package CoinbasePro
|
||||
|
||||
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://travis-ci.org/thrasher-/gocryptotrader)
|
||||
[](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/coinbasepro)
|
||||
[](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
|
||||
|
||||
|
||||
This coinbasepro package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
|
||||
|
||||
## CoinbasePro Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ Initial generation
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
|
||||
## Contribution
|
||||
|
||||
Please feel free to submit any pull requests or suggest any desired features to be added.
|
||||
|
||||
When submitting a PR, please abide by our coding guidelines:
|
||||
|
||||
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
|
||||
|
||||
807
exchanges/coinbasepro/coinbasepro.go
Normal file
807
exchanges/coinbasepro/coinbasepro.go
Normal file
@@ -0,0 +1,807 @@
|
||||
package coinbasepro
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"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"
|
||||
)
|
||||
|
||||
const (
|
||||
coinbaseproAPIURL = "https://api.pro.coinbase.com/"
|
||||
coinbaseproSandboxAPIURL = "https://public.sandbox.pro.coinbase.com"
|
||||
coinbaseproAPIVersion = "0"
|
||||
coinbaseproProducts = "products"
|
||||
coinbaseproOrderbook = "book"
|
||||
coinbaseproTicker = "ticker"
|
||||
coinbaseproTrades = "trades"
|
||||
coinbaseproHistory = "candles"
|
||||
coinbaseproStats = "stats"
|
||||
coinbaseproCurrencies = "currencies"
|
||||
coinbaseproAccounts = "accounts"
|
||||
coinbaseproLedger = "ledger"
|
||||
coinbaseproHolds = "holds"
|
||||
coinbaseproOrders = "orders"
|
||||
coinbaseproFills = "fills"
|
||||
coinbaseproTransfers = "transfers"
|
||||
coinbaseproReports = "reports"
|
||||
coinbaseproTime = "time"
|
||||
coinbaseproMarginTransfer = "profiles/margin-transfer"
|
||||
coinbaseproFunding = "funding"
|
||||
coinbaseproFundingRepay = "funding/repay"
|
||||
coinbaseproPosition = "position"
|
||||
coinbaseproPositionClose = "position/close"
|
||||
coinbaseproPaymentMethod = "payment-methods"
|
||||
coinbaseproPaymentMethodDeposit = "deposits/payment-method"
|
||||
coinbaseproDepositCoinbase = "deposits/coinbase-account"
|
||||
coinbaseproWithdrawalPaymentMethod = "withdrawals/payment-method"
|
||||
coinbaseproWithdrawalCoinbase = "withdrawals/coinbase"
|
||||
coinbaseproWithdrawalCrypto = "withdrawals/crypto"
|
||||
coinbaseproCoinbaseAccounts = "coinbase-accounts"
|
||||
coinbaseproTrailingVolume = "users/self/trailing-volume"
|
||||
|
||||
coinbaseproAuthRate = 5
|
||||
coinbaseproUnauthRate = 3
|
||||
)
|
||||
|
||||
// CoinbasePro is the overarching type across the coinbasepro package
|
||||
type CoinbasePro struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
// SetDefaults sets default values for the exchange
|
||||
func (c *CoinbasePro) SetDefaults() {
|
||||
c.Name = "CoinbasePro"
|
||||
c.Enabled = false
|
||||
c.Verbose = false
|
||||
c.TakerFee = 0.25
|
||||
c.MakerFee = 0
|
||||
c.Websocket = false
|
||||
c.RESTPollingDelay = 10
|
||||
c.RequestCurrencyPairFormat.Delimiter = "-"
|
||||
c.RequestCurrencyPairFormat.Uppercase = true
|
||||
c.ConfigCurrencyPairFormat.Delimiter = ""
|
||||
c.ConfigCurrencyPairFormat.Uppercase = true
|
||||
c.AssetTypes = []string{ticker.Spot}
|
||||
c.APIUrl = coinbaseproAPIURL
|
||||
c.SupportsAutoPairUpdating = true
|
||||
c.SupportsRESTTickerBatching = false
|
||||
c.Requester = request.New(c.Name, request.NewRateLimit(time.Second, coinbaseproAuthRate), request.NewRateLimit(time.Second, coinbaseproUnauthRate), common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
}
|
||||
|
||||
// Setup initialises the exchange parameters with the current configuration
|
||||
func (c *CoinbasePro) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
c.SetEnabled(false)
|
||||
} else {
|
||||
c.Enabled = true
|
||||
c.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
||||
c.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, true)
|
||||
c.SetHTTPClientTimeout(exch.HTTPTimeout)
|
||||
c.RESTPollingDelay = exch.RESTPollingDelay
|
||||
c.Verbose = exch.Verbose
|
||||
c.Websocket = exch.Websocket
|
||||
c.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
c.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
c.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
if exch.UseSandbox {
|
||||
c.APIUrl = coinbaseproSandboxAPIURL
|
||||
}
|
||||
err := c.SetCurrencyPairFormat()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = c.SetAssetTypes()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = c.SetAutoPairDefaults()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetFee returns the current fee for the exchange
|
||||
func (c *CoinbasePro) GetFee(maker bool) float64 {
|
||||
if maker {
|
||||
return c.MakerFee
|
||||
}
|
||||
return c.TakerFee
|
||||
}
|
||||
|
||||
// GetProducts returns supported currency pairs on the exchange with specific
|
||||
// information about the pair
|
||||
func (c *CoinbasePro) GetProducts() ([]Product, error) {
|
||||
products := []Product{}
|
||||
|
||||
return products, c.SendHTTPRequest(c.APIUrl+coinbaseproProducts, &products)
|
||||
}
|
||||
|
||||
// GetOrderbook returns orderbook by currency pair and level
|
||||
func (c *CoinbasePro) GetOrderbook(symbol string, level int) (interface{}, error) {
|
||||
orderbook := OrderbookResponse{}
|
||||
|
||||
path := fmt.Sprintf("%s/%s/%s", c.APIUrl+coinbaseproProducts, symbol, coinbaseproOrderbook)
|
||||
if level > 0 {
|
||||
levelStr := strconv.Itoa(level)
|
||||
path = fmt.Sprintf("%s/%s/%s?level=%s", c.APIUrl+coinbaseproProducts, symbol, coinbaseproOrderbook, levelStr)
|
||||
}
|
||||
|
||||
if err := c.SendHTTPRequest(path, &orderbook); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if level == 3 {
|
||||
ob := OrderbookL3{}
|
||||
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, OrderL3{Price: price, Amount: amount, OrderID: x[2].(string)})
|
||||
}
|
||||
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, 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
|
||||
}
|
||||
|
||||
ob.Asks = append(ob.Asks, OrderL1L2{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, OrderL1L2{Price: price, Amount: amount, NumOrders: x[2].(float64)})
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// GetTicker returns ticker by currency pair
|
||||
// currencyPair - example "BTC-USD"
|
||||
func (c *CoinbasePro) GetTicker(currencyPair string) (Ticker, error) {
|
||||
ticker := Ticker{}
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", c.APIUrl+coinbaseproProducts, currencyPair, coinbaseproTicker)
|
||||
|
||||
return ticker, c.SendHTTPRequest(path, &ticker)
|
||||
}
|
||||
|
||||
// GetTrades listd the latest trades for a product
|
||||
// currencyPair - example "BTC-USD"
|
||||
func (c *CoinbasePro) GetTrades(currencyPair string) ([]Trade, error) {
|
||||
trades := []Trade{}
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", c.APIUrl+coinbaseproProducts, currencyPair, coinbaseproTrades)
|
||||
|
||||
return trades, c.SendHTTPRequest(path, &trades)
|
||||
}
|
||||
|
||||
// GetHistoricRates returns historic rates for a product. Rates are returned in
|
||||
// grouped buckets based on requested granularity.
|
||||
func (c *CoinbasePro) GetHistoricRates(currencyPair string, start, end, granularity int64) ([]History, error) {
|
||||
var resp [][]interface{}
|
||||
history := []History{}
|
||||
values := url.Values{}
|
||||
|
||||
if start > 0 {
|
||||
values.Set("start", strconv.FormatInt(start, 10))
|
||||
}
|
||||
|
||||
if end > 0 {
|
||||
values.Set("end", strconv.FormatInt(end, 10))
|
||||
}
|
||||
|
||||
if granularity > 0 {
|
||||
values.Set("granularity", strconv.FormatInt(granularity, 10))
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(
|
||||
fmt.Sprintf("%s/%s/%s", c.APIUrl+coinbaseproProducts, currencyPair, coinbaseproHistory),
|
||||
values)
|
||||
|
||||
if err := c.SendHTTPRequest(path, &resp); err != nil {
|
||||
return history, err
|
||||
}
|
||||
|
||||
for _, single := range resp {
|
||||
var s History
|
||||
a, _ := single[0].(float64)
|
||||
s.Time = int64(a)
|
||||
b, _ := single[1].(float64)
|
||||
s.Low = b
|
||||
c, _ := single[2].(float64)
|
||||
s.High = c
|
||||
d, _ := single[3].(float64)
|
||||
s.Open = d
|
||||
e, _ := single[4].(float64)
|
||||
s.Close = e
|
||||
f, _ := single[5].(float64)
|
||||
s.Volume = f
|
||||
history = append(history, s)
|
||||
}
|
||||
|
||||
return history, nil
|
||||
}
|
||||
|
||||
// GetStats returns a 24 hr stat for the product. Volume is in base currency
|
||||
// units. open, high, low are in quote currency units.
|
||||
func (c *CoinbasePro) GetStats(currencyPair string) (Stats, error) {
|
||||
stats := Stats{}
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s/%s", c.APIUrl+coinbaseproProducts, currencyPair, coinbaseproStats)
|
||||
|
||||
return stats, c.SendHTTPRequest(path, &stats)
|
||||
}
|
||||
|
||||
// GetCurrencies returns a list of supported currency on the exchange
|
||||
// Warning: Not all currencies may be currently in use for tradinc.
|
||||
func (c *CoinbasePro) GetCurrencies() ([]Currency, error) {
|
||||
currencies := []Currency{}
|
||||
|
||||
return currencies, c.SendHTTPRequest(c.APIUrl+coinbaseproCurrencies, ¤cies)
|
||||
}
|
||||
|
||||
// GetServerTime returns the API server time
|
||||
func (c *CoinbasePro) GetServerTime() (ServerTime, error) {
|
||||
serverTime := ServerTime{}
|
||||
|
||||
return serverTime, c.SendHTTPRequest(c.APIUrl+coinbaseproTime, &serverTime)
|
||||
}
|
||||
|
||||
// GetAccounts returns a list of trading accounts associated with the APIKEYS
|
||||
func (c *CoinbasePro) GetAccounts() ([]AccountResponse, error) {
|
||||
resp := []AccountResponse{}
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("GET", coinbaseproAccounts, nil, &resp)
|
||||
}
|
||||
|
||||
// GetAccount returns information for a single account. Use this endpoint when
|
||||
// account_id is known
|
||||
func (c *CoinbasePro) GetAccount(accountID string) (AccountResponse, error) {
|
||||
resp := AccountResponse{}
|
||||
path := fmt.Sprintf("%s/%s", coinbaseproAccounts, accountID)
|
||||
|
||||
return resp, c.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
|
||||
}
|
||||
|
||||
// GetAccountHistory returns a list of account activity. Account activity either
|
||||
// increases or decreases your account balance. Items are paginated and sorted
|
||||
// latest first.
|
||||
func (c *CoinbasePro) GetAccountHistory(accountID string) ([]AccountLedgerResponse, error) {
|
||||
resp := []AccountLedgerResponse{}
|
||||
path := fmt.Sprintf("%s/%s/%s", coinbaseproAccounts, accountID, coinbaseproLedger)
|
||||
|
||||
return resp, c.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
|
||||
}
|
||||
|
||||
// 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 (c *CoinbasePro) GetHolds(accountID string) ([]AccountHolds, error) {
|
||||
resp := []AccountHolds{}
|
||||
path := fmt.Sprintf("%s/%s/%s", coinbaseproAccounts, accountID, coinbaseproHolds)
|
||||
|
||||
return resp, c.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 (c *CoinbasePro) PlaceLimitOrder(clientRef string, price, amount float64, side, timeInforce, cancelAfter, productID, stp string, postOnly bool) (string, error) {
|
||||
resp := GeneralizedOrderResponse{}
|
||||
request := make(map[string]interface{})
|
||||
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
|
||||
}
|
||||
if postOnly {
|
||||
request["post_only"] = postOnly
|
||||
}
|
||||
|
||||
err := c.SendAuthenticatedHTTPRequest("POST", coinbaseproOrders, request, &resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
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 (c *CoinbasePro) 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 := c.SendAuthenticatedHTTPRequest("POST", coinbaseproOrders, 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 (c *CoinbasePro) 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 := c.SendAuthenticatedHTTPRequest("POST", coinbaseproOrders, request, &resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
}
|
||||
|
||||
// CancelOrder cancels order by orderID
|
||||
func (c *CoinbasePro) CancelOrder(orderID string) error {
|
||||
path := fmt.Sprintf("%s/%s", coinbaseproOrders, orderID)
|
||||
|
||||
return c.SendAuthenticatedHTTPRequest("DELETE", path, nil, nil)
|
||||
}
|
||||
|
||||
// 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 (c *CoinbasePro) CancelAllOrders(currencyPair string) ([]string, error) {
|
||||
var resp []string
|
||||
request := make(map[string]interface{})
|
||||
|
||||
if len(currencyPair) != 0 {
|
||||
request["product_id"] = currencyPair
|
||||
}
|
||||
return resp, c.SendAuthenticatedHTTPRequest("DELETE", coinbaseproOrders, request, &resp)
|
||||
}
|
||||
|
||||
// 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 (c *CoinbasePro) GetOrders(status []string, currencyPair string) ([]GeneralizedOrderResponse, error) {
|
||||
resp := []GeneralizedOrderResponse{}
|
||||
params := url.Values{}
|
||||
|
||||
for _, individualStatus := range status {
|
||||
params.Add("status", individualStatus)
|
||||
}
|
||||
if len(currencyPair) != 0 {
|
||||
params.Set("product_id", currencyPair)
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(c.APIUrl+coinbaseproOrders, params)
|
||||
path = common.GetURIPath(path)
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("GET", path[1:], nil, &resp)
|
||||
}
|
||||
|
||||
// GetOrder returns a single order by order id.
|
||||
func (c *CoinbasePro) GetOrder(orderID string) (GeneralizedOrderResponse, error) {
|
||||
resp := GeneralizedOrderResponse{}
|
||||
path := fmt.Sprintf("%s/%s", coinbaseproOrders, orderID)
|
||||
|
||||
return resp, c.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
|
||||
}
|
||||
|
||||
// GetFills returns a list of recent fills
|
||||
func (c *CoinbasePro) 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 parameters set")
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(c.APIUrl+coinbaseproFills, params)
|
||||
uri := common.GetURIPath(path)
|
||||
|
||||
return resp,
|
||||
c.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 (c *CoinbasePro) GetFundingRecords(status string) ([]Funding, error) {
|
||||
resp := []Funding{}
|
||||
params := url.Values{}
|
||||
params.Set("status", status)
|
||||
|
||||
path := common.EncodeURLValues(c.APIUrl+coinbaseproFunding, params)
|
||||
uri := common.GetURIPath(path)
|
||||
|
||||
return resp,
|
||||
c.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 (c *CoinbasePro) RepayFunding(amount, currency string) (Funding, error) {
|
||||
// resp := Funding{}
|
||||
// params := make(map[string]interface{})
|
||||
// params["amount"] = amount
|
||||
// params["currency"] = currency
|
||||
//
|
||||
// return resp,
|
||||
// c.SendAuthenticatedHTTPRequest("POST", coinbaseproFundingRepay, 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 (c *CoinbasePro) 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["currency"] = currency
|
||||
request["margin_profile_id"] = profileID
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproMarginTransfer, request, &resp)
|
||||
}
|
||||
|
||||
// GetPosition returns an overview of account profile.
|
||||
func (c *CoinbasePro) GetPosition() (AccountOverview, error) {
|
||||
resp := AccountOverview{}
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("GET", coinbaseproPosition, nil, &resp)
|
||||
}
|
||||
|
||||
// ClosePosition closes a position and allowing you to repay position as well
|
||||
// repayOnly - allows the position to be repaid
|
||||
func (c *CoinbasePro) ClosePosition(repayOnly bool) (AccountOverview, error) {
|
||||
resp := AccountOverview{}
|
||||
request := make(map[string]interface{})
|
||||
request["repay_only"] = repayOnly
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproPositionClose, request, &resp)
|
||||
}
|
||||
|
||||
// GetPayMethods returns a full list of payment methods
|
||||
func (c *CoinbasePro) GetPayMethods() ([]PaymentMethod, error) {
|
||||
resp := []PaymentMethod{}
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("GET", coinbaseproPaymentMethod, 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 (c *CoinbasePro) 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,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproPaymentMethodDeposit, req, &resp)
|
||||
}
|
||||
|
||||
// DepositViaCoinbase deposits funds from a coinbase account. Move funds between
|
||||
// a Coinbase account and coinbasepro trading account within daily limits. Moving
|
||||
// funds between Coinbase and coinbasepro 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 (c *CoinbasePro) 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,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproDepositCoinbase, 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 (c *CoinbasePro) 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,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproWithdrawalPaymentMethod, 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 (c *CoinbasePro) 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,
|
||||
// c.SendAuthenticatedHTTPRequest("POST", coinbaseproWithdrawalCoinbase, 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 (c *CoinbasePro) 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,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproWithdrawalCrypto, req, &resp)
|
||||
}
|
||||
|
||||
// GetCoinbaseAccounts returns a list of coinbase accounts
|
||||
func (c *CoinbasePro) GetCoinbaseAccounts() ([]CoinbaseAccounts, error) {
|
||||
resp := []CoinbaseAccounts{}
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("GET", coinbaseproCoinbaseAccounts, 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.c. 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 (default is pdf)
|
||||
// email - [optional] Email address to send the report to
|
||||
func (c *CoinbasePro) 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"
|
||||
|
||||
if len(currencyPair) != 0 {
|
||||
request["product_id"] = currencyPair
|
||||
}
|
||||
if len(accountID) != 0 {
|
||||
request["account_id"] = accountID
|
||||
}
|
||||
if format == "csv" {
|
||||
request["format"] = format
|
||||
}
|
||||
if len(email) != 0 {
|
||||
request["email"] = email
|
||||
}
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("POST", coinbaseproReports, request, &resp)
|
||||
}
|
||||
|
||||
// GetReportStatus once a report request has been accepted for processing, the
|
||||
// status is available by polling the report resource endpoint.
|
||||
func (c *CoinbasePro) GetReportStatus(reportID string) (Report, error) {
|
||||
resp := Report{}
|
||||
path := fmt.Sprintf("%s/%s", coinbaseproReports, reportID)
|
||||
|
||||
return resp, c.SendAuthenticatedHTTPRequest("GET", path, nil, &resp)
|
||||
}
|
||||
|
||||
// GetTrailingVolume this request will return your 30-day trailing volume for
|
||||
// all products.
|
||||
func (c *CoinbasePro) GetTrailingVolume() ([]Volume, error) {
|
||||
resp := []Volume{}
|
||||
|
||||
return resp,
|
||||
c.SendAuthenticatedHTTPRequest("GET", coinbaseproTrailingVolume, nil, &resp)
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (c *CoinbasePro) SendHTTPRequest(path string, result interface{}) error {
|
||||
return c.SendPayload("GET", path, nil, nil, result, false, c.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP reque
|
||||
func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) (err error) {
|
||||
if !c.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name)
|
||||
}
|
||||
|
||||
payload := []byte("")
|
||||
|
||||
if params != nil {
|
||||
payload, err = common.JSONEncode(params)
|
||||
if err != nil {
|
||||
return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request")
|
||||
}
|
||||
|
||||
if c.Verbose {
|
||||
log.Printf("Request JSON: %s\n", payload)
|
||||
}
|
||||
}
|
||||
|
||||
nonce := c.Nonce.GetValue(c.Name, false).String()
|
||||
message := nonce + method + "/" + path + string(payload)
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(c.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["CB-ACCESS-SIGN"] = common.Base64Encode([]byte(hmac))
|
||||
headers["CB-ACCESS-TIMESTAMP"] = nonce
|
||||
headers["CB-ACCESS-KEY"] = c.APIKey
|
||||
headers["CB-ACCESS-PASSPHRASE"] = c.ClientID
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
return c.SendPayload(method, c.APIUrl+path, headers, bytes.NewBuffer(payload), result, true, c.Verbose)
|
||||
}
|
||||
226
exchanges/coinbasepro/coinbasepro_test.go
Normal file
226
exchanges/coinbasepro/coinbasepro_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package coinbasepro
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
var c CoinbasePro
|
||||
|
||||
// Please supply your APIKeys here for better testing
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
clientID = "" //passphrase you made at API CREATION
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
c.SetDefaults()
|
||||
c.Requester.SetRateLimit(false, time.Second, 1)
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
gdxConfig, err := cfg.GetExchangeConfig("CoinbasePro")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - coinbasepro Setup() init error")
|
||||
}
|
||||
|
||||
c.Setup(gdxConfig)
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
if c.GetFee(false) == 0 {
|
||||
t.Error("Test failed - GetFee() error")
|
||||
}
|
||||
if c.GetFee(true) != 0 {
|
||||
t.Error("Test failed - GetFee() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProducts(t *testing.T) {
|
||||
_, err := c.GetProducts()
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetProducts() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
_, err := c.GetTicker("BTC-USD")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
_, err := c.GetTrades("BTC-USD")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTrades() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricRates(t *testing.T) {
|
||||
_, err := c.GetHistoricRates("BTC-USD", 0, 0, 0)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetHistoricRates() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStats(t *testing.T) {
|
||||
_, err := c.GetStats("BTC-USD")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetStats() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
_, err := c.GetCurrencies()
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetCurrencies() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerTime(t *testing.T) {
|
||||
_, err := c.GetServerTime()
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetServerTime() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRequests(t *testing.T) {
|
||||
|
||||
if c.APIKey != "" && c.APISecret != "" && c.ClientID != "" {
|
||||
|
||||
_, err := c.GetAccounts()
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetAccounts() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetAccount("234cb213-ac6f-4ed8-b7b6-e62512930945")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetAccount() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetAccountHistory("234cb213-ac6f-4ed8-b7b6-e62512930945")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetAccountHistory() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetHolds("234cb213-ac6f-4ed8-b7b6-e62512930945")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetHolds() error", err)
|
||||
}
|
||||
|
||||
_, err = c.PlaceLimitOrder("", 0, 0, "buy", "", "", "BTC-USD", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test failed - PlaceLimitOrder() error", err)
|
||||
}
|
||||
|
||||
_, err = c.PlaceMarketOrder("", 1, 0, "buy", "BTC-USD", "")
|
||||
if err == nil {
|
||||
t.Error("Test failed - PlaceMarketOrder() error", err)
|
||||
}
|
||||
|
||||
err = c.CancelOrder("1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - CancelOrder() error", err)
|
||||
}
|
||||
|
||||
_, err = c.CancelAllOrders("BTC-USD")
|
||||
if err == nil {
|
||||
t.Error("Test failed - CancelAllOrders() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetOrders([]string{"open", "done"}, "BTC-USD")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetOrders() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetOrder("1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetOrders() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetFills("1337", "BTC-USD")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetFills() error", err)
|
||||
}
|
||||
_, err = c.GetFills("", "")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetFills() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetFundingRecords("rejected")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetFundingRecords() error", err)
|
||||
}
|
||||
|
||||
// _, err := c.RepayFunding("1", "BTC")
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - RepayFunding() error", err)
|
||||
// }
|
||||
|
||||
_, err = c.MarginTransfer(1, "withdraw", "45fa9e3b-00ba-4631-b907-8a98cbdf21be", "BTC")
|
||||
if err == nil {
|
||||
t.Error("Test failed - MarginTransfer() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetPosition()
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetPosition() error", err)
|
||||
}
|
||||
|
||||
_, err = c.ClosePosition(false)
|
||||
if err == nil {
|
||||
t.Error("Test failed - ClosePosition() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetPayMethods()
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetPayMethods() error", err)
|
||||
}
|
||||
|
||||
_, err = c.DepositViaPaymentMethod(1, "BTC", "1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - DepositViaPaymentMethod() error", err)
|
||||
}
|
||||
|
||||
_, err = c.DepositViaCoinbase(1, "BTC", "1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - DepositViaCoinbase() error", err)
|
||||
}
|
||||
|
||||
_, err = c.WithdrawViaPaymentMethod(1, "BTC", "1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - WithdrawViaPaymentMethod() error", err)
|
||||
}
|
||||
|
||||
// _, err := c.WithdrawViaCoinbase(1, "BTC", "c13cd0fc-72ca-55e9-843b-b84ef628c198")
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - WithdrawViaCoinbase() error", err)
|
||||
// }
|
||||
|
||||
_, err = c.WithdrawCrypto(1, "BTC", "1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - WithdrawViaCoinbase() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetCoinbaseAccounts()
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetCoinbaseAccounts() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetReportStatus("1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetReportStatus() error", err)
|
||||
}
|
||||
|
||||
_, err = c.GetTrailingVolume()
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetTrailingVolume() error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
405
exchanges/coinbasepro/coinbasepro_types.go
Normal file
405
exchanges/coinbasepro/coinbasepro_types.go
Normal file
@@ -0,0 +1,405 @@
|
||||
package coinbasepro
|
||||
|
||||
// Product holds product information
|
||||
type Product struct {
|
||||
ID string `json:"id"`
|
||||
BaseCurrency string `json:"base_currency"`
|
||||
QuoteCurrency string `json:"quote_currency"`
|
||||
BaseMinSize float64 `json:"base_min_size,string"`
|
||||
BaseMaxSize int64 `json:"base_max_size,string"`
|
||||
QuoteIncrement float64 `json:"quote_increment,string"`
|
||||
DisplayName string `json:"string"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Trade holds executed trade information
|
||||
type Trade struct {
|
||||
TradeID int64 `json:"trade_id"`
|
||||
Price float64 `json:"price,string"`
|
||||
Size float64 `json:"size,string"`
|
||||
Time string `json:"time"`
|
||||
Side string `json:"side"`
|
||||
}
|
||||
|
||||
// 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 coinbasepro
|
||||
type Stats struct {
|
||||
Open float64 `json:"open,string"`
|
||||
High float64 `json:"high,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
Volume float64 `json:"volume,string"`
|
||||
}
|
||||
|
||||
// Currency holds singular currency product information
|
||||
type Currency struct {
|
||||
ID string
|
||||
Name string
|
||||
MinSize float64 `json:"min_size,string"`
|
||||
}
|
||||
|
||||
// ServerTime holds current requested server time information
|
||||
type ServerTime struct {
|
||||
ISO string `json:"iso"`
|
||||
Epoch float64 `json:"epoch"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// AccountLedgerResponse holds account history information
|
||||
type AccountLedgerResponse struct {
|
||||
ID string `json:"id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Balance float64 `json:"balance,string"`
|
||||
Type string `json:"type"`
|
||||
Details interface{} `json:"details"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Type string `json:"type"`
|
||||
Reference string `json:"ref"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
CompletedAt string `json:"completed_at"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
FileURL string `json:"file_url"`
|
||||
Params struct {
|
||||
StartDate string `json:"start_date"`
|
||||
EndDate string `json:"end_date"`
|
||||
} `json:"params"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// WebsocketReceived holds websocket received values
|
||||
type WebsocketReceived struct {
|
||||
Type string `json:"type"`
|
||||
Time string `json:"time"`
|
||||
Sequence int `json:"sequence"`
|
||||
OrderID string `json:"order_id"`
|
||||
Size float64 `json:"size,string"`
|
||||
Price float64 `json:"price,string"`
|
||||
Side string `json:"side"`
|
||||
}
|
||||
|
||||
// WebsocketOpen collates open orders
|
||||
type WebsocketOpen struct {
|
||||
Type string `json:"type"`
|
||||
Time string `json:"time"`
|
||||
Sequence int `json:"sequence"`
|
||||
OrderID string `json:"order_id"`
|
||||
Price float64 `json:"price,string"`
|
||||
RemainingSize float64 `json:"remaining_size,string"`
|
||||
Side string `json:"side"`
|
||||
}
|
||||
|
||||
// WebsocketDone holds finished order information
|
||||
type WebsocketDone struct {
|
||||
Type string `json:"type"`
|
||||
Time string `json:"time"`
|
||||
Sequence int `json:"sequence"`
|
||||
Price float64 `json:"price,string"`
|
||||
OrderID string `json:"order_id"`
|
||||
Reason string `json:"reason"`
|
||||
Side string `json:"side"`
|
||||
RemainingSize float64 `json:"remaining_size,string"`
|
||||
}
|
||||
|
||||
// WebsocketMatch holds match information
|
||||
type WebsocketMatch struct {
|
||||
Type string `json:"type"`
|
||||
TradeID int `json:"trade_id"`
|
||||
Sequence int `json:"sequence"`
|
||||
MakerOrderID string `json:"maker_order_id"`
|
||||
TakerOrderID string `json:"taker_order_id"`
|
||||
Time string `json:"time"`
|
||||
Size float64 `json:"size,string"`
|
||||
Price float64 `json:"price,string"`
|
||||
Side string `json:"side"`
|
||||
}
|
||||
|
||||
// WebsocketChange holds change information
|
||||
type WebsocketChange struct {
|
||||
Type string `json:"type"`
|
||||
Time string `json:"time"`
|
||||
Sequence int `json:"sequence"`
|
||||
OrderID string `json:"order_id"`
|
||||
NewSize float64 `json:"new_size,string"`
|
||||
OldSize float64 `json:"old_size,string"`
|
||||
Price float64 `json:"price,string"`
|
||||
Side string `json:"side"`
|
||||
}
|
||||
127
exchanges/coinbasepro/coinbasepro_websocket.go
Normal file
127
exchanges/coinbasepro/coinbasepro_websocket.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package coinbasepro
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
)
|
||||
|
||||
const (
|
||||
coinbaseproWebsocketURL = "wss://ws-feed.pro.coinbase.com"
|
||||
)
|
||||
|
||||
// WebsocketSubscribe subscribes to a websocket connection
|
||||
func (c *CoinbasePro) WebsocketSubscribe(product string, conn *websocket.Conn) error {
|
||||
subscribe := WebsocketSubscribe{"subscribe", product}
|
||||
json, err := common.JSONEncode(subscribe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = conn.WriteMessage(websocket.TextMessage, json)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WebsocketClient initiates a websocket client
|
||||
func (c *CoinbasePro) WebsocketClient() {
|
||||
for c.Enabled && c.Websocket {
|
||||
var Dialer websocket.Dialer
|
||||
conn, _, err := Dialer.Dial(coinbaseproWebsocketURL, http.Header{})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to connect to Websocket. Error: %s\n", c.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("%s Connected to Websocket.\n", c.GetName())
|
||||
|
||||
currencies := []string{}
|
||||
for _, x := range c.EnabledPairs {
|
||||
currency := x[0:3] + "-" + x[3:]
|
||||
currencies = append(currencies, currency)
|
||||
}
|
||||
|
||||
for _, x := range currencies {
|
||||
err = c.WebsocketSubscribe(x, conn)
|
||||
if err != nil {
|
||||
log.Printf("%s Websocket subscription error: %s\n", c.GetName(), err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if c.Verbose {
|
||||
log.Printf("%s Subscribed to product messages.", c.GetName())
|
||||
}
|
||||
|
||||
for c.Enabled && c.Websocket {
|
||||
msgType, resp, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
|
||||
switch msgType {
|
||||
case websocket.TextMessage:
|
||||
type MsgType struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
msgType := MsgType{}
|
||||
err := common.JSONDecode(resp, &msgType)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
switch msgType.Type {
|
||||
case "error":
|
||||
log.Println(string(resp))
|
||||
break
|
||||
case "received":
|
||||
received := WebsocketReceived{}
|
||||
err := common.JSONDecode(resp, &received)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case "open":
|
||||
open := WebsocketOpen{}
|
||||
err := common.JSONDecode(resp, &open)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case "done":
|
||||
done := WebsocketDone{}
|
||||
err := common.JSONDecode(resp, &done)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case "match":
|
||||
match := WebsocketMatch{}
|
||||
err := common.JSONDecode(resp, &match)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case "change":
|
||||
change := WebsocketChange{}
|
||||
err := common.JSONDecode(resp, &change)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
conn.Close()
|
||||
log.Printf("%s Websocket client disconnected.", c.GetName())
|
||||
}
|
||||
}
|
||||
177
exchanges/coinbasepro/coinbasepro_wrapper.go
Normal file
177
exchanges/coinbasepro/coinbasepro_wrapper.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package coinbasepro
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
// Start starts the coinbasepro go routine
|
||||
func (c *CoinbasePro) Start(wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
c.Run()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Run implements the coinbasepro wrapper
|
||||
func (c *CoinbasePro) Run() {
|
||||
if c.Verbose {
|
||||
log.Printf("%s Websocket: %s. (url: %s).\n", c.GetName(), common.IsEnabled(c.Websocket), coinbaseproWebsocketURL)
|
||||
log.Printf("%s polling delay: %ds.\n", c.GetName(), c.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", c.GetName(), len(c.EnabledPairs), c.EnabledPairs)
|
||||
}
|
||||
|
||||
if c.Websocket {
|
||||
go c.WebsocketClient()
|
||||
}
|
||||
|
||||
exchangeProducts, err := c.GetProducts()
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to get available products.\n", c.GetName())
|
||||
} else {
|
||||
currencies := []string{}
|
||||
for _, x := range exchangeProducts {
|
||||
if x.ID != "BTC" && x.ID != "USD" && x.ID != "GBP" {
|
||||
currencies = append(currencies, x.ID[0:3]+x.ID[4:])
|
||||
}
|
||||
}
|
||||
err = c.UpdateCurrencies(currencies, false, false)
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to update available currencies.\n", c.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetExchangeAccountInfo retrieves balances for all enabled currencies for the
|
||||
// coinbasepro exchange
|
||||
func (c *CoinbasePro) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
var response exchange.AccountInfo
|
||||
response.ExchangeName = c.GetName()
|
||||
accountBalance, err := c.GetAccounts()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
for i := 0; i < len(accountBalance); i++ {
|
||||
var exchangeCurrency exchange.AccountCurrencyInfo
|
||||
exchangeCurrency.CurrencyName = accountBalance[i].Currency
|
||||
exchangeCurrency.TotalValue = accountBalance[i].Available
|
||||
exchangeCurrency.Hold = accountBalance[i].Hold
|
||||
|
||||
response.Currencies = append(response.Currencies, exchangeCurrency)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (c *CoinbasePro) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
var tickerPrice ticker.Price
|
||||
tick, err := c.GetTicker(exchange.FormatExchangeCurrency(c.Name, p).String())
|
||||
if err != nil {
|
||||
return ticker.Price{}, err
|
||||
}
|
||||
|
||||
stats, err := c.GetStats(exchange.FormatExchangeCurrency(c.Name, p).String())
|
||||
|
||||
if err != nil {
|
||||
return ticker.Price{}, err
|
||||
}
|
||||
|
||||
tickerPrice.Pair = p
|
||||
tickerPrice.Volume = stats.Volume
|
||||
tickerPrice.Last = tick.Price
|
||||
tickerPrice.High = stats.High
|
||||
tickerPrice.Low = stats.Low
|
||||
ticker.ProcessTicker(c.GetName(), p, tickerPrice, assetType)
|
||||
return ticker.GetTicker(c.Name, p, assetType)
|
||||
}
|
||||
|
||||
// GetTickerPrice returns the ticker for a currency pair
|
||||
func (c *CoinbasePro) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
tickerNew, err := ticker.GetTicker(c.GetName(), p, assetType)
|
||||
if err != nil {
|
||||
return c.UpdateTicker(p, assetType)
|
||||
}
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns orderbook base on the currency pair
|
||||
func (c *CoinbasePro) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
ob, err := orderbook.GetOrderbook(c.GetName(), p, assetType)
|
||||
if err != nil {
|
||||
return c.UpdateOrderbook(p, assetType)
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (c *CoinbasePro) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
var orderBook orderbook.Base
|
||||
orderbookNew, err := c.GetOrderbook(exchange.FormatExchangeCurrency(c.Name, p).String(), 2)
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
for x := range obNew.Asks {
|
||||
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: obNew.Bids[x].Amount, Price: obNew.Bids[x].Price})
|
||||
}
|
||||
|
||||
orderbook.ProcessOrderbook(c.GetName(), p, orderBook, assetType)
|
||||
return orderbook.GetOrderbook(c.Name, p, assetType)
|
||||
}
|
||||
|
||||
// GetExchangeHistory returns historic trade data since exchange openinc.
|
||||
func (c *CoinbasePro) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
|
||||
var resp []exchange.TradeHistory
|
||||
|
||||
return resp, errors.New("trade history not yet implemented")
|
||||
}
|
||||
|
||||
// SubmitExchangeOrder submits a new order
|
||||
func (c *CoinbasePro) SubmitExchangeOrder(p pair.CurrencyPair, side string, orderType int, amount, price float64) (int64, error) {
|
||||
return 0, errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// ModifyExchangeOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (c *CoinbasePro) ModifyExchangeOrder(p pair.CurrencyPair, orderID, action int64) (int64, error) {
|
||||
return 0, errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// CancelExchangeOrder cancels an order by its corresponding ID number
|
||||
func (c *CoinbasePro) CancelExchangeOrder(p pair.CurrencyPair, orderID int64) (int64, error) {
|
||||
return 0, errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// CancelAllExchangeOrders cancels all orders associated with a currency pair
|
||||
func (c *CoinbasePro) CancelAllExchangeOrders(p pair.CurrencyPair) error {
|
||||
return errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// GetExchangeOrderInfo returns information on a current open order
|
||||
func (c *CoinbasePro) GetExchangeOrderInfo(orderID int64) (float64, error) {
|
||||
return 0, errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// GetExchangeDepositAddress returns a deposit address for a specified currency
|
||||
func (c *CoinbasePro) GetExchangeDepositAddress(p pair.CurrencyPair) (string, error) {
|
||||
return "", errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// WithdrawExchangeFunds returns a withdrawal ID when a withdrawal is submitted
|
||||
func (c *CoinbasePro) WithdrawExchangeFunds(address string, p pair.CurrencyPair, amount float64) (string, error) {
|
||||
return "", errors.New("not yet implemented")
|
||||
}
|
||||
Reference in New Issue
Block a user