mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-07 23:16:53 +00:00
cmd/exchange_template, exchanges: Update templates and propogate to exchanges (#1777)
* Added TimeInForce type and updated related files * Linter issue fix and minor coinbasepro type update * Bitrex consts update * added unit test and minor changes in bittrex * Unit tests update * Fix minor linter issues * Update TestStringToTimeInForce unit test * Exchange test template change * A different approach * fix conflict with gateio timeInForce * minor exchange template update * Minor fix to test_files template * Update order tests * Complete updating the order unit tests * Updating exchange wrapper and test template files * update kucoin and deribit wrapper to match the time in force change * minor comment update * fix time-in-force related test errors * linter issue fix * ADD_NEW_EXCHANGE documentation update * time in force constants, functions and unit tests update * shift tif policies to TimeInForce * Update time-in-force, related functions, and unit tests * fix linter issue and time-in-force processing * added a good till crossing tif value * order type fix and fix related tim-in-force entries * update time-in-force unmarshaling and unit test * consistency guideline added * fix time-in-force error in gateio * linter issue fix * update based on review comments * add unit test and fix missing issues * minor fix and added benchmark unit test * change GTT to GTC for limit * fix linter issue * added time-in-force value to place order param * fix minor issues based on review comment and move tif code to separate files * update on exchanges linked to time-in-force * resolve missing review comments * minor linter issues fix * added time-in-force handler and update timeInForce parametered endpoint * minor fixes based on review * nits fix * update based on review * linter fix * rm getTimeInForce func and minor change to time-in-force * minor change * update based on review comments * wrappers and time-in-force calling approach * minor change * update gateio string to timeInForce conversion and unit test * update exchange template * update wrapper template file * policy comments, and template files update * rename all exchange types name to Exchange * update on template files and template generation * templates and generation code and other updates * linter issue fix * added subscriptions and websocket templates * update ADD_NEW_EXCHANGE.md with recent binance functions and implementations * rename template files and update unit tests * minor template and unit test fix * rename templates and fix on unit tests * update on template files and documentation * removed unnecessary tag fix and update templates * fix Add_NEW_EXCHANGE.md doc file * formatting, comments, and error checks update on template files * rename exchange receivers to e and ex for consistency * rename unit test exchange receiver and minor updates * linter issues fix * fix deribit issue and minor style update * fix test issues caused by receiver change * raname local variables exchange declaration variables * update templates comments * update templates and related comments * renamed ex to e * update template comments * toggle WS to false to improve coverage * template comments update * added test coverage to Ws enabled and minor changes --------- Co-authored-by: Samuel Reid <43227667+cranktakular@users.noreply.github.com>
This commit is contained in:
@@ -51,31 +51,31 @@ const (
|
||||
geminiTransfers = "transfers"
|
||||
)
|
||||
|
||||
// Gemini is the overarching type across the Gemini package, create multiple
|
||||
// Exchange implements exchange.IBotExchange and contains additional specific api methods for interacting with Gemini, create multiple
|
||||
// instances with differing APIkeys for segregation of roles for authenticated
|
||||
// requests & sessions by appending new sessions to the Session map using
|
||||
// AddSession. If sandbox test is needed, append a new session with the same
|
||||
// API keys and change the IsSandbox variable to true.
|
||||
type Gemini struct {
|
||||
type Exchange struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
// GetSymbols returns all available symbols for trading
|
||||
func (g *Gemini) GetSymbols(ctx context.Context) ([]string, error) {
|
||||
func (e *Exchange) GetSymbols(ctx context.Context) ([]string, error) {
|
||||
var symbols []string
|
||||
path := fmt.Sprintf("/v%s/%s", geminiAPIVersion, geminiSymbols)
|
||||
return symbols, g.SendHTTPRequest(ctx, exchange.RestSpot, path, &symbols)
|
||||
return symbols, e.SendHTTPRequest(ctx, exchange.RestSpot, path, &symbols)
|
||||
}
|
||||
|
||||
// GetSymbolDetails returns extra symbol details
|
||||
// use symbol "all" to get everything
|
||||
func (g *Gemini) GetSymbolDetails(ctx context.Context, symbol string) ([]SymbolDetails, error) {
|
||||
func (e *Exchange) GetSymbolDetails(ctx context.Context, symbol string) ([]SymbolDetails, error) {
|
||||
if symbol == "all" {
|
||||
var details []SymbolDetails
|
||||
return details, g.SendHTTPRequest(ctx, exchange.RestSpot, "/v"+geminiAPIVersion+"/"+geminiSymbolDetails+"/"+symbol, &details)
|
||||
return details, e.SendHTTPRequest(ctx, exchange.RestSpot, "/v"+geminiAPIVersion+"/"+geminiSymbolDetails+"/"+symbol, &details)
|
||||
}
|
||||
var details SymbolDetails
|
||||
err := g.SendHTTPRequest(ctx, exchange.RestSpot, "/v"+geminiAPIVersion+"/"+geminiSymbolDetails+"/"+symbol, &details)
|
||||
err := e.SendHTTPRequest(ctx, exchange.RestSpot, "/v"+geminiAPIVersion+"/"+geminiSymbolDetails+"/"+symbol, &details)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -83,16 +83,16 @@ func (g *Gemini) GetSymbolDetails(ctx context.Context, symbol string) ([]SymbolD
|
||||
}
|
||||
|
||||
// GetTicker returns information about recent trading activity for the symbol
|
||||
func (g *Gemini) GetTicker(ctx context.Context, currencyPair string) (TickerV2, error) {
|
||||
func (e *Exchange) GetTicker(ctx context.Context, currencyPair string) (TickerV2, error) {
|
||||
ticker := TickerV2{}
|
||||
path := "/v2/ticker/" + currencyPair
|
||||
err := g.SendHTTPRequest(ctx, exchange.RestSpot, path, &ticker)
|
||||
err := e.SendHTTPRequest(ctx, exchange.RestSpot, path, &ticker)
|
||||
if err != nil {
|
||||
return ticker, err
|
||||
}
|
||||
if ticker.Result == "error" {
|
||||
return ticker, fmt.Errorf("%v %v %v",
|
||||
g.Name,
|
||||
e.Name,
|
||||
ticker.Reason,
|
||||
ticker.Message)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func (g *Gemini) GetTicker(ctx context.Context, currencyPair string) (TickerV2,
|
||||
//
|
||||
// params - limit_bids or limit_asks [OPTIONAL] default 50, 0 returns all Values
|
||||
// Type is an integer ie "params.Set("limit_asks", 30)"
|
||||
func (g *Gemini) GetOrderbook(ctx context.Context, currencyPair string, params url.Values) (*Orderbook, error) {
|
||||
func (e *Exchange) GetOrderbook(ctx context.Context, currencyPair string, params url.Values) (*Orderbook, error) {
|
||||
path := common.EncodeURLValues(
|
||||
fmt.Sprintf("/v%s/%s/%s",
|
||||
geminiAPIVersion,
|
||||
@@ -114,7 +114,7 @@ func (g *Gemini) GetOrderbook(ctx context.Context, currencyPair string, params u
|
||||
params)
|
||||
|
||||
var orderbook Orderbook
|
||||
return &orderbook, g.SendHTTPRequest(ctx, exchange.RestSpot, path, &orderbook)
|
||||
return &orderbook, e.SendHTTPRequest(ctx, exchange.RestSpot, path, &orderbook)
|
||||
}
|
||||
|
||||
// GetTrades return the trades that have executed since the specified timestamp.
|
||||
@@ -126,7 +126,7 @@ func (g *Gemini) GetOrderbook(ctx context.Context, currencyPair string, params u
|
||||
// limit_trades integer Optional. The maximum number of trades to return.
|
||||
// include_breaks boolean Optional. Whether to display broken trades. False by
|
||||
// default. Can be '1' or 'true' to activate
|
||||
func (g *Gemini) GetTrades(ctx context.Context, currencyPair string, since, limit int64, includeBreaks bool) ([]Trade, error) {
|
||||
func (e *Exchange) GetTrades(ctx context.Context, currencyPair string, since, limit int64, includeBreaks bool) ([]Trade, error) {
|
||||
params := url.Values{}
|
||||
if since > 0 {
|
||||
params.Add("since", strconv.FormatInt(since, 10))
|
||||
@@ -140,15 +140,15 @@ func (g *Gemini) GetTrades(ctx context.Context, currencyPair string, since, limi
|
||||
path := common.EncodeURLValues(fmt.Sprintf("/v%s/%s/%s", geminiAPIVersion, geminiTrades, currencyPair), params)
|
||||
var trades []Trade
|
||||
|
||||
return trades, g.SendHTTPRequest(ctx, exchange.RestSpot, path, &trades)
|
||||
return trades, e.SendHTTPRequest(ctx, exchange.RestSpot, path, &trades)
|
||||
}
|
||||
|
||||
// GetAuction returns auction information
|
||||
func (g *Gemini) GetAuction(ctx context.Context, currencyPair string) (Auction, error) {
|
||||
func (e *Exchange) GetAuction(ctx context.Context, currencyPair string) (Auction, error) {
|
||||
path := fmt.Sprintf("/v%s/%s/%s", geminiAPIVersion, geminiAuction, currencyPair)
|
||||
auction := Auction{}
|
||||
|
||||
return auction, g.SendHTTPRequest(ctx, exchange.RestSpot, path, &auction)
|
||||
return auction, e.SendHTTPRequest(ctx, exchange.RestSpot, path, &auction)
|
||||
}
|
||||
|
||||
// GetAuctionHistory returns the auction events, optionally including
|
||||
@@ -168,15 +168,15 @@ func (g *Gemini) GetAuction(ctx context.Context, currencyPair string) (Auction,
|
||||
// include_indicative - [bool] Whether to include publication of
|
||||
//
|
||||
// indicative prices and quantities.
|
||||
func (g *Gemini) GetAuctionHistory(ctx context.Context, currencyPair string, params url.Values) ([]AuctionHistory, error) {
|
||||
func (e *Exchange) GetAuctionHistory(ctx context.Context, currencyPair string, params url.Values) ([]AuctionHistory, error) {
|
||||
path := common.EncodeURLValues(fmt.Sprintf("/v%s/%s/%s/%s", geminiAPIVersion, geminiAuction, currencyPair, geminiAuctionHistory), params)
|
||||
var auctionHist []AuctionHistory
|
||||
return auctionHist, g.SendHTTPRequest(ctx, exchange.RestSpot, path, &auctionHist)
|
||||
return auctionHist, e.SendHTTPRequest(ctx, exchange.RestSpot, path, &auctionHist)
|
||||
}
|
||||
|
||||
// NewOrder Only limit orders are supported through the API at present.
|
||||
// returns order ID if successful
|
||||
func (g *Gemini) NewOrder(ctx context.Context, symbol string, amount, price float64, side, orderType string) (int64, error) {
|
||||
func (e *Exchange) NewOrder(ctx context.Context, symbol string, amount, price float64, side, orderType string) (int64, error) {
|
||||
req := make(map[string]any)
|
||||
req["symbol"] = symbol
|
||||
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
||||
@@ -185,7 +185,7 @@ func (g *Gemini) NewOrder(ctx context.Context, symbol string, amount, price floa
|
||||
req["type"] = orderType
|
||||
|
||||
response := Order{}
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrderNew, req, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrderNew, req, &response)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -193,7 +193,7 @@ func (g *Gemini) NewOrder(ctx context.Context, symbol string, amount, price floa
|
||||
}
|
||||
|
||||
// Transfers returns transfer history ie withdrawals and deposits
|
||||
func (g *Gemini) Transfers(ctx context.Context, curr currency.Code, start time.Time, limit int64, account string, showCompletedDeposit bool) ([]TransferResponse, error) {
|
||||
func (e *Exchange) Transfers(ctx context.Context, curr currency.Code, start time.Time, limit int64, account string, showCompletedDeposit bool) ([]TransferResponse, error) {
|
||||
req := make(map[string]any)
|
||||
if !curr.IsEmpty() {
|
||||
req["symbol"] = curr.String()
|
||||
@@ -212,17 +212,17 @@ func (g *Gemini) Transfers(ctx context.Context, curr currency.Code, start time.T
|
||||
}
|
||||
|
||||
var response []TransferResponse
|
||||
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiTransfers, req, &response)
|
||||
return response, e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiTransfers, req, &response)
|
||||
}
|
||||
|
||||
// CancelExistingOrder will cancel an order. If the order is already canceled, the
|
||||
// message will succeed but have no effect.
|
||||
func (g *Gemini) CancelExistingOrder(ctx context.Context, orderID int64) (Order, error) {
|
||||
func (e *Exchange) CancelExistingOrder(ctx context.Context, orderID int64) (Order, error) {
|
||||
req := make(map[string]any)
|
||||
req["order_id"] = orderID
|
||||
|
||||
response := Order{}
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrderCancel, req, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrderCancel, req, &response)
|
||||
if err != nil {
|
||||
return Order{}, err
|
||||
}
|
||||
@@ -237,14 +237,14 @@ func (g *Gemini) CancelExistingOrder(ctx context.Context, orderID int64) (Order,
|
||||
// sessions owned by this account, including interactive orders placed through
|
||||
// the UI. If sessions = true will only cancel the order that is called on this
|
||||
// session associated with the APIKEY
|
||||
func (g *Gemini) CancelExistingOrders(ctx context.Context, cancelBySession bool) (OrderResult, error) {
|
||||
func (e *Exchange) CancelExistingOrders(ctx context.Context, cancelBySession bool) (OrderResult, error) {
|
||||
path := geminiOrderCancelAll
|
||||
if cancelBySession {
|
||||
path = geminiOrderCancelSession
|
||||
}
|
||||
|
||||
var response OrderResult
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, path, nil, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, path, nil, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -255,13 +255,13 @@ func (g *Gemini) CancelExistingOrders(ctx context.Context, cancelBySession bool)
|
||||
}
|
||||
|
||||
// GetOrderStatus returns the status for an order
|
||||
func (g *Gemini) GetOrderStatus(ctx context.Context, orderID int64) (Order, error) {
|
||||
func (e *Exchange) GetOrderStatus(ctx context.Context, orderID int64) (Order, error) {
|
||||
req := make(map[string]any)
|
||||
req["order_id"] = orderID
|
||||
|
||||
response := Order{}
|
||||
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrderStatus, req, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrderStatus, req, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -273,14 +273,14 @@ func (g *Gemini) GetOrderStatus(ctx context.Context, orderID int64) (Order, erro
|
||||
}
|
||||
|
||||
// GetOrders returns active orders in the market
|
||||
func (g *Gemini) GetOrders(ctx context.Context) ([]Order, error) {
|
||||
func (e *Exchange) GetOrders(ctx context.Context) ([]Order, error) {
|
||||
var response any
|
||||
|
||||
type orders struct {
|
||||
orders []Order
|
||||
}
|
||||
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrders, nil, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiOrders, nil, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func (g *Gemini) GetOrders(ctx context.Context) ([]Order, error) {
|
||||
//
|
||||
// currencyPair - example "btcusd"
|
||||
// timestamp - [optional] Only return trades on or after this timestamp.
|
||||
func (g *Gemini) GetTradeHistory(ctx context.Context, currencyPair string, timestamp int64) ([]TradeHistory, error) {
|
||||
func (e *Exchange) GetTradeHistory(ctx context.Context, currencyPair string, timestamp int64) ([]TradeHistory, error) {
|
||||
var response []TradeHistory
|
||||
req := make(map[string]any)
|
||||
req["symbol"] = currencyPair
|
||||
@@ -307,35 +307,35 @@ func (g *Gemini) GetTradeHistory(ctx context.Context, currencyPair string, times
|
||||
}
|
||||
|
||||
return response,
|
||||
g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiMyTrades, req, &response)
|
||||
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiMyTrades, req, &response)
|
||||
}
|
||||
|
||||
// GetNotionalVolume returns the volume in price currency that has been traded across all pairs over a period of 30 days
|
||||
func (g *Gemini) GetNotionalVolume(ctx context.Context) (NotionalVolume, error) {
|
||||
func (e *Exchange) GetNotionalVolume(ctx context.Context) (NotionalVolume, error) {
|
||||
response := NotionalVolume{}
|
||||
|
||||
return response,
|
||||
g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiVolume, nil, &response)
|
||||
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiVolume, nil, &response)
|
||||
}
|
||||
|
||||
// GetTradeVolume returns a multi-arrayed volume response
|
||||
func (g *Gemini) GetTradeVolume(ctx context.Context) ([][]TradeVolume, error) {
|
||||
func (e *Exchange) GetTradeVolume(ctx context.Context) ([][]TradeVolume, error) {
|
||||
var response [][]TradeVolume
|
||||
|
||||
return response,
|
||||
g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiTradeVolume, nil, &response)
|
||||
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiTradeVolume, nil, &response)
|
||||
}
|
||||
|
||||
// GetBalances returns available balances in the supported currencies
|
||||
func (g *Gemini) GetBalances(ctx context.Context) ([]Balance, error) {
|
||||
func (e *Exchange) GetBalances(ctx context.Context) ([]Balance, error) {
|
||||
var response []Balance
|
||||
|
||||
return response,
|
||||
g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiBalances, nil, &response)
|
||||
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiBalances, nil, &response)
|
||||
}
|
||||
|
||||
// GetCryptoDepositAddress returns a deposit address
|
||||
func (g *Gemini) GetCryptoDepositAddress(ctx context.Context, depositAddlabel, currency string) (DepositAddress, error) {
|
||||
func (e *Exchange) GetCryptoDepositAddress(ctx context.Context, depositAddlabel, currency string) (DepositAddress, error) {
|
||||
response := DepositAddress{}
|
||||
req := make(map[string]any)
|
||||
|
||||
@@ -343,7 +343,7 @@ func (g *Gemini) GetCryptoDepositAddress(ctx context.Context, depositAddlabel, c
|
||||
req["label"] = depositAddlabel
|
||||
}
|
||||
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiDeposit+"/"+currency+"/"+geminiNewAddress, req, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiDeposit+"/"+currency+"/"+geminiNewAddress, req, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -354,13 +354,13 @@ func (g *Gemini) GetCryptoDepositAddress(ctx context.Context, depositAddlabel, c
|
||||
}
|
||||
|
||||
// WithdrawCrypto withdraws crypto currency to a whitelisted address
|
||||
func (g *Gemini) WithdrawCrypto(ctx context.Context, address, currency string, amount float64) (WithdrawalAddress, error) {
|
||||
func (e *Exchange) WithdrawCrypto(ctx context.Context, address, currency string, amount float64) (WithdrawalAddress, error) {
|
||||
response := WithdrawalAddress{}
|
||||
req := make(map[string]any)
|
||||
req["address"] = address
|
||||
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
||||
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiWithdraw+strings.ToLower(currency), req, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiWithdraw+strings.ToLower(currency), req, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -372,14 +372,14 @@ func (g *Gemini) WithdrawCrypto(ctx context.Context, address, currency string, a
|
||||
|
||||
// PostHeartbeat sends a maintenance heartbeat to the exchange for all heartbeat
|
||||
// maintained sessions
|
||||
func (g *Gemini) PostHeartbeat(ctx context.Context) (string, error) {
|
||||
func (e *Exchange) PostHeartbeat(ctx context.Context) (string, error) {
|
||||
type Response struct {
|
||||
Result string `json:"result"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
response := Response{}
|
||||
|
||||
err := g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiHeartbeat, nil, &response)
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, geminiHeartbeat, nil, &response)
|
||||
if err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
@@ -390,8 +390,8 @@ func (g *Gemini) PostHeartbeat(ctx context.Context) (string, error) {
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (g *Gemini) SendHTTPRequest(ctx context.Context, ep exchange.URL, path string, result any) error {
|
||||
endpoint, err := g.API.Endpoints.GetURL(ep)
|
||||
func (e *Exchange) SendHTTPRequest(ctx context.Context, ep exchange.URL, path string, result any) error {
|
||||
endpoint, err := e.API.Endpoints.GetURL(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -400,33 +400,33 @@ func (g *Gemini) SendHTTPRequest(ctx context.Context, ep exchange.URL, path stri
|
||||
Method: http.MethodGet,
|
||||
Path: endpoint + path,
|
||||
Result: result,
|
||||
Verbose: g.Verbose,
|
||||
HTTPDebugging: g.HTTPDebugging,
|
||||
HTTPRecording: g.HTTPRecording,
|
||||
Verbose: e.Verbose,
|
||||
HTTPDebugging: e.HTTPDebugging,
|
||||
HTTPRecording: e.HTTPRecording,
|
||||
}
|
||||
|
||||
return g.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) {
|
||||
return e.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) {
|
||||
return item, nil
|
||||
}, request.UnauthenticatedRequest)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the
|
||||
// exchange and returns an error
|
||||
func (g *Gemini) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL, method, path string, params map[string]any, result any) (err error) {
|
||||
creds, err := g.GetCredentials(ctx)
|
||||
func (e *Exchange) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL, method, path string, params map[string]any, result any) (err error) {
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint, err := g.API.Endpoints.GetURL(ep)
|
||||
endpoint, err := e.API.Endpoints.GetURL(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return g.SendPayload(ctx, request.Auth, func() (*request.Item, error) {
|
||||
return e.SendPayload(ctx, request.Auth, func() (*request.Item, error) {
|
||||
req := make(map[string]any)
|
||||
req["request"] = fmt.Sprintf("/v%s/%s", geminiAPIVersion, path)
|
||||
req["nonce"] = g.Requester.GetNonce(nonce.UnixNano).String()
|
||||
req["nonce"] = e.Requester.GetNonce(nonce.UnixNano).String()
|
||||
|
||||
maps.Copy(req, params)
|
||||
|
||||
@@ -455,19 +455,19 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.U
|
||||
Headers: headers,
|
||||
Result: result,
|
||||
NonceEnabled: true,
|
||||
Verbose: g.Verbose,
|
||||
HTTPDebugging: g.HTTPDebugging,
|
||||
HTTPRecording: g.HTTPRecording,
|
||||
Verbose: e.Verbose,
|
||||
HTTPDebugging: e.HTTPDebugging,
|
||||
HTTPRecording: e.HTTPRecording,
|
||||
}, nil
|
||||
}, request.AuthenticatedRequest)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
func (g *Gemini) GetFee(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
func (e *Exchange) GetFee(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
var fee float64
|
||||
switch feeBuilder.FeeType {
|
||||
case exchange.CryptocurrencyTradeFee:
|
||||
notionVolume, err := g.GetNotionalVolume(ctx)
|
||||
notionVolume, err := e.GetNotionalVolume(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@ import (
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
g = new(Gemini)
|
||||
if err := testexch.Setup(g); err != nil {
|
||||
e = new(Exchange)
|
||||
if err := testexch.Setup(e); err != nil {
|
||||
log.Fatalf("Gemini Setup error: %s", err)
|
||||
}
|
||||
if apiKey != "" && apiSecret != "" {
|
||||
g.API.AuthenticatedSupport = true
|
||||
g.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
}
|
||||
if err := g.API.Endpoints.SetRunningURL(exchange.RestSpot.String(), geminiAPIURL); err != nil {
|
||||
if err := e.API.Endpoints.SetRunningURL(exchange.RestSpot.String(), geminiAPIURL); err != nil {
|
||||
log.Fatalf("Gemini SetRunningURL error: %s", err)
|
||||
}
|
||||
log.Printf(sharedtestvalues.LiveTesting, g.Name)
|
||||
log.Printf(sharedtestvalues.LiveTesting, e.Name)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ import (
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
g = new(Gemini)
|
||||
if err := testexch.Setup(g); err != nil {
|
||||
e = new(Exchange)
|
||||
if err := testexch.Setup(e); err != nil {
|
||||
log.Fatalf("Gemini Setup error: %s", err)
|
||||
}
|
||||
|
||||
if err := testexch.MockHTTPInstance(g); err != nil {
|
||||
if err := testexch.MockHTTPInstance(e); err != nil {
|
||||
log.Fatalf("Gemini MockHTTPInstance error: %s", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ const (
|
||||
|
||||
const testCurrency = "btcusd"
|
||||
|
||||
var g = &Gemini{}
|
||||
var e *Exchange
|
||||
|
||||
func TestGetSymbols(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetSymbols(t.Context())
|
||||
_, err := e.GetSymbols(t.Context())
|
||||
if err != nil {
|
||||
t.Error("GetSymbols() error", err)
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func TestGetSymbols(t *testing.T) {
|
||||
|
||||
func TestFetchTradablePairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
pairs, err := g.FetchTradablePairs(t.Context(), asset.Spot)
|
||||
pairs, err := e.FetchTradablePairs(t.Context(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -62,11 +62,11 @@ func TestFetchTradablePairs(t *testing.T) {
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetTicker(t.Context(), "BTCUSD")
|
||||
_, err := e.GetTicker(t.Context(), "BTCUSD")
|
||||
if err != nil {
|
||||
t.Error("GetTicker() error", err)
|
||||
}
|
||||
_, err = g.GetTicker(t.Context(), "bla")
|
||||
_, err = e.GetTicker(t.Context(), "bla")
|
||||
if err == nil {
|
||||
t.Error("GetTicker() Expected error")
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func TestGetTicker(t *testing.T) {
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetOrderbook(t.Context(), testCurrency, url.Values{})
|
||||
_, err := e.GetOrderbook(t.Context(), testCurrency, url.Values{})
|
||||
if err != nil {
|
||||
t.Error("GetOrderbook() error", err)
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func TestGetOrderbook(t *testing.T) {
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetTrades(t.Context(), testCurrency, 0, 0, false)
|
||||
_, err := e.GetTrades(t.Context(), testCurrency, 0, 0, false)
|
||||
if err != nil {
|
||||
t.Error("GetTrades() error", err)
|
||||
}
|
||||
@@ -90,7 +90,7 @@ func TestGetTrades(t *testing.T) {
|
||||
|
||||
func TestGetNotionalVolume(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetNotionalVolume(t.Context())
|
||||
_, err := e.GetNotionalVolume(t.Context())
|
||||
if err != nil && mockTests {
|
||||
t.Error("GetNotionalVolume() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -100,7 +100,7 @@ func TestGetNotionalVolume(t *testing.T) {
|
||||
|
||||
func TestGetAuction(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetAuction(t.Context(), testCurrency)
|
||||
_, err := e.GetAuction(t.Context(), testCurrency)
|
||||
if err != nil {
|
||||
t.Error("GetAuction() error", err)
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func TestGetAuction(t *testing.T) {
|
||||
|
||||
func TestGetAuctionHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetAuctionHistory(t.Context(), testCurrency, url.Values{})
|
||||
_, err := e.GetAuctionHistory(t.Context(), testCurrency, url.Values{})
|
||||
if err != nil {
|
||||
t.Error("GetAuctionHistory() error", err)
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func TestGetAuctionHistory(t *testing.T) {
|
||||
|
||||
func TestNewOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.NewOrder(t.Context(),
|
||||
_, err := e.NewOrder(t.Context(),
|
||||
testCurrency,
|
||||
1,
|
||||
9000000,
|
||||
@@ -131,7 +131,7 @@ func TestNewOrder(t *testing.T) {
|
||||
|
||||
func TestCancelExistingOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.CancelExistingOrder(t.Context(), 265555413)
|
||||
_, err := e.CancelExistingOrder(t.Context(), 265555413)
|
||||
if err != nil && mockTests {
|
||||
t.Error("CancelExistingOrder() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -141,7 +141,7 @@ func TestCancelExistingOrder(t *testing.T) {
|
||||
|
||||
func TestCancelExistingOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.CancelExistingOrders(t.Context(), false)
|
||||
_, err := e.CancelExistingOrders(t.Context(), false)
|
||||
if err != nil && mockTests {
|
||||
t.Error("CancelExistingOrders() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -151,7 +151,7 @@ func TestCancelExistingOrders(t *testing.T) {
|
||||
|
||||
func TestGetOrderStatus(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetOrderStatus(t.Context(), 265563260)
|
||||
_, err := e.GetOrderStatus(t.Context(), 265563260)
|
||||
if err != nil && mockTests {
|
||||
t.Error("GetOrderStatus() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -161,7 +161,7 @@ func TestGetOrderStatus(t *testing.T) {
|
||||
|
||||
func TestGetOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetOrders(t.Context())
|
||||
_, err := e.GetOrders(t.Context())
|
||||
if err != nil && mockTests {
|
||||
t.Error("GetOrders() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -171,7 +171,7 @@ func TestGetOrders(t *testing.T) {
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetTradeHistory(t.Context(), testCurrency, 0)
|
||||
_, err := e.GetTradeHistory(t.Context(), testCurrency, 0)
|
||||
if err != nil && mockTests {
|
||||
t.Error("GetTradeHistory() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -181,7 +181,7 @@ func TestGetTradeHistory(t *testing.T) {
|
||||
|
||||
func TestGetTradeVolume(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetTradeVolume(t.Context())
|
||||
_, err := e.GetTradeVolume(t.Context())
|
||||
if err != nil && mockTests {
|
||||
t.Error("GetTradeVolume() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -191,7 +191,7 @@ func TestGetTradeVolume(t *testing.T) {
|
||||
|
||||
func TestGetBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetBalances(t.Context())
|
||||
_, err := e.GetBalances(t.Context())
|
||||
if err != nil && mockTests {
|
||||
t.Error("GetBalances() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -201,7 +201,7 @@ func TestGetBalances(t *testing.T) {
|
||||
|
||||
func TestGetCryptoDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetCryptoDepositAddress(t.Context(), "LOL123", "btc")
|
||||
_, err := e.GetCryptoDepositAddress(t.Context(), "LOL123", "btc")
|
||||
if err == nil {
|
||||
t.Error("GetCryptoDepositAddress() Expected error")
|
||||
}
|
||||
@@ -209,7 +209,7 @@ func TestGetCryptoDepositAddress(t *testing.T) {
|
||||
|
||||
func TestWithdrawCrypto(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.WithdrawCrypto(t.Context(), "LOL123", "btc", 1)
|
||||
_, err := e.WithdrawCrypto(t.Context(), "LOL123", "btc", 1)
|
||||
if err == nil {
|
||||
t.Error("WithdrawCrypto() Expected error")
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func TestWithdrawCrypto(t *testing.T) {
|
||||
|
||||
func TestPostHeartbeat(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.PostHeartbeat(t.Context())
|
||||
_, err := e.PostHeartbeat(t.Context())
|
||||
if err != nil && mockTests {
|
||||
t.Error("PostHeartbeat() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
@@ -242,11 +242,11 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
feeBuilder := setFeeBuilder()
|
||||
_, err := g.GetFeeByType(t.Context(), feeBuilder)
|
||||
_, err := e.GetFeeByType(t.Context(), feeBuilder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !sharedtestvalues.AreAPICredentialsSet(g) {
|
||||
if !sharedtestvalues.AreAPICredentialsSet(e) {
|
||||
if feeBuilder.FeeType != exchange.OfflineTradeFee {
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.OfflineTradeFee,
|
||||
@@ -264,9 +264,9 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
func TestGetFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
feeBuilder := setFeeBuilder()
|
||||
if sharedtestvalues.AreAPICredentialsSet(g) || mockTests {
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) || mockTests {
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -274,28 +274,28 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Amount = 1000
|
||||
feeBuilder.PurchasePrice = 1000
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee IsMaker
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.IsMaker = true
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee Negative purchase price
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// CryptocurrencyWithdrawalFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -303,21 +303,21 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Pair.Base = currency.NewCode("hello")
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyDepositFee
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// InternationalBankDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
feeBuilder.FiatCurrency = currency.USD
|
||||
if _, err := g.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -337,7 +337,7 @@ func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
exchange.AutoWithdrawCryptoWithSetupText +
|
||||
" & " +
|
||||
exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
withdrawPermissions := g.FormatWithdrawPermissions()
|
||||
withdrawPermissions := e.FormatWithdrawPermissions()
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s",
|
||||
expectedResult,
|
||||
@@ -356,11 +356,11 @@ func TestGetActiveOrders(t *testing.T) {
|
||||
Side: order.AnySide,
|
||||
}
|
||||
|
||||
_, err := g.GetActiveOrders(t.Context(), &getOrdersRequest)
|
||||
_, err := e.GetActiveOrders(t.Context(), &getOrdersRequest)
|
||||
switch {
|
||||
case sharedtestvalues.AreAPICredentialsSet(g) && err != nil && !mockTests:
|
||||
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil && !mockTests:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
case !sharedtestvalues.AreAPICredentialsSet(g) && err == nil && !mockTests:
|
||||
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
@@ -376,11 +376,11 @@ func TestGetOrderHistory(t *testing.T) {
|
||||
Side: order.AnySide,
|
||||
}
|
||||
|
||||
_, err := g.GetOrderHistory(t.Context(), &getOrdersRequest)
|
||||
_, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
||||
switch {
|
||||
case sharedtestvalues.AreAPICredentialsSet(g) && err != nil:
|
||||
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
case !sharedtestvalues.AreAPICredentialsSet(g) && err == nil && !mockTests:
|
||||
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case err != nil && mockTests:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
@@ -392,11 +392,11 @@ func TestGetOrderHistory(t *testing.T) {
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
}
|
||||
|
||||
orderSubmission := &order.Submit{
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Pair: currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.LTC,
|
||||
@@ -410,11 +410,11 @@ func TestSubmitOrder(t *testing.T) {
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
|
||||
response, err := g.SubmitOrder(t.Context(), orderSubmission)
|
||||
response, err := e.SubmitOrder(t.Context(), orderSubmission)
|
||||
switch {
|
||||
case sharedtestvalues.AreAPICredentialsSet(g) && (err != nil || response.Status != order.New):
|
||||
case sharedtestvalues.AreAPICredentialsSet(e) && (err != nil || response.Status != order.New):
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
case !sharedtestvalues.AreAPICredentialsSet(g) && err == nil && !mockTests:
|
||||
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
@@ -424,7 +424,7 @@ func TestSubmitOrder(t *testing.T) {
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
}
|
||||
orderCancellation := &order.Cancel{
|
||||
OrderID: "266029865",
|
||||
@@ -432,11 +432,11 @@ func TestCancelExchangeOrder(t *testing.T) {
|
||||
Pair: currency.NewBTCUSDT(),
|
||||
}
|
||||
|
||||
err := g.CancelOrder(t.Context(), orderCancellation)
|
||||
err := e.CancelOrder(t.Context(), orderCancellation)
|
||||
switch {
|
||||
case !sharedtestvalues.AreAPICredentialsSet(g) && err == nil && !mockTests:
|
||||
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case sharedtestvalues.AreAPICredentialsSet(g) && err != nil:
|
||||
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case err != nil && mockTests:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
@@ -446,7 +446,7 @@ func TestCancelExchangeOrder(t *testing.T) {
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
@@ -457,11 +457,11 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
|
||||
resp, err := g.CancelAllOrders(t.Context(), orderCancellation)
|
||||
resp, err := e.CancelAllOrders(t.Context(), orderCancellation)
|
||||
switch {
|
||||
case !sharedtestvalues.AreAPICredentialsSet(g) && err == nil && !mockTests:
|
||||
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case sharedtestvalues.AreAPICredentialsSet(g) && err != nil:
|
||||
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
@@ -474,9 +474,9 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
|
||||
_, err := g.ModifyOrder(t.Context(), &order.Modify{AssetType: asset.Spot})
|
||||
_, err := e.ModifyOrder(t.Context(), &order.Modify{AssetType: asset.Spot})
|
||||
if err == nil {
|
||||
t.Error("ModifyOrder() Expected error")
|
||||
}
|
||||
@@ -486,12 +486,12 @@ func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
}
|
||||
|
||||
_, err := g.WithdrawCryptocurrencyFunds(t.Context(),
|
||||
_, err := e.WithdrawCryptocurrencyFunds(t.Context(),
|
||||
&withdraw.Request{
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
@@ -499,13 +499,13 @@ func TestWithdraw(t *testing.T) {
|
||||
Address: core.BitcoinDonationAddress,
|
||||
},
|
||||
})
|
||||
if !sharedtestvalues.AreAPICredentialsSet(g) && err == nil {
|
||||
if !sharedtestvalues.AreAPICredentialsSet(e) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if sharedtestvalues.AreAPICredentialsSet(g) && err != nil && !mockTests {
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err != nil && !mockTests {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
}
|
||||
if sharedtestvalues.AreAPICredentialsSet(g) && err == nil && mockTests {
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err == nil && mockTests {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -513,11 +513,11 @@ func TestWithdraw(t *testing.T) {
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
}
|
||||
|
||||
withdrawFiatRequest := withdraw.Request{}
|
||||
_, err := g.WithdrawFiatFunds(t.Context(), &withdrawFiatRequest)
|
||||
_, err := e.WithdrawFiatFunds(t.Context(), &withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
@@ -528,11 +528,11 @@ func TestWithdrawFiat(t *testing.T) {
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, g, canManipulateRealOrders)
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
}
|
||||
|
||||
withdrawFiatRequest := withdraw.Request{}
|
||||
_, err := g.WithdrawFiatFundsToInternationalBank(t.Context(),
|
||||
_, err := e.WithdrawFiatFundsToInternationalBank(t.Context(),
|
||||
&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
@@ -543,7 +543,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetDepositAddress(t.Context(), currency.BTC, "", "")
|
||||
_, err := e.GetDepositAddress(t.Context(), currency.BTC, "", "")
|
||||
if err == nil {
|
||||
t.Error("GetDepositAddress error cannot be nil")
|
||||
}
|
||||
@@ -552,24 +552,24 @@ func TestGetDepositAddress(t *testing.T) {
|
||||
// TestWsAuth dials websocket, sends login request.
|
||||
func TestWsAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := g.API.Endpoints.SetRunningURL(exchange.WebsocketSpot.String(), geminiWebsocketSandboxEndpoint)
|
||||
err := e.API.Endpoints.SetRunningURL(exchange.WebsocketSpot.String(), geminiWebsocketSandboxEndpoint)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !g.Websocket.IsEnabled() &&
|
||||
!g.API.AuthenticatedWebsocketSupport ||
|
||||
!sharedtestvalues.AreAPICredentialsSet(g) {
|
||||
if !e.Websocket.IsEnabled() &&
|
||||
!e.API.AuthenticatedWebsocketSupport ||
|
||||
!sharedtestvalues.AreAPICredentialsSet(e) {
|
||||
t.Skip(websocket.ErrWebsocketNotEnabled.Error())
|
||||
}
|
||||
var dialer gws.Dialer
|
||||
go g.wsReadData()
|
||||
err = g.WsAuth(t.Context(), &dialer)
|
||||
go e.wsReadData()
|
||||
err = e.WsAuth(t.Context(), &dialer)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-g.Websocket.DataHandler:
|
||||
case resp := <-e.Websocket.DataHandler:
|
||||
subAck, ok := resp.(WsSubscriptionAcknowledgementResponse)
|
||||
if !ok {
|
||||
t.Error("unable to type assert WsSubscriptionAcknowledgementResponse")
|
||||
@@ -589,7 +589,7 @@ func TestWsMissingRole(t *testing.T) {
|
||||
"reason":"MissingRole",
|
||||
"message":"To access this endpoint, you need to log in to the website and go to the settings page to assign one of these roles [FundManager] to API key wujB3szN54gtJ4QDhqRJ which currently has roles [Trader]"
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err == nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err == nil {
|
||||
t.Error("Expected error")
|
||||
}
|
||||
}
|
||||
@@ -613,7 +613,7 @@ func TestWsOrderEventSubscriptionResponse(t *testing.T) {
|
||||
"original_amount" : "14.0296",
|
||||
"price" : "1059.54"
|
||||
} ]`)
|
||||
err := g.wsHandleData(pressXToJSON)
|
||||
err := e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -635,7 +635,7 @@ func TestWsOrderEventSubscriptionResponse(t *testing.T) {
|
||||
"price": "3592.00",
|
||||
"socket_sequence": 13
|
||||
}]`)
|
||||
err = g.wsHandleData(pressXToJSON)
|
||||
err = e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -656,7 +656,7 @@ func TestWsOrderEventSubscriptionResponse(t *testing.T) {
|
||||
"total_spend": "200.00",
|
||||
"socket_sequence": 29
|
||||
}]`)
|
||||
err = g.wsHandleData(pressXToJSON)
|
||||
err = e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -677,7 +677,7 @@ func TestWsOrderEventSubscriptionResponse(t *testing.T) {
|
||||
"original_amount": "25",
|
||||
"socket_sequence": 26
|
||||
}]`)
|
||||
err = g.wsHandleData(pressXToJSON)
|
||||
err = e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -699,7 +699,7 @@ func TestWsOrderEventSubscriptionResponse(t *testing.T) {
|
||||
"original_amount" : "500",
|
||||
"socket_sequence" : 32307
|
||||
} ]`)
|
||||
err = g.wsHandleData(pressXToJSON)
|
||||
err = e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -721,7 +721,7 @@ func TestWsSubAck(t *testing.T) {
|
||||
"closed"
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -734,7 +734,7 @@ func TestWsHeartbeat(t *testing.T) {
|
||||
"trace_id": "b8biknoqppr32kc7gfgg",
|
||||
"socket_sequence": 37
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -755,7 +755,7 @@ func TestWsUnsubscribe(t *testing.T) {
|
||||
]}
|
||||
]
|
||||
}`)
|
||||
err := g.wsHandleData(pressXToJSON)
|
||||
err := e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -778,7 +778,7 @@ func TestWsTradeData(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -810,7 +810,7 @@ func TestWsAuctionData(t *testing.T) {
|
||||
],
|
||||
"type": "update"
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -831,7 +831,7 @@ func TestWsBlockTrade(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -846,7 +846,7 @@ func TestWSTrade(t *testing.T) {
|
||||
"quantity": "0.09110000",
|
||||
"side": "buy"
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -874,7 +874,7 @@ func TestWsCandles(t *testing.T) {
|
||||
]
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -896,7 +896,7 @@ func TestWsAuctions(t *testing.T) {
|
||||
],
|
||||
"type": "update"
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -920,7 +920,7 @@ func TestWsAuctions(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -951,7 +951,7 @@ func TestWsAuctions(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -980,7 +980,7 @@ func TestWsMarketData(t *testing.T) {
|
||||
}
|
||||
]
|
||||
} `)
|
||||
err := g.wsHandleData(pressXToJSON)
|
||||
err := e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1008,7 +1008,7 @@ func TestWsMarketData(t *testing.T) {
|
||||
}
|
||||
]
|
||||
} `)
|
||||
err = g.wsHandleData(pressXToJSON)
|
||||
err = e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1030,7 +1030,7 @@ func TestWsMarketData(t *testing.T) {
|
||||
}
|
||||
]
|
||||
} `)
|
||||
err = g.wsHandleData(pressXToJSON)
|
||||
err = e.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1068,7 +1068,7 @@ func TestWsError(t *testing.T) {
|
||||
}
|
||||
|
||||
for x := range tt {
|
||||
err := g.wsHandleData(tt[x].Data)
|
||||
err := e.wsHandleData(tt[x].Data)
|
||||
if tt[x].ErrorExpected && err != nil && !strings.Contains(err.Error(), tt[x].ErrorShouldContain) {
|
||||
t.Errorf("expected error to contain: %s, got: %s",
|
||||
tt[x].ErrorShouldContain, err.Error(),
|
||||
@@ -1128,7 +1128,7 @@ func TestWsLevel2Update(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
if err := g.wsHandleData(pressXToJSON); err != nil {
|
||||
if err := e.wsHandleData(pressXToJSON); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -1183,7 +1183,7 @@ func TestGetRecentTrades(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = g.GetRecentTrades(t.Context(), currencyPair, asset.Spot)
|
||||
_, err = e.GetRecentTrades(t.Context(), currencyPair, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1201,7 +1201,7 @@ func TestGetHistoricTrades(t *testing.T) {
|
||||
tStart = time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.UTC)
|
||||
tEnd = time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 15, 0, 0, time.UTC)
|
||||
}
|
||||
_, err = g.GetHistoricTrades(t.Context(),
|
||||
_, err = e.GetHistoricTrades(t.Context(),
|
||||
currencyPair, asset.Spot, tStart, tEnd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -1210,9 +1210,9 @@ func TestGetHistoricTrades(t *testing.T) {
|
||||
|
||||
func TestTransfers(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, g)
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := g.Transfers(t.Context(), currency.BTC, time.Time{}, 100, "", true)
|
||||
_, err := e.Transfers(t.Context(), currency.BTC, time.Time{}, 100, "", true)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1220,9 +1220,9 @@ func TestTransfers(t *testing.T) {
|
||||
|
||||
func TestGetAccountFundingHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, g)
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := g.GetAccountFundingHistory(t.Context())
|
||||
_, err := e.GetAccountFundingHistory(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1230,9 +1230,9 @@ func TestGetAccountFundingHistory(t *testing.T) {
|
||||
|
||||
func TestGetWithdrawalsHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, g)
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := g.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Spot)
|
||||
_, err := e.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1240,9 +1240,9 @@ func TestGetWithdrawalsHistory(t *testing.T) {
|
||||
|
||||
func TestGetOrderInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, g)
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := g.GetOrderInfo(t.Context(), "1234", currency.EMPTYPAIR, asset.Empty)
|
||||
_, err := e.GetOrderInfo(t.Context(), "1234", currency.EMPTYPAIR, asset.Empty)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1250,11 +1250,11 @@ func TestGetOrderInfo(t *testing.T) {
|
||||
|
||||
func TestGetSymbolDetails(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetSymbolDetails(t.Context(), "all")
|
||||
_, err := e.GetSymbolDetails(t.Context(), "all")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = g.GetSymbolDetails(t.Context(), "btcusd")
|
||||
_, err = e.GetSymbolDetails(t.Context(), "btcusd")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1262,18 +1262,18 @@ func TestGetSymbolDetails(t *testing.T) {
|
||||
|
||||
func TestSetExchangeOrderExecutionLimits(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := g.UpdateOrderExecutionLimits(t.Context(), asset.Spot)
|
||||
err := e.UpdateOrderExecutionLimits(t.Context(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = g.UpdateOrderExecutionLimits(t.Context(), asset.Futures)
|
||||
err = e.UpdateOrderExecutionLimits(t.Context(), asset.Futures)
|
||||
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
||||
|
||||
availPairs, err := g.GetAvailablePairs(asset.Spot)
|
||||
availPairs, err := e.GetAvailablePairs(asset.Spot)
|
||||
require.NoError(t, err)
|
||||
for x := range availPairs {
|
||||
var limit order.MinMaxLevel
|
||||
limit, err = g.GetOrderExecutionLimits(asset.Spot, availPairs[x])
|
||||
limit, err = e.GetOrderExecutionLimits(asset.Spot, availPairs[x])
|
||||
if err != nil {
|
||||
t.Fatal(err, availPairs[x])
|
||||
}
|
||||
@@ -1285,12 +1285,12 @@ func TestSetExchangeOrderExecutionLimits(t *testing.T) {
|
||||
|
||||
func TestGetCurrencyTradeURL(t *testing.T) {
|
||||
t.Parallel()
|
||||
testexch.UpdatePairsOnce(t, g)
|
||||
for _, a := range g.GetAssetTypes(false) {
|
||||
pairs, err := g.CurrencyPairs.GetPairs(a, false)
|
||||
testexch.UpdatePairsOnce(t, e)
|
||||
for _, a := range e.GetAssetTypes(false) {
|
||||
pairs, err := e.CurrencyPairs.GetPairs(a, false)
|
||||
require.NoErrorf(t, err, "cannot get pairs for %s", a)
|
||||
require.NotEmptyf(t, pairs, "no pairs for %s", a)
|
||||
resp, err := g.GetCurrencyTradeURL(t.Context(), a, pairs[0])
|
||||
resp, err := e.GetCurrencyTradeURL(t.Context(), a, pairs[0])
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
@@ -1298,12 +1298,12 @@ func TestGetCurrencyTradeURL(t *testing.T) {
|
||||
|
||||
func TestGenerateSubscriptions(t *testing.T) {
|
||||
t.Parallel()
|
||||
g := new(Gemini)
|
||||
require.NoError(t, testexch.Setup(g), "Test instance Setup must not error")
|
||||
e := new(Exchange)
|
||||
require.NoError(t, testexch.Setup(e), "Test instance Setup must not error")
|
||||
p := currency.Pairs{currency.NewPairWithDelimiter("BTC", "USD", ""), currency.NewPairWithDelimiter("ETH", "BTC", "")}
|
||||
require.NoError(t, g.CurrencyPairs.StorePairs(asset.Spot, p, false))
|
||||
require.NoError(t, g.CurrencyPairs.StorePairs(asset.Spot, p, true))
|
||||
subs, err := g.generateSubscriptions()
|
||||
require.NoError(t, e.CurrencyPairs.StorePairs(asset.Spot, p, false))
|
||||
require.NoError(t, e.CurrencyPairs.StorePairs(asset.Spot, p, true))
|
||||
subs, err := e.generateSubscriptions()
|
||||
require.NoError(t, err)
|
||||
exp := subscription.List{
|
||||
{Asset: asset.Spot, Channel: subscription.CandlesChannel, Pairs: p, QualifiedChannel: "candles_1d", Interval: kline.OneDay},
|
||||
@@ -1312,12 +1312,12 @@ func TestGenerateSubscriptions(t *testing.T) {
|
||||
testsubs.EqualLists(t, exp, subs)
|
||||
|
||||
for _, i := range []kline.Interval{kline.OneMin, kline.FiveMin, kline.FifteenMin, kline.ThirtyMin, kline.OneHour, kline.SixHour} {
|
||||
subs, err = subscription.List{{Asset: asset.Spot, Channel: subscription.CandlesChannel, Pairs: p, Interval: i}}.ExpandTemplates(g)
|
||||
subs, err = subscription.List{{Asset: asset.Spot, Channel: subscription.CandlesChannel, Pairs: p, Interval: i}}.ExpandTemplates(e)
|
||||
assert.NoErrorf(t, err, "ExpandTemplates should not error on interval %s", i)
|
||||
require.NotEmpty(t, subs)
|
||||
assert.Equal(t, "candles_"+i.Short(), subs[0].QualifiedChannel)
|
||||
}
|
||||
_, err = subscription.List{{Asset: asset.Spot, Channel: subscription.CandlesChannel, Pairs: p, Interval: kline.FourHour}}.ExpandTemplates(g)
|
||||
_, err = subscription.List{{Asset: asset.Spot, Channel: subscription.CandlesChannel, Pairs: p, Interval: kline.FourHour}}.ExpandTemplates(e)
|
||||
assert.ErrorIs(t, err, kline.ErrUnsupportedInterval, "ExpandTemplates should error on invalid interval")
|
||||
|
||||
assert.PanicsWithError(t,
|
||||
|
||||
@@ -58,39 +58,39 @@ var subscriptionNames = map[string]string{
|
||||
var comms = make(chan websocket.Response)
|
||||
|
||||
// WsConnect initiates a websocket connection
|
||||
func (g *Gemini) WsConnect() error {
|
||||
func (e *Exchange) WsConnect() error {
|
||||
ctx := context.TODO()
|
||||
if !g.Websocket.IsEnabled() || !g.IsEnabled() {
|
||||
if !e.Websocket.IsEnabled() || !e.IsEnabled() {
|
||||
return websocket.ErrWebsocketNotEnabled
|
||||
}
|
||||
|
||||
var dialer gws.Dialer
|
||||
err := g.Websocket.Conn.Dial(ctx, &dialer, http.Header{})
|
||||
err := e.Websocket.Conn.Dial(ctx, &dialer, http.Header{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.Websocket.Wg.Add(2)
|
||||
go g.wsReadData()
|
||||
go g.wsFunnelConnectionData(g.Websocket.Conn)
|
||||
e.Websocket.Wg.Add(2)
|
||||
go e.wsReadData()
|
||||
go e.wsFunnelConnectionData(e.Websocket.Conn)
|
||||
|
||||
if g.Websocket.CanUseAuthenticatedEndpoints() {
|
||||
err := g.WsAuth(ctx, &dialer)
|
||||
if e.Websocket.CanUseAuthenticatedEndpoints() {
|
||||
err := e.WsAuth(ctx, &dialer)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%v - websocket authentication failed: %v\n", g.Name, err)
|
||||
g.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
log.Errorf(log.ExchangeSys, "%v - websocket authentication failed: %v\n", e.Name, err)
|
||||
e.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateSubscriptions returns a list of subscriptions from the configured subscriptions feature
|
||||
func (g *Gemini) generateSubscriptions() (subscription.List, error) {
|
||||
return g.Features.Subscriptions.ExpandTemplates(g)
|
||||
func (e *Exchange) generateSubscriptions() (subscription.List, error) {
|
||||
return e.Features.Subscriptions.ExpandTemplates(e)
|
||||
}
|
||||
|
||||
// GetSubscriptionTemplate returns a subscription channel template
|
||||
func (g *Gemini) GetSubscriptionTemplate(_ *subscription.Subscription) (*template.Template, error) {
|
||||
func (e *Exchange) GetSubscriptionTemplate(_ *subscription.Subscription) (*template.Template, error) {
|
||||
return template.New("master.tmpl").Funcs(template.FuncMap{
|
||||
"channelName": channelName,
|
||||
"interval": channelInterval,
|
||||
@@ -98,18 +98,18 @@ func (g *Gemini) GetSubscriptionTemplate(_ *subscription.Subscription) (*templat
|
||||
}
|
||||
|
||||
// Subscribe sends a websocket message to receive data from the channel
|
||||
func (g *Gemini) Subscribe(subs subscription.List) error {
|
||||
func (e *Exchange) Subscribe(subs subscription.List) error {
|
||||
ctx := context.TODO()
|
||||
return g.manageSubs(ctx, subs, wsSubscribeOp)
|
||||
return e.manageSubs(ctx, subs, wsSubscribeOp)
|
||||
}
|
||||
|
||||
// Unsubscribe sends a websocket message to stop receiving data from the channel
|
||||
func (g *Gemini) Unsubscribe(subs subscription.List) error {
|
||||
func (e *Exchange) Unsubscribe(subs subscription.List) error {
|
||||
ctx := context.TODO()
|
||||
return g.manageSubs(ctx, subs, wsUnsubscribeOp)
|
||||
return e.manageSubs(ctx, subs, wsUnsubscribeOp)
|
||||
}
|
||||
|
||||
func (g *Gemini) manageSubs(ctx context.Context, subs subscription.List, op wsSubOp) error {
|
||||
func (e *Exchange) manageSubs(ctx context.Context, subs subscription.List, op wsSubOp) error {
|
||||
req := wsSubscribeRequest{
|
||||
Type: op,
|
||||
Subscriptions: make([]wsSubscriptions, 0, len(subs)),
|
||||
@@ -121,23 +121,23 @@ func (g *Gemini) manageSubs(ctx context.Context, subs subscription.List, op wsSu
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Websocket.Conn.SendJSONMessage(ctx, request.Unset, req); err != nil {
|
||||
if err := e.Websocket.Conn.SendJSONMessage(ctx, request.Unset, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if op == wsUnsubscribeOp {
|
||||
return g.Websocket.RemoveSubscriptions(g.Websocket.Conn, subs...)
|
||||
return e.Websocket.RemoveSubscriptions(e.Websocket.Conn, subs...)
|
||||
}
|
||||
|
||||
return g.Websocket.AddSuccessfulSubscriptions(g.Websocket.Conn, subs...)
|
||||
return e.Websocket.AddSuccessfulSubscriptions(e.Websocket.Conn, subs...)
|
||||
}
|
||||
|
||||
// WsAuth will connect to Gemini's secure endpoint
|
||||
func (g *Gemini) WsAuth(ctx context.Context, dialer *gws.Dialer) error {
|
||||
if !g.IsWebsocketAuthenticationSupported() {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", g.Name)
|
||||
func (e *Exchange) WsAuth(ctx context.Context, dialer *gws.Dialer) error {
|
||||
if !e.IsWebsocketAuthenticationSupported() {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", e.Name)
|
||||
}
|
||||
creds, err := g.GetCredentials(ctx)
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -147,9 +147,9 @@ func (g *Gemini) WsAuth(ctx context.Context, dialer *gws.Dialer) error {
|
||||
}
|
||||
payloadJSON, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v sendAuthenticatedHTTPRequest: Unable to JSON request", g.Name)
|
||||
return fmt.Errorf("%v sendAuthenticatedHTTPRequest: Unable to JSON request", e.Name)
|
||||
}
|
||||
wsEndpoint, err := g.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
wsEndpoint, err := e.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -168,18 +168,18 @@ func (g *Gemini) WsAuth(ctx context.Context, dialer *gws.Dialer) error {
|
||||
headers.Add("X-GEMINI-SIGNATURE", hex.EncodeToString(hmac))
|
||||
headers.Add("Cache-Control", "no-cache")
|
||||
|
||||
err = g.Websocket.AuthConn.Dial(ctx, dialer, headers)
|
||||
err = e.Websocket.AuthConn.Dial(ctx, dialer, headers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v Websocket connection %v error. Error %v", g.Name, endpoint, err)
|
||||
return fmt.Errorf("%v Websocket connection %v error. Error %v", e.Name, endpoint, err)
|
||||
}
|
||||
g.Websocket.Wg.Add(1)
|
||||
go g.wsFunnelConnectionData(g.Websocket.AuthConn)
|
||||
e.Websocket.Wg.Add(1)
|
||||
go e.wsFunnelConnectionData(e.Websocket.AuthConn)
|
||||
return nil
|
||||
}
|
||||
|
||||
// wsFunnelConnectionData receives data from multiple connections and passes it to wsReadData
|
||||
func (g *Gemini) wsFunnelConnectionData(ws websocket.Connection) {
|
||||
defer g.Websocket.Wg.Done()
|
||||
func (e *Exchange) wsFunnelConnectionData(ws websocket.Connection) {
|
||||
defer e.Websocket.Wg.Done()
|
||||
for {
|
||||
resp := ws.ReadMessage()
|
||||
if resp.Raw == nil {
|
||||
@@ -190,21 +190,21 @@ func (g *Gemini) wsFunnelConnectionData(ws websocket.Connection) {
|
||||
}
|
||||
|
||||
// wsReadData receives and passes on websocket messages for processing
|
||||
func (g *Gemini) wsReadData() {
|
||||
defer g.Websocket.Wg.Done()
|
||||
func (e *Exchange) wsReadData() {
|
||||
defer e.Websocket.Wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-g.Websocket.ShutdownC:
|
||||
case <-e.Websocket.ShutdownC:
|
||||
select {
|
||||
case resp := <-comms:
|
||||
err := g.wsHandleData(resp.Raw)
|
||||
err := e.wsHandleData(resp.Raw)
|
||||
if err != nil {
|
||||
select {
|
||||
case g.Websocket.DataHandler <- err:
|
||||
case e.Websocket.DataHandler <- err:
|
||||
default:
|
||||
log.Errorf(log.WebsocketMgr,
|
||||
"%s websocket handle data error: %v",
|
||||
g.Name,
|
||||
e.Name,
|
||||
err)
|
||||
}
|
||||
}
|
||||
@@ -212,15 +212,15 @@ func (g *Gemini) wsReadData() {
|
||||
}
|
||||
return
|
||||
case resp := <-comms:
|
||||
err := g.wsHandleData(resp.Raw)
|
||||
err := e.wsHandleData(resp.Raw)
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- err
|
||||
e.Websocket.DataHandler <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
func (e *Exchange) wsHandleData(respRaw []byte) error {
|
||||
// only order details are sent in arrays
|
||||
if strings.HasPrefix(string(respRaw), "[") {
|
||||
var result []WsOrderResponse
|
||||
@@ -232,8 +232,8 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
for i := range result {
|
||||
oSide, err := order.StringToOrderSide(result[i].Side)
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: g.Name,
|
||||
e.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: e.Name,
|
||||
OrderID: result[i].OrderID,
|
||||
Err: err,
|
||||
}
|
||||
@@ -241,8 +241,8 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
var oType order.Type
|
||||
oType, err = stringToOrderType(result[i].OrderType)
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: g.Name,
|
||||
e.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: e.Name,
|
||||
OrderID: result[i].OrderID,
|
||||
Err: err,
|
||||
}
|
||||
@@ -250,19 +250,19 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
var oStatus order.Status
|
||||
oStatus, err = stringToOrderStatus(result[i].Type)
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: g.Name,
|
||||
e.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: e.Name,
|
||||
OrderID: result[i].OrderID,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
enabledPairs, err := g.GetAvailablePairs(asset.Spot)
|
||||
enabledPairs, err := e.GetAvailablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
format, err := g.GetPairFormat(asset.Spot, true)
|
||||
format, err := e.GetPairFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -272,13 +272,13 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
g.Websocket.DataHandler <- &order.Detail{
|
||||
e.Websocket.DataHandler <- &order.Detail{
|
||||
HiddenOrder: result[i].IsHidden,
|
||||
Price: result[i].Price,
|
||||
Amount: result[i].OriginalAmount,
|
||||
ExecutedAmount: result[i].ExecutedAmount,
|
||||
RemainingAmount: result[i].RemainingAmount,
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
OrderID: result[i].OrderID,
|
||||
Type: oType,
|
||||
Side: oSide,
|
||||
@@ -293,7 +293,7 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
var result map[string]any
|
||||
err := json.Unmarshal(respRaw, &result)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v Error: %v, Raw: %v", g.Name, err, string(respRaw))
|
||||
return fmt.Errorf("%v Error: %v, Raw: %v", e.Name, err, string(respRaw))
|
||||
}
|
||||
if _, ok := result["type"]; ok {
|
||||
switch result["type"] {
|
||||
@@ -303,9 +303,9 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.wsProcessUpdate(l2MarketData)
|
||||
return e.wsProcessUpdate(l2MarketData)
|
||||
case "trade":
|
||||
if !g.IsSaveTradeDataEnabled() {
|
||||
if !e.IsSaveTradeDataEnabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -317,18 +317,18 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
|
||||
tSide, err := order.StringToOrderSide(result.Side)
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: g.Name,
|
||||
e.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: e.Name,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
enabledPairs, err := g.GetEnabledPairs(asset.Spot)
|
||||
enabledPairs, err := e.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
format, err := g.GetPairFormat(asset.Spot, true)
|
||||
format, err := e.GetPairFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -342,7 +342,7 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
Timestamp: result.Timestamp.Time(),
|
||||
CurrencyPair: pair,
|
||||
AssetType: asset.Spot,
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Price: result.Price,
|
||||
Amount: result.Quantity,
|
||||
Side: tSide,
|
||||
@@ -356,14 +356,14 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Websocket.DataHandler <- result
|
||||
e.Websocket.DataHandler <- result
|
||||
case "initial":
|
||||
var result WsSubscriptionAcknowledgementResponse
|
||||
err := json.Unmarshal(respRaw, &result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Websocket.DataHandler <- result
|
||||
e.Websocket.DataHandler <- result
|
||||
case "heartbeat":
|
||||
return nil
|
||||
case "candles_1m_updates",
|
||||
@@ -378,12 +378,12 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enabledPairs, err := g.GetEnabledPairs(asset.Spot)
|
||||
enabledPairs, err := e.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
format, err := g.GetPairFormat(asset.Spot, true)
|
||||
format, err := e.GetPairFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -401,11 +401,11 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
if !ok {
|
||||
return errors.New("unable to type assert interval")
|
||||
}
|
||||
g.Websocket.DataHandler <- websocket.KlineData{
|
||||
e.Websocket.DataHandler <- websocket.KlineData{
|
||||
Timestamp: time.UnixMilli(int64(candle.Changes[i][0])),
|
||||
Pair: pair,
|
||||
AssetType: asset.Spot,
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Interval: interval,
|
||||
OpenPrice: candle.Changes[i][1],
|
||||
HighPrice: candle.Changes[i][2],
|
||||
@@ -415,7 +415,7 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
}
|
||||
}
|
||||
default:
|
||||
g.Websocket.DataHandler <- websocket.UnhandledMessageWarning{Message: g.Name + websocket.UnhandledMessage + string(respRaw)}
|
||||
e.Websocket.DataHandler <- websocket.UnhandledMessageWarning{Message: e.Name + websocket.UnhandledMessage + string(respRaw)}
|
||||
return nil
|
||||
}
|
||||
} else if r, ok := result["result"].(string); ok {
|
||||
@@ -427,9 +427,9 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
|
||||
}
|
||||
return errors.New(reason)
|
||||
}
|
||||
return fmt.Errorf("%v Unhandled websocket error %s", g.Name, respRaw)
|
||||
return fmt.Errorf("%v Unhandled websocket error %s", e.Name, respRaw)
|
||||
default:
|
||||
g.Websocket.DataHandler <- websocket.UnhandledMessageWarning{Message: g.Name + websocket.UnhandledMessage + string(respRaw)}
|
||||
e.Websocket.DataHandler <- websocket.UnhandledMessageWarning{Message: e.Name + websocket.UnhandledMessage + string(respRaw)}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -468,14 +468,14 @@ func stringToOrderType(oType string) (order.Type, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
func (e *Exchange) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
isInitial := len(result.Changes) > 0 && len(result.Trades) > 0
|
||||
enabledPairs, err := g.GetEnabledPairs(asset.Spot)
|
||||
enabledPairs, err := e.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
format, err := g.GetPairFormat(asset.Spot, true)
|
||||
format, err := e.GetPairFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -514,10 +514,10 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
newOrderBook.Bids = bids
|
||||
newOrderBook.Asset = asset.Spot
|
||||
newOrderBook.Pair = pair
|
||||
newOrderBook.Exchange = g.Name
|
||||
newOrderBook.ValidateOrderbook = g.ValidateOrderbook
|
||||
newOrderBook.Exchange = e.Name
|
||||
newOrderBook.ValidateOrderbook = e.ValidateOrderbook
|
||||
newOrderBook.LastUpdated = time.Now() // No time is sent
|
||||
err := g.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
||||
err := e.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -525,7 +525,7 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
if len(asks) == 0 && len(bids) == 0 {
|
||||
return nil
|
||||
}
|
||||
err := g.Websocket.Orderbook.Update(&orderbook.Update{
|
||||
err := e.Websocket.Orderbook.Update(&orderbook.Update{
|
||||
Asks: asks,
|
||||
Bids: bids,
|
||||
Pair: pair,
|
||||
@@ -538,10 +538,10 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
}
|
||||
|
||||
if len(result.AuctionEvents) > 0 {
|
||||
g.Websocket.DataHandler <- result.AuctionEvents
|
||||
e.Websocket.DataHandler <- result.AuctionEvents
|
||||
}
|
||||
|
||||
if !g.IsSaveTradeDataEnabled() {
|
||||
if !e.IsSaveTradeDataEnabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -549,8 +549,8 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
for x := range result.Trades {
|
||||
tSide, err := order.StringToOrderSide(result.Trades[x].Side)
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: g.Name,
|
||||
e.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: e.Name,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
@@ -558,7 +558,7 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
Timestamp: result.Trades[x].Timestamp.Time(),
|
||||
CurrencyPair: pair,
|
||||
AssetType: asset.Spot,
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Price: result.Trades[x].Price,
|
||||
Amount: result.Trades[x].Quantity,
|
||||
Side: tSide,
|
||||
|
||||
@@ -32,12 +32,12 @@ import (
|
||||
)
|
||||
|
||||
// SetDefaults sets package defaults for gemini exchange
|
||||
func (g *Gemini) SetDefaults() {
|
||||
g.Name = "Gemini"
|
||||
g.Enabled = true
|
||||
g.Verbose = true
|
||||
g.API.CredentialsValidator.RequiresKey = true
|
||||
g.API.CredentialsValidator.RequiresSecret = true
|
||||
func (e *Exchange) SetDefaults() {
|
||||
e.Name = "Gemini"
|
||||
e.Enabled = true
|
||||
e.Verbose = true
|
||||
e.API.CredentialsValidator.RequiresKey = true
|
||||
e.API.CredentialsValidator.RequiresSecret = true
|
||||
|
||||
requestFmt := ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
@@ -47,12 +47,12 @@ func (g *Gemini) SetDefaults() {
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
}
|
||||
err := g.SetGlobalPairsManager(requestFmt, configFmt, asset.Spot)
|
||||
err := e.SetGlobalPairsManager(requestFmt, configFmt, asset.Spot)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
g.Features = exchange.Features{
|
||||
e.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
@@ -92,68 +92,68 @@ func (g *Gemini) SetDefaults() {
|
||||
Subscriptions: defaultSubscriptions.Clone(),
|
||||
}
|
||||
|
||||
g.Requester, err = request.New(g.Name,
|
||||
e.Requester, err = request.New(e.Name,
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout),
|
||||
request.WithLimiter(GetRateLimit()))
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
g.API.Endpoints = g.NewEndpoints()
|
||||
err = g.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
e.API.Endpoints = e.NewEndpoints()
|
||||
err = e.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
exchange.RestSpot: geminiAPIURL,
|
||||
exchange.WebsocketSpot: geminiWebsocketEndpoint,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
g.Websocket = websocket.NewManager()
|
||||
g.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
g.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
g.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
|
||||
e.Websocket = websocket.NewManager()
|
||||
e.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
e.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
e.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
|
||||
}
|
||||
|
||||
// Setup sets exchange configuration parameters
|
||||
func (g *Gemini) Setup(exch *config.Exchange) error {
|
||||
func (e *Exchange) Setup(exch *config.Exchange) error {
|
||||
err := exch.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exch.Enabled {
|
||||
g.SetEnabled(false)
|
||||
e.SetEnabled(false)
|
||||
return nil
|
||||
}
|
||||
err = g.SetupDefaults(exch)
|
||||
err = e.SetupDefaults(exch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exch.UseSandbox {
|
||||
err = g.API.Endpoints.SetRunningURL(exchange.RestSpot.String(), geminiSandboxAPIURL)
|
||||
err = e.API.Endpoints.SetRunningURL(exchange.RestSpot.String(), geminiSandboxAPIURL)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
}
|
||||
|
||||
wsRunningURL, err := g.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
wsRunningURL, err := e.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.Websocket.Setup(&websocket.ManagerSetup{
|
||||
err = e.Websocket.Setup(&websocket.ManagerSetup{
|
||||
ExchangeConfig: exch,
|
||||
DefaultURL: geminiWebsocketEndpoint,
|
||||
RunningURL: wsRunningURL,
|
||||
Connector: g.WsConnect,
|
||||
Subscriber: g.Subscribe,
|
||||
Unsubscriber: g.Unsubscribe,
|
||||
GenerateSubscriptions: g.generateSubscriptions,
|
||||
Features: &g.Features.Supports.WebsocketCapabilities,
|
||||
Connector: e.WsConnect,
|
||||
Subscriber: e.Subscribe,
|
||||
Unsubscriber: e.Unsubscribe,
|
||||
GenerateSubscriptions: e.generateSubscriptions,
|
||||
Features: &e.Features.Supports.WebsocketCapabilities,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
|
||||
err = e.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
|
||||
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
|
||||
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
|
||||
URL: geminiWebsocketEndpoint + "/v2/" + geminiWsMarketData,
|
||||
@@ -162,7 +162,7 @@ func (g *Gemini) Setup(exch *config.Exchange) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return g.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
|
||||
return e.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
|
||||
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
|
||||
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
|
||||
URL: geminiWebsocketEndpoint + "/v1/" + geminiWsOrderEvents,
|
||||
@@ -171,12 +171,12 @@ func (g *Gemini) Setup(exch *config.Exchange) error {
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (g *Gemini) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.Pairs, error) {
|
||||
if !g.SupportsAsset(a) {
|
||||
func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.Pairs, error) {
|
||||
if !e.SupportsAsset(a) {
|
||||
return nil, asset.ErrNotSupported
|
||||
}
|
||||
|
||||
details, err := g.GetSymbolDetails(ctx, "all")
|
||||
details, err := e.GetSymbolDetails(ctx, "all")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -202,24 +202,24 @@ func (g *Gemini) FetchTradablePairs(ctx context.Context, a asset.Item) (currency
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func (g *Gemini) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error {
|
||||
pairs, err := g.FetchTradablePairs(ctx, asset.Spot)
|
||||
func (e *Exchange) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error {
|
||||
pairs, err := e.FetchTradablePairs(ctx, asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = g.UpdatePairs(pairs, asset.Spot, false, forceUpdate)
|
||||
err = e.UpdatePairs(pairs, asset.Spot, false, forceUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.EnsureOnePairEnabled()
|
||||
return e.EnsureOnePairEnabled()
|
||||
}
|
||||
|
||||
// UpdateAccountInfo Retrieves balances for all enabled currencies for the
|
||||
// Gemini exchange
|
||||
func (g *Gemini) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
|
||||
func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
|
||||
var response account.Holdings
|
||||
response.Exchange = g.Name
|
||||
accountBalance, err := g.GetBalances(ctx)
|
||||
response.Exchange = e.Name
|
||||
accountBalance, err := e.GetBalances(ctx)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -239,7 +239,7 @@ func (g *Gemini) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a
|
||||
Currencies: currencies,
|
||||
})
|
||||
|
||||
creds, err := g.GetCredentials(ctx)
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return account.Holdings{}, err
|
||||
}
|
||||
@@ -252,18 +252,18 @@ func (g *Gemini) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a
|
||||
}
|
||||
|
||||
// UpdateTickers updates the ticker for all currency pairs of a given asset type
|
||||
func (g *Gemini) UpdateTickers(_ context.Context, _ asset.Item) error {
|
||||
func (e *Exchange) UpdateTickers(_ context.Context, _ asset.Item) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (g *Gemini) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
|
||||
fPair, err := g.FormatExchangeCurrency(p, a)
|
||||
func (e *Exchange) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
|
||||
fPair, err := e.FormatExchangeCurrency(p, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tick, err := g.GetTicker(ctx, fPair.String())
|
||||
tick, err := e.GetTicker(ctx, fPair.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -276,36 +276,36 @@ func (g *Gemini) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item
|
||||
Open: tick.Open,
|
||||
Close: tick.Close,
|
||||
Pair: fPair,
|
||||
ExchangeName: g.Name,
|
||||
ExchangeName: e.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ticker.GetTicker(g.Name, fPair, a)
|
||||
return ticker.GetTicker(e.Name, fPair, a)
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (g *Gemini) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType asset.Item) (*orderbook.Book, error) {
|
||||
func (e *Exchange) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType asset.Item) (*orderbook.Book, error) {
|
||||
if p.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
if err := g.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
|
||||
if err := e.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
book := &orderbook.Book{
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Pair: p,
|
||||
Asset: assetType,
|
||||
ValidateOrderbook: g.ValidateOrderbook,
|
||||
ValidateOrderbook: e.ValidateOrderbook,
|
||||
}
|
||||
fPair, err := g.FormatExchangeCurrency(p, assetType)
|
||||
fPair, err := e.FormatExchangeCurrency(p, assetType)
|
||||
if err != nil {
|
||||
return book, err
|
||||
}
|
||||
|
||||
orderbookNew, err := g.GetOrderbook(ctx, fPair.String(), url.Values{})
|
||||
orderbookNew, err := e.GetOrderbook(ctx, fPair.String(), url.Values{})
|
||||
if err != nil {
|
||||
return book, err
|
||||
}
|
||||
@@ -329,13 +329,13 @@ func (g *Gemini) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType
|
||||
if err != nil {
|
||||
return book, err
|
||||
}
|
||||
return orderbook.Get(g.Name, fPair, assetType)
|
||||
return orderbook.Get(e.Name, fPair, assetType)
|
||||
}
|
||||
|
||||
// GetAccountFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (g *Gemini) GetAccountFundingHistory(ctx context.Context) ([]exchange.FundingHistory, error) {
|
||||
transfers, err := g.Transfers(ctx, currency.EMPTYCODE, time.Time{}, 50, "", false)
|
||||
func (e *Exchange) GetAccountFundingHistory(ctx context.Context) ([]exchange.FundingHistory, error) {
|
||||
transfers, err := e.Transfers(ctx, currency.EMPTYCODE, time.Time{}, 50, "", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -357,11 +357,11 @@ func (g *Gemini) GetAccountFundingHistory(ctx context.Context) ([]exchange.Fundi
|
||||
}
|
||||
|
||||
// GetWithdrawalsHistory returns previous withdrawals data
|
||||
func (g *Gemini) GetWithdrawalsHistory(ctx context.Context, c currency.Code, a asset.Item) ([]exchange.WithdrawalHistory, error) {
|
||||
if err := g.CurrencyPairs.IsAssetEnabled(a); err != nil {
|
||||
func (e *Exchange) GetWithdrawalsHistory(ctx context.Context, c currency.Code, a asset.Item) ([]exchange.WithdrawalHistory, error) {
|
||||
if err := e.CurrencyPairs.IsAssetEnabled(a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transfers, err := g.Transfers(ctx, c, time.Time{}, 50, "", false)
|
||||
transfers, err := e.Transfers(ctx, c, time.Time{}, 50, "", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -386,17 +386,17 @@ func (g *Gemini) GetWithdrawalsHistory(ctx context.Context, c currency.Code, a a
|
||||
}
|
||||
|
||||
// GetRecentTrades returns the most recent trades for a currency and asset
|
||||
func (g *Gemini) GetRecentTrades(ctx context.Context, pair currency.Pair, assetType asset.Item) ([]trade.Data, error) {
|
||||
return g.GetHistoricTrades(ctx, pair, assetType, time.Time{}, time.Time{})
|
||||
func (e *Exchange) GetRecentTrades(ctx context.Context, pair currency.Pair, assetType asset.Item) ([]trade.Data, error) {
|
||||
return e.GetHistoricTrades(ctx, pair, assetType, time.Time{}, time.Time{})
|
||||
}
|
||||
|
||||
// GetHistoricTrades returns historic trade data within the timeframe provided
|
||||
func (g *Gemini) GetHistoricTrades(ctx context.Context, p currency.Pair, assetType asset.Item, timestampStart, timestampEnd time.Time) ([]trade.Data, error) {
|
||||
func (e *Exchange) GetHistoricTrades(ctx context.Context, p currency.Pair, assetType asset.Item, timestampStart, timestampEnd time.Time) ([]trade.Data, error) {
|
||||
if err := common.StartEndTimeCheck(timestampStart, timestampEnd); err != nil && !errors.Is(err, common.ErrDateUnset) {
|
||||
return nil, fmt.Errorf("invalid time range supplied. Start: %v End %v %w", timestampStart, timestampEnd, err)
|
||||
}
|
||||
var err error
|
||||
p, err = g.FormatExchangeCurrency(p, assetType)
|
||||
p, err = e.FormatExchangeCurrency(p, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -406,7 +406,7 @@ func (g *Gemini) GetHistoricTrades(ctx context.Context, p currency.Pair, assetTy
|
||||
allTrades:
|
||||
for {
|
||||
var tradeData []Trade
|
||||
tradeData, err = g.GetTrades(ctx, p.String(), ts.Unix(), int64(limit), false)
|
||||
tradeData, err = e.GetTrades(ctx, p.String(), ts.Unix(), int64(limit), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -422,7 +422,7 @@ allTrades:
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, trade.Data{
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
TID: strconv.FormatInt(tradeData[i].TID, 10),
|
||||
CurrencyPair: p,
|
||||
AssetType: assetType,
|
||||
@@ -443,7 +443,7 @@ allTrades:
|
||||
}
|
||||
}
|
||||
|
||||
err = g.AddTradesToBuffer(resp...)
|
||||
err = e.AddTradesToBuffer(resp...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -454,8 +454,8 @@ allTrades:
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (g *Gemini) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(g.GetTradingRequirements()); err != nil {
|
||||
func (e *Exchange) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(e.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -463,12 +463,12 @@ func (g *Gemini) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
return nil, errors.New("only limit orders are enabled through this exchange")
|
||||
}
|
||||
|
||||
fPair, err := g.FormatExchangeCurrency(s.Pair, asset.Spot)
|
||||
fPair, err := e.FormatExchangeCurrency(s.Pair, asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := g.NewOrder(ctx,
|
||||
response, err := e.NewOrder(ctx,
|
||||
fPair.String(),
|
||||
s.Amount,
|
||||
s.Price,
|
||||
@@ -483,12 +483,12 @@ func (g *Gemini) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (g *Gemini) ModifyOrder(_ context.Context, _ *order.Modify) (*order.ModifyResponse, error) {
|
||||
func (e *Exchange) ModifyOrder(_ context.Context, _ *order.Modify) (*order.ModifyResponse, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (g *Gemini) CancelOrder(ctx context.Context, o *order.Cancel) error {
|
||||
func (e *Exchange) CancelOrder(ctx context.Context, o *order.Cancel) error {
|
||||
if err := o.Validate(o.StandardCancel()); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -498,26 +498,26 @@ func (g *Gemini) CancelOrder(ctx context.Context, o *order.Cancel) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = g.CancelExistingOrder(ctx, orderIDInt)
|
||||
_, err = e.CancelExistingOrder(ctx, orderIDInt)
|
||||
return err
|
||||
}
|
||||
|
||||
// CancelBatchOrders cancels an orders by their corresponding ID numbers
|
||||
func (g *Gemini) CancelBatchOrders(_ context.Context, _ []order.Cancel) (*order.CancelBatchResponse, error) {
|
||||
func (e *Exchange) CancelBatchOrders(_ context.Context, _ []order.Cancel) (*order.CancelBatchResponse, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetServerTime returns the current exchange server time.
|
||||
func (g *Gemini) GetServerTime(_ context.Context, _ asset.Item) (time.Time, error) {
|
||||
func (e *Exchange) GetServerTime(_ context.Context, _ asset.Item) (time.Time, error) {
|
||||
return time.Time{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (g *Gemini) CancelAllOrders(ctx context.Context, _ *order.Cancel) (order.CancelAllResponse, error) {
|
||||
func (e *Exchange) CancelAllOrders(ctx context.Context, _ *order.Cancel) (order.CancelAllResponse, error) {
|
||||
cancelAllOrdersResponse := order.CancelAllResponse{
|
||||
Status: make(map[string]string),
|
||||
}
|
||||
resp, err := g.CancelExistingOrders(ctx, false)
|
||||
resp, err := e.CancelExistingOrders(ctx, false)
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
@@ -530,12 +530,12 @@ func (g *Gemini) CancelAllOrders(ctx context.Context, _ *order.Cancel) (order.Ca
|
||||
}
|
||||
|
||||
// GetOrderInfo returns order information based on order ID
|
||||
func (g *Gemini) GetOrderInfo(ctx context.Context, orderID string, _ currency.Pair, _ asset.Item) (*order.Detail, error) {
|
||||
func (e *Exchange) GetOrderInfo(ctx context.Context, orderID string, _ currency.Pair, _ asset.Item) (*order.Detail, error) {
|
||||
iOID, err := strconv.ParseInt(orderID, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := g.GetOrderStatus(ctx, iOID)
|
||||
resp, err := e.GetOrderStatus(ctx, iOID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -575,8 +575,8 @@ func (g *Gemini) GetOrderInfo(ctx context.Context, orderID string, _ currency.Pa
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (g *Gemini) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, _ string) (*deposit.Address, error) {
|
||||
addr, err := g.GetCryptoDepositAddress(ctx, "", cryptocurrency.String())
|
||||
func (e *Exchange) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, _ string) (*deposit.Address, error) {
|
||||
addr, err := e.GetCryptoDepositAddress(ctx, "", cryptocurrency.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -585,11 +585,11 @@ func (g *Gemini) GetDepositAddress(ctx context.Context, cryptocurrency currency.
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (g *Gemini) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
func (e *Exchange) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
if err := withdrawRequest.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := g.WithdrawCrypto(ctx,
|
||||
resp, err := e.WithdrawCrypto(ctx,
|
||||
withdrawRequest.Crypto.Address,
|
||||
withdrawRequest.Currency.String(),
|
||||
withdrawRequest.Amount)
|
||||
@@ -607,46 +607,46 @@ func (g *Gemini) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawReques
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a
|
||||
// withdrawal is submitted
|
||||
func (g *Gemini) WithdrawFiatFunds(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
func (e *Exchange) WithdrawFiatFunds(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a
|
||||
// withdrawal is submitted
|
||||
func (g *Gemini) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
func (e *Exchange) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (g *Gemini) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
func (e *Exchange) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if feeBuilder == nil {
|
||||
return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer)
|
||||
}
|
||||
if (!g.AreCredentialsValid(ctx) || g.SkipAuthCheck) && // Todo check connection status
|
||||
if (!e.AreCredentialsValid(ctx) || e.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
return g.GetFee(ctx, feeBuilder)
|
||||
return e.GetFee(ctx, feeBuilder)
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func (g *Gemini) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
func (e *Exchange) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
err := req.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := g.GetOrders(ctx)
|
||||
resp, err := e.GetOrders(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
availPairs, err := g.GetAvailablePairs(asset.Spot)
|
||||
availPairs, err := e.GetAvailablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
format, err := g.GetPairFormat(asset.Spot, true)
|
||||
format, err := e.GetPairFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -680,7 +680,7 @@ func (g *Gemini) GetActiveOrders(ctx context.Context, req *order.MultiOrderReque
|
||||
RemainingAmount: resp[i].RemainingAmount,
|
||||
OrderID: strconv.FormatInt(resp[i].OrderID, 10),
|
||||
ExecutedAmount: resp[i].ExecutedAmount,
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Type: orderType,
|
||||
Side: side,
|
||||
Price: resp[i].Price,
|
||||
@@ -688,12 +688,12 @@ func (g *Gemini) GetActiveOrders(ctx context.Context, req *order.MultiOrderReque
|
||||
Date: resp[i].Timestamp.Time(),
|
||||
}
|
||||
}
|
||||
return req.Filter(g.Name, orders), nil
|
||||
return req.Filter(e.Name, orders), nil
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
func (g *Gemini) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
func (e *Exchange) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
err := req.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -706,13 +706,13 @@ func (g *Gemini) GetOrderHistory(ctx context.Context, req *order.MultiOrderReque
|
||||
var trades []TradeHistory
|
||||
for j := range req.Pairs {
|
||||
var fPair currency.Pair
|
||||
fPair, err = g.FormatExchangeCurrency(req.Pairs[j], asset.Spot)
|
||||
fPair, err = e.FormatExchangeCurrency(req.Pairs[j], asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []TradeHistory
|
||||
resp, err = g.GetTradeHistory(ctx, fPair.String(), req.StartTime.Unix())
|
||||
resp, err = e.GetTradeHistory(ctx, fPair.String(), req.StartTime.Unix())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -724,7 +724,7 @@ func (g *Gemini) GetOrderHistory(ctx context.Context, req *order.MultiOrderReque
|
||||
}
|
||||
}
|
||||
|
||||
format, err := g.GetPairFormat(asset.Spot, false)
|
||||
format, err := e.GetPairFormat(asset.Spot, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -740,7 +740,7 @@ func (g *Gemini) GetOrderHistory(ctx context.Context, req *order.MultiOrderReque
|
||||
OrderID: strconv.FormatInt(trades[i].OrderID, 10),
|
||||
Amount: trades[i].Amount,
|
||||
ExecutedAmount: trades[i].Amount,
|
||||
Exchange: g.Name,
|
||||
Exchange: e.Name,
|
||||
Date: trades[i].Timestamp.Time(),
|
||||
Side: side,
|
||||
Fee: trades[i].FeeAmount,
|
||||
@@ -755,37 +755,37 @@ func (g *Gemini) GetOrderHistory(ctx context.Context, req *order.MultiOrderReque
|
||||
detail.InferCostsAndTimes()
|
||||
orders[i] = detail
|
||||
}
|
||||
return req.Filter(g.Name, orders), nil
|
||||
return req.Filter(e.Name, orders), nil
|
||||
}
|
||||
|
||||
// ValidateAPICredentials validates current credentials used for wrapper
|
||||
// functionality
|
||||
func (g *Gemini) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
|
||||
_, err := g.UpdateAccountInfo(ctx, assetType)
|
||||
return g.CheckTransientError(err)
|
||||
func (e *Exchange) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
|
||||
_, err := e.UpdateAccountInfo(ctx, assetType)
|
||||
return e.CheckTransientError(err)
|
||||
}
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (g *Gemini) GetHistoricCandles(_ context.Context, _ currency.Pair, _ asset.Item, _ kline.Interval, _, _ time.Time) (*kline.Item, error) {
|
||||
func (e *Exchange) GetHistoricCandles(_ context.Context, _ currency.Pair, _ asset.Item, _ kline.Interval, _, _ time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetHistoricCandlesExtended returns candles between a time period for a set time interval
|
||||
func (g *Gemini) GetHistoricCandlesExtended(_ context.Context, _ currency.Pair, _ asset.Item, _ kline.Interval, _, _ time.Time) (*kline.Item, error) {
|
||||
func (e *Exchange) GetHistoricCandlesExtended(_ context.Context, _ currency.Pair, _ asset.Item, _ kline.Interval, _, _ time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetFuturesContractDetails returns all contracts from the exchange by asset type
|
||||
func (g *Gemini) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
|
||||
func (e *Exchange) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
|
||||
func (g *Gemini) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
|
||||
func (e *Exchange) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
|
||||
if a != asset.Spot {
|
||||
return fmt.Errorf("%w %v", asset.ErrNotSupported, a)
|
||||
}
|
||||
details, err := g.GetSymbolDetails(ctx, "all")
|
||||
details, err := e.GetSymbolDetails(ctx, "all")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot update exchange execution limits: %w", err)
|
||||
}
|
||||
@@ -807,17 +807,17 @@ func (g *Gemini) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) e
|
||||
QuoteStepIncrementSize: details[i].QuoteIncrement,
|
||||
})
|
||||
}
|
||||
return g.LoadLimits(resp)
|
||||
return e.LoadLimits(resp)
|
||||
}
|
||||
|
||||
// GetLatestFundingRates returns the latest funding rates data
|
||||
func (g *Gemini) GetLatestFundingRates(context.Context, *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) {
|
||||
func (e *Exchange) GetLatestFundingRates(context.Context, *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetCurrencyTradeURL returns the URL to the exchange's trade page for the given asset and currency pair
|
||||
func (g *Gemini) GetCurrencyTradeURL(_ context.Context, a asset.Item, cp currency.Pair) (string, error) {
|
||||
_, err := g.CurrencyPairs.IsPairEnabled(cp, a)
|
||||
func (e *Exchange) GetCurrencyTradeURL(_ context.Context, a asset.Item, cp currency.Pair) (string, error) {
|
||||
_, err := e.CurrencyPairs.IsPairEnabled(cp, a)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user