1
This commit is contained in:
		| @ -353,31 +353,34 @@ type LineTreeOrder struct { | ||||
|  | ||||
| // LineBatchAddPreOrderReq 批量添加订单请求参数 | ||||
| type LineBatchAddPreOrderReq struct { | ||||
| 	ExchangeType          string                  `json:"exchange_type"`      //交易所类型 字典exchange_type | ||||
| 	SymbolType            int                     `json:"symbol_type"`        //主单交易对类型 0-现货 1-合约 | ||||
| 	OrderType             int                     `json:"order_type"`         //订单类型 | ||||
| 	SymbolGroupId         string                  `json:"symbol_group_id"`    //交易对组id | ||||
| 	Symbol                string                  `json:"symbol"`             //交易对 | ||||
| 	ApiUserId             string                  `json:"api_id"`             //下单用户 | ||||
| 	Site                  string                  `json:"site"`               //购买方向 | ||||
| 	BuyPrice              string                  `json:"buy_price"`          //购买金额 U | ||||
| 	PricePattern          string                  `json:"price_pattern"`      //价格模式 | ||||
| 	Price                 string                  `json:"price"`              //下单价百分比 | ||||
| 	Profit                string                  `json:"profit"`             //止盈价 | ||||
| 	StopPrice             string                  `json:"stop_price"`         //止损价 | ||||
| 	PriceType             string                  `json:"price_type"`         //价格类型 | ||||
| 	SaveTemplate          string                  `json:"save_template"`      //是否保存模板 | ||||
| 	TemplateName          string                  `json:"template_name"`      //模板名字 | ||||
| 	OrderNum              int                     `json:"order_num"`          //脚本运行次数 | ||||
| 	Script                string                  `json:"script"`             //是否是脚本运行 1 = 是 0= 否 | ||||
| 	CoverType             int                     `json:"cover_type"`         //对冲类型 1= 现货对合约 2=合约对合约 3 合约对现货 | ||||
| 	ExpireHour            int                     `json:"expire_hour"`        // 过期时间 单位小时 | ||||
| 	MainOrderType         string                  `json:"main_order_type"`    //主单类型:限价(LIMIT)或市价(MARKET) | ||||
| 	ReducePriceRatio      decimal.Decimal         `json:"reduce_price"`       //主单减仓价格百分比 | ||||
| 	ReduceNumRatio        decimal.Decimal         `json:"reduce_num"`         //主单减仓数量百分比 | ||||
| 	ReduceTakeProfitRatio decimal.Decimal         `json:"reduce_take_profit"` //主单减仓后止盈价百分比 | ||||
| 	ReduceStopLossRatio   decimal.Decimal         `json:"reduce_stop_price"`  //主单减仓后止损价百分比 | ||||
| 	Ext                   []LineAddPreOrderExtReq `json:"ext"`                //拓展字段 | ||||
| 	ExchangeType          string                  `json:"exchange_type"`            //交易所类型 字典exchange_type | ||||
| 	SymbolType            int                     `json:"symbol_type"`              //主单交易对类型 0-现货 1-合约 | ||||
| 	OrderType             int                     `json:"order_type"`               //订单类型 | ||||
| 	SymbolGroupId         string                  `json:"symbol_group_id"`          //交易对组id | ||||
| 	Symbol                string                  `json:"symbol"`                   //交易对 | ||||
| 	ApiUserId             string                  `json:"api_id"`                   //下单用户 | ||||
| 	Site                  string                  `json:"site"`                     //购买方向 | ||||
| 	BuyPrice              string                  `json:"buy_price"`                //购买金额 U | ||||
| 	PricePattern          string                  `json:"price_pattern"`            //价格模式 | ||||
| 	Price                 string                  `json:"price"`                    //下单价百分比 | ||||
| 	ProfitNumRatio        decimal.Decimal         `json:"profit_num_ratio"`         //止盈数量百分比 | ||||
| 	ProfitTpTpPriceRatio  decimal.Decimal         `json:"profit_tp_tp_price_ratio"` //止盈后止盈价百分比 | ||||
| 	ProfitTpSlPriceRatio  decimal.Decimal         `json:"profit_tp_sl_price_ratio"` //止盈后止损价百分比 | ||||
| 	Profit                string                  `json:"profit"`                   //止盈价 | ||||
| 	StopPrice             string                  `json:"stop_price"`               //止损价 | ||||
| 	PriceType             string                  `json:"price_type"`               //价格类型 | ||||
| 	SaveTemplate          string                  `json:"save_template"`            //是否保存模板 | ||||
| 	TemplateName          string                  `json:"template_name"`            //模板名字 | ||||
| 	OrderNum              int                     `json:"order_num"`                //脚本运行次数 | ||||
| 	Script                string                  `json:"script"`                   //是否是脚本运行 1 = 是 0= 否 | ||||
| 	CoverType             int                     `json:"cover_type"`               //对冲类型 1= 现货对合约 2=合约对合约 3 合约对现货 | ||||
| 	ExpireHour            int                     `json:"expire_hour"`              // 过期时间 单位小时 | ||||
| 	MainOrderType         string                  `json:"main_order_type"`          //主单类型:限价(LIMIT)或市价(MARKET) | ||||
| 	ReducePriceRatio      decimal.Decimal         `json:"reduce_price"`             //主单减仓价格百分比 | ||||
| 	ReduceNumRatio        decimal.Decimal         `json:"reduce_num"`               //主单减仓数量百分比 | ||||
| 	ReduceTakeProfitRatio decimal.Decimal         `json:"reduce_take_profit"`       //主单减仓后止盈价百分比 | ||||
| 	ReduceStopLossRatio   decimal.Decimal         `json:"reduce_stop_price"`        //主单减仓后止损价百分比 | ||||
| 	Ext                   []LineAddPreOrderExtReq `json:"ext"`                      //拓展字段 | ||||
| } | ||||
|  | ||||
| func (req LineBatchAddPreOrderReq) CheckParams() error { | ||||
|  | ||||
| @ -244,7 +244,49 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi | ||||
| 	} | ||||
|  | ||||
| 	positions := map[string]positiondto.LinePreOrderPositioinDelReq{} | ||||
| 	addPosition := binanceservice.AddPositionList{} | ||||
| 	reduceItem := binanceservice.ReduceListItem{} | ||||
| 	futAddPosition := map[int]string{} | ||||
| 	spotAddPosition := map[int]string{} | ||||
| 	futReduces := map[int]string{} | ||||
| 	spotRedces := map[int]string{} | ||||
|  | ||||
| 	futAddPositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) | ||||
| 	spotAddPositionKey := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE) | ||||
| 	futReduceKey := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) | ||||
| 	spotReduceKey := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE) | ||||
| 	futAddPositionVal, _ := helper.DefaultRedis.GetAllList(futAddPositionKey) | ||||
| 	futReduceVal, _ := helper.DefaultRedis.GetAllList(spotAddPositionKey) | ||||
| 	spotAddPositionVal, _ := helper.DefaultRedis.GetAllList(futReduceKey) | ||||
| 	spotReduceVal, _ := helper.DefaultRedis.GetAllList(spotReduceKey) | ||||
|  | ||||
| 	for _, v := range futAddPositionVal { | ||||
| 		sonic.Unmarshal([]byte(v), &addPosition) | ||||
| 		if addPosition.MainId > 0 { | ||||
| 			futAddPosition[addPosition.MainId] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, v := range spotAddPositionVal { | ||||
| 		sonic.Unmarshal([]byte(v), &addPosition) | ||||
| 		if addPosition.MainId > 0 { | ||||
| 			spotAddPosition[addPosition.MainId] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, v := range futReduceVal { | ||||
| 		sonic.Unmarshal([]byte(v), &reduceItem) | ||||
| 		if reduceItem.MainId > 0 { | ||||
| 			futReduces[reduceItem.MainId] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, v := range spotReduceVal { | ||||
| 		sonic.Unmarshal([]byte(v), &reduceItem) | ||||
| 		if reduceItem.MainId > 0 { | ||||
| 			spotRedces[reduceItem.MainId] = v | ||||
| 		} | ||||
| 	} | ||||
| 	//删除的缓存 | ||||
| 	for _, order := range list { | ||||
| 		redisList := dto.PreOrderRedisList{ | ||||
| @ -261,6 +303,21 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi | ||||
| 			apiIds = append(apiIds, order.ApiId) | ||||
| 		} | ||||
|  | ||||
| 		//清除待加仓、待减仓 | ||||
| 		if val, ok := futAddPosition[order.Id]; ok { | ||||
| 			helper.DefaultRedis.LRem(futAddPositionKey, val) | ||||
| 		} | ||||
|  | ||||
| 		if val, ok := spotAddPosition[order.Id]; ok { | ||||
| 			helper.DefaultRedis.LRem(spotAddPositionKey, val) | ||||
| 		} | ||||
| 		if val, ok := futReduces[order.Id]; ok { | ||||
| 			helper.DefaultRedis.LRem(futReduceKey, val) | ||||
| 		} | ||||
| 		if val, ok := spotRedces[order.Id]; ok { | ||||
| 			helper.DefaultRedis.LRem(spotReduceKey, val) | ||||
| 		} | ||||
|  | ||||
| 		tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, fmt.Sprintf(global.TICKER_SPOT, order.ExchangeType, order.Symbol)) | ||||
| 		redisList.Price = utility.StringToDecimal(redisList.Price).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 		marshal, _ := sonic.Marshal(redisList) | ||||
| @ -483,6 +540,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 		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) | ||||
| 		preOrderExts = append(preOrderExts, defultExt2) | ||||
|  | ||||
| 		calculateResp := dto.CalculateBreakEvenRatioResp{} | ||||
| 		mainParam := dto.CalculateBreakEevenRatioReq{ | ||||
| @ -550,7 +608,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
|  | ||||
| 			//加仓、减仓状态 | ||||
| 			tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus) | ||||
|  | ||||
| 			preOrderExts[0].OrderId = AddOrder.Id | ||||
| 			list := dto.PreOrderRedisList{ | ||||
| 				Id:          AddOrder.Id, | ||||
| 				Symbol:      AddOrder.Symbol, | ||||
| @ -626,7 +684,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 				stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String() | ||||
|  | ||||
| 				tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder) | ||||
|  | ||||
| 				preOrderExts[1].OrderId = stopOrder.Id | ||||
| 				if req.ReduceNumRatio.Cmp(decimal.Zero) > 0 && req.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { | ||||
| 					if newOrders, err := makeReduceTakeAndStoploss(&stopOrder, defultExt2, tradeSet, false); err != nil { | ||||
| 						logger.Errorf("主单减仓生成止盈、减仓失败 err:%v", err) | ||||
| @ -643,10 +701,10 @@ 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 | ||||
| 				// } | ||||
| 				if index < 2 { | ||||
| 					// preOrderExts[index].OrderId = AddOrder.Id | ||||
| 					continue | ||||
| 				} | ||||
| 				var newOrder models.LinePreOrder | ||||
|  | ||||
| 				if v.AddType == 1 { | ||||
| @ -801,10 +859,10 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO | ||||
| 	orders := make([]models.LinePreOrder, 0) | ||||
| 	var side string | ||||
|  | ||||
| 	if strings.ToUpper(preOrder.Site) == "BUY" { | ||||
| 		side = "SELL" | ||||
| 	} else { | ||||
| 	if (preOrder.OrderType != 0 && strings.ToUpper(preOrder.Site) == "BUY") || (preOrder.OrderType == 0 && strings.ToUpper(preOrder.Site) == "SELL") { | ||||
| 		side = "BUY" | ||||
| 	} else { | ||||
| 		side = "SELL" | ||||
| 	} | ||||
|  | ||||
| 	if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 { | ||||
| @ -1055,6 +1113,9 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p | ||||
| 					req.PricePattern = batchReq.PricePattern | ||||
| 					req.Price = batchReq.Price | ||||
| 					req.Profit = batchReq.Profit | ||||
| 					req.ProfitNumRatio = batchReq.ProfitNumRatio | ||||
| 					req.ProfitTpTpPriceRatio = batchReq.ProfitTpSlPriceRatio | ||||
| 					req.ProfitTpSlPriceRatio = batchReq.ProfitTpSlPriceRatio | ||||
| 					req.Ext = batchReq.Ext | ||||
| 					req.SymbolType = batchReq.SymbolType | ||||
| 					// req.StopPrice = batchReq.StopPrice | ||||
| @ -1663,8 +1724,10 @@ func (e *LinePreOrder) FutClosePosition(position *dto.ClosePosition, errs *[]err | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				//撤销合约的委托 | ||||
| 				api.CancelAllFutOrder(apiUserInfo, list.Symbol) | ||||
| 				//撤销合约的委托(根据方向撤) | ||||
| 				orderSns, _ := binanceservice.GetOpenOrderSns(e.Orm, []int{list.Id}) | ||||
| 				api.CancelBatchFutOrder(apiUserInfo, list.Symbol, orderSns) | ||||
| 				// api.CancelAllFutOrder(apiUserInfo, list.Symbol) | ||||
| 				//side=BUY&positionSide=LONG是开多, | ||||
| 				//side=SELL&positionSide=LONG是平多, | ||||
| 				//side=SELL&positionSide=SHORT是开空, | ||||
|  | ||||
| @ -50,9 +50,10 @@ const ( | ||||
| 	SpotReduceList      = "spot_reduce_list:%s"      //现货减仓待触发 {交易所类型code} | ||||
| 	FuturesStopLossList = "futures_stoploss_list:%s" //合约止损待触发列表 {交易所类型code} | ||||
| 	FuturesReduceList   = "futures_reduce_list:%s"   //合约减仓待触发 {交易所类型code} | ||||
|  | ||||
| 	SpotAddPositionList    = "spot_add_position_list:%s"    //现货加仓待触发 {交易所code} | ||||
| 	FuturesAddPositionList = "futures_add_position_list:%s" //合约加仓待触发 {交易所code} | ||||
| 	//现货加仓待触发 {交易所code} | ||||
| 	SpotAddPositionList = "spot_add_position_list:%s" | ||||
| 	//合约加仓待触发 {交易所code} | ||||
| 	FuturesAddPositionList = "futures_add_position_list:%s" | ||||
| 	//现货持仓 {exchangeType,apiuserid,symbol,side} | ||||
| 	SpotPosition = "spot_position:%s:%v:%s_%s" | ||||
| 	//合约持仓 {exchangeType,apiuserid,symbol,side} | ||||
|  | ||||
| @ -471,7 +471,7 @@ func getOpenPositionMainOrderId(db *gorm.DB, newId, apiId, symbolType int, excha | ||||
| } | ||||
|  | ||||
| // 获取需要取消的订单号 | ||||
| func getOpenOrderSns(db *gorm.DB, mainIds []int) ([]string, error) { | ||||
| func GetOpenOrderSns(db *gorm.DB, mainIds []int) ([]string, error) { | ||||
| 	result := []string{} | ||||
|  | ||||
| 	//委托中的订单 | ||||
|  | ||||
| @ -201,8 +201,8 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes | ||||
| 		return | ||||
| 	} else if ok { | ||||
| 		defer lock.Release() | ||||
| 		takeOrder := DbModels.LinePreOrder{} | ||||
| 		if err := db.Model(&DbModels.LinePreOrder{}).Where("pid =? AND order_type =1", reduceOrder.Pid).Find(&takeOrder).Error; err != nil { | ||||
| 		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 { | ||||
| 			log.Error("查询止盈单失败") | ||||
| 			return | ||||
| 		} | ||||
| @ -214,18 +214,19 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		apiInfo, _ := GetApiInfo(takeOrder.ApiId) | ||||
| 		apiInfo, _ := GetApiInfo(reduceOrder.ApiId) | ||||
|  | ||||
| 		if apiInfo.Id == 0 { | ||||
| 			log.Error("现货减仓 查询api用户不存在") | ||||
| 			return | ||||
| 		} | ||||
| 		for _, takeOrder := range takeOrders { | ||||
| 			err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) | ||||
|  | ||||
| 		err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			log.Error("合约止盈撤单失败", err) | ||||
| 			return | ||||
| 			if err != nil { | ||||
| 				log.Error("合约止盈撤单失败", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)) | ||||
|  | ||||
| @ -154,7 +154,6 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
|  | ||||
| 	orderExt := models.LinePreOrderExt{} | ||||
| 	totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) | ||||
| 	totalNum = totalNum.Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit)) | ||||
| 	futApi := FutRestApi{} | ||||
| 	mainId := preOrder.Id | ||||
| @ -199,7 +198,7 @@ func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("id =?", nextOrder.Id).First(&nextExt).Error; err != nil { | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? and add_type =2", nextOrder.Id).First(&nextExt).Error; err != nil { | ||||
| 		logger.Errorf("获取下一个单失败 err:%v", err) | ||||
| 	} | ||||
|  | ||||
| @ -223,6 +222,10 @@ func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, | ||||
| 		// 计算减仓数量 | ||||
| 		num = totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 		nextOrder.Num = num.String() | ||||
|  | ||||
| 		if err := db.Model(&nextOrder).Update("num", nextOrder.Num).Error; err != nil { | ||||
| 			logger.Errorf("更新减仓单数量失败 err:%v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	processFutReduceOrder(nextOrder, utility.StrToDecimal(nextOrder.Price).Truncate(int32(tradeSet.PriceDigit)), num) | ||||
| @ -321,16 +324,12 @@ func handleStopLoss(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 	removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) | ||||
| 	removePosition(db, preOrder) | ||||
|  | ||||
| 	spotApi := SpotRestApi{} | ||||
| 	apiUserInfo, _ := GetApiInfo(preOrder.ApiId) | ||||
|  | ||||
| 	if apiUserInfo.Id > 0 { | ||||
| 		req := CancelOpenOrdersReq{ | ||||
| 			Symbol: preOrder.Symbol, | ||||
| 			ApiId:  preOrder.ApiId, | ||||
| 		} | ||||
| 		if err := spotApi.CancelOpenOrders(db, req); err != nil { | ||||
| 			logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) | ||||
| 		mainIds := []int{preOrder.MainId} | ||||
| 		if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil { | ||||
| 			logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -353,12 +352,12 @@ func handleTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
| 		removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) | ||||
| 		removePosition(db, preOrder) | ||||
|  | ||||
| 		futApi := FutRestApi{} | ||||
| 		apiUserInfo, _ := GetApiInfo(preOrder.ApiId) | ||||
|  | ||||
| 		if apiUserInfo.Id > 0 { | ||||
| 			if err := futApi.CancelAllFutOrder(apiUserInfo, preOrder.Symbol); err != nil { | ||||
| 				logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) | ||||
| 			mainOrder, _ := GetOrderById(db, preOrder.MainId) | ||||
| 			if err := cancelPositionOtherOrders(apiUserInfo, db, &mainOrder, false); err != nil { | ||||
| 				logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @ -445,9 +444,9 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 			logger.Errorf("处理主单加仓失败, 主单号:%s, 错误信息: %v", preOrder.MainId, err) | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 	} else if first { | ||||
| 		// 处理其他主单逻辑 | ||||
| 		if err := cancelPositionOtherOrders(apiInfo, db, preOrder); err != nil { | ||||
| 		if err := cancelPositionOtherOrders(apiInfo, db, preOrder, true); err != nil { | ||||
| 			logger.Errorf("取消主单相关订单失败, 订单号:%s, 错误信息: %v", preOrder.OrderSn, err) | ||||
| 			return | ||||
| 		} | ||||
| @ -497,7 +496,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 	positionData := savePosition(db, preOrder) | ||||
| 	orderExt := models.LinePreOrderExt{} | ||||
| 	db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt) | ||||
| 	num := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	totalNum := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet).Truncate(int32(tradeSet.AmountDigit)) | ||||
|  | ||||
| 	// 更新订单数量并处理止盈、止损、减仓 | ||||
| 	for _, order := range orders { | ||||
| @ -505,7 +504,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 		order.Price = price.String() | ||||
|  | ||||
| 		// 更新止盈止损订单数量 | ||||
| 		num = updateOrderQuantity(db, order, preOrder, &orderExt, num, first, tradeSet) | ||||
| 		num := updateOrderQuantity(db, order, preOrder, &orderExt, totalNum, first, tradeSet) | ||||
|  | ||||
| 		// 根据订单类型处理 | ||||
| 		switch order.OrderType { | ||||
| @ -552,7 +551,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	nextFuturesReduceTrigger(db, mainId, num, tradeSet) | ||||
| 	nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet) | ||||
| } | ||||
|  | ||||
| // 处理主单加仓 | ||||
| @ -569,7 +568,8 @@ func handleMainOrderAddPosition(db *gorm.DB, preOrder *models.LinePreOrder) erro | ||||
| } | ||||
|  | ||||
| // 取消主单相关订单 | ||||
| func cancelPositionOtherOrders(apiUserInfo DbModels.LineApiUser, db *gorm.DB, preOrder *models.LinePreOrder) error { | ||||
| // changeMainOrderStatus 是否修改主单状态 | ||||
| func cancelPositionOtherOrders(apiUserInfo DbModels.LineApiUser, db *gorm.DB, preOrder *models.LinePreOrder, changeMainOrderStatus bool) error { | ||||
| 	mainOrders, err := getOpenPositionMainOrderId(db, preOrder.Id, preOrder.ApiId, preOrder.SymbolType, preOrder.ExchangeType, preOrder.Symbol, preOrder.Site) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @ -589,25 +589,36 @@ func cancelPositionOtherOrders(apiUserInfo DbModels.LineApiUser, db *gorm.DB, pr | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 批量取消订单 | ||||
| 	err = cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, changeMainOrderStatus) | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // 根据mainid 取消订单 | ||||
| // @changeMainOrderStatus 是否更新主单状态 | ||||
| func cancelMainOrders(mainIds []int, db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, changeMainOrderStatus bool) error { | ||||
| 	if len(mainIds) > 0 { | ||||
| 		orderSns, err := getOpenOrderSns(db, mainIds) | ||||
| 		orderSns, err := GetOpenOrderSns(db, mainIds) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		// 批量取消订单 | ||||
| 		orderArray := utility.SplitSlice(orderSns, 10) | ||||
| 		futApi := FutRestApi{} | ||||
| 		for _, item := range orderArray { | ||||
| 			err := futApi.CancelBatchFutOrder(apiUserInfo, preOrder.Symbol, item) | ||||
| 			err := futApi.CancelBatchFutOrder(apiUserInfo, symbol, item) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				logger.Errorf("批量取消订单失败 orderSns:%v", item) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if err := db.Exec("UPDATE line_pre_order SET `status`=4, `desc`=CONCAT(`desc`, ' 新单触发取消') WHERE id IN ? AND `status` =6", mainIds).Error; err != nil { | ||||
| 			logger.Errorf("合约 新下单成功后更新主单取消状态失败, 新主单号:%s, 错误信息:%v", preOrder.MainId, err) | ||||
| 		//需要修改主单状态 | ||||
| 		if changeMainOrderStatus { | ||||
| 			if err := db.Exec("UPDATE line_pre_order SET `status`=4, `desc`=CONCAT(`desc`, ' 新单触发取消') WHERE id IN ? AND `status` =6", mainIds).Error; err != nil { | ||||
| 				logger.Errorf("合约 新下单成功后更新主单取消状态失败, 交易对:%s, 错误信息:%v", symbol, err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| @ -633,7 +644,7 @@ func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *model | ||||
| 	// 	order.Num = num.String() | ||||
| 	// } else | ||||
|  | ||||
| 	if first && order.OrderCategory == 1 && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 	if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && order.OrderType == 1 && 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)) | ||||
| 		order.Num = num.String() | ||||
|  | ||||
| @ -308,8 +308,8 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest | ||||
| 		return | ||||
| 	} else if ok { | ||||
| 		defer lock.Release() | ||||
| 		takeOrder := DbModels.LinePreOrder{} | ||||
| 		if err := db.Model(&DbModels.LinePreOrder{}).Where("pid =? AND order_type =1", reduceOrder.Pid).Find(&takeOrder).Error; err != nil { | ||||
| 		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 { | ||||
| 			log.Error("查询止盈单失败") | ||||
| 			return | ||||
| 		} | ||||
| @ -320,18 +320,20 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		apiInfo, _ := GetApiInfo(takeOrder.ApiId) | ||||
| 		apiInfo, _ := GetApiInfo(reduceOrder.ApiId) | ||||
|  | ||||
| 		if apiInfo.Id == 0 { | ||||
| 			log.Error("现货减仓 查询api用户不存在") | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) | ||||
| 		for _, takeOrder := range takeOrders { | ||||
| 			err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			log.Error("现货止盈撤单失败", err) | ||||
| 			return | ||||
| 			if err != nil { | ||||
| 				log.Error("现货止盈撤单失败", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)) | ||||
|  | ||||
|  | ||||
| @ -195,7 +195,7 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { | ||||
|  | ||||
| 	db.Model(&orderExt).Where("order_id =?", preOrder.Pid).Find(&orderExt) | ||||
| 	totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet) | ||||
| 	totalNum = totalNum.Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	totalNum = totalNum.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	price := utility.StrToDecimal(preOrder.Price) | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status=0", preOrder.Id).Find(&orders).Error; err != nil { | ||||
| @ -244,7 +244,7 @@ func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tr | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("id =?", nextOrder.Id).First(&nextExt).Error; err != nil { | ||||
| 	if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? and add_type =2", nextOrder.Id).First(&nextExt).Error; err != nil { | ||||
| 		logger.Errorf("获取下一个单失败 err:%v", err) | ||||
| 	} | ||||
|  | ||||
| @ -265,12 +265,12 @@ func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tr | ||||
| 	//减仓配置 且减仓比例大于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() | ||||
|  | ||||
| 		if err := db.Model(&nextOrder).Update("num", nextOrder.Num).Error; err != nil { | ||||
| 			logger.Errorf("更新减仓单数量失败 err:%v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	// 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) | ||||
| @ -638,7 +638,7 @@ func parseOrderStatus(status interface{}, mapData map[string]interface{}) (int, | ||||
| 		return 5, reason | ||||
| 	case "FILLED": // 完全成交 | ||||
| 		return 6, reason | ||||
| 	case "CANCELED", "EXPIRED": // 取消 | ||||
| 	case "CANCELED", "EXPIRED", "EXPIRED_IN_MATCH": // 取消 | ||||
| 		return 4, reason | ||||
| 	default: | ||||
| 		return 0, reason | ||||
| @ -729,13 +729,17 @@ 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)) | ||||
| 	totalNum := num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	num = totalNum | ||||
|  | ||||
| 	// if orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { | ||||
| 	// 	num = num.Mul(orderExt.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) | ||||
| 	// } | ||||
| 	//止盈止损 | ||||
| 	for _, order := range orders { | ||||
| 		order.Num = num.String() | ||||
|  | ||||
| 		if fist && order.OrderCategory == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 		if fist && order.OrderCategory == 1 && order.OrderType == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 			//主单第一次且止盈数量不是100% 止盈数量 | ||||
| 			order.Num = num.Mul(orderExt.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 		} | ||||
| @ -777,7 +781,7 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd | ||||
| 	} | ||||
|  | ||||
| 	//待触发减仓单 | ||||
| 	nextSpotReduceTrigger(db, mainId, num, tradeSet) | ||||
| 	nextSpotReduceTrigger(db, mainId, totalNum, tradeSet) | ||||
| } | ||||
|  | ||||
| // 根据下单百分比计算价格 | ||||
| @ -947,6 +951,8 @@ func CancelOpenOrderByOrderSnLoop(apiInfo DbModels.LineApiUser, symbol string, o | ||||
| 			err = nil | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		time.Sleep(time.Millisecond * 300) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user