拆分加仓、减仓
This commit is contained in:
		| @ -277,6 +277,10 @@ func (req LineAddPreOrderReq) Valid() error { | ||||
| 		return errors.New("主单减仓数量百分比不能为空") | ||||
| 	} | ||||
|  | ||||
| 	if req.ReducePriceRatio.IsZero() || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 { | ||||
| 		return errors.New("主单减仓价格百分比错误") | ||||
| 	} | ||||
|  | ||||
| 	for _, v := range req.Ext { | ||||
| 		name := "加仓" | ||||
|  | ||||
| @ -299,13 +303,17 @@ func (req LineAddPreOrderReq) Valid() error { | ||||
| 			return errors.New("止盈价格不正确") | ||||
| 		} | ||||
|  | ||||
| 		if v.TpTpPriceRatio.IsZero() || v.TpTpPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { | ||||
| 		if v.AddType == 1 && v.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 && | ||||
| 			v.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && | ||||
| 			(v.TpTpPriceRatio.IsZero() || v.TpTpPriceRatio.Cmp(decimal.NewFromInt(100)) > 0) { | ||||
| 			return errors.New("止盈后止盈价格不正确") | ||||
| 		} | ||||
|  | ||||
| 		if v.TpSlPriceRatio.Cmp(decimal.Zero) <= 0 || v.TpSlPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { | ||||
| 			return errors.New("止盈后止损价格不正确") | ||||
| 		} | ||||
| 		// if v.AddType == 1 && v.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 && | ||||
| 		// 	v.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && | ||||
| 		// 	(v.TpSlPriceRatio.Cmp(decimal.Zero) <= 0 || v.TpSlPriceRatio.Cmp(decimal.NewFromInt(100)) > 0) { | ||||
| 		// 	return errors.New("止盈后止损价格不正确") | ||||
| 		// } | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
|  | ||||
| @ -481,10 +481,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 		defultExt.TotalAfter = utility.StrToDecimal(AddOrder.Num).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		defultExt2.TotalBefore = defultExt.TotalAfter | ||||
| 		defultExt2.TotalAfter = mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio)).Div(decimal.NewFromInt(100)).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		defultExt2.ReTakeRatio = req.ReducePriceRatio.Div(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(2) | ||||
| 		preOrderExts = append(preOrderExts, defultExt) | ||||
|  | ||||
| 		calculateResp := dto.CalculateBreakEvenRatioResp{} | ||||
| 		mainParam := dto.CalculateBreakEevenRatioReq{ | ||||
| 			AddType:          2, | ||||
| 			Price:            mainPrice, | ||||
| 			ExchangeType:     req.ExchangeType, | ||||
| 			Symbol:           req.Symbol, | ||||
| @ -492,8 +494,8 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			BuyPrice:         buyPrice, | ||||
| 			LossBeginPercent: decimal.Zero, | ||||
| 			LossEndPercent:   req.ReducePriceRatio, | ||||
| 			AddPositionType:  2, | ||||
| 			AddPositionVal:   decimal.Zero, | ||||
| 			AddPositionType:  1, | ||||
| 			AddPositionVal:   req.ReduceNumRatio, | ||||
| 		} | ||||
|  | ||||
| 		//计算减仓后 | ||||
| @ -510,14 +512,17 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			ext := models.LinePreOrderExt{ | ||||
| 				AddType:            addPosition.AddType, | ||||
| 				OrderType:          addPosition.OrderType, | ||||
| 				PriceRatio:         addPosition.PriceRatio, | ||||
| 				TakeProfitRatio:    addPosition.TakeProfitRatio, | ||||
| 				TakeProfitNumRatio: addPosition.TakeProfitNumRatio, | ||||
| 				StopLossRatio:      addPosition.StopLossRatio, | ||||
| 				TpTpPriceRatio:     addPosition.TpTpPriceRatio, | ||||
| 				TpSlPriceRatio:     addPosition.TpSlPriceRatio, | ||||
| 				AddPositionType:    addPosition.AddPositionType, | ||||
| 				AddPositionVal:     addPosition.AddPositionVal, | ||||
| 			} | ||||
|  | ||||
| 			mainParam.AddType = addPosition.AddType | ||||
| 			mainParam.LossEndPercent = req.Ext[index].PriceRatio | ||||
| 			mainParam.AddPositionType = req.Ext[index].AddPositionType | ||||
| 			mainParam.AddPositionVal = req.Ext[index].AddPositionVal | ||||
| @ -623,7 +628,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 				tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder) | ||||
|  | ||||
| 				if req.ReduceNumRatio.Cmp(decimal.Zero) > 0 && req.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { | ||||
| 					if newOrders, err := makeReduceTakeAndStoploss(&stopOrder, defultExt, tradeSet); err != nil { | ||||
| 					if newOrders, err := makeReduceTakeAndStoploss(&stopOrder, defultExt2, tradeSet, false); err != nil { | ||||
| 						logger.Errorf("主单减仓生成止盈、减仓失败 err:%v", err) | ||||
| 						return err | ||||
| 					} else if len(newOrders) > 0 { | ||||
| @ -638,30 +643,30 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			//添加止盈单 | ||||
| 			for index, v := range preOrderExts { | ||||
| 				preOrderExts[index].MainOrderId = AddOrder.Id | ||||
| 				if index == 0 { | ||||
| 					preOrderExts[index].OrderId = AddOrder.Id | ||||
| 					continue | ||||
| 				} | ||||
| 				var AddOrder models.LinePreOrder | ||||
| 				// if index == 0 { | ||||
| 				// 	preOrderExts[index].OrderId = AddOrder.Id | ||||
| 				// 	continue | ||||
| 				// } | ||||
| 				var newOrder models.LinePreOrder | ||||
|  | ||||
| 				if v.AddType == 1 { | ||||
| 					AddOrder = createPreAddPosition(&AddOrder, v, tradeSet) | ||||
| 					newOrder = createPreAddPosition(&AddOrder, v, tradeSet) | ||||
| 				} else if v.AddType == 2 { | ||||
| 					AddOrder = createPreReduceOrder(&AddOrder, v, tradeSet) | ||||
| 					newOrder = createPreReduceOrder(&AddOrder, v, tradeSet) | ||||
| 				} | ||||
|  | ||||
| 				if AddOrder.OrderSn == "" { | ||||
| 				if newOrder.OrderSn == "" { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				if err := e.Orm.Create(&AddOrder).Error; err != nil { | ||||
| 				if err := e.Orm.Create(&newOrder).Error; err != nil { | ||||
| 					logger.Error("保存加仓单失败") | ||||
| 					return err | ||||
| 				} | ||||
|  | ||||
| 				preOrderExts[index].OrderId = AddOrder.Id | ||||
| 				preOrderExts[index].OrderId = newOrder.Id | ||||
| 				//止盈、减仓 | ||||
| 				orders, err := makeFuturesTakeAndReduce(&AddOrder, v, tradeSet) | ||||
| 				orders, err := makeFuturesTakeAndReduce(&newOrder, v, tradeSet) | ||||
|  | ||||
| 				if err != nil { | ||||
| 					logger.Error("构造止盈、止损失败") | ||||
| @ -676,7 +681,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 				for index := range orders { | ||||
| 					//减仓单且 减仓比例大于0 小于100 就冲下止盈止损 | ||||
| 					if orders[index].OrderType == 1 && v.TakeProfitRatio.Cmp(decimal.Zero) > 0 && v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) < 0 { | ||||
| 						reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet) | ||||
| 						reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet, true) | ||||
|  | ||||
| 						if err != nil { | ||||
| 							logger.Error("生产止盈后止盈、减仓失败") | ||||
| @ -722,6 +727,11 @@ func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderEx | ||||
| 	data.Pid = preOrder.Id | ||||
| 	data.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) | ||||
| 	data.MainId = preOrder.Id | ||||
|  | ||||
| 	if preOrder.MainId > 0 { | ||||
| 		data.MainId = preOrder.MainId | ||||
| 	} | ||||
|  | ||||
| 	data.CreatedAt = time.Now() | ||||
| 	data.MainOrderType = v.OrderType | ||||
| 	data.Status = 0 | ||||
| @ -761,12 +771,18 @@ func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrder | ||||
| 		stopOrder.Id = 0 | ||||
| 		stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) | ||||
| 		stopOrder.Pid = preOrder.Id | ||||
| 		stopOrder.MainId = preOrder.MainId | ||||
| 		stopOrder.MainId = preOrder.Id | ||||
|  | ||||
| 		if preOrder.MainId > 0 { | ||||
| 			stopOrder.MainId = preOrder.MainId | ||||
| 		} | ||||
|  | ||||
| 		stopOrder.OrderType = 4 | ||||
| 		stopOrder.Status = 0 | ||||
| 		stopOrder.Rate = ext.PriceRatio.String() | ||||
| 		stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 		stopOrder.BuyPrice = "0" | ||||
| 		stopOrder.Rate = ext.PriceRatio.String() | ||||
|  | ||||
| 		if strings.ToUpper(preOrder.Site) == "BUY" { | ||||
| 			stopOrder.Site = "SELL" | ||||
| @ -801,7 +817,11 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO | ||||
| 		profitOrder.Pid = preOrder.Id | ||||
| 		profitOrder.OrderType = 1 | ||||
| 		profitOrder.Status = 0 | ||||
| 		profitOrder.MainId = preOrder.MainId | ||||
| 		profitOrder.MainId = preOrder.Id | ||||
|  | ||||
| 		if preOrder.MainId > 0 { | ||||
| 			profitOrder.MainId = preOrder.MainId | ||||
| 		} | ||||
| 		profitOrder.BuyPrice = "0" | ||||
| 		profitOrder.Site = side | ||||
|  | ||||
| @ -877,16 +897,25 @@ func makeTpOrder(parentOrder *models.LinePreOrder, reminQuantity decimal.Decimal | ||||
| } | ||||
|  | ||||
| // 构建减仓后止盈止损 | ||||
| func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) { | ||||
| // isTpTp 是否止盈后止盈止损 | ||||
| func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet, isTpTp bool) ([]models.LinePreOrder, error) { | ||||
| 	orders := make([]models.LinePreOrder, 0) | ||||
| 	var num decimal.Decimal | ||||
| 	num := ext.TotalAfter | ||||
| 	var takeProfitRatio, slPriceRatio decimal.Decimal | ||||
| 	if isTpTp { | ||||
| 		takeProfitRatio = ext.TpTpPriceRatio | ||||
| 		slPriceRatio = ext.TpSlPriceRatio | ||||
| 	} else { | ||||
| 		takeProfitRatio = ext.TakeProfitRatio | ||||
| 		slPriceRatio = ext.StopLossRatio | ||||
| 	} | ||||
|  | ||||
| 	if ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { | ||||
| 		percent := decimal.NewFromInt(1).Sub(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))) | ||||
| 		num = ext.TotalAfter.Mul(percent).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	} | ||||
|  | ||||
| 	if ext.TpTpPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 { | ||||
| 	if takeProfitRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 { | ||||
| 		takeProfitOrder := models.LinePreOrder{} | ||||
| 		copier.Copy(&takeProfitOrder, parentOrder) | ||||
| 		takeProfitOrder.Id = 0 | ||||
| @ -894,21 +923,25 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line | ||||
| 		takeProfitOrder.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) | ||||
| 		takeProfitOrder.Status = 0 | ||||
| 		takeProfitOrder.OrderType = 1 | ||||
| 		takeProfitOrder.Rate = ext.TpTpPriceRatio.String() | ||||
| 		takeProfitOrder.SignPrice = parentOrder.Price | ||||
| 		takeProfitOrder.CreatedAt = time.Now() | ||||
| 		takeProfitOrder.BuyPrice = "0" | ||||
| 		takeProfitOrder.MainOrderType = "LIMIT" | ||||
| 		takeProfitOrder.Num = num.String() | ||||
| 		//止盈需要累加之前的亏损 | ||||
| 		takeProfitOrder.Rate = ext.TpTpPriceRatio.Truncate(2).String() | ||||
| 		if isTpTp { | ||||
| 			takeProfitOrder.Rate = takeProfitRatio.Truncate(2).String() | ||||
| 		} else { | ||||
| 			takeProfitOrder.Rate = takeProfitRatio.Add(ext.ReTakeRatio).Truncate(2).String() | ||||
| 		} | ||||
|  | ||||
| 		takeProfitOrder.BuyPrice = "0" | ||||
|  | ||||
| 		binanceservice.SetPrice(&takeProfitOrder, parentOrder, tradeSet) | ||||
| 		orders = append(orders, takeProfitOrder) | ||||
| 	} | ||||
| 	//有止损单 | ||||
| 	if ext.TpSlPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 { | ||||
| 	if slPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 { | ||||
| 		var stoploss models.LinePreOrder | ||||
|  | ||||
| 		copier.Copy(&stoploss, parentOrder) | ||||
| @ -920,7 +953,7 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line | ||||
| 		stoploss.OrderType = 2 | ||||
| 		stoploss.SignPrice = parentOrder.Price | ||||
| 		stoploss.BuyPrice = "0" | ||||
| 		stoploss.Rate = ext.TpSlPriceRatio.String() | ||||
| 		stoploss.Rate = slPriceRatio.String() | ||||
| 		stoploss.MainOrderType = "LIMIT" | ||||
| 		stoploss.Num = num.String() | ||||
| 		stoploss.BuyPrice = "0" | ||||
| @ -1658,6 +1691,7 @@ func (e *LinePreOrder) FutClosePosition(position *dto.ClosePosition, errs *[]err | ||||
| // ClearUnTriggered 清除待触发的交易对 | ||||
| func (e *LinePreOrder) ClearUnTriggered() error { | ||||
| 	var orderLists []models.LinePreOrder | ||||
| 	positions := map[string]positiondto.LinePreOrderPositioinDelReq{} | ||||
| 	e.Orm.Model(&models.LinePreOrder{}).Where("main_id = 0 AND pid = 0 AND status = '0'").Find(&orderLists).Unscoped().Delete(&models.LinePreOrder{}) | ||||
|  | ||||
| 	for _, order := range orderLists { | ||||
| @ -1680,8 +1714,43 @@ func (e *LinePreOrder) ClearUnTriggered() error { | ||||
| 			key := fmt.Sprintf(rediskey.PreSpotOrderList, order.ExchangeType) | ||||
| 			helper.DefaultRedis.LRem(key, string(marshal)) | ||||
| 		} | ||||
|  | ||||
| 		//会影响持仓的 | ||||
| 		removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType) | ||||
|  | ||||
| 		if _, ok := positions[removeSymbolKey]; !ok { | ||||
| 			positions[removeSymbolKey] = positiondto.LinePreOrderPositioinDelReq{ | ||||
| 				ApiId:        order.ApiId, | ||||
| 				Symbol:       order.Symbol, | ||||
| 				ExchangeType: order.ExchangeType, | ||||
| 				Side:         order.Site, | ||||
| 				SymbolType:   order.SymbolType, | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		e.Orm.Model(&models.LinePreOrder{}).Where("main_id = ?", order.Id).Unscoped().Delete(&models.LinePreOrder{}) | ||||
| 	} | ||||
|  | ||||
| 	//清理仓位缓存 | ||||
| 	for _, v := range positions { | ||||
| 		var count int64 | ||||
| 		e.Orm.Model(&models.LinePreOrder{}). | ||||
| 			Where("api_id =? AND site=? AND symbol=? AND symbol_type =? AND exchange_type =? AND status =6", | ||||
| 				v.ApiId, v.Side, v.Symbol, v.SymbolType, v.ExchangeType).Count(&count) | ||||
|  | ||||
| 		//没有已开仓的订单 直接清理仓位 | ||||
| 		if count == 0 { | ||||
| 			var key string | ||||
|  | ||||
| 			if v.SymbolType == 1 { | ||||
| 				key = fmt.Sprintf(rediskey.SpotPosition, v.ExchangeType, v.ApiId, v.Symbol, v.Side) | ||||
| 			} else { | ||||
| 				key = fmt.Sprintf(rediskey.FuturePosition, v.ExchangeType, v.ApiId, v.Symbol, v.Side) | ||||
| 			} | ||||
|  | ||||
| 			helper.DefaultRedis.DeleteString(key) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -1774,8 +1843,8 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error { | ||||
| 		BuyPrice:         buyPrice, | ||||
| 		LossBeginPercent: lossBeginPercent, | ||||
| 		LossEndPercent:   req.ReducePriceRatio, | ||||
| 		AddPositionType:  2, | ||||
| 		AddPositionVal:   decimal.Zero, | ||||
| 		AddPositionType:  1, | ||||
| 		AddPositionVal:   req.ReduceNumRatio, | ||||
| 	} | ||||
|  | ||||
| 	//计算减仓后 | ||||
| @ -1794,6 +1863,7 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error { | ||||
| 	}) | ||||
|  | ||||
| 	for index := range req.Ext { | ||||
| 		mainParam.AddType = req.Ext[index].AddType | ||||
| 		mainParam.LossBeginPercent = lossBeginPercent | ||||
| 		mainParam.LossEndPercent = req.Ext[index].PriceRatio | ||||
| 		mainParam.AddPositionType = req.Ext[index].AddPositionType | ||||
| @ -1819,9 +1889,9 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio | ||||
|  | ||||
| 	var addPositionBuyPrice decimal.Decimal | ||||
|  | ||||
| 	if req.AddPositionType == 1 { | ||||
| 	if req.AddType == 1 && req.AddPositionType == 1 { | ||||
| 		addPositionBuyPrice = req.BuyPrice.Mul(req.AddPositionVal.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(2) | ||||
| 	} else { | ||||
| 	} else if req.AddType == 1 { | ||||
| 		addPositionBuyPrice = req.AddPositionVal.Truncate(2) | ||||
| 	} | ||||
|  | ||||
| @ -1839,7 +1909,7 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio | ||||
| 	lossAmountU := req.Price.Mul(percentDiff.Div(decimal.NewFromInt(100).Truncate(4))).Mul(req.RemainingQuantity).Truncate(int32(tradeSet.PriceDigit)) | ||||
|  | ||||
| 	//计算减仓数量 | ||||
| 	if req.AddPositionType == 2 && req.AddPositionVal.Cmp(decimal.NewFromInt(0)) > 0 { | ||||
| 	if req.AddType == 2 && req.AddPositionType == 1 && req.AddPositionVal.Cmp(decimal.NewFromInt(0)) > 0 { | ||||
| 		reduceAmount = totalAmount.Mul(req.AddPositionVal.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @ -100,6 +100,9 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta | ||||
| 	//减仓回调 | ||||
| 	case preOrder.OrderType == 4 && orderStatus == 6: | ||||
| 		handleReduceFilled(db, preOrder) | ||||
| 		//主单取消 | ||||
| 	case preOrder.OrderType == 0 && preOrder.Pid == 0 && orderStatus == 4: | ||||
| 		handleMainOrderCancel(db, preOrder, 2) | ||||
| 	//止损成交 | ||||
| 	case preOrder.OrderType == 2 && orderStatus == 6: | ||||
| 		handleStopLoss(db, preOrder) | ||||
| @ -154,6 +157,12 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 	totalNum = totalNum.Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 	futApi := FutRestApi{} | ||||
| 	mainId := preOrder.Id | ||||
|  | ||||
| 	if preOrder.MainId > 0 { | ||||
| 		mainId = preOrder.MainId | ||||
| 	} | ||||
|  | ||||
| 	db.Model(&orderExt).Where("order_id =?", preOrder.Pid).First(&orderExt) | ||||
|  | ||||
| 	for _, v := range orders { | ||||
| @ -177,39 +186,46 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 			processFutStopLossOrder(db, v, utility.StrToDecimal(v.Price), totalNum) | ||||
| 		} | ||||
| 	} | ||||
| 	nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet) | ||||
| } | ||||
|  | ||||
| 	//加仓待触发 | ||||
| 	addPositionOrder := DbModels.LinePreOrder{} | ||||
| // 下一个合约待触发 | ||||
| func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tradeSet models2.TradeSet) { | ||||
| 	nextOrder := DbModels.LinePreOrder{} | ||||
| 	nextExt := DbModels.LinePreOrderExt{} | ||||
|  | ||||
| 	if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 	if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil { | ||||
| 		logger.Errorf("获取下一个单失败 err:%v", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	keyFutAddpositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) | ||||
|  | ||||
| 	addPositionData := AddPositionList{ | ||||
| 		Id:         addPositionOrder.Id, | ||||
| 		OrderSn:    addPositionOrder.OrderSn, | ||||
| 		MainId:     addPositionOrder.MainId, | ||||
| 		Pid:        addPositionOrder.Pid, | ||||
| 		Price:      utility.StrToDecimal(addPositionOrder.Price), | ||||
| 		ApiId:      addPositionOrder.ApiId, | ||||
| 		Symbol:     addPositionOrder.Symbol, | ||||
| 		Side:       addPositionOrder.Site, | ||||
| 		SymbolType: addPositionOrder.SymbolType, | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("id =?", nextOrder.Id).First(&nextExt).Error; err != nil { | ||||
| 		logger.Errorf("获取下一个单失败 err:%v", err) | ||||
| 	} | ||||
|  | ||||
| 	addVal, err := sonic.MarshalString(addPositionData) | ||||
| 	num := totalNum | ||||
| 	//移除缓存 | ||||
| 	key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE) | ||||
| 	vals, _ := helper.DefaultRedis.GetAllList(key) | ||||
| 	item := ReduceListItem{} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 		return | ||||
| 	for _, val := range vals { | ||||
| 		sonic.Unmarshal([]byte(val), &item) | ||||
| 		if item.MainId == mainId { | ||||
| 			if _, err := helper.DefaultRedis.LRem(key, val); err != nil { | ||||
| 				logger.Errorf("减仓单 redis删除失败 main_id:%v err:%v", mainId, err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := helper.DefaultRedis.RPushList(keyFutAddpositionKey, addVal); err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 	// | ||||
| 	if nextExt.AddPositionVal.Cmp(decimal.Zero) > 0 && nextExt.AddPositionVal.Cmp(decimal.Zero) < 100 { | ||||
| 		// 计算减仓数量 | ||||
| 		num = totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		nextOrder.Num = num.String() | ||||
| 	} | ||||
|  | ||||
| 	processFutReduceOrder(nextOrder, utility.StrToDecimal(nextOrder.Price).Truncate(int32(tradeSet.PriceDigit)), num) | ||||
| } | ||||
|  | ||||
| // 获取合约可用数量 | ||||
| @ -407,6 +423,7 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) { | ||||
| func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) { | ||||
| 	// 获取交易对配置和API信息 | ||||
| 	tradeSet, err := GetTradeSet(preOrder.Symbol, 1) | ||||
| 	mainId := preOrder.Id | ||||
| 	if err != nil || tradeSet.Coin == "" { | ||||
| 		logger.Errorf("获取交易对配置失败, 回调订单号:%s, 错误信息: %v", preOrder.OrderSn, err) | ||||
| 		return | ||||
| @ -418,6 +435,10 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if preOrder.MainId > 0 { | ||||
| 		mainId = preOrder.MainId | ||||
| 	} | ||||
|  | ||||
| 	// 处理主单加仓 | ||||
| 	if preOrder.OrderCategory == 3 { | ||||
| 		if err := handleMainOrderAddPosition(db, preOrder); err != nil { | ||||
| @ -430,6 +451,39 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 			logger.Errorf("取消主单相关订单失败, 订单号:%s, 错误信息: %v", preOrder.OrderSn, err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		//加仓待触发 | ||||
| 		addPositionOrders := make([]DbModels.LinePreOrder, 0) | ||||
|  | ||||
| 		if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.Id).Order("rate asc").Find(&addPositionOrders).Error; err != nil { | ||||
| 			logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 		} | ||||
| 		keyFutAddpositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) | ||||
|  | ||||
| 		for _, addPositionOrder := range addPositionOrders { | ||||
| 			addPositionData := AddPositionList{ | ||||
| 				Id:         addPositionOrder.Id, | ||||
| 				OrderSn:    addPositionOrder.OrderSn, | ||||
| 				MainId:     addPositionOrder.MainId, | ||||
| 				Pid:        addPositionOrder.Pid, | ||||
| 				Price:      utility.StrToDecimal(addPositionOrder.Price), | ||||
| 				ApiId:      addPositionOrder.ApiId, | ||||
| 				Symbol:     addPositionOrder.Symbol, | ||||
| 				Side:       addPositionOrder.Site, | ||||
| 				SymbolType: addPositionOrder.SymbolType, | ||||
| 			} | ||||
|  | ||||
| 			addVal, err := sonic.MarshalString(addPositionData) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			if err := helper.DefaultRedis.RPushList(keyFutAddpositionKey, addVal); err != nil { | ||||
| 				logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 获取止盈止损订单 | ||||
| @ -493,10 +547,12 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 			} | ||||
|  | ||||
| 			processFutStopLossOrder(db, order, price, num) | ||||
| 		case 4: // 减仓 | ||||
| 			processFutReduceOrder(order, price, num) | ||||
| 			// case 4: // 减仓 | ||||
| 			// processFutReduceOrder(order, price, num) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	nextFuturesReduceTrigger(db, mainId, num, tradeSet) | ||||
| } | ||||
|  | ||||
| // 处理主单加仓 | ||||
|  | ||||
| @ -119,7 +119,7 @@ func handleOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderStatus | ||||
| 		handleMainReduceFilled(db, preOrder) | ||||
| 	//主单取消 | ||||
| 	case preOrder.OrderType == 0 && preOrder.Pid == 0 && orderStatus == 4: | ||||
| 		handleMainOrderCancel(preOrder) | ||||
| 		handleMainOrderCancel(db, preOrder, 1) | ||||
| 	// 止盈成交 | ||||
| 	case preOrder.OrderType == 1 && orderStatus == 6: | ||||
| 		handleSpotTakeProfitFilled(db, preOrder) | ||||
| @ -224,38 +224,57 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//加仓待触发 | ||||
| 	addPositionOrder := DbModels.LinePreOrder{} | ||||
| 	mainId := preOrder.Id | ||||
|  | ||||
| 	if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 		return | ||||
| 	if preOrder.MainId > 0 { | ||||
| 		mainId = preOrder.MainId | ||||
| 	} | ||||
|  | ||||
| 	keySpotAddPosition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) | ||||
| 	nextSpotReduceTrigger(db, mainId, totalNum, tradeSet) | ||||
| } | ||||
|  | ||||
| 	addPositionData := AddPositionList{ | ||||
| 		Id:         addPositionOrder.Id, | ||||
| 		OrderSn:    addPositionOrder.OrderSn, | ||||
| 		MainId:     addPositionOrder.MainId, | ||||
| 		Pid:        addPositionOrder.Pid, | ||||
| 		Price:      utility.StrToDecimal(addPositionOrder.Price), | ||||
| 		ApiId:      addPositionOrder.ApiId, | ||||
| 		Symbol:     addPositionOrder.Symbol, | ||||
| 		Side:       addPositionOrder.Site, | ||||
| 		SymbolType: addPositionOrder.SymbolType, | ||||
| // 缓存下一个减仓单 | ||||
| func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tradeSet models2.TradeSet) bool { | ||||
| 	nextOrder := DbModels.LinePreOrder{} | ||||
| 	nextExt := DbModels.LinePreOrderExt{} | ||||
| 	// var percentag decimal.Decimal | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil { | ||||
| 		logger.Errorf("获取下一个单失败 err:%v", err) | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	addVal, err := sonic.MarshalString(addPositionData) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 		return | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("id =?", nextOrder.Id).First(&nextExt).Error; err != nil { | ||||
| 		logger.Errorf("获取下一个单失败 err:%v", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := helper.DefaultRedis.RPushList(keySpotAddPosition, addVal); err != nil { | ||||
| 		logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 	//移除缓存 | ||||
| 	key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE) | ||||
| 	vals, _ := helper.DefaultRedis.GetAllList(key) | ||||
| 	item := ReduceListItem{} | ||||
|  | ||||
| 	for _, val := range vals { | ||||
| 		sonic.Unmarshal([]byte(val), &item) | ||||
| 		if item.MainId == mainId { | ||||
| 			if _, err := helper.DefaultRedis.LRem(key, val); err != nil { | ||||
| 				logger.Errorf("减仓单 redis删除失败 main_id:%v err:%v", mainId, err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//减仓配置 且减仓比例大于0小于100 | ||||
| 	if nextExt.Id > 0 && nextExt.AddType == 2 && nextExt.AddPositionVal.Cmp(decimal.Zero) > 0 && nextExt.AddPositionVal.Cmp(decimal.Zero) < 100 { | ||||
| 		num := totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		// percentag = positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100)).Truncate(2) | ||||
| 		nextOrder.Num = num.String() | ||||
| 	} | ||||
| 	// percentag = nextExt.PriceRatio.Add(percentag) | ||||
| 	// nextOrder.Rate = percentag.String() | ||||
| 	// nextOrder.Price = price.Mul(decimal.NewFromInt(1).Add(percentag.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
|  | ||||
| 	//减仓待触发 | ||||
| 	processSpotReduceOrder(nextOrder) | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // 获取主单可用数量 | ||||
| @ -344,8 +363,16 @@ func getSpotPositionNum(apiUserInfo DbModels.LineApiUser, preOrder *DbModels.Lin | ||||
| } | ||||
|  | ||||
| // 主单取消 | ||||
| func handleMainOrderCancel(preOrder *DbModels.LinePreOrder) { | ||||
| 	preOrderKey := fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE) | ||||
| // symbolType 1:现货 2:合约 | ||||
| func handleMainOrderCancel(db *gorm.DB, preOrder *DbModels.LinePreOrder, symboType int) { | ||||
| 	var preOrderKey string | ||||
|  | ||||
| 	if symboType == 1 { | ||||
| 		preOrderKey = fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE) | ||||
| 	} else { | ||||
| 		preOrderKey = fmt.Sprintf(rediskey.PreFutOrderList, global.EXCHANGE_BINANCE) | ||||
| 	} | ||||
|  | ||||
| 	preSpotOrders, _ := helper.DefaultRedis.GetAllList(preOrderKey) | ||||
| 	preOrderCache := DbModels.LinePreOrder{} | ||||
|  | ||||
| @ -356,10 +383,17 @@ func handleMainOrderCancel(preOrder *DbModels.LinePreOrder) { | ||||
|  | ||||
| 		sonic.Unmarshal([]byte(v), &preOrderCache) | ||||
| 		if preOrderCache.Pid == preOrder.Id { | ||||
| 			_, err := helper.DefaultRedis.LRem(preOrderKey, v) | ||||
| 			var count int64 | ||||
| 			db.Model(&models.LinePreOrder{}). | ||||
| 				Where("api_id =? AND site=? AND symbol=? AND symbol_type =? AND exchange_type =? AND status =6", | ||||
| 					preOrder.ApiId, preOrder.Site, preOrder.Symbol, preOrder.SymbolType, preOrder.ExchangeType).Count(&count) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				logger.Errorf("订单回调失败, 回调订单号:%s 删除缓存失败:%v", preOrder.OrderSn, err) | ||||
| 			if count == 0 { | ||||
| 				_, err := helper.DefaultRedis.LRem(preOrderKey, v) | ||||
|  | ||||
| 				if err != nil { | ||||
| 					logger.Errorf("订单回调失败, 回调订单号:%s 删除缓存失败:%v", preOrder.OrderSn, err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -549,9 +583,45 @@ func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		//加仓待触发 | ||||
| 		addPositionOrders := make([]DbModels.LinePreOrder, 0) | ||||
|  | ||||
| 		if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.Id).Order("rate asc").Find(&addPositionOrders).Error; err != nil { | ||||
| 			logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 		} | ||||
|  | ||||
| 		keySpotAddPosition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) | ||||
|  | ||||
| 		for _, addPositionOrder := range addPositionOrders { | ||||
| 			addPositionData := AddPositionList{ | ||||
| 				Id:         addPositionOrder.Id, | ||||
| 				OrderSn:    addPositionOrder.OrderSn, | ||||
| 				MainId:     addPositionOrder.MainId, | ||||
| 				Pid:        addPositionOrder.Pid, | ||||
| 				Price:      utility.StrToDecimal(addPositionOrder.Price), | ||||
| 				ApiId:      addPositionOrder.ApiId, | ||||
| 				Symbol:     addPositionOrder.Symbol, | ||||
| 				Side:       addPositionOrder.Site, | ||||
| 				SymbolType: addPositionOrder.SymbolType, | ||||
| 			} | ||||
|  | ||||
| 			addVal, err := sonic.MarshalString(addPositionData) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			if err := helper.DefaultRedis.RPushList(keySpotAddPosition, addVal); err != nil { | ||||
| 				logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	processTakeProfitAndStopLossOrders(db, preOrder, &positionData, preOrder.Id, true) | ||||
|  | ||||
| } | ||||
|  | ||||
| // 解析订单状态 | ||||
| @ -623,6 +693,11 @@ func updateOrderStatus(db *gorm.DB, preOrder *models.LinePreOrder, status int, r | ||||
| func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) { | ||||
| 	orders := []models.LinePreOrder{} | ||||
| 	tradeSet, _ := GetTradeSet(preOrder.Symbol, 0) | ||||
| 	mainId := preOrder.Id | ||||
|  | ||||
| 	if preOrder.MainId > 0 { | ||||
| 		mainId = preOrder.MainId | ||||
| 	} | ||||
|  | ||||
| 	if tradeSet.Coin == "" { | ||||
| 		logger.Error("获取交易对失败") | ||||
| @ -654,9 +729,11 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd | ||||
| 	spotApi := SpotRestApi{} | ||||
| 	orderExt := models.LinePreOrderExt{} | ||||
| 	db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt) | ||||
| 	num = num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)) | ||||
|  | ||||
| 	//止盈止损 | ||||
| 	for _, order := range orders { | ||||
| 		order.Num = num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 		order.Num = num.String() | ||||
|  | ||||
| 		if fist && order.OrderCategory == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 			//主单第一次且止盈数量不是100% 止盈数量 | ||||
| @ -694,10 +771,13 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd | ||||
| 			} | ||||
|  | ||||
| 			processStopLossOrder(order) | ||||
| 		case 4: //减仓 | ||||
| 			processSpotReduceOrder(order) | ||||
| 			// case 4: //减仓 | ||||
| 			// processSpotReduceOrder(order) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//待触发减仓单 | ||||
| 	nextSpotReduceTrigger(db, mainId, num, tradeSet) | ||||
| } | ||||
|  | ||||
| // 根据下单百分比计算价格 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user