From 80661043d966669e1796e455abc9171b406c1d99 Mon Sep 17 00:00:00 2001 From: edwin Date: Wed, 6 Mar 2024 14:46:14 +0800 Subject: [PATCH 1/2] pkg/exchange: add more tests to place order --- ...get_history_orders_request_market_buy.json | 26 ++ ...illed_orders_request_market_buy_order.json | 25 ++ ...lled_orders_request_market_sell_order.json | 25 ++ pkg/exchange/bitget/exchange_test.go | 288 +++++++++++++++++- 4 files changed, 356 insertions(+), 8 deletions(-) create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_history_orders_request_market_buy.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json diff --git a/pkg/exchange/bitget/bitgetapi/v2/testdata/get_history_orders_request_market_buy.json b/pkg/exchange/bitget/bitgetapi/v2/testdata/get_history_orders_request_market_buy.json new file mode 100644 index 0000000000..e0236acf5e --- /dev/null +++ b/pkg/exchange/bitget/bitgetapi/v2/testdata/get_history_orders_request_market_buy.json @@ -0,0 +1,26 @@ +{ + "code":"00000", + "msg":"success", + "requestTime":1709649001209, + "data":[ + { + "userId":"8672173294", + "symbol":"BTCUSDT", + "orderId":"1148903850645331968", + "clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770", + "price":"0", + "size":"6.0000000000000000", + "orderType":"market", + "side":"buy", + "status":"filled", + "priceAvg":"67360.8700000000000000", + "baseVolume":"0.0000890000000000", + "quoteVolume":"5.9951174300000000", + "enterPointSource":"API", + "feeDetail":"{\"BTC\":{\"deduction\":false,\"feeCoinCode\":\"BTC\",\"totalDeductionFee\":0,\"totalFee\":-8.90000000E-8},\"newFees\":{\"c\":0,\"d\":0,\"deduction\":false,\"r\":-8.9E-8,\"t\":-8.9E-8,\"totalDeductionFee\":0}}", + "orderSource":"market", + "cTime":"1709645944272", + "uTime":"1709645944272" + } + ] +} diff --git a/pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json b/pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json new file mode 100644 index 0000000000..99872d8b3a --- /dev/null +++ b/pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json @@ -0,0 +1,25 @@ +{ + "code":"00000", + "msg":"success", + "requestTime":1709692258790, + "data":[ + { + "userId":"8672173294", + "symbol":"BTCUSDT", + "orderId":"1148903850645331968", + "clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770", + "priceAvg":"0", + "size":"6", + "orderType":"market", + "side":"buy", + "status":"live", + "basePrice":"0", + "baseVolume":"0", + "quoteVolume":"0", + "enterPointSource":"API", + "orderSource":"market", + "cTime":"1709645944272", + "uTime":"1709645944272" + } + ] +} diff --git a/pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json b/pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json new file mode 100644 index 0000000000..d09393d75a --- /dev/null +++ b/pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json @@ -0,0 +1,25 @@ +{ + "code":"00000", + "msg":"success", + "requestTime":1709692258790, + "data":[ + { + "userId":"8672173294", + "symbol":"BTCUSDT", + "orderId":"1148903850645331968", + "clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770", + "priceAvg":"0", + "size":"0.00009", + "orderType":"market", + "side":"sell", + "status":"live", + "basePrice":"0", + "baseVolume":"0", + "quoteVolume":"0", + "enterPointSource":"API", + "orderSource":"market", + "cTime":"1709645944272", + "uTime":"1709645944272" + } + ] +} diff --git a/pkg/exchange/bitget/exchange_test.go b/pkg/exchange/bitget/exchange_test.go index 7183761dd3..72a1de10b3 100644 --- a/pkg/exchange/bitget/exchange_test.go +++ b/pkg/exchange/bitget/exchange_test.go @@ -545,13 +545,15 @@ func TestExchange_QueryAccountBalances(t *testing.T) { func TestExchange_SubmitOrder(t *testing.T) { var ( - assert = assert.New(t) - ex = New("key", "secret", "passphrase") - placeOrderUrl = "/api/v2/spot/trade/place-order" - openOrderUrl = "/api/v2/spot/trade/unfilled-orders" - clientOrderId = "684a79df-f931-474f-a9a5-f1deab1cd770" - expBtcSymbol = "BTCUSDT" - expOrder = &types.Order{ + assert = assert.New(t) + ex = New("key", "secret", "passphrase") + placeOrderUrl = "/api/v2/spot/trade/place-order" + openOrderUrl = "/api/v2/spot/trade/unfilled-orders" + tickerUrl = "/api/v2/spot/market/tickers" + historyOrderUrl = "/api/v2/spot/trade/history-orders" + clientOrderId = "684a79df-f931-474f-a9a5-f1deab1cd770" + expBtcSymbol = "BTCUSDT" + expOrder = &types.Order{ SubmitOrder: types.SubmitOrder{ ClientOrderID: clientOrderId, Symbol: expBtcSymbol, @@ -642,7 +644,277 @@ func TestExchange_SubmitOrder(t *testing.T) { assert.Equal(expOrder, acct) }) - // TODO: add market buy, limit maker + t.Run("Limit Maker order", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json") + assert.NoError(err) + + transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) { + raw, err := io.ReadAll(req.Body) + assert.NoError(err) + + reqq := &NewOrder{} + err = json.Unmarshal(raw, &reqq) + assert.NoError(err) + assert.Equal(&NewOrder{ + ClientOid: expOrder.ClientOrderID, + Force: string(v2.OrderForcePostOnly), + OrderType: string(v2.OrderTypeLimit), + Price: "66000.00", + Side: string(v2.SideTypeBuy), + Size: "0.000090", + Symbol: expBtcSymbol, + }, reqq) + + return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil + }) + + unfilledFile, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_limit_order.json") + assert.NoError(err) + + transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Len(query, 1) + assert.Contains(query, "orderId") + assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)}) + return httptesting.BuildResponseString(http.StatusOK, string(unfilledFile)), nil + }) + + reqLimitOrder2 := reqLimitOrder + reqLimitOrder2.Type = types.OrderTypeLimitMaker + acct, err := ex.SubmitOrder(context.Background(), reqLimitOrder2) + assert.NoError(err) + assert.Equal(expOrder, acct) + }) + + t.Run("Market order", func(t *testing.T) { + t.Run("Buy", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + // get ticker to calculate btc amount + tickerFile, err := os.ReadFile("bitgetapi/v2/testdata/get_ticker_request.json") + assert.NoError(err) + + transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) { + assert.Contains(req.URL.Query(), "symbol") + assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol}) + return httptesting.BuildResponseString(http.StatusOK, string(tickerFile)), nil + }) + + // place order + placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json") + assert.NoError(err) + + transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) { + raw, err := io.ReadAll(req.Body) + assert.NoError(err) + + reqq := &NewOrder{} + err = json.Unmarshal(raw, &reqq) + assert.NoError(err) + assert.Equal(&NewOrder{ + ClientOid: expOrder.ClientOrderID, + Force: string(v2.OrderForceGTC), + OrderType: string(v2.OrderTypeMarket), + Price: "", + Side: string(v2.SideTypeBuy), + Size: reqLimitOrder.Market.FormatQuantity(fixedpoint.MustNewFromString("66554").Mul(fixedpoint.MustNewFromString("0.00009"))), // ticker: 66554, size: 0.00009 + Symbol: expBtcSymbol, + }, reqq) + + return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil + }) + + // unfilled order + unfilledFile, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json") + assert.NoError(err) + + transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Len(query, 1) + assert.Contains(query, "orderId") + assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)}) + return httptesting.BuildResponseString(http.StatusOK, string(unfilledFile)), nil + }) + + reqMarketOrder := reqLimitOrder + reqMarketOrder.Side = types.SideTypeBuy + reqMarketOrder.Type = types.OrderTypeMarket + acct, err := ex.SubmitOrder(context.Background(), reqMarketOrder) + assert.NoError(err) + expOrder2 := *expOrder + expOrder2.Side = types.SideTypeBuy + expOrder2.Type = types.OrderTypeMarket + expOrder2.Quantity = fixedpoint.Zero + expOrder2.Price = fixedpoint.Zero + assert.Equal(&expOrder2, acct) + }) + + t.Run("Sell", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + // get ticker to calculate btc amount + tickerFile, err := os.ReadFile("bitgetapi/v2/testdata/get_ticker_request.json") + assert.NoError(err) + + transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) { + assert.Contains(req.URL.Query(), "symbol") + assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol}) + return httptesting.BuildResponseString(http.StatusOK, string(tickerFile)), nil + }) + + // place order + placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json") + assert.NoError(err) + + transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) { + raw, err := io.ReadAll(req.Body) + assert.NoError(err) + + reqq := &NewOrder{} + err = json.Unmarshal(raw, &reqq) + assert.NoError(err) + assert.Equal(&NewOrder{ + ClientOid: expOrder.ClientOrderID, + Force: string(v2.OrderForceGTC), + OrderType: string(v2.OrderTypeMarket), + Price: "", + Side: string(v2.SideTypeSell), + Size: "0.000090", // size: 0.00009 + Symbol: expBtcSymbol, + }, reqq) + + return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil + }) + + // unfilled order + unfilledFile, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json") + assert.NoError(err) + + transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Len(query, 1) + assert.Contains(query, "orderId") + assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)}) + return httptesting.BuildResponseString(http.StatusOK, string(unfilledFile)), nil + }) + + reqMarketOrder := reqLimitOrder + reqMarketOrder.Side = types.SideTypeSell + reqMarketOrder.Type = types.OrderTypeMarket + acct, err := ex.SubmitOrder(context.Background(), reqMarketOrder) + assert.NoError(err) + expOrder2 := *expOrder + expOrder2.Side = types.SideTypeSell + expOrder2.Type = types.OrderTypeMarket + expOrder2.Price = fixedpoint.Zero + assert.Equal(&expOrder2, acct) + }) + + t.Run("failed to get ticker on buy", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + // get ticker to calculate btc amount + requestErrFile, err := os.ReadFile("bitgetapi/v2/testdata/request_error.json") + assert.NoError(err) + + transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) { + assert.Contains(req.URL.Query(), "symbol") + assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol}) + return httptesting.BuildResponseString(http.StatusBadRequest, string(requestErrFile)), nil + }) + + reqMarketOrder := reqLimitOrder + reqMarketOrder.Side = types.SideTypeBuy + reqMarketOrder.Type = types.OrderTypeMarket + _, err = ex.SubmitOrder(context.Background(), reqMarketOrder) + assert.ErrorContains(err, "Invalid IP") + }) + + t.Run("get order from history due to unfilled order not found", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + // get ticker to calculate btc amount + tickerFile, err := os.ReadFile("bitgetapi/v2/testdata/get_ticker_request.json") + assert.NoError(err) + + transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) { + assert.Contains(req.URL.Query(), "symbol") + assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol}) + return httptesting.BuildResponseString(http.StatusOK, string(tickerFile)), nil + }) + + // place order + placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json") + assert.NoError(err) + + transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) { + raw, err := io.ReadAll(req.Body) + assert.NoError(err) + + reqq := &NewOrder{} + err = json.Unmarshal(raw, &reqq) + assert.NoError(err) + assert.Equal(&NewOrder{ + ClientOid: expOrder.ClientOrderID, + Force: string(v2.OrderForceGTC), + OrderType: string(v2.OrderTypeMarket), + Price: "", + Side: string(v2.SideTypeBuy), + Size: reqLimitOrder.Market.FormatQuantity(fixedpoint.MustNewFromString("66554").Mul(fixedpoint.MustNewFromString("0.00009"))), // ticker: 66554, size: 0.00009 + Symbol: expBtcSymbol, + }, reqq) + + return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil + }) + + // unfilled order + transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Len(query, 1) + assert.Contains(query, "orderId") + assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)}) + + apiResp := v2.APIResponse{Code: "00000"} + raw, err := json.Marshal(apiResp) + assert.NoError(err) + return httptesting.BuildResponseString(http.StatusOK, string(raw)), nil + }) + + // order history + historyOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/get_history_orders_request_market_buy.json") + assert.NoError(err) + + transport.GET(historyOrderUrl, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Len(query, 1) + assert.Contains(query, "orderId") + assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)}) + return httptesting.BuildResponseString(http.StatusOK, string(historyOrderFile)), nil + }) + + reqMarketOrder := reqLimitOrder + reqMarketOrder.Side = types.SideTypeBuy + reqMarketOrder.Type = types.OrderTypeMarket + acct, err := ex.SubmitOrder(context.Background(), reqMarketOrder) + assert.NoError(err) + expOrder2 := *expOrder + expOrder2.Side = types.SideTypeBuy + expOrder2.Type = types.OrderTypeMarket + expOrder2.Status = types.OrderStatusFilled + expOrder2.ExecutedQuantity = fixedpoint.MustNewFromString("0.000089") + expOrder2.Quantity = fixedpoint.MustNewFromString("0.000089") + expOrder2.Price = fixedpoint.MustNewFromString("67360.87") + expOrder2.IsWorking = false + assert.Equal(&expOrder2, acct) + }) + }) t.Run("error on query open orders", func(t *testing.T) { transport := &httptesting.MockTransport{} From 71b8665b32ff356674e7c7b61444e1e1d76df462 Mon Sep 17 00:00:00 2001 From: edwin Date: Wed, 6 Mar 2024 16:26:18 +0800 Subject: [PATCH 2/2] pkg/exchange: add more tests for query open orders --- pkg/exchange/bitget/exchange_test.go | 187 +++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/pkg/exchange/bitget/exchange_test.go b/pkg/exchange/bitget/exchange_test.go index 72a1de10b3..3332d9ae42 100644 --- a/pkg/exchange/bitget/exchange_test.go +++ b/pkg/exchange/bitget/exchange_test.go @@ -3,6 +3,7 @@ package bitget import ( "context" "encoding/json" + "fmt" "io" "math" "net/http" @@ -1073,3 +1074,189 @@ func TestExchange_SubmitOrder(t *testing.T) { assert.ErrorContains(err, "not supported") }) } + +func TestExchange_QueryOpenOrders(t *testing.T) { + var ( + assert = assert.New(t) + ex = New("key", "secret", "passphrase") + expBtcSymbol = "BTCUSDT" + url = "/api/v2/spot/trade/unfilled-orders" + ) + + t.Run("succeeds", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + f, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_limit_order.json") + assert.NoError(err) + + transport.GET(url, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Len(query, 2) + assert.Contains(query, "symbol") + assert.Equal(query["symbol"], []string{expBtcSymbol}) + assert.Equal(query["limit"], []string{strconv.FormatInt(queryLimit, 10)}) + return httptesting.BuildResponseString(http.StatusOK, string(f)), nil + }) + + orders, err := ex.QueryOpenOrders(context.Background(), expBtcSymbol) + assert.NoError(err) + expOrder := []types.Order{ + { + SubmitOrder: types.SubmitOrder{ + ClientOrderID: "684a79df-f931-474f-a9a5-f1deab1cd770", + Symbol: expBtcSymbol, + Side: types.SideTypeBuy, + Type: types.OrderTypeLimit, + Quantity: fixedpoint.MustNewFromString("0.00009"), + Price: fixedpoint.MustNewFromString("66000"), + TimeInForce: types.TimeInForceGTC, + }, + Exchange: types.ExchangeBitget, + OrderID: 1148903850645331968, + UUID: "1148903850645331968", + Status: types.OrderStatusNew, + ExecutedQuantity: fixedpoint.Zero, + IsWorking: true, + CreationTime: types.Time(types.NewMillisecondTimestampFromInt(1709645944272).Time()), + UpdateTime: types.Time(types.NewMillisecondTimestampFromInt(1709645944272).Time()), + }, + } + assert.Equal(expOrder, orders) + }) + + t.Run("succeeds on pagination with mock limit + 1", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + dataTemplate := `{ + "userId":"8672173294", + "symbol":"BTCUSDT", + "orderId":"%d", + "clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770", + "priceAvg":"0", + "size":"0.00009", + "orderType":"market", + "side":"sell", + "status":"live", + "basePrice":"0", + "baseVolume":"0", + "quoteVolume":"0", + "enterPointSource":"API", + "orderSource":"market", + "cTime":"1709645944272", + "uTime":"1709645944272" + }` + + openOrdersStr := make([]string, 0, queryLimit+1) + expOrders := make([]types.Order, 0, queryLimit+1) + for i := 0; i < queryLimit+1; i++ { + dataStr := fmt.Sprintf(dataTemplate, i) + openOrdersStr = append(openOrdersStr, dataStr) + + unfilledOdr := &v2.UnfilledOrder{} + err := json.Unmarshal([]byte(dataStr), &unfilledOdr) + assert.NoError(err) + gOdr, err := unfilledOrderToGlobalOrder(*unfilledOdr) + assert.NoError(err) + expOrders = append(expOrders, *gOdr) + } + + transport.GET(url, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Contains(query, "symbol") + assert.Equal(query["symbol"], []string{expBtcSymbol}) + assert.Equal(query["limit"], []string{strconv.FormatInt(queryLimit, 10)}) + if len(query) == 2 { + // first time query + resp := &v2.APIResponse{ + Code: "00000", + Data: []byte("[" + strings.Join(openOrdersStr[0:queryLimit], ",") + "]"), + } + respRaw, err := json.Marshal(resp) + assert.NoError(err) + + return httptesting.BuildResponseString(http.StatusOK, string(respRaw)), nil + } + // second time query + // last order id, so need to -1 + assert.Equal(query["idLessThan"], []string{strconv.FormatInt(queryLimit-1, 10)}) + + resp := &v2.APIResponse{ + Code: "00000", + Data: []byte("[" + strings.Join(openOrdersStr[queryLimit:queryLimit+1], ",") + "]"), + } + respRaw, err := json.Marshal(resp) + assert.NoError(err) + return httptesting.BuildResponseString(http.StatusOK, string(respRaw)), nil + }) + + orders, err := ex.QueryOpenOrders(context.Background(), expBtcSymbol) + assert.NoError(err) + assert.Equal(expOrders, orders) + }) + + t.Run("succeeds on pagination with mock limit + 1", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + dataTemplate := `{ + "userId":"8672173294", + "symbol":"BTCUSDT", + "orderId":"%d", + "clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770", + "priceAvg":"0", + "size":"0.00009", + "orderType":"market", + "side":"sell", + "status":"live", + "basePrice":"0", + "baseVolume":"0", + "quoteVolume":"0", + "enterPointSource":"API", + "orderSource":"market", + "cTime":"1709645944272", + "uTime":"1709645944272" + }` + + openOrdersStr := make([]string, 0, queryLimit+1) + for i := 0; i < queryLimit+1; i++ { + dataStr := fmt.Sprintf(dataTemplate, i) + openOrdersStr = append(openOrdersStr, dataStr) + } + + transport.GET(url, func(req *http.Request) (*http.Response, error) { + query := req.URL.Query() + assert.Contains(query, "symbol") + assert.Equal(query["symbol"], []string{expBtcSymbol}) + assert.Equal(query["limit"], []string{strconv.FormatInt(queryLimit, 10)}) + // first time query + resp := &v2.APIResponse{ + Code: "00000", + Data: []byte("[" + strings.Join(openOrdersStr, ",") + "]"), + } + respRaw, err := json.Marshal(resp) + assert.NoError(err) + + return httptesting.BuildResponseString(http.StatusOK, string(respRaw)), nil + }) + + _, err := ex.QueryOpenOrders(context.Background(), expBtcSymbol) + assert.ErrorContains(err, "unexpected open orders length") + }) + + t.Run("error", func(t *testing.T) { + transport := &httptesting.MockTransport{} + ex.client.HttpClient.Transport = transport + + f, err := os.ReadFile("bitgetapi/v2/testdata/request_error.json") + assert.NoError(err) + + transport.GET(url, func(req *http.Request) (*http.Response, error) { + return httptesting.BuildResponseString(http.StatusBadRequest, string(f)), nil + }) + + _, err = ex.QueryOpenOrders(context.Background(), "BTCUSDT") + assert.ErrorContains(err, "Invalid IP") + }) +}