mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-04 09:58:22 +08:00
fix: 修复 update_stop_loss/update_take_profit 未删除旧订单的BUG
## 问题描述 更新止损止盈时,旧订单没有被删除,导致订单累积。 用户看到多个止损/止盈订单同时存在(如截图所示有4个订单)。 ## 根本原因 币安Futures采用双向持仓模式(Hedge Mode),每个symbol可以同时持有LONG和SHORT两个方向的仓位。 取消订单时: - 创建订单时指定了 PositionSide(LONG/SHORT) - 取消订单时未遍历所有订单,导致部分订单残留 ## 修复内容 ### 1. binance_futures.go - CancelStopLossOrders: 取消所有方向(LONG+SHORT)的止损订单 - CancelTakeProfitOrders: 取消所有方向(LONG+SHORT)的止盈订单 - 添加错误收集机制,记录每个失败的订单 - 增强日志输出,显示订单方向(PositionSide) - 仅当所有取消都失败时才返回错误 ### 2. aster_trader.go - 同步应用相同的修复逻辑 - 保持多交易所一致性 ## 预期效果 - 更新止损时,所有旧止损订单被删除 - 更新止盈时,所有旧止盈订单被删除 - 不会出现订单累积问题 - 更详细的日志输出,方便排查问题 ## 测试建议 1. 在双向持仓模式下测试 update_stop_loss 2. 验证旧订单是否全部删除 3. 检查日志中的 positionSide 输出 Related: 用户反馈截图显示4个订单同时存在
This commit is contained in:
+28
-10
@@ -1029,14 +1029,16 @@ func (t *AsterTrader) CancelStopLossOrders(symbol string) error {
|
||||
return fmt.Errorf("解析订单数据失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤出止损单并取消
|
||||
// 过滤出止损单并取消(取消所有方向的止损单,包括LONG和SHORT)
|
||||
canceledCount := 0
|
||||
var cancelErrors []error
|
||||
for _, order := range orders {
|
||||
orderType, _ := order["type"].(string)
|
||||
|
||||
// 只取消止损订单(不取消止盈订单)
|
||||
if orderType == "STOP_MARKET" || orderType == "STOP" {
|
||||
orderID, _ := order["orderId"].(float64)
|
||||
positionSide, _ := order["positionSide"].(string)
|
||||
cancelParams := map[string]interface{}{
|
||||
"symbol": symbol,
|
||||
"orderId": int64(orderID),
|
||||
@@ -1044,21 +1046,28 @@ func (t *AsterTrader) CancelStopLossOrders(symbol string) error {
|
||||
|
||||
_, err := t.request("DELETE", "/fapi/v1/order", cancelParams)
|
||||
if err != nil {
|
||||
log.Printf(" ⚠ 取消止损单 %d 失败: %v", int64(orderID), err)
|
||||
errMsg := fmt.Sprintf("订单ID %d: %v", int64(orderID), err)
|
||||
cancelErrors = append(cancelErrors, fmt.Errorf(errMsg))
|
||||
log.Printf(" ⚠ 取消止损单失败: %s", errMsg)
|
||||
continue
|
||||
}
|
||||
|
||||
canceledCount++
|
||||
log.Printf(" ✓ 已取消止损单 (订单ID: %d, 类型: %s)", int64(orderID), orderType)
|
||||
log.Printf(" ✓ 已取消止损单 (订单ID: %d, 类型: %s, 方向: %s)", int64(orderID), orderType, positionSide)
|
||||
}
|
||||
}
|
||||
|
||||
if canceledCount == 0 {
|
||||
if canceledCount == 0 && len(cancelErrors) == 0 {
|
||||
log.Printf(" ℹ %s 没有止损单需要取消", symbol)
|
||||
} else {
|
||||
} else if canceledCount > 0 {
|
||||
log.Printf(" ✓ 已取消 %s 的 %d 个止损单", symbol, canceledCount)
|
||||
}
|
||||
|
||||
// 如果所有取消都失败了,返回错误
|
||||
if len(cancelErrors) > 0 && canceledCount == 0 {
|
||||
return fmt.Errorf("取消止损单失败: %v", cancelErrors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1079,14 +1088,16 @@ func (t *AsterTrader) CancelTakeProfitOrders(symbol string) error {
|
||||
return fmt.Errorf("解析订单数据失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤出止盈单并取消
|
||||
// 过滤出止盈单并取消(取消所有方向的止盈单,包括LONG和SHORT)
|
||||
canceledCount := 0
|
||||
var cancelErrors []error
|
||||
for _, order := range orders {
|
||||
orderType, _ := order["type"].(string)
|
||||
|
||||
// 只取消止盈订单(不取消止损订单)
|
||||
if orderType == "TAKE_PROFIT_MARKET" || orderType == "TAKE_PROFIT" {
|
||||
orderID, _ := order["orderId"].(float64)
|
||||
positionSide, _ := order["positionSide"].(string)
|
||||
cancelParams := map[string]interface{}{
|
||||
"symbol": symbol,
|
||||
"orderId": int64(orderID),
|
||||
@@ -1094,21 +1105,28 @@ func (t *AsterTrader) CancelTakeProfitOrders(symbol string) error {
|
||||
|
||||
_, err := t.request("DELETE", "/fapi/v1/order", cancelParams)
|
||||
if err != nil {
|
||||
log.Printf(" ⚠ 取消止盈单 %d 失败: %v", int64(orderID), err)
|
||||
errMsg := fmt.Sprintf("订单ID %d: %v", int64(orderID), err)
|
||||
cancelErrors = append(cancelErrors, fmt.Errorf(errMsg))
|
||||
log.Printf(" ⚠ 取消止盈单失败: %s", errMsg)
|
||||
continue
|
||||
}
|
||||
|
||||
canceledCount++
|
||||
log.Printf(" ✓ 已取消止盈单 (订单ID: %d, 类型: %s)", int64(orderID), orderType)
|
||||
log.Printf(" ✓ 已取消止盈单 (订单ID: %d, 类型: %s, 方向: %s)", int64(orderID), orderType, positionSide)
|
||||
}
|
||||
}
|
||||
|
||||
if canceledCount == 0 {
|
||||
if canceledCount == 0 && len(cancelErrors) == 0 {
|
||||
log.Printf(" ℹ %s 没有止盈单需要取消", symbol)
|
||||
} else {
|
||||
} else if canceledCount > 0 {
|
||||
log.Printf(" ✓ 已取消 %s 的 %d 个止盈单", symbol, canceledCount)
|
||||
}
|
||||
|
||||
// 如果所有取消都失败了,返回错误
|
||||
if len(cancelErrors) > 0 && canceledCount == 0 {
|
||||
return fmt.Errorf("取消止盈单失败: %v", cancelErrors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+26
-10
@@ -504,8 +504,9 @@ func (t *FuturesTrader) CancelStopLossOrders(symbol string) error {
|
||||
return fmt.Errorf("获取未完成订单失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤出止损单并取消
|
||||
// 过滤出止损单并取消(取消所有方向的止损单,包括LONG和SHORT)
|
||||
canceledCount := 0
|
||||
var cancelErrors []error
|
||||
for _, order := range orders {
|
||||
orderType := order.Type
|
||||
|
||||
@@ -517,21 +518,28 @@ func (t *FuturesTrader) CancelStopLossOrders(symbol string) error {
|
||||
Do(context.Background())
|
||||
|
||||
if err != nil {
|
||||
log.Printf(" ⚠ 取消止损单 %d 失败: %v", order.OrderID, err)
|
||||
errMsg := fmt.Sprintf("订单ID %d: %v", order.OrderID, err)
|
||||
cancelErrors = append(cancelErrors, fmt.Errorf(errMsg))
|
||||
log.Printf(" ⚠ 取消止损单失败: %s", errMsg)
|
||||
continue
|
||||
}
|
||||
|
||||
canceledCount++
|
||||
log.Printf(" ✓ 已取消止损单 (订单ID: %d, 类型: %s)", order.OrderID, orderType)
|
||||
log.Printf(" ✓ 已取消止损单 (订单ID: %d, 类型: %s, 方向: %s)", order.OrderID, orderType, order.PositionSide)
|
||||
}
|
||||
}
|
||||
|
||||
if canceledCount == 0 {
|
||||
if canceledCount == 0 && len(cancelErrors) == 0 {
|
||||
log.Printf(" ℹ %s 没有止损单需要取消", symbol)
|
||||
} else {
|
||||
} else if canceledCount > 0 {
|
||||
log.Printf(" ✓ 已取消 %s 的 %d 个止损单", symbol, canceledCount)
|
||||
}
|
||||
|
||||
// 如果所有取消都失败了,返回错误
|
||||
if len(cancelErrors) > 0 && canceledCount == 0 {
|
||||
return fmt.Errorf("取消止损单失败: %v", cancelErrors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -546,8 +554,9 @@ func (t *FuturesTrader) CancelTakeProfitOrders(symbol string) error {
|
||||
return fmt.Errorf("获取未完成订单失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤出止盈单并取消
|
||||
// 过滤出止盈单并取消(取消所有方向的止盈单,包括LONG和SHORT)
|
||||
canceledCount := 0
|
||||
var cancelErrors []error
|
||||
for _, order := range orders {
|
||||
orderType := order.Type
|
||||
|
||||
@@ -559,21 +568,28 @@ func (t *FuturesTrader) CancelTakeProfitOrders(symbol string) error {
|
||||
Do(context.Background())
|
||||
|
||||
if err != nil {
|
||||
log.Printf(" ⚠ 取消止盈单 %d 失败: %v", order.OrderID, err)
|
||||
errMsg := fmt.Sprintf("订单ID %d: %v", order.OrderID, err)
|
||||
cancelErrors = append(cancelErrors, fmt.Errorf(errMsg))
|
||||
log.Printf(" ⚠ 取消止盈单失败: %s", errMsg)
|
||||
continue
|
||||
}
|
||||
|
||||
canceledCount++
|
||||
log.Printf(" ✓ 已取消止盈单 (订单ID: %d, 类型: %s)", order.OrderID, orderType)
|
||||
log.Printf(" ✓ 已取消止盈单 (订单ID: %d, 类型: %s, 方向: %s)", order.OrderID, orderType, order.PositionSide)
|
||||
}
|
||||
}
|
||||
|
||||
if canceledCount == 0 {
|
||||
if canceledCount == 0 && len(cancelErrors) == 0 {
|
||||
log.Printf(" ℹ %s 没有止盈单需要取消", symbol)
|
||||
} else {
|
||||
} else if canceledCount > 0 {
|
||||
log.Printf(" ✓ 已取消 %s 的 %d 个止盈单", symbol, canceledCount)
|
||||
}
|
||||
|
||||
// 如果所有取消都失败了,返回错误
|
||||
if len(cancelErrors) > 0 && canceledCount == 0 {
|
||||
return fmt.Errorf("取消止盈单失败: %v", cancelErrors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user