mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
Merge pull request #1164 from c9s/fix/grid2/trade-fee
FIX: [grid2] apply defensive programming on the order quantity
This commit is contained in:
commit
9db62ed0fc
|
@ -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 {
|
||||
s.logger.Warnf("order trades missing. expected: %s got: %s",
|
||||
o.Quantity.String(),
|
||||
tq.String())
|
||||
return false
|
||||
// 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",
|
||||
executedQuantity.String(),
|
||||
tq.String())
|
||||
return false
|
||||
} else if c > 0 {
|
||||
s.logger.Errorf("aggregated trade quantity %s > order executed quantity %s, something is wrong, please check", tq.String(), executedQuantity.String())
|
||||
return true
|
||||
}
|
||||
|
||||
// shouldn't reach here
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -360,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
|
||||
|
@ -384,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{
|
||||
|
@ -392,13 +411,19 @@ 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:
|
||||
fees := collectTradeFee(orderTrades)
|
||||
if fee, ok := fees[feeCurrency]; ok {
|
||||
return fee, feeCurrency
|
||||
}
|
||||
|
||||
return fixedpoint.Zero, feeCurrency
|
||||
}
|
||||
|
||||
|
@ -408,9 +433,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 #%d is filled, but order executed quantity %s != order quantity %s, something is wrong", o.OrderID, o.ExecutedQuantity, o.Quantity)
|
||||
}
|
||||
|
||||
/*
|
||||
if o.AveragePrice.Sign() > 0 {
|
||||
executedPrice = o.AveragePrice
|
||||
|
@ -418,7 +454,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
|
||||
|
|
Loading…
Reference in New Issue
Block a user