Files
gocryptotrader/exchanges/trade/trade_test.go
Adrian Gallagher d5ba674fc4 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
2025-06-12 14:12:36 +10:00

252 lines
5.6 KiB
Go

package trade
import (
"sync"
"sync/atomic"
"testing"
"time"
"github.com/gofrs/uuid"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/database"
"github.com/thrasher-corp/gocryptotrader/database/drivers"
sqltrade "github.com/thrasher-corp/gocryptotrader/database/repository/trade"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
)
func TestAddTradesToBuffer(t *testing.T) {
t.Parallel()
processor.mutex.Lock()
processor.bufferProcessorInterval = BufferProcessorIntervalTime
processor.mutex.Unlock()
dbConf := database.Config{
Enabled: true,
Driver: database.DBSQLite3,
ConnectionDetails: drivers.ConnectionDetails{
Host: "localhost",
Database: "./rpctestdb",
},
}
var wg sync.WaitGroup
wg.Add(1)
processor.setup(&wg)
wg.Wait()
err := database.DB.SetConfig(&dbConf)
if err != nil {
t.Error(err)
}
err = AddTradesToBuffer([]Data{
{
Timestamp: time.Now(),
Exchange: "test!",
CurrencyPair: currency.NewBTCUSD(),
AssetType: asset.Spot,
Price: 1337,
Amount: 1337,
Side: order.Buy,
},
}...)
if err != nil {
t.Error(err)
}
if atomic.AddInt32(&processor.started, 0) == 0 {
t.Error("expected the processor to have started")
}
err = AddTradesToBuffer([]Data{
{
Timestamp: time.Now(),
Exchange: "test!",
CurrencyPair: currency.NewBTCUSD(),
AssetType: asset.Spot,
Price: 0,
Amount: 0,
Side: order.Buy,
},
}...)
if err == nil {
t.Error("expected error")
}
processor.mutex.Lock()
processor.buffer = nil
processor.mutex.Unlock()
err = AddTradesToBuffer([]Data{
{
Timestamp: time.Now(),
Exchange: "test!",
CurrencyPair: currency.NewBTCUSD(),
AssetType: asset.Spot,
Price: -1,
Amount: -1,
},
}...)
if err != nil {
t.Error(err)
}
processor.mutex.Lock()
if processor.buffer[0].Amount != 1 {
t.Error("expected positive amount")
}
if processor.buffer[0].Side != order.Sell {
t.Error("expected unknown side")
}
processor.mutex.Unlock()
}
func TestSqlDataToTrade(t *testing.T) {
t.Parallel()
uuiderino, _ := uuid.NewV4()
data, err := SQLDataToTrade(sqltrade.Data{
ID: uuiderino.String(),
Timestamp: time.Time{},
Exchange: "hello",
Base: currency.BTC.String(),
Quote: currency.USD.String(),
AssetType: "spot",
Price: 1337,
Amount: 1337,
Side: "buy",
})
if err != nil {
t.Error(err)
}
if len(data) != 1 {
t.Fatal("unexpected scenario")
}
if data[0].Side != order.Buy {
t.Error("expected buy side")
}
if data[0].CurrencyPair.String() != "BTCUSD" {
t.Errorf("expected \"BTCUSD\", got %v", data[0].CurrencyPair)
}
if data[0].AssetType != asset.Spot {
t.Error("expected spot")
}
}
func TestTradeToSQLData(t *testing.T) {
t.Parallel()
cp := currency.NewBTCUSD()
sqlData, err := tradeToSQLData(Data{
Timestamp: time.Now(),
Exchange: "test!",
CurrencyPair: cp,
AssetType: asset.Spot,
Price: 1337,
Amount: 1337,
Side: order.Buy,
})
if err != nil {
t.Error(err)
}
if len(sqlData) != 1 {
t.Fatal("unexpected result")
}
if sqlData[0].Base != cp.Base.String() {
t.Errorf("expected \"BTC\", got %v", sqlData[0].Base)
}
if sqlData[0].AssetType != asset.Spot.String() {
t.Error("expected spot")
}
}
func TestConvertTradesToCandles(t *testing.T) {
t.Parallel()
cp := currency.NewBTCUSD()
startDate := time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC)
candles, err := ConvertTradesToCandles(kline.FifteenSecond, []Data{
{
Timestamp: startDate,
Exchange: "test!",
CurrencyPair: cp,
AssetType: asset.Spot,
Price: 1337,
Amount: 1337,
Side: order.Buy,
},
{
Timestamp: startDate.Add(time.Second),
Exchange: "test!",
CurrencyPair: cp,
AssetType: asset.Spot,
Price: 1337,
Amount: 1337,
Side: order.Buy,
},
{
Timestamp: startDate.Add(time.Minute),
Exchange: "test!",
CurrencyPair: cp,
AssetType: asset.Spot,
Price: -1337,
Amount: -1337,
Side: order.Buy,
},
}...)
if err != nil {
t.Fatal(err)
}
if len(candles.Candles) != 2 {
t.Fatal("unexpected candle amount")
}
if candles.Interval != kline.FifteenSecond {
t.Error("expected fifteen seconds")
}
}
func TestShutdown(t *testing.T) {
t.Parallel()
var p Processor
p.mutex.Lock()
p.bufferProcessorInterval = time.Millisecond
p.mutex.Unlock()
var wg sync.WaitGroup
wg.Add(1)
go p.Run(&wg)
wg.Wait()
if atomic.LoadInt32(&p.started) != 1 {
t.Error("expected it to start running")
}
time.Sleep(time.Millisecond * 20)
if atomic.LoadInt32(&p.started) != 0 {
t.Error("expected it to stop running")
}
}
func TestFilterTradesByTime(t *testing.T) {
t.Parallel()
trades := []Data{
{
Exchange: "test",
Timestamp: time.Now().Add(-time.Second),
},
}
trades = FilterTradesByTime(trades, time.Now().Add(-time.Minute), time.Now())
if len(trades) != 1 {
t.Error("failed to filter")
}
trades = FilterTradesByTime(trades, time.Now().Add(-time.Millisecond), time.Now())
if len(trades) != 0 {
t.Error("failed to filter")
}
}
func TestSaveTradesToDatabase(t *testing.T) {
t.Parallel()
err := SaveTradesToDatabase(Data{})
if err != nil && err.Error() != "exchange name/uuid not set, cannot insert" {
t.Error(err)
}
}
func TestGetTradesInRange(t *testing.T) {
t.Parallel()
_, err := GetTradesInRange("", "", "", "", time.Time{}, time.Time{})
if err != nil && err.Error() != "invalid arguments received" {
t.Error(err)
}
}