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:
Samuael A.
2025-07-17 03:46:36 +03:00
committed by GitHub
parent 485397a0c7
commit 3f534a15f1
163 changed files with 20453 additions and 20313 deletions

View File

@@ -53,16 +53,16 @@ const (
var errSymbolIsEmpty = errors.New("symbol cannot be empty")
// Bithumb is the overarching type across the Bithumb package
type Bithumb struct {
// Exchange implements exchange.IBotExchange and contains additional specific api methods for interacting with Bithumb
type Exchange struct {
exchange.Base
location *time.Location
obm orderbookManager
}
// GetTradablePairs returns a list of tradable currencies
func (b *Bithumb) GetTradablePairs(ctx context.Context) ([]string, error) {
result, err := b.GetAllTickers(ctx)
func (e *Exchange) GetTradablePairs(ctx context.Context) ([]string, error) {
result, err := e.GetAllTickers(ctx)
if err != nil {
return nil, err
}
@@ -77,9 +77,9 @@ func (b *Bithumb) GetTradablePairs(ctx context.Context) ([]string, error) {
// GetTicker returns ticker information
//
// symbol e.g. "btc"
func (b *Bithumb) GetTicker(ctx context.Context, symbol string) (Ticker, error) {
func (e *Exchange) GetTicker(ctx context.Context, symbol string) (Ticker, error) {
var response TickerResponse
err := b.SendHTTPRequest(ctx, exchange.RestSpot, publicTicker+strings.ToUpper(symbol), &response)
err := e.SendHTTPRequest(ctx, exchange.RestSpot, publicTicker+strings.ToUpper(symbol), &response)
if err != nil {
return response.Data, err
}
@@ -92,9 +92,9 @@ func (b *Bithumb) GetTicker(ctx context.Context, symbol string) (Ticker, error)
}
// GetAllTickers returns all ticker information
func (b *Bithumb) GetAllTickers(ctx context.Context) (map[string]Ticker, error) {
func (e *Exchange) GetAllTickers(ctx context.Context) (map[string]Ticker, error) {
var response TickersResponse
err := b.SendHTTPRequest(ctx, exchange.RestSpot, publicTicker+"all", &response)
err := e.SendHTTPRequest(ctx, exchange.RestSpot, publicTicker+"all", &response)
if err != nil {
return nil, err
}
@@ -121,9 +121,9 @@ func (b *Bithumb) GetAllTickers(ctx context.Context) (map[string]Ticker, error)
// GetOrderBook returns current orderbook
//
// symbol e.g. "btc"
func (b *Bithumb) GetOrderBook(ctx context.Context, symbol string) (*Orderbook, error) {
func (e *Exchange) GetOrderBook(ctx context.Context, symbol string) (*Orderbook, error) {
response := Orderbook{}
err := b.SendHTTPRequest(ctx, exchange.RestSpot, publicOrderBook+strings.ToUpper(symbol), &response)
err := e.SendHTTPRequest(ctx, exchange.RestSpot, publicOrderBook+strings.ToUpper(symbol), &response)
if err != nil {
return nil, err
}
@@ -136,12 +136,12 @@ func (b *Bithumb) GetOrderBook(ctx context.Context, symbol string) (*Orderbook,
}
// GetAssetStatus returns the withdrawal and deposit status for the symbol
func (b *Bithumb) GetAssetStatus(ctx context.Context, symbol string) (*Status, error) {
func (e *Exchange) GetAssetStatus(ctx context.Context, symbol string) (*Status, error) {
if symbol == "" {
return nil, errSymbolIsEmpty
}
var response Status
err := b.SendHTTPRequest(ctx, exchange.RestSpot, publicAssetStatus+strings.ToUpper(symbol), &response)
err := e.SendHTTPRequest(ctx, exchange.RestSpot, publicAssetStatus+strings.ToUpper(symbol), &response)
if err != nil {
return nil, err
}
@@ -154,9 +154,9 @@ func (b *Bithumb) GetAssetStatus(ctx context.Context, symbol string) (*Status, e
}
// GetAssetStatusAll returns the withdrawal and deposit status for all symbols
func (b *Bithumb) GetAssetStatusAll(ctx context.Context) (*StatusAll, error) {
func (e *Exchange) GetAssetStatusAll(ctx context.Context) (*StatusAll, error) {
var response StatusAll
err := b.SendHTTPRequest(ctx, exchange.RestSpot, publicAssetStatus+"ALL", &response)
err := e.SendHTTPRequest(ctx, exchange.RestSpot, publicAssetStatus+"ALL", &response)
if err != nil {
return nil, err
}
@@ -171,12 +171,12 @@ func (b *Bithumb) GetAssetStatusAll(ctx context.Context) (*StatusAll, error) {
// GetTransactionHistory returns recent transactions
//
// symbol e.g. "btc"
func (b *Bithumb) GetTransactionHistory(ctx context.Context, symbol string) (TransactionHistory, error) {
func (e *Exchange) GetTransactionHistory(ctx context.Context, symbol string) (TransactionHistory, error) {
response := TransactionHistory{}
path := publicTransactionHistory +
strings.ToUpper(symbol)
err := b.SendHTTPRequest(ctx, exchange.RestSpot, path, &response)
err := e.SendHTTPRequest(ctx, exchange.RestSpot, path, &response)
if err != nil {
return response, err
}
@@ -190,7 +190,7 @@ func (b *Bithumb) GetTransactionHistory(ctx context.Context, symbol string) (Tra
// GetAccountInformation returns account information based on the desired
// order/payment currencies
func (b *Bithumb) GetAccountInformation(ctx context.Context, orderCurrency, paymentCurrency string) (Account, error) {
func (e *Exchange) GetAccountInformation(ctx context.Context, orderCurrency, paymentCurrency string) (Account, error) {
var response Account
if orderCurrency == "" {
return response, errSymbolIsEmpty
@@ -203,11 +203,11 @@ func (b *Bithumb) GetAccountInformation(ctx context.Context, orderCurrency, paym
}
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateAccInfo, val, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateAccInfo, val, &response)
}
// GetAccountBalance returns customer wallet information
func (b *Bithumb) GetAccountBalance(ctx context.Context, c string) (FullBalance, error) {
func (e *Exchange) GetAccountBalance(ctx context.Context, c string) (FullBalance, error) {
var response Balance
fullBalance := FullBalance{
make(map[string]float64),
@@ -222,7 +222,7 @@ func (b *Bithumb) GetAccountBalance(ctx context.Context, c string) (FullBalance,
vals.Set("currency", c)
}
err := b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateAccBalance, vals, &response)
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateAccBalance, vals, &response)
if err != nil {
return fullBalance, err
}
@@ -260,12 +260,12 @@ func (b *Bithumb) GetAccountBalance(ctx context.Context, c string) (FullBalance,
// GetWalletAddress returns customer wallet address
//
// currency e.g. btc, ltc or "", will default to btc without currency specified
func (b *Bithumb) GetWalletAddress(ctx context.Context, curr currency.Code) (WalletAddressRes, error) {
func (e *Exchange) GetWalletAddress(ctx context.Context, curr currency.Code) (WalletAddressRes, error) {
response := WalletAddressRes{}
params := url.Values{}
params.Set("currency", curr.Upper().String())
err := b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateWalletAdd, params, &response)
err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateWalletAdd, params, &response)
if err != nil {
return response, err
}
@@ -303,11 +303,11 @@ func (b *Bithumb) GetWalletAddress(ctx context.Context, curr currency.Code) (Wal
}
// GetLastTransaction returns customer last transaction
func (b *Bithumb) GetLastTransaction(ctx context.Context) (LastTransactionTicker, error) {
func (e *Exchange) GetLastTransaction(ctx context.Context) (LastTransactionTicker, error) {
response := LastTransactionTicker{}
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateTicker, nil, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateTicker, nil, &response)
}
// GetOrders returns order list
@@ -317,7 +317,7 @@ func (b *Bithumb) GetLastTransaction(ctx context.Context) (LastTransactionTicker
// count: Value : 1 ~1000 (default : 100)
// after: YYYY-MM-DD hh:mm:ss's UNIX Timestamp
// (2014-11-28 16:40:01 = 1417160401000)
func (b *Bithumb) GetOrders(ctx context.Context, orderID, transactionType string, count int64, after time.Time, orderCurrency, paymentCurrency currency.Code) (Orders, error) {
func (e *Exchange) GetOrders(ctx context.Context, orderID, transactionType string, count int64, after time.Time, orderCurrency, paymentCurrency currency.Code) (Orders, error) {
response := Orders{}
params := url.Values{}
@@ -347,11 +347,11 @@ func (b *Bithumb) GetOrders(ctx context.Context, orderID, transactionType string
}
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateOrders, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateOrders, params, &response)
}
// GetUserTransactions returns customer transactions
func (b *Bithumb) GetUserTransactions(ctx context.Context, offset, count, searchType int64, orderCurrency, paymentCurrency currency.Code) (UserTransactions, error) {
func (e *Exchange) GetUserTransactions(ctx context.Context, offset, count, searchType int64, orderCurrency, paymentCurrency currency.Code) (UserTransactions, error) {
params := url.Values{}
if offset > 0 {
params.Set("offset", strconv.FormatInt(offset, 10))
@@ -370,7 +370,7 @@ func (b *Bithumb) GetUserTransactions(ctx context.Context, offset, count, search
}
var response UserTransactions
return response, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateUserTrans, params, &response)
return response, e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateUserTrans, params, &response)
}
// PlaceTrade executes a trade order
@@ -380,7 +380,7 @@ func (b *Bithumb) GetUserTransactions(ctx context.Context, offset, count, search
// transactionType: Transaction type(bid : purchase, ask : sales)
// units: Order quantity
// price: Transaction amount per currency
func (b *Bithumb) PlaceTrade(ctx context.Context, orderCurrency, transactionType string, units float64, price int64) (OrderPlace, error) {
func (e *Exchange) PlaceTrade(ctx context.Context, orderCurrency, transactionType string, units float64, price int64) (OrderPlace, error) {
response := OrderPlace{}
params := url.Values{}
@@ -391,7 +391,7 @@ func (b *Bithumb) PlaceTrade(ctx context.Context, orderCurrency, transactionType
params.Set("price", strconv.FormatInt(price, 10))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privatePlaceTrade, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privatePlaceTrade, params, &response)
}
// GetOrderDetails returns specific order details
@@ -400,7 +400,7 @@ func (b *Bithumb) PlaceTrade(ctx context.Context, orderCurrency, transactionType
// transactionType: Transaction type(bid : purchase, ask : sales)
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
func (b *Bithumb) GetOrderDetails(ctx context.Context, orderID, transactionType, currency string) (OrderDetails, error) {
func (e *Exchange) GetOrderDetails(ctx context.Context, orderID, transactionType, currency string) (OrderDetails, error) {
response := OrderDetails{}
params := url.Values{}
@@ -409,7 +409,7 @@ func (b *Bithumb) GetOrderDetails(ctx context.Context, orderID, transactionType,
params.Set("currency", strings.ToUpper(currency))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateOrderDetail, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateOrderDetail, params, &response)
}
// CancelTrade cancels a customer purchase/sales transaction
@@ -417,7 +417,7 @@ func (b *Bithumb) GetOrderDetails(ctx context.Context, orderID, transactionType,
// orderID: Order number registered for purchase/sales
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
func (b *Bithumb) CancelTrade(ctx context.Context, transactionType, orderID, currency string) (ActionStatus, error) {
func (e *Exchange) CancelTrade(ctx context.Context, transactionType, orderID, currency string) (ActionStatus, error) {
response := ActionStatus{}
params := url.Values{}
@@ -426,7 +426,7 @@ func (b *Bithumb) CancelTrade(ctx context.Context, transactionType, orderID, cur
params.Set("currency", strings.ToUpper(currency))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateCancelTrade, nil, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateCancelTrade, nil, &response)
}
// WithdrawCrypto withdraws a customer currency to an address
@@ -437,7 +437,7 @@ func (b *Bithumb) CancelTrade(ctx context.Context, transactionType, orderID, cur
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM
// (default value: BTC)
// units: Quantity to withdraw currency
func (b *Bithumb) WithdrawCrypto(ctx context.Context, address, destination, currency string, units float64) (ActionStatus, error) {
func (e *Exchange) WithdrawCrypto(ctx context.Context, address, destination, currency string, units float64) (ActionStatus, error) {
response := ActionStatus{}
params := url.Values{}
@@ -449,16 +449,16 @@ func (b *Bithumb) WithdrawCrypto(ctx context.Context, address, destination, curr
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateBTCWithdraw, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateBTCWithdraw, params, &response)
}
// RequestKRWDepositDetails returns Bithumb banking details for deposit
// information
func (b *Bithumb) RequestKRWDepositDetails(ctx context.Context) (KRWDeposit, error) {
func (e *Exchange) RequestKRWDepositDetails(ctx context.Context) (KRWDeposit, error) {
response := KRWDeposit{}
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateKRWDeposit, nil, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateKRWDeposit, nil, &response)
}
// RequestKRWWithdraw allows a customer KRW withdrawal request
@@ -466,7 +466,7 @@ func (b *Bithumb) RequestKRWDepositDetails(ctx context.Context) (KRWDeposit, err
// bank: Bankcode with bank name e.g. (bankcode)_(bankname)
// account: Withdrawing bank account number
// price: Withdrawing amount
func (b *Bithumb) RequestKRWWithdraw(ctx context.Context, bank, account string, price int64) (ActionStatus, error) {
func (e *Exchange) RequestKRWWithdraw(ctx context.Context, bank, account string, price int64) (ActionStatus, error) {
response := ActionStatus{}
params := url.Values{}
@@ -475,7 +475,7 @@ func (b *Bithumb) RequestKRWWithdraw(ctx context.Context, bank, account string,
params.Set("price", strconv.FormatInt(price, 10))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateKRWWithdraw, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateKRWWithdraw, params, &response)
}
// MarketBuyOrder initiates a buy order through available order books
@@ -483,7 +483,7 @@ func (b *Bithumb) RequestKRWWithdraw(ctx context.Context, bank, account string,
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
// units: Order quantity
func (b *Bithumb) MarketBuyOrder(ctx context.Context, pair currency.Pair, units float64) (MarketBuy, error) {
func (e *Exchange) MarketBuyOrder(ctx context.Context, pair currency.Pair, units float64) (MarketBuy, error) {
response := MarketBuy{}
params := url.Values{}
@@ -492,7 +492,7 @@ func (b *Bithumb) MarketBuyOrder(ctx context.Context, pair currency.Pair, units
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateMarketBuy, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateMarketBuy, params, &response)
}
// MarketSellOrder initiates a sell order through available order books
@@ -500,7 +500,7 @@ func (b *Bithumb) MarketBuyOrder(ctx context.Context, pair currency.Pair, units
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
// units: Order quantity
func (b *Bithumb) MarketSellOrder(ctx context.Context, pair currency.Pair, units float64) (MarketSell, error) {
func (e *Exchange) MarketSellOrder(ctx context.Context, pair currency.Pair, units float64) (MarketSell, error) {
response := MarketSell{}
params := url.Values{}
@@ -509,12 +509,12 @@ func (b *Bithumb) MarketSellOrder(ctx context.Context, pair currency.Pair, units
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
return response,
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateMarketSell, params, &response)
e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, privateMarketSell, params, &response)
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *Bithumb) SendHTTPRequest(ctx context.Context, ep exchange.URL, path string, result any) error {
endpoint, err := b.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
}
@@ -522,22 +522,22 @@ func (b *Bithumb) SendHTTPRequest(ctx context.Context, ep exchange.URL, path str
Method: http.MethodGet,
Path: endpoint + path,
Result: result,
Verbose: b.Verbose,
HTTPDebugging: b.HTTPDebugging,
HTTPRecording: b.HTTPRecording,
Verbose: e.Verbose,
HTTPDebugging: e.HTTPDebugging,
HTTPRecording: e.HTTPRecording,
}
return b.SendPayload(ctx, request.Unset, func() (*request.Item, error) {
return e.SendPayload(ctx, request.Unset, func() (*request.Item, error) {
return item, nil
}, request.UnauthenticatedRequest)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bithumb
func (b *Bithumb) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL, path string, params url.Values, result any) error {
creds, err := b.GetCredentials(ctx)
func (e *Exchange) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL, path string, params url.Values, result any) error {
creds, err := e.GetCredentials(ctx)
if err != nil {
return err
}
endpoint, err := b.API.Endpoints.GetURL(ep)
endpoint, err := e.API.Endpoints.GetURL(ep)
if err != nil {
return err
}
@@ -546,7 +546,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.
}
var intermediary json.RawMessage
err = b.SendPayload(ctx, request.Auth, func() (*request.Item, error) {
err = e.SendPayload(ctx, request.Auth, func() (*request.Item, error) {
// This is time window sensitive
n := strconv.FormatInt(time.Now().UnixMilli(), 10)
@@ -573,9 +573,9 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.
Body: bytes.NewBufferString(payload),
Result: &intermediary,
NonceEnabled: true,
Verbose: b.Verbose,
HTTPDebugging: b.HTTPDebugging,
HTTPRecording: b.HTTPRecording,
Verbose: e.Verbose,
HTTPDebugging: e.HTTPDebugging,
HTTPRecording: e.HTTPRecording,
}, nil
}, request.AuthenticatedRequest)
if err != nil {
@@ -599,7 +599,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.
}
// GetFee returns an estimate of fee based on type of transaction
func (b *Bithumb) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
func (e *Exchange) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
var fee float64
switch feeBuilder.FeeType {
@@ -676,15 +676,15 @@ var errCode = map[string]string{
}
// GetCandleStick returns candle stick data for requested pair
func (b *Bithumb) GetCandleStick(ctx context.Context, symbol, interval string) (resp *OHLCVResponse, err error) {
func (e *Exchange) GetCandleStick(ctx context.Context, symbol, interval string) (resp *OHLCVResponse, err error) {
path := publicCandleStick + symbol + "/" + interval
err = b.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
err = e.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
return
}
// FetchExchangeLimits fetches spot order execution limits
func (b *Bithumb) FetchExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
ticks, err := b.GetAllTickers(ctx)
func (e *Exchange) FetchExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
ticks, err := e.GetAllTickers(ctx)
if err != nil {
return nil, err
}

View File

@@ -29,18 +29,18 @@ const (
var testPair = currency.NewPairWithDelimiter("BTC", "KRW", "_")
var b = &Bithumb{}
var e *Exchange
func TestMain(m *testing.M) {
b = new(Bithumb)
if err := testexch.Setup(b); err != nil {
e = new(Exchange)
if err := testexch.Setup(e); err != nil {
log.Fatalf("Bithumb Setup error: %s", err)
}
if apiKey != "" && apiSecret != "" {
b.API.AuthenticatedSupport = true
b.API.AuthenticatedWebsocketSupport = true
b.SetCredentials(apiKey, apiSecret, "", "", "", "")
e.API.AuthenticatedSupport = true
e.API.AuthenticatedWebsocketSupport = true
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
}
os.Exit(m.Run())
@@ -48,13 +48,13 @@ func TestMain(m *testing.M) {
func TestGetTradablePairs(t *testing.T) {
t.Parallel()
_, err := b.GetTradablePairs(t.Context())
_, err := e.GetTradablePairs(t.Context())
require.NoError(t, err, "GetTradablePairs must not error")
}
func TestGetTicker(t *testing.T) {
t.Parallel()
tick, err := b.GetTicker(t.Context(), testPair.Base.String())
tick, err := e.GetTicker(t.Context(), testPair.Base.String())
require.NoError(t, err, "GetTicker must not error")
assert.Positive(t, tick.OpeningPrice, "OpeningPrice should be positive")
assert.Positive(t, tick.ClosingPrice, "ClosingPrice should be positive")
@@ -73,14 +73,14 @@ func TestGetTicker(t *testing.T) {
// not all currencies have dates and fluctuation rates
func TestGetAllTickers(t *testing.T) {
t.Parallel()
tick, err := b.GetAllTickers(t.Context())
tick, err := e.GetAllTickers(t.Context())
require.NoError(t, err, "GetAllTickers must not error")
assert.NotEmpty(t, tick, "tick should not be empty")
}
func TestGetOrderBook(t *testing.T) {
t.Parallel()
ob, err := b.GetOrderBook(t.Context(), testPair.Base.String())
ob, err := e.GetOrderBook(t.Context(), testPair.Base.String())
require.NoError(t, err, "GetOrderBook must not error")
assert.NotEmpty(t, ob.Status, "Status should not be empty")
assert.NotEmpty(t, ob.Data.Timestamp, "Timestamp should not be empty")
@@ -90,8 +90,8 @@ func TestGetOrderBook(t *testing.T) {
func TestGetTransactionHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
_, err := b.GetTransactionHistory(t.Context(), testPair.Base.String())
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := e.GetTransactionHistory(t.Context(), testPair.Base.String())
require.NoError(t, err, "GetTransactionHistory must not error")
}
@@ -99,28 +99,28 @@ func TestGetAccountInformation(t *testing.T) {
t.Parallel()
// Offline test
_, err := b.GetAccountInformation(t.Context(), "", "")
_, err := e.GetAccountInformation(t.Context(), "", "")
assert.Error(t, err, "expected error when no order currency is specified")
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = b.GetAccountInformation(t.Context(), testPair.Base.String(), testPair.Quote.String())
_, err = e.GetAccountInformation(t.Context(), testPair.Base.String(), testPair.Quote.String())
assert.NoError(t, err, "GetAccountInformation should not error")
}
func TestGetAccountBalance(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetAccountBalance(t.Context(), testPair.Base.String())
_, err := e.GetAccountBalance(t.Context(), testPair.Base.String())
require.NoError(t, err, "GetAccountBalance must not error")
}
func TestGetWalletAddress(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
a, err := b.GetWalletAddress(t.Context(), testPair.Base)
a, err := e.GetWalletAddress(t.Context(), testPair.Base)
require.NoError(t, err, "GetWalletAddress must not error")
assert.NotEmpty(t, a.Data.Currency, "Currency should not be empty")
assert.NotEmpty(t, a.Data.Tag, "Tag should not be empty")
@@ -129,96 +129,96 @@ func TestGetWalletAddress(t *testing.T) {
func TestGetLastTransaction(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetLastTransaction(t.Context())
_, err := e.GetLastTransaction(t.Context())
require.NoError(t, err, "GetLastTransaction must not error")
}
func TestGetOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetOrders(t.Context(), "1337", order.Bid.Lower(), 100, time.Time{}, testPair.Base, testPair.Quote)
_, err := e.GetOrders(t.Context(), "1337", order.Bid.Lower(), 100, time.Time{}, testPair.Base, testPair.Quote)
require.NoError(t, err, "GetOrders must not error")
}
func TestGetUserTransactions(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetUserTransactions(t.Context(), 0, 0, 0, currency.EMPTYCODE, currency.EMPTYCODE)
_, err := e.GetUserTransactions(t.Context(), 0, 0, 0, currency.EMPTYCODE, currency.EMPTYCODE)
require.NoError(t, err, "GetUserTransactions must not error")
}
func TestPlaceTrade(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.PlaceTrade(t.Context(), testPair.Base.String(), order.Bid.Lower(), 0, 0)
_, err := e.PlaceTrade(t.Context(), testPair.Base.String(), order.Bid.Lower(), 0, 0)
require.NoError(t, err, "PlaceTrade must not error")
}
func TestGetOrderDetails(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetOrderDetails(t.Context(), "1337", order.Bid.Lower(), testPair.Base.String())
_, err := e.GetOrderDetails(t.Context(), "1337", order.Bid.Lower(), testPair.Base.String())
require.NoError(t, err, "GetOrderDetails must not error")
}
func TestCancelTrade(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.CancelTrade(t.Context(), "", "", "")
_, err := e.CancelTrade(t.Context(), "", "", "")
require.NoError(t, err, "CancelTrade must not error")
}
func TestWithdrawCrypto(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.WithdrawCrypto(t.Context(), "LQxiDhKU7idKiWQhx4ALKYkBx8xKEQVxJR", "", "ltc", 0)
_, err := e.WithdrawCrypto(t.Context(), "LQxiDhKU7idKiWQhx4ALKYkBx8xKEQVxJR", "", "ltc", 0)
require.NoError(t, err, "WithdrawCrypto must not error")
}
func TestRequestKRWDepositDetails(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
_, err := b.RequestKRWDepositDetails(t.Context())
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := e.RequestKRWDepositDetails(t.Context())
require.NoError(t, err, "RequestKRWDepositDetails must not error")
}
func TestRequestKRWWithdraw(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.RequestKRWWithdraw(t.Context(), "102_bank", "1337", 1000)
_, err := e.RequestKRWWithdraw(t.Context(), "102_bank", "1337", 1000)
require.NoError(t, err, "RequestKRWWithdraw must not error")
}
func TestMarketBuyOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.MarketBuyOrder(t.Context(), testPair, 0)
_, err := e.MarketBuyOrder(t.Context(), testPair, 0)
require.NoError(t, err, "MarketBuyOrder must not error")
}
func TestMarketSellOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.MarketSellOrder(t.Context(), testPair, 0)
_, err := e.MarketSellOrder(t.Context(), testPair, 0)
require.NoError(t, err, "MarketSellOrder must not error")
}
func TestUpdateTicker(t *testing.T) {
t.Parallel()
testexch.UpdatePairsOnce(t, b)
tick, err := b.UpdateTicker(t.Context(), testPair, asset.Spot)
testexch.UpdatePairsOnce(t, e)
tick, err := e.UpdateTicker(t.Context(), testPair, asset.Spot)
require.NoError(t, err, "UpdateTicker must not error")
assert.Positive(t, tick.High, "High should be positive")
assert.Positive(t, tick.Low, "Low should be positive")
@@ -233,8 +233,8 @@ func TestUpdateTicker(t *testing.T) {
func TestUpdateTickers(t *testing.T) {
t.Parallel()
testexch.UpdatePairsOnce(t, b)
err := b.UpdateTickers(t.Context(), asset.Spot)
testexch.UpdatePairsOnce(t, e)
err := e.UpdateTickers(t.Context(), asset.Spot)
require.NoError(t, err, "UpdateTickers must not error")
}
@@ -251,10 +251,10 @@ func setFeeBuilder() *exchange.FeeBuilder {
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
t.Parallel()
feeBuilder := setFeeBuilder()
_, err := b.GetFeeByType(t.Context(), feeBuilder)
_, err := e.GetFeeByType(t.Context(), feeBuilder)
require.NoError(t, err, "GetFeeByType must not error")
if !sharedtestvalues.AreAPICredentialsSet(b) {
if !sharedtestvalues.AreAPICredentialsSet(e) {
assert.Equal(t, exchange.OfflineTradeFee, feeBuilder.FeeType, "FeeType should be correct")
} else {
assert.Equal(t, exchange.CryptocurrencyTradeFee, feeBuilder.FeeType, "FeeType should be correct")
@@ -265,65 +265,65 @@ func TestGetFee(t *testing.T) {
t.Parallel()
feeBuilder := setFeeBuilder()
// CryptocurrencyTradeFee Basic
_, err := b.GetFee(feeBuilder)
_, err := e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// CryptocurrencyTradeFee High quantity
feeBuilder = setFeeBuilder()
feeBuilder.Amount = 1000
feeBuilder.PurchasePrice = 1000
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// CryptocurrencyTradeFee IsMaker
feeBuilder = setFeeBuilder()
feeBuilder.IsMaker = true
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// CryptocurrencyTradeFee Negative purchase price
feeBuilder = setFeeBuilder()
feeBuilder.PurchasePrice = -1000
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// CryptocurrencyWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// CryptocurrencyDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyDepositFee
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.FiatCurrency = currency.HKD
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.FiatCurrency = currency.HKD
_, err = b.GetFee(feeBuilder)
_, err = e.GetFee(feeBuilder)
require.NoError(t, err, "GetFee must not error")
}
func TestFormatWithdrawPermissions(t *testing.T) {
t.Parallel()
expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.AutoWithdrawFiatText
withdrawPermissions := b.FormatWithdrawPermissions()
withdrawPermissions := e.FormatWithdrawPermissions()
assert.Equal(t, expectedResult, withdrawPermissions, "withdrawPermissions should be correct")
}
func TestGetActiveOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
getOrdersRequest := order.MultiOrderRequest{
Type: order.AnyType,
@@ -331,13 +331,13 @@ func TestGetActiveOrders(t *testing.T) {
AssetType: asset.Spot,
}
_, err := b.GetActiveOrders(t.Context(), &getOrdersRequest)
_, err := e.GetActiveOrders(t.Context(), &getOrdersRequest)
require.NoError(t, err, "GetActiveOrders must not error")
}
func TestGetOrderHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
getOrdersRequest := order.MultiOrderRequest{
Type: order.AnyType,
@@ -346,7 +346,7 @@ func TestGetOrderHistory(t *testing.T) {
Pairs: currency.Pairs{testPair},
}
_, err := b.GetOrderHistory(t.Context(), &getOrdersRequest)
_, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
require.NoError(t, err, "GetOrderHistory must not error")
}
@@ -355,10 +355,10 @@ func TestGetOrderHistory(t *testing.T) {
func TestSubmitOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
orderSubmission := &order.Submit{
Exchange: b.Name,
Exchange: e.Name,
Pair: testPair,
Side: order.Buy,
Type: order.Limit,
@@ -367,13 +367,13 @@ func TestSubmitOrder(t *testing.T) {
ClientID: "meowOrder",
AssetType: asset.Spot,
}
_, err := b.SubmitOrder(t.Context(), orderSubmission)
_, err := e.SubmitOrder(t.Context(), orderSubmission)
require.NoError(t, err, "SubmitOrder must not error")
}
func TestCancelExchangeOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
orderCancellation := &order.Cancel{
OrderID: "1",
@@ -382,13 +382,13 @@ func TestCancelExchangeOrder(t *testing.T) {
AssetType: asset.Spot,
}
err := b.CancelOrder(t.Context(), orderCancellation)
err := e.CancelOrder(t.Context(), orderCancellation)
require.NoError(t, err, "CancelOrder must not error")
}
func TestCancelAllExchangeOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
orderCancellation := &order.Cancel{
OrderID: "1",
@@ -397,7 +397,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
AssetType: asset.Spot,
}
resp, err := b.CancelAllOrders(t.Context(), orderCancellation)
resp, err := e.CancelAllOrders(t.Context(), orderCancellation)
require.NoError(t, err, "CancelAllOrders must not error")
assert.Emptyf(t, resp.Status, "%v orders failed to cancel", len(resp.Status))
@@ -405,17 +405,17 @@ func TestCancelAllExchangeOrders(t *testing.T) {
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.UpdateAccountInfo(t.Context(), asset.Spot)
_, err := e.UpdateAccountInfo(t.Context(), asset.Spot)
require.NoError(t, err, "UpdateAccountInfo must not error")
}
func TestModifyOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err := b.ModifyOrder(t.Context(), &order.Modify{
_, err := e.ModifyOrder(t.Context(), &order.Modify{
OrderID: "1337",
Price: 100,
Amount: 1000,
@@ -428,21 +428,21 @@ func TestModifyOrder(t *testing.T) {
func TestWithdraw(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
t.Skip("TestWithdraw not allowed for live tests")
}
func TestWithdrawFiat(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
withdrawFiatRequest := withdraw.Request{
Type: withdraw.Fiat,
Exchange: b.Name,
Exchange: e.Name,
Fiat: withdraw.FiatRequest{
Bank: banking.Account{
SupportedExchanges: b.Name,
SupportedExchanges: e.Name,
Enabled: true,
AccountName: "Satoshi Nakamoto",
AccountNumber: "12345",
@@ -464,30 +464,30 @@ func TestWithdrawFiat(t *testing.T) {
Description: "WITHDRAW IT ALL",
}
_, err := b.WithdrawFiatFunds(t.Context(), &withdrawFiatRequest)
_, err := e.WithdrawFiatFunds(t.Context(), &withdrawFiatRequest)
require.NoError(t, err, "WithdrawFiatFunds must not error")
}
func TestWithdrawInternationalBank(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
withdrawFiatRequest := withdraw.Request{}
_, err := b.WithdrawFiatFundsToInternationalBank(t.Context(), &withdrawFiatRequest)
_, err := e.WithdrawFiatFundsToInternationalBank(t.Context(), &withdrawFiatRequest)
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
}
func TestGetDepositAddress(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetDepositAddress(t.Context(), testPair.Base, "", "")
_, err := e.GetDepositAddress(t.Context(), testPair.Base, "", "")
require.NoError(t, err, "GetDepositAddress must not error")
}
func TestGetCandleStick(t *testing.T) {
t.Parallel()
c, err := b.GetCandleStick(t.Context(), testPair.String(), "1m")
c, err := e.GetCandleStick(t.Context(), testPair.String(), "1m")
require.NoError(t, err, "GetCandleStick must not error")
assert.NotEmpty(t, c.Status, "Status should not be empty")
assert.NotEmpty(t, c.Data, "Data should not be empty")
@@ -496,7 +496,7 @@ func TestGetCandleStick(t *testing.T) {
func TestGetHistoricCandles(t *testing.T) {
t.Parallel()
startTime := time.Now().AddDate(0, -1, 0)
c, err := b.GetHistoricCandles(t.Context(), testPair, asset.Spot, kline.OneDay, startTime, time.Now())
c, err := e.GetHistoricCandles(t.Context(), testPair, asset.Spot, kline.OneDay, startTime, time.Now())
require.NoError(t, err, "GetHistoricCandles must not error")
assert.NotEmpty(t, c.Exchange, "Exchange should not be empty")
assert.NotEmpty(t, c.Candles, "Candles should not be empty")
@@ -505,14 +505,14 @@ func TestGetHistoricCandles(t *testing.T) {
func TestGetHistoricCandlesExtended(t *testing.T) {
t.Parallel()
startTime := time.Now().Add(-time.Hour * 24)
_, err := b.GetHistoricCandlesExtended(t.Context(), testPair, asset.Spot, kline.OneDay, startTime, time.Now())
_, err := e.GetHistoricCandlesExtended(t.Context(), testPair, asset.Spot, kline.OneDay, startTime, time.Now())
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
}
func TestGetRecentTrades(t *testing.T) {
t.Parallel()
tr, err := b.GetRecentTrades(t.Context(), testPair, asset.Spot)
tr, err := e.GetRecentTrades(t.Context(), testPair, asset.Spot)
require.NoError(t, err, "GetRecentTrades must not error")
assert.NotEmpty(t, tr, "Trades should not be empty")
for _, req := range tr {
@@ -526,16 +526,16 @@ func TestGetRecentTrades(t *testing.T) {
func TestGetHistoricTrades(t *testing.T) {
t.Parallel()
_, err := b.GetHistoricTrades(t.Context(), testPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
_, err := e.GetHistoricTrades(t.Context(), testPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
}
func TestUpdateOrderExecutionLimits(t *testing.T) {
t.Parallel()
err := b.UpdateOrderExecutionLimits(t.Context(), asset.Empty)
err := e.UpdateOrderExecutionLimits(t.Context(), asset.Empty)
require.NoError(t, err, "UpdateOrderExecutionLimits must not error")
limit, err := b.GetOrderExecutionLimits(asset.Spot, testPair)
limit, err := e.GetOrderExecutionLimits(asset.Spot, testPair)
require.NoError(t, err, "GetOrderExecutionLimits must not error")
err = limit.Conforms(46241000, 0.00001, order.Limit)
@@ -595,10 +595,10 @@ func TestGetAmountMinimum(t *testing.T) {
func TestGetAssetStatus(t *testing.T) {
t.Parallel()
_, err := b.GetAssetStatus(t.Context(), "")
_, err := e.GetAssetStatus(t.Context(), "")
assert.ErrorIs(t, err, errSymbolIsEmpty)
s, err := b.GetAssetStatus(t.Context(), "sol")
s, err := e.GetAssetStatus(t.Context(), "sol")
require.NoError(t, err, "GetAssetStatus must not error")
assert.NotEmpty(t, s.Status, "Status should not be empty")
assert.NotEmpty(t, s.Data.DepositStatus, "DepositStatus should not be empty")
@@ -607,7 +607,7 @@ func TestGetAssetStatus(t *testing.T) {
func TestGetAssetStatusAll(t *testing.T) {
t.Parallel()
s, err := b.GetAssetStatusAll(t.Context())
s, err := e.GetAssetStatusAll(t.Context())
require.NoError(t, err, "GetAssetStatusAll must not error")
require.NoError(t, err, "GetAssetStatus must not error")
assert.NotEmpty(t, s.Status, "Status should not be empty")
@@ -615,42 +615,42 @@ func TestGetAssetStatusAll(t *testing.T) {
func TestUpdateCurrencyStates(t *testing.T) {
t.Parallel()
err := b.UpdateCurrencyStates(t.Context(), asset.Spot)
err := e.UpdateCurrencyStates(t.Context(), asset.Spot)
require.NoError(t, err, "UpdateCurrencyStates must not error")
}
func TestGetWithdrawalsHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetWithdrawalsHistory(t.Context(), testPair.Base, asset.Spot)
_, err := e.GetWithdrawalsHistory(t.Context(), testPair.Base, asset.Spot)
require.NoError(t, err, "GetWithdrawalsHistory must not error")
}
func TestGetOrderInfo(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetOrderInfo(t.Context(), "1234", testPair, asset.Spot)
_, err := e.GetOrderInfo(t.Context(), "1234", testPair, asset.Spot)
require.NoError(t, err, "GetOrderInfo must not error")
}
func TestGetWithdrawalHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := b.GetWithdrawalsHistory(t.Context(), testPair.Base, asset.Spot)
_, err := e.GetWithdrawalsHistory(t.Context(), testPair.Base, asset.Spot)
require.NoError(t, err, "GetWithdrawalsHistory must not error")
}
func TestGetCurrencyTradeURL(t *testing.T) {
t.Parallel()
testexch.UpdatePairsOnce(t, b)
for _, a := range b.GetAssetTypes(false) {
pairs, err := b.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 := b.GetCurrencyTradeURL(t.Context(), a, pairs[0])
resp, err := e.GetCurrencyTradeURL(t.Context(), a, pairs[0])
require.NoError(t, err)
assert.NotEmpty(t, resp)
}

View File

@@ -35,50 +35,50 @@ var defaultSubscriptions = subscription.List{
}
// WsConnect initiates a websocket connection
func (b *Bithumb) WsConnect() error {
func (e *Exchange) WsConnect() error {
ctx := context.TODO()
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
if !e.Websocket.IsEnabled() || !e.IsEnabled() {
return websocket.ErrWebsocketNotEnabled
}
var dialer gws.Dialer
dialer.HandshakeTimeout = b.Config.HTTPTimeout
dialer.HandshakeTimeout = e.Config.HTTPTimeout
dialer.Proxy = http.ProxyFromEnvironment
err := b.Websocket.Conn.Dial(ctx, &dialer, http.Header{})
err := e.Websocket.Conn.Dial(ctx, &dialer, http.Header{})
if err != nil {
return fmt.Errorf("%v - Unable to connect to Websocket. Error: %w", b.Name, err)
return fmt.Errorf("%v - Unable to connect to Websocket. Error: %w", e.Name, err)
}
b.Websocket.Wg.Add(1)
go b.wsReadData()
e.Websocket.Wg.Add(1)
go e.wsReadData()
b.setupOrderbookManager(ctx)
e.setupOrderbookManager(ctx)
return nil
}
// wsReadData receives and passes on websocket messages for processing
func (b *Bithumb) wsReadData() {
defer b.Websocket.Wg.Done()
func (e *Exchange) wsReadData() {
defer e.Websocket.Wg.Done()
for {
select {
case <-b.Websocket.ShutdownC:
case <-e.Websocket.ShutdownC:
return
default:
resp := b.Websocket.Conn.ReadMessage()
resp := e.Websocket.Conn.ReadMessage()
if resp.Raw == nil {
return
}
err := b.wsHandleData(resp.Raw)
err := e.wsHandleData(resp.Raw)
if err != nil {
b.Websocket.DataHandler <- err
e.Websocket.DataHandler <- err
}
}
}
}
func (b *Bithumb) wsHandleData(respRaw []byte) error {
func (e *Exchange) wsHandleData(respRaw []byte) error {
var resp WsResponse
err := json.Unmarshal(respRaw, &resp)
if err != nil {
@@ -102,12 +102,12 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {
return err
}
var lu time.Time
lu, err = time.ParseInLocation(tickerTimeLayout, tick.Date+tick.Time, b.location)
lu, err = time.ParseInLocation(tickerTimeLayout, tick.Date+tick.Time, e.location)
if err != nil {
return err
}
b.Websocket.DataHandler <- &ticker.Price{
ExchangeName: b.Name,
e.Websocket.DataHandler <- &ticker.Price{
ExchangeName: e.Name,
AssetType: asset.Spot,
Last: tick.PreviousClosePrice,
Pair: tick.Symbol,
@@ -120,7 +120,7 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {
LastUpdated: lu,
}
case "transaction":
if !b.IsSaveTradeDataEnabled() {
if !e.IsSaveTradeDataEnabled() {
return nil
}
@@ -133,13 +133,13 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {
toBuffer := make([]trade.Data, len(trades.List))
var lu time.Time
for x := range trades.List {
lu, err = time.ParseInLocation(tradeTimeLayout, trades.List[x].ContractTime, b.location)
lu, err = time.ParseInLocation(tradeTimeLayout, trades.List[x].ContractTime, e.location)
if err != nil {
return err
}
toBuffer[x] = trade.Data{
Exchange: b.Name,
Exchange: e.Name,
AssetType: asset.Spot,
CurrencyPair: trades.List[x].Symbol,
Timestamp: lu,
@@ -148,7 +148,7 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {
}
}
err = b.AddTradesToBuffer(toBuffer...)
err = e.AddTradesToBuffer(toBuffer...)
if err != nil {
return err
}
@@ -158,9 +158,9 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {
if err != nil {
return err
}
init, err := b.UpdateLocalBuffer(&orderbooks)
init, err := e.UpdateLocalBuffer(&orderbooks)
if err != nil && !init {
return fmt.Errorf("%v - UpdateLocalCache error: %s", b.Name, err)
return fmt.Errorf("%v - UpdateLocalCache error: %s", e.Name, err)
}
return nil
default:
@@ -171,23 +171,23 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {
}
// generateSubscriptions generates the default subscription set
func (b *Bithumb) generateSubscriptions() (subscription.List, error) {
return b.Features.Subscriptions.ExpandTemplates(b)
func (e *Exchange) generateSubscriptions() (subscription.List, error) {
return e.Features.Subscriptions.ExpandTemplates(e)
}
// GetSubscriptionTemplate returns a subscription channel template
func (b *Bithumb) GetSubscriptionTemplate(_ *subscription.Subscription) (*template.Template, error) {
func (e *Exchange) GetSubscriptionTemplate(_ *subscription.Subscription) (*template.Template, error) {
return template.New("master.tmpl").Funcs(sprig.FuncMap()).Funcs(template.FuncMap{"subToReq": subToReq}).Parse(subTplText)
}
// Subscribe subscribes to a set of channels
func (b *Bithumb) Subscribe(subs subscription.List) error {
func (e *Exchange) Subscribe(subs subscription.List) error {
ctx := context.TODO()
var errs error
for _, s := range subs {
err := b.Websocket.Conn.SendJSONMessage(ctx, request.Unset, json.RawMessage(s.QualifiedChannel))
err := e.Websocket.Conn.SendJSONMessage(ctx, request.Unset, json.RawMessage(s.QualifiedChannel))
if err == nil {
err = b.Websocket.AddSuccessfulSubscriptions(b.Websocket.Conn, s)
err = e.Websocket.AddSuccessfulSubscriptions(e.Websocket.Conn, s)
}
if err != nil {
errs = common.AppendError(errs, err)

View File

@@ -28,7 +28,7 @@ func TestWsHandleData(t *testing.T) {
pairs := currency.Pairs{currency.NewBTCUSDT()}
dummy := Bithumb{
dummy := Exchange{
location: time.Local,
Base: exchange.Base{
Name: "dummy",
@@ -52,7 +52,7 @@ func TestWsHandleData(t *testing.T) {
}
dummy.setupOrderbookManager(t.Context())
dummy.API.Endpoints = b.NewEndpoints()
dummy.API.Endpoints = e.NewEndpoints()
welcomeMsg := []byte(`{"status":"0000","resmsg":"Connected Successfully"}`)
err := dummy.wsHandleData(welcomeMsg)
@@ -94,12 +94,12 @@ func TestSubToReq(t *testing.T) {
func TestGenerateSubscriptions(t *testing.T) {
t.Parallel()
b := new(Bithumb)
require.NoError(t, testexch.Setup(b), "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", "KRW", "_"), currency.NewPairWithDelimiter("ETH", "KRW", "_")}
require.NoError(t, b.CurrencyPairs.StorePairs(asset.Spot, p, false))
require.NoError(t, b.CurrencyPairs.StorePairs(asset.Spot, p, true))
subs, err := b.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.AllTradesChannel, Pairs: p, QualifiedChannel: `{"type":"transaction","symbols":["BTC_KRW","ETH_KRW"]}`},

View File

@@ -35,26 +35,26 @@ import (
var errNotEnoughPairs = errors.New("at least one currency is required to fetch order history")
// SetDefaults sets the basic defaults for Bithumb
func (b *Bithumb) SetDefaults() {
b.Name = "Bithumb"
b.Enabled = true
b.Verbose = true
b.API.CredentialsValidator.RequiresKey = true
b.API.CredentialsValidator.RequiresSecret = true
func (e *Exchange) SetDefaults() {
e.Name = "Bithumb"
e.Enabled = true
e.Verbose = true
e.API.CredentialsValidator.RequiresKey = true
e.API.CredentialsValidator.RequiresSecret = true
requestFmt := &currency.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}
configFmt := &currency.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}
err := b.SetGlobalPairsManager(requestFmt, configFmt, asset.Spot)
err := e.SetGlobalPairsManager(requestFmt, configFmt, asset.Spot)
if err != nil {
log.Errorln(log.ExchangeSys, err)
}
b.location, err = time.LoadLocation("Asia/Seoul")
e.location, err = time.LoadLocation("Asia/Seoul")
if err != nil {
log.Errorf(log.ExchangeSys, "Bithumb unable to load time location: %s", err)
}
b.Features = exchange.Features{
e.Features = exchange.Features{
Supports: exchange.FeaturesSupported{
REST: true,
RESTCapabilities: protocol.Features{
@@ -116,14 +116,14 @@ func (b *Bithumb) SetDefaults() {
},
Subscriptions: defaultSubscriptions.Clone(),
}
b.Requester, err = request.New(b.Name,
e.Requester, err = request.New(e.Name,
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout),
request.WithLimiter(GetRateLimit()))
if err != nil {
log.Errorln(log.ExchangeSys, err)
}
b.API.Endpoints = b.NewEndpoints()
err = b.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
e.API.Endpoints = e.NewEndpoints()
err = e.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
exchange.RestSpot: apiURL,
exchange.WebsocketSpot: wsEndpoint,
})
@@ -131,44 +131,44 @@ func (b *Bithumb) SetDefaults() {
log.Errorln(log.ExchangeSys, err)
}
b.Websocket = websocket.NewManager()
b.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
b.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
e.Websocket = websocket.NewManager()
e.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
e.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
}
// Setup takes in the supplied exchange configuration details and sets params
func (b *Bithumb) Setup(exch *config.Exchange) error {
func (e *Exchange) Setup(exch *config.Exchange) error {
err := exch.Validate()
if err != nil {
return err
}
if !exch.Enabled {
b.SetEnabled(false)
e.SetEnabled(false)
return nil
}
err = b.SetupDefaults(exch)
err = e.SetupDefaults(exch)
if err != nil {
return err
}
ePoint, err := b.API.Endpoints.GetURL(exchange.WebsocketSpot)
ePoint, err := e.API.Endpoints.GetURL(exchange.WebsocketSpot)
if err != nil {
return err
}
err = b.Websocket.Setup(&websocket.ManagerSetup{
err = e.Websocket.Setup(&websocket.ManagerSetup{
ExchangeConfig: exch,
DefaultURL: wsEndpoint,
RunningURL: ePoint,
Connector: b.WsConnect,
Subscriber: b.Subscribe,
GenerateSubscriptions: b.generateSubscriptions,
Features: &b.Features.Supports.WebsocketCapabilities,
Connector: e.WsConnect,
Subscriber: e.Subscribe,
GenerateSubscriptions: e.generateSubscriptions,
Features: &e.Features.Supports.WebsocketCapabilities,
})
if err != nil {
return err
}
return b.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
return e.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
RateLimit: request.NewWeightedRateLimitByDuration(time.Second),
@@ -176,8 +176,8 @@ func (b *Bithumb) Setup(exch *config.Exchange) error {
}
// FetchTradablePairs returns a list of the exchanges tradable pairs
func (b *Bithumb) FetchTradablePairs(ctx context.Context, _ asset.Item) (currency.Pairs, error) {
currencies, err := b.GetTradablePairs(ctx)
func (e *Exchange) FetchTradablePairs(ctx context.Context, _ asset.Item) (currency.Pairs, error) {
currencies, err := e.GetTradablePairs(ctx)
if err != nil {
return nil, err
}
@@ -196,25 +196,25 @@ func (b *Bithumb) FetchTradablePairs(ctx context.Context, _ asset.Item) (currenc
// UpdateTradablePairs updates the exchanges available pairs and stores
// them in the exchanges config
func (b *Bithumb) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error {
pairs, err := b.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 = b.UpdatePairs(pairs, asset.Spot, false, forceUpdate)
err = e.UpdatePairs(pairs, asset.Spot, false, forceUpdate)
if err != nil {
return err
}
return b.EnsureOnePairEnabled()
return e.EnsureOnePairEnabled()
}
// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (b *Bithumb) UpdateTickers(ctx context.Context, a asset.Item) error {
tickers, err := b.GetAllTickers(ctx)
func (e *Exchange) UpdateTickers(ctx context.Context, a asset.Item) error {
tickers, err := e.GetAllTickers(ctx)
if err != nil {
return err
}
pairs, err := b.GetEnabledPairs(a)
pairs, err := e.GetEnabledPairs(a)
if err != nil {
return err
}
@@ -226,7 +226,7 @@ func (b *Bithumb) UpdateTickers(ctx context.Context, a asset.Item) error {
return fmt.Errorf("enabled pair %s [%s] not found in returned ticker map %v",
pairs[i], pairs, tickers)
}
p, err := b.FormatExchangeCurrency(pairs[i], a)
p, err := e.FormatExchangeCurrency(pairs[i], a)
if err != nil {
return err
}
@@ -237,7 +237,7 @@ func (b *Bithumb) UpdateTickers(ctx context.Context, a asset.Item) error {
Open: t.OpeningPrice,
Close: t.ClosingPrice,
Pair: p,
ExchangeName: b.Name,
ExchangeName: e.Name,
AssetType: a,
})
if err != nil {
@@ -248,30 +248,30 @@ func (b *Bithumb) UpdateTickers(ctx context.Context, a asset.Item) error {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bithumb) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
if err := b.UpdateTickers(ctx, a); err != nil {
func (e *Exchange) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
if err := e.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)
return ticker.GetTicker(e.Name, p, a)
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bithumb) 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 := b.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
if err := e.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
return nil, err
}
book := &orderbook.Book{
Exchange: b.Name,
Exchange: e.Name,
Pair: p,
Asset: assetType,
ValidateOrderbook: b.ValidateOrderbook,
ValidateOrderbook: e.ValidateOrderbook,
}
curr := p.Base.String()
orderbookNew, err := b.GetOrderBook(ctx, curr)
orderbookNew, err := e.GetOrderBook(ctx, curr)
if err != nil {
return book, err
}
@@ -296,14 +296,14 @@ func (b *Bithumb) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp
if err != nil {
return book, err
}
return orderbook.Get(b.Name, p, assetType)
return orderbook.Get(e.Name, p, assetType)
}
// UpdateAccountInfo retrieves balances for all enabled currencies for the
// Bithumb exchange
func (b *Bithumb) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
var info account.Holdings
bal, err := b.GetAccountBalance(ctx, "ALL")
bal, err := e.GetAccountBalance(ctx, "ALL")
if err != nil {
return info, err
}
@@ -334,8 +334,8 @@ func (b *Bithumb) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (
AssetType: assetType,
})
info.Exchange = b.Name
creds, err := b.GetCredentials(ctx)
info.Exchange = e.Name
creds, err := e.GetCredentials(ctx)
if err != nil {
return account.Holdings{}, err
}
@@ -349,13 +349,13 @@ func (b *Bithumb) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (
// GetAccountFundingHistory returns funding history, deposits and
// withdrawals
func (b *Bithumb) GetAccountFundingHistory(_ context.Context) ([]exchange.FundingHistory, error) {
func (e *Exchange) GetAccountFundingHistory(_ context.Context) ([]exchange.FundingHistory, error) {
return nil, common.ErrFunctionNotSupported
}
// GetWithdrawalsHistory returns previous withdrawals data
func (b *Bithumb) GetWithdrawalsHistory(ctx context.Context, c currency.Code, _ asset.Item) ([]exchange.WithdrawalHistory, error) {
transactions, err := b.GetUserTransactions(ctx, 0, 0, 3, c, currency.EMPTYCODE)
func (e *Exchange) GetWithdrawalsHistory(ctx context.Context, c currency.Code, _ asset.Item) ([]exchange.WithdrawalHistory, error) {
transactions, err := e.GetUserTransactions(ctx, 0, 0, 3, c, currency.EMPTYCODE)
if err != nil {
return nil, err
}
@@ -372,13 +372,13 @@ func (b *Bithumb) GetWithdrawalsHistory(ctx context.Context, c currency.Code, _
}
// GetRecentTrades returns the most recent trades for a currency and asset
func (b *Bithumb) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
func (e *Exchange) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
var err error
p, err = b.FormatExchangeCurrency(p, assetType)
p, err = e.FormatExchangeCurrency(p, assetType)
if err != nil {
return nil, err
}
tradeData, err := b.GetTransactionHistory(ctx, p.String())
tradeData, err := e.GetTransactionHistory(ctx, p.String())
if err != nil {
return nil, err
}
@@ -390,7 +390,7 @@ func (b *Bithumb) GetRecentTrades(ctx context.Context, p currency.Pair, assetTyp
return nil, err
}
resp[i] = trade.Data{
Exchange: b.Name,
Exchange: e.Name,
CurrencyPair: p,
AssetType: assetType,
Side: side,
@@ -400,7 +400,7 @@ func (b *Bithumb) GetRecentTrades(ctx context.Context, p currency.Pair, assetTyp
}
}
err = b.AddTradesToBuffer(resp...)
err = e.AddTradesToBuffer(resp...)
if err != nil {
return nil, err
}
@@ -410,18 +410,18 @@ func (b *Bithumb) GetRecentTrades(ctx context.Context, p currency.Pair, assetTyp
}
// GetHistoricTrades returns historic trade data within the timeframe provided
func (b *Bithumb) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.Item, _, _ time.Time) ([]trade.Data, error) {
func (e *Exchange) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.Item, _, _ time.Time) ([]trade.Data, error) {
return nil, common.ErrFunctionNotSupported
}
// SubmitOrder submits a new order
// TODO: Fill this out to support limit orders
func (b *Bithumb) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
if err := s.Validate(b.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
}
fPair, err := b.FormatExchangeCurrency(s.Pair, s.AssetType)
fPair, err := e.FormatExchangeCurrency(s.Pair, s.AssetType)
if err != nil {
return nil, err
}
@@ -429,14 +429,14 @@ func (b *Bithumb) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Subm
var orderID string
if s.Side.IsLong() {
var result MarketBuy
result, err = b.MarketBuyOrder(ctx, fPair, s.Amount)
result, err = e.MarketBuyOrder(ctx, fPair, s.Amount)
if err != nil {
return nil, err
}
orderID = result.OrderID
} else if s.Side.IsShort() {
var result MarketSell
result, err = b.MarketSellOrder(ctx, fPair, s.Amount)
result, err = e.MarketSellOrder(ctx, fPair, s.Amount)
if err != nil {
return nil, err
}
@@ -447,27 +447,27 @@ func (b *Bithumb) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Subm
// ModifyOrder will allow of changing orderbook placement and limit to
// market conversion
func (b *Bithumb) 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 (b *Bithumb) 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
}
_, err := b.CancelTrade(ctx, o.Side.String(), o.OrderID, o.Pair.Base.String())
_, err := e.CancelTrade(ctx, o.Side.String(), o.OrderID, o.Pair.Base.String())
return err
}
// CancelBatchOrders cancels an orders by their corresponding ID numbers
func (b *Bithumb) CancelBatchOrders(_ context.Context, _ []order.Cancel) (*order.CancelBatchResponse, error) {
func (e *Exchange) CancelBatchOrders(_ context.Context, _ []order.Cancel) (*order.CancelBatchResponse, error) {
return nil, common.ErrFunctionNotSupported
}
// CancelAllOrders cancels all orders associated with a currency pair
func (b *Bithumb) CancelAllOrders(ctx context.Context, orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
func (e *Exchange) CancelAllOrders(ctx context.Context, orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
if err := orderCancellation.Validate(); err != nil {
return order.CancelAllResponse{}, err
}
@@ -477,13 +477,13 @@ func (b *Bithumb) CancelAllOrders(ctx context.Context, orderCancellation *order.
}
var allOrders []OrderData
currs, err := b.GetEnabledPairs(asset.Spot)
currs, err := e.GetEnabledPairs(asset.Spot)
if err != nil {
return cancelAllOrdersResponse, err
}
for i := range currs {
orders, err := b.GetOrders(ctx, "", orderCancellation.Side.String(), 100, time.Time{}, currs[i].Base, currency.EMPTYCODE)
orders, err := e.GetOrders(ctx, "", orderCancellation.Side.String(), 100, time.Time{}, currs[i].Base, currency.EMPTYCODE)
if err != nil {
return cancelAllOrdersResponse, err
}
@@ -491,7 +491,7 @@ func (b *Bithumb) CancelAllOrders(ctx context.Context, orderCancellation *order.
}
for i := range allOrders {
_, err := b.CancelTrade(ctx,
_, err := e.CancelTrade(ctx,
orderCancellation.Side.String(),
allOrders[i].OrderID,
orderCancellation.Pair.Base.String())
@@ -504,11 +504,11 @@ func (b *Bithumb) CancelAllOrders(ctx context.Context, orderCancellation *order.
}
// GetOrderInfo returns order information based on order ID
func (b *Bithumb) GetOrderInfo(ctx context.Context, orderID string, pair currency.Pair, _ asset.Item) (*order.Detail, error) {
func (e *Exchange) GetOrderInfo(ctx context.Context, orderID string, pair currency.Pair, _ asset.Item) (*order.Detail, error) {
if pair.IsEmpty() {
return nil, currency.ErrCurrencyPairEmpty
}
orders, err := b.GetOrders(ctx, orderID, "", 0, time.Time{}, pair.Base, currency.EMPTYCODE)
orders, err := e.GetOrders(ctx, orderID, "", 0, time.Time{}, pair.Base, currency.EMPTYCODE)
if err != nil {
return nil, err
}
@@ -518,7 +518,7 @@ func (b *Bithumb) GetOrderInfo(ctx context.Context, orderID string, pair currenc
}
orderDetail := order.Detail{
Amount: orders.Data[i].Units,
Exchange: b.Name,
Exchange: e.Name,
ExecutedAmount: orders.Data[i].Units - orders.Data[i].UnitsRemaining,
OrderID: orders.Data[i].OrderID,
Date: orders.Data[i].OrderDate.Time(),
@@ -540,8 +540,8 @@ func (b *Bithumb) GetOrderInfo(ctx context.Context, orderID string, pair currenc
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bithumb) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, _ string) (*deposit.Address, error) {
addr, err := b.GetWalletAddress(ctx, cryptocurrency)
func (e *Exchange) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, _ string) (*deposit.Address, error) {
addr, err := e.GetWalletAddress(ctx, cryptocurrency)
if err != nil {
return nil, err
}
@@ -554,11 +554,11 @@ func (b *Bithumb) GetDepositAddress(ctx context.Context, cryptocurrency currency
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
// submitted
func (b *Bithumb) 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
}
v, err := b.WithdrawCrypto(ctx,
v, err := e.WithdrawCrypto(ctx,
withdrawRequest.Crypto.Address,
withdrawRequest.Crypto.AddressTag,
withdrawRequest.Currency.String(),
@@ -574,7 +574,7 @@ func (b *Bithumb) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawReque
// WithdrawFiatFunds returns a withdrawal ID when a
// withdrawal is submitted
func (b *Bithumb) WithdrawFiatFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
func (e *Exchange) WithdrawFiatFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
if err := withdrawRequest.Validate(); err != nil {
return nil, err
}
@@ -586,7 +586,7 @@ func (b *Bithumb) WithdrawFiatFunds(ctx context.Context, withdrawRequest *withdr
}
bankDetails := strconv.FormatFloat(withdrawRequest.Fiat.Bank.BankCode, 'f', -1, 64) +
"_" + withdrawRequest.Fiat.Bank.BankName
resp, err := b.RequestKRWWithdraw(ctx,
resp, err := e.RequestKRWWithdraw(ctx,
bankDetails,
withdrawRequest.Fiat.Bank.AccountNumber,
int64(withdrawRequest.Amount))
@@ -603,24 +603,24 @@ func (b *Bithumb) WithdrawFiatFunds(ctx context.Context, withdrawRequest *withdr
}
// WithdrawFiatFundsToInternationalBank is not supported as Bithumb only withdraws KRW to South Korean banks
func (b *Bithumb) 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 (b *Bithumb) 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 !b.AreCredentialsValid(ctx) && // Todo check connection status
if !e.AreCredentialsValid(ctx) && // Todo check connection status
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
feeBuilder.FeeType = exchange.OfflineTradeFee
}
return b.GetFee(feeBuilder)
return e.GetFee(feeBuilder)
}
// GetActiveOrders retrieves any orders that are active/open
func (b *Bithumb) 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
@@ -630,7 +630,7 @@ func (b *Bithumb) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequ
return nil, errNotEnoughPairs
}
format, err := b.GetPairFormat(req.AssetType, false)
format, err := e.GetPairFormat(req.AssetType, false)
if err != nil {
return nil, err
}
@@ -638,7 +638,7 @@ func (b *Bithumb) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequ
var orders []order.Detail
for x := range req.Pairs {
var resp Orders
resp, err = b.GetOrders(ctx, "", "", 1000, time.Time{}, req.Pairs[x].Base, currency.EMPTYCODE)
resp, err = e.GetOrders(ctx, "", "", 1000, time.Time{}, req.Pairs[x].Base, currency.EMPTYCODE)
if err != nil {
return nil, err
}
@@ -650,7 +650,7 @@ func (b *Bithumb) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequ
orderDetail := order.Detail{
Amount: resp.Data[i].Units,
Exchange: b.Name,
Exchange: e.Name,
ExecutedAmount: resp.Data[i].Units - resp.Data[i].UnitsRemaining,
OrderID: resp.Data[i].OrderID,
Date: resp.Data[i].OrderDate.Time(),
@@ -672,12 +672,12 @@ func (b *Bithumb) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequ
orders = append(orders, orderDetail)
}
}
return req.Filter(b.Name, orders), nil
return req.Filter(e.Name, orders), nil
}
// GetOrderHistory retrieves account order information
// Can Limit response to specific order status
func (b *Bithumb) 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
@@ -687,7 +687,7 @@ func (b *Bithumb) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequ
return nil, errNotEnoughPairs
}
format, err := b.GetPairFormat(req.AssetType, false)
format, err := e.GetPairFormat(req.AssetType, false)
if err != nil {
return nil, err
}
@@ -695,7 +695,7 @@ func (b *Bithumb) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequ
var orders []order.Detail
for x := range req.Pairs {
var resp Orders
resp, err = b.GetOrders(ctx, "", "", 1000, time.Time{}, req.Pairs[x].Base, currency.EMPTYCODE)
resp, err = e.GetOrders(ctx, "", "", 1000, time.Time{}, req.Pairs[x].Base, currency.EMPTYCODE)
if err != nil {
return nil, err
}
@@ -709,7 +709,7 @@ func (b *Bithumb) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequ
Amount: resp.Data[i].Units,
ExecutedAmount: resp.Data[i].Units - resp.Data[i].UnitsRemaining,
RemainingAmount: resp.Data[i].UnitsRemaining,
Exchange: b.Name,
Exchange: e.Name,
OrderID: resp.Data[i].OrderID,
Date: resp.Data[i].OrderDate.Time(),
Price: resp.Data[i].Price,
@@ -729,29 +729,29 @@ func (b *Bithumb) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequ
orders = append(orders, orderDetail)
}
}
return req.Filter(b.Name, orders), nil
return req.Filter(e.Name, orders), nil
}
// ValidateAPICredentials validates current credentials used for wrapper
// functionality
func (b *Bithumb) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
_, err := b.UpdateAccountInfo(ctx, assetType)
return b.CheckTransientError(err)
func (e *Exchange) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
_, err := e.UpdateAccountInfo(ctx, assetType)
return e.CheckTransientError(err)
}
// FormatExchangeKlineInterval returns Interval to exchange formatted string
func (b *Bithumb) FormatExchangeKlineInterval(in kline.Interval) string {
func (e *Exchange) FormatExchangeKlineInterval(in kline.Interval) string {
return in.Short()
}
// GetHistoricCandles returns candles between a time period for a set time interval
func (b *Bithumb) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
req, err := b.GetKlineRequest(pair, a, interval, start, end, true)
func (e *Exchange) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
req, err := e.GetKlineRequest(pair, a, interval, start, end, true)
if err != nil {
return nil, err
}
candles, err := b.GetCandleStick(ctx, req.RequestFormatted.String(), b.FormatExchangeKlineInterval(req.ExchangeInterval))
candles, err := e.GetCandleStick(ctx, req.RequestFormatted.String(), e.FormatExchangeKlineInterval(req.ExchangeInterval))
if err != nil {
return nil, err
}
@@ -777,22 +777,22 @@ func (b *Bithumb) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
}
// GetHistoricCandlesExtended returns candles between a time period for a set time interval
func (b *Bithumb) 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
}
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
func (b *Bithumb) UpdateOrderExecutionLimits(ctx context.Context, _ asset.Item) error {
limits, err := b.FetchExchangeLimits(ctx)
func (e *Exchange) UpdateOrderExecutionLimits(ctx context.Context, _ asset.Item) error {
limits, err := e.FetchExchangeLimits(ctx)
if err != nil {
return fmt.Errorf("cannot update exchange execution limits: %w", err)
}
return b.LoadLimits(limits)
return e.LoadLimits(limits)
}
// UpdateCurrencyStates updates currency states for exchange
func (b *Bithumb) UpdateCurrencyStates(ctx context.Context, a asset.Item) error {
status, err := b.GetAssetStatusAll(ctx)
func (e *Exchange) UpdateCurrencyStates(ctx context.Context, a asset.Item) error {
status, err := e.GetAssetStatusAll(ctx)
if err != nil {
return err
}
@@ -804,27 +804,27 @@ func (b *Bithumb) UpdateCurrencyStates(ctx context.Context, a asset.Item) error
Deposit: convert.BoolPtr(options.DepositStatus == 1),
}
}
return b.States.UpdateAll(a, payload)
return e.States.UpdateAll(a, payload)
}
// GetServerTime returns the current exchange server time.
func (b *Bithumb) GetServerTime(_ context.Context, _ asset.Item) (time.Time, error) {
func (e *Exchange) GetServerTime(_ context.Context, _ asset.Item) (time.Time, error) {
return time.Time{}, common.ErrFunctionNotSupported
}
// GetFuturesContractDetails returns all contracts from the exchange by asset type
func (b *Bithumb) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
func (e *Exchange) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
return nil, common.ErrFunctionNotSupported
}
// GetLatestFundingRates returns the latest funding rates data
func (b *Bithumb) 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 (b *Bithumb) GetCurrencyTradeURL(_ context.Context, a asset.Item, cp currency.Pair) (string, error) {
_, err := b.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
}

View File

@@ -24,7 +24,7 @@ const (
maxWSOrderbookWorkers = 10
)
func (b *Bithumb) processBooks(updates *WsOrderbooks) error {
func (e *Exchange) processBooks(updates *WsOrderbooks) error {
bids := make([]orderbook.Level, 0, len(updates.List))
asks := make([]orderbook.Level, 0, len(updates.List))
for x := range updates.List {
@@ -35,7 +35,7 @@ func (b *Bithumb) processBooks(updates *WsOrderbooks) error {
}
asks = append(asks, i)
}
return b.Websocket.Orderbook.Update(&orderbook.Update{
return e.Websocket.Orderbook.Update(&orderbook.Update{
Pair: updates.List[0].Symbol,
Asset: asset.Spot,
Bids: bids,
@@ -45,30 +45,30 @@ func (b *Bithumb) processBooks(updates *WsOrderbooks) error {
}
// UpdateLocalBuffer updates and returns the most recent iteration of the orderbook
func (b *Bithumb) UpdateLocalBuffer(wsdp *WsOrderbooks) (bool, error) {
func (e *Exchange) UpdateLocalBuffer(wsdp *WsOrderbooks) (bool, error) {
if len(wsdp.List) < 1 {
return false, errors.New("insufficient data to process")
}
err := b.obm.stageWsUpdate(wsdp, wsdp.List[0].Symbol, asset.Spot)
err := e.obm.stageWsUpdate(wsdp, wsdp.List[0].Symbol, asset.Spot)
if err != nil {
init, err2 := b.obm.checkIsInitialSync(wsdp.List[0].Symbol)
init, err2 := e.obm.checkIsInitialSync(wsdp.List[0].Symbol)
if err2 != nil {
return false, err2
}
return init, err
}
err = b.applyBufferUpdate(wsdp.List[0].Symbol)
err = e.applyBufferUpdate(wsdp.List[0].Symbol)
if err != nil {
b.invalidateAndCleanupOrderbook(wsdp.List[0].Symbol)
e.invalidateAndCleanupOrderbook(wsdp.List[0].Symbol)
}
return false, err
}
// applyBufferUpdate applies the buffer to the orderbook or initiates a new
// orderbook sync by the REST protocol which is off handed to go routine.
func (b *Bithumb) applyBufferUpdate(pair currency.Pair) error {
fetching, needsFetching, err := b.obm.handleFetchingBook(pair)
func (e *Exchange) applyBufferUpdate(pair currency.Pair) error {
fetching, needsFetching, err := e.obm.handleFetchingBook(pair)
if err != nil {
return err
}
@@ -77,22 +77,22 @@ func (b *Bithumb) applyBufferUpdate(pair currency.Pair) error {
}
if needsFetching {
if b.Verbose {
log.Debugf(log.WebsocketMgr, "%s Orderbook: Fetching via REST\n", b.Name)
if e.Verbose {
log.Debugf(log.WebsocketMgr, "%s Orderbook: Fetching via REST\n", e.Name)
}
return b.obm.fetchBookViaREST(pair)
return e.obm.fetchBookViaREST(pair)
}
recent, err := b.Websocket.Orderbook.GetOrderbook(pair, asset.Spot)
recent, err := e.Websocket.Orderbook.GetOrderbook(pair, asset.Spot)
if err != nil {
log.Errorf(log.WebsocketMgr, "%s error fetching recent orderbook when applying updates: %s\n", b.Name, err)
log.Errorf(log.WebsocketMgr, "%s error fetching recent orderbook when applying updates: %s\n", e.Name, err)
}
if recent != nil {
err = b.obm.checkAndProcessOrderbookUpdate(b.processBooks, pair, recent)
err = e.obm.checkAndProcessOrderbookUpdate(e.processBooks, pair, recent)
if err != nil {
log.Errorf(log.WebsocketMgr, "%s error processing update - initiating new orderbook sync via REST: %s\n", b.Name, err)
err = b.obm.setNeedsFetchingBook(pair)
log.Errorf(log.WebsocketMgr, "%s error processing update - initiating new orderbook sync via REST: %s\n", e.Name, err)
err = e.obm.setNeedsFetchingBook(pair)
if err != nil {
return err
}
@@ -104,24 +104,24 @@ func (b *Bithumb) applyBufferUpdate(pair currency.Pair) error {
// SynchroniseWebsocketOrderbook synchronises full orderbook for currency pair
// asset
func (b *Bithumb) SynchroniseWebsocketOrderbook(ctx context.Context) {
b.Websocket.Wg.Add(1)
func (e *Exchange) SynchroniseWebsocketOrderbook(ctx context.Context) {
e.Websocket.Wg.Add(1)
go func() {
defer b.Websocket.Wg.Done()
defer e.Websocket.Wg.Done()
for {
select {
case <-b.Websocket.ShutdownC:
case <-e.Websocket.ShutdownC:
for {
select {
case <-b.obm.jobs:
case <-e.obm.jobs:
default:
return
}
}
case j := <-b.obm.jobs:
err := b.processJob(ctx, j.Pair)
case j := <-e.obm.jobs:
err := e.processJob(ctx, j.Pair)
if err != nil {
log.Errorf(log.WebsocketMgr, "%s processing websocket orderbook error %v", b.Name, err)
log.Errorf(log.WebsocketMgr, "%s processing websocket orderbook error %v", e.Name, err)
}
}
}
@@ -129,45 +129,45 @@ func (b *Bithumb) SynchroniseWebsocketOrderbook(ctx context.Context) {
}
// processJob fetches and processes orderbook updates
func (b *Bithumb) processJob(ctx context.Context, p currency.Pair) error {
err := b.SeedLocalCache(ctx, p)
func (e *Exchange) processJob(ctx context.Context, p currency.Pair) error {
err := e.SeedLocalCache(ctx, p)
if err != nil {
return fmt.Errorf("%s %s seeding local cache for orderbook error: %v",
p, asset.Spot, err)
}
err = b.obm.stopFetchingBook(p)
err = e.obm.stopFetchingBook(p)
if err != nil {
return err
}
// Immediately apply the buffer updates so we don't wait for a
// new update to initiate this.
err = b.applyBufferUpdate(p)
err = e.applyBufferUpdate(p)
if err != nil {
b.invalidateAndCleanupOrderbook(p)
e.invalidateAndCleanupOrderbook(p)
return err
}
return nil
}
// invalidateAndCleanupOrderbook invalidates orderbook and cleans local cache
func (b *Bithumb) invalidateAndCleanupOrderbook(p currency.Pair) {
if err := b.Websocket.Orderbook.InvalidateOrderbook(p, asset.Spot); err != nil {
log.Errorf(log.WebsocketMgr, "%s invalidate orderbook websocket error: %v", b.Name, err)
func (e *Exchange) invalidateAndCleanupOrderbook(p currency.Pair) {
if err := e.Websocket.Orderbook.InvalidateOrderbook(p, asset.Spot); err != nil {
log.Errorf(log.WebsocketMgr, "%s invalidate orderbook websocket error: %v", e.Name, err)
}
if err := b.obm.cleanup(p); err != nil {
log.Errorf(log.WebsocketMgr, "%s cleanup websocket error: %v", b.Name, err)
if err := e.obm.cleanup(p); err != nil {
log.Errorf(log.WebsocketMgr, "%s cleanup websocket error: %v", e.Name, err)
}
}
func (b *Bithumb) setupOrderbookManager(ctx context.Context) {
if b.obm.state == nil {
b.obm.state = make(map[currency.Code]map[currency.Code]map[asset.Item]*update)
b.obm.jobs = make(chan job, maxWSOrderbookJobs)
func (e *Exchange) setupOrderbookManager(ctx context.Context) {
if e.obm.state == nil {
e.obm.state = make(map[currency.Code]map[currency.Code]map[asset.Item]*update)
e.obm.jobs = make(chan job, maxWSOrderbookJobs)
} else {
// Change state on reconnect for initial sync.
for _, m1 := range b.obm.state {
for _, m1 := range e.obm.state {
for _, m2 := range m1 {
for _, update := range m2 {
update.initialSync = true
@@ -180,7 +180,7 @@ func (b *Bithumb) setupOrderbookManager(ctx context.Context) {
for range maxWSOrderbookWorkers {
// 10 workers for synchronising book
b.SynchroniseWebsocketOrderbook(ctx)
e.SynchroniseWebsocketOrderbook(ctx)
}
}
@@ -398,22 +398,22 @@ bufferEmpty:
}
// SeedLocalCache seeds depth data
func (b *Bithumb) SeedLocalCache(ctx context.Context, p currency.Pair) error {
ob, err := b.GetOrderBook(ctx, p.String())
func (e *Exchange) SeedLocalCache(ctx context.Context, p currency.Pair) error {
ob, err := e.GetOrderBook(ctx, p.String())
if err != nil {
return err
}
return b.SeedLocalCacheWithBook(p, ob)
return e.SeedLocalCacheWithBook(p, ob)
}
// SeedLocalCacheWithBook seeds the local orderbook cache
func (b *Bithumb) SeedLocalCacheWithBook(p currency.Pair, o *Orderbook) error {
func (e *Exchange) SeedLocalCacheWithBook(p currency.Pair, o *Orderbook) error {
ob := &orderbook.Book{
Pair: p,
Asset: asset.Spot,
Exchange: b.Name,
Exchange: e.Name,
LastUpdated: o.Data.Timestamp.Time(),
ValidateOrderbook: b.ValidateOrderbook,
ValidateOrderbook: e.ValidateOrderbook,
Bids: make(orderbook.Levels, len(o.Data.Bids)),
Asks: make(orderbook.Levels, len(o.Data.Asks)),
}
@@ -425,7 +425,7 @@ func (b *Bithumb) SeedLocalCacheWithBook(p currency.Pair, o *Orderbook) error {
ob.Asks[i].Price = o.Data.Asks[i].Price
ob.Asks[i].Amount = o.Data.Asks[i].Quantity
}
return b.Websocket.Orderbook.LoadSnapshot(ob)
return e.Websocket.Orderbook.LoadSnapshot(ob)
}
// setNeedsFetchingBook completes the book fetching initiation.