package binanceservice

import (
	"context"
	"errors"
	"fmt"
	DbModels "go-admin/app/admin/models"
	"go-admin/app/admin/service/dto"
	"go-admin/common/const/rediskey"
	"go-admin/common/global"
	"go-admin/common/helper"
	"go-admin/models"
	"go-admin/models/positiondto"
	"go-admin/pkg/utility"
	"go-admin/services/cacheservice"
	"go-admin/services/commonservice"
	"go-admin/services/orderservice"
	"strings"
	"time"

	"github.com/bytedance/sonic"
	log "github.com/go-admin-team/go-admin-core/logger"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
)

/*
判断是否触发
*/
func JudgeSpotPrice(trade models.TradeSet) {
	key := fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE)
	preOrderVal, _ := helper.DefaultRedis.GetAllList(key)
	db := commonservice.GetDBConnection()

	if len(preOrderVal) == 0 {
		return
	}

	spotApi := SpotRestApi{}
	orderService := orderservice.OrderService{}
	orderService.Orm = db

	for _, item := range preOrderVal {
		preOrder := dto.PreOrderRedisList{}
		if err := sonic.Unmarshal([]byte(item), &preOrder); err != nil {
			log.Error("反序列化失败")
			continue
		}

		if preOrder.Symbol == trade.Coin+trade.Currency {
			orderPrice, _ := decimal.NewFromString(preOrder.Price)
			tradePrice, _ := decimal.NewFromString(trade.LastPrice)
			//买入
			if strings.ToUpper(preOrder.Site) == "BUY" && orderPrice.Cmp(tradePrice) >= 0 && orderPrice.Cmp(decimal.Zero) > 0 && tradePrice.Cmp(decimal.Zero) > 0 {
				//判断个人websocket是否超时

				apiInfo, _ := GetApiInfo(preOrder.ApiId)
				if err := commonservice.JudgeWebsocketTimeout(apiInfo.ApiKey, 1); err != nil {
					log.Errorf("现货行情订阅超时,apiKey:%s err:%v", apiInfo.ApiKey, err)

					if err1 := orderService.ErrorTrigger(preOrder.Id, 1,
						global.EXCHANGE_BINANCE, item,
						fmt.Sprintf("行情触发失败,err:%v", err)); err1 != nil {
						log.Error("触发失败", err1)
					}
					continue
				}

				SpotOrderLock(db, &preOrder, item, spotApi)
			}
		}
	}
}

// 分布式锁下单（现货预设主单触发）
// v: 预下单信息；item: Redis 原始条目（用于准确删除）
func SpotOrderLock(db *gorm.DB, v *dto.PreOrderRedisList, item string, spotApi SpotRestApi) {
	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, v.ApiId, v.Symbol), 20, 5, 100*time.Millisecond)

	if ok, err := lock.AcquireWait(context.Background()); err != nil {
		log.Error("获取锁失败", err)
		return
	} else if ok {
		defer lock.Release()

		key := fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE)
		preOrder := DbModels.LinePreOrder{}
		if err := db.Where("id = ?", v.Id).First(&preOrder).Error; err != nil {
			log.Error("获取预下单失败", err)

			if errors.Is(err, gorm.ErrRecordNotFound) {
				log.Error("不存在待触发主单", item)
				helper.DefaultRedis.LRem(key, item)
			}

			return
		}

		hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)

		if !hasrecord {
			log.Error("不存在待触发主单", item)
			return
		}

		price, _ := decimal.NewFromString(v.Price)
		num, _ := decimal.NewFromString(preOrder.Num)
		params := OrderPlacementService{
			ApiId:            v.ApiId,
			Symbol:           v.Symbol,
			Side:             v.Site,
			Type:             preOrder.MainOrderType,
			TimeInForce:      "GTC",
			Price:            price,
			Quantity:         num,
			NewClientOrderId: v.OrderSn,
		}
		if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
			log.Error("下单失败", v.Symbol, " err:", err)
			err = db.Model(&DbModels.LinePreOrder{}).Where("id =? AND status =0", preOrder.Id).Updates(map[string]interface{}{"status": "2", "desc": err.Error()}).Error

			if err != nil {
				log.Error("下单失败后修改订单失败")
			}
			if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
				log.Error("删除redis 预下单失败:", err)
			}

			return
		}
		if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
			log.Error("删除redis 预下单失败:", err)
		}

		if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", preOrder.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil {
			log.Error("更新预下单状态失败 ordersn:", v.OrderSn, " status:1")
		}
		return
	} else {
		log.Error("获取锁失败")
		return
	}
}

