mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +00:00
add QueryClosedOrders() and QueryTrades() for okex, also fix conflict for QueryOrderTrades() and update typo error in QueryOrderTrades()
This commit is contained in:
parent
cf31796224
commit
99a69f4f2f
|
@ -23,7 +23,7 @@ import (
|
|||
// Market data limiter means public api, this includes QueryMarkets, QueryTicker, QueryTickers, QueryKLines
|
||||
var (
|
||||
marketDataLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 5)
|
||||
tradeRateLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 5)
|
||||
tradeRateLimiter = rate.NewLimiter(rate.Every(300*time.Millisecond), 5)
|
||||
orderRateLimiter = rate.NewLimiter(rate.Every(300*time.Millisecond), 5)
|
||||
)
|
||||
|
||||
|
@ -32,6 +32,11 @@ const ID = "okex"
|
|||
// PlatformToken is the platform currency of OKEx, pre-allocate static string here
|
||||
const PlatformToken = "OKB"
|
||||
|
||||
const (
|
||||
// Constant For query limit
|
||||
defaultQueryLimit = 100
|
||||
)
|
||||
|
||||
var log = logrus.WithFields(logrus.Fields{
|
||||
"exchange": ID,
|
||||
})
|
||||
|
@ -360,7 +365,7 @@ func (e *Exchange) QueryOrder(ctx context.Context, q types.OrderQuery) (*types.O
|
|||
return nil, errors.New("okex.QueryOrder: OrderId or ClientOrderId is required parameter")
|
||||
}
|
||||
req := e.client.NewGetOrderDetailsRequest()
|
||||
req.InstrumentID(q.Symbol).
|
||||
req.InstrumentID(toLocalSymbol(q.Symbol)).
|
||||
OrderID(q.OrderID).
|
||||
ClientOrderID(q.ClientOrderID)
|
||||
|
||||
|
@ -380,9 +385,9 @@ func (e *Exchange) QueryOrderTrades(ctx context.Context, q types.OrderQuery) ([]
|
|||
log.Warn("!!!OKEX EXCHANGE API NOTICE!!! Okex does not support searching for trades using OrderClientId.")
|
||||
}
|
||||
|
||||
req := e.client.NewGetTransactionHistoriesRequest()
|
||||
req := e.client.NewGetTransactionHistoryRequest()
|
||||
if len(q.Symbol) != 0 {
|
||||
req.InstrumentID(q.Symbol)
|
||||
req.InstrumentID(toLocalSymbol(q.Symbol))
|
||||
}
|
||||
|
||||
if len(q.OrderID) != 0 {
|
||||
|
@ -411,6 +416,131 @@ func (e *Exchange) QueryOrderTrades(ctx context.Context, q types.OrderQuery) ([]
|
|||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
return trades, nil
|
||||
}
|
||||
|
||||
/*
|
||||
QueryClosedOrders can query closed orders in last 3 months, there are no time interval limitations, as long as until >= since.
|
||||
Please Use lastOrderID as cursor, only return orders later than that order, that order is not included.
|
||||
If you want to query orders by time range, please just pass since and until.
|
||||
If you want to query by cursor, please pass lastOrderID.
|
||||
Because it gets the correct response even when you pass all parameters with the right time interval and invalid lastOrderID, like 0.
|
||||
Time interval boundary unit is second.
|
||||
since is inclusive, ex. order created in 1694155903, get response if query since 1694155903, get empty if query since 1694155904
|
||||
until is not inclusive, ex. order created in 1694155903, get response if query until 1694155904, get empty if query until 1694155903
|
||||
*/
|
||||
func (e *Exchange) QueryClosedOrders(ctx context.Context, symbol string, since, until time.Time, lastOrderID uint64) ([]types.Order, error) {
|
||||
if symbol == "" {
|
||||
return nil, ErrSymbolRequired
|
||||
}
|
||||
|
||||
if err := tradeRateLimiter.Wait(ctx); err != nil {
|
||||
return nil, fmt.Errorf("query closed order rate limiter wait error: %w", err)
|
||||
}
|
||||
|
||||
var lastOrder string
|
||||
if lastOrderID <= 0 {
|
||||
lastOrder = ""
|
||||
} else {
|
||||
lastOrder = strconv.FormatUint(lastOrderID, 10)
|
||||
}
|
||||
|
||||
res, err := e.client.NewGetOrderHistoryRequest().
|
||||
InstrumentID(toLocalSymbol(symbol)).
|
||||
StartTime(since).
|
||||
EndTime(until).
|
||||
Limit(defaultQueryLimit).
|
||||
Before(lastOrder).
|
||||
Do(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to call get order histories error: %w", err)
|
||||
}
|
||||
|
||||
var orders []types.Order
|
||||
|
||||
for _, order := range res {
|
||||
o, err2 := toGlobalOrder(&order)
|
||||
if err2 != nil {
|
||||
err = multierr.Append(err, err2)
|
||||
continue
|
||||
}
|
||||
|
||||
orders = append(orders, *o)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.SortOrdersAscending(orders), nil
|
||||
}
|
||||
|
||||
/*
|
||||
QueryTrades can query trades in last 3 months, there are no time interval limitations, as long as end_time >= start_time.
|
||||
OKEX do not provide api to query by tradeID, So use /api/v5/trade/orders-history-archive as its official site do.
|
||||
Please Use LastTradeID as cursor, only return trades later than that trade, that trade is not included.
|
||||
If you want to query trades by time range, please just pass start_time and end_time.
|
||||
If you want to query by cursor, please pass LastTradeID.
|
||||
Because it gets the correct response even when you pass all parameters with the right time interval and invalid LastTradeID, like 0.
|
||||
*/
|
||||
func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) ([]types.Trade, error) {
|
||||
if symbol == "" {
|
||||
return nil, ErrSymbolRequired
|
||||
}
|
||||
|
||||
req := e.client.NewGetOrderHistoryRequest().InstrumentID(toLocalSymbol(symbol))
|
||||
|
||||
limit := uint64(options.Limit)
|
||||
if limit > defaultQueryLimit || limit <= 0 {
|
||||
log.Debugf("limit is exceeded default limit %d or zero, got: %d, Do not pass limit", defaultQueryLimit, options.Limit)
|
||||
} else {
|
||||
req.Limit(limit)
|
||||
}
|
||||
|
||||
if err := tradeRateLimiter.Wait(ctx); err != nil {
|
||||
return nil, fmt.Errorf("query trades rate limiter wait error: %w", err)
|
||||
}
|
||||
|
||||
var err error
|
||||
var response []okexapi.OrderDetails
|
||||
// query by time interval
|
||||
if options.StartTime != nil || options.EndTime != nil {
|
||||
if options.StartTime != nil {
|
||||
req.StartTime(*options.StartTime)
|
||||
}
|
||||
if options.EndTime != nil {
|
||||
req.EndTime(*options.EndTime)
|
||||
}
|
||||
|
||||
response, err = req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to call get order histories error: %w", err)
|
||||
}
|
||||
} else if options.StartTime == nil && options.EndTime == nil && options.LastTradeID == 0 { // query by no any parameters
|
||||
response, err = req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to call get order histories error: %w", err)
|
||||
}
|
||||
} else { // query by trade id
|
||||
lastTradeID := strconv.FormatUint(options.LastTradeID, 10)
|
||||
res, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to call get order histories error: %w", err)
|
||||
}
|
||||
for _, trade := range res {
|
||||
if trade.LastTradeID == lastTradeID {
|
||||
response, err = req.Before(trade.OrderID).Do(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to call get order histories error: %w", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trades, err := toGlobalTrades(response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to trans order detail to trades error: %w", err)
|
||||
}
|
||||
return trades, nil
|
||||
}
|
||||
|
|
40
pkg/exchange/okex/okexapi/get_order_history_request.go
Normal file
40
pkg/exchange/okex/okexapi/get_order_history_request.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package okexapi
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/c9s/requestgen"
|
||||
)
|
||||
|
||||
//go:generate GetRequest -url "/api/v5/trade/orders-history-archive" -type GetOrderHistoryRequest -responseDataType .APIResponse
|
||||
type GetOrderHistoryRequest struct {
|
||||
client requestgen.AuthenticatedAPIClient
|
||||
|
||||
instrumentType InstrumentType `param:"instType,query"`
|
||||
instrumentID *string `param:"instId,query"`
|
||||
orderType *OrderType `param:"ordType,query"`
|
||||
// underlying and instrumentFamil Applicable to FUTURES/SWAP/OPTION
|
||||
underlying *string `param:"uly,query"`
|
||||
instrumentFamily *string `param:"instFamily,query"`
|
||||
|
||||
state *OrderState `param:"state,query"`
|
||||
after *string `param:"after,query"`
|
||||
before *string `param:"before,query"`
|
||||
startTime *time.Time `param:"begin,query,milliseconds"`
|
||||
|
||||
// endTime for each request, startTime and endTime can be any interval, but should be in last 3 months
|
||||
endTime *time.Time `param:"end,query,milliseconds"`
|
||||
|
||||
// limit for data size per page. Default: 100
|
||||
limit *uint64 `param:"limit,query"`
|
||||
}
|
||||
|
||||
type OrderList []OrderDetails
|
||||
|
||||
// NewGetOrderHistoriesRequest is descending order by createdTime
|
||||
func (c *RestClient) NewGetOrderHistoryRequest() *GetOrderHistoryRequest {
|
||||
return &GetOrderHistoryRequest{
|
||||
client: c,
|
||||
instrumentType: InstrumentTypeSpot,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v5/trade/orders-history-archive -type GetOrderHistoryRequest -responseDataType .OrderList"; DO NOT EDIT.
|
||||
|
||||
package okexapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GetOrderHistoryRequest) InstrumentType(instrumentType InstrumentType) *GetOrderHistoryRequest {
|
||||
g.instrumentType = instrumentType
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) InstrumentID(instrumentID string) *GetOrderHistoryRequest {
|
||||
g.instrumentID = &instrumentID
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) OrderType(orderType OrderType) *GetOrderHistoryRequest {
|
||||
g.orderType = &orderType
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) Underlying(underlying string) *GetOrderHistoryRequest {
|
||||
g.underlying = &underlying
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) InstrumentFamily(instrumentFamily string) *GetOrderHistoryRequest {
|
||||
g.instrumentFamily = &instrumentFamily
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) State(state OrderState) *GetOrderHistoryRequest {
|
||||
g.state = &state
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) After(after string) *GetOrderHistoryRequest {
|
||||
g.after = &after
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) Before(before string) *GetOrderHistoryRequest {
|
||||
g.before = &before
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) StartTime(startTime time.Time) *GetOrderHistoryRequest {
|
||||
g.startTime = &startTime
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) EndTime(endTime time.Time) *GetOrderHistoryRequest {
|
||||
g.endTime = &endTime
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) Limit(limit uint64) *GetOrderHistoryRequest {
|
||||
g.limit = &limit
|
||||
return g
|
||||
}
|
||||
|
||||
// GetQueryParameters builds and checks the query parameters and returns url.Values
|
||||
func (g *GetOrderHistoryRequest) GetQueryParameters() (url.Values, error) {
|
||||
var params = map[string]interface{}{}
|
||||
// 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 instrumentID field -> json key instId
|
||||
if g.instrumentID != nil {
|
||||
instrumentID := *g.instrumentID
|
||||
|
||||
// assign parameter of instrumentID
|
||||
params["instId"] = instrumentID
|
||||
} else {
|
||||
}
|
||||
// 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 underlying field -> json key uly
|
||||
if g.underlying != nil {
|
||||
underlying := *g.underlying
|
||||
|
||||
// assign parameter of underlying
|
||||
params["uly"] = underlying
|
||||
} else {
|
||||
}
|
||||
// check instrumentFamily field -> json key instFamily
|
||||
if g.instrumentFamily != nil {
|
||||
instrumentFamily := *g.instrumentFamily
|
||||
|
||||
// assign parameter of instrumentFamily
|
||||
params["instFamily"] = instrumentFamily
|
||||
} 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 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 startTime field -> json key begin
|
||||
if g.startTime != nil {
|
||||
startTime := *g.startTime
|
||||
|
||||
// assign parameter of startTime
|
||||
// convert time.Time to milliseconds time stamp
|
||||
params["begin"] = strconv.FormatInt(startTime.UnixNano()/int64(time.Millisecond), 10)
|
||||
} else {
|
||||
}
|
||||
// check endTime field -> json key end
|
||||
if g.endTime != nil {
|
||||
endTime := *g.endTime
|
||||
|
||||
// assign parameter of endTime
|
||||
// convert time.Time to milliseconds time stamp
|
||||
params["end"] = strconv.FormatInt(endTime.UnixNano()/int64(time.Millisecond), 10)
|
||||
} 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 *GetOrderHistoryRequest) 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 *GetOrderHistoryRequest) 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 *GetOrderHistoryRequest) 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 *GetOrderHistoryRequest) GetSlugParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) 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 *GetOrderHistoryRequest) 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 *GetOrderHistoryRequest) isVarSlice(_v interface{}) bool {
|
||||
rt := reflect.TypeOf(_v)
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) 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
|
||||
}
|
||||
|
||||
func (g *GetOrderHistoryRequest) Do(ctx context.Context) (OrderList, error) {
|
||||
|
||||
// no body params
|
||||
var params interface{}
|
||||
query, err := g.GetQueryParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiURL := "/api/v5/trade/orders-history-archive"
|
||||
|
||||
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
|
||||
}
|
||||
var data OrderList
|
||||
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
|
@ -6,8 +6,8 @@ import (
|
|||
"github.com/c9s/requestgen"
|
||||
)
|
||||
|
||||
//go:generate GetRequest -url "/api/v5/trade/fills-history" -type GetTransactionHistoriesRequest -responseDataType .APIResponse
|
||||
type GetTransactionHistoriesRequest struct {
|
||||
//go:generate GetRequest -url "/api/v5/trade/fills-history" -type GetTransactionHistoryRequest -responseDataType .APIResponse
|
||||
type GetTransactionHistoryRequest struct {
|
||||
client requestgen.AuthenticatedAPIClient
|
||||
|
||||
instrumentType InstrumentType `param:"instType,query"`
|
||||
|
@ -29,11 +29,9 @@ type GetTransactionHistoriesRequest struct {
|
|||
limit *uint64 `param:"limit,query"`
|
||||
}
|
||||
|
||||
type OrderList []OrderDetails
|
||||
|
||||
// NewGetOrderHistoriesRequest is descending order by createdTime
|
||||
func (c *RestClient) NewGetTransactionHistoriesRequest() *GetTransactionHistoriesRequest {
|
||||
return &GetTransactionHistoriesRequest{
|
||||
func (c *RestClient) NewGetTransactionHistoryRequest() *GetTransactionHistoryRequest {
|
||||
return &GetTransactionHistoryRequest{
|
||||
client: c,
|
||||
instrumentType: InstrumentTypeSpot,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v5/trade/fills-history -type GetTransactionHistoriesRequest -responseDataType .OrderList"; DO NOT EDIT.
|
||||
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v5/trade/fills-history -type GetTransactionHistoryRequest -responseDataType .OrderList"; DO NOT EDIT.
|
||||
|
||||
package okexapi
|
||||
|
||||
|
@ -13,63 +13,63 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) InstrumentType(instrumentType InstrumentType) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) InstrumentType(instrumentType InstrumentType) *GetTransactionHistoryRequest {
|
||||
g.instrumentType = instrumentType
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) InstrumentID(instrumentID string) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) InstrumentID(instrumentID string) *GetTransactionHistoryRequest {
|
||||
g.instrumentID = &instrumentID
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) OrderType(orderType OrderType) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) OrderType(orderType OrderType) *GetTransactionHistoryRequest {
|
||||
g.orderType = &orderType
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) OrderID(orderID string) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) OrderID(orderID string) *GetTransactionHistoryRequest {
|
||||
g.orderID = orderID
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) Underlying(underlying string) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) Underlying(underlying string) *GetTransactionHistoryRequest {
|
||||
g.underlying = &underlying
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) InstrumentFamily(instrumentFamily string) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) InstrumentFamily(instrumentFamily string) *GetTransactionHistoryRequest {
|
||||
g.instrumentFamily = &instrumentFamily
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) After(after string) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) After(after string) *GetTransactionHistoryRequest {
|
||||
g.after = &after
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) Before(before string) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) Before(before string) *GetTransactionHistoryRequest {
|
||||
g.before = &before
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) StartTime(startTime time.Time) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) StartTime(startTime time.Time) *GetTransactionHistoryRequest {
|
||||
g.startTime = &startTime
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) EndTime(endTime time.Time) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) EndTime(endTime time.Time) *GetTransactionHistoryRequest {
|
||||
g.endTime = &endTime
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) Limit(limit uint64) *GetTransactionHistoriesRequest {
|
||||
func (g *GetTransactionHistoryRequest) Limit(limit uint64) *GetTransactionHistoryRequest {
|
||||
g.limit = &limit
|
||||
return g
|
||||
}
|
||||
|
||||
// GetQueryParameters builds and checks the query parameters and returns url.Values
|
||||
func (g *GetTransactionHistoriesRequest) GetQueryParameters() (url.Values, error) {
|
||||
func (g *GetTransactionHistoryRequest) GetQueryParameters() (url.Values, error) {
|
||||
var params = map[string]interface{}{}
|
||||
// check instrumentType field -> json key instType
|
||||
instrumentType := g.instrumentType
|
||||
|
@ -187,14 +187,14 @@ func (g *GetTransactionHistoriesRequest) GetQueryParameters() (url.Values, error
|
|||
}
|
||||
|
||||
// GetParameters builds and checks the parameters and return the result in a map object
|
||||
func (g *GetTransactionHistoriesRequest) GetParameters() (map[string]interface{}, error) {
|
||||
func (g *GetTransactionHistoryRequest) 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 *GetTransactionHistoriesRequest) GetParametersQuery() (url.Values, error) {
|
||||
func (g *GetTransactionHistoryRequest) GetParametersQuery() (url.Values, error) {
|
||||
query := url.Values{}
|
||||
|
||||
params, err := g.GetParameters()
|
||||
|
@ -216,7 +216,7 @@ func (g *GetTransactionHistoriesRequest) GetParametersQuery() (url.Values, error
|
|||
}
|
||||
|
||||
// GetParametersJSON converts the parameters from GetParameters into the JSON format
|
||||
func (g *GetTransactionHistoriesRequest) GetParametersJSON() ([]byte, error) {
|
||||
func (g *GetTransactionHistoryRequest) GetParametersJSON() ([]byte, error) {
|
||||
params, err := g.GetParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -226,13 +226,13 @@ func (g *GetTransactionHistoriesRequest) GetParametersJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
|
||||
func (g *GetTransactionHistoriesRequest) GetSlugParameters() (map[string]interface{}, error) {
|
||||
func (g *GetTransactionHistoryRequest) GetSlugParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) applySlugsToUrl(url string, slugs map[string]string) string {
|
||||
func (g *GetTransactionHistoryRequest) applySlugsToUrl(url string, slugs map[string]string) string {
|
||||
for _k, _v := range slugs {
|
||||
needleRE := regexp.MustCompile(":" + _k + "\\b")
|
||||
url = needleRE.ReplaceAllString(url, _v)
|
||||
|
@ -241,7 +241,7 @@ func (g *GetTransactionHistoriesRequest) applySlugsToUrl(url string, slugs map[s
|
|||
return url
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) iterateSlice(slice interface{}, _f func(it interface{})) {
|
||||
func (g *GetTransactionHistoryRequest) iterateSlice(slice interface{}, _f func(it interface{})) {
|
||||
sliceValue := reflect.ValueOf(slice)
|
||||
for _i := 0; _i < sliceValue.Len(); _i++ {
|
||||
it := sliceValue.Index(_i).Interface()
|
||||
|
@ -249,7 +249,7 @@ func (g *GetTransactionHistoriesRequest) iterateSlice(slice interface{}, _f func
|
|||
}
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) isVarSlice(_v interface{}) bool {
|
||||
func (g *GetTransactionHistoryRequest) isVarSlice(_v interface{}) bool {
|
||||
rt := reflect.TypeOf(_v)
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
|
@ -258,7 +258,7 @@ func (g *GetTransactionHistoriesRequest) isVarSlice(_v interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) GetSlugsMap() (map[string]string, error) {
|
||||
func (g *GetTransactionHistoryRequest) GetSlugsMap() (map[string]string, error) {
|
||||
slugs := map[string]string{}
|
||||
params, err := g.GetSlugParameters()
|
||||
if err != nil {
|
||||
|
@ -272,7 +272,7 @@ func (g *GetTransactionHistoriesRequest) GetSlugsMap() (map[string]string, error
|
|||
return slugs, nil
|
||||
}
|
||||
|
||||
func (g *GetTransactionHistoriesRequest) Do(ctx context.Context) (OrderList, error) {
|
||||
func (g *GetTransactionHistoryRequest) Do(ctx context.Context) (OrderList, error) {
|
||||
|
||||
// no body params
|
||||
var params interface{}
|
62
pkg/exchange/okex/query_closed_orders_test.go
Normal file
62
pkg/exchange/okex/query_closed_orders_test.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package okex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/testutil"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_QueryClosedOrders(t *testing.T) {
|
||||
|
||||
key, secret, passphrase, ok := testutil.IntegrationTestWithPassphraseConfigured(t, types.ExchangeOKEx.String())
|
||||
if !ok {
|
||||
t.Skip("Please configure all credentials about OKEX")
|
||||
}
|
||||
|
||||
e := New(key, secret, passphrase)
|
||||
|
||||
queryOrder := types.OrderQuery{
|
||||
Symbol: "BTCUSDT",
|
||||
}
|
||||
|
||||
// test by order id as a cursor
|
||||
closedOrder, err := e.QueryClosedOrders(context.Background(), string(queryOrder.Symbol), time.Time{}, time.Time{}, 609869603774656544)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, closedOrder)
|
||||
}
|
||||
t.Logf("closed order detail: %+v", closedOrder)
|
||||
// test by time interval
|
||||
closedOrder, err = e.QueryClosedOrders(context.Background(), string(queryOrder.Symbol), time.Now().Add(-90*24*time.Hour), time.Now(), 0)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, closedOrder)
|
||||
}
|
||||
t.Logf("closed order detail: %+v", closedOrder)
|
||||
// test by no parameter
|
||||
closedOrder, err = e.QueryClosedOrders(context.Background(), string(queryOrder.Symbol), time.Time{}, time.Time{}, 0)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, closedOrder)
|
||||
}
|
||||
t.Logf("closed order detail: %+v", closedOrder)
|
||||
// test by time interval (boundary test)
|
||||
closedOrder, err = e.QueryClosedOrders(context.Background(), string(queryOrder.Symbol), time.Unix(1694155903, 999), time.Now(), 0)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, closedOrder)
|
||||
}
|
||||
t.Logf("closed order detail: %+v", closedOrder)
|
||||
// test by time interval (boundary test)
|
||||
closedOrder, err = e.QueryClosedOrders(context.Background(), string(queryOrder.Symbol), time.Unix(1694154903, 999), time.Unix(1694155904, 0), 0)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, closedOrder)
|
||||
}
|
||||
t.Logf("closed order detail: %+v", closedOrder)
|
||||
// test by time interval and order id together
|
||||
closedOrder, err = e.QueryClosedOrders(context.Background(), string(queryOrder.Symbol), time.Unix(1694154903, 999), time.Now(), 609869603774656544)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, closedOrder)
|
||||
}
|
||||
t.Logf("closed order detail: %+v", closedOrder)
|
||||
}
|
|
@ -25,7 +25,7 @@ func Test_QueryOrder(t *testing.T) {
|
|||
e := New(key, secret, passphrase)
|
||||
|
||||
queryOrder := types.OrderQuery{
|
||||
Symbol: "BTC-USDT",
|
||||
Symbol: "BTCUSDT",
|
||||
OrderID: "609869603774656544",
|
||||
}
|
||||
orderDetail, err := e.QueryOrder(context.Background(), queryOrder)
|
||||
|
|
57
pkg/exchange/okex/query_trades_test.go
Normal file
57
pkg/exchange/okex/query_trades_test.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package okex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/testutil"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_QueryTrades(t *testing.T) {
|
||||
key, secret, passphrase, ok := testutil.IntegrationTestWithPassphraseConfigured(t, "OKEX")
|
||||
if !ok {
|
||||
t.Skip("Please configure all credentials about OKEX")
|
||||
}
|
||||
|
||||
e := New(key, secret, passphrase)
|
||||
|
||||
queryOrder := types.OrderQuery{
|
||||
Symbol: "BTCUSDT",
|
||||
}
|
||||
|
||||
since := time.Now().AddDate(0, -3, 0)
|
||||
until := time.Now()
|
||||
|
||||
queryOption := types.TradeQueryOptions{
|
||||
StartTime: &since,
|
||||
EndTime: &until,
|
||||
Limit: 100,
|
||||
}
|
||||
// query by time interval
|
||||
transactionDetail, err := e.QueryTrades(context.Background(), queryOrder.Symbol, &queryOption)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, transactionDetail)
|
||||
}
|
||||
t.Logf("transaction detail: %+v", transactionDetail)
|
||||
// query by trade id
|
||||
transactionDetail, err = e.QueryTrades(context.Background(), queryOrder.Symbol, &types.TradeQueryOptions{LastTradeID: 432044402})
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, transactionDetail)
|
||||
}
|
||||
t.Logf("transaction detail: %+v", transactionDetail)
|
||||
// query by no time interval and no trade id
|
||||
transactionDetail, err = e.QueryTrades(context.Background(), queryOrder.Symbol, &types.TradeQueryOptions{})
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, transactionDetail)
|
||||
}
|
||||
t.Logf("transaction detail: %+v", transactionDetail)
|
||||
// query by limit exceed default value
|
||||
transactionDetail, err = e.QueryTrades(context.Background(), queryOrder.Symbol, &types.TradeQueryOptions{Limit: 150})
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotEmpty(t, transactionDetail)
|
||||
}
|
||||
t.Logf("transaction detail: %+v", transactionDetail)
|
||||
}
|
|
@ -3,6 +3,7 @@ package testutil
|
|||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -26,6 +27,7 @@ func IntegrationTestConfigured(t *testing.T, prefix string) (key, secret string,
|
|||
|
||||
func IntegrationTestWithPassphraseConfigured(t *testing.T, prefix string) (key, secret, passphrase string, ok bool) {
|
||||
var hasKey, hasSecret, hasPassphrase bool
|
||||
prefix = strings.ToUpper(prefix)
|
||||
key, hasKey = os.LookupEnv(prefix + "_API_KEY")
|
||||
secret, hasSecret = os.LookupEnv(prefix + "_API_SECRET")
|
||||
passphrase, hasPassphrase = os.LookupEnv(prefix + "_API_PASSPHRASE")
|
||||
|
|
Loading…
Reference in New Issue
Block a user