1、阶段减仓
This commit is contained in:
		| @ -11,6 +11,7 @@ type LineReduceStrategyItem struct { | ||||
|  | ||||
| 	ReduceStrategyId int                `json:"reduceStrategyId" gorm:"type:bigint;comment:减仓策略id"` | ||||
| 	LossPercent      decimal.Decimal    `json:"lossPercent" gorm:"type:decimal(10,2);comment:亏损百分比"` | ||||
| 	QuantityPercent  decimal.Decimal    `json:"quantityPercent" gorm:"type:decimal(10,2);comment:减仓数量百分比"` | ||||
| 	OrderType        string             `json:"orderType" gorm:"type:varchar(20);comment:订单类型 LIMIT-限价 MARKET-市价"` | ||||
| 	ReduceStrategy   LineReduceStrategy `json:"reduceStrategy" gorm:"foreignKey:ReduceStrategyId;"` | ||||
| 	models.ModelTime | ||||
|  | ||||
| @ -3,7 +3,8 @@ package dto | ||||
| import "github.com/shopspring/decimal" | ||||
|  | ||||
| type LineOrderReduceStrategyResp struct { | ||||
| 	OrderId int                               `json:"orderId"` | ||||
| 	MainId  int                               `json:"mainId" comment:"主单id"` | ||||
| 	OrderId int                               `json:"orderId" comment:"减仓单id"` | ||||
| 	Symbol  string                            `json:"symbol"` | ||||
| 	Side    string                            `json:"side" comment:"BUY SELL"` | ||||
| 	Items   []LineOrderReduceStrategyRespItem `json:"items"` | ||||
| @ -12,6 +13,7 @@ type LineOrderReduceStrategyResp struct { | ||||
| // 减仓节点 | ||||
| type LineOrderReduceStrategyRespItem struct { | ||||
| 	Price        decimal.Decimal `json:"p" comment:"下单价"` | ||||
| 	Num          decimal.Decimal `json:"n" comment:"下单数量"` | ||||
| 	TriggerPrice decimal.Decimal `json:"t" comment:"触发价"` | ||||
| 	LossPercent  decimal.Decimal `json:"l" comment:"亏损百分比"` | ||||
| 	OrderType    string          `json:"o" comment:"订单类型 LIMIT-限价 MARKET-市价"` | ||||
|  | ||||
| @ -56,7 +56,7 @@ func (s *LineReduceStrategyInsertReq) Valid() error { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if index > 0 && item.LossPercent.Cmp(s.Items[index].LossPercent) <= 0 { | ||||
| 		if index > 0 && item.LossPercent.Cmp(s.Items[index-1].LossPercent) <= 0 { | ||||
| 			return errors.New("亏损比例必须递增") | ||||
| 		} | ||||
| 	} | ||||
| @ -75,6 +75,7 @@ func (s *LineReduceStrategyInsertReq) Generate(model *models.LineReduceStrategy) | ||||
| 		strategyItem := models.LineReduceStrategyItem{} | ||||
| 		strategyItem.OrderType = item.OrderType | ||||
| 		strategyItem.LossPercent = item.LossPercent | ||||
| 		strategyItem.QuantityPercent = item.QuantityPercent | ||||
|  | ||||
| 		model.Items = append(model.Items, strategyItem) | ||||
| 	} | ||||
| @ -105,6 +106,7 @@ func (s *LineReduceStrategyUpdateReq) Generate(model *models.LineReduceStrategy) | ||||
| 		strategyItem := models.LineReduceStrategyItem{} | ||||
| 		strategyItem.OrderType = item.OrderType | ||||
| 		strategyItem.LossPercent = item.LossPercent | ||||
| 		strategyItem.QuantityPercent = item.QuantityPercent | ||||
|  | ||||
| 		model.Items = append(model.Items, strategyItem) | ||||
| 	} | ||||
|  | ||||
| @ -32,8 +32,9 @@ func (m *LineReduceStrategyItemGetPageReq) GetNeedSearch() interface{} { | ||||
| } | ||||
|  | ||||
| type LineReduceStrategyItem struct { | ||||
| 	LossPercent decimal.Decimal `json:"lossPercent" comment:"止损百分比"` | ||||
| 	OrderType   string          `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"` | ||||
| 	LossPercent     decimal.Decimal `json:"lossPercent" comment:"止损百分比"` | ||||
| 	QuantityPercent decimal.Decimal `json:"quantityPercent" comment:"数量百分比"` | ||||
| 	OrderType       string          `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"` | ||||
| } | ||||
|  | ||||
| func (s *LineReduceStrategyItem) Valid() error { | ||||
| @ -46,6 +47,14 @@ func (s *LineReduceStrategyItem) Valid() error { | ||||
| 		return errors.New("百分比不能大于等于100") | ||||
| 	} | ||||
|  | ||||
| 	if s.QuantityPercent.Cmp(decimal.Zero) <= 0 { | ||||
| 		return errors.New("百分比不能小于等于0") | ||||
| 	} | ||||
|  | ||||
| 	if s.QuantityPercent.Cmp(decimal.NewFromInt(100)) >= 0 { | ||||
| 		return errors.New("数量百分比不能大于等于100") | ||||
| 	} | ||||
|  | ||||
| 	keys := []string{"LIMIT", "MARKET"} | ||||
|  | ||||
| 	if !utility.ContainsStr(keys, s.OrderType) { | ||||
|  | ||||
| @ -1042,6 +1042,7 @@ func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrder | ||||
| // 构建止盈、止盈止损 | ||||
| func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) { | ||||
| 	orders := make([]models.LinePreOrder, 0) | ||||
| 	mainId := preOrder.Id | ||||
| 	var side string | ||||
|  | ||||
| 	if (preOrder.OrderType != 0 && strings.ToUpper(preOrder.Site) == "BUY") || (preOrder.OrderType == 0 && strings.ToUpper(preOrder.Site) == "SELL") { | ||||
| @ -1050,6 +1051,10 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO | ||||
| 		side = "SELL" | ||||
| 	} | ||||
|  | ||||
| 	if preOrder.MainId > 0 { | ||||
| 		mainId = preOrder.MainId | ||||
| 	} | ||||
|  | ||||
| 	if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 { | ||||
| 		// 止盈单 | ||||
| 		profitOrder := models.LinePreOrder{} | ||||
| @ -1060,11 +1065,7 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO | ||||
| 		profitOrder.Pid = preOrder.Id | ||||
| 		profitOrder.OrderType = 1 | ||||
| 		profitOrder.Status = 0 | ||||
| 		profitOrder.MainId = preOrder.Id | ||||
|  | ||||
| 		if preOrder.MainId > 0 { | ||||
| 			profitOrder.MainId = preOrder.MainId | ||||
| 		} | ||||
| 		profitOrder.MainId = mainId | ||||
| 		profitOrder.BuyPrice = "0" | ||||
| 		profitOrder.Site = side | ||||
|  | ||||
| @ -1090,7 +1091,7 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO | ||||
| 		lossOrder.Pid = preOrder.Id | ||||
| 		lossOrder.OrderType = 2 | ||||
| 		lossOrder.Status = 0 | ||||
| 		lossOrder.MainId = preOrder.MainId | ||||
| 		lossOrder.MainId = mainId | ||||
| 		lossOrder.BuyPrice = "0" | ||||
| 		lossOrder.Num = ext.TotalAfter.Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 		lossOrder.Rate = ext.StopLossRatio.Truncate(2).String() | ||||
| @ -1611,6 +1612,10 @@ func (e *LinePreOrder) ClearAll() error { | ||||
| 		"futures_reduce_list", | ||||
| 		"spot_reduce_strategy_list", | ||||
| 		"fut_reduce_strategy_list", | ||||
| 		"future_position", | ||||
| 		"spot_position", | ||||
| 		"strategy_spot_order_list", | ||||
| 		"strategy_fut_order_list", | ||||
| 	} | ||||
| 	err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...) | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -26,9 +26,9 @@ const ( | ||||
| 	PreFutOrderList    = "_PreFutOrderList_:%s"  // 待触发的订单集合 {交易所类型 exchange_type} | ||||
|  | ||||
| 	//策略现货订单集合 {交易所类型 exchange_type} | ||||
| 	StrategySpotOrderList = "strategy_spot_order_list_%s" | ||||
| 	StrategySpotOrderList = "strategy_spot_order_list:%s" | ||||
| 	//策略合约订单集合 {交易所类型 exchange_type} | ||||
| 	StrategyFutOrderList = "strategy_fut_order_list_%s" | ||||
| 	StrategyFutOrderList = "strategy_fut_order_list:%s" | ||||
|  | ||||
| 	API_USER      = "api_user:%v"    // api用户 | ||||
| 	SystemSetting = "system_setting" //系统设置 | ||||
| @ -51,6 +51,11 @@ const ( | ||||
| 	//波段合约触发{apiuserid|symbol} | ||||
| 	StrategyFutTriggerLock = "strategy_fut_trigger_l:%v_%s" | ||||
|  | ||||
| 	//减仓波段合约触发 {apiuserid|symbol} | ||||
| 	ReduceStrategyFutTriggerLock = "reduce_strategy_fut_trigger_l:%v_%s" | ||||
| 	//减仓波段现货触发 {apiuserid|symbol} | ||||
| 	ReduceStrategySpotTriggerLock = "reduce_strategy_spot_trigger_l:%v_%s" | ||||
|  | ||||
| 	SpotCallBack = "spot_callback:%s" //现货回调 {ordersn} | ||||
| 	FutCallBack  = "fut_callback:%s"  //合约回调 {ordersn} | ||||
|  | ||||
|  | ||||
							
								
								
									
										63
									
								
								services/binanceservice/futures_judge_service_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								services/binanceservice/futures_judge_service_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| package binanceservice | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go-admin/common/const/rediskey" | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	"go-admin/models" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk" | ||||
| 	"gorm.io/driver/mysql" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
|  | ||||
| func TestFutureJudge(t *testing.T) { | ||||
| 	dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" | ||||
| 	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | ||||
| 	helper.InitDefaultRedis("127.0.0.1:6379", "", 2) | ||||
| 	helper.InitLockRedisConn("127.0.0.1:6379", "", "2") | ||||
| 	// tradeSet := models.TradeSet{ | ||||
| 	// 	Coin:      "ADA", | ||||
| 	// 	Currency:  "USDT", | ||||
| 	// 	LastPrice: "0.516", | ||||
| 	// } | ||||
|  | ||||
| 	key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE) | ||||
| 	item := `{"id":4,"apiId":49,"mainId":1,"pid":1,"symbol":"ADAUSDT","price":"0.5417","side":"SELL","num":"13","orderSn":"397659701065547776"}` | ||||
| 	reduceOrder := ReduceListItem{} | ||||
| 	futApi := FutRestApi{} | ||||
| 	setting, err := cacheservice.GetSystemSetting(db) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		logger.Error("获取系统设置失败") | ||||
| 		return | ||||
| 	} | ||||
| 	if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil { | ||||
| 		logger.Error("反序列化失败") | ||||
| 		return | ||||
| 	} | ||||
| 	// JudgeFuturesReduce(tradeSet) | ||||
| 	FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false) | ||||
| } | ||||
|  | ||||
| // 测试减仓后减仓触发 | ||||
| func TestFutureReduceReduce(t *testing.T) { | ||||
| 	dsn := "root:123456@tcp(127.0.0.1:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" | ||||
| 	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | ||||
| 	sdk.Runtime.SetDb("default", db) | ||||
| 	helper.InitDefaultRedis("127.0.0.1:6379", "", 2) | ||||
| 	helper.InitLockRedisConn("127.0.0.1:6379", "", "2") | ||||
| 	tradeSet := models.TradeSet{ | ||||
| 		Coin:      "ADA", | ||||
| 		Currency:  "USDT", | ||||
| 		LastPrice: "0.5307", | ||||
| 	} | ||||
|  | ||||
| 	// JudgeFuturesReduce(tradeSet) | ||||
| 	JudgeFuturesReduce(tradeSet) | ||||
| } | ||||
| @ -10,6 +10,7 @@ import ( | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	"go-admin/models" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/services/cacheservice" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| @ -161,30 +162,83 @@ func JudgeFuturesReduce(trade models.TradeSet) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	reduceOrder := ReduceListItem{} | ||||
| 	tradePrice, _ := decimal.NewFromString(trade.LastPrice) | ||||
| 	//减仓单减仓策略 | ||||
| 	orderReduceVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)) | ||||
| 	reduceReduceListKey := fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE) | ||||
| 	orderReduceVal, _ := helper.DefaultRedis.HGetAllFields(reduceReduceListKey) | ||||
| 	reduceOrderStrategy := dto.LineOrderReduceStrategyResp{} | ||||
|  | ||||
| 	for _, item := range orderReduceVal { | ||||
| 		sonic.Unmarshal([]byte(item), &reduceOrderStrategy) | ||||
|  | ||||
| 		for _, item2 := range reduceOrderStrategy.Items { | ||||
| 			if reduceOrderStrategy.Symbol == trade.Coin+trade.Currency { | ||||
| 		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)) { | ||||
| 					//todo 生成订单并触发 | ||||
| 					// SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item) | ||||
| 					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.IsElementInList(reduceReduceListKey, item) | ||||
|  | ||||
| 						if !hasrecord { | ||||
| 							log.Debug("减仓缓存中不存在", item) | ||||
| 							return | ||||
| 						} | ||||
|  | ||||
| 						order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.AmountDigit) | ||||
|  | ||||
| 						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.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 { | ||||
| 		reduceOrder := ReduceListItem{} | ||||
| 		if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil { | ||||
| 			log.Error("反序列化失败") | ||||
| 			continue | ||||
| @ -198,52 +252,54 @@ func JudgeFuturesReduce(trade models.TradeSet) { | ||||
| 				((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) | ||||
| 				FuturesReduceTrigger(db, reduceOrder, futApi, setting, key, item, false) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 触发合约减仓 | ||||
| func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string) { | ||||
| // isStrategy 是否是策略减仓 | ||||
| func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool) bool { | ||||
| 	tradeSet, _ := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 1) | ||||
| 	result := true | ||||
|  | ||||
| 	if tradeSet.LastPrice == "" { | ||||
| 		return | ||||
| 		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 | ||||
| 		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 =1 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil { | ||||
| 		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 | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item) | ||||
|  | ||||
| 		if !hasrecord { | ||||
| 			log.Debug("减仓缓存中不存在", item) | ||||
| 			return | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		apiInfo, _ := GetApiInfo(reduceOrder.ApiId) | ||||
|  | ||||
| 		if apiInfo.Id == 0 { | ||||
| 			log.Error("现货减仓 查询api用户不存在") | ||||
| 			return | ||||
| 			return false | ||||
| 		} | ||||
| 		for _, takeOrder := range takeOrders { | ||||
| 			err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				log.Error("合约止盈撤单失败", err) | ||||
| 				return | ||||
| 				log.Error("撤单失败", err) | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @ -258,6 +314,7 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes | ||||
| 		} | ||||
|  | ||||
| 		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{}). | ||||
| @ -276,15 +333,22 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes | ||||
| 			} | ||||
|  | ||||
| 			//处理减仓单减仓策略 | ||||
| 			CacheOrderStrategyAndReCreate(db, reduceOrder, 2, tradeSet, setting) | ||||
| 			if err := CacheOrderStrategyAndReCreate(db, reduceOrder, 2, tradeSet, setting); err != nil { | ||||
| 				log.Errorf("合约减仓策略处理失败 id:%s err:%v", reduceOrder.Id, err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if _, err := helper.DefaultRedis.LRem(key, item); err != nil { | ||||
| 			log.Errorf("合约减仓 删除缓存失败 id:%v 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 | ||||
| } | ||||
|  | ||||
| // 判断合约加仓 | ||||
|  | ||||
| @ -163,9 +163,9 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 		positionData := savePosition(db, preOrder) | ||||
|  | ||||
| 		//市价单就跳出 市价减仓不设止盈止损 | ||||
| 		if preOrder.MainOrderType == "MARKET" { | ||||
| 			return | ||||
| 		} | ||||
| 		// if preOrder.MainOrderType == "MARKET" { | ||||
| 		// 	return | ||||
| 		// } | ||||
|  | ||||
| 		//亏损大于0 重新计算比例 | ||||
| 		FutTakeProfit(db, preOrder, apiUserInfo, tradeSet, positionData, orderExt, decimal.Zero, decimal.Zero) | ||||
| @ -435,6 +435,8 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) { | ||||
| 	stoploss := dto.StopLossRedisList{} | ||||
| 	addPosition := AddPositionList{} | ||||
| 	reduce := ReduceListItem{} | ||||
| 	//移除减仓后减仓策略 | ||||
| 	RemoveReduceReduceCacheByMainId(mainId, 2) | ||||
|  | ||||
| 	//止损缓存 | ||||
| 	for _, v := range stoplossVal { | ||||
| @ -598,7 +600,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			processFutStopLossOrder(db, order, price, num) | ||||
| 			processFutStopLossOrder(db, order, utility.StrToDecimal(order.Price), num) | ||||
| 			// case 4: // 减仓 | ||||
| 			// processFutReduceOrder(order, price, num) | ||||
| 		} | ||||
| @ -700,9 +702,13 @@ func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *model | ||||
| 	// 	order.Num = num.String() | ||||
| 	// } else | ||||
|  | ||||
| 	if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && order.OrderType == 1 && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 	//止盈止损重算数量 | ||||
| 	if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 		// 计算止盈数量 | ||||
| 		num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		if order.OrderType == 1 { | ||||
| 			num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		} | ||||
|  | ||||
| 		order.Num = num.String() | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @ -1,10 +1,15 @@ | ||||
| package binanceservice | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go-admin/app/admin/models" | ||||
| 	DbModels "go-admin/app/admin/models" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/pkg/utility/snowflakehelper" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| 	"github.com/jinzhu/copier" | ||||
| 	"github.com/shopspring/decimal" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
| @ -170,3 +175,68 @@ func GetChildTpOrder(db *gorm.DB, pid int) (int, error) { | ||||
|  | ||||
| 	return int(count), nil | ||||
| } | ||||
|  | ||||
| // 创建减仓后减仓单 | ||||
| func CreateReduceReduceOrder(db *gorm.DB, pid int, price, num decimal.Decimal, amountDigit int) (models.LinePreOrder, error) { | ||||
| 	var preOrder models.LinePreOrder | ||||
| 	var result models.LinePreOrder | ||||
| 	var ext models.LinePreOrderExt | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrder{}).Preload("Childs").Where("id =? ", pid).First(&preOrder).Error; err != nil { | ||||
| 		return preOrder, err | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? ", pid).Find(&ext).Error; err != nil { | ||||
| 		return preOrder, err | ||||
| 	} | ||||
|  | ||||
| 	copier.Copy(&result, &preOrder) | ||||
|  | ||||
| 	result.Id = 0 | ||||
| 	result.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) | ||||
| 	result.Status = 0 | ||||
| 	result.CreatedAt = time.Now() | ||||
| 	result.TriggerTime = nil | ||||
| 	result.UpdatedAt = time.Now() | ||||
| 	result.BuyPrice = decimal.Zero.String() | ||||
| 	result.Price = price.String() | ||||
| 	result.Num = num.String() | ||||
|  | ||||
| 	for index := range result.Childs { | ||||
| 		result.Childs[index].Id = 0 | ||||
| 		result.Childs[index].OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) | ||||
| 		result.Childs[index].Status = 0 | ||||
| 		result.Childs[index].CreatedAt = time.Now() | ||||
| 		result.Childs[index].TriggerTime = nil | ||||
| 		result.Childs[index].UpdatedAt = time.Now() | ||||
| 		result.Childs[index].BuyPrice = decimal.Zero.String() | ||||
| 		var pricePercent decimal.Decimal | ||||
|  | ||||
| 		if result.Childs[index].OrderType == 1 && ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 { | ||||
| 			// 减仓单卖出 | ||||
| 			if preOrder.Site == "SELL" { | ||||
| 				pricePercent = decimal.NewFromInt(100).Add(ext.TakeProfitRatio).Div(decimal.NewFromInt(100)) | ||||
| 			} else { | ||||
| 				pricePercent = decimal.NewFromInt(100).Sub(ext.TakeProfitRatio).Div(decimal.NewFromInt(100)) | ||||
| 			} | ||||
|  | ||||
| 		} else if result.Childs[index].OrderType == 2 && ext.StopLossRatio.Cmp(decimal.Zero) > 0 { | ||||
| 			if preOrder.Site == "SELL" { | ||||
| 				pricePercent = decimal.NewFromInt(100).Sub(ext.StopLossRatio).Div(decimal.NewFromInt(100)) | ||||
| 			} else { | ||||
| 				pricePercent = decimal.NewFromInt(100).Add(ext.StopLossRatio).Div(decimal.NewFromInt(100)) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		//重新计算止盈止损价 | ||||
| 		if pricePercent.Cmp(decimal.Zero) > 0 { | ||||
| 			result.Childs[index].Price = price.Mul(pricePercent).Truncate(int32(amountDigit)).String() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Create(&result).Error; err != nil { | ||||
| 		return result, fmt.Errorf("复制减仓单失败:pid:%d err:%v", pid, err) | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	models2 "go-admin/models" | ||||
| 	"go-admin/pkg/utility" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| @ -19,7 +20,7 @@ import ( | ||||
| // reduceOrder:原始减仓单 | ||||
| // reduceOrderStrategy:减仓策略 | ||||
| func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symbolType int, tradeSet models2.TradeSet, setting models.LineSystemSetting) error { | ||||
| 	reduceOrderStrategy := models.LineReduceStrategy{} | ||||
| 	reduceOrderStrategy := models.LineOrderReduceStrategy{} | ||||
| 	var key string | ||||
|  | ||||
| 	if symbolType == 1 { | ||||
| @ -28,21 +29,27 @@ func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symb | ||||
| 		key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE) | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Model(&reduceOrderStrategy).Where("order_id =?", reduceOrder.Id).Find(reduceOrderStrategy).Error; err != nil { | ||||
| 	if err := db.Model(&reduceOrderStrategy).Where("order_id =?", reduceOrder.Id).Find(&reduceOrderStrategy).Error; err != nil { | ||||
| 		logger.Errorf("获取减仓策略失败,err:%v", err) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if reduceOrderStrategy.Id > 0 { | ||||
| 		items := make([]models.LineReduceStrategyItem, 0) | ||||
| 		strategyCache := dto.LineOrderReduceStrategyResp{ | ||||
| 			OrderId: reduceOrder.Id, | ||||
| 			Symbol:  reduceOrder.Symbol, | ||||
| 			MainId:  reduceOrder.MainId, | ||||
| 			Side:    reduceOrder.Side, | ||||
| 		} | ||||
|  | ||||
| 		for _, item := range reduceOrderStrategy.Items { | ||||
| 		sonic.Unmarshal([]byte(reduceOrderStrategy.ItemContent), &items) | ||||
|  | ||||
| 		for _, item := range items { | ||||
| 			var rate decimal.Decimal | ||||
| 			var triggerRate decimal.Decimal | ||||
|  | ||||
| 			if reduceOrder.Side == "BUY" { | ||||
| 			if reduceOrder.Side == "SELL" { | ||||
| 				rate = (decimal.NewFromInt(100).Sub(item.LossPercent)).Div(decimal.NewFromInt(100)) | ||||
|  | ||||
| 				if setting.ReduceEarlyTriggerPercent.Cmp(decimal.Zero) > 0 { | ||||
| @ -61,19 +68,26 @@ func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symb | ||||
| 			} | ||||
| 			price := reduceOrder.Price.Mul(rate).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 			triggerPrice := reduceOrder.Price.Mul(triggerRate).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 			num := reduceOrder.Num | ||||
|  | ||||
| 			//百分比大于0就重新计算 否则就是主减仓单数量 | ||||
| 			if item.QuantityPercent.Cmp(decimal.Zero) > 0 { | ||||
| 				num = reduceOrder.Num.Mul(item.QuantityPercent.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 			} | ||||
|  | ||||
| 			strategyCache.Items = append(strategyCache.Items, dto.LineOrderReduceStrategyRespItem{ | ||||
| 				LossPercent:  item.LossPercent, | ||||
| 				OrderType:    item.OrderType, | ||||
| 				Price:        price, | ||||
| 				TriggerPrice: triggerPrice, | ||||
| 				Num:          num, | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		str, _ := sonic.MarshalString(reduceOrderStrategy) | ||||
| 		str, _ := sonic.MarshalString(strategyCache) | ||||
|  | ||||
| 		if str != "" { | ||||
| 			if err := helper.DefaultRedis.SetString(key, str); err != nil { | ||||
| 			if err := helper.DefaultRedis.HSetField(key, utility.IntToString(reduceOrder.Id), str); err != nil { | ||||
| 				logger.Errorf("减仓单缓存减仓策略,err:%v", err) | ||||
| 			} | ||||
| 		} | ||||
| @ -132,3 +146,33 @@ func ReduceCallBack(db *gorm.DB, preOrder *models.LinePreOrder) error { | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 移除减仓后减仓策略 | ||||
| // mainId 主单id | ||||
| // symbolType 交易对类型 | ||||
| func RemoveReduceReduceCacheByMainId(mainId int, symbolType int) error { | ||||
| 	var key string | ||||
| 	switch symbolType { | ||||
| 	case 1: | ||||
| 		key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE) | ||||
| 	case 2: | ||||
| 		key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE) | ||||
| 	default: | ||||
| 		return fmt.Errorf("交易对类型错误") | ||||
| 	} | ||||
|  | ||||
| 	arrays, _ := helper.DefaultRedis.HGetAllFields(key) | ||||
| 	cache := dto.LineOrderReduceStrategyResp{} | ||||
|  | ||||
| 	for _, v := range arrays { | ||||
| 		sonic.Unmarshal([]byte(v), &cache) | ||||
|  | ||||
| 		if cache.MainId == mainId { | ||||
| 			if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil { | ||||
| 				logger.Errorf("移除减仓单减仓策略失败redis err:%v", err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -266,23 +266,76 @@ func JudgeSpotReduce(trade models.TradeSet) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	reduceOrder := ReduceListItem{} | ||||
| 	tradePrice, _ := decimal.NewFromString(trade.LastPrice) | ||||
| 	//减仓单减仓策略 | ||||
| 	orderReduceVal, _ := helper.DefaultRedis.GetAllList(fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)) | ||||
| 	reduceReduceListKey := fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE) | ||||
| 	orderReduceVal, _ := helper.DefaultRedis.GetAllList(reduceReduceListKey) | ||||
| 	reduceOrderStrategy := dto.LineOrderReduceStrategyResp{} | ||||
|  | ||||
| 	for _, item := range orderReduceVal { | ||||
| 		sonic.Unmarshal([]byte(item), &reduceOrderStrategy) | ||||
|  | ||||
| 		for _, item2 := range reduceOrderStrategy.Items { | ||||
| 		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 { | ||||
| 					//todo 生成订单并触发 | ||||
| 					// SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item) | ||||
| 					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.IsElementInList(reduceReduceListKey, item) | ||||
|  | ||||
| 						if !hasrecord { | ||||
| 							log.Debug("减仓缓存中不存在", item) | ||||
| 							return | ||||
| 						} | ||||
|  | ||||
| 						order, err := CreateReduceReduceOrder(db, reduceOrderStrategy.OrderId, item2.Price, item2.Num, trade.AmountDigit) | ||||
|  | ||||
| 						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, key, item, true) { | ||||
| 							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()) | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @ -292,7 +345,6 @@ func JudgeSpotReduce(trade models.TradeSet) { | ||||
| 	reduceVal, _ := helper.DefaultRedis.GetAllList(key) | ||||
|  | ||||
| 	for _, item := range reduceVal { | ||||
| 		reduceOrder := ReduceListItem{} | ||||
| 		if err := sonic.Unmarshal([]byte(item), &reduceOrder); err != nil { | ||||
| 			log.Error("反序列化失败") | ||||
| 			continue | ||||
| @ -306,52 +358,53 @@ func JudgeSpotReduce(trade models.TradeSet) { | ||||
| 				orderPrice.Cmp(decimal.Zero) > 0 && | ||||
| 				tradePrice.Cmp(decimal.Zero) > 0 { | ||||
|  | ||||
| 				SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item) | ||||
| 				SpotReduceTrigger(db, reduceOrder, spotApi, setting, key, item, false) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 触发现货减仓 | ||||
| func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string) { | ||||
| func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRestApi, setting DbModels.LineSystemSetting, key, item string, isStrategy bool) bool { | ||||
| 	tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, reduceOrder.Symbol, 0) | ||||
| 	result := true | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error("获取交易设置失败") | ||||
| 		return | ||||
| 		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 | ||||
| 		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 =1 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil { | ||||
| 		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 | ||||
| 			return false | ||||
| 		} | ||||
| 		hasrecord, _ := helper.DefaultRedis.IsElementInList(key, item) | ||||
|  | ||||
| 		if !hasrecord { | ||||
| 			log.Debug("减仓缓存中不存在", item) | ||||
| 			return | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		apiInfo, _ := GetApiInfo(reduceOrder.ApiId) | ||||
|  | ||||
| 		if apiInfo.Id == 0 { | ||||
| 			log.Error("现货减仓 查询api用户不存在") | ||||
| 			return | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		for _, takeOrder := range takeOrders { | ||||
| 			err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				log.Error("现货止盈撤单失败", err) | ||||
| 				return | ||||
| 				log.Error("现货撤单失败", err) | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 		price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)) | ||||
| @ -368,6 +421,7 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest | ||||
| 		} | ||||
|  | ||||
| 		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{}). | ||||
| @ -387,15 +441,21 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest | ||||
| 			} | ||||
|  | ||||
| 			//处理减仓单减仓策略 | ||||
| 			CacheOrderStrategyAndReCreate(db, reduceOrder, 1, tradeSet, setting) | ||||
| 			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 | ||||
| } | ||||
|  | ||||
| // 判断现货加仓 | ||||
|  | ||||
| @ -550,6 +550,9 @@ func removeSpotLossAndAddPosition(mainId int, orderSn string) { | ||||
| 	addPosition := AddPositionList{} | ||||
| 	reduce := ReduceListItem{} | ||||
|  | ||||
| 	//移除减仓后减仓策略 | ||||
| 	RemoveReduceReduceCacheByMainId(mainId, 1) | ||||
|  | ||||
| 	//止损缓存 | ||||
| 	for _, v := range stoplossVal { | ||||
| 		sonic.Unmarshal([]byte(v), &stoploss) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user