mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-11 23:07:01 +08:00
feat(gate): complete Gate.io exchange integration with trader refactoring
Gate.io Integration: - Add Gate trader with full Trader interface implementation - Add order_sync.go for background trade synchronization - Fix quantity display (convert contracts to actual tokens via quanto_multiplier) - Fix fill price return in OpenLong/OpenShort/CloseLong/CloseShort - Add Gate-specific CoinAnk K-line data source support - Add Gate to supported exchanges in frontend and backend - Add Gate/KuCoin logo SVG icons Trader Package Refactoring: - Move exchange-specific code into subdirectories (binance/, bybit/, okx/, bitget/, hyperliquid/, aster/, lighter/, gate/) - Create types/ package for shared types to avoid circular dependencies - Move TraderTestSuite to trader/testutil package to avoid import cycles - Update market.GetWithExchange to support exchange-specific data
This commit is contained in:
665
trader/testutil/test_suite.go
Normal file
665
trader/testutil/test_suite.go
Normal file
@@ -0,0 +1,665 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/agiledragon/gomonkey/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"nofx/trader/types"
|
||||
)
|
||||
|
||||
// TraderTestSuite Generic Trader interface test suite (base suite)
|
||||
// Used for black-box testing any trader that implements the Trader interface
|
||||
//
|
||||
// Usage:
|
||||
// 1. Create a concrete test suite struct, embedding TraderTestSuite
|
||||
// 2. Implement SetupMocks() method to configure gomonkey mocks
|
||||
// 3. Call RunAllTests() to run all generic tests
|
||||
type TraderTestSuite struct {
|
||||
T *testing.T
|
||||
Trader types.Trader
|
||||
Patches *gomonkey.Patches
|
||||
}
|
||||
|
||||
// NewTraderTestSuite Create new base test suite
|
||||
func NewTraderTestSuite(t *testing.T, trader types.Trader) *TraderTestSuite {
|
||||
return &TraderTestSuite{
|
||||
T: t,
|
||||
Trader: trader,
|
||||
Patches: gomonkey.NewPatches(),
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup Clean up mock patches
|
||||
func (s *TraderTestSuite) Cleanup() {
|
||||
if s.Patches != nil {
|
||||
s.Patches.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
// RunAllTests Run all generic interface tests
|
||||
// Note: Before calling this method, please set up required mocks via SetupMocks
|
||||
func (s *TraderTestSuite) RunAllTests() {
|
||||
// Basic query methods
|
||||
s.T.Run("GetBalance", func(t *testing.T) { s.TestGetBalance() })
|
||||
s.T.Run("GetPositions", func(t *testing.T) { s.TestGetPositions() })
|
||||
s.T.Run("GetMarketPrice", func(t *testing.T) { s.TestGetMarketPrice() })
|
||||
|
||||
// Configuration methods
|
||||
s.T.Run("SetLeverage", func(t *testing.T) { s.TestSetLeverage() })
|
||||
s.T.Run("SetMarginMode", func(t *testing.T) { s.TestSetMarginMode() })
|
||||
s.T.Run("FormatQuantity", func(t *testing.T) { s.TestFormatQuantity() })
|
||||
|
||||
// Core trading methods
|
||||
s.T.Run("OpenLong", func(t *testing.T) { s.TestOpenLong() })
|
||||
s.T.Run("OpenShort", func(t *testing.T) { s.TestOpenShort() })
|
||||
s.T.Run("CloseLong", func(t *testing.T) { s.TestCloseLong() })
|
||||
s.T.Run("CloseShort", func(t *testing.T) { s.TestCloseShort() })
|
||||
|
||||
// Stop-loss and take-profit
|
||||
s.T.Run("SetStopLoss", func(t *testing.T) { s.TestSetStopLoss() })
|
||||
s.T.Run("SetTakeProfit", func(t *testing.T) { s.TestSetTakeProfit() })
|
||||
|
||||
// Order management
|
||||
s.T.Run("CancelAllOrders", func(t *testing.T) { s.TestCancelAllOrders() })
|
||||
s.T.Run("CancelStopOrders", func(t *testing.T) { s.TestCancelStopOrders() })
|
||||
s.T.Run("CancelStopLossOrders", func(t *testing.T) { s.TestCancelStopLossOrders() })
|
||||
s.T.Run("CancelTakeProfitOrders", func(t *testing.T) { s.TestCancelTakeProfitOrders() })
|
||||
}
|
||||
|
||||
// TestGetBalance Test getting account balance
|
||||
func (s *TraderTestSuite) TestGetBalance() {
|
||||
tests := []struct {
|
||||
name string
|
||||
wantError bool
|
||||
validate func(*testing.T, map[string]interface{})
|
||||
}{
|
||||
{
|
||||
name: "Successfully get balance",
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
assert.Contains(t, result, "totalWalletBalance")
|
||||
assert.Contains(t, result, "availableBalance")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.GetBalance()
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetPositions Test getting positions
|
||||
func (s *TraderTestSuite) TestGetPositions() {
|
||||
tests := []struct {
|
||||
name string
|
||||
wantError bool
|
||||
validate func(*testing.T, []map[string]interface{})
|
||||
}{
|
||||
{
|
||||
name: "Successfully get position list",
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, positions []map[string]interface{}) {
|
||||
assert.NotNil(t, positions)
|
||||
// Positions can be empty array
|
||||
for _, pos := range positions {
|
||||
assert.Contains(t, pos, "symbol")
|
||||
assert.Contains(t, pos, "side")
|
||||
assert.Contains(t, pos, "positionAmt")
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.GetPositions()
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetMarketPrice Test getting market price
|
||||
func (s *TraderTestSuite) TestGetMarketPrice() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
wantError bool
|
||||
validate func(*testing.T, float64)
|
||||
}{
|
||||
{
|
||||
name: "Successfully get BTC price",
|
||||
symbol: "BTCUSDT",
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, price float64) {
|
||||
assert.Greater(t, price, 0.0)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Invalid trading pair returns error",
|
||||
symbol: "INVALIDUSDT",
|
||||
wantError: true,
|
||||
validate: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
price, err := s.Trader.GetMarketPrice(tt.symbol)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, price)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSetLeverage Test setting leverage
|
||||
func (s *TraderTestSuite) TestSetLeverage() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
leverage int
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Set 10x leverage",
|
||||
symbol: "BTCUSDT",
|
||||
leverage: 10,
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "Set 1x leverage",
|
||||
symbol: "ETHUSDT",
|
||||
leverage: 1,
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.SetLeverage(tt.symbol, tt.leverage)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSetMarginMode Test setting margin mode
|
||||
func (s *TraderTestSuite) TestSetMarginMode() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
isCrossMargin bool
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Set cross margin mode",
|
||||
symbol: "BTCUSDT",
|
||||
isCrossMargin: true,
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "Set isolated margin mode",
|
||||
symbol: "ETHUSDT",
|
||||
isCrossMargin: false,
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.SetMarginMode(tt.symbol, tt.isCrossMargin)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestFormatQuantity Test formatting quantity
|
||||
func (s *TraderTestSuite) TestFormatQuantity() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
quantity float64
|
||||
wantError bool
|
||||
validate func(*testing.T, string)
|
||||
}{
|
||||
{
|
||||
name: "Format BTC quantity",
|
||||
symbol: "BTCUSDT",
|
||||
quantity: 1.23456789,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result string) {
|
||||
assert.NotEmpty(t, result)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Format small quantity",
|
||||
symbol: "ETHUSDT",
|
||||
quantity: 0.001,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result string) {
|
||||
assert.NotEmpty(t, result)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.FormatQuantity(tt.symbol, tt.quantity)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCancelAllOrders Test canceling all orders
|
||||
func (s *TraderTestSuite) TestCancelAllOrders() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Cancel all BTC orders",
|
||||
symbol: "BTCUSDT",
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.CancelAllOrders(tt.symbol)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Core trading method tests
|
||||
// ============================================================
|
||||
|
||||
// TestOpenLong Test opening long position
|
||||
func (s *TraderTestSuite) TestOpenLong() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
quantity float64
|
||||
leverage int
|
||||
wantError bool
|
||||
validate func(*testing.T, map[string]interface{})
|
||||
}{
|
||||
{
|
||||
name: "Successfully open long",
|
||||
symbol: "BTCUSDT",
|
||||
quantity: 0.01,
|
||||
leverage: 10,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
assert.Contains(t, result, "symbol")
|
||||
assert.Equal(t, "BTCUSDT", result["symbol"])
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Small quantity long",
|
||||
symbol: "ETHUSDT",
|
||||
quantity: 0.004, // Increased to 0.004 to meet Binance Futures minimum order value of 10 USDT (0.004 * 3000 = 12 USDT)
|
||||
leverage: 5,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.OpenLong(tt.symbol, tt.quantity, tt.leverage)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestOpenShort Test opening short position
|
||||
func (s *TraderTestSuite) TestOpenShort() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
quantity float64
|
||||
leverage int
|
||||
wantError bool
|
||||
validate func(*testing.T, map[string]interface{})
|
||||
}{
|
||||
{
|
||||
name: "Successfully open short",
|
||||
symbol: "BTCUSDT",
|
||||
quantity: 0.01,
|
||||
leverage: 10,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
assert.Contains(t, result, "symbol")
|
||||
assert.Equal(t, "BTCUSDT", result["symbol"])
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Small quantity short",
|
||||
symbol: "ETHUSDT",
|
||||
quantity: 0.004, // Increased to 0.004 to meet Binance Futures minimum order value of 10 USDT (0.004 * 3000 = 12 USDT)
|
||||
leverage: 5,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.OpenShort(tt.symbol, tt.quantity, tt.leverage)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCloseLong Test closing long position
|
||||
func (s *TraderTestSuite) TestCloseLong() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
quantity float64
|
||||
wantError bool
|
||||
validate func(*testing.T, map[string]interface{})
|
||||
}{
|
||||
{
|
||||
name: "Close specified quantity",
|
||||
symbol: "BTCUSDT",
|
||||
quantity: 0.01,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
assert.Contains(t, result, "symbol")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Close all with quantity=0 returns error when no position",
|
||||
symbol: "ETHUSDT",
|
||||
quantity: 0,
|
||||
wantError: true, // When no position exists, quantity=0 should return error
|
||||
validate: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.CloseLong(tt.symbol, tt.quantity)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCloseShort Test closing short position
|
||||
func (s *TraderTestSuite) TestCloseShort() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
quantity float64
|
||||
wantError bool
|
||||
validate func(*testing.T, map[string]interface{})
|
||||
}{
|
||||
{
|
||||
name: "Close specified quantity",
|
||||
symbol: "BTCUSDT",
|
||||
quantity: 0.01,
|
||||
wantError: false,
|
||||
validate: func(t *testing.T, result map[string]interface{}) {
|
||||
assert.NotNil(t, result)
|
||||
assert.Contains(t, result, "symbol")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Close all with quantity=0 returns error when no position",
|
||||
symbol: "ETHUSDT",
|
||||
quantity: 0,
|
||||
wantError: true, // When no position exists, quantity=0 should return error
|
||||
validate: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
result, err := s.Trader.CloseShort(tt.symbol, tt.quantity)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if tt.validate != nil {
|
||||
tt.validate(t, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Stop-loss and take-profit tests
|
||||
// ============================================================
|
||||
|
||||
// TestSetStopLoss Test setting stop-loss
|
||||
func (s *TraderTestSuite) TestSetStopLoss() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
positionSide string
|
||||
quantity float64
|
||||
stopPrice float64
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Long stop-loss",
|
||||
symbol: "BTCUSDT",
|
||||
positionSide: "LONG",
|
||||
quantity: 0.01,
|
||||
stopPrice: 45000.0,
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "Short stop-loss",
|
||||
symbol: "ETHUSDT",
|
||||
positionSide: "SHORT",
|
||||
quantity: 0.1,
|
||||
stopPrice: 3200.0,
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.SetStopLoss(tt.symbol, tt.positionSide, tt.quantity, tt.stopPrice)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSetTakeProfit Test setting take-profit
|
||||
func (s *TraderTestSuite) TestSetTakeProfit() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
positionSide string
|
||||
quantity float64
|
||||
takeProfitPrice float64
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Long take-profit",
|
||||
symbol: "BTCUSDT",
|
||||
positionSide: "LONG",
|
||||
quantity: 0.01,
|
||||
takeProfitPrice: 55000.0,
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "Short take-profit",
|
||||
symbol: "ETHUSDT",
|
||||
positionSide: "SHORT",
|
||||
quantity: 0.1,
|
||||
takeProfitPrice: 2800.0,
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.SetTakeProfit(tt.symbol, tt.positionSide, tt.quantity, tt.takeProfitPrice)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCancelStopOrders Test canceling stop-loss/take-profit orders
|
||||
func (s *TraderTestSuite) TestCancelStopOrders() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Cancel BTC stop orders",
|
||||
symbol: "BTCUSDT",
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.CancelStopOrders(tt.symbol)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCancelStopLossOrders Test canceling stop-loss orders
|
||||
func (s *TraderTestSuite) TestCancelStopLossOrders() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Cancel BTC stop-loss orders",
|
||||
symbol: "BTCUSDT",
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.CancelStopLossOrders(tt.symbol)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCancelTakeProfitOrders Test canceling take-profit orders
|
||||
func (s *TraderTestSuite) TestCancelTakeProfitOrders() {
|
||||
tests := []struct {
|
||||
name string
|
||||
symbol string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "Cancel BTC take-profit orders",
|
||||
symbol: "BTCUSDT",
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
s.T.Run(tt.name, func(t *testing.T) {
|
||||
err := s.Trader.CancelTakeProfitOrders(tt.symbol)
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user