Merge pull request #1250 from bailantaotao/edwin/cancel-order

FEATURE: [bybit] support cancel order
This commit is contained in:
bailantaotao 2023-07-27 11:19:09 +08:00 committed by GitHub
commit 270283d027
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 381 additions and 65 deletions

View File

@ -0,0 +1,35 @@
package bybitapi
import (
"github.com/c9s/requestgen"
)
//go:generate -command GetRequest requestgen -method GET -responseType .APIResponse -responseDataField Result
//go:generate -command PostRequest requestgen -method POST -responseType .APIResponse -responseDataField Result
type CancelOrderResponse struct {
OrderId string `json:"orderId"`
OrderLinkId string `json:"orderLinkId"`
}
//go:generate PostRequest -url "/v5/order/cancel" -type CancelOrderRequest -responseDataType .CancelOrderResponse
type CancelOrderRequest struct {
client requestgen.AuthenticatedAPIClient
category Category `param:"category" validValues:"spot"`
symbol string `param:"symbol"`
// User customised order ID. Either orderId or orderLinkId is required
orderLinkId string `param:"orderLinkId"`
orderId *string `param:"orderLinkId"`
// orderFilter default type is Order
// tpsl order type are not currently supported
orderFilter *string `param:"timeInForce" validValues:"Order"`
}
func (c *RestClient) NewCancelOrderRequest() *CancelOrderRequest {
return &CancelOrderRequest{
client: c,
category: CategorySpot,
}
}

View File

