pkg/exchange: add query open orders

This commit is contained in:
Edwin 2024-01-11 16:41:42 +08:00
parent c01be14c70
commit b352ae855f
8 changed files with 628 additions and 117 deletions

View File

@ -149,6 +149,49 @@ func toGlobalTrades(orderDetails []okexapi.OrderDetails) ([]types.Trade, error)
return trades, nil
}
func openOrderToGlobal(order *okexapi.OpenOrder) (*types.Order, error) {
side := toGlobalSide(order.Side)
orderType, err := toGlobalOrderType(order.OrderType)
if err != nil {
return nil, err
}
timeInForce := types.TimeInForceGTC
switch order.OrderType {
case okexapi.OrderTypeFOK:
timeInForce = types.TimeInForceFOK
case okexapi.OrderTypeIOC:
timeInForce = types.TimeInForceIOC
}
orderStatus, err := toGlobalOrderStatus(order.State)
if err != nil {
return nil, err
}
return &types.Order{
SubmitOrder: types.SubmitOrder{
ClientOrderID: order.ClientOrderId,
Symbol: toGlobalSymbol(order.InstrumentID),
Side: side,
Type: orderType,
Price: order.Price,
Quantity: order.Size,
TimeInForce: timeInForce,
},
Exchange: types.ExchangeOKEx,
OrderID: uint64(order.OrderId),
UUID: strconv.FormatInt(int64(order.OrderId), 10),
Status: orderStatus,
OriginalStatus: string(order.State),
ExecutedQuantity: order.AccumulatedFillSize,
IsWorking: order.State.IsWorking(),
CreationTime: types.Time(order.CreatedTime),
UpdateTime: types.Time(order.UpdatedTime),
}, nil
}
func toGlobalOrders(orderDetails []okexapi.OrderDetails) ([]types.Order, error) {
var orders []types.Order
var err error

View File

@ -0,0 +1,84 @@
package okex
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/exchange/okex/okexapi"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
func Test_openOrderToGlobal(t *testing.T) {
var (
assert = assert.New(t)
orderId = 665576973905014786
// {"accFillSz":"0","algoClOrdId":"","algoId":"","attachAlgoClOrdId":"","attachAlgoOrds":[],"avgPx":"","cTime":"1704957916401","cancelSource":"","cancelSourceReason":"","category":"normal","ccy":"","clOrdId":"","fee":"0","feeCcy":"USDT","fillPx":"","fillSz":"0","fillTime":"","instId":"BTC-USDT","instType":"SPOT","lever":"","ordId":"665576973905014786","ordType":"limit","pnl":"0","posSide":"net","px":"48174.5","pxType":"","pxUsd":"","pxVol":"","quickMgnType":"","rebate":"0","rebateCcy":"BTC","reduceOnly":"false","side":"sell","slOrdPx":"","slTriggerPx":"","slTriggerPxType":"","source":"","state":"live","stpId":"","stpMode":"","sz":"0.00001","tag":"","tdMode":"cash","tgtCcy":"","tpOrdPx":"","tpTriggerPx":"","tpTriggerPxType":"","tradeId":"","uTime":"1704957916401"}
openOrder = &okexapi.OpenOrder{
AccumulatedFillSize: fixedpoint.NewFromFloat(0),
AvgPrice: fixedpoint.NewFromFloat(0),
CreatedTime: types.NewMillisecondTimestampFromInt(1704957916401),
Category: "normal",
Currency: "BTC",
ClientOrderId: "",
Fee: fixedpoint.Zero,
FeeCurrency: "USDT",
FillTime: types.NewMillisecondTimestampFromInt(0),
InstrumentID: "BTC-USDT",
InstrumentType: okexapi.InstrumentTypeSpot,
OrderId: types.StrInt64(orderId),
OrderType: okexapi.OrderTypeLimit,
Price: fixedpoint.NewFromFloat(48174.5),
Side: okexapi.SideTypeBuy,
State: okexapi.OrderStateLive,
Size: fixedpoint.NewFromFloat(0.00001),
UpdatedTime: types.NewMillisecondTimestampFromInt(1704957916401),
}
expOrder = &types.Order{
SubmitOrder: types.SubmitOrder{
ClientOrderID: openOrder.ClientOrderId,
Symbol: toGlobalSymbol(openOrder.InstrumentID),
Side: types.SideTypeBuy,
Type: types.OrderTypeLimit,
Quantity: fixedpoint.NewFromFloat(0.00001),
Price: fixedpoint.NewFromFloat(48174.5),
AveragePrice: fixedpoint.Zero,
StopPrice: fixedpoint.Zero,
TimeInForce: types.TimeInForceGTC,
},
Exchange: types.ExchangeOKEx,
OrderID: uint64(orderId),
UUID: fmt.Sprintf("%d", orderId),
Status: types.OrderStatusNew,
OriginalStatus: string(okexapi.OrderStateLive),
ExecutedQuantity: fixedpoint.Zero,
IsWorking: true,
CreationTime: types.Time(types.NewMillisecondTimestampFromInt(1704957916401).Time()),
UpdateTime: types.Time(types.NewMillisecondTimestampFromInt(1704957916401).Time()),
}
)
t.Run("succeeds", func(t *testing.T) {
order, err := openOrderToGlobal(openOrder)
assert.NoError(err)
assert.Equal(expOrder, order)
})
t.Run("unexpected order status", func(t *testing.T) {
newOrder := *openOrder
newOrder.State = "xxx"
_, err := openOrderToGlobal(&newOrder)
assert.ErrorContains(err, "xxx")
})
t.Run("unexpected order type", func(t *testing.T) {
newOrder := *openOrder
newOrder.OrderType = "xxx"
_, err := openOrderToGlobal(&newOrder)
assert.ErrorContains(err, "xxx")
})
}

View File

@ -30,15 +30,15 @@ var (
queryAccountLimiter = rate.NewLimiter(rate.Every(200*time.Millisecond), 5)
placeOrderLimiter = rate.NewLimiter(rate.Every(30*time.Millisecond), 30)
batchCancelOrderLimiter = rate.NewLimiter(rate.Every(5*time.Millisecond), 200)
queryOpenOrderLimiter = rate.NewLimiter(rate.Every(30*time.Millisecond), 30)
)
const ID = "okex"
const (
ID = "okex"
// PlatformToken is the platform currency of OKEx, pre-allocate static string here
const PlatformToken = "OKB"
PlatformToken = "OKB"
const (
// Constant For query limit
defaultQueryLimit = 100
)
@ -295,15 +295,46 @@ func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (*t
*/
}
// QueryOpenOrders retrieves the pending orders. The data returned is ordered by createdTime, and we utilized the
// `After` parameter to acquire all orders.
func (e *Exchange) QueryOpenOrders(ctx context.Context, symbol string) (orders []types.Order, err error) {
instrumentID := toLocalSymbol(symbol)
req := e.client.NewGetPendingOrderRequest().InstrumentType(okexapi.InstrumentTypeSpot).InstrumentID(instrumentID)
orderDetails, err := req.Do(ctx)
if err != nil {
return orders, err
nextCursor := int64(0)
for {
if err := queryOpenOrderLimiter.Wait(ctx); err != nil {
return nil, fmt.Errorf("query open orders rate limiter wait error: %w", err)
}
req := e.client.NewGetOpenOrdersRequest().
InstrumentID(instrumentID).
After(strconv.FormatInt(nextCursor, 10))
openOrders, err := req.Do(ctx)
if err != nil {
return nil, fmt.Errorf("failed to query open orders: %w", err)
}
for _, o := range openOrders {
o, err := openOrderToGlobal(&o)
if err != nil {
return nil, fmt.Errorf("failed to convert order, err: %v", err)
}
orders = append(orders, *o)
}
orderLen := len(openOrders)
// a defensive programming to ensure the length of order response is expected.
if orderLen > defaultQueryLimit {
return nil, fmt.Errorf("unexpected open orders length %d", orderLen)
}
if orderLen < defaultQueryLimit {
break
}
nextCursor = int64(openOrders[orderLen-1].OrderId)
}
orders, err = toGlobalOrders(orderDetails)
return orders, err
}

View File

@ -58,6 +58,10 @@ const (
OrderStateFilled OrderState = "filled"
)
func (o OrderState) IsWorking() bool {
return o == OrderStateLive || o == OrderStatePartiallyFilled
}
type RestClient struct {
requestgen.BaseAPIClient

View File

@ -140,6 +140,26 @@ func TestClient_CancelOrderRequest(t *testing.T) {
t.Log(cancelResp)
}
func TestClient_OpenOrdersRequest(t *testing.T) {
client := getTestClientOrSkip(t)
ctx := context.Background()
orders := []OpenOrder{}
beforeId := int64(0)
for {
c := client.NewGetOpenOrdersRequest().InstrumentID("BTC-USDT").Limit("1").After(fmt.Sprintf("%d", beforeId))
res, err := c.Do(ctx)
assert.NoError(t, err)
if len(res) != 1 {
break
}
orders = append(orders, res...)
beforeId = int64(res[0].OrderId)
}
t.Log(orders)
}
func TestClient_BatchCancelOrderRequest(t *testing.T) {
client := getTestClientOrSkip(t)
ctx := context.Background()
@ -170,21 +190,6 @@ func TestClient_BatchCancelOrderRequest(t *testing.T) {
t.Log(cancelResp)
}
func TestClient_GetPendingOrderRequest(t *testing.T) {
client := getTestClientOrSkip(t)
ctx := context.Background()
req := client.NewGetPendingOrderRequest()
odr_type := []string{string(OrderTypeLimit), string(OrderTypeIOC)}
pending_order, err := req.
InstrumentID("BTC-USDT").
OrderTypes(odr_type).
Do(ctx)
assert.NoError(t, err)
assert.NotEmpty(t, pending_order)
t.Logf("pending order: %+v", pending_order)
}
func TestClient_GetOrderDetailsRequest(t *testing.T) {
client := getTestClientOrSkip(t)
ctx := context.Background()

View File

@ -0,0 +1,112 @@
package okexapi
import (
"time"
"github.com/c9s/requestgen"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
//go:generate -command GetRequest requestgen -method GET -responseType .APIResponse -responseDataField Data
//go:generate -command PostRequest requestgen -method POST -responseType .APIResponse -responseDataField Data
type OpenOrder struct {
AccumulatedFillSize fixedpoint.Value `json:"accFillSz"`
// If none is filled, it will return "".
AvgPrice fixedpoint.Value `json:"avgPx"`
CreatedTime types.MillisecondTimestamp `json:"cTime"`
Category string `json:"category"`
ClientOrderId string `json:"clOrdId"`
Fee fixedpoint.Value `json:"fee"`
FeeCurrency string `json:"feeCcy"`
// Last filled time
FillTime types.MillisecondTimestamp `json:"fillTime"`
InstrumentID string `json:"instId"`
InstrumentType InstrumentType `json:"instType"`
OrderId types.StrInt64 `json:"ordId"`
OrderType OrderType `json:"ordType"`
Price fixedpoint.Value `json:"px"`
Side SideType `json:"side"`
State OrderState `json:"state"`
Size fixedpoint.Value `json:"sz"`
TargetCurrency string `json:"tgtCcy"`
UpdatedTime types.MillisecondTimestamp `json:"uTime"`
// Margin currency
// Only applicable to cross MARGIN orders in Single-currency margin.
Currency string `json:"ccy"`
TradeId string `json:"tradeId"`
// Last filled price
FillPrice fixedpoint.Value `json:"fillPx"`
// Last filled quantity
FillSize fixedpoint.Value `json:"fillSz"`
// Leverage, from 0.01 to 125.
// Only applicable to MARGIN/FUTURES/SWAP
Lever string `json:"lever"`
// Profit and loss, Applicable to orders which have a trade and aim to close position. It always is 0 in other conditions
Pnl fixedpoint.Value `json:"pnl"`
PositionSide string `json:"posSide"`
// Options price in USDOnly applicable to options; return "" for other instrument types
PriceUsd fixedpoint.Value `json:"pxUsd"`
// Implied volatility of the options orderOnly applicable to options; return "" for other instrument types
PriceVol fixedpoint.Value `json:"pxVol"`
// Price type of options
PriceType string `json:"pxType"`
// Rebate amount, only applicable to spot and margin, the reward of placing orders from the platform (rebate)
// given to user who has reached the specified trading level. If there is no rebate, this field is "".
Rebate fixedpoint.Value `json:"rebate"`
RebateCcy string `json:"rebateCcy"`
// Client-supplied Algo ID when placing order attaching TP/SL.
AttachAlgoClOrdId string `json:"attachAlgoClOrdId"`
SlOrdPx fixedpoint.Value `json:"slOrdPx"`
SlTriggerPx fixedpoint.Value `json:"slTriggerPx"`
SlTriggerPxType string `json:"slTriggerPxType"`
AttachAlgoOrds []interface{} `json:"attachAlgoOrds"`
Source string `json:"source"`
// Self trade prevention ID. Return "" if self trade prevention is not applicable
StpId string `json:"stpId"`
// Self trade prevention mode. Return "" if self trade prevention is not applicable
StpMode string `json:"stpMode"`
Tag string `json:"tag"`
TradeMode string `json:"tdMode"`
TpOrdPx fixedpoint.Value `json:"tpOrdPx"`
TpTriggerPx fixedpoint.Value `json:"tpTriggerPx"`
TpTriggerPxType string `json:"tpTriggerPxType"`
ReduceOnly string `json:"reduceOnly"`
QuickMgnType string `json:"quickMgnType"`
AlgoClOrdId string `json:"algoClOrdId"`
AlgoId string `json:"algoId"`
}
//go:generate GetRequest -url "/api/v5/trade/orders-pending" -type GetOpenOrdersRequest -responseDataType []OpenOrder
type GetOpenOrdersRequest struct {
client requestgen.AuthenticatedAPIClient
instrumentID *string `param:"instId,query"`
instrumentType InstrumentType `param:"instType,query"`
orderType *OrderType `param:"ordType,query"`
state *OrderState `param:"state,query"`
category *string `param:"category,query"`
// Pagination of data to return records earlier than the requested ordId
after *string `param:"after,query"`
// Pagination of data to return records newer than the requested ordId
before *string `param:"before,query"`
// Filter with a begin timestamp. Unix timestamp format in milliseconds, e.g. 1597026383085
begin *time.Time `param:"begin,query"`
// Filter with an end timestamp. Unix timestamp format in milliseconds, e.g. 1597026383085
end *time.Time `param:"end,query"`
limit *string `param:"limit,query"`
}
func (c *RestClient) NewGetOpenOrdersRequest() *GetOpenOrdersRequest {
return &GetOpenOrdersRequest{
client: c,
instrumentType: InstrumentTypeSpot,
}
}

View File

@ -0,0 +1,321 @@
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v5/trade/orders-pending -type GetOpenOrdersRequest -responseDataType []OpenOrder"; DO NOT EDIT.
package okexapi
import (
"context"
"encoding/json"
"fmt"
"net/url"
"reflect"
"regexp"
"time"
)
func (g *GetOpenOrdersRequest) InstrumentID(instrumentID string) *GetOpenOrdersRequest {
g.instrumentID = &instrumentID
return g
}
func (g *GetOpenOrdersRequest) InstrumentType(instrumentType InstrumentType) *GetOpenOrdersRequest {
g.instrumentType = instrumentType
return g
}
func (g *GetOpenOrdersRequest) OrderType(orderType OrderType) *GetOpenOrdersRequest {
g.orderType = &orderType
return g
}
func (g *GetOpenOrdersRequest) State(state OrderState) *GetOpenOrdersRequest {
g.state = &state
return g
}
func (g *GetOpenOrdersRequest) Category(category string) *GetOpenOrdersRequest {
g.category = &category
return g
}
func (g *GetOpenOrdersRequest) After(after string) *GetOpenOrdersRequest {
g.after = &after
return g
}
func (g *GetOpenOrdersRequest) Before(before string) *GetOpenOrdersRequest {
g.before = &before
return g
}
func (g *GetOpenOrdersRequest) Begin(begin time.Time) *GetOpenOrdersRequest {
g.begin = &begin
return g
}
func (g *GetOpenOrdersRequest) End(end time.Time) *GetOpenOrdersRequest {
g.end = &end
return g
}
func (g *GetOpenOrdersRequest) Limit(limit string) *GetOpenOrdersRequest {
g.limit = &limit
return g
}
// GetQueryParameters builds and checks the query parameters and returns url.Values
func (g *GetOpenOrdersRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{}
// check instrumentID field -> json key instId
if g.instrumentID != nil {
instrumentID := *g.instrumentID
// assign parameter of instrumentID
params["instId"] = instrumentID
} else {
}
// check instrumentType field -> json key instType
instrumentType := g.instrumentType
// TEMPLATE check-valid-values
switch instrumentType {
case InstrumentTypeSpot, InstrumentTypeSwap, InstrumentTypeFutures, InstrumentTypeOption, InstrumentTypeMARGIN:
params["instType"] = instrumentType
default:
return nil, fmt.Errorf("instType value %v is invalid", instrumentType)
}
// END TEMPLATE check-valid-values
// assign parameter of instrumentType
params["instType"] = instrumentType
// check orderType field -> json key ordType
if g.orderType != nil {
orderType := *g.orderType
// TEMPLATE check-valid-values
switch orderType {
case OrderTypeMarket, OrderTypeLimit, OrderTypePostOnly, OrderTypeFOK, OrderTypeIOC:
params["ordType"] = orderType
default:
return nil, fmt.Errorf("ordType value %v is invalid", orderType)
}
// END TEMPLATE check-valid-values
// assign parameter of orderType
params["ordType"] = orderType
} else {
}
// check state field -> json key state
if g.state != nil {
state := *g.state
// TEMPLATE check-valid-values
switch state {
case OrderStateCanceled, OrderStateLive, OrderStatePartiallyFilled, OrderStateFilled:
params["state"] = state
default:
return nil, fmt.Errorf("state value %v is invalid", state)
}
// END TEMPLATE check-valid-values
// assign parameter of state
params["state"] = state
} else {
}
// check category field -> json key category
if g.category != nil {
category := *g.category
// assign parameter of category
params["category"] = category
} else {
}
// check after field -> json key after
if g.after != nil {
after := *g.after
// assign parameter of after
params["after"] = after
} else {
}
// check before field -> json key before
if g.before != nil {
before := *g.before
// assign parameter of before
params["before"] = before
} else {
}
// check begin field -> json key begin
if g.begin != nil {
begin := *g.begin
// assign parameter of begin
params["begin"] = begin
} else {
}
// check end field -> json key end
if g.end != nil {
end := *g.end
// assign parameter of end
params["end"] = end
} else {
}
// check limit field -> json key limit
if g.limit != nil {
limit := *g.limit
// assign parameter of limit
params["limit"] = limit
} else {
}
query := url.Values{}
for _k, _v := range params {
query.Add(_k, fmt.Sprintf("%v", _v))
}
return query, nil
}
// GetParameters builds and checks the parameters and return the result in a map object
func (g *GetOpenOrdersRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil
}
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (g *GetOpenOrdersRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{}
params, err := g.GetParameters()
if err != nil {
return query, err
}
for _k, _v := range params {
if g.isVarSlice(_v) {
g.iterateSlice(_v, func(it interface{}) {
query.Add(_k+"[]", fmt.Sprintf("%v", it))
})
} else {
query.Add(_k, fmt.Sprintf("%v", _v))
}
}
return query, nil
}
// GetParametersJSON converts the parameters from GetParameters into the JSON format
func (g *GetOpenOrdersRequest) GetParametersJSON() ([]byte, error) {
params, err := g.GetParameters()
if err != nil {
return nil, err
}
return json.Marshal(params)
}
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
func (g *GetOpenOrdersRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil
}
func (g *GetOpenOrdersRequest) applySlugsToUrl(url string, slugs map[string]string) string {
for _k, _v := range slugs {
needleRE := regexp.MustCompile(":" + _k + "\\b")
url = needleRE.ReplaceAllString(url, _v)
}
return url
}
func (g *GetOpenOrdersRequest) iterateSlice(slice interface{}, _f func(it interface{})) {
sliceValue := reflect.ValueOf(slice)
for _i := 0; _i < sliceValue.Len(); _i++ {
it := sliceValue.Index(_i).Interface()
_f(it)
}
}
func (g *GetOpenOrdersRequest) isVarSlice(_v interface{}) bool {
rt := reflect.TypeOf(_v)
switch rt.Kind() {
case reflect.Slice:
return true
}
return false
}
func (g *GetOpenOrdersRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{}
params, err := g.GetSlugParameters()
if err != nil {
return slugs, nil
}
for _k, _v := range params {
slugs[_k] = fmt.Sprintf("%v", _v)
}
return slugs, nil
}
// GetPath returns the request path of the API
func (g *GetOpenOrdersRequest) GetPath() string {
return "/api/v5/trade/orders-pending"
}
// Do generates the request object and send the request object to the API endpoint
func (g *GetOpenOrdersRequest) Do(ctx context.Context) ([]OpenOrder, error) {
// no body params
var params interface{}
query, err := g.GetQueryParameters()
if err != nil {
return nil, err
}
var apiURL string
apiURL = g.GetPath()
req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
if err != nil {
return nil, err
}
response, err := g.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse APIResponse
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
type responseValidator interface {
Validate() error
}
validator, ok := interface{}(apiResponse).(responseValidator)
if ok {
if err := validator.Validate(); err != nil {
return nil, err
}
}
var data []OpenOrder
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
return nil, err
}
return data, nil
}

View File

@ -4,11 +4,11 @@ import (
"context"
"encoding/json"
"net/url"
"strings"
"github.com/pkg/errors"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
"github.com/pkg/errors"
)
func (c *RestClient) NewBatchPlaceOrderRequest() *BatchPlaceOrderRequest {
@ -29,12 +29,6 @@ func (c *RestClient) NewGetOrderDetailsRequest() *GetOrderDetailsRequest {
}
}
func (c *RestClient) NewGetPendingOrderRequest() *GetPendingOrderRequest {
return &GetPendingOrderRequest{
client: c,
}
}
func (c *RestClient) NewGetTransactionDetailsRequest() *GetTransactionDetailsRequest {
return &GetTransactionDetailsRequest{
client: c,
@ -249,89 +243,6 @@ func (r *GetOrderDetailsRequest) Do(ctx context.Context) (*OrderDetails, error)
return &data[0], nil
}
type GetPendingOrderRequest struct {
client *RestClient
instId *string
instType *InstrumentType
orderTypes []string
state *OrderState
}
func (r *GetPendingOrderRequest) InstrumentID(instId string) *GetPendingOrderRequest {
r.instId = &instId
return r
}
func (r *GetPendingOrderRequest) InstrumentType(instType InstrumentType) *GetPendingOrderRequest {
r.instType = &instType
return r
}
func (r *GetPendingOrderRequest) State(state OrderState) *GetPendingOrderRequest {
r.state = &state
return r
}
func (r *GetPendingOrderRequest) OrderTypes(orderTypes []string) *GetPendingOrderRequest {
r.orderTypes = orderTypes
return r
}
func (r *GetPendingOrderRequest) AddOrderTypes(orderTypes ...string) *GetPendingOrderRequest {
r.orderTypes = append(r.orderTypes, orderTypes...)
return r
}
func (r *GetPendingOrderRequest) Parameters() map[string]interface{} {
var payload = map[string]interface{}{}
if r.instId != nil {
payload["instId"] = r.instId
}
if r.instType != nil {
payload["instType"] = r.instType
}
if r.state != nil {
payload["state"] = r.state
}
if len(r.orderTypes) > 0 {
payload["ordType"] = strings.Join(r.orderTypes, ",")
}
return payload
}
func (r *GetPendingOrderRequest) Do(ctx context.Context) ([]OrderDetails, error) {
payload := r.Parameters()
req, err := r.client.NewAuthenticatedRequest(ctx, "GET", "/api/v5/trade/orders-pending", nil, payload)
if err != nil {
return nil, err
}
response, err := r.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse APIResponse
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
var data []OrderDetails
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
return nil, err
}
return data, nil
}
type GetTransactionDetailsRequest struct {
client *RestClient