Rename GDAX -> CoinbasePro

This commit is contained in:
Adrian Gallagher
2018-07-11 10:41:17 +10:00
parent 7cacca1115
commit 42d458d5ea
17 changed files with 308 additions and 305 deletions

View 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">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/coinbasepro)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](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***

View 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, &currencies)
}
// 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)
}

View 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)
}
}
}

View 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"`
}

View 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())
}
}

View 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")
}