Skip to content

Commit 8066104

Browse files
committed
pkg/exchange: add more tests to place order
1 parent 38a155d commit 8066104

4 files changed

+356
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"code":"00000",
3+
"msg":"success",
4+
"requestTime":1709649001209,
5+
"data":[
6+
{
7+
"userId":"8672173294",
8+
"symbol":"BTCUSDT",
9+
"orderId":"1148903850645331968",
10+
"clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770",
11+
"price":"0",
12+
"size":"6.0000000000000000",
13+
"orderType":"market",
14+
"side":"buy",
15+
"status":"filled",
16+
"priceAvg":"67360.8700000000000000",
17+
"baseVolume":"0.0000890000000000",
18+
"quoteVolume":"5.9951174300000000",
19+
"enterPointSource":"API",
20+
"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}}",
21+
"orderSource":"market",
22+
"cTime":"1709645944272",
23+
"uTime":"1709645944272"
24+
}
25+
]
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"code":"00000",
3+
"msg":"success",
4+
"requestTime":1709692258790,
5+
"data":[
6+
{
7+
"userId":"8672173294",
8+
"symbol":"BTCUSDT",
9+
"orderId":"1148903850645331968",
10+
"clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770",
11+
"priceAvg":"0",
12+
"size":"6",
13+
"orderType":"market",
14+
"side":"buy",
15+
"status":"live",
16+
"basePrice":"0",
17+
"baseVolume":"0",
18+
"quoteVolume":"0",
19+
"enterPointSource":"API",
20+
"orderSource":"market",
21+
"cTime":"1709645944272",
22+
"uTime":"1709645944272"
23+
}
24+
]
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"code":"00000",
3+
"msg":"success",
4+
"requestTime":1709692258790,
5+
"data":[
6+
{
7+
"userId":"8672173294",
8+
"symbol":"BTCUSDT",
9+
"orderId":"1148903850645331968",
10+
"clientOid":"684a79df-f931-474f-a9a5-f1deab1cd770",
11+
"priceAvg":"0",
12+
"size":"0.00009",
13+
"orderType":"market",
14+
"side":"sell",
15+
"status":"live",
16+
"basePrice":"0",
17+
"baseVolume":"0",
18+
"quoteVolume":"0",
19+
"enterPointSource":"API",
20+
"orderSource":"market",
21+
"cTime":"1709645944272",
22+
"uTime":"1709645944272"
23+
}
24+
]
25+
}

pkg/exchange/bitget/exchange_test.go