// 判断是否触发止损
func JudgeSpotStopLoss(trade models.TradeSet) {
	key := fmt.Sprintf(rediskey.SpotStopLossList, global.EXCHANGE_BINANCE)
	stopLossVal, _ := helper.DefaultRedis.GetAllList(key)

	if len(stopLossVal) == 0 {
		return
	}

	db := commonservice.GetDBConnection()
	spotApi := SpotRestApi{}
	setting, err := cacheservice.GetSystemSetting(db)

	if err != nil {
		log.Error("获取系统设置失败")
		return
	}

	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, trade.Coin+trade.Currency, 1)

	if err != nil {
		log.Error("获取交易设置失败")
		return
	}

	for _, item := range stopLossVal {
		stopOrder := dto.StopLossRedisList{}
		if err := sonic.Unmarshal([]byte(item), &stopOrder); err != nil {
			log.Error("反序列化失败")
			continue
		}

		if stopOrder.Symbol == trade.Coin+trade.Currency {
			orderPrice := stopOrder.Price
			tradePrice, _ := decimal.NewFromString(trade.LastPrice)
			//买入
			if strings.ToUpper(stopOrder.Site) == "SELL" &&
				orderPrice.Cmp(tradePrice) >= 0 &&
				orderPrice.Cmp(decimal.Zero) > 0 &&
				tradePrice.Cmp(decimal.Zero) > 0 {

				SpotStopLossTrigger(db, stopOrder, spotApi, setting, tradeSet, key, item)
			}
		}
	}
}

// 触发现货止损
func SpotStopLossTrigger(db *gorm.DB, stopOrder dto.StopLossRedisList, spotApi SpotRestApi, setting DbModels.LineSystemSetting, tradeSet models.TradeSet, key string, item string) {
	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, stopOrder.ApiId, stopOrder.Symbol), 20, 5, 100*time.Millisecond)

	if ok, err := lock.AcquireWait(context.Background()); err != nil {
		log.Error("获取锁失败", err)
		return
	} else if ok {
		defer lock.Release()
		takeOrder := DbModels.LinePreOrder{}
		if err := db.Model(&DbModels.LinePreOrder{}).Where("pid =? AND order_type =1", stopOrder.PId).Find(&takeOrder).Error; err != nil {
			log.Error("查询止盈单失败")
			return
		}

		hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)

		if !hasrecord {
			log.Debug("止损缓存中不存在", item)
			return
		}

		apiInfo, _ := GetApiInfo(takeOrder.ApiId)

		if apiInfo.Id == 0 {
			log.Error("现货止损 查询api用户不存在")
			return
		}

		// 使用统一的撤单重试封装，确保行为一致且高效
		if err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn); err != nil {
			log.Error("现货止损撤单失败", err)
			return
		}
		stopPreOrder, _ := GetOrderById(db, stopOrder.Id)
		price := stopOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.StopLossPremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
		num := utility.StrToDecimal(takeOrder.Num).Truncate(int32(tradeSet.AmountDigit))

		params := OrderPlacementService{
			ApiId:            takeOrder.ApiId,
			Side:             takeOrder.Site,
			Type:             "LIMIT",
			TimeInForce:      "GTC",
			Symbol:           takeOrder.Symbol,
			Price:            price,
			Quantity:         num,
			NewClientOrderId: stopPreOrder.OrderSn,
		}

		if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
			log.Errorf("现货止损挂单失败 id：%s err:%v", stopOrder.Id, err)
		} else {
			if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ? ", stopOrder.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil {
				log.Errorf("现货止损更新状态失败 id：%s err:%v", stopOrder.Id, err)
			}
		}

		if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
			log.Errorf("现货止损 删除缓存失败 id:%v err:%v", stopOrder.Id, err)
		}
	} else {
		log.Error("获取锁失败")
	}
}

