mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
pkg/exchange: add query open orders
This commit is contained in:
parent
c01be14c70
commit
b352ae855f
|
@ -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
|
||||
|
|
84
pkg/exchange/okex/convert_test.go
Normal file
84
pkg/exchange/okex/convert_test.go
Normal 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")
|
||||
})
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,10 @@ const (
|
|||
OrderStateFilled OrderState = "filled"
|
||||
)
|
||||
|
||||
func (o OrderState) IsWorking() bool {
|
||||
return o == OrderStateLive || o == OrderStatePartiallyFilled
|
||||
}
|
||||
|
||||
type RestClient struct {
|
||||
requestgen.BaseAPIClient
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
112
pkg/exchange/okex/okexapi/get_open_orders_request.go
Normal file
112
pkg/exchange/okex/okexapi/get_open_orders_request.go
Normal 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,
|
||||
}
|
||||
}
|
321
pkg/exchange/okex/okexapi/get_open_orders_request_requestgen.go
Normal file
321
pkg/exchange/okex/okexapi/get_open_orders_request_requestgen.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user