493 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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 JudgeFuturesPrice(tradeSet models.TradeSet) {
 | ||
| 	preOrderVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.PreFutOrderList, global.EXCHANGE_BINANCE))
 | ||
| 	db := commonservice.GetDBConnection()
 | ||
| 
 | ||
| 	if len(preOrderVal) == 0 {
 | ||
| 		return
 | ||
| 	}
 | ||
| 	futApi := FutRestApi{}
 | ||
| 
 | ||
| 	for _, item := range preOrderVal {
 | ||
| 		preOrder := dto.PreOrderRedisList{}
 | ||
| 		if err := sonic.Unmarshal([]byte(item), &preOrder); err != nil {
 | ||
| 			log.Error("反序列化失败")
 | ||
| 			continue
 | ||
| 		}
 | ||
| 
 | ||
| 		if preOrder.Symbol != tradeSet.Coin+tradeSet.Currency {
 | ||
| 			continue
 | ||
| 		}
 | ||
| 
 | ||
| 		orderPrice, _ := decimal.NewFromString(preOrder.Price)
 | ||
| 		tradePrice, _ := decimal.NewFromString(tradeSet.LastPrice)
 | ||
| 
 | ||
| 		if orderPrice.Cmp(decimal.Zero) == 0 || tradePrice.Cmp(decimal.Zero) == 0 {
 | ||
| 			continue
 | ||
| 		}
 | ||
| 
 | ||
| 		//多
 | ||
| 		if (strings.ToUpper(preOrder.Site) == "BUY" && orderPrice.Cmp(tradePrice) >= 0) ||
 | ||
| 			(strings.ToUpper(preOrder.Site) == "SELL" && orderPrice.Cmp(tradePrice) <= 0) {
 | ||
| 			futTriggerOrder(db, &preOrder, item, futApi)
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // 分布式锁下单
 | ||
| func futTriggerOrder(db *gorm.DB, v *dto.PreOrderRedisList, item string, futApi FutRestApi) {
 | ||
| 	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotTrigger, v.ApiId, v.Symbol), 200, 5, 100*time.Millisecond)
 | ||
| 
 | ||
| 	if ok, err := lock.AcquireWait(context.Background()); err != nil {
 | ||
| 		log.Debug("获取锁失败", err)
 | ||
| 		return
 | ||
| 	} else if ok {
 | ||
| 		defer lock.Release()
 | ||
| 
 | ||
| 		key := fmt.Sprintf(rediskey.PreFutOrderList, 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.Debug("预下单缓存中不存在", item)
 | ||
| 			return
 | ||
| 		}
 | ||
| 
 | ||
| 		price, _ := decimal.NewFromString(v.Price)
 | ||
| 		num, _ := decimal.NewFromString(preOrder.Num)
 | ||
| 
 | ||
| 		if price.Cmp(decimal.Zero) == 0 {
 | ||
| 			log.Error("价格不能为0")
 | ||
| 			return
 | ||
| 		}
 | ||
| 
 | ||
| 		params := FutOrderPlace{
 | ||
| 			ApiId:            v.ApiId,
 | ||
| 			Symbol:           v.Symbol,
 | ||
| 			Side:             v.Site,
 | ||
| 			OrderType:        preOrder.MainOrderType,
 | ||
| 			SideType:         preOrder.MainOrderType,
 | ||
| 			Price:            price,
 | ||
| 			Quantity:         num,
 | ||
| 			NewClientOrderId: v.OrderSn,
 | ||
| 		}
 | ||
| 		preOrderVal, _ := sonic.MarshalString(&v)
 | ||
| 
 | ||
| 		if err := futApi.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 preOrderVal != "" {
 | ||
| 				if _, err := helper.DefaultRedis.LRem(key, preOrderVal); err != nil {
 | ||
| 					log.Error("删除redis 预下单失败:", err)
 | ||
| 				}
 | ||
| 			}
 | ||
| 
 | ||
| 			return
 | ||
| 		}
 | ||
| 
 | ||
| 		if preOrderVal != "" {
 | ||
| 			if _, err := helper.DefaultRedis.LRem(key, preOrderVal); 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:", preOrder.OrderSn, " status:1")
 | ||
| 		}
 | ||
| 
 | ||
| 		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 JudgeFuturesReduce(trade models.TradeSet) {
 | ||
| 	key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
 | ||
| 	reduceVal, _ := helper.DefaultRedis.GetAllList(key)
 | ||
| 
 | ||
| 	db := commonservice.GetDBConnection()
 | ||
| 	futApi := FutRestApi{}
 | ||
| 	setting, err := cacheservice.GetSystemSetting(db)
 | ||
| 
 | ||
| 	if err != nil {
 | ||
| 		log.Error("获取系统设置失败")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	reduceOrder := positiondto.ReduceListItem{}
 | ||
| 	tradePrice, _ := decimal.NewFromString(trade.LastPrice)
 | ||
| 	//减仓单减仓策略
 | ||
| 	reduceReduceListKey := fmt.Sprintf(rediskey.FutOrderReduceStrategyList, 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 && !item2.Actived {
 | ||
| 				//买入
 | ||
| 				if item2.TriggerPrice.Cmp(decimal.Zero) > 0 &&
 | ||
| 					tradePrice.Cmp(decimal.Zero) > 0 &&
 | ||
| 					((strings.ToUpper(reduceOrderStrategy.Side) == "SELL" && item2.TriggerPrice.Cmp(tradePrice) >= 0) ||
 | ||
| 						(strings.ToUpper(reduceOrderStrategy.Side) == "BUY" && item2.TriggerPrice.Cmp(tradePrice) <= 0)) {
 | ||
| 					lock := helper.NewRedisLock(fmt.Sprintf(rediskey.ReduceStrategyFutTriggerLock, 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 FuturesReduceTrigger(db, reduceOrder, futApi, 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())
 | ||
| 								}
 | ||
| 							}
 | ||
| 						}
 | ||
| 					}
 | ||
| 				}
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	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 orderPrice.Cmp(decimal.Zero) > 0 &&
 | ||
| 				tradePrice.Cmp(decimal.Zero) > 0 &&
 | ||
| 				((strings.ToUpper(reduceOrder.Side) == "SELL" && orderPrice.Cmp(tradePrice) >= 0) ||
 | ||
| 					(strings.ToUpper(reduceOrder.Side) == "BUY" && orderPrice.Cmp(tradePrice) <= 0)) {
 | ||
| 
 | ||
| 				FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false, 0)
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // 触发合约减仓
 | ||
| // isStrategy 是否是策略减仓
 | ||
| // reduceId 父减仓单id
 | ||
| func FuturesReduceTrigger(db *gorm.DB, reduceOrder positiondto.ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool, reduceId int) bool {
 | ||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 2)
 | ||
| 	result := true
 | ||
| 
 | ||
| 	if tradeSet.LastPrice == "" {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 
 | ||
| 	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutTrigger, 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 := CancelFutOrderByOrderSnLoop(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))
 | ||
| 		num := reduceOrder.Num.Truncate(int32(tradeSet.AmountDigit))
 | ||
| 		var positionSide string
 | ||
| 
 | ||
| 		if reduceOrder.Side == "BUY" {
 | ||
| 			positionSide = "SHORT"
 | ||
| 		} else {
 | ||
| 			positionSide = "LONG"
 | ||
| 		}
 | ||
| 
 | ||
| 		if err := futApi.ClosePositionLoop(reduceOrder.Symbol, reduceOrder.OrderSn, num, reduceOrder.Side, positionSide, apiInfo, "LIMIT", "0", price, 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, " status:1")
 | ||
| 			}
 | ||
| 
 | ||
| 			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, 2, tradeSet, setting); err != nil {
 | ||
| 				log.Errorf("合约减仓策略处理失败 id:%s err:%v", reduceOrder.Id, err)
 | ||
| 			}
 | ||
| 		}
 | ||