// 判断是否触发现货减仓
func JudgeSpotReduce(trade models.TradeSet) {
	key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE)
	db := commonservice.GetDBConnection()
	spotApi := SpotRestApi{}
	setting, err := cacheservice.GetSystemSetting(db)

	if err != nil {
		log.Error("获取系统设置失败")
		return
	}

	reduceOrder := positiondto.ReduceListItem{}
	tradePrice, _ := decimal.NewFromString(trade.LastPrice)
	//减仓单减仓策略
	reduceReduceListKey := fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
	orderReduceVal, _ := helper.DefaultRedis.HGetAllFields(reduceReduceListKey)
	reduceOrderStrategy := dto.LineOrderReduceStrategyResp{}
	orderService := orderservice.OrderService{}
	orderService.Orm = db

	for _, item := range orderReduceVal {
		sonic.Unmarshal([]byte(item), &reduceOrderStrategy)

		for index, item2 := range reduceOrderStrategy.Items {
			if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency {
				//买入
				if strings.ToUpper(reduceOrderStrategy.Side) == "SELL" &&
					item2.TriggerPrice.Cmp(tradePrice) >= 0 &&
					item2.TriggerPrice.Cmp(decimal.Zero) > 0 &&
					tradePrice.Cmp(decimal.Zero) > 0 {
					lock := helper.NewRedisLock(fmt.Sprintf(rediskey.ReduceStrategySpotTriggerLock, reduceOrder.ApiId, reduceOrder.Symbol), 50, 15, 100*time.Millisecond)

					if ok, err := lock.AcquireWait(context.Background()); err != nil {
						log.Error("获取锁失败", err)
						return
					} else if ok {
						defer lock.Release()
						hasrecord, _ := helper.DefaultRedis.HExists(reduceReduceListKey, utility.IntToString(reduceOrderStrategy.OrderId), item)

						if !hasrecord {
							log.Debug("减仓缓存中不存在", item)
							return
						}

						order, err := orderService.CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.PriceDigit)

						if err != nil {
							log.Errorf("%d 生成订单失败", reduceOrderStrategy.OrderId)
						}

						reduceOrder.ApiId = order.ApiId
						reduceOrder.Id = order.Id
						reduceOrder.Pid = order.Pid
						reduceOrder.MainId = order.MainId
						reduceOrder.Symbol = order.Symbol
						reduceOrder.Side = reduceOrderStrategy.Side
						reduceOrder.OrderSn = order.OrderSn
						reduceOrder.Price = item2.Price
						reduceOrder.Num = item2.Num
						if SpotReduceTrigger(db, reduceOrder, spotApi, setting, reduceReduceListKey, item, true, reduceOrderStrategy.OrderId) {
							reduceOrderStrategy.Items[index].Actived = true
							allActive := true
							orderId := utility.IntToString(reduceOrderStrategy.OrderId)

							for _, item3 := range reduceOrderStrategy.Items {
								if !item3.Actived {
									allActive = false
									break
								}
							}

							if allActive {
								if err := helper.DefaultRedis.HDelField(reduceReduceListKey, orderId); err != nil {
									log.Errorf("删除redis reduceReduceListKey失败 %s", err.Error())
								}
							} else {
								str, _ := sonic.MarshalString(reduceOrderStrategy)
								if err := helper.DefaultRedis.HSetField(reduceReduceListKey, orderId, str); err != nil {
									log.Errorf("更新redis reduceReduceListKey失败 %s", err.Error())
								}
							}
						}
					}
				}
			}
		}
	}

	//减仓单
	reduceVal, _ := helper.DefaultRedis.GetAllList(key)

	for _, item := range reduceVal {
		if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil {
			log.Error("反序列化失败")
			continue
		}

		if reduceOrder.Symbol == trade.Coin+trade.Currency {
			orderPrice := reduceOrder.Price
			//买入
			if strings.ToUpper(reduceOrder.Side) == "SELL" &&
				orderPrice.Cmp(tradePrice) >= 0 &&
				orderPrice.Cmp(decimal.Zero) > 0 &&
				tradePrice.Cmp(decimal.Zero) > 0 {

				SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false, 0)
			}
		}
	}
}

