mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
LBank: Fix TestGetWithdrawConfig, assertify tests and other minor changes (#1920)
* LBank: Fix TestGetWithdrawConfig, assertify tests and other minor changes * refactor: Update pair var and other tweaks * refactor: Increase test coverage for crypto funcs and minor adjustments * refactor: Replace assert with require for error checks in TestCreateOrder * Update exchanges/lbank/lbank.go Co-authored-by: Ryan O'Hara-Reid <oharareid.ryan@gmail.com> * refactor: Correct spelling of HighestPrice in KlineResponse and increase test coverage * refactor: Update error handling in CreateOrder and improve GetTrades comment --------- Co-authored-by: Ryan O'Hara-Reid <oharareid.ryan@gmail.com>
This commit is contained in:
@@ -16,7 +16,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
gctcrypto "github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
@@ -61,10 +63,16 @@ const (
|
||||
lbankTimestamp = "timestamp.do"
|
||||
)
|
||||
|
||||
var (
|
||||
errPEMBlockIsNil = errors.New("pem block is nil")
|
||||
errUnableToParsePrivateKey = errors.New("unable to parse private key")
|
||||
errPrivateKeyNotLoaded = errors.New("private key not loaded")
|
||||
)
|
||||
|
||||
// GetTicker returns a ticker for the specified symbol
|
||||
// symbol: eth_btc
|
||||
func (l *Lbank) GetTicker(ctx context.Context, symbol string) (TickerResponse, error) {
|
||||
var t TickerResponse
|
||||
func (l *Lbank) GetTicker(ctx context.Context, symbol string) (*TickerResponse, error) {
|
||||
var t *TickerResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
path := fmt.Sprintf("/v%s/%s?%s", lbankAPIVersion1, lbankTicker, params.Encode())
|
||||
@@ -79,7 +87,7 @@ func (l *Lbank) GetTimestamp(ctx context.Context) (time.Time, error) {
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.UnixMilli(resp.Timestamp), nil
|
||||
return resp.Timestamp.Time(), nil
|
||||
}
|
||||
|
||||
// GetTickers returns all tickers
|
||||
@@ -100,39 +108,39 @@ func (l *Lbank) GetCurrencyPairs(ctx context.Context) ([]string, error) {
|
||||
}
|
||||
|
||||
// GetMarketDepths returns arrays of asks, bids and timestamp
|
||||
func (l *Lbank) GetMarketDepths(ctx context.Context, symbol, size, merge string) (*MarketDepthResponse, error) {
|
||||
func (l *Lbank) GetMarketDepths(ctx context.Context, symbol string, size uint64) (*MarketDepthResponse, error) {
|
||||
var m MarketDepthResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("size", size)
|
||||
params.Set("merge", merge)
|
||||
params.Set("size", strconv.FormatUint(size, 10))
|
||||
path := fmt.Sprintf("/v%s/%s?%s", lbankAPIVersion2, lbankMarketDepths, params.Encode())
|
||||
return &m, l.SendHTTPRequest(ctx, exchange.RestSpot, path, &m)
|
||||
}
|
||||
|
||||
// GetTrades returns an array of available trades regarding a particular exchange
|
||||
func (l *Lbank) GetTrades(ctx context.Context, symbol string, limit, time int64) ([]TradeResponse, error) {
|
||||
// The time parameter is optional, if provided it will return trades after the given time
|
||||
func (l *Lbank) GetTrades(ctx context.Context, symbol string, limit uint64, tm time.Time) ([]TradeResponse, error) {
|
||||
var g []TradeResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
if limit > 0 {
|
||||
params.Set("size", strconv.FormatInt(limit, 10))
|
||||
params.Set("size", strconv.FormatUint(limit, 10))
|
||||
}
|
||||
if time > 0 {
|
||||
params.Set("time", strconv.FormatInt(time, 10))
|
||||
if !tm.IsZero() {
|
||||
params.Set("time", strconv.FormatInt(tm.Unix(), 10))
|
||||
}
|
||||
path := fmt.Sprintf("/v%s/%s?%s", lbankAPIVersion1, lbankTrades, params.Encode())
|
||||
return g, l.SendHTTPRequest(ctx, exchange.RestSpot, path, &g)
|
||||
}
|
||||
|
||||
// GetKlines returns kline data
|
||||
func (l *Lbank) GetKlines(ctx context.Context, symbol, size, klineType, tm string) ([]KlineResponse, error) {
|
||||
func (l *Lbank) GetKlines(ctx context.Context, symbol, size, klineType string, tm time.Time) ([]KlineResponse, error) {
|
||||
var klineTemp [][]float64
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("size", size)
|
||||
params.Set("type", klineType)
|
||||
params.Set("time", tm)
|
||||
params.Set("time", strconv.FormatInt(tm.Unix(), 10))
|
||||
path := fmt.Sprintf("/v%s/%s?%s", lbankAPIVersion1, lbankKlines, params.Encode())
|
||||
err := l.SendHTTPRequest(ctx, exchange.RestSpot, path, &klineTemp)
|
||||
if err != nil {
|
||||
@@ -147,7 +155,7 @@ func (l *Lbank) GetKlines(ctx context.Context, symbol, size, klineType, tm strin
|
||||
k[x] = KlineResponse{
|
||||
TimeStamp: time.Unix(int64(klineTemp[x][0]), 0).UTC(),
|
||||
OpenPrice: klineTemp[x][1],
|
||||
HigestPrice: klineTemp[x][2],
|
||||
HighestPrice: klineTemp[x][2],
|
||||
LowestPrice: klineTemp[x][3],
|
||||
ClosePrice: klineTemp[x][4],
|
||||
TradingVolume: klineTemp[x][5],
|
||||
@@ -175,18 +183,17 @@ func (l *Lbank) GetUserInfo(ctx context.Context) (InfoFinalResponse, error) {
|
||||
// CreateOrder creates an order
|
||||
func (l *Lbank) CreateOrder(ctx context.Context, pair, side string, amount, price float64) (CreateOrderResponse, error) {
|
||||
var resp CreateOrderResponse
|
||||
if !strings.EqualFold(side, order.Buy.String()) &&
|
||||
!strings.EqualFold(side, order.Sell.String()) {
|
||||
return resp, errors.New("side type invalid can only be 'buy' or 'sell'")
|
||||
if !strings.EqualFold(side, order.Buy.String()) && !strings.EqualFold(side, order.Sell.String()) {
|
||||
return resp, order.ErrSideIsInvalid
|
||||
}
|
||||
if amount <= 0 {
|
||||
return resp, errors.New("amount can't be smaller than or equal to 0")
|
||||
return resp, order.ErrAmountBelowMin
|
||||
}
|
||||
if price <= 0 {
|
||||
return resp, errors.New("price can't be smaller than or equal to 0")
|
||||
return resp, order.ErrPriceBelowMin
|
||||
}
|
||||
params := url.Values{}
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("symbol", pair)
|
||||
params.Set("type", strings.ToLower(side))
|
||||
params.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
|
||||
@@ -384,10 +391,10 @@ func (l *Lbank) USD2RMBRate(ctx context.Context) (ExchangeRateResponse, error) {
|
||||
}
|
||||
|
||||
// GetWithdrawConfig gets information about withdrawals
|
||||
func (l *Lbank) GetWithdrawConfig(ctx context.Context, assetCode string) ([]WithdrawConfigResponse, error) {
|
||||
func (l *Lbank) GetWithdrawConfig(ctx context.Context, c currency.Code) ([]WithdrawConfigResponse, error) {
|
||||
var resp []WithdrawConfigResponse
|
||||
params := url.Values{}
|
||||
params.Set("assetCode", assetCode)
|
||||
params.Set("assetCode", c.Lower().String())
|
||||
path := fmt.Sprintf("/v%s/%s?%s", lbankAPIVersion1, lbankWithdrawConfig, params.Encode())
|
||||
return resp, l.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
|
||||
}
|
||||
@@ -506,25 +513,25 @@ func (l *Lbank) loadPrivKey(ctx context.Context) error {
|
||||
|
||||
block, _ := pem.Decode([]byte(key))
|
||||
if block == nil {
|
||||
return errors.New("pem block is nil")
|
||||
return errPEMBlockIsNil
|
||||
}
|
||||
|
||||
p, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode priv key: %s", err)
|
||||
return fmt.Errorf("%w: %w", errUnableToParsePrivateKey, err)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
l.privateKey, ok = p.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return errors.New("unable to parse RSA private key")
|
||||
return common.GetTypeAssertError("*rsa.PrivateKey", p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lbank) sign(data string) (string, error) {
|
||||
if l.privateKey == nil {
|
||||
return "", errors.New("private key not loaded")
|
||||
return "", errPrivateKeyNotLoaded
|
||||
}
|
||||
md5hash, err := gctcrypto.GetMD5([]byte(data))
|
||||
if err != nil {
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package lbank
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
gctcrypto "github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
@@ -23,120 +31,84 @@ import (
|
||||
|
||||
// Please supply your own keys here for due diligence testing
|
||||
const (
|
||||
testAPIKey = ""
|
||||
testAPISecret = ""
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
testCurrencyPair = "btc_usdt"
|
||||
)
|
||||
|
||||
var l = &Lbank{}
|
||||
var (
|
||||
l = &Lbank{}
|
||||
testPair = currency.NewBTCUSDT().Format(currency.PairFormat{Delimiter: "_"})
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
l.SetDefaults()
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
||||
if err != nil {
|
||||
l = new(Lbank)
|
||||
if err := testexch.Setup(l); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lbankConfig, err := cfg.GetExchangeConfig("Lbank")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lbankConfig.API.AuthenticatedSupport = true
|
||||
lbankConfig.API.Credentials.Key = testAPIKey
|
||||
lbankConfig.API.Credentials.Secret = testAPISecret
|
||||
err = l.Setup(lbankConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = l.UpdateTradablePairs(context.Background(), true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cp, err := currency.NewPairFromString(testCurrencyPair)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = l.CurrencyPairs.EnablePair(asset.Spot, cp)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if apiKey != "" && apiSecret != "" {
|
||||
l.API.AuthenticatedSupport = true
|
||||
l.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetTicker(t.Context(), testCurrencyPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetTicker(t.Context(), testPair.String())
|
||||
assert.NoError(t, err, "GetTicker should not error")
|
||||
}
|
||||
|
||||
func TestGetTimestamp(t *testing.T) {
|
||||
t.Parallel()
|
||||
ts, err := l.GetTimestamp(t.Context())
|
||||
require.NoError(t, err, "GetTimestamp must not error")
|
||||
assert.NotZero(t, ts, "GetTimestamp should return a non-zero time")
|
||||
}
|
||||
|
||||
func TestGetTickers(t *testing.T) {
|
||||
t.Parallel()
|
||||
tickers, err := l.GetTickers(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(tickers) <= 1 {
|
||||
t.Errorf("expected multiple tickers, received %v", len(tickers))
|
||||
}
|
||||
require.NoError(t, err, "GetTickers must not error")
|
||||
assert.Greater(t, len(tickers), 1, "GetTickers should return more than 1 ticker")
|
||||
}
|
||||
|
||||
func TestGetCurrencyPairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetCurrencyPairs(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "GetCurrencyPairs should not error")
|
||||
}
|
||||
|
||||
func TestGetMarketDepths(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetMarketDepths(t.Context(), testCurrencyPair, "600", "1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a, _ := l.GetMarketDepths(t.Context(), testCurrencyPair, "4", "0")
|
||||
if len(a.Data.Asks) != 4 {
|
||||
t.Errorf("asks length requested doesn't match the output")
|
||||
}
|
||||
d, err := l.GetMarketDepths(t.Context(), testPair.String(), 4)
|
||||
require.NoError(t, err, "GetMarketDepths must not error")
|
||||
require.NotEmpty(t, d, "GetMarketDepths must return a non-empty response")
|
||||
assert.Len(t, d.Data.Asks, 4, "GetMarketDepths should return 4 asks")
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetTrades(t.Context(), testCurrencyPair, 600, time.Now().Unix())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
a, err := l.GetTrades(t.Context(), testCurrencyPair, 600, 0)
|
||||
if len(a) != 600 && err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
r, err := l.GetTrades(t.Context(), testPair.String(), 420, time.Now())
|
||||
require.NoError(t, err, "GetTrades must not error")
|
||||
require.NotEmpty(t, r, "GetTrades must return a non-empty response")
|
||||
assert.Len(t, r, 420, "GetTrades should return 420 trades")
|
||||
}
|
||||
|
||||
func TestGetKlines(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetKlines(t.Context(),
|
||||
testCurrencyPair, "600", "minute1",
|
||||
strconv.FormatInt(time.Now().Unix(), 10))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetKlines(t.Context(), testPair.String(), "600", "minute1", time.Now())
|
||||
assert.NoError(t, err, "GetKlines should not error")
|
||||
}
|
||||
|
||||
func TestUpdateOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
p := currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.ETH,
|
||||
Quote: currency.BTC,
|
||||
}
|
||||
|
||||
_, err := l.UpdateOrderbook(t.Context(), p.Lower(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.UpdateOrderbook(t.Context(), currency.EMPTYPAIR, asset.Spot)
|
||||
assert.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
|
||||
_, err = l.UpdateOrderbook(t.Context(), testPair, asset.Options)
|
||||
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
||||
_, err = l.UpdateOrderbook(t.Context(), testPair, asset.Spot)
|
||||
assert.NoError(t, err, "UpdateOrderbook should not error")
|
||||
}
|
||||
|
||||
func TestGetUserInfo(t *testing.T) {
|
||||
@@ -144,125 +116,90 @@ func TestGetUserInfo(t *testing.T) {
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.GetUserInfo(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err, "GetUserInfo must not error")
|
||||
}
|
||||
|
||||
func TestCreateOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := l.CreateOrder(t.Context(), testPair.String(), "what", 1231, 12314)
|
||||
require.ErrorIs(t, err, order.ErrSideIsInvalid)
|
||||
_, err = l.CreateOrder(t.Context(), testPair.String(), order.Buy.String(), 0, 0)
|
||||
require.ErrorIs(t, err, order.ErrAmountBelowMin)
|
||||
_, err = l.CreateOrder(t.Context(), testPair.String(), order.Sell.String(), 1231, 0)
|
||||
require.ErrorIs(t, err, order.ErrPriceBelowMin)
|
||||
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l, canManipulateRealOrders)
|
||||
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.CreateOrder(t.Context(), cp.Lower().String(), "what", 1231, 12314)
|
||||
if err == nil {
|
||||
t.Error("CreateOrder error cannot be nil")
|
||||
}
|
||||
_, err = l.CreateOrder(t.Context(), cp.Lower().String(), order.Buy.Lower(), 0, 0)
|
||||
if err == nil {
|
||||
t.Error("CreateOrder error cannot be nil")
|
||||
}
|
||||
_, err = l.CreateOrder(t.Context(), cp.Lower().String(), order.Sell.Lower(), 1231, 0)
|
||||
if err == nil {
|
||||
t.Error("CreateOrder error cannot be nil")
|
||||
}
|
||||
_, err = l.CreateOrder(t.Context(), cp.Lower().String(), order.Buy.Lower(), 58, 681)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
_, err = l.CreateOrder(t.Context(), testPair.String(), order.Buy.String(), 58, 681)
|
||||
assert.NoError(t, err, "CreateOrder should not error")
|
||||
}
|
||||
|
||||
func TestRemoveOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l, canManipulateRealOrders)
|
||||
|
||||
cp := currency.NewPairWithDelimiter(currency.ETH.String(), currency.BTC.String(), "_")
|
||||
_, err := l.RemoveOrder(t.Context(),
|
||||
cp.Lower().String(), "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.RemoveOrder(t.Context(), testPair.String(), "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23")
|
||||
assert.NoError(t, err, "RemoveOrder should not error")
|
||||
}
|
||||
|
||||
func TestQueryOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.QueryOrder(t.Context(), cp.Lower().String(), "1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.QueryOrder(t.Context(), testPair.String(), "1")
|
||||
assert.NoError(t, err, "QueryOrder should not error")
|
||||
}
|
||||
|
||||
func TestQueryOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.QueryOrderHistory(t.Context(),
|
||||
cp.Lower().String(), "1", "100")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.QueryOrderHistory(t.Context(), testPair.String(), "1", "100")
|
||||
assert.NoError(t, err, "QueryOrderHistory should not error")
|
||||
}
|
||||
|
||||
func TestGetPairInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetPairInfo(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "GetPairInfo should not error")
|
||||
}
|
||||
|
||||
func TestOrderTransactionDetails(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.OrderTransactionDetails(t.Context(),
|
||||
testCurrencyPair, "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.OrderTransactionDetails(t.Context(), testPair.String(), "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23")
|
||||
assert.NoError(t, err, "OrderTransactionDetails should not error")
|
||||
}
|
||||
|
||||
func TestTransactionHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.TransactionHistory(t.Context(),
|
||||
testCurrencyPair, "", "", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.TransactionHistory(t.Context(), testPair.String(), "", "", "", "", "", "")
|
||||
assert.NoError(t, err, "TransactionHistory should not error")
|
||||
}
|
||||
|
||||
func TestGetOpenOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.GetOpenOrders(t.Context(), cp.Lower().String(), "1", "50")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetOpenOrders(t.Context(), testPair.String(), "1", "50")
|
||||
assert.NoError(t, err, "GetOpenOrders should not error")
|
||||
}
|
||||
|
||||
func TestUSD2RMBRate(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.USD2RMBRate(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "USD2RMBRate should not error")
|
||||
}
|
||||
|
||||
func TestGetWithdrawConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := l.GetWithdrawConfig(t.Context(),
|
||||
currency.ETH.Lower().String())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
c, err := l.GetWithdrawConfig(t.Context(), currency.ETH)
|
||||
require.NoError(t, err, "GetWithdrawConfig must not error")
|
||||
assert.NotEmpty(t, c)
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
@@ -270,75 +207,106 @@ func TestWithdraw(t *testing.T) {
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l, canManipulateRealOrders)
|
||||
|
||||
_, err := l.Withdraw(t.Context(), "", "", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err, "Withdraw must not error")
|
||||
}
|
||||
|
||||
func TestGetWithdrawRecords(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.GetWithdrawalRecords(t.Context(), currency.ETH.Lower().String(), 0, 1, 20)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetWithdrawalRecords(t.Context(), currency.ETH.String(), 0, 1, 20)
|
||||
assert.NoError(t, err, "GetWithdrawRecords should not error")
|
||||
}
|
||||
|
||||
func TestLoadPrivKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
l2 := new(Lbank)
|
||||
l2.SetDefaults()
|
||||
require.ErrorIs(t, l2.loadPrivKey(t.Context()), exchange.ErrCredentialsAreEmpty)
|
||||
|
||||
ctx := account.DeployCredentialsToContext(t.Context(), &account.Credentials{Key: "test", Secret: "errortest"})
|
||||
assert.ErrorIs(t, l2.loadPrivKey(ctx), errPEMBlockIsNil)
|
||||
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err)
|
||||
der := x509.MarshalPKCS1PrivateKey(key)
|
||||
ctx = account.DeployCredentialsToContext(t.Context(), &account.Credentials{Key: "test", Secret: base64.StdEncoding.EncodeToString(der)})
|
||||
require.ErrorIs(t, l2.loadPrivKey(ctx), errUnableToParsePrivateKey)
|
||||
|
||||
ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
der, err = x509.MarshalPKCS8PrivateKey(ecdsaKey)
|
||||
require.NoError(t, err)
|
||||
ctx = account.DeployCredentialsToContext(t.Context(), &account.Credentials{Key: "test", Secret: base64.StdEncoding.EncodeToString(der)})
|
||||
require.ErrorIs(t, l2.loadPrivKey(ctx), common.ErrTypeAssertFailure)
|
||||
|
||||
key, err = rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err)
|
||||
der, err = x509.MarshalPKCS8PrivateKey(key)
|
||||
require.NoError(t, err)
|
||||
ctx = account.DeployCredentialsToContext(t.Context(), &account.Credentials{Key: "test", Secret: base64.StdEncoding.EncodeToString(der)})
|
||||
assert.NoError(t, l2.loadPrivKey(ctx), "loadPrivKey should not error")
|
||||
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
err := l.loadPrivKey(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ctx := account.DeployCredentialsToContext(t.Context(),
|
||||
&account.Credentials{Secret: "errortest"})
|
||||
err = l.loadPrivKey(ctx)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error due to pemblock nil")
|
||||
}
|
||||
assert.NoError(t, l.loadPrivKey(t.Context()), "loadPrivKey should not error")
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
l2 := new(Lbank)
|
||||
l2.SetDefaults()
|
||||
_, err := l2.sign("hello123")
|
||||
require.ErrorIs(t, err, errPrivateKeyNotLoaded)
|
||||
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err, "GenerateKey must not error")
|
||||
l2.privateKey = key
|
||||
|
||||
targetMessage := "hello123"
|
||||
msg, err := l2.sign(targetMessage)
|
||||
require.NoError(t, err, "sign must not error")
|
||||
|
||||
md5hash, err := gctcrypto.GetMD5([]byte(targetMessage))
|
||||
require.NoError(t, err)
|
||||
m := strings.ToUpper(hex.EncodeToString(md5hash))
|
||||
shaHash, err := gctcrypto.GetSHA256([]byte(m))
|
||||
require.NoError(t, err)
|
||||
|
||||
sigBytes, err := base64.StdEncoding.DecodeString(msg)
|
||||
require.NoError(t, err)
|
||||
err = rsa.VerifyPKCS1v15(&l2.privateKey.PublicKey, crypto.SHA256, shaHash, sigBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
err := l.loadPrivKey(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, l.loadPrivKey(t.Context()), "loadPrivKey must not error")
|
||||
|
||||
_, err = l.sign("hello123")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "sign should not error")
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, l, canManipulateRealOrders)
|
||||
|
||||
orderSubmission := &order.Submit{
|
||||
Exchange: l.Name,
|
||||
Pair: currency.Pair{
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USDT,
|
||||
Delimiter: "_",
|
||||
},
|
||||
r, err := l.SubmitOrder(t.Context(), &order.Submit{
|
||||
Exchange: l.Name,
|
||||
Pair: testPair,
|
||||
Side: order.Buy,
|
||||
Type: order.Limit,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
response, err := l.SubmitOrder(t.Context(), orderSubmission)
|
||||
if sharedtestvalues.AreAPICredentialsSet(l) && (err != nil || response.Status != order.New) {
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !sharedtestvalues.AreAPICredentialsSet(l) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
})
|
||||
if sharedtestvalues.AreAPICredentialsSet(l) {
|
||||
require.NoError(t, err, "SubmitOrder must not error")
|
||||
assert.Equal(t, order.New, r.Status, "SubmitOrder should return order status New")
|
||||
} else {
|
||||
assert.Error(t, err, "SubmitOrder should error when credentials are not set")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,26 +314,20 @@ func TestCancelOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l, canManipulateRealOrders)
|
||||
|
||||
cp := currency.NewPairWithDelimiter(currency.ETH.String(), currency.BTC.String(), "_")
|
||||
var a order.Cancel
|
||||
a.Pair = cp
|
||||
a.AssetType = asset.Spot
|
||||
a.OrderID = "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23"
|
||||
err := l.CancelOrder(t.Context(), &a)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
err := l.CancelOrder(t.Context(), &order.Cancel{
|
||||
Pair: testPair,
|
||||
AssetType: asset.Spot,
|
||||
OrderID: "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23",
|
||||
})
|
||||
assert.NoError(t, err, "CancelOrder should not error")
|
||||
}
|
||||
|
||||
func TestGetOrderInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.GetOrderInfo(t.Context(),
|
||||
"9ead39f5-701a-400b-b635-d7349eb0f6b", currency.EMPTYPAIR, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetOrderInfo(t.Context(), "9ead39f5-701a-400b-b635-d7349eb0f6b", currency.EMPTYPAIR, asset.Spot)
|
||||
assert.NoError(t, err, "GetOrderInfo should not error")
|
||||
}
|
||||
|
||||
func TestGetAllOpenOrderID(t *testing.T) {
|
||||
@@ -373,22 +335,17 @@ func TestGetAllOpenOrderID(t *testing.T) {
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.getAllOpenOrderID(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "getAllOpenOrderID should not error")
|
||||
}
|
||||
|
||||
func TestGetFeeByType(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
var input exchange.FeeBuilder
|
||||
input.Amount = 2
|
||||
input.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
input.Pair = cp
|
||||
_, err := l.GetFeeByType(t.Context(), &input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetFeeByType(t.Context(), &exchange.FeeBuilder{
|
||||
Amount: 2,
|
||||
FeeType: exchange.CryptocurrencyWithdrawalFee,
|
||||
Pair: testPair,
|
||||
})
|
||||
assert.NoError(t, err, "GetFeeByType should not error")
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
@@ -396,75 +353,50 @@ func TestGetAccountInfo(t *testing.T) {
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.UpdateAccountInfo(t.Context(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "UpdateAccountInfo should not error")
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
var input order.MultiOrderRequest
|
||||
input.Side = order.Buy
|
||||
input.AssetType = asset.Spot
|
||||
input.Type = order.AnyType
|
||||
input.Side = order.AnySide
|
||||
_, err := l.GetActiveOrders(t.Context(), &input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetActiveOrders(t.Context(), &order.MultiOrderRequest{
|
||||
Side: order.AnySide,
|
||||
AssetType: asset.Spot,
|
||||
Type: order.AnyType,
|
||||
})
|
||||
assert.NoError(t, err, "GetActiveOrders should not error")
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
var input order.MultiOrderRequest
|
||||
input.Side = order.Buy
|
||||
input.AssetType = asset.Spot
|
||||
input.Type = order.AnyType
|
||||
input.Side = order.AnySide
|
||||
_, err := l.GetOrderHistory(t.Context(), &input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetOrderHistory(t.Context(), &order.MultiOrderRequest{
|
||||
Side: order.AnySide,
|
||||
AssetType: asset.Spot,
|
||||
Type: order.AnyType,
|
||||
})
|
||||
assert.NoError(t, err, "GetOrderHistory should not error")
|
||||
}
|
||||
|
||||
func TestGetHistoricCandles(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString(testCurrencyPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = l.GetHistoricCandles(t.Context(), cp, asset.Spot, kline.OneMin, time.Now().Add(-24*time.Hour), time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = l.GetHistoricCandles(t.Context(), cp, asset.Spot, kline.OneHour, time.Now().Add(-24*time.Hour), time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := l.GetHistoricCandles(t.Context(), currency.EMPTYPAIR, asset.Spot, kline.OneMin, time.Time{}, time.Time{})
|
||||
assert.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
|
||||
_, err = l.GetHistoricCandles(t.Context(), testPair, asset.Spot, kline.OneMin, time.Now().Add(-24*time.Hour), time.Now())
|
||||
assert.NoError(t, err, "GetHistoricCandles should not error")
|
||||
}
|
||||
|
||||
func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
t.Parallel()
|
||||
startTime := time.Now().Add(-time.Minute * 2)
|
||||
end := time.Now()
|
||||
cp, err := currency.NewPairFromString(testCurrencyPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = l.GetHistoricCandlesExtended(t.Context(), cp, asset.Spot, kline.OneMin, startTime, end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := l.GetHistoricCandlesExtended(t.Context(), testPair, asset.Spot, kline.OneMin, time.Now().Add(-time.Minute*2), time.Now())
|
||||
assert.NoError(t, err, "GetHistoricCandlesExtended should not error")
|
||||
}
|
||||
|
||||
func Test_FormatExchangeKlineInterval(t *testing.T) {
|
||||
func TestFormatExchangeKlineInterval(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
interval kline.Interval
|
||||
output string
|
||||
@@ -494,71 +426,41 @@ func Test_FormatExchangeKlineInterval(t *testing.T) {
|
||||
kline.FifteenDay,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for x := range testCases {
|
||||
test := testCases[x]
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ret := l.FormatExchangeKlineInterval(test.interval)
|
||||
|
||||
if ret != test.output {
|
||||
t.Fatalf("unexpected result return expected: %v received: %v", test.output, ret)
|
||||
}
|
||||
ret := l.FormatExchangeKlineInterval(tc.interval)
|
||||
assert.Equalf(t, tc.output, ret, "FormatExchangeKlineInterval(%s) should return %q", tc.interval, tc.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRecentTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString(testCurrencyPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = l.GetRecentTrades(t.Context(), currencyPair, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetRecentTrades(t.Context(), testPair, asset.Spot)
|
||||
assert.NoError(t, err, "GetRecentTrades should not error")
|
||||
}
|
||||
|
||||
func TestGetHistoricTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString(testCurrencyPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = l.GetHistoricTrades(t.Context(),
|
||||
currencyPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// longer term
|
||||
_, err = l.GetHistoricTrades(t.Context(),
|
||||
currencyPair, asset.Spot, time.Now().Add(-time.Minute*60*200), time.Now().Add(-time.Minute*60*199))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.GetHistoricTrades(t.Context(), testPair, asset.Spot, time.Now().AddDate(69, 0, 0), time.Now())
|
||||
assert.ErrorIs(t, err, common.ErrStartAfterEnd)
|
||||
_, err = l.GetHistoricTrades(t.Context(), currency.EMPTYPAIR, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
|
||||
assert.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
|
||||
_, err = l.GetHistoricTrades(t.Context(), testPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
|
||||
assert.NoError(t, err, "GetHistoricTrades should not error")
|
||||
}
|
||||
|
||||
func TestUpdateTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString(testCurrencyPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = l.UpdateTicker(t.Context(), cp, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := l.UpdateTicker(t.Context(), testPair, asset.Spot)
|
||||
assert.NoError(t, err, "UpdateTicker should not error")
|
||||
}
|
||||
|
||||
func TestUpdateTickers(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := l.UpdateTickers(t.Context(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "UpdateTickers should not error")
|
||||
}
|
||||
|
||||
func TestGetStatus(t *testing.T) {
|
||||
@@ -574,36 +476,18 @@ func TestGetStatus(t *testing.T) {
|
||||
{status: 4, resp: order.Cancelling},
|
||||
{status: 5, resp: order.UnknownStatus},
|
||||
} {
|
||||
t.Run("", func(t *testing.T) {
|
||||
t.Run(tt.resp.String(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp := l.GetStatus(tt.status)
|
||||
if resp != tt.resp {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", resp, tt.resp)
|
||||
}
|
||||
assert.Equalf(t, tt.resp.String(), l.GetStatus(tt.status).String(), "GetStatus(%d) should return %s", tt.status, tt.resp)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTimestamp(t *testing.T) {
|
||||
t.Parallel()
|
||||
tt, err := l.GetTimestamp(t.Context())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if tt.IsZero() {
|
||||
t.Error("expected time")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
tt, err := l.GetServerTime(t.Context(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if tt.IsZero() {
|
||||
t.Error("expected time")
|
||||
}
|
||||
ts, err := l.GetServerTime(t.Context(), asset.Spot)
|
||||
require.NoError(t, err, "GetServerTime must not error")
|
||||
assert.NotZero(t, ts, "GetServerTime should return a non-zero time")
|
||||
}
|
||||
|
||||
func TestGetWithdrawalsHistory(t *testing.T) {
|
||||
@@ -611,9 +495,7 @@ func TestGetWithdrawalsHistory(t *testing.T) {
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, l)
|
||||
|
||||
_, err := l.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err, "GetWithdrawalsHistory should not error")
|
||||
}
|
||||
|
||||
func TestGetCurrencyTradeURL(t *testing.T) {
|
||||
@@ -621,8 +503,8 @@ func TestGetCurrencyTradeURL(t *testing.T) {
|
||||
testexch.UpdatePairsOnce(t, l)
|
||||
for _, a := range l.GetAssetTypes(false) {
|
||||
pairs, err := l.CurrencyPairs.GetPairs(a, false)
|
||||
require.NoError(t, err, "cannot get pairs for %s", a)
|
||||
require.NotEmpty(t, pairs, "no pairs for %s", a)
|
||||
require.NoErrorf(t, err, "GetPairs must not error for asset %s", a)
|
||||
require.NotEmptyf(t, pairs, "GetPairs for asset %s must return pairs", a)
|
||||
resp, err := l.GetCurrencyTradeURL(t.Context(), a, pairs[0])
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
|
||||
// Ticker stores the ticker price data for a currency pair
|
||||
@@ -20,7 +21,7 @@ type Ticker struct {
|
||||
// TickerResponse stores the ticker price data and timestamp for a currency pair
|
||||
type TickerResponse struct {
|
||||
Symbol currency.Pair `json:"symbol"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Timestamp types.Time `json:"timestamp"`
|
||||
Ticker Ticker `json:"ticker"`
|
||||
}
|
||||
|
||||
@@ -28,10 +29,10 @@ type TickerResponse struct {
|
||||
type MarketDepthResponse struct {
|
||||
ErrCapture
|
||||
Data struct {
|
||||
Asks [][2]string `json:"asks"`
|
||||
Bids [][2]string `json:"bids"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
Asks [][2]types.Number `json:"asks"`
|
||||
Bids [][2]types.Number `json:"bids"`
|
||||
Timestamp types.Time `json:"timestamp"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// TradeResponse stores date_ms, amount, price, type, tid for a currency pair
|
||||
@@ -47,7 +48,7 @@ type TradeResponse struct {
|
||||
type KlineResponse struct {
|
||||
TimeStamp time.Time `json:"timestamp"`
|
||||
OpenPrice float64 `json:"openprice"`
|
||||
HigestPrice float64 `json:"highestprice"`
|
||||
HighestPrice float64 `json:"highestprice"`
|
||||
LowestPrice float64 `json:"lowestprice"`
|
||||
ClosePrice float64 `json:"closeprice"`
|
||||
TradingVolume float64 `json:"tradingvolume"`
|
||||
@@ -183,10 +184,15 @@ type ExchangeRateResponse struct {
|
||||
|
||||
// WithdrawConfigResponse stores info about withdrawal configurations
|
||||
type WithdrawConfigResponse struct {
|
||||
AssetCode string `json:"assetCode"`
|
||||
Minimum string `json:"min"`
|
||||
CanWithDraw bool `json:"canWithDraw"`
|
||||
Fee string `json:"fee"`
|
||||
AmountScale int64 `json:"amountScale,string"`
|
||||
Chain string `json:"chain"`
|
||||
AssetCode currency.Code `json:"assetCode"`
|
||||
Minimum float64 `json:"min,string"`
|
||||
TransferAmountScale int64 `json:"transferAmtScale,string"`
|
||||
CanWithdraw bool `json:"canWithDraw"`
|
||||
Fee float64 `json:"fee"`
|
||||
MinimumTransfer float64 `json:"minTransfer,string"`
|
||||
Type int64 `json:"type,string"`
|
||||
}
|
||||
|
||||
// WithdrawResponse stores info about the withdrawal
|
||||
@@ -238,7 +244,7 @@ type GetAllOpenIDResp struct {
|
||||
|
||||
// TimestampResponse holds timestamp data
|
||||
type TimestampResponse struct {
|
||||
Timestamp int64 `json:"data"`
|
||||
Timestamp types.Time `json:"data"`
|
||||
}
|
||||
|
||||
var errorCodes = map[int64]string{
|
||||
|
||||
@@ -170,17 +170,16 @@ func (l *Lbank) UpdateTickers(ctx context.Context, a asset.Item) error {
|
||||
continue
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
if err := ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tickerInfo[j].Ticker.Latest,
|
||||
High: tickerInfo[j].Ticker.High,
|
||||
Low: tickerInfo[j].Ticker.Low,
|
||||
Volume: tickerInfo[j].Ticker.Volume,
|
||||
Pair: tickerInfo[j].Symbol,
|
||||
LastUpdated: time.Unix(0, tickerInfo[j].Timestamp),
|
||||
LastUpdated: tickerInfo[j].Timestamp.Time(),
|
||||
ExchangeName: l.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
if err != nil {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -198,62 +197,42 @@ func (l *Lbank) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item)
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (l *Lbank) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType asset.Item) (*orderbook.Base, error) {
|
||||
if p.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyPairEmpty
|
||||
if !l.SupportsAsset(assetType) {
|
||||
return nil, fmt.Errorf("%w: %q", asset.ErrNotSupported, assetType)
|
||||
}
|
||||
if err := l.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
|
||||
|
||||
fPair, err := l.FormatExchangeCurrency(p, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d, err := l.GetMarketDepths(ctx, fPair.String(), 60)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
book := &orderbook.Base{
|
||||
Exchange: l.Name,
|
||||
Pair: p,
|
||||
Asset: assetType,
|
||||
VerifyOrderbook: l.CanVerifyOrderbook,
|
||||
}
|
||||
fPair, err := l.FormatExchangeCurrency(p, assetType)
|
||||
if err != nil {
|
||||
return book, err
|
||||
Asks: make(orderbook.Tranches, len(d.Data.Asks)),
|
||||
Bids: make(orderbook.Tranches, len(d.Data.Bids)),
|
||||
}
|
||||
|
||||
a, err := l.GetMarketDepths(ctx, fPair.String(), "60", "1")
|
||||
if err != nil {
|
||||
return book, err
|
||||
for i := range d.Data.Asks {
|
||||
book.Asks[i].Price = d.Data.Asks[i][0].Float64()
|
||||
book.Asks[i].Amount = d.Data.Asks[i][1].Float64()
|
||||
}
|
||||
for i := range d.Data.Bids {
|
||||
book.Bids[i].Price = d.Data.Bids[i][0].Float64()
|
||||
book.Bids[i].Amount = d.Data.Bids[i][1].Float64()
|
||||
}
|
||||
|
||||
book.Asks = make(orderbook.Tranches, len(a.Data.Asks))
|
||||
for i := range a.Data.Asks {
|
||||
price, convErr := strconv.ParseFloat(a.Data.Asks[i][0], 64)
|
||||
if convErr != nil {
|
||||
return book, convErr
|
||||
}
|
||||
amount, convErr := strconv.ParseFloat(a.Data.Asks[i][1], 64)
|
||||
if convErr != nil {
|
||||
return book, convErr
|
||||
}
|
||||
book.Asks[i] = orderbook.Tranche{
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
book.Bids = make(orderbook.Tranches, len(a.Data.Bids))
|
||||
for i := range a.Data.Bids {
|
||||
price, convErr := strconv.ParseFloat(a.Data.Bids[i][0], 64)
|
||||
if convErr != nil {
|
||||
return book, convErr
|
||||
}
|
||||
amount, convErr := strconv.ParseFloat(a.Data.Bids[i][1], 64)
|
||||
if convErr != nil {
|
||||
return book, convErr
|
||||
}
|
||||
book.Bids[i] = orderbook.Tranche{
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
err = book.Process()
|
||||
if err != nil {
|
||||
return book, err
|
||||
if err := book.Process(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return orderbook.Get(l.Name, p, assetType)
|
||||
}
|
||||
|
||||
@@ -352,14 +331,11 @@ func (l *Lbank) GetHistoricTrades(ctx context.Context, p currency.Pair, assetTyp
|
||||
}
|
||||
var resp []trade.Data
|
||||
ts := timestampStart
|
||||
limit := 600
|
||||
const limit uint64 = 600
|
||||
allTrades:
|
||||
for {
|
||||
var tradeData []TradeResponse
|
||||
tradeData, err = l.GetTrades(ctx,
|
||||
p.String(),
|
||||
int64(limit),
|
||||
ts.UnixMilli())
|
||||
tradeData, err = l.GetTrades(ctx, p.String(), limit, ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -390,7 +366,7 @@ allTrades:
|
||||
ts = tradeTime
|
||||
}
|
||||
}
|
||||
if len(tradeData) != limit {
|
||||
if len(tradeData) != int(limit) {
|
||||
break allTrades
|
||||
}
|
||||
}
|
||||
@@ -756,22 +732,16 @@ func (l *Lbank) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilde
|
||||
return feeBuilder.Amount * feeBuilder.PurchasePrice * 0.002, nil
|
||||
}
|
||||
if feeBuilder.FeeType == exchange.CryptocurrencyWithdrawalFee {
|
||||
withdrawalFee, err := l.GetWithdrawConfig(ctx,
|
||||
feeBuilder.Pair.Base.Lower().String())
|
||||
withdrawalFee, err := l.GetWithdrawConfig(ctx, feeBuilder.Pair.Base)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
for i := range withdrawalFee {
|
||||
if !strings.EqualFold(withdrawalFee[i].AssetCode, feeBuilder.Pair.Base.String()) {
|
||||
if !withdrawalFee[i].AssetCode.Equal(feeBuilder.Pair.Base) {
|
||||
continue
|
||||
}
|
||||
if withdrawalFee[i].Fee == "" {
|
||||
return 0, nil
|
||||
}
|
||||
resp, err = strconv.ParseFloat(withdrawalFee[i].Fee, 64)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp = withdrawalFee[i].Fee
|
||||
break
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
@@ -856,7 +826,7 @@ func (l *Lbank) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
|
||||
req.RequestFormatted.String(),
|
||||
strconv.FormatUint(req.RequestLimit, 10),
|
||||
l.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(req.Start.Unix(), 10))
|
||||
req.Start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -866,7 +836,7 @@ func (l *Lbank) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
|
||||
timeSeries[x] = kline.Candle{
|
||||
Time: data[x].TimeStamp,
|
||||
Open: data[x].OpenPrice,
|
||||
High: data[x].HigestPrice,
|
||||
High: data[x].HighestPrice,
|
||||
Low: data[x].LowestPrice,
|
||||
Close: data[x].ClosePrice,
|
||||
Volume: data[x].TradingVolume,
|
||||
@@ -889,7 +859,7 @@ func (l *Lbank) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pa
|
||||
req.RequestFormatted.String(),
|
||||
strconv.FormatUint(req.RequestLimit, 10),
|
||||
l.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(req.RangeHolder.Ranges[x].Start.Ticks, 10))
|
||||
req.RangeHolder.Ranges[x].Start.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -901,7 +871,7 @@ func (l *Lbank) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pa
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: data[i].TimeStamp,
|
||||
Open: data[i].OpenPrice,
|
||||
High: data[i].HigestPrice,
|
||||
High: data[i].HighestPrice,
|
||||
Low: data[i].LowestPrice,
|
||||
Close: data[i].ClosePrice,
|
||||
Volume: data[i].TradingVolume,
|
||||
|
||||
Reference in New Issue
Block a user