+280-8
Original file line numberDiff line numberDiff line change
@@ -545,13 +545,15 @@ func TestExchange_QueryAccountBalances(t *testing.T) {
545545

546546
func TestExchange_SubmitOrder(t *testing.T) {
547547
var (
548-
assert = assert.New(t)
549-
ex = New("key", "secret", "passphrase")
550-
placeOrderUrl = "/api/v2/spot/trade/place-order"
551-
openOrderUrl = "/api/v2/spot/trade/unfilled-orders"
552-
clientOrderId = "684a79df-f931-474f-a9a5-f1deab1cd770"
553-
expBtcSymbol = "BTCUSDT"
554-
expOrder = &types.Order{
548+
assert = assert.New(t)
549+
ex = New("key", "secret", "passphrase")
550+
placeOrderUrl = "/api/v2/spot/trade/place-order"
551+
openOrderUrl = "/api/v2/spot/trade/unfilled-orders"
552+
tickerUrl = "/api/v2/spot/market/tickers"
553+
historyOrderUrl = "/api/v2/spot/trade/history-orders"
554+
clientOrderId = "684a79df-f931-474f-a9a5-f1deab1cd770"
555+
expBtcSymbol = "BTCUSDT"
556+
expOrder = &types.Order{
555557
SubmitOrder: types.SubmitOrder{
556558
ClientOrderID: clientOrderId,
557559
Symbol: expBtcSymbol,
@@ -642,7 +644,277 @@ func TestExchange_SubmitOrder(t *testing.T) {
642644
assert.Equal(expOrder, acct)
643645
})
644646

645-
// TODO: add market buy, limit maker
647+
t.Run("Limit Maker order", func(t *testing.T) {
648+
transport := &httptesting.MockTransport{}
649+
ex.client.HttpClient.Transport = transport
650+
651+
placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json")
652+
assert.NoError(err)
653+
654+
transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) {
655+
raw, err := io.ReadAll(req.Body)
656+
assert.NoError(err)
657+
658+
reqq := &NewOrder{}
659+
err = json.Unmarshal(raw, &reqq)
660+
assert.NoError(err)
661+
assert.Equal(&NewOrder{
662+
ClientOid: expOrder.ClientOrderID,
663+
Force: string(v2.OrderForcePostOnly),
664+
OrderType: string(v2.OrderTypeLimit),
665+
Price: "66000.00",
666+
Side: string(v2.SideTypeBuy),
667+
Size: "0.000090",
668+
Symbol: expBtcSymbol,
669+
}, reqq)
670+
671+
return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil
672+
})
673+
674+
unfilledFile, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_limit_order.json")
675+
assert.NoError(err)
676+
677+
transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) {
678+
query := req.URL.Query()
679+
assert.Len(query, 1)
680+
assert.Contains(query, "orderId")
681+
assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)})
682+
return httptesting.BuildResponseString(http.StatusOK, string(unfilledFile)), nil
683+
})
684+
685+
reqLimitOrder2 := reqLimitOrder
686+
reqLimitOrder2.Type = types.OrderTypeLimitMaker
687+
acct, err := ex.SubmitOrder(context.Background(), reqLimitOrder2)
688+
assert.NoError(err)
689+
assert.Equal(expOrder, acct)
690+
})
691+
692+
t.Run("Market order", func(t *testing.T) {
693+
t.Run("Buy", func(t *testing.T) {
694+
transport := &httptesting.MockTransport{}
695+
ex.client.HttpClient.Transport = transport
696+
697+
// get ticker to calculate btc amount
698+
tickerFile, err := os.ReadFile("bitgetapi/v2/testdata/get_ticker_request.json")
699+
assert.NoError(err)
700+
701+
transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) {
702+
assert.Contains(req.URL.Query(), "symbol")
703+
assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol})
704+
return httptesting.BuildResponseString(http.StatusOK, string(tickerFile)), nil
705+
})
706+
707+
// place order
708+
placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json")
709+
assert.NoError(err)
710+
711+
transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) {
712+
raw, err := io.ReadAll(req.Body)
713+
assert.NoError(err)
714+
715+
reqq := &NewOrder{}
716+
err = json.Unmarshal(raw, &reqq)
717+
assert.NoError(err)
718+
assert.Equal(&NewOrder{
719+
ClientOid: expOrder.ClientOrderID,
720+
Force: string(v2.OrderForceGTC),
721+
OrderType: string(v2.OrderTypeMarket),
722+
Price: "",
723+
Side: string(v2.SideTypeBuy),
724+
Size: reqLimitOrder.Market.FormatQuantity(fixedpoint.MustNewFromString("66554").Mul(fixedpoint.MustNewFromString("0.00009"))), // ticker: 66554, size: 0.00009
725+
Symbol: expBtcSymbol,
726+
}, reqq)
727+
728+
return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil
729+
})
730+
731+
// unfilled order
732+
unfilledFile, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json")
733+
assert.NoError(err)
734+
735+
transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) {
736+
query := req.URL.Query()
737+
assert.Len(query, 1)
738+
assert.Contains(query, "orderId")
739+
assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)})
740+
return httptesting.BuildResponseString(http.StatusOK, string(unfilledFile)), nil
741+
})
742+
743+
reqMarketOrder := reqLimitOrder
744+
reqMarketOrder.Side = types.SideTypeBuy
745+
reqMarketOrder.Type = types.OrderTypeMarket
746+
acct, err := ex.SubmitOrder(context.Background(), reqMarketOrder)
747+
assert.NoError(err)
748+
expOrder2 := *expOrder
749+
expOrder2.Side = types.SideTypeBuy
750+
expOrder2.Type = types.OrderTypeMarket
751+
expOrder2.Quantity = fixedpoint.Zero
752+
expOrder2.Price = fixedpoint.Zero
753+
assert.Equal(&expOrder2, acct)
754+
})
755+
756+
t.Run("Sell", func(t *testing.T) {
757+
transport := &httptesting.MockTransport{}
758+
ex.client.HttpClient.Transport = transport
759+
760+
// get ticker to calculate btc amount
761+
tickerFile, err := os.ReadFile("bitgetapi/v2/testdata/get_ticker_request.json")
762+
assert.NoError(err)
763+
764+
transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) {
765+
assert.Contains(req.URL.Query(), "symbol")
766+
assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol})
767+
return httptesting.BuildResponseString(http.StatusOK, string(tickerFile)), nil
768+
})
769+
770+
// place order
771+
placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json")
772+
assert.NoError(err)
773+
774+
transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) {
775+
raw, err := io.ReadAll(req.Body)
776+
assert.NoError(err)
777+
778+
reqq := &NewOrder{}
779+
err = json.Unmarshal(raw, &reqq)
780+
assert.NoError(err)
781+
assert.Equal(&NewOrder{
782+
ClientOid: expOrder.ClientOrderID,
783+
Force: string(v2.OrderForceGTC),
784+
OrderType: string(v2.OrderTypeMarket),
785+
Price: "",
786+
Side: string(v2.SideTypeSell),
787+
Size: "0.000090", // size: 0.00009
788+
Symbol: expBtcSymbol,
789+
}, reqq)
790+
791+
return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil
792+
})
793+
794+
// unfilled order
795+
unfilledFile, err := os.ReadFile("bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json")
796+
assert.NoError(err)
797+
798+
transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) {
799+
query := req.URL.Query()
800+
assert.Len(query, 1)
801+
assert.Contains(query, "orderId")
802+
assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)})
803+
return httptesting.BuildResponseString(http.StatusOK, string(unfilledFile)), nil
804+
})
805+
806+
reqMarketOrder := reqLimitOrder
807+
reqMarketOrder.Side = types.SideTypeSell
808+
reqMarketOrder.Type = types.OrderTypeMarket
809+
acct, err := ex.SubmitOrder(context.Background(), reqMarketOrder)
810+
assert.NoError(err)
811+
expOrder2 := *expOrder
812+
expOrder2.Side = types.SideTypeSell
813+
expOrder2.Type = types.OrderTypeMarket
814+
expOrder2.Price = fixedpoint.Zero
815+
assert.Equal(&expOrder2, acct)
816+
})
817+
818+
t.Run("failed to get ticker on buy", func(t *testing.T) {
819+
transport := &httptesting.MockTransport{}
820+
ex.client.HttpClient.Transport = transport
821+
822+
// get ticker to calculate btc amount
823+
requestErrFile, err := os.ReadFile("bitgetapi/v2/testdata/request_error.json")
824+
assert.NoError(err)
825+
826+
transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) {
827+
assert.Contains(req.URL.Query(), "symbol")
828+
assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol})
829+
return httptesting.BuildResponseString(http.StatusBadRequest, string(requestErrFile)), nil
830+
})
831+
832+
reqMarketOrder := reqLimitOrder
833+
reqMarketOrder.Side = types.SideTypeBuy
834+
reqMarketOrder.Type = types.OrderTypeMarket
835+
_, err = ex.SubmitOrder(context.Background(), reqMarketOrder)
836+
assert.ErrorContains(err, "Invalid IP")
837+
})
838+
839+
t.Run("get order from history due to unfilled order not found", func(t *testing.T) {
840+
transport := &httptesting.MockTransport{}
841+
ex.client.HttpClient.Transport = transport
842+
843+
// get ticker to calculate btc amount
844+
tickerFile, err := os.ReadFile("bitgetapi/v2/testdata/get_ticker_request.json")
845+
assert.NoError(err)
846+
847+
transport.GET(tickerUrl, func(req *http.Request) (*http.Response, error) {
848+
assert.Contains(req.URL.Query(), "symbol")
849+
assert.Equal(req.URL.Query()["symbol"], []string{expBtcSymbol})
850+
return httptesting.BuildResponseString(http.StatusOK, string(tickerFile)), nil
851+
})
852+
853+
// place order
854+
placeOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/place_order_request.json")
855+
assert.NoError(err)
856+
857+
transport.POST(placeOrderUrl, func(req *http.Request) (*http.Response, error) {
858+
raw, err := io.ReadAll(req.Body)
859+
assert.NoError(err)
860+
861+
reqq := &NewOrder{}
862+
err = json.Unmarshal(raw, &reqq)
863+
assert.NoError(err)
864+
assert.Equal(&NewOrder{
865+
ClientOid: expOrder.ClientOrderID,
866+
Force: string(v2.OrderForceGTC),
867+
OrderType: string(v2.OrderTypeMarket),
868+
Price: "",
869+
Side: string(v2.SideTypeBuy),
870+
Size: reqLimitOrder.Market.FormatQuantity(fixedpoint.MustNewFromString("66554").Mul(fixedpoint.MustNewFromString("0.00009"))), // ticker: 66554, size: 0.00009
871+
Symbol: expBtcSymbol,
872+
}, reqq)
873+
874+
return httptesting.BuildResponseString(http.StatusOK, string(placeOrderFile)), nil
875+
})
876+
877+
// unfilled order
878+
transport.GET(openOrderUrl, func(req *http.Request) (*http.Response, error) {
879+
query := req.URL.Query()
880+
assert.Len(query, 1)
881+
assert.Contains(query, "orderId")
882+
assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)})
883+
884+
apiResp := v2.APIResponse{Code: "00000"}
885+
raw, err := json.Marshal(apiResp)
886+
assert.NoError(err)
887+
return httptesting.BuildResponseString(http.StatusOK, string(raw)), nil
888+
})
889+
890+
// order history
891+
historyOrderFile, err := os.ReadFile("bitgetapi/v2/testdata/get_history_orders_request_market_buy.json")
892+
assert.NoError(err)
893+
894+
transport.GET(historyOrderUrl, func(req *http.Request) (*http.Response, error) {
895+
query := req.URL.Query()
896+
assert.Len(query, 1)
897+
assert.Contains(query, "orderId")
898+
assert.Equal(query["orderId"], []string{strconv.FormatUint(expOrder.OrderID, 10)})
899+
return httptesting.BuildResponseString(http.StatusOK, string(historyOrderFile)), nil
900+
})
901+
902+
reqMarketOrder := reqLimitOrder
903+
reqMarketOrder.Side = types.SideTypeBuy
904+
reqMarketOrder.Type = types.OrderTypeMarket
905+
acct, err := ex.SubmitOrder(context.Background(), reqMarketOrder)
906+
assert.NoError(err)
907+
expOrder2 := *expOrder
908+
expOrder2.Side = types.SideTypeBuy
909+
expOrder2.Type = types.OrderTypeMarket
910+
expOrder2.Status = types.OrderStatusFilled
911+
expOrder2.ExecutedQuantity = fixedpoint.MustNewFromString("0.000089")
912+
expOrder2.Quantity = fixedpoint.MustNewFromString("0.000089")
913+
expOrder2.Price = fixedpoint.MustNewFromString("67360.87")
914+
expOrder2.IsWorking = false
915+
assert.Equal(&expOrder2, acct)
916+
})
917+
})
646918

647919
t.Run("error on query open orders", func(t *testing.T) {
648920
transport := &httptesting.MockTransport{}

0 commit comments

Comments
 (0)