Merge pull request #414 from c9s/c9s/kucoin-get-history-orders

feature: add kucoin history orders api
This commit is contained in:
Yo-An Lin 2022-01-01 01:32:24 +08:00 committed by GitHub
commit 4e875a4b3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 372 additions and 124 deletions

View File

@ -4,31 +4,11 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# if you want to route channel by exchange session
sessionChannels:
max: "bbgo-max"
binance: "bbgo-binance"
# routing rules
routing:
trade: "$symbol"
trade: "$silent"
order: "$silent"
submitOrder: "$silent"
pnL: "bbgo-pnl"
reportPnL:
- averageCostBySymbols:
- "BTCUSDT"
- "BNBUSDT"
of: binance
when:
- "@daily"
- "@hourly"
persistence:
json:
@ -59,10 +39,11 @@ crossExchangeStrategies:
# disableHedge: true
hedgeInterval: 10s
notifyTrade: true
margin: 0.004
askMargin: 0.004
bidMargin: 0.004
askMargin: 0.4%
bidMargin: 0.4%
quantity: 0.001
quantityMultiplier: 2

View File

@ -14,5 +14,9 @@ go run ./examples/kucoin orders --symbol LTC-USDT --status active
go run ./examples/kucoin orders --symbol LTC-USDT --status done
go run ./examples/kucoin orders cancel --order-id 61b48b73b4de3e0001251382
# list history orders
go run ./examples/kucoin orders history --symbol BTC-USDT
go run ./examples/kucoin fills --symbol LTC-USDT
```

View File

@ -2,6 +2,7 @@ package main
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -26,6 +27,9 @@ func init() {
placeOrderCmd.Flags().String("order-type", string(kucoinapi.OrderTypeLimit), "order type")
placeOrderCmd.Flags().String("side", "", "buy or sell")
ordersCmd.AddCommand(placeOrderCmd)
historyOrdersCmd.Flags().String("symbol", "", "symbol, BTC-USDT, LTC-USDT...etc")
ordersCmd.AddCommand(historyOrdersCmd)
}
@ -37,7 +41,6 @@ var ordersCmd = &cobra.Command{
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
req := client.TradeService.NewListOrdersRequest()
symbol, err := cmd.Flags().GetString("symbol")
if err != nil {
@ -48,14 +51,14 @@ var ordersCmd = &cobra.Command{
return errors.New("--symbol option is required")
}
req.Symbol(symbol)
status, err := cmd.Flags().GetString("status")
if err != nil {
return err
}
req := client.TradeService.NewListOrdersRequest()
req.Symbol(symbol)
if len(status) > 0 {
req.Status(status)
}
@ -71,6 +74,38 @@ var ordersCmd = &cobra.Command{
}
// go run ./examples/kucoin orders history
var historyOrdersCmd = &cobra.Command{
Use: "history [--symbol SYMBOL]",
// SilenceUsage is an option to silence usage when an error occurs.
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
symbol, err := cmd.Flags().GetString("symbol")
if err != nil {
return err
}
if len(symbol) == 0 {
return errors.New("--symbol option is required")
}
req := client.TradeService.NewListHistoryOrdersRequest()
req.Symbol(symbol)
req.StartAt(time.Now().AddDate(0, -2, 0))
page, err := req.Do(context.Background())
if err != nil {
return err
}
logrus.Infof("page: %+v", page)
return nil
},
}
// usage:
// go run ./examples/kucoin orders place --symbol LTC-USDT --price 50 --size 1 --order-type limit --side buy
var placeOrderCmd = &cobra.Command{

View File

@ -295,15 +295,24 @@ func (e *Exchange) QueryClosedOrders(ctx context.Context, symbol string, since,
req := e.client.TradeService.NewListOrdersRequest()
req.Symbol(toLocalSymbol(symbol))
req.Status("done")
req.EndAt(until)
req.StartAt(since)
// kucoin:
// When you query orders in active status, there is no time limit.
// However, when you query orders in done status, the start and end time range cannot exceed 7* 24 hours.
// An error will occur if the specified time window exceeds the range.
// If you specify the end time only, the system will automatically calculate the start time as end time minus 7*24 hours, and vice versa.
if until.Sub(since) < 7 * 24 * time.Hour {
req.EndAt(until)
} else {
req.EndAt(since.Add(7 * 24 * time.Hour - time.Minute))
}
orderList, err := req.Do(ctx)
if err != nil {
return orders, err
}
// TODO: support pagination (right now we can only get 50 items from the first page)
for _, o := range orderList.Items {
order := toGlobalOrder(o)
orders = append(orders, order)

View File

@ -41,6 +41,7 @@ func (r *CancelAllOrderRequest) GetParameters() (map[string]interface{}, error)
// assign parameter of symbol
params["symbol"] = symbol
}
// check tradeType field -> json key tradeType
if r.tradeType != nil {
@ -48,6 +49,7 @@ func (r *CancelAllOrderRequest) GetParameters() (map[string]interface{}, error)
// assign parameter of tradeType
params["tradeType"] = tradeType
}
return params, nil

View File

@ -40,6 +40,7 @@ func (r *CancelOrderRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of orderID
params["orderID"] = orderID
}
// check clientOrderID field -> json key clientOrderID
if r.clientOrderID != nil {
@ -47,6 +48,7 @@ func (r *CancelOrderRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of clientOrderID
params["clientOrderID"] = clientOrderID
}
return params, nil

View File

@ -1,8 +1,9 @@
// Code generated by "requestgen -type GetFillsRequest"; DO NOT EDIT.
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v1/fills -type GetFillsRequest -responseDataType .FillListPage"; DO NOT EDIT.
package kucoinapi
import (
"context"
"encoding/json"
"fmt"
"net/url"
@ -16,6 +17,11 @@ func (r *GetFillsRequest) OrderID(orderID string) *GetFillsRequest {
return r
}
func (r *GetFillsRequest) TradeType(tradeType string) *GetFillsRequest {
r.tradeType = &tradeType
return r
}
func (r *GetFillsRequest) Symbol(symbol string) *GetFillsRequest {
r.symbol = &symbol
return r
@ -62,6 +68,15 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of orderID
params["orderId"] = orderID
}
// check tradeType field -> json key tradeType
if r.tradeType != nil {
tradeType := *r.tradeType
// assign parameter of tradeType
params["tradeType"] = tradeType
}
// check symbol field -> json key symbol
if r.symbol != nil {
@ -69,11 +84,13 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of symbol
params["symbol"] = symbol
}
// check side field -> json key side
if r.side != nil {
side := *r.side
// TEMPLATE check-valid-values
switch side {
case "buy", "sell":
params["side"] = side
@ -82,14 +99,17 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
return params, fmt.Errorf("side value %v is invalid", side)
}
// END TEMPLATE check-valid-values
// assign parameter of side
params["side"] = side
}
// check orderType field -> json key type
if r.orderType != nil {
orderType := *r.orderType
// TEMPLATE check-valid-values
switch orderType {
case "limit", "market", "limit_stop", "market_stop":
params["type"] = orderType
@ -98,9 +118,11 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
return params, fmt.Errorf("type value %v is invalid", orderType)
}
// END TEMPLATE check-valid-values
// assign parameter of orderType
params["type"] = orderType
}
// check startAt field -> json key startAt
if r.startAt != nil {
@ -109,6 +131,7 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of startAt
// convert time.Time to milliseconds time stamp
params["startAt"] = strconv.FormatInt(startAt.UnixNano()/int64(time.Millisecond), 10)
}
// check endAt field -> json key endAt
if r.endAt != nil {
@ -117,6 +140,7 @@ func (r *GetFillsRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of endAt
// convert time.Time to milliseconds time stamp
params["endAt"] = strconv.FormatInt(endAt.UnixNano()/int64(time.Millisecond), 10)
}
return params, nil
@ -177,3 +201,32 @@ func (r *GetFillsRequest) GetSlugsMap() (map[string]string, error) {
return slugs, nil
}
func (r *GetFillsRequest) Do(ctx context.Context) (*FillListPage, error) {
// empty params for GET operation
var params interface{}
query := url.Values{}
apiURL := "/api/v1/fills"
req, err := r.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
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 FillListPage
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
return nil, err
}
return &data, nil
}

View File

@ -0,0 +1,158 @@
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v1/hist-orders -type ListHistoryOrdersRequest -responseDataType .HistoryOrderListPage"; DO NOT EDIT.
package kucoinapi
import (
"context"
"encoding/json"
"fmt"
"net/url"
"regexp"
"strconv"
"time"
)
func (l *ListHistoryOrdersRequest) Symbol(symbol string) *ListHistoryOrdersRequest {
l.symbol = &symbol
return l
}
func (l *ListHistoryOrdersRequest) StartAt(startAt time.Time) *ListHistoryOrdersRequest {
l.startAt = &startAt
return l
}
func (l *ListHistoryOrdersRequest) EndAt(endAt time.Time) *ListHistoryOrdersRequest {
l.endAt = &endAt
return l
}
// GetQueryParameters builds and checks the query parameters and returns url.Values
func (l *ListHistoryOrdersRequest) 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 (l *ListHistoryOrdersRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check symbol field -> json key symbol
if l.symbol != nil {
symbol := *l.symbol
// assign parameter of symbol
params["symbol"] = symbol
}
// check startAt field -> json key startAt
if l.startAt != nil {
startAt := *l.startAt
// assign parameter of startAt
// convert time.Time to milliseconds time stamp
params["startAt"] = strconv.FormatInt(startAt.UnixNano()/int64(time.Millisecond), 10)
}
// check endAt field -> json key endAt
if l.endAt != nil {
endAt := *l.endAt
// assign parameter of endAt
// convert time.Time to milliseconds time stamp
params["endAt"] = strconv.FormatInt(endAt.UnixNano()/int64(time.Millisecond), 10)
}
return params, nil
}
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (l *ListHistoryOrdersRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{}
params, err := l.GetParameters()
if err != nil {
return query, err
}
for k, v := range params {
query.Add(k, fmt.Sprintf("%v", v))
}
return query, nil
}
// GetParametersJSON converts the parameters from GetParameters into the JSON format
func (l *ListHistoryOrdersRequest) GetParametersJSON() ([]byte, error) {
params, err := l.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 (l *ListHistoryOrdersRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil
}
func (l *ListHistoryOrdersRequest) 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 (l *ListHistoryOrdersRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{}
params, err := l.GetSlugParameters()
if err != nil {
return slugs, nil
}
for k, v := range params {
slugs[k] = fmt.Sprintf("%v", v)
}
return slugs, nil
}
func (l *ListHistoryOrdersRequest) Do(ctx context.Context) (*HistoryOrderListPage, error) {
// empty params for GET operation
var params interface{}
query := url.Values{}
apiURL := "/api/v1/hist-orders"
req, err := l.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
if err != nil {
return nil, err
}
response, err := l.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse APIResponse
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
var data HistoryOrderListPage
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
return nil, err
}
return &data, nil
}

View File

@ -1,8 +1,9 @@
// Code generated by "requestgen -type ListOrdersRequest"; DO NOT EDIT.
// Code generated by "requestgen -method GET -responseType .APIResponse -responseDataField Data -url /api/v1/orders -type ListOrdersRequest -responseDataType .OrderListPage"; DO NOT EDIT.
package kucoinapi
import (
"context"
"encoding/json"
"fmt"
"net/url"
@ -65,6 +66,7 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
if r.status != nil {
status := *r.status
// TEMPLATE check-valid-values
switch status {
case "active", "done":
params["status"] = status
@ -73,9 +75,11 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
return params, fmt.Errorf("status value %v is invalid", status)
}
// END TEMPLATE check-valid-values
// assign parameter of status
params["status"] = status
}
// check symbol field -> json key symbol
if r.symbol != nil {
@ -83,11 +87,13 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of symbol
params["symbol"] = symbol
}
// check side field -> json key side
if r.side != nil {
side := *r.side
// TEMPLATE check-valid-values
switch side {
case "buy", "sell":
params["side"] = side
@ -96,9 +102,11 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
return params, fmt.Errorf("side value %v is invalid", side)
}
// END TEMPLATE check-valid-values
// assign parameter of side
params["side"] = side
}
// check orderType field -> json key type
if r.orderType != nil {
@ -106,6 +114,7 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of orderType
params["type"] = orderType
}
// check tradeType field -> json key tradeType
if r.tradeType != nil {
@ -113,6 +122,7 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of tradeType
params["tradeType"] = tradeType
}
// check startAt field -> json key startAt
if r.startAt != nil {
@ -121,6 +131,7 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of startAt
// convert time.Time to milliseconds time stamp
params["startAt"] = strconv.FormatInt(startAt.UnixNano()/int64(time.Millisecond), 10)
}
// check endAt field -> json key endAt
if r.endAt != nil {
@ -129,6 +140,7 @@ func (r *ListOrdersRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of endAt
// convert time.Time to milliseconds time stamp
params["endAt"] = strconv.FormatInt(endAt.UnixNano()/int64(time.Millisecond), 10)
}
return params, nil
@ -189,3 +201,32 @@ func (r *ListOrdersRequest) GetSlugsMap() (map[string]string, error) {
return slugs, nil
}
func (r *ListOrdersRequest) Do(ctx context.Context) (*OrderListPage, error) {
// empty params for GET operation
var params interface{}
query := url.Values{}
apiURL := "/api/v1/orders"
req, err := r.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
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 OrderListPage
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
return nil, err
}
return &data, nil
}

View File

@ -70,17 +70,19 @@ func (r *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
if r.clientOrderID != nil {
clientOrderID := *r.clientOrderID
// TEMPLATE check-required
if len(clientOrderID) == 0 {
return params, fmt.Errorf("clientOid is required, empty string given")
}
// END TEMPLATE check-required
// assign parameter of clientOrderID
params["clientOid"] = clientOrderID
} else {
// assign default of clientOrderID
clientOrderID := uuid.New().String()
// assign parameter of clientOrderID
params["clientOid"] = clientOrderID
@ -88,9 +90,11 @@ func (r *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
// check symbol field -> json key symbol
symbol := r.symbol
// TEMPLATE check-required
if len(symbol) == 0 {
return params, fmt.Errorf("symbol is required, empty string given")
}
// END TEMPLATE check-required
// assign parameter of symbol
params["symbol"] = symbol
@ -100,6 +104,7 @@ func (r *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of tag
params["tag"] = tag
}
// check side field -> json key side
side := r.side
@ -114,9 +119,11 @@ func (r *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
// check size field -> json key size
size := r.size
// TEMPLATE check-required
if len(size) == 0 {
return params, fmt.Errorf("size is required, empty string given")
}
// END TEMPLATE check-required
// assign parameter of size
params["size"] = size
@ -126,17 +133,21 @@ func (r *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
// assign parameter of price
params["price"] = price
}
// check timeInForce field -> json key timeInForce
if r.timeInForce != nil {
timeInForce := *r.timeInForce
// TEMPLATE check-required
if len(timeInForce) == 0 {
return params, fmt.Errorf("timeInForce is required, empty string given")
}
// END TEMPLATE check-required
// assign parameter of timeInForce
params["timeInForce"] = timeInForce
}
return params, nil

View File

@ -10,7 +10,6 @@ import (
"github.com/c9s/requestgen"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
@ -24,41 +23,38 @@ type OrderResponse struct {
OrderID string `json:"orderId"`
}
func (c *TradeService) NewListHistoryOrdersRequest() *ListHistoryOrdersRequest {
return &ListHistoryOrdersRequest{client: c.client}
}
func (c *TradeService) NewPlaceOrderRequest() *PlaceOrderRequest {
return &PlaceOrderRequest{
client: c.client,
}
return &PlaceOrderRequest{client: c.client}
}
func (c *TradeService) NewBatchPlaceOrderRequest() *BatchPlaceOrderRequest {
return &BatchPlaceOrderRequest{
client: c.client,
}
return &BatchPlaceOrderRequest{client: c.client}
}
func (c *TradeService) NewCancelOrderRequest() *CancelOrderRequest {
return &CancelOrderRequest{
client: c.client,
}
return &CancelOrderRequest{client: c.client}
}
func (c *TradeService) NewCancelAllOrderRequest() *CancelAllOrderRequest {
return &CancelAllOrderRequest{
client: c.client,
}
return &CancelAllOrderRequest{client: c.client}
}
func (c *TradeService) NewGetFillsRequest() *GetFillsRequest {
return &GetFillsRequest{client: c.client}
}
//go:generate requestgen -type GetFillsRequest
//go:generate GetRequest -url /api/v1/fills -type GetFillsRequest -responseDataType .FillListPage
type GetFillsRequest struct {
client *RestClient
client requestgen.AuthenticatedAPIClient
orderID *string `param:"orderId"`
// tradeType *string `param:"tradeType" default:"TRADE"`
tradeType *string `param:"tradeType" default:"TRADE"`
symbol *string `param:"symbol"`
@ -99,48 +95,38 @@ type Fill struct {
TradeType TradeType `json:"tradeType"`
}
func (r *GetFillsRequest) Do(ctx context.Context) (*FillListPage, error) {
params, err := r.GetParametersQuery()
if err != nil {
return nil, err
}
//go:generate GetRequest -url /api/v1/hist-orders -type ListHistoryOrdersRequest -responseDataType .HistoryOrderListPage
type ListHistoryOrdersRequest struct {
client requestgen.AuthenticatedAPIClient
if _, ok := params["tradeType"]; !ok {
params.Add("tradeType", "TRADE")
}
symbol *string `param:"symbol"`
logrus.Infof("get fills: %+v", params)
startAt *time.Time `param:"startAt,milliseconds"`
req, err := r.client.NewAuthenticatedRequest(ctx, "GET", "/api/v1/fills", params, nil)
if err != nil {
return nil, err
}
response, err := r.client.SendRequest(req)
if err != nil {
return nil, err
}
var orderResponse struct {
Code string `json:"code"`
Message string `json:"msg"`
Data *FillListPage `json:"data"`
}
if err := response.DecodeJSON(&orderResponse); err != nil {
return nil, err
}
if orderResponse.Data == nil {
return nil, errors.New("api error: [" + orderResponse.Code + "] " + orderResponse.Message)
}
return orderResponse.Data, nil
endAt *time.Time `param:"endAt,milliseconds"`
}
//go:generate requestgen -type ListOrdersRequest
type HistoryOrder struct {
Symbol string `json:"symbol"`
DealPrice string `json:"dealPrice"`
DealValue string `json:"dealValue"`
Amount string `json:"amount"`
Fee string `json:"fee"`
Side string `json:"side"`
CreatedAt int `json:"createdAt"`
}
type HistoryOrderListPage struct {
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
TotalNum int `json:"totalNum"`
TotalPage int `json:"totalPage"`
Items []HistoryOrder `json:"items"`
}
//go:generate GetRequest -url /api/v1/orders -type ListOrdersRequest -responseDataType .OrderListPage
type ListOrdersRequest struct {
client *RestClient
client requestgen.AuthenticatedAPIClient
status *string `param:"status" validValues:"active,done"`
@ -150,7 +136,7 @@ type ListOrdersRequest struct {
orderType *OrderType `param:"type"`
tradeType *TradeType `param:"tradeType"`
tradeType *TradeType `param:"tradeType" default:"TRADE"`
startAt *time.Time `param:"startAt,milliseconds"`
@ -193,43 +179,6 @@ type OrderListPage struct {
Items []Order `json:"items"`
}
func (r *ListOrdersRequest) Do(ctx context.Context) (*OrderListPage, error) {
params, err := r.GetParametersQuery()
if err != nil {
return nil, err
}
if _, ok := params["tradeType"]; !ok {
params.Add("tradeType", "TRADE")
}
req, err := r.client.NewAuthenticatedRequest(ctx, "GET", "/api/v1/orders", params, nil)
if err != nil {
return nil, err
}
response, err := r.client.SendRequest(req)
if err != nil {
return nil, err
}
var orderResponse struct {
Code string `json:"code"`
Message string `json:"msg"`
Data *OrderListPage `json:"data"`
}
if err := response.DecodeJSON(&orderResponse); err != nil {
return nil, err
}
if orderResponse.Data == nil {
return nil, errors.New("api error: [" + orderResponse.Code + "] " + orderResponse.Message)
}
return orderResponse.Data, nil
}
func (c *TradeService) NewListOrdersRequest() *ListOrdersRequest {
return &ListOrdersRequest{client: c.client}
}
@ -259,7 +208,6 @@ type PlaceOrderRequest struct {
timeInForce *TimeInForceType `param:"timeInForce,required"`
}
type CancelOrderResponse struct {
CancelledOrderIDs []string `json:"cancelledOrderIds,omitempty"`
@ -276,7 +224,6 @@ type CancelOrderRequest struct {
clientOrderID *string `param:"clientOrderID"`
}
func (r *CancelOrderRequest) Do(ctx context.Context) (*CancelOrderResponse, error) {
if r.orderID == nil && r.clientOrderID == nil {
return nil, errors.New("either orderID or clientOrderID is required for canceling order")

View File

@ -80,6 +80,11 @@ func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol
continue
}
// skip canceled and not filled orders
if order.Status == types.OrderStatusCanceled && order.ExecutedQuantity == 0.0 {
continue
}
if err := s.Insert(order); err != nil {
return err
}