From 5a901e929c2bbfe7a30e6db191a467fb9ff55c3f Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 28 Apr 2023 15:58:12 +0800 Subject: [PATCH 1/4] grid2: apply defensive programming on the order quantity --- pkg/strategy/grid2/strategy.go | 36 +++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/pkg/strategy/grid2/strategy.go b/pkg/strategy/grid2/strategy.go index bd6743009..827b12769 100644 --- a/pkg/strategy/grid2/strategy.go +++ b/pkg/strategy/grid2/strategy.go @@ -344,13 +344,32 @@ func (s *Strategy) calculateProfit(o types.Order, buyPrice, buyQuantity fixedpoi func (s *Strategy) verifyOrderTrades(o types.Order, trades []types.Trade) bool { tq := aggregateTradesQuantity(trades) - if tq.Compare(o.Quantity) != 0 { + // on MAX: if order.status == filled, it does not mean order.executedQuantity == order.quantity + // order.executedQuantity can be less than order.quantity + // so here we use executed quantity to check if the total trade quantity matches to order.executedQuantity + executedQuantity := o.ExecutedQuantity + if executedQuantity.IsZero() { + // fall back to the original quantity if the executed quantity is zero + executedQuantity = o.Quantity + } + + // early return here if it matches + c := tq.Compare(executedQuantity) + if c == 0 { + return true + } + + if c < 0 { s.logger.Warnf("order trades missing. expected: %s got: %s", o.Quantity.String(), tq.String()) return false + } else if c > 0 { + s.logger.Errorf("aggregated trade quantity > order.quantity, something is wrong, please check") + return true } + // shouldn't reach here return true } @@ -408,9 +427,20 @@ func (s *Strategy) processFilledOrder(o types.Order) { // check order fee newSide := types.SideTypeSell newPrice := o.Price - newQuantity := o.Quantity + + executedQuantity := o.ExecutedQuantity + // A safeguard check, fallback to the original quantity + if executedQuantity.IsZero() { + executedQuantity = o.Quantity + } + + newQuantity := executedQuantity executedPrice := o.Price + if o.ExecutedQuantity.Compare(o.Quantity) != 0 { + s.logger.Warnf("order executed quantity %s != order quantity %s, something is wrong", o.ExecutedQuantity, o.Quantity) + } + /* if o.AveragePrice.Sign() > 0 { executedPrice = o.AveragePrice @@ -418,7 +448,7 @@ func (s *Strategy) processFilledOrder(o types.Order) { */ // will be used for calculating quantity - orderExecutedQuoteAmount := o.Quantity.Mul(executedPrice) + orderExecutedQuoteAmount := executedQuantity.Mul(executedPrice) // collect trades for fee // fee calculation is used to reduce the order quantity From 717de67d5abc0b612d7628135e746dd7111dc19a Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 28 Apr 2023 16:07:03 +0800 Subject: [PATCH 2/4] grid2: improve log and try best to return the order fee --- pkg/strategy/grid2/strategy.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/pkg/strategy/grid2/strategy.go b/pkg/strategy/grid2/strategy.go index 827b12769..b2c5c7b6d 100644 --- a/pkg/strategy/grid2/strategy.go +++ b/pkg/strategy/grid2/strategy.go @@ -361,11 +361,11 @@ func (s *Strategy) verifyOrderTrades(o types.Order, trades []types.Trade) bool { if c < 0 { s.logger.Warnf("order trades missing. expected: %s got: %s", - o.Quantity.String(), + executedQuantity.String(), tq.String()) return false } else if c > 0 { - s.logger.Errorf("aggregated trade quantity > order.quantity, something is wrong, please check") + s.logger.Errorf("aggregated trade quantity %s > order executed quantity %s, something is wrong, please check", tq.String(), executedQuantity.String()) return true } @@ -379,7 +379,7 @@ func (s *Strategy) aggregateOrderFee(o types.Order) (fixedpoint.Value, string) { // try to get the received trades (websocket trades) orderTrades := s.historicalTrades.GetOrderTrades(o) if len(orderTrades) > 0 { - s.logger.Infof("found filled order trades: %+v", orderTrades) + s.logger.Infof("GRID: found filled order trades: %+v", orderTrades) } feeCurrency := s.Market.BaseCurrency @@ -403,7 +403,7 @@ func (s *Strategy) aggregateOrderFee(o types.Order) (fixedpoint.Value, string) { return fixedpoint.Zero, feeCurrency } - s.logger.Warnf("missing order trades or missing trade fee, pulling order trades from API") + s.logger.Warnf("GRID: missing #%d order trades or missing trade fee, pulling order trades from API", o.OrderID) // if orderQueryService is supported, use it to query the trades of the filled order apiOrderTrades, err := s.orderQueryService.QueryOrderTrades(context.Background(), types.OrderQuery{ @@ -411,13 +411,21 @@ func (s *Strategy) aggregateOrderFee(o types.Order) (fixedpoint.Value, string) { OrderID: strconv.FormatUint(o.OrderID, 10), }) if err != nil { - s.logger.WithError(err).Errorf("query order trades error") + s.logger.WithError(err).Errorf("query #%d order trades error", o.OrderID) } else { - s.logger.Infof("fetched api trades: %+v", apiOrderTrades) + s.logger.Infof("GRID: fetched api #%d order trades: %+v", o.OrderID, apiOrderTrades) orderTrades = apiOrderTrades } } + // still try to aggregate the trades quantity if we can: + if len(orderTrades) > 0 { + fees := collectTradeFee(orderTrades) + if fee, ok := fees[feeCurrency]; ok { + return fee, feeCurrency + } + } + return fixedpoint.Zero, feeCurrency } From f958120fb5a8401c3b6a2a3bae089dd411e7e435 Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 28 Apr 2023 16:12:57 +0800 Subject: [PATCH 3/4] grid2: remove the len check since we just iterate --- pkg/strategy/grid2/strategy.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/strategy/grid2/strategy.go b/pkg/strategy/grid2/strategy.go index b2c5c7b6d..216929fa7 100644 --- a/pkg/strategy/grid2/strategy.go +++ b/pkg/strategy/grid2/strategy.go @@ -419,11 +419,9 @@ func (s *Strategy) aggregateOrderFee(o types.Order) (fixedpoint.Value, string) { } // still try to aggregate the trades quantity if we can: - if len(orderTrades) > 0 { - fees := collectTradeFee(orderTrades) - if fee, ok := fees[feeCurrency]; ok { - return fee, feeCurrency - } + fees := collectTradeFee(orderTrades) + if fee, ok := fees[feeCurrency]; ok { + return fee, feeCurrency } return fixedpoint.Zero, feeCurrency From 829edeb401e29a95f4d791ea8ef57c055a4cfa97 Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 28 Apr 2023 16:16:23 +0800 Subject: [PATCH 4/4] grid2: improve warning message --- pkg/strategy/grid2/strategy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/strategy/grid2/strategy.go b/pkg/strategy/grid2/strategy.go index 216929fa7..6192c63dd 100644 --- a/pkg/strategy/grid2/strategy.go +++ b/pkg/strategy/grid2/strategy.go @@ -444,7 +444,7 @@ func (s *Strategy) processFilledOrder(o types.Order) { executedPrice := o.Price if o.ExecutedQuantity.Compare(o.Quantity) != 0 { - s.logger.Warnf("order executed quantity %s != order quantity %s, something is wrong", o.ExecutedQuantity, o.Quantity) + s.logger.Warnf("order #%d is filled, but order executed quantity %s != order quantity %s, something is wrong", o.OrderID, o.ExecutedQuantity, o.Quantity) } /*