mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-12 15:26:55 +08:00
修復關鍵缺陷:添加 CancelStopOrders 方法避免多個止損單共存
問題: - 調整止損/止盈時,直接調用 SetStopLoss/SetTakeProfit 會創建新訂單 - 但舊的止損/止盈單仍然存在,導致多個訂單共存 - 可能造成意外觸發或訂單衝突 解決方案(參考 PR #197): 1. 在 Trader 接口添加 CancelStopOrders 方法 2. 為三個交易所實現: - binance_futures.go: 過濾 STOP_MARKET/TAKE_PROFIT_MARKET 類型 - aster_trader.go: 同樣邏輯 - hyperliquid_trader.go: 過濾 trigger 訂單(有 triggerPx) 3. 在 executeUpdateStopLossWithRecord 和 executeUpdateTakeProfitWithRecord 中: - 先調用 CancelStopOrders 取消舊單 - 然後設置新止損/止盈 - 取消失敗不中斷執行(記錄警告) 優勢: - ✅ 避免多個止損單同時存在 - ✅ 保留我們的價格驗證邏輯 - ✅ 保留執行價格記錄 - ✅ 詳細錯誤信息 - ✅ 取消失敗時繼續執行(更健壯) 測試建議: - 開倉後調整止損,檢查舊止損單是否被取消 - 連續調整兩次,確認只有最新止損單存在 致謝:參考 PR #197 的實現思路
This commit is contained in:
@@ -981,6 +981,61 @@ func (t *AsterTrader) CancelAllOrders(symbol string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// CancelStopOrders 取消该币种的止盈/止损单(用于调整止盈止损位置)
|
||||
func (t *AsterTrader) CancelStopOrders(symbol string) error {
|
||||
// 获取该币种的所有未完成订单
|
||||
params := map[string]interface{}{
|
||||
"symbol": symbol,
|
||||
}
|
||||
|
||||
body, err := t.request("GET", "/fapi/v3/openOrders", params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取未完成订单失败: %w", err)
|
||||
}
|
||||
|
||||
var orders []map[string]interface{}
|
||||
if err := json.Unmarshal(body, &orders); err != nil {
|
||||
return fmt.Errorf("解析订单数据失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤出止盈止损单并取消
|
||||
canceledCount := 0
|
||||
for _, order := range orders {
|
||||
orderType, _ := order["type"].(string)
|
||||
|
||||
// 只取消止损和止盈订单
|
||||
if orderType == "STOP_MARKET" ||
|
||||
orderType == "TAKE_PROFIT_MARKET" ||
|
||||
orderType == "STOP" ||
|
||||
orderType == "TAKE_PROFIT" {
|
||||
|
||||
orderID, _ := order["orderId"].(float64)
|
||||
cancelParams := map[string]interface{}{
|
||||
"symbol": symbol,
|
||||
"orderId": int64(orderID),
|
||||
}
|
||||
|
||||
_, err := t.request("DELETE", "/fapi/v3/order", cancelParams)
|
||||
if err != nil {
|
||||
log.Printf(" ⚠ 取消订单 %d 失败: %v", int64(orderID), err)
|
||||
continue
|
||||
}
|
||||
|
||||
canceledCount++
|
||||
log.Printf(" ✓ 已取消 %s 的止盈/止损单 (订单ID: %d, 类型: %s)",
|
||||
symbol, int64(orderID), orderType)
|
||||
}
|
||||
}
|
||||
|
||||
if canceledCount == 0 {
|
||||
log.Printf(" ℹ %s 没有止盈/止损单需要取消", symbol)
|
||||
} else {
|
||||
log.Printf(" ✓ 已取消 %s 的 %d 个止盈/止损单", symbol, canceledCount)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatQuantity 格式化数量(实现Trader接口)
|
||||
func (t *AsterTrader) FormatQuantity(symbol string, quantity float64) (string, error) {
|
||||
formatted, err := t.formatQuantity(symbol, quantity)
|
||||
|
||||
Reference in New Issue
Block a user