| 
 | ||
| 		if !isStrategy {
 | ||
| 			if _, err := helper.DefaultRedis.LRem(key, item); err != nil {
 | ||
| 				log.Errorf("合约减仓 删除缓存失败 id:%v err:%v", reduceOrder.Id, err)
 | ||
| 			}
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		log.Error("获取锁失败")
 | ||
| 		result = false
 | ||
| 	}
 | ||
| 
 | ||
| 	return result
 | ||
| }
 | ||
| 
 | ||
| // 判断合约加仓
 | ||
| func JudgeFutAddPosition(trade models.TradeSet) {
 | ||
| 	key := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE)
 | ||
| 	preOrderVal, _ := helper.DefaultRedis.GetAllList(key)
 | ||
| 	db := commonservice.GetDBConnection()
 | ||
| 
 | ||
| 	if len(preOrderVal) == 0 {
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	futApi := FutRestApi{}
 | ||
| 	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 orderPrice.Cmp(decimal.Zero) == 0 || tradePrice.Cmp(decimal.Zero) == 0 {
 | ||
| 				continue
 | ||
| 			}
 | ||
| 
 | ||
| 			//多
 | ||
| 			if (strings.ToUpper(preOrder.Side) == "BUY" && orderPrice.Cmp(tradePrice) >= 0) ||
 | ||
| 				(strings.ToUpper(preOrder.Side) == "SELL" && orderPrice.Cmp(tradePrice) <= 0) {
 | ||
| 				FutAddPositionTrigger(db, &preOrder, item, futApi)
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // 合约加仓触发
 | ||
| func FutAddPositionTrigger(db *gorm.DB, v *positiondto.AddPositionList, item string, futApi FutRestApi) {
 | ||
| 	lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutTrigger, 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, 2)
 | ||
| 
 | ||
| 		if tradeSet.LastPrice == "" {
 | ||
| 			log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
 | ||
| 			return
 | ||
| 		}
 | ||
| 
 | ||
| 		key := fmt.Sprintf(rediskey.FuturesAddPositionList, 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.Truncate(int32(tradeSet.PriceDigit))
 | ||
| 		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 := FutOrderPlace{
 | ||
| 			ApiId:            v.ApiId,
 | ||
| 			Symbol:           v.Symbol,
 | ||
| 			Side:             v.Side,
 | ||
| 			OrderType:        "LIMIT",
 | ||
| 			Price:            price,
 | ||
| 			Quantity:         num.Truncate(int32(tradeSet.AmountDigit)),
 | ||
| 			NewClientOrderId: v.OrderSn,
 | ||
| 		}
 | ||
| 		preOrderVal, _ := sonic.MarshalString(&v)
 | ||
| 
 | ||
| 		if err := futApi.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 preOrderVal != "" {
 | ||
| 				if _, err := helper.DefaultRedis.LRem(key, preOrderVal); err != nil {
 | ||
| 					log.Error("删除redis 预下单失败:", err)
 | ||
| 				}
 | ||
| 			}
 | ||
| 
 | ||
| 			return
 | ||
| 		}
 | ||
| 
 | ||
| 		if preOrderVal != "" {
 | ||
| 			if _, err := helper.DefaultRedis.LRem(key, preOrderVal); 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")
 | ||
| 		}
 | ||
| 
 | ||
| 		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
 | ||
| 	}
 | ||
| }
 |