mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-30 15:10:40 +00:00
codebase: Cleanup various things (#1935)
* codebase: Rid base64/hex to string common funcs * codebase: Rid local scope variable usage and other improvements * codebase: Refactor currency pair usage across multiple exchanges - Updated HitBTC tests to use the new currency pair format. - Modified Kraken futures types to use currency.Pair instead of string for Symbol. - Adjusted Kraken wrapper methods to handle currency pairs correctly. - Refined OKX tests and types to utilize currency.Pair for instrument IDs. - Enhanced Poloniex tests to consistently use predefined currency pairs. - Streamlined order and orderbook tests to replace string pairs with currency.NewBTCUSD(). - Improved Yobit tests to utilize a standardized currency pair format. - Updated validator wrapper to use currency pairs directly instead of string conversions. * codebase: Use types.Number where possible * refactor: update PayoutFee type to types.Number for consistency * Refactor: Remove crypto functions to use standard library and other minor changes - Removed custom crypto functions for SHA256, SHA512, and MD5 from the common/crypto package. - Replaced usages of removed functions with standard library implementations in various files including: - cmd/websocket_client/main.go - engine/apiserver.go - exchanges/kraken/kraken.go - exchanges/lbank/lbank.go - exchanges/okx/okx_business_websocket.go - exchanges/kucoin/kucoin_websocket.go - gctscript/vm/vm.go - Updated tests to reflect changes in the crypto functions. - Renamed several functions for clarity, particularly in the context of order book updates across multiple exchanges. * refactor: replace assert with require for consistency in test assertions * refactor: Improve Binance futures candlestick test, standardise orderbook update function names and improve test parallelism * refactor: Replace require.Len with require.Equal for better output in TestGetFuturesKlineData
This commit is contained in:
@@ -3,6 +3,7 @@ package bitstamp
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -170,9 +172,9 @@ func (b *Bitstamp) GetTicker(ctx context.Context, currency string, hourly bool)
|
||||
// the amount.
|
||||
func (b *Bitstamp) GetOrderbook(ctx context.Context, currency string) (*Orderbook, error) {
|
||||
type response struct {
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Bids [][2]string `json:"bids"`
|
||||
Asks [][2]string `json:"asks"`
|
||||
Timestamp types.Time `json:"timestamp"`
|
||||
Bids [][2]types.Number `json:"bids"`
|
||||
Asks [][2]types.Number `json:"asks"`
|
||||
}
|
||||
|
||||
path := "/v" + bitstampAPIVersion + "/" + bitstampAPIOrderbook + "/" + strings.ToLower(currency) + "/"
|
||||
@@ -182,37 +184,23 @@ func (b *Bitstamp) GetOrderbook(ctx context.Context, currency string) (*Orderboo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderbook := Orderbook{
|
||||
Timestamp: resp.Timestamp,
|
||||
ob := &Orderbook{
|
||||
Timestamp: resp.Timestamp.Time(),
|
||||
Bids: make([]OrderbookBase, len(resp.Bids)),
|
||||
Asks: make([]OrderbookBase, len(resp.Asks)),
|
||||
}
|
||||
|
||||
for x := range resp.Bids {
|
||||
price, err := strconv.ParseFloat(resp.Bids[x][0], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount, err := strconv.ParseFloat(resp.Bids[x][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderbook.Bids[x] = OrderbookBase{price, amount}
|
||||
ob.Bids[x].Price = resp.Bids[x][0].Float64()
|
||||
ob.Bids[x].Amount = resp.Bids[x][1].Float64()
|
||||
}
|
||||
|
||||
for x := range resp.Asks {
|
||||
price, err := strconv.ParseFloat(resp.Asks[x][0], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount, err := strconv.ParseFloat(resp.Asks[x][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderbook.Asks[x] = OrderbookBase{price, amount}
|
||||
ob.Asks[x].Price = resp.Asks[x][0].Float64()
|
||||
ob.Asks[x].Amount = resp.Asks[x][1].Float64()
|
||||
}
|
||||
|
||||
return &orderbook, nil
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// GetTradingPairs returns a list of trading pairs which Bitstamp
|
||||
@@ -244,7 +232,7 @@ func (b *Bitstamp) GetEURUSDConversionRate(ctx context.Context) (EURUSDConversio
|
||||
|
||||
// GetBalance returns full balance of currency held on the exchange
|
||||
func (b *Bitstamp) GetBalance(ctx context.Context) (Balances, error) {
|
||||
var balance map[string]string
|
||||
var balance map[string]types.Number
|
||||
err := b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPIBalance, true, nil, &balance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -259,15 +247,11 @@ func (b *Bitstamp) GetBalance(ctx context.Context) (Balances, error) {
|
||||
|
||||
balances := make(map[string]Balance)
|
||||
for _, curr := range currs {
|
||||
avail, _ := strconv.ParseFloat(balance[curr+"_available"], 64)
|
||||
bal, _ := strconv.ParseFloat(balance[curr+"_balance"], 64)
|
||||
reserved, _ := strconv.ParseFloat(balance[curr+"_reserved"], 64)
|
||||
withdrawalFee, _ := strconv.ParseFloat(balance[curr+"_withdrawal_fee"], 64)
|
||||
currBalance := Balance{
|
||||
Available: avail,
|
||||
Balance: bal,
|
||||
Reserved: reserved,
|
||||
WithdrawalFee: withdrawalFee,
|
||||
Available: balance[curr+"_available"].Float64(),
|
||||
Balance: balance[curr+"_balance"].Float64(),
|
||||
Reserved: balance[curr+"_reserved"].Float64(),
|
||||
WithdrawalFee: balance[curr+"_withdrawal_fee"].Float64(),
|
||||
}
|
||||
balances[strings.ToUpper(curr)] = currBalance
|
||||
}
|
||||
@@ -277,19 +261,19 @@ func (b *Bitstamp) GetBalance(ctx context.Context) (Balances, error) {
|
||||
// GetUserTransactions returns an array of transactions
|
||||
func (b *Bitstamp) GetUserTransactions(ctx context.Context, currencyPair string) ([]UserTransactions, error) {
|
||||
type Response struct {
|
||||
Date string `json:"datetime"`
|
||||
TransactionID int64 `json:"id"`
|
||||
Type int `json:"type,string"`
|
||||
USD any `json:"usd"`
|
||||
EUR any `json:"eur"`
|
||||
XRP any `json:"xrp"`
|
||||
BTC any `json:"btc"`
|
||||
BTCUSD any `json:"btc_usd"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
Date string `json:"datetime"`
|
||||
TransactionID int64 `json:"id"`
|
||||
Type int64 `json:"type,string"`
|
||||
USD types.Number `json:"usd"`
|
||||
EUR types.Number `json:"eur"`
|
||||
XRP types.Number `json:"xrp"`
|
||||
BTC types.Number `json:"btc"`
|
||||
BTCUSD types.Number `json:"btc_usd"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
var response []Response
|
||||
|
||||
var response []Response
|
||||
if currencyPair == "" {
|
||||
if err := b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPIUserTransactions,
|
||||
true,
|
||||
@@ -306,32 +290,20 @@ func (b *Bitstamp) GetUserTransactions(ctx context.Context, currencyPair string)
|
||||
}
|
||||
}
|
||||
|
||||
processNumber := func(i any) float64 {
|
||||
switch t := i.(type) {
|
||||
case float64:
|
||||
return t
|
||||
case string:
|
||||
amt, _ := strconv.ParseFloat(t, 64)
|
||||
return amt
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
transactions := make([]UserTransactions, len(response))
|
||||
for x := range response {
|
||||
tx := UserTransactions{}
|
||||
tx.Date = response[x].Date
|
||||
tx.TransactionID = response[x].TransactionID
|
||||
tx.Type = response[x].Type
|
||||
tx.EUR = processNumber(response[x].EUR)
|
||||
tx.XRP = processNumber(response[x].XRP)
|
||||
tx.USD = processNumber(response[x].USD)
|
||||
tx.BTC = processNumber(response[x].BTC)
|
||||
tx.BTCUSD = processNumber(response[x].BTCUSD)
|
||||
tx.Fee = response[x].Fee
|
||||
tx.OrderID = response[x].OrderID
|
||||
transactions[x] = tx
|
||||
transactions[x] = UserTransactions{
|
||||
Date: response[x].Date,
|
||||
TransactionID: response[x].TransactionID,
|
||||
Type: response[x].Type,
|
||||
EUR: response[x].EUR.Float64(),
|
||||
XRP: response[x].XRP.Float64(),
|
||||
USD: response[x].USD.Float64(),
|
||||
BTC: response[x].BTC.Float64(),
|
||||
BTCUSD: response[x].BTCUSD.Float64(),
|
||||
Fee: response[x].Fee,
|
||||
OrderID: response[x].OrderID,
|
||||
}
|
||||
}
|
||||
|
||||
return transactions, nil
|
||||
@@ -600,15 +572,12 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange
|
||||
values.Set("key", creds.Key)
|
||||
values.Set("nonce", n)
|
||||
|
||||
var hmac []byte
|
||||
hmac, err = crypto.GetHMAC(crypto.HashSHA256,
|
||||
[]byte(n+creds.ClientID+creds.Key),
|
||||
[]byte(creds.Secret))
|
||||
hmac, err := crypto.GetHMAC(crypto.HashSHA256, []byte(n+creds.ClientID+creds.Key), []byte(creds.Secret))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values.Set("signature", strings.ToUpper(crypto.HexEncodeToString(hmac)))
|
||||
values.Set("signature", strings.ToUpper(hex.EncodeToString(hmac)))
|
||||
|
||||
var fullPath string
|
||||
if v2 {
|
||||
|
||||
@@ -391,7 +391,7 @@ func TestGetOrderStatus(t *testing.T) {
|
||||
assert.Equal(t, "2022-01-31 14:43:15", o.DateTime, "DateTime should match")
|
||||
assert.Equal(t, "1458532827766784", o.ID, "OrderID should match")
|
||||
assert.Equal(t, 200.00, o.AmountRemaining, "AmountRemaining should match")
|
||||
assert.Equal(t, 0, o.Type, "Type should match")
|
||||
assert.Equal(t, int64(0), o.Type, "Type should match")
|
||||
assert.Equal(t, "0.50000000", o.ClientOrderID, "ClientOrderID should match")
|
||||
assert.Equal(t, "BTC/USD", o.Market, "Market should match")
|
||||
for _, tr := range o.Transactions {
|
||||
@@ -399,7 +399,7 @@ func TestGetOrderStatus(t *testing.T) {
|
||||
assert.Equal(t, 50.00, tr.Price, "Price should match")
|
||||
assert.Equal(t, 101.00, tr.FromCurrency, "FromCurrency should match")
|
||||
assert.Equal(t, 1.0, tr.ToCurrency, "ToCurrency should match")
|
||||
assert.Equal(t, 0, o.Type, "Type should match")
|
||||
assert.Equal(t, int64(0), o.Type, "Type should match")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -863,11 +863,10 @@ func TestWsRequestReconnect(t *testing.T) {
|
||||
require.NoError(t, err, "WsRequestReconnect must not error")
|
||||
}
|
||||
|
||||
func TestBitstamp_OHLC(t *testing.T) {
|
||||
start := time.Unix(1546300800, 0)
|
||||
end := time.Unix(1577836799, 0)
|
||||
o, err := b.OHLC(t.Context(), "btcusd", start, end, "60", "10")
|
||||
require.NoError(t, err, "TestBitstamp_OHLC must not error")
|
||||
func TestOHLC(t *testing.T) {
|
||||
t.Parallel()
|
||||
o, err := b.OHLC(t.Context(), "btcusd", time.Unix(1546300800, 0), time.Unix(1577836799, 0), "60", "10")
|
||||
require.NoError(t, err, "OHLC must not error")
|
||||
assert.Equal(t, "BTC/USD", o.Data.Pair, "Pair should be correct")
|
||||
for _, req := range o.Data.OHLCV {
|
||||
assert.Positive(t, req.Low, "Low should be positive")
|
||||
@@ -878,10 +877,9 @@ func TestBitstamp_OHLC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitstamp_GetHistoricCandles(t *testing.T) {
|
||||
start := time.Unix(1546300800, 0)
|
||||
end := time.Unix(1577836799, 0)
|
||||
c, err := b.GetHistoricCandles(t.Context(), btcusdPair, asset.Spot, kline.OneDay, start, end)
|
||||
func TestGetHistoricCandles(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, err := b.GetHistoricCandles(t.Context(), btcusdPair, asset.Spot, kline.OneDay, time.Unix(1546300800, 0), time.Unix(1577836799, 0))
|
||||
require.NoError(t, err, "GetHistoricCandles must not error")
|
||||
assert.Equal(t, btcusdPair, c.Pair, "Pair should be correct")
|
||||
assert.NotEmpty(t, c, "Candles should not be empty")
|
||||
@@ -895,11 +893,9 @@ func TestBitstamp_GetHistoricCandles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitstamp_GetHistoricCandlesExtended(t *testing.T) {
|
||||
start := time.Unix(1546300800, 0)
|
||||
end := time.Unix(1577836799, 0)
|
||||
|
||||
c, err := b.GetHistoricCandlesExtended(t.Context(), btcusdPair, asset.Spot, kline.OneDay, start, end)
|
||||
func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, err := b.GetHistoricCandlesExtended(t.Context(), btcusdPair, asset.Spot, kline.OneDay, time.Unix(1546300800, 0), time.Unix(1577836799, 0))
|
||||
require.NoError(t, err, "GetHistoricCandlesExtended must not error")
|
||||
assert.Equal(t, btcusdPair, c.Pair, "Pair should be correct")
|
||||
assert.NotEmpty(t, c, "Candles should not be empty")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package bitstamp
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
@@ -43,7 +45,7 @@ type OrderbookBase struct {
|
||||
|
||||
// Orderbook holds orderbook information
|
||||
type Orderbook struct {
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Timestamp time.Time
|
||||
Bids []OrderbookBase
|
||||
Asks []OrderbookBase
|
||||
}
|
||||
@@ -101,7 +103,7 @@ type Balances map[string]Balance
|
||||
type UserTransactions struct {
|
||||
Date string `json:"datetime"`
|
||||
TransactionID int64 `json:"id"`
|
||||
Type int `json:"type,string"`
|
||||
Type int64 `json:"type,string"`
|
||||
USD float64 `json:"usd"`
|
||||
EUR float64 `json:"eur"`
|
||||
BTC float64 `json:"btc"`
|
||||
@@ -128,7 +130,7 @@ type Order struct {
|
||||
// OrderStatus holds order status information
|
||||
type OrderStatus struct {
|
||||
AmountRemaining float64 `json:"amount_remaining,string"`
|
||||
Type int `json:"type"`
|
||||
Type int64 `json:"type"`
|
||||
ID string `json:"id"`
|
||||
DateTime string `json:"datetime"`
|
||||
Status string `json:"status"`
|
||||
@@ -251,10 +253,10 @@ type websocketOrderBookResponse struct {
|
||||
}
|
||||
|
||||
type websocketOrderBook struct {
|
||||
Asks [][2]string `json:"asks"`
|
||||
Bids [][2]string `json:"bids"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Microtimestamp int64 `json:"microtimestamp,string"`
|
||||
Asks [][2]types.Number `json:"asks"`
|
||||
Bids [][2]types.Number `json:"bids"`
|
||||
Timestamp types.Time `json:"timestamp"`
|
||||
Microtimestamp types.Time `json:"microtimestamp"`
|
||||
}
|
||||
|
||||
// OHLCResponse holds returned candle data
|
||||
@@ -262,12 +264,12 @@ type OHLCResponse struct {
|
||||
Data struct {
|
||||
Pair string `json:"pair"`
|
||||
OHLCV []struct {
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Open float64 `json:"open,string"`
|
||||
High float64 `json:"high,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
Close float64 `json:"close,string"`
|
||||
Volume float64 `json:"volume,string"`
|
||||
Timestamp types.Time `json:"timestamp"`
|
||||
Open float64 `json:"open,string"`
|
||||
High float64 `json:"high,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
Close float64 `json:"close,string"`
|
||||
Volume float64 `json:"volume,string"`
|
||||
} `json:"ohlc"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
@@ -291,47 +291,28 @@ func (b *Bitstamp) handleWSOrderbook(msg []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
wsOrderBookResp := websocketOrderBookResponse{}
|
||||
var wsOrderBookResp websocketOrderBookResponse
|
||||
if err := json.Unmarshal(msg, &wsOrderBookResp); err != nil {
|
||||
return err
|
||||
}
|
||||
update := &wsOrderBookResp.Data
|
||||
|
||||
if len(update.Asks) == 0 && len(update.Bids) == 0 {
|
||||
return errors.New("no orderbook data")
|
||||
}
|
||||
|
||||
obUpdate := &orderbook.Base{
|
||||
Bids: make(orderbook.Tranches, len(update.Bids)),
|
||||
Asks: make(orderbook.Tranches, len(update.Asks)),
|
||||
Bids: make(orderbook.Tranches, len(wsOrderBookResp.Data.Bids)),
|
||||
Asks: make(orderbook.Tranches, len(wsOrderBookResp.Data.Asks)),
|
||||
Pair: p,
|
||||
LastUpdated: time.UnixMicro(update.Microtimestamp),
|
||||
LastUpdated: wsOrderBookResp.Data.Microtimestamp.Time(),
|
||||
Asset: asset.Spot,
|
||||
Exchange: b.Name,
|
||||
VerifyOrderbook: b.CanVerifyOrderbook,
|
||||
}
|
||||
|
||||
for i := range update.Asks {
|
||||
target, err := strconv.ParseFloat(update.Asks[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
amount, err := strconv.ParseFloat(update.Asks[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obUpdate.Asks[i] = orderbook.Tranche{Price: target, Amount: amount}
|
||||
for i := range wsOrderBookResp.Data.Asks {
|
||||
obUpdate.Asks[i].Price = wsOrderBookResp.Data.Asks[i][0].Float64()
|
||||
obUpdate.Asks[i].Amount = wsOrderBookResp.Data.Asks[i][1].Float64()
|
||||
}
|
||||
for i := range update.Bids {
|
||||
target, err := strconv.ParseFloat(update.Bids[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
amount, err := strconv.ParseFloat(update.Bids[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obUpdate.Bids[i] = orderbook.Tranche{Price: target, Amount: amount}
|
||||
for i := range wsOrderBookResp.Data.Bids {
|
||||
obUpdate.Bids[i].Price = wsOrderBookResp.Data.Bids[i][0].Float64()
|
||||
obUpdate.Bids[i].Amount = wsOrderBookResp.Data.Bids[i][1].Float64()
|
||||
}
|
||||
filterOrderbookZeroBidPrice(obUpdate)
|
||||
return b.Websocket.Orderbook.LoadSnapshot(obUpdate)
|
||||
@@ -360,7 +341,7 @@ func (b *Bitstamp) seedOrderBook(ctx context.Context) error {
|
||||
VerifyOrderbook: b.CanVerifyOrderbook,
|
||||
Bids: make(orderbook.Tranches, len(orderbookSeed.Bids)),
|
||||
Asks: make(orderbook.Tranches, len(orderbookSeed.Asks)),
|
||||
LastUpdated: time.Unix(orderbookSeed.Timestamp, 0),
|
||||
LastUpdated: orderbookSeed.Timestamp,
|
||||
}
|
||||
|
||||
for i := range orderbookSeed.Asks {
|
||||
|
||||
@@ -819,7 +819,7 @@ func (b *Bitstamp) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
|
||||
timeSeries := make([]kline.Candle, 0, len(candles.Data.OHLCV))
|
||||
for x := range candles.Data.OHLCV {
|
||||
timestamp := time.Unix(candles.Data.OHLCV[x].Timestamp, 0)
|
||||
timestamp := candles.Data.OHLCV[x].Timestamp.Time()
|
||||
if timestamp.Before(req.Start) || timestamp.After(req.End) {
|
||||
continue
|
||||
}
|
||||
@@ -857,13 +857,13 @@ func (b *Bitstamp) GetHistoricCandlesExtended(ctx context.Context, pair currency
|
||||
}
|
||||
|
||||
for i := range candles.Data.OHLCV {
|
||||
timestamp := time.Unix(candles.Data.OHLCV[i].Timestamp, 0)
|
||||
timestamp := candles.Data.OHLCV[i].Timestamp.Time()
|
||||
if timestamp.Before(req.RangeHolder.Ranges[x].Start.Time) ||
|
||||
timestamp.After(req.RangeHolder.Ranges[x].End.Time) {
|
||||
continue
|
||||
}
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: time.Unix(candles.Data.OHLCV[i].Timestamp, 0),
|
||||
Time: timestamp,
|
||||
Open: candles.Data.OHLCV[i].Open,
|
||||
High: candles.Data.OHLCV[i].High,
|
||||
Low: candles.Data.OHLCV[i].Low,
|
||||
|
||||
Reference in New Issue
Block a user