// 触发现货减仓
// isStrategy 是否是策略减仓单
// reduceId 策略主减仓单id
func SpotReduceTrigger(db *gorm.DB, reduceOrder positiondto.ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool, reduceId int) bool {
	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 1)
	result := true

	if err != nil {
		log.Error("获取交易设置失败")
		return false
	}
	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, reduceOrder.ApiId, reduceOrder.Symbol), 20, 5, 100*time.Millisecond)

	if ok, err := lock.AcquireWait(context.Background()); err != nil {
		log.Error("获取锁失败", err)
		return false
	} else if ok {
		defer lock.Release()
		takeOrders := make([]DbModels.LinePreOrder, 0)
		if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type IN (1,2,4) AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil {
			log.Error("查询止盈单失败")
			return false
		}
		var hasrecord bool

		if isStrategy {
			hasrecord, _ = helper.DefaultRedis.HExists(key, utility.IntToString(reduceId), item)
		} else {
			hasrecord, _ = helper.DefaultRedis.IsElementInList(key, item)
		}

		if !hasrecord {
			log.Debug("减仓缓存中不存在", item)
			return false
		}

		apiInfo, _ := GetApiInfo(reduceOrder.ApiId)

		if apiInfo.Id == 0 {
			log.Error("现货减仓 查询api用户不存在")
			return false
		}

		for _, takeOrder := range takeOrders {
			err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn)

			if err != nil {
				log.Error("现货撤单失败", err)
				return false
			}
		}
		price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))

		params := OrderPlacementService{
			ApiId:            reduceOrder.ApiId,
			Side:             reduceOrder.Side,
			Type:             "LIMIT",
			TimeInForce:      "GTC",
			Symbol:           reduceOrder.Symbol,
			Price:            price,
			Quantity:         reduceOrder.Num,
			NewClientOrderId: reduceOrder.OrderSn,
		}

		if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
			result = false
			log.Errorf("现货减仓挂单失败 id：%s err:%v", reduceOrder.Id, err)

			if err2 := db.Model(&DbModels.LinePreOrder{}).
				Where("id =? AND status =0", reduceOrder.Id).
				Updates(map[string]interface{}{"status": 2, "desc": err.Error()}).Error; err2 != nil {
				log.Errorf("修改现货减仓状态失败 id：%s err:%v", reduceOrder.Id, err2)
			}
		} else {
			if err := db.Model(&DbModels.LinePreOrder{}).Where("id =?", reduceOrder.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil {
				log.Error("更新预下单触发事件失败 ordersn:", reduceOrder.OrderSn)
			}

			if err := db.Model(&DbModels.LinePreOrder{}).
				Where("id =? AND status =0", reduceOrder.Id).
				Updates(map[string]interface{}{"status": 1}).Error; err != nil {
				log.Errorf("修改现货减仓状态失败 id：%s err:%v", reduceOrder.Id, err)
			}

			//处理减仓单减仓策略
			if err := CacheOrderStrategyAndReCreate(db, reduceOrder, 1, tradeSet, setting); err != nil {
				log.Errorf("现货减仓 处理减仓策略失败 id:%v err:%v", reduceOrder.Id, err)
			}
		}

		if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
			result = false
			log.Errorf("现货减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
		}
	} else {
		log.Error("获取锁失败")
		result = false
	}

	return result
}

// 判断现货加仓
func JudgeSpotAddPosition(trade models.TradeSet) {
	key := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE)
	preOrderVal, _ := helper.DefaultRedis.GetAllList(key)
	db := commonservice.GetDBConnection()

	if len(preOrderVal) == 0 {
		return
	}

	spotApi := SpotRestApi{}
	for _, item := range preOrderVal {
		preOrder := positiondto.AddPositionList{}
		if err := sonic.Unmarshal([]byte(item), &preOrder); err != nil {
			log.Error("反序列化失败")
			continue
		}

		if preOrder.Symbol == trade.Coin+trade.Currency {
			orderPrice := preOrder.Price
			tradePrice, _ := decimal.NewFromString(trade.LastPrice)
			//买入
			if strings.ToUpper(preOrder.Side) == "BUY" && orderPrice.Cmp(tradePrice) >= 0 && orderPrice.Cmp(decimal.Zero) > 0 && tradePrice.Cmp(decimal.Zero) > 0 {
				SpotAddPositionTrigger(db, &preOrder, item, spotApi)
			}
		}
	}
}

