package binanceservice import ( "context" "database/sql" "errors" "fmt" DbModels "go-admin/app/admin/models" "go-admin/common/global" "go-admin/common/helper" "go-admin/pkg/maphelper" "go-admin/pkg/retryhelper" "go-admin/pkg/utility/snowflakehelper" "go-admin/services/cacheservice" "strconv" "sync" "time" "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/service" "github.com/shopspring/decimal" "gorm.io/gorm" ) // ReverseServiceOptimized 优化后的反向下单服务 type ReverseServiceOptimized struct { service.Service // 订单状态更新锁,防止并发状态覆盖 orderStatusMutex sync.RWMutex // 持仓更新锁,防止持仓数据竞态 positionMutex sync.RWMutex // 止盈止损订单取消锁 takeProfitMutex sync.RWMutex } // PositionSyncResult 持仓同步结果 type PositionSyncResult struct { ExchangePosition decimal.Decimal // 交易所实际持仓 SystemPosition decimal.Decimal // 系统记录持仓 NeedSync bool // 是否需要同步 SyncError error // 同步错误 } // OrderStatusUpdate 订单状态更新结构 type OrderStatusUpdate struct { OrderSn string Status int UpdateData map[string]interface{} RetryCount int LastAttempt time.Time } // ReverseOrderOptimized 优化后的反向下单处理 // 增强并发安全性和错误处理 func (e *ReverseServiceOptimized) ReverseOrderOptimized(apiKey string, mapData map[string]interface{}) (bool, error) { apiInfo := GetApiInfoByKey(apiKey) if apiInfo.Id == 0 { e.Log.Errorf("获取apiInfo失败 %s", apiKey) return false, nil } status, _ := maphelper.GetString(mapData, "X") orderSn, err := maphelper.GetString(mapData, "c") if err != nil { return true, err } // 使用Redis分布式锁确保同一订单号的处理原子性 lockKey := fmt.Sprintf("reverse_order_lock:%s", orderSn) lock := helper.NewRedisLock(lockKey, 30, 5, 100*time.Millisecond) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if acquired, err := lock.AcquireWait(ctx); err != nil || !acquired { return false, fmt.Errorf("获取订单处理锁失败: %s, err: %v", orderSn, err) } defer lock.Release() switch status { case "NEW", "CANCELED", "EXPIRED", "EXPIRED_IN_MATCH": return e.handleSimpleStatusChangeOptimized(status, orderSn, mapData) case "FILLED": return e.handleFilledOrderOptimized(apiInfo, mapData) default: return false, fmt.Errorf("不支持的订单状态 %s", status) } } // handleSimpleStatusChangeOptimized 优化的简单状态变更处理 func (e *ReverseServiceOptimized) handleSimpleStatusChangeOptimized(status string, orderSn string, mapData map[string]interface{}) (bool, error) { statusMap := map[string]int{ "NEW": 2, "CANCELED": 6, "EXPIRED": 7, "EXPIRED_IN_MATCH": 7, } if newStatus, ok := statusMap[status]; ok { // 使用重试机制确保状态更新成功 update := &OrderStatusUpdate{ OrderSn: orderSn, Status: newStatus, UpdateData: mapData, } return false, e.updateOrderStatusWithRetry(update) } return false, fmt.Errorf("不支持的订单状态 %s", status) } // handleFilledOrderOptimized 优化的成交订单处理 func (e *ReverseServiceOptimized) handleFilledOrderOptimized(apiInfo DbModels.LineApiUser, mapData map[string]interface{}) (bool, error) { if apiInfo.ReverseStatus != 1 || apiInfo.OpenStatus != 1 || apiInfo.ReverseApiId <= 0 { return false, nil } reverseApiInfo, err := GetApiInfo(apiInfo.ReverseApiId) if err != nil { e.Log.Errorf("获取反向api信息失败 reverseApiId:%d, err:%v", apiInfo.ReverseApiId, err) return true, err } mainOrder, err := e.SaveMainOrderOptimized(mapData, apiInfo) if err != nil { return false, err } // 使用事务确保持仓和订单状态的一致性 return e.processMainOrderWithTransaction(&mainOrder, &apiInfo, &reverseApiInfo) } // SaveMainOrderOptimized 优化的主单保存 func (e *ReverseServiceOptimized) SaveMainOrderOptimized(mapData map[string]interface{}, apiInfo DbModels.LineApiUser) (DbModels.LineReverseOrder, error) { now := time.Now() symbol, err := maphelper.GetString(mapData, "s") var reverseOrder DbModels.LineReverseOrder if err != nil { return reverseOrder, err } orderSn, err := maphelper.GetString(mapData, "c") if err != nil { return reverseOrder, err } // 检查订单是否已存在,防止重复处理 existingOrder := DbModels.LineReverseOrder{} if err := e.Orm.Where("order_sn = ?", orderSn).First(&existingOrder).Error; err == nil { e.Log.Warnf("订单已存在,跳过处理: %s", orderSn) return existingOrder, nil } side, err := maphelper.GetString(mapData, "S") if err != nil { return reverseOrder, err } positionSide, err := maphelper.GetString(mapData, "ps") if err != nil { return reverseOrder, err } mainType, _ := maphelper.GetString(mapData, "ot") reverseOrder = DbModels.LineReverseOrder{ ApiId: apiInfo.Id, Category: 0, OrderSn: orderSn, TriggerTime: &now, Status: 3, Symbol: symbol, FollowOrderSn: "", Type: mainType, Price: maphelper.GetDecimal(mapData, "p"), FinalPrice: maphelper.GetDecimal(mapData, "ap"), TotalNum: maphelper.GetDecimal(mapData, "z"), Side: side, PositionSide: positionSide, } reverseOrder.PriceU = reverseOrder.Price if !reverseOrder.Price.IsZero() && !reverseOrder.TotalNum.IsZero() { reverseOrder.BuyPrice = reverseOrder.Price.Mul(reverseOrder.TotalNum) } if id, err := maphelper.GetFloat64(mapData, "i"); err == nil { reverseOrder.OrderId = strconv.FormatFloat(id, 'f', -1, 64) } orderType, _ := maphelper.GetString(mapData, "ot") switch orderType { case "LIMIT", "MARKET": reverseOrder.OrderType = 0 case "TAKE_PROFIT_MARKET", "TAKE_PROFIT": reverseOrder.OrderType = 1 case "STOP_MARKET", "STOP", "TRAILING_STOP_MARKET": reverseOrder.OrderType = 2 default: return reverseOrder, fmt.Errorf("不支持的订单类型: %s", orderType) } if reverseOrder.PositionSide == "BOTH" { return reverseOrder, errors.New("不支持的持仓类型,必须为双向持仓") } // 使用事务保存订单 err = e.Orm.Transaction(func(tx *gorm.DB) error { return tx.Create(&reverseOrder).Error }) if err != nil { e.Log.Errorf("保存主单失败:%v", err) return reverseOrder, err } return reverseOrder, nil } // processMainOrderWithTransaction 在事务中处理主单 func (e *ReverseServiceOptimized) processMainOrderWithTransaction(mainOrder *DbModels.LineReverseOrder, apiInfo *DbModels.LineApiUser, reverseApiInfo *DbModels.LineApiUser) (bool, error) { var needReverseOrder bool var closePosition bool var err error err = e.Orm.Transaction(func(tx *gorm.DB) error { // 在事务中处理持仓更新 switch { case mainOrder.PositionSide == "LONG" && mainOrder.Side == "BUY", mainOrder.PositionSide == "SHORT" && mainOrder.Side == "SELL": if mainOrder.Category == 0 { needReverseOrder, closePosition, err = e.savePositionOptimized(tx, mainOrder, apiInfo, true, false) if err != nil { return err } } case mainOrder.PositionSide == "SHORT" && mainOrder.Side == "BUY", mainOrder.PositionSide == "LONG" && mainOrder.Side == "SELL": if mainOrder.Category == 0 { needReverseOrder, closePosition, err = e.savePositionOptimized(tx, mainOrder, apiInfo, true, true) if err != nil { e.Log.Errorf("保存主订单失败: %v", err) return err } } default: return errors.New("不支持的订单类型") } return nil }) if err != nil { return false, err } // 事务成功后,异步处理反向下单 if needReverseOrder { go func() { if err := e.DoAddReverseOrderOptimized(mainOrder, reverseApiInfo, apiInfo.OrderProportion, false, closePosition); err != nil { e.Log.Errorf("异步反向下单失败: %v", err) } }() } return true, nil } // savePositionOptimized 优化的持仓保存,增强并发安全性 func (e *ReverseServiceOptimized) savePositionOptimized(tx *gorm.DB, order *DbModels.LineReverseOrder, apiInfo *DbModels.LineApiUser, isMain, reducePosition bool) (bool, bool, error) { e.positionMutex.Lock() defer e.positionMutex.Unlock() position := DbModels.LineReversePosition{} positionSide := order.PositionSide side := order.Side totalNum := order.TotalNum closePosition := false needReverseOrder := false symbol, err1 := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1) if err1 != nil { e.Log.Errorf("获取交易对失败 symbol:%s err:%v", order.Symbol, err1) } var querySql string sqlStr := "" // 持仓同步检查 syncResult := e.syncPositionWithExchange(apiInfo, order.Symbol, order.PositionSide) if syncResult.NeedSync { e.Log.Warnf("检测到持仓不同步,交易所持仓: %s, 系统持仓: %s", syncResult.ExchangePosition.String(), syncResult.SystemPosition.String()) } // 如果是主单,存储仓位则是反单的持仓方向 if isMain { if order.PositionSide == "LONG" { positionSide = "SHORT" } else { positionSide = "LONG" } // 减仓判断是否为平仓 closePosition = e.getClosePositionOptimized(reducePosition, apiInfo, order, order.PositionSide, isMain) if !reducePosition { // 反单止盈止损方向相反 if side == "SELL" { side = "BUY" } else { side = "SELL" } position.ReverseApiId = apiInfo.ReverseApiId position.Side = side position.ApiId = order.ApiId position.Symbol = order.Symbol position.Status = 1 position.ReverseStatus = 0 position.PositionSide = positionSide position.AveragePrice = order.FinalPrice position.PositionNo = snowflakehelper.GetOrderNo() } querySql = "api_id =? and position_side =? and symbol =? and status =1" // 使用乐观锁防止并发更新冲突 if closePosition { totalNum = decimal.Zero sqlStr = "UPDATE line_reverse_position set amount=@totalNum,updated_at=now(),status=2,version=version+1 where id =@id and status!=2 and version=@version" } else if reducePosition { sqlStr = "UPDATE line_reverse_position set amount=amount - @totalNum,updated_at=now(),average_price=@averagePrice,version=version+1 where id =@id and status!=2 and version=@version" } else { sqlStr = "UPDATE line_reverse_position set total_amount=total_amount + @totalNum,amount=amount + @totalNum,updated_at=now(),average_price=@averagePrice,version=version+1 where id =@id and status!=2 and version=@version" } } else { querySql = "reverse_api_id =? and position_side =? and symbol =? and reverse_status in (0,1)" closePosition = e.getClosePositionOptimized(reducePosition, apiInfo, order, order.PositionSide, isMain) if closePosition { totalNum = decimal.Zero sqlStr = "UPDATE line_reverse_position set reverse_amount=@totalNum,updated_at=now(),reverse_status=2,version=version+1 where id =@id and reverse_status !=2 and version=@version" } else if reducePosition { sqlStr = "UPDATE line_reverse_position set reverse_amount=reverse_amount - @totalNum,updated_at=now(),reverse_average_price=@averagePrice,version=version+1 where id =@id and reverse_status !=2 and version=@version" } else { sqlStr = "UPDATE line_reverse_position set total_reverse_amount=total_reverse_amount + @totalNum,reverse_amount=reverse_amount + @totalNum,updated_at=now(),reverse_status =1,reverse_average_price=@averagePrice,version=version+1 where id =@id and reverse_status !=2 and version=@version" } } var averagePrice decimal.Decimal var remainQuantity decimal.Decimal var currentVersion int // 获取当前持仓记录 err1 = tx.Model(&position).Where(querySql, order.ApiId, positionSide, order.Symbol).First(&position).Error if err1 != nil { // 主单仓位不存在,创建新仓位 if isMain && errors.Is(err1, gorm.ErrRecordNotFound) && !reducePosition { if err2 := tx.Create(&position).Error; err2 != nil { return false, false, err2 } averagePrice = position.AveragePrice } else { return false, false, err1 } } else { currentVersion = position.Version // 计算平均价格逻辑保持不变 var totalAmount decimal.Decimal var totalPrice decimal.Decimal if !position.Amount.IsZero() && !position.AveragePrice.IsZero() { if isMain { totalPrice = position.Amount.Mul(position.AveragePrice) totalAmount = position.Amount } else { totalPrice = position.ReverseAmount.Mul(position.ReverseAveragePrice) totalAmount = position.ReverseAmount } if !reducePosition { totalPrice = totalPrice.Add(order.Price.Mul(order.TotalNum)) totalAmount = totalAmount.Add(order.TotalNum) } else if reducePosition && !closePosition { totalPrice = totalPrice.Sub(order.Price.Mul(order.TotalNum)) totalAmount = totalAmount.Sub(order.TotalNum) } } if totalAmount.IsZero() || totalPrice.IsZero() { if isMain { averagePrice = position.AveragePrice } else { if position.ReverseAveragePrice.IsZero() { averagePrice = order.Price } else { averagePrice = position.ReverseAveragePrice } } } else { if closePosition { if isMain { averagePrice = position.AveragePrice } else { averagePrice = position.ReverseAveragePrice } } else { averagePrice = totalPrice.Div(totalAmount).Truncate(int32(symbol.PriceDigit)) } } } // 关联订单的仓位id if err2 := tx.Exec("UPDATE line_reverse_order set position_id=@positionId where id=@orderId and position_id = 0", sql.Named("positionId", position.Id), sql.Named("orderId", order.Id)).Error; err2 != nil { return false, false, err2 } // 使用版本号进行乐观锁更新 dbResult := tx.Exec(sqlStr, sql.Named("totalNum", totalNum), sql.Named("id", position.Id), sql.Named("averagePrice", averagePrice), sql.Named("version", currentVersion)) if dbResult.Error != nil { return false, false, dbResult.Error } order.PositionId = position.Id if dbResult.RowsAffected == 0 { e.Log.Errorf("持仓更新失败,可能存在并发冲突 closePosition:%v order:%v", closePosition, order) return false, false, errors.New("持仓更新失败,可能存在并发冲突") } if reducePosition && !isMain { remainQuantity = position.ReverseAmount.Sub(totalNum) } else if !isMain { remainQuantity = position.ReverseAmount.Add(totalNum) } // 主单且对手单没有平仓 if isMain && position.ReverseStatus != 2 { needReverseOrder = true } // 异步处理止盈止损 if !isMain && !closePosition { go func() { if err := e.doDefaultTakeStopOptimized(order, apiInfo, remainQuantity); err != nil { e.Log.Errorf("设置默认止盈止损失败: %v", err) } }() } else if !isMain && closePosition { // 异步取消剩余委托 go func() { if err := e.DoCancelTakeAndStopOptimized(order.Symbol, position.PositionSide, apiInfo); err != nil { e.Log.Errorf("取消止盈止损订单失败: %v", err) } }() } return needReverseOrder, closePosition, nil } // syncPositionWithExchange 同步交易所持仓数据 func (e *ReverseServiceOptimized) syncPositionWithExchange(apiInfo *DbModels.LineApiUser, symbol, positionSide string) *PositionSyncResult { result := &PositionSyncResult{} // 获取交易所实际持仓 futApi := FutRestApi{} holdData := HoldeData{} err := futApi.GetPositionData(apiInfo, symbol, positionSide, &holdData) if err != nil { result.SyncError = err return result } result.ExchangePosition = holdData.TotalQuantity // 获取系统记录的持仓 position := DbModels.LineReversePosition{} err = e.Orm.Where("api_id = ? AND position_side = ? AND symbol = ? AND status = 1", apiInfo.Id, positionSide, symbol).First(&position).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { result.SystemPosition = decimal.Zero } else { result.SyncError = err return result } } else { result.SystemPosition = position.Amount } // 判断是否需要同步(允许小幅误差) diff := result.ExchangePosition.Sub(result.SystemPosition).Abs() threshold := decimal.NewFromFloat(0.001) // 0.001的误差阈值 result.NeedSync = diff.GreaterThan(threshold) return result } // getClosePositionOptimized 优化的平仓判断 func (e *ReverseServiceOptimized) getClosePositionOptimized(reducePosition bool, apiInfo *DbModels.LineApiUser, order *DbModels.LineReverseOrder, positionSide string, isMain bool) bool { closePosition := false if reducePosition { // 使用重试机制获取持仓数据 opts := retryhelper.DefaultRetryOptions() opts.MaxRetries = 3 opts.InitialInterval = time.Second holdData, err := retryhelper.RetryWithResult(func() (*HoldeData, error) { futApi := FutRestApi{} holdData := &HoldeData{} err := futApi.GetPositionData(apiInfo, order.Symbol, positionSide, holdData) return holdData, err }, opts) if err != nil { e.Log.Errorf("获取剩余持仓信息失败 symbol:%s err:%v", order.Symbol, err) // 降级到数据库查询 lastPosition := DbModels.LineReversePosition{} if err2 := e.Orm.Model(&DbModels.LineReversePosition{}).Where("position_side =? and symbol =? and status =1", positionSide, order.Symbol).First(&lastPosition).Error; err2 != nil { e.Log.Errorf("获取上一次持仓信息失败 symbol:%s err:%v", order.Symbol, err2) } else if isMain && lastPosition.Amount.Cmp(order.TotalNum) <= 0 { closePosition = true } else if !isMain && lastPosition.ReverseAmount.Cmp(order.TotalNum) <= 0 { closePosition = true } } else if holdData.TotalQuantity.IsZero() { closePosition = true } } return closePosition } // updateOrderStatusWithRetry 带重试的订单状态更新 func (e *ReverseServiceOptimized) updateOrderStatusWithRetry(update *OrderStatusUpdate) error { e.orderStatusMutex.Lock() defer e.orderStatusMutex.Unlock() opts := retryhelper.DefaultRetryOptions() opts.MaxRetries = 3 opts.InitialInterval = 500 * time.Millisecond return retryhelper.Retry(func() error { data := map[string]interface{}{ "status": update.Status, "updated_at": time.Now(), } if update.Status == 3 { now := time.Now() if orderId, ok := update.UpdateData["i"].(float64); ok { data["order_id"] = orderId } if ap, ok := update.UpdateData["ap"].(string); ok { data["final_price"], _ = decimal.NewFromString(ap) } if num, ok := update.UpdateData["z"].(string); ok { data["total_num"], _ = decimal.NewFromString(num) } data["trigger_time"] = &now } else if update.Status == 2 { if orderId, ok := update.UpdateData["i"].(float64); ok { data["order_id"] = orderId } } db := e.Orm.Model(&DbModels.LineReverseOrder{}). Where("order_sn = ? and status != 3", update.OrderSn). Updates(data) if db.Error != nil { e.Log.Errorf("修改订单状态失败 orderSn:%s, err:%v", update.OrderSn, db.Error) return db.Error } if db.RowsAffected == 0 { e.Log.Warnf("修改订单状态失败 orderSn:%s, 未找到订单或状态未变更", update.OrderSn) } return nil }, opts) } // DoAddReverseOrderOptimized 优化的反向下单 func (e *ReverseServiceOptimized) DoAddReverseOrderOptimized(mainOrder *DbModels.LineReverseOrder, reverseApiInfo *DbModels.LineApiUser, orderProportion decimal.Decimal, reducePosition, closePosition bool) error { // 使用分布式锁防止重复下单 lockKey := fmt.Sprintf("reverse_add_order:%s", mainOrder.OrderSn) lock := helper.NewRedisLock(lockKey, 30, 5, 100*time.Millisecond) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if acquired, err := lock.AcquireWait(ctx); err != nil || !acquired { return fmt.Errorf("获取反向下单锁失败: %s, err: %v", mainOrder.OrderSn, err) } defer lock.Release() // 检查是否已经存在反向订单 existingOrder := DbModels.LineReverseOrder{} if err := e.Orm.Where("follow_order_sn = ? AND category = 1", mainOrder.OrderSn).First(&existingOrder).Error; err == nil { e.Log.Warnf("反向订单已存在,跳过处理: %s", mainOrder.OrderSn) return nil } order := DbModels.LineReverseOrder{} order.ApiId = reverseApiInfo.Id order.Category = 1 order.OrderSn = helper.GetOrderNo() order.FollowOrderSn = mainOrder.OrderSn order.Symbol = mainOrder.Symbol order.OrderType = 0 // 设置持仓方向和交易方向 switch mainOrder.PositionSide { case "LONG": order.PositionSide = "SHORT" case "SHORT": order.PositionSide = "LONG" } switch mainOrder.Side { case "SELL": order.Side = "BUY" case "BUY": order.Side = "SELL" default: return fmt.Errorf("不支持的订单类型 side:%s", mainOrder.Side) } if reducePosition && closePosition { order.OrderType = 4 } else if reducePosition { order.OrderType = 3 } symbol, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, mainOrder.Symbol, 1) if err != nil { e.Log.Errorf("获取交易对信息失败 symbol:%s custom:%s :%v", mainOrder.Symbol, mainOrder.OrderSn, err) return err } setting, err := cacheservice.GetReverseSetting(e.Orm) if err != nil { e.Log.Errorf("获取反单设置失败 symbol:%s custom:%s :%v", mainOrder.Symbol, mainOrder.OrderSn, err) return err } // 获取最新价格 signPrice, _ := decimal.NewFromString(symbol.LastPrice) price := signPrice.Truncate(int32(symbol.PriceDigit)) if price.Cmp(decimal.Zero) <= 0 { e.Log.Errorf("获取最新价格失败 symbol:%s custom:%s 单价小于0", mainOrder.Symbol, mainOrder.OrderSn) return errors.New("获取最新价格失败") } // 计算溢价 var percent decimal.Decimal switch { case order.PositionSide == "LONG" && order.Side == "BUY", order.PositionSide == "SHORT" && order.Side == "BUY": percent = decimal.NewFromInt(100).Add(setting.ReversePremiumRatio) case order.PositionSide == "SHORT" && order.Side == "SELL", order.PositionSide == "LONG" && order.Side == "SELL": percent = decimal.NewFromInt(100).Sub(setting.ReversePremiumRatio) default: return fmt.Errorf("不支持的订单类型 ps:%s, side:%s", order.PositionSide, order.Side) } percent = percent.Div(decimal.NewFromInt(100)).Truncate(4) price = price.Mul(percent).Truncate(int32(symbol.PriceDigit)) var amount decimal.Decimal // 计算下单数量 if closePosition { var position DbModels.LineReversePosition if err1 := e.Orm.Model(position). Where("position_side = ? and reverse_api_id = ? and reverse_status = 1", order.PositionSide, order.ApiId). Select("reverse_amount"). Find(&position).Error; err1 != nil { e.Log.Errorf("获取剩余仓位失败 symbol:%s custom:%s :%v", order.Symbol, order.OrderSn, err1) if len(err1.Error()) < 255 { order.Remark = err1.Error() } else { order.Remark = err1.Error()[:254] } } amount = position.ReverseAmount if amount.IsZero() { order.Remark = "没有持仓数量" } } else { proportion := decimal.NewFromInt(100) if orderProportion.Cmp(decimal.Zero) > 0 { proportion = orderProportion } proportion = proportion.Div(decimal.NewFromInt(100)).Truncate(4) amount = mainOrder.TotalNum.Mul(proportion).Truncate(int32(symbol.AmountDigit)) logger.Info("反向下单比例 %s ,原始数量:%s,反向下单数量:%s", proportion.String(), mainOrder.TotalNum.String(), amount.String()) if amount.Cmp(decimal.Zero) <= 0 { e.Log.Errorf("计算数量失败 symbol:%s custom:%s 数量小于0", mainOrder.Symbol, mainOrder.OrderSn) return errors.New("计算数量失败") } } order.TotalNum = amount order.Price = price order.PriceU = price order.BuyPrice = amount.Mul(price).Truncate(int32(symbol.PriceDigit)) order.Status = 1 order.Type = setting.ReverseOrderType order.SignPrice = signPrice order.PositionId = mainOrder.PositionId if order.Remark != "" { order.Status = 8 } // 保存反向订单 if err := e.Orm.Model(&order).Create(&order).Error; err != nil { e.Log.Errorf("保存反单失败 symbol:%s custom:%s :%v", mainOrder.Symbol, mainOrder.OrderSn, err) return err } // 如果状态正常,进行下单 if order.Status == 1 { err = e.DoBianceOrderOptimized(&order, reverseApiInfo, &setting, reducePosition, closePosition) // 下单成功且为平仓单时,取消止盈止损 if err == nil && closePosition { go func() { if err := e.DoCancelTakeProfitBatchOptimized(symbol.GetSymbol(), order.PositionSide, order.Side, 1, reverseApiInfo); err != nil { e.Log.Errorf("取消止盈止损订单失败: %v", err) } }() } } return err } // DoBianceOrderOptimized 优化的币安下单 func (e *ReverseServiceOptimized) DoBianceOrderOptimized(order *DbModels.LineReverseOrder, apiInfo *DbModels.LineApiUser, setting *DbModels.LineReverseSetting, reducePosition, closePosition bool) error { // 使用重试机制进行下单 opts := retryhelper.DefaultRetryOptions() opts.MaxRetries = 3 opts.InitialInterval = time.Second opts.RetryableErrFn = func(err error) bool { // 某些错误不需要重试 if err != nil { errStr := err.Error() // 余额不足、订单重复等错误不重试 if contains(errStr, []string{"余额不足", "订单重复", "API-key", "无效"}) { return false } } return true } return retryhelper.Retry(func() error { futApiV2 := FutRestApi{} params := FutOrderPlace{ ApiId: apiInfo.Id, Symbol: order.Symbol, Side: order.Side, PositionSide: order.PositionSide, OrderType: setting.ReverseOrderType, Quantity: order.TotalNum, Price: order.Price, NewClientOrderId: order.OrderSn, } if err := futApiV2.OrderPlaceLoop(e.Orm, params, 3); err != nil { e.Log.Errorf("币安下单失败 orderSn:%s, err:%v", order.OrderSn, err) // 更新订单状态为失败 e.Orm.Model(&DbModels.LineReverseOrder{}). Where("id = ?", order.Id). Updates(map[string]interface{}{ "status": 8, "remark": err.Error()[:min(len(err.Error()), 254)], "updated_at": time.Now(), }) return err } return nil }, opts) } // DoCancelTakeProfitBatchOptimized 优化的批量取消止盈止损订单 func (e *ReverseServiceOptimized) DoCancelTakeProfitBatchOptimized(symbol, positionSide, side string, orderType int, apiInfo *DbModels.LineApiUser) error { e.takeProfitMutex.Lock() defer e.takeProfitMutex.Unlock() // 获取需要取消的订单 orderSnList := e.GetTakeProfitBatchOptimized(symbol, positionSide, side, apiInfo.Id, orderType) if len(orderSnList) == 0 { return nil } // 分批取消,每次最多10个 batchSize := 10 for i := 0; i < len(orderSnList); i += batchSize { end := i + batchSize if end > len(orderSnList) { end = len(orderSnList) } batch := orderSnList[i:end] // 使用重试机制取消订单 opts := retryhelper.DefaultRetryOptions() opts.MaxRetries = 3 opts.InitialInterval = time.Second err := retryhelper.Retry(func() error { futApi := FutRestApi{} return futApi.CancelBatchFutOrder(*apiInfo, symbol, batch) }, opts) if err != nil { e.Log.Errorf("批量取消止盈止损订单失败 symbol:%s, batch:%v, err:%v", symbol, batch, err) // 继续处理下一批,不因为一批失败而中断 continue } e.Log.Infof("成功取消止盈止损订单 symbol:%s, count:%d", symbol, len(batch)) } return nil } // GetTakeProfitBatchOptimized 优化的获取止盈止损订单列表 func (e *ReverseServiceOptimized) GetTakeProfitBatchOptimized(symbol, positionSide, side string, apiId int, orderType int) []string { var orders []DbModels.LineReverseOrder query := e.Orm.Model(&DbModels.LineReverseOrder{}). Where("symbol = ? AND position_side = ? AND side = ? AND api_id = ? AND order_type = ? AND status = 2", symbol, positionSide, side, apiId, orderType). Select("order_sn") if err := query.Find(&orders).Error; err != nil { e.Log.Errorf("查询止盈止损订单失败: %v", err) return nil } orderSnList := make([]string, 0, len(orders)) for _, order := range orders { orderSnList = append(orderSnList, order.OrderSn) } return orderSnList } // DoCancelTakeAndStopOptimized 优化的取消止盈止损订单 func (e *ReverseServiceOptimized) DoCancelTakeAndStopOptimized(symbol, positionSide string, apiInfo *DbModels.LineApiUser) error { e.takeProfitMutex.Lock() defer e.takeProfitMutex.Unlock() var orders []DbModels.LineReverseOrder if err := e.Orm.Model(&DbModels.LineReverseOrder{}). Where("symbol = ? AND position_side = ? AND api_id = ? AND order_type IN (1,2) AND status = 2", symbol, positionSide, apiInfo.Id). Select("order_sn"). Find(&orders).Error; err != nil { e.Log.Errorf("查询止盈止损订单失败: %v", err) return err } if len(orders) == 0 { return nil } orderSnList := make([]string, 0, len(orders)) for _, order := range orders { orderSnList = append(orderSnList, order.OrderSn) } // 分批取消 batchSize := 10 for i := 0; i < len(orderSnList); i += batchSize { end := i + batchSize if end > len(orderSnList) { end = len(orderSnList) } batch := orderSnList[i:end] opts := retryhelper.DefaultRetryOptions() opts.MaxRetries = 3 opts.InitialInterval = time.Second err := retryhelper.Retry(func() error { futApi := FutRestApi{} return futApi.CancelBatchFutOrder(*apiInfo, symbol, batch) }, opts) if err != nil { e.Log.Errorf("批量取消止盈止损订单失败 symbol:%s, batch:%v, err:%v", symbol, batch, err) } } return nil } // doDefaultTakeStopOptimized 优化的默认止盈止损设置 func (e *ReverseServiceOptimized) doDefaultTakeStopOptimized(order *DbModels.LineReverseOrder, apiInfo *DbModels.LineApiUser, totalNum decimal.Decimal) error { // 异步处理,避免阻塞主流程 go func() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // 使用重试机制 opts := retryhelper.DefaultRetryOptions() opts.MaxRetries = 3 opts.InitialInterval = 2 * time.Second err := retryhelper.Retry(func() error { select { case <-ctx.Done(): return ctx.Err() default: return e.processDefaultTakeStop(order, apiInfo, totalNum) } }, opts) if err != nil { e.Log.Errorf("设置默认止盈止损失败: %v", err) } }() return nil } // processDefaultTakeStop 处理默认止盈止损逻辑 func (e *ReverseServiceOptimized) processDefaultTakeStop(order *DbModels.LineReverseOrder, apiInfo *DbModels.LineApiUser, totalNum decimal.Decimal) error { // 获取反单设置 setting, err := cacheservice.GetReverseSetting(e.Orm) if err != nil { return fmt.Errorf("获取反单设置失败: %v", err) } // 获取交易对信息 symbol, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, order.Symbol, 1) if err != nil { return fmt.Errorf("获取交易对信息失败: %v", err) } // 获取当前价格 lastPrice, _ := decimal.NewFromString(symbol.LastPrice) if lastPrice.IsZero() { return errors.New("获取最新价格失败") } now := time.Now() // 设置止盈订单 if setting.TakeProfitRatio.GreaterThan(decimal.Zero) { takeProfitPrice := e.calculatePriceOptimized(order.PositionSide, lastPrice, setting.TakeProfitRatio, true) takeProfitParams := CreateOrderParams{ ApiInfo: apiInfo, Order: order, Symbol: &symbol, Side: e.getOppositeSideOptimized(order.Side), OrderType: "TAKE_PROFIT_MARKET", Price: takeProfitPrice, TotalNum: totalNum, Now: now, LastPrice: lastPrice, Close: false, PositionId: order.PositionId, OrderSn: helper.GetOrderNo(), PositionSide: order.PositionSide, } if err := e.createReverseOrderOptimized(takeProfitParams); err != nil { e.Log.Errorf("创建止盈订单失败: %v", err) } } // 设置止损订单 if setting.StopLossRatio.GreaterThan(decimal.Zero) { stopLossPrice := e.calculatePriceOptimized(order.PositionSide, lastPrice, setting.StopLossRatio, false) stopLossParams := CreateOrderParams{ ApiInfo: apiInfo, Order: order, Symbol: &symbol, Side: e.getOppositeSideOptimized(order.Side), OrderType: "STOP_MARKET", Price: stopLossPrice, TotalNum: totalNum, Now: now, LastPrice: lastPrice, Close: false, PositionId: order.PositionId, OrderSn: helper.GetOrderNo(), PositionSide: order.PositionSide, } if err := e.createReverseOrderOptimized(stopLossParams); err != nil { e.Log.Errorf("创建止损订单失败: %v", err) } } return nil } // calculatePriceOptimized 优化的价格计算 func (e *ReverseServiceOptimized) calculatePriceOptimized(positionSide string, base decimal.Decimal, ratio decimal.Decimal, isTakeProfit bool) decimal.Decimal { var multiplier decimal.Decimal if isTakeProfit { if positionSide == "LONG" { multiplier = decimal.NewFromInt(1).Add(ratio.Div(decimal.NewFromInt(100))) } else { multiplier = decimal.NewFromInt(1).Sub(ratio.Div(decimal.NewFromInt(100))) } } else { if positionSide == "LONG" { multiplier = decimal.NewFromInt(1).Sub(ratio.Div(decimal.NewFromInt(100))) } else { multiplier = decimal.NewFromInt(1).Add(ratio.Div(decimal.NewFromInt(100))) } } return base.Mul(multiplier) } // getOppositeSideOptimized 获取相反的交易方向 func (e *ReverseServiceOptimized) getOppositeSideOptimized(side string) string { if side == "BUY" { return "SELL" } return "BUY" } // CreateOrderParams 创建订单参数 // CreateOrderParams 已在 reverse_service.go 中定义 // createReverseOrderOptimized 优化的创建反向订单 func (e *ReverseServiceOptimized) createReverseOrderOptimized(params CreateOrderParams) error { // 使用事务确保数据一致性 return e.Orm.Transaction(func(tx *gorm.DB) error { reverseOrder := DbModels.LineReverseOrder{ ApiId: params.ApiInfo.Id, Category: 1, OrderSn: params.OrderSn, FollowOrderSn: params.Order.OrderSn, Symbol: params.Order.Symbol, Side: params.Side, PositionSide: params.PositionSide, Price: params.Price, PriceU: params.Price, TotalNum: params.TotalNum, BuyPrice: params.Price.Mul(params.TotalNum), SignPrice: params.LastPrice, Status: 1, PositionId: params.PositionId, TriggerTime: ¶ms.Now, } // 设置订单类型 switch params.OrderType { case "TAKE_PROFIT_MARKET", "TAKE_PROFIT": reverseOrder.OrderType = 1 reverseOrder.Type = "TAKE_PROFIT_MARKET" case "STOP_MARKET", "STOP": reverseOrder.OrderType = 2 reverseOrder.Type = "STOP_MARKET" default: return fmt.Errorf("不支持的订单类型: %s", params.OrderType) } // 保存订单到数据库 if err := tx.Create(&reverseOrder).Error; err != nil { e.Log.Errorf("保存反向订单失败: %v", err) return err } // 下单到交易所 futApi := FutRestApi{} orderParams := FutOrderPlace{ ApiId: params.ApiInfo.Id, Symbol: reverseOrder.Symbol, Side: reverseOrder.Side, PositionSide: reverseOrder.PositionSide, OrderType: "MARKET", Quantity: reverseOrder.TotalNum, StopPrice: reverseOrder.Price, NewClientOrderId: reverseOrder.OrderSn, } if err := futApi.OrderPlaceLoop(tx, orderParams, 3); err != nil { e.Log.Errorf("下单失败: %v", err) // 更新订单状态为失败 tx.Model(&reverseOrder).Updates(map[string]interface{}{ "status": 8, "remark": err.Error()[:min(len(err.Error()), 254)], "updated_at": time.Now(), }) return err } return nil }) } // contains 检查字符串是否包含任意一个子字符串 func contains(s string, substrs []string) bool { for _, substr := range substrs { if len(substr) > 0 && len(s) >= len(substr) { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } } } return false } // min 返回两个整数中的较小值 func min(a, b int) int { if a < b { return a } return b }