From ea5b45bfe44c3389cf418d004b0ded74edf712a6 Mon Sep 17 00:00:00 2001 From: "Alan.sung" Date: Fri, 11 Aug 2023 09:28:58 +0800 Subject: [PATCH] queryOrder() and test for it --- go.sum | 1 - pkg/exchange/okex/convert.go | 57 ++++++++++++++++++------ pkg/exchange/okex/exchange.go | 31 +++---------- pkg/exchange/okex/okexapi/client.go | 13 +++--- pkg/exchange/okex/okexapi/client_test.go | 24 +++++----- pkg/exchange/okex/query_order_test.go | 36 +++++++++++++++ 6 files changed, 106 insertions(+), 56 deletions(-) create mode 100644 pkg/exchange/okex/query_order_test.go diff --git a/go.sum b/go.sum index b39b94663..cdc1af5fe 100644 --- a/go.sum +++ b/go.sum @@ -1000,7 +1000,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20190226202314-149afe6ec0b6/go.mod h1:jevfED4GnIEnJrWW55YmY9DMhajHcnkqVnEXmEtMyNI= gonum.org/v1/gonum v0.0.0-20190902003836-43865b531bee/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= diff --git a/pkg/exchange/okex/convert.go b/pkg/exchange/okex/convert.go index 2977c12c2..175dcf731 100644 --- a/pkg/exchange/okex/convert.go +++ b/pkg/exchange/okex/convert.go @@ -2,6 +2,7 @@ package okex import ( "fmt" + "hash/fnv" "regexp" "strconv" "strings" @@ -172,10 +173,7 @@ func toGlobalOrders(orderDetails []okexapi.OrderDetails) ([]types.Order, error) side := types.SideType(strings.ToUpper(string(orderDetail.Side))) - orderType, err := toGlobalOrderType(orderDetail.OrderType) - if err != nil { - return orders, err - } + orderType := toGlobalOrderType(orderDetail.OrderType) timeInForce := types.TimeInForceGTC switch orderDetail.OrderType { @@ -186,10 +184,7 @@ func toGlobalOrders(orderDetails []okexapi.OrderDetails) ([]types.Order, error) } - orderStatus, err := toGlobalOrderStatus(orderDetail.State) - if err != nil { - return orders, err - } + orderStatus := toGlobalOrderStatus(orderDetail.State) isWorking := false switch orderStatus { @@ -258,16 +253,21 @@ func toLocalOrderType(orderType types.OrderType) (okexapi.OrderType, error) { func toGlobalOrderType(orderType okexapi.OrderType) types.OrderType { switch orderType { - case okexapi.OrderTypeMarket: + case okexapi.OrderTypeMarket, okexapi.OrderTypeMarketMakerProtection: return types.OrderTypeMarket + case okexapi.OrderTypeLimit: return types.OrderTypeLimit + case okexapi.OrderTypePostOnly: return types.OrderTypeLimitMaker - case okexapi.OrderTypeFOK: - return types.OrderTypeFillOrKill - case okexapi.OrderTypeIOC: - return types.OrderTypeIOC + + case okexapi.OrderTypeIOC, okexapi.OrderTypeFOK: + return types.OrderTypeMarket + + case okexapi.OrderTypeMarektMakerProtectionPostOnly: + return types.OrderTypeLimitMaker + default: log.Errorf("unsupported order type: %v", orderType) return "" @@ -280,3 +280,34 @@ func toLocalInterval(src string) string { return strings.ToUpper(w) }) } + +func hashStringID(s string) uint64 { + h := fnv.New64a() + h.Write([]byte(s)) + return h.Sum64() +} + +func toGlobalOrder(okexOrder *okexapi.OrderDetails, isMargin bool) (*types.Order, error) { + timeInForce := types.TimeInForceFOK + if okexOrder.OrderType == okexapi.OrderTypeIOC { + timeInForce = types.TimeInForceIOC + } + return &types.Order{ + SubmitOrder: types.SubmitOrder{ + ClientOrderID: okexOrder.ClientOrderID, + Symbol: okexOrder.InstrumentID, + Side: types.SideType(okexOrder.Side), + Type: toGlobalOrderType(okexOrder.OrderType), + Quantity: okexOrder.Quantity, + Price: okexOrder.Price, + TimeInForce: types.TimeInForce(timeInForce), + }, + Exchange: types.ExchangeOKEx, + OrderID: hashStringID(okexOrder.OrderID), + Status: toGlobalOrderStatus(okexOrder.State), + ExecutedQuantity: okexOrder.FilledQuantity, + CreationTime: types.Time(okexOrder.CreationTime), + UpdateTime: types.Time(okexOrder.UpdateTime), + IsMargin: isMargin, + }, nil +} diff --git a/pkg/exchange/okex/exchange.go b/pkg/exchange/okex/exchange.go index 1214ed527..02b48af64 100644 --- a/pkg/exchange/okex/exchange.go +++ b/pkg/exchange/okex/exchange.go @@ -351,37 +351,18 @@ func (e *Exchange) QueryOrder(ctx context.Context, q types.OrderQuery) (*types.O req.InstrumentID(q.Symbol). OrderID(q.OrderID). ClientOrderID(q.ClientOrderID) - orderID, err := strconv.ParseInt(q.OrderID, 10, 64) - if err != nil { - return nil, err - } var order *okexapi.OrderDetails - order, err = req.Do(ctx) + order, err := req.Do(ctx) if err != nil { return nil, err } - timeInForce := types.TimeInForceFOK - if order.OrderType == okexapi.OrderTypeIOC { - timeInForce = types.TimeInForceIOC + isMargin := false + if order.InstrumentType == string(okexapi.InstrumentTypeMARGIN) { + isMargin = true } - return &types.Order{ - SubmitOrder: types.SubmitOrder{ - ClientOrderID: order.ClientOrderID, - Symbol: order.InstrumentID, - Side: types.SideType(order.Side), - Type: toGlobalOrderType(order.OrderType), - Quantity: order.Quantity, - Price: order.Price, - TimeInForce: types.TimeInForce(timeInForce), - }, - Exchange: types.ExchangeOKEx, - OrderID: uint64(orderID), - Status: toGlobalOrderStatus(order.State), - ExecutedQuantity: order.FilledQuantity, - CreationTime: types.Time(order.CreationTime), - UpdateTime: types.Time(order.UpdateTime), - }, nil + + return toGlobalOrder(order, isMargin) } diff --git a/pkg/exchange/okex/okexapi/client.go b/pkg/exchange/okex/okexapi/client.go index 626e84160..1138fd41a 100644 --- a/pkg/exchange/okex/okexapi/client.go +++ b/pkg/exchange/okex/okexapi/client.go @@ -33,11 +33,13 @@ const ( type OrderType string const ( - OrderTypeMarket OrderType = "market" - OrderTypeLimit OrderType = "limit" - OrderTypePostOnly OrderType = "post_only" - OrderTypeFOK OrderType = "fok" - OrderTypeIOC OrderType = "ioc" + OrderTypeMarket OrderType = "market" + OrderTypeLimit OrderType = "limit" + OrderTypePostOnly OrderType = "post_only" + OrderTypeFOK OrderType = "fok" + OrderTypeIOC OrderType = "ioc" + OrderTypeMarketMakerProtection OrderType = "mmp" + OrderTypeMarektMakerProtectionPostOnly OrderType = "mmp_and_post_only" ) type InstrumentType string @@ -47,6 +49,7 @@ const ( InstrumentTypeSwap InstrumentType = "SWAP" InstrumentTypeFutures InstrumentType = "FUTURES" InstrumentTypeOption InstrumentType = "OPTION" + InstrumentTypeMARGIN InstrumentType = "MARGIN" ) type OrderState string diff --git a/pkg/exchange/okex/okexapi/client_test.go b/pkg/exchange/okex/okexapi/client_test.go index 04fc69e1d..0f670d334 100644 --- a/pkg/exchange/okex/okexapi/client_test.go +++ b/pkg/exchange/okex/okexapi/client_test.go @@ -63,16 +63,16 @@ func TestClient_PlaceOrderRequest(t *testing.T) { req := srv.NewPlaceOrderRequest() order, err := req. - InstrumentID("XTZ-BTC"). + InstrumentID("BTC-USDT"). TradeMode("cash"). - Side(SideTypeSell). + Side(SideTypeBuy). OrderType(OrderTypeLimit). - Price("0.001"). - Quantity("0.01"). + Price("15000"). + Quantity("0.0001"). Do(ctx) assert.NoError(t, err) assert.NotEmpty(t, order) - t.Logf("order: %+v", order) // Right now account has no money + t.Logf("place order: %+v", order) } func TestClient_GetPendingOrderRequest(t *testing.T) { @@ -83,12 +83,12 @@ func TestClient_GetPendingOrderRequest(t *testing.T) { odr_type := []string{string(OrderTypeLimit), string(OrderTypeIOC)} pending_order, err := req. - InstrumentID("XTZ-BTC"). + InstrumentID("BTC-USDT"). OrderTypes(odr_type). Do(ctx) assert.NoError(t, err) - assert.Empty(t, pending_order) - t.Logf("order: %+v", pending_order) + assert.NotEmpty(t, pending_order) + t.Logf("pending order: %+v", pending_order) } func TestClient_GetOrderDetailsRequest(t *testing.T) { @@ -99,9 +99,9 @@ func TestClient_GetOrderDetailsRequest(t *testing.T) { orderDetail, err := req. InstrumentID("BTC-USDT"). - OrderID("xxx-test-order-id"). + OrderID("609869603774656544"). Do(ctx) - assert.Error(t, err) // Right now account has no orders - assert.Empty(t, orderDetail) - t.Logf("err: %+v", err) + assert.NoError(t, err) + assert.NotEmpty(t, orderDetail) + t.Logf("order detail: %+v", orderDetail) } diff --git a/pkg/exchange/okex/query_order_test.go b/pkg/exchange/okex/query_order_test.go new file mode 100644 index 000000000..3c32da40c --- /dev/null +++ b/pkg/exchange/okex/query_order_test.go @@ -0,0 +1,36 @@ +package okex + +import ( + "context" + "os" + "testing" + + "github.com/c9s/bbgo/pkg/types" + "github.com/stretchr/testify/assert" +) + +func Test_QueryOrder(t *testing.T) { + key := os.Getenv("OKEX_API_KEY") + secret := os.Getenv("OKEX_API_SECRET") + passphrase := os.Getenv("OKEX_API_PASSPHRASE") + if len(key) == 0 && len(secret) == 0 { + t.Skip("api key/secret are not configured") + return + } + if len(passphrase) == 0 { + t.Skip("passphrase are not configured") + return + } + + e := New(key, secret, passphrase) + + queryOrder := types.OrderQuery{ + Symbol: "BTC-USDT", + OrderID: "609869603774656544", + } + orderDetail, err := e.QueryOrder(context.Background(), queryOrder) + if assert.NoError(t, err) { + assert.NotEmpty(t, orderDetail) + } + t.Logf("order detail: %+v", orderDetail) +}