// 现货加仓触发
// v: 加仓触发信息；item: Redis 原始条目（用于准确删除）
func SpotAddPositionTrigger(db *gorm.DB, v *positiondto.AddPositionList, item string, spotApi SpotRestApi) {
	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, v.ApiId, v.Symbol), 20, 5, 100*time.Millisecond)

	if ok, err := lock.AcquireWait(context.Background()); err != nil {
		log.Error("获取锁失败", err)
		return
	} else if ok {
		defer lock.Release()

		setting, _ := cacheservice.GetSystemSetting(db)
		tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, v.Symbol, 1)

		if tradeSet.LastPrice == "" {
			log.Errorf("现货加仓触发 查询交易对失败 交易对：%s ordersn:%s", v.Symbol, v.OrderSn)
			return
		}

		key := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE)
		preOrder := DbModels.LinePreOrder{}
		if err := db.Where("id = ?", v.Id).First(&preOrder).Error; err != nil {
			log.Error("获取预下单失败", err)

			if errors.Is(err, gorm.ErrRecordNotFound) {
				log.Error("不存在待触发加仓主单", item)
				helper.DefaultRedis.LRem(key, item)
			}

			return
		}

		hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)

		if !hasrecord {
			log.Error("不存在待触发加仓主单", item)
			return
		}

		price := v.Price
		num, _ := decimal.NewFromString(preOrder.Num)

		if setting.AddPositionPremium.Cmp(decimal.Zero) > 0 {
			price = price.Mul(decimal.NewFromInt(1).Sub(setting.AddPositionPremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
		}

		params := OrderPlacementService{
			ApiId:            v.ApiId,
			Symbol:           v.Symbol,
			Side:             v.Side,
			Type:             preOrder.MainOrderType,
			TimeInForce:      "GTC",
			Price:            price,
			Quantity:         num.Truncate(int32(tradeSet.AmountDigit)),
			NewClientOrderId: v.OrderSn,
		}
		if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
			log.Error("下单失败", v.Symbol, " err:", err)
			err := db.Model(&DbModels.LinePreOrder{}).Where("id =? AND status =0", preOrder.Id).Updates(map[string]interface{}{"status": "2", "desc": err.Error()}).Error

			if err != nil {
				log.Error("下单失败后修改订单失败")
			}
			if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
				log.Error("删除redis 预下单失败:", err)
			}

			return
		}
		if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
			log.Error("删除redis 预下单失败:", err)
		}

		if err := db.Model(&DbModels.LinePreOrder{}).Where("id =?", preOrder.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil {
			log.Error("更新预下单触发事件失败 ordersn:", v.OrderSn)
		}

		if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? AND status ='0'", preOrder.Id).Updates(map[string]interface{}{"status": "1"}).Error; err != nil {
			log.Error("更新预下单状态失败 ordersn:", v.OrderSn, " status:1")
		}
		return
	} else {
		log.Error("获取锁失败")
		return
	}
}

// 触发现货止盈
func SpotTakeProfitTrigger(db *gorm.DB, takeOrder dto.TakeProfitRedisList, spotApi SpotRestApi, setting DbModels.LineSystemSetting, tradeSet models.TradeSet, key string, item string) {
	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, takeOrder.ApiId, takeOrder.Symbol), 20, 5, 100*time.Millisecond)

	if ok, err := lock.AcquireWait(context.Background()); err != nil {
		log.Error("获取锁失败", err)
		return
	} else if ok {
		defer lock.Release()
		stopOrder := DbModels.LinePreOrder{}
		if err := db.Model(&DbModels.LinePreOrder{}).
			Where("pid =? AND order_type =2", takeOrder.PId).
			Find(&stopOrder).Error; err != nil {
			log.Error("查询止盈单失败")
			return
		}

		hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item)

		if !hasrecord {
			log.Debug("止损缓存中不存在", item)
			return
		}

		apiInfo, _ := GetApiInfo(takeOrder.ApiId)

		if apiInfo.Id == 0 {
			log.Error("现货止盈 查询api用户不存在")
			return
		}

		// 使用统一的撤单重试封装，确保行为一致且高效
		if err := CancelOpenOrderByOrderSnLoop(apiInfo, stopOrder.Symbol, stopOrder.OrderSn); err != nil {
			log.Error("现货止盈撤单失败", err)
			return
		}
		price := takeOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.StopLossPremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
		num := utility.StrToDecimal(stopOrder.Num).Truncate(int32(tradeSet.AmountDigit))

		params := OrderPlacementService{
			ApiId:            takeOrder.ApiId,
			Side:             takeOrder.Site,
			Type:             "TAKE_PROFIT_Market",
			TimeInForce:      "GTC",
			Symbol:           takeOrder.Symbol,
			Price:            price,
			Quantity:         num,
			NewClientOrderId: takeOrder.OrderSn,
		}

		if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
			log.Errorf("现货止盈挂单失败 id：%s err:%v", takeOrder.Id, err)
		} else {
			if err := db.Model(&DbModels.LinePreOrder{}).
				Where("id = ? ", takeOrder.Id).
				Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil {
				log.Errorf("现货止盈更新状态失败 id：%s err:%v", takeOrder.Id, err)
			}
		}

		if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
			log.Errorf("现货止盈 删除缓存失败 id:%v err:%v", takeOrder.Id, err)
		}
	} else {
		log.Error("获取锁失败")
	}
}
