diff --git a/config/xmaker.yaml b/config/xmaker.yaml index 9afcf296e..293b58247 100644 --- a/config/xmaker.yaml +++ b/config/xmaker.yaml @@ -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 diff --git a/doc/development/kucoin-cli.md b/doc/development/kucoin-cli.md index 2b62a02bd..6f803f0b6 100644 --- a/doc/development/kucoin-cli.md +++ b/doc/development/kucoin-cli.md @@ -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 + ``` diff --git a/examples/kucoin/orders.go b/examples/kucoin/orders.go index 7a5405c5c..8e13b874d 100644 --- a/examples/kucoin/orders.go +++ b/examples/kucoin/orders.go @@ -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{ diff --git a/pkg/exchange/kucoin/exchange.go b/pkg/exchange/kucoin/exchange.go index 749dcdc14..2185a2272 100644 --- a/pkg/exchange/kucoin/exchange.go +++ b/pkg/exchange/kucoin/exchange.go @@ -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) diff --git a/pkg/exchange/kucoin/kucoinapi/cancel_all_order_request_requestgen.go b/pkg/exchange/kucoin/kucoinapi/cancel_all_order_request_requestgen.go index 0f0f2a55c..86148258c 100644 --- a/pkg/exchange/kucoin/kucoinapi/cancel_all_order_request_requestgen.go +++ b/pkg/exchange/kucoin/kucoinapi/cancel_all_order_request_requestgen.go @@ -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 diff --git a/pkg/exchange/kucoin/kucoinapi/cancel_order_request_requestgen.go b/pkg/exchange/kucoin/kucoinapi/cancel_order_request_requestgen.go index 232567527..e5a7250f5 100644 --- a/pkg/exchange/kucoin/kucoinapi/cancel_order_request_requestgen.go +++ b/pkg/exchange/kucoin/kucoinapi/cancel_order_request_requestgen.go @@ -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 diff --git a/pkg/exchange/kucoin/kucoinapi/get_fills_request_requestgen.go b/pkg/exchange/kucoin/kucoinapi/get_fills_request_requestgen.go index 12cbdb2e0..20f3e305e 100644 --- a/pkg/exchange/kucoin/kucoinapi/get_fills_request_requestgen.go +++ b/pkg/exchange/kucoin/kucoinapi/get_fills_request_requestgen.go @@ -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 +} diff --git a/pkg/exchange/kucoin/kucoinapi/list_history_orders_request_requestgen.go b/pkg/exchange/kucoin/kucoinapi/list_history_orders_request_requestgen.go new file mode 100644 index 000000000..43ed886d5 --- /dev/null +++ b/pkg/exchange/kucoin/kucoinapi/list_history_orders_request_requestgen.go @@ -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 +} diff --git a/pkg/exchange/kucoin/kucoinapi/list_orders_request_requestgen.go b/pkg/exchange/kucoin/kucoinapi/list_orders_request_requestgen.go index 565e4ec50..548820e8e 100644 --- a/pkg/exchange/kucoin/kucoinapi/list_orders_request_requestgen.go +++ b/pkg/exchange/kucoin/kucoinapi/list_orders_request_requestgen.go @@ -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 +} diff --git a/pkg/exchange/kucoin/kucoinapi/place_order_request_requestgen.go b/pkg/exchange/kucoin/kucoinapi/place_order_request_requestgen.go index 3d2813bc7..c0832eb7e 100644 --- a/pkg/exchange/kucoin/kucoinapi/place_order_request_requestgen.go +++ b/pkg/exchange/kucoin/kucoinapi/place_order_request_requestgen.go @@ -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 diff --git a/pkg/exchange/kucoin/kucoinapi/trade.go b/pkg/exchange/kucoin/kucoinapi/trade.go index bebc1bf1d..efd6ffc11 100644 --- a/pkg/exchange/kucoin/kucoinapi/trade.go +++ b/pkg/exchange/kucoin/kucoinapi/trade.go @@ -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") diff --git a/pkg/service/order.go b/pkg/service/order.go index 85070ad32..9b8498974 100644 --- a/pkg/service/order.go +++ b/pkg/service/order.go @@ -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 }