@ -0,0 +1,219 @@
// Code generated by "requestgen -method POST -responseType .APIResponse -responseDataField Result -url /v5/order/cancel -type CancelOrderRequest -responseDataType .CancelOrderResponse"; DO NOT EDIT.
package bybitapi
import (
"context"
"encoding/json"
"fmt"
"net/url"
"reflect"
"regexp"
)
func (p *CancelOrderRequest) Category(category Category) *CancelOrderRequest {
p.category = category
return p
}
func (p *CancelOrderRequest) Symbol(symbol string) *CancelOrderRequest {
p.symbol = symbol
return p
}
func (p *CancelOrderRequest) OrderLinkId(orderLinkId string) *CancelOrderRequest {
p.orderLinkId = orderLinkId
return p
}
func (p *CancelOrderRequest) OrderId(orderId string) *CancelOrderRequest {
p.orderId = &orderId
return p
}
func (p *CancelOrderRequest) OrderFilter(orderFilter string) *CancelOrderRequest {
p.orderFilter = &orderFilter
return p
}
// GetQueryParameters builds and checks the query parameters and returns url.Values
func (p *CancelOrderRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{}
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 (p *CancelOrderRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check category field -> json key category
category := p.category
// TEMPLATE check-valid-values
switch category {
case "spot":
params["category"] = category
default:
return nil, fmt.Errorf("category value %v is invalid", category)
}
// END TEMPLATE check-valid-values
// assign parameter of category
params["category"] = category
// check symbol field -> json key symbol
symbol := p.symbol
// assign parameter of symbol
params["symbol"] = symbol
// check orderLinkId field -> json key orderLinkId
orderLinkId := p.orderLinkId
// assign parameter of orderLinkId
params["orderLinkId"] = orderLinkId
// check orderId field -> json key orderLinkId
if p.orderId != nil {
orderId := *p.orderId
// assign parameter of orderId
params["orderLinkId"] = orderId
} else {
}
// check orderFilter field -> json key timeInForce
if p.orderFilter != nil {
orderFilter := *p.orderFilter
// TEMPLATE check-valid-values
switch orderFilter {
case "Order":
params["timeInForce"] = orderFilter
default:
return nil, fmt.Errorf("timeInForce value %v is invalid", orderFilter)
}
// END TEMPLATE check-valid-values
// assign parameter of orderFilter
params["timeInForce"] = orderFilter
} else {
}
return params, nil
}
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (p *CancelOrderRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{}
params, err := p.GetParameters()
if err != nil {
return query, err
}
for _k, _v := range params {
if p.isVarSlice(_v) {
p.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 (p *CancelOrderRequest) GetParametersJSON() ([]byte, error) {
params, err := p.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 (p *CancelOrderRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil
}
func (p *CancelOrderRequest) 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 (p *CancelOrderRequest) 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 (p *CancelOrderRequest) isVarSlice(_v interface{}) bool {
rt := reflect.TypeOf(_v)
switch rt.Kind() {
case reflect.Slice:
return true
}
return false
}
func (p *CancelOrderRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{}
params, err := p.GetSlugParameters()
if err != nil {
return slugs, nil
}
for _k, _v := range params {
slugs[_k] = fmt.Sprintf("%v", _v)
}
return slugs, nil
}
func (p *CancelOrderRequest) Do(ctx context.Context) (*CancelOrderResponse, error) {
params, err := p.GetParameters()
if err != nil {
return nil, err
}
query := url.Values{}
apiURL := "/v5/order/cancel"
req, err := p.client.NewAuthenticatedRequest(ctx, "POST", apiURL, query, params)
if err != nil {
return nil, err
}
response, err := p.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse APIResponse
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
var data CancelOrderResponse
if err := json.Unmarshal(apiResponse.Result, &data); err != nil {
return nil, err
}
return &data, nil
}

View File

@ -79,7 +79,7 @@ func TestClient(t *testing.T) {
} }
}) })
t.Run("PostPlaceOrderRequest", func(t *testing.T) { t.Run("PlaceOrderRequest", func(t *testing.T) {
req := client.NewPlaceOrderRequest(). req := client.NewPlaceOrderRequest().
Symbol("DOTUSDT"). Symbol("DOTUSDT").
Side(SideBuy). Side(SideBuy).
@ -97,4 +97,36 @@ func TestClient(t *testing.T) {
assert.Equal(t, len(ordersResp.List), 1) assert.Equal(t, len(ordersResp.List), 1)
t.Logf("apiResp: %+v", ordersResp.List[0]) t.Logf("apiResp: %+v", ordersResp.List[0])
}) })
t.Run("CancelOrderRequest", func(t *testing.T) {
req := client.NewPlaceOrderRequest().
Symbol("DOTUSDT").
Side(SideBuy).
OrderType(OrderTypeLimit).
Qty("1").
Price("4.6").
OrderLinkId(uuid.NewString()).
TimeInForce(TimeInForceGTC)
apiResp, err := req.Do(ctx)
assert.NoError(t, err)
t.Logf("apiResp: %+v", apiResp)
ordersResp, err := client.NewGetOpenOrderRequest().OrderLinkId(apiResp.OrderLinkId).Do(ctx)
assert.NoError(t, err)
assert.Equal(t, len(ordersResp.List), 1)
t.Logf("apiResp: %+v", ordersResp.List[0])
cancelReq := client.NewCancelOrderRequest().
Symbol("DOTUSDT").
OrderLinkId(apiResp.OrderLinkId)
cancelResp, err := cancelReq.Do(ctx)
assert.NoError(t, err)
t.Logf("apiResp: %+v", cancelResp)
ordersResp, err = client.NewGetOpenOrderRequest().OrderLinkId(apiResp.OrderLinkId).Do(ctx)
assert.NoError(t, err)
assert.Equal(t, len(ordersResp.List), 1)
assert.Equal(t, ordersResp.List[0].OrderStatus, OrderStatusCancelled)
t.Logf("apiResp: %+v", ordersResp.List[0])
})
} }

View File

@ -12,8 +12,8 @@ type PlaceOrderResponse struct {
OrderLinkId string `json:"orderLinkId"` OrderLinkId string `json:"orderLinkId"`
} }
//go:generate PostRequest -url "/v5/order/create" -type PostPlaceOrderRequest -responseDataType .PlaceOrderResponse //go:generate PostRequest -url "/v5/order/create" -type PlaceOrderRequest -responseDataType .PlaceOrderResponse
type PostPlaceOrderRequest struct { type PlaceOrderRequest struct {
client requestgen.AuthenticatedAPIClient client requestgen.AuthenticatedAPIClient
category Category `param:"category" validValues:"spot"` category Category `param:"category" validValues:"spot"`
@ -49,8 +49,8 @@ type PostPlaceOrderRequest struct {
slOrderType *string `param:"slOrderType"` slOrderType *string `param:"slOrderType"`
} }
func (c *RestClient) NewPlaceOrderRequest() *PostPlaceOrderRequest { func (c *RestClient) NewPlaceOrderRequest() *PlaceOrderRequest {
return &PostPlaceOrderRequest{ return &PlaceOrderRequest{
client: c, client: c,
category: CategorySpot, category: CategorySpot,
} }

View File

@ -1,4 +1,4 @@
// Code generated by "requestgen -method POST -responseType .APIResponse -responseDataField Result -url /v5/order/create -type PostPlaceOrderRequest -responseDataType .PlaceOrderResponse"; DO NOT EDIT. // Code generated by "requestgen -method POST -responseType .APIResponse -responseDataField Result -url /v5/order/create -type PlaceOrderRequest -responseDataType .PlaceOrderResponse"; DO NOT EDIT.
package bybitapi package bybitapi
@ -11,148 +11,148 @@ import (
"regexp" "regexp"
) )
func (p *PostPlaceOrderRequest) Category(category Category) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) Category(category Category) *PlaceOrderRequest {
p.category = category p.category = category
return p return p
} }
func (p *PostPlaceOrderRequest) Symbol(symbol string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) Symbol(symbol string) *PlaceOrderRequest {
p.symbol = symbol p.symbol = symbol
return p return p
} }
func (p *PostPlaceOrderRequest) Side(side Side) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) Side(side Side) *PlaceOrderRequest {
p.side = side p.side = side
return p return p
} }
func (p *PostPlaceOrderRequest) OrderType(orderType OrderType) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) OrderType(orderType OrderType) *PlaceOrderRequest {
p.orderType = orderType p.orderType = orderType
return p return p
} }
func (p *PostPlaceOrderRequest) Qty(qty string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) Qty(qty string) *PlaceOrderRequest {
p.qty = qty p.qty = qty
return p return p
} }
func (p *PostPlaceOrderRequest) OrderLinkId(orderLinkId string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) OrderLinkId(orderLinkId string) *PlaceOrderRequest {
p.orderLinkId = orderLinkId p.orderLinkId = orderLinkId
return p return p
} }
func (p *PostPlaceOrderRequest) TimeInForce(timeInForce TimeInForce) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TimeInForce(timeInForce TimeInForce) *PlaceOrderRequest {
p.timeInForce = timeInForce p.timeInForce = timeInForce
return p return p
} }
func (p *PostPlaceOrderRequest) IsLeverage(isLeverage bool) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) IsLeverage(isLeverage bool) *PlaceOrderRequest {
p.isLeverage = &isLeverage p.isLeverage = &isLeverage
return p return p
} }
func (p *PostPlaceOrderRequest) Price(price string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) Price(price string) *PlaceOrderRequest {
p.price = &price p.price = &price
return p return p
} }
func (p *PostPlaceOrderRequest) TriggerDirection(triggerDirection int) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TriggerDirection(triggerDirection int) *PlaceOrderRequest {
p.triggerDirection = &triggerDirection p.triggerDirection = &triggerDirection
return p return p
} }
func (p *PostPlaceOrderRequest) OrderFilter(orderFilter string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) OrderFilter(orderFilter string) *PlaceOrderRequest {
p.orderFilter = &orderFilter p.orderFilter = &orderFilter
return p return p
} }
func (p *PostPlaceOrderRequest) TriggerPrice(triggerPrice string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TriggerPrice(triggerPrice string) *PlaceOrderRequest {
p.triggerPrice = &triggerPrice p.triggerPrice = &triggerPrice
return p return p
} }
func (p *PostPlaceOrderRequest) TriggerBy(triggerBy string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TriggerBy(triggerBy string) *PlaceOrderRequest {
p.triggerBy = &triggerBy p.triggerBy = &triggerBy
return p return p
} }
func (p *PostPlaceOrderRequest) OrderIv(orderIv string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) OrderIv(orderIv string) *PlaceOrderRequest {
p.orderIv = &orderIv p.orderIv = &orderIv
return p return p
} }
func (p *PostPlaceOrderRequest) PositionIdx(positionIdx string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) PositionIdx(positionIdx string) *PlaceOrderRequest {
p.positionIdx = &positionIdx p.positionIdx = &positionIdx
return p return p
} }
func (p *PostPlaceOrderRequest) TakeProfit(takeProfit string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TakeProfit(takeProfit string) *PlaceOrderRequest {
p.takeProfit = &takeProfit p.takeProfit = &takeProfit
return p return p
} }
func (p *PostPlaceOrderRequest) StopLoss(stopLoss string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) StopLoss(stopLoss string) *PlaceOrderRequest {
p.stopLoss = &stopLoss p.stopLoss = &stopLoss
return p return p
} }
func (p *PostPlaceOrderRequest) TpTriggerBy(tpTriggerBy string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TpTriggerBy(tpTriggerBy string) *PlaceOrderRequest {
p.tpTriggerBy = &tpTriggerBy p.tpTriggerBy = &tpTriggerBy
return p return p
} }
func (p *PostPlaceOrderRequest) SlTriggerBy(slTriggerBy string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) SlTriggerBy(slTriggerBy string) *PlaceOrderRequest {
p.slTriggerBy = &slTriggerBy p.slTriggerBy = &slTriggerBy
return p return p
} }
func (p *PostPlaceOrderRequest) ReduceOnly(reduceOnly bool) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) ReduceOnly(reduceOnly bool) *PlaceOrderRequest {
p.reduceOnly = &reduceOnly p.reduceOnly = &reduceOnly
return p return p
} }
func (p *PostPlaceOrderRequest) CloseOnTrigger(closeOnTrigger bool) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) CloseOnTrigger(closeOnTrigger bool) *PlaceOrderRequest {
p.closeOnTrigger = &closeOnTrigger p.closeOnTrigger = &closeOnTrigger
return p return p
} }
func (p *PostPlaceOrderRequest) SmpType(smpType string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) SmpType(smpType string) *PlaceOrderRequest {
p.smpType = &smpType p.smpType = &smpType
return p return p
} }
func (p *PostPlaceOrderRequest) Mmp(mmp bool) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) Mmp(mmp bool) *PlaceOrderRequest {
p.mmp = &mmp p.mmp = &mmp
return p return p
} }
func (p *PostPlaceOrderRequest) TpslMode(tpslMode string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TpslMode(tpslMode string) *PlaceOrderRequest {
p.tpslMode = &tpslMode p.tpslMode = &tpslMode
return p return p
} }
func (p *PostPlaceOrderRequest) TpLimitPrice(tpLimitPrice string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TpLimitPrice(tpLimitPrice string) *PlaceOrderRequest {
p.tpLimitPrice = &tpLimitPrice p.tpLimitPrice = &tpLimitPrice
return p return p
} }
func (p *PostPlaceOrderRequest) SlLimitPrice(slLimitPrice string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) SlLimitPrice(slLimitPrice string) *PlaceOrderRequest {
p.slLimitPrice = &slLimitPrice p.slLimitPrice = &slLimitPrice
return p return p
} }
func (p *PostPlaceOrderRequest) TpOrderType(tpOrderType string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) TpOrderType(tpOrderType string) *PlaceOrderRequest {
p.tpOrderType = &tpOrderType p.tpOrderType = &tpOrderType
return p return p
} }
func (p *PostPlaceOrderRequest) SlOrderType(slOrderType string) *PostPlaceOrderRequest { func (p *PlaceOrderRequest) SlOrderType(slOrderType string) *PlaceOrderRequest {
p.slOrderType = &slOrderType p.slOrderType = &slOrderType
return p return p
} }
// GetQueryParameters builds and checks the query parameters and returns url.Values // GetQueryParameters builds and checks the query parameters and returns url.Values
func (p *PostPlaceOrderRequest) GetQueryParameters() (url.Values, error) { func (p *PlaceOrderRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{} var params = map[string]interface{}{}
query := url.Values{} query := url.Values{}
@ -164,7 +164,7 @@ func (p *PostPlaceOrderRequest) GetQueryParameters() (url.Values, error) {
} }
// GetParameters builds and checks the parameters and return the result in a map object // GetParameters builds and checks the parameters and return the result in a map object
func (p *PostPlaceOrderRequest) GetParameters() (map[string]interface{}, error) { func (p *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{} var params = map[string]interface{}{}
// check category field -> json key category // check category field -> json key category
category := p.category category := p.category
@ -418,7 +418,7 @@ func (p *PostPlaceOrderRequest) GetParameters() (map[string]interface{}, error)
} }
// GetParametersQuery converts the parameters from GetParameters into the url.Values format // GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (p *PostPlaceOrderRequest) GetParametersQuery() (url.Values, error) { func (p *PlaceOrderRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{} query := url.Values{}
params, err := p.GetParameters() params, err := p.GetParameters()
@ -440,7 +440,7 @@ func (p *PostPlaceOrderRequest) GetParametersQuery() (url.Values, error) {
} }
// GetParametersJSON converts the parameters from GetParameters into the JSON format // GetParametersJSON converts the parameters from GetParameters into the JSON format
func (p *PostPlaceOrderRequest) GetParametersJSON() ([]byte, error) { func (p *PlaceOrderRequest) GetParametersJSON() ([]byte, error) {
params, err := p.GetParameters() params, err := p.GetParameters()
if err != nil { if err != nil {
return nil, err return nil, err
@ -450,13 +450,13 @@ func (p *PostPlaceOrderRequest) GetParametersJSON() ([]byte, error) {
} }
// GetSlugParameters builds and checks the slug parameters and return the result in a map object // GetSlugParameters builds and checks the slug parameters and return the result in a map object
func (p *PostPlaceOrderRequest) GetSlugParameters() (map[string]interface{}, error) { func (p *PlaceOrderRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{} var params = map[string]interface{}{}
return params, nil return params, nil
} }
func (p *PostPlaceOrderRequest) applySlugsToUrl(url string, slugs map[string]string) string { func (p *PlaceOrderRequest) applySlugsToUrl(url string, slugs map[string]string) string {
for _k, _v := range slugs { for _k, _v := range slugs {
needleRE := regexp.MustCompile(":" + _k + "\\b") needleRE := regexp.MustCompile(":" + _k + "\\b")
url = needleRE.ReplaceAllString(url, _v) url = needleRE.ReplaceAllString(url, _v)
@ -465,7 +465,7 @@ func (p *PostPlaceOrderRequest) applySlugsToUrl(url string, slugs map[string]str
return url return url
} }
func (p *PostPlaceOrderRequest) iterateSlice(slice interface{}, _f func(it interface{})) { func (p *PlaceOrderRequest) iterateSlice(slice interface{}, _f func(it interface{})) {
sliceValue := reflect.ValueOf(slice) sliceValue := reflect.ValueOf(slice)
for _i := 0; _i < sliceValue.Len(); _i++ { for _i := 0; _i < sliceValue.Len(); _i++ {
it := sliceValue.Index(_i).Interface() it := sliceValue.Index(_i).Interface()
@ -473,7 +473,7 @@ func (p *PostPlaceOrderRequest) iterateSlice(slice interface{}, _f func(it inter
} }
} }
func (p *PostPlaceOrderRequest) isVarSlice(_v interface{}) bool { func (p *PlaceOrderRequest) isVarSlice(_v interface{}) bool {
rt := reflect.TypeOf(_v) rt := reflect.TypeOf(_v)
switch rt.Kind() { switch rt.Kind() {
case reflect.Slice: case reflect.Slice:
@ -482,7 +482,7 @@ func (p *PostPlaceOrderRequest) isVarSlice(_v interface{}) bool {
return false return false
} }
func (p *PostPlaceOrderRequest) GetSlugsMap() (map[string]string, error) { func (p *PlaceOrderRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{} slugs := map[string]string{}
params, err := p.GetSlugParameters() params, err := p.GetSlugParameters()
if err != nil { if err != nil {
@ -496,7 +496,7 @@ func (p *PostPlaceOrderRequest) GetSlugsMap() (map[string]string, error) {
return slugs, nil return slugs, nil
} }
func (p *PostPlaceOrderRequest) Do(ctx context.Context) (*PlaceOrderResponse, error) { func (p *PlaceOrderRequest) Do(ctx context.Context) (*PlaceOrderResponse, error) {
params, err := p.GetParameters() params, err := p.GetParameters()
if err != nil { if err != nil {

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"go.uber.org/multierr"
"golang.org/x/time/rate" "golang.org/x/time/rate"
"github.com/c9s/bbgo/pkg/exchange/bybit/bybitapi" "github.com/c9s/bbgo/pkg/exchange/bybit/bybitapi"
@ -66,14 +67,12 @@ func (e *Exchange) PlatformFeeCurrency() string {
func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) { func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
if err := sharedRateLimiter.Wait(ctx); err != nil { if err := sharedRateLimiter.Wait(ctx); err != nil {
log.WithError(err).Errorf("markets rate limiter wait error") return nil, fmt.Errorf("markets rate limiter wait error: %v", err)
return nil, err
} }
instruments, err := e.client.NewGetInstrumentsInfoRequest().Do(ctx) instruments, err := e.client.NewGetInstrumentsInfoRequest().Do(ctx)
if err != nil { if err != nil {
log.Warnf("failed to query instruments, err: %v", err) return nil, fmt.Errorf("failed to get instruments, err: %v", err)
return nil, err
} }
marketMap := types.MarketMap{} marketMap := types.MarketMap{}
@ -86,18 +85,15 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
func (e *Exchange) QueryTicker(ctx context.Context, symbol string) (*types.Ticker, error) { func (e *Exchange) QueryTicker(ctx context.Context, symbol string) (*types.Ticker, error) {
if err := sharedRateLimiter.Wait(ctx); err != nil { if err := sharedRateLimiter.Wait(ctx); err != nil {
log.WithError(err).Errorf("ticker rate limiter wait error") return nil, fmt.Errorf("ticker order rate limiter wait error: %v", err)
return nil, err
} }
s, err := e.client.NewGetTickersRequest().Symbol(symbol).DoWithResponseTime(ctx) s, err := e.client.NewGetTickersRequest().Symbol(symbol).DoWithResponseTime(ctx)
if err != nil { if err != nil {
log.Warnf("failed to get tickers, symbol: %s, err: %v", symbol, err)
return nil, err return nil, err
} }
if len(s.List) != 1 { if len(s.List) != 1 {
log.Warnf("unexpected ticker length, exp: 1, got: %d", len(s.List))
return nil, fmt.Errorf("unexpected ticker lenght, exp:1, got:%d", len(s.List)) return nil, fmt.Errorf("unexpected ticker lenght, exp:1, got:%d", len(s.List))
} }
@ -121,12 +117,10 @@ func (e *Exchange) QueryTickers(ctx context.Context, symbols ...string) (map[str
} }
if err := sharedRateLimiter.Wait(ctx); err != nil { if err := sharedRateLimiter.Wait(ctx); err != nil {
log.WithError(err).Errorf("ticker rate limiter wait error") return nil, fmt.Errorf("tickers rate limiter wait error: %v", err)
return nil, err
} }
allTickers, err := e.client.NewGetTickersRequest().DoWithResponseTime(ctx) allTickers, err := e.client.NewGetTickersRequest().DoWithResponseTime(ctx)
if err != nil { if err != nil {
log.Warnf("failed to get tickers, err: %v", err)
return nil, err return nil, err
} }
@ -147,20 +141,17 @@ func (e *Exchange) QueryOpenOrders(ctx context.Context, symbol string) (orders [
} }
if err = tradeRateLimiter.Wait(ctx); err != nil { if err = tradeRateLimiter.Wait(ctx); err != nil {
log.WithError(err).Errorf("trade rate limiter wait error") return nil, fmt.Errorf("place order rate limiter wait error: %v", err)
return nil, err
} }
res, err := req.Do(ctx) res, err := req.Do(ctx)
if err != nil { if err != nil {
log.Warnf("failed to get open order, cursor: %s, err: %v", cursor, err) return nil, fmt.Errorf("failed to query open orders, err: %v", err)
return nil, err
} }
for _, order := range res.List { for _, order := range res.List {
order, err := toGlobalOrder(order) order, err := toGlobalOrder(order)
if err != nil { if err != nil {
log.Warnf("failed to convert order, err: %v", err) return nil, fmt.Errorf("failed to convert order, err: %v", err)
return nil, err
} }
orders = append(orders, *order) orders = append(orders, *order)
@ -223,13 +214,11 @@ func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (*t
req.OrderLinkId(order.ClientOrderID) req.OrderLinkId(order.ClientOrderID)
if err := orderRateLimiter.Wait(ctx); err != nil { if err := orderRateLimiter.Wait(ctx); err != nil {
log.WithError(err).Errorf("place order rate limiter wait error") return nil, fmt.Errorf("place order rate limiter wait error: %v", err)
return nil, err
} }
res, err := req.Do(ctx) res, err := req.Do(ctx)
if err != nil { if err != nil {
log.Warnf("failed to place order, order: %#v, err: %v", order, err) return nil, fmt.Errorf("failed to place order, order: %#v, err: %v", order, err)
return nil, err
} }
if len(res.OrderId) == 0 || res.OrderLinkId != order.ClientOrderID { if len(res.OrderId) == 0 || res.OrderLinkId != order.ClientOrderID {
@ -247,3 +236,44 @@ func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (*t
return toGlobalOrder(ordersResp.List[0]) return toGlobalOrder(ordersResp.List[0])
} }
func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) (errs error) {
if len(orders) == 0 {
return nil
}
for _, order := range orders {
req := e.client.NewCancelOrderRequest()
switch {
case len(order.ClientOrderID) != 0:
req.OrderLinkId(order.ClientOrderID)
case len(order.UUID) != 0 && order.OrderID != 0:
req.OrderId(order.UUID)
default:
errs = multierr.Append(
errs,
fmt.Errorf("the order uuid and client order id are empty, order: %#v", order),
)
continue
}
req.Symbol(order.Market.Symbol)
if err := orderRateLimiter.Wait(ctx); err != nil {
errs = multierr.Append(errs, fmt.Errorf("cancel order rate limiter wait, order id: %s, error: %v", order.ClientOrderID, err))
continue
}
res, err := req.Do(ctx)
if err != nil {
errs = multierr.Append(errs, fmt.Errorf("failed to cancel order id: %s, err: %v", order.ClientOrderID, err))
continue
}
if res.OrderId != order.UUID || res.OrderLinkId != order.ClientOrderID {
errs = multierr.Append(errs, fmt.Errorf("unexpected order id, resp: %#v, order: %#v", res, order))
continue
}
}
return errs
}