diff --git a/app/admin/models/line_pre_order.go b/app/admin/models/line_pre_order.go index e50d22f..27bbcce 100644 --- a/app/admin/models/line_pre_order.go +++ b/app/admin/models/line_pre_order.go @@ -27,7 +27,7 @@ type LinePreOrder struct { OrderCategory int `json:"orderCategory" gorm:"type:int;comment:订单类型: 1=主单 2=对冲单"` Site string `json:"site" gorm:"type:enum('BUY','SELL');omitempty;comment:购买方向:BUY=买;SELL=卖"` OrderSn string `json:"orderSn" gorm:"type:varchar(255);omitempty;comment:订单号"` - OrderType int `json:"orderType" gorm:"type:int;omitempty;comment:订单类型:0=主单 1=止盈 2=止损 3=平仓"` + OrderType int `json:"orderType" gorm:"type:int;omitempty;comment:订单类型:0=主单 1=止盈 2=止损 3=平仓 4=减仓"` Desc string `json:"desc" gorm:"type:text;omitempty;comment:订单描述"` Status int `json:"status" gorm:"type:int;omitempty;comment:是否被触发:0=待触发;1=已触发;2=下单失败;4=已取消;5=委托中;6=已成交;9=已平仓"` CoverType int `json:"coverType" gorm:"type:int unsigned;omitempty;comment:对冲类型 1= 现货对合约 2=合约对合约 3 合约对现货"` diff --git a/app/admin/service/dto/line_pre_order.go b/app/admin/service/dto/line_pre_order.go index a7abdcd..4574778 100644 --- a/app/admin/service/dto/line_pre_order.go +++ b/app/admin/service/dto/line_pre_order.go @@ -181,16 +181,16 @@ func (s *LinePreOrderDeleteReq) GetId() interface{} { } type LineAddPreOrderReq struct { - ExchangeType string `json:"exchange_type"` //交易所类型 - OrderType int `json:"order_type"` //订单类型 - 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"` //止损价 + ExchangeType string `json:"exchange_type"` //交易所类型 + OrderType int `json:"order_type"` //订单类型 + 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"` //模板名字 diff --git a/app/admin/service/line_pre_order.go b/app/admin/service/line_pre_order.go index 09f46e9..7bece41 100644 --- a/app/admin/service/line_pre_order.go +++ b/app/admin/service/line_pre_order.go @@ -378,7 +378,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP AddOrder.Num = buyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String() } if utility.StringToFloat64(AddOrder.Num) < tradeSet.MinQty { - *errs = append(*errs, errors.New(fmt.Sprintf("api_id:%s 获取交易对:%s 小于最小下单数量", id, req.Symbol))) + *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 小于最小下单数量", id, req.Symbol)) continue } AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) @@ -391,70 +391,113 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP copier.Copy(&profitOrder, &AddOrder) copier.Copy(&stopOrder, &AddOrder) - err := e.Orm.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error - if err != nil { - *errs = append(*errs, errors.New(fmt.Sprintf("api_id:%s 获取交易对:%s 生成订单失败", id, req.Symbol))) - continue - } - preOrderStatus := models.LinePreOrderStatus{} - preOrderStatus.OrderId = AddOrder.Id preOrderStatus.OrderSn = AddOrder.OrderSn - e.Orm.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus) - - list := dto.PreOrderRedisList{ - Id: AddOrder.Id, - Symbol: AddOrder.Symbol, - Price: AddOrder.Price, - Site: AddOrder.Site, - ApiId: AddOrder.ApiId, - OrderSn: AddOrder.OrderSn, - QuoteSymbol: AddOrder.QuoteSymbol, + //订单配置信息 + preOrderExts := make([]models.LinePreOrderExt, 0) + defultExt := models.LinePreOrderExt{ + TakeProfitRatio: req.TakeProfitRatio, + ReducePriceRatio: req.ReducePriceRatio, + ReduceNumRatio: req.ReduceNumRatio, + ReduceTakeProfitRatio: req.ReduceTakeProfitRatio, + ReduceStopLossRatio: req.ReduceStopLossRatio, } - marshal, _ := sonic.Marshal(&list) - var preKey string - if AddOrder.SymbolType == global.SYMBOL_SPOT { - preKey = fmt.Sprintf(rediskey.PreSpotOrderList, AddOrder.ExchangeType) - } else { - preKey = fmt.Sprintf(rediskey.PreFutOrderList, AddOrder.ExchangeType) - } - helper.DefaultRedis.LPushList(preKey, string(marshal)) + preOrderExts = append(preOrderExts, defultExt) - //是否有止盈止损订单 - if req.Profit != "" { - if strings.ToUpper(req.Site) == "BUY" { - profitOrder.Site = "SELL" - profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() - } else { - profitOrder.Site = "BUY" - profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() + for _, addPosition := range req.Ext { + ext := models.LinePreOrderExt{ + TakeProfitRatio: addPosition.TakeProfitRatio, + ReducePriceRatio: addPosition.ReducePriceRatio, + ReduceNumRatio: addPosition.ReduceNumRatio, + ReduceTakeProfitRatio: addPosition.ReduceTakeProfitRatio, + ReduceStopLossRatio: addPosition.ReduceStopLossRatio, + AddPositionPriceRatio: addPosition.AddPositionPriceRatio, + AddPositionType: addPosition.AddPositionType, + AddPositionVal: addPosition.AddPositionVal, } - profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) - profitOrder.Pid = AddOrder.Id - profitOrder.OrderType = 1 - profitOrder.Status = 0 - profitOrder.Rate = req.Profit - e.Orm.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&profitOrder) + preOrderExts = append(preOrderExts, ext) } - if req.StopPrice != "" { - if strings.ToUpper(req.Site) == "BUY" { - stopOrder.Site = "SELL" - stopOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.StopPrice)/100)).Truncate(int32(tradeSet.PriceDigit)).String() - } else { - stopOrder.Site = "BUY" - stopOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.StopPrice)/100)).Truncate(int32(tradeSet.PriceDigit)).String() + //事务添加 + e.Orm.Transaction(func(tx *gorm.DB) error { + err := tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error + if err != nil { + *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", id, req.Symbol)) + return err } - stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) - stopOrder.Pid = AddOrder.Id - stopOrder.OrderType = 2 - stopOrder.Status = 0 - stopOrder.Rate = req.StopPrice - e.Orm.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder) - } + preOrderStatus.OrderId = AddOrder.Id + + //加仓、减仓状态 + tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus) + + for index := range preOrderExts { + if index == 0 { + preOrderExts[index].OrderId = AddOrder.Id + } + + preOrderExts[index].MainOrderId = AddOrder.Id + } + + list := dto.PreOrderRedisList{ + Id: AddOrder.Id, + Symbol: AddOrder.Symbol, + Price: AddOrder.Price, + Site: AddOrder.Site, + ApiId: AddOrder.ApiId, + OrderSn: AddOrder.OrderSn, + QuoteSymbol: AddOrder.QuoteSymbol, + } + marshal, _ := sonic.Marshal(&list) + var preKey string + if AddOrder.SymbolType == global.SYMBOL_SPOT { + preKey = fmt.Sprintf(rediskey.PreSpotOrderList, AddOrder.ExchangeType) + } else { + preKey = fmt.Sprintf(rediskey.PreFutOrderList, AddOrder.ExchangeType) + } + helper.DefaultRedis.LPushList(preKey, string(marshal)) + + //是否有止盈止损订单 + if req.Profit != "" { + if strings.ToUpper(req.Site) == "BUY" { + profitOrder.Site = "SELL" + profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + profitOrder.Site = "BUY" + profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() + } + profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) + profitOrder.Pid = AddOrder.Id + profitOrder.OrderType = 1 + profitOrder.Status = 0 + profitOrder.Rate = req.Profit + profitOrder.MainId = AddOrder.Id + + tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&profitOrder) + } + + if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 { + if strings.ToUpper(req.Site) == "BUY" { + stopOrder.Site = "SELL" + stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(req.ReducePriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + stopOrder.Site = "BUY" + stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(req.ReducePriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } + stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) + stopOrder.Pid = AddOrder.Id + stopOrder.MainId = AddOrder.Id + stopOrder.OrderType = 4 + stopOrder.Status = 0 + stopOrder.Rate = req.ReducePriceRatio.String() + + tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&stopOrder) + } + + return nil + }) } return nil @@ -527,7 +570,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p //scriptLogs = append(scriptLogs, log) err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error if err != nil { - *errs = append(*errs, errors.New(fmt.Sprintf("记录脚本失败:%+v", err.Error()))) + *errs = append(*errs, fmt.Errorf("记录脚本失败:%+v", err.Error())) return nil } helper.DefaultRedis.RPushList(rediskey.PreOrderScriptList, utility.IntToString(log.Id)) @@ -550,11 +593,15 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p req.PricePattern = batchReq.PricePattern req.Price = batchReq.Price req.Profit = batchReq.Profit - req.StopPrice = batchReq.StopPrice + // req.StopPrice = batchReq.StopPrice + req.ReducePriceRatio = batchReq.ReducePriceRatio req.PriceType = batchReq.PriceType req.CoverType = batchReq.CoverType req.ExpireHour = batchReq.ExpireHour req.MainOrderType = batchReq.MainOrderType + req.ReduceNumRatio = batchReq.ReduceNumRatio + req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio + req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio e.AddPreOrder(&req, p, errs, tickerSymbol) } @@ -585,7 +632,7 @@ func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *ac } err := e.AddPreOrder(&addPreOrderParams, p, errs, tickerSymbol) if err != nil { - *errs = append(*errs, errors.New(fmt.Sprintf("api_id:%s 获取交易对:%s 生成订单失败", addPreOrderParams.ApiUserId, addPreOrderParams.Symbol))) + *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", addPreOrderParams.ApiUserId, addPreOrderParams.Symbol)) continue } } @@ -743,7 +790,7 @@ func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]erro var orderInfo models.LinePreOrder e.Orm.Model(&models.LinePreOrder{}).Where("symbol = ? AND order_sn = ? AND status = '5'", req.Symbol, req.OrderSn).Find(&orderInfo) if orderInfo.Id <= 0 { - *errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", "未找到可以取消的委托"))) + *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", "未找到可以取消的委托")) return } if req.OrderType == 1 { //现货 @@ -753,14 +800,14 @@ func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]erro err = futApi.CancelBatchFutOrder(apiUserInfo, req.Symbol, newClientOrderIdList) } if err != nil { - *errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", err.Error()))) + *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error())) return } } else { var orderList []models.LinePreOrder e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND pid = 0 status = '5' AND order_type = ?", req.ApiId, strconv.Itoa(req.OrderType)).Find(&orderList) if len(orderList) <= 0 { - *errs = append(*errs, errors.New(fmt.Sprintf("没有可撤销的委托"))) + *errs = append(*errs, fmt.Errorf("没有可撤销的委托")) return } for _, order := range orderList { @@ -768,13 +815,13 @@ func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]erro if order.OrderType == global.SYMBOL_SPOT { err := spotApi.CancelOpenOrderByOrderSn(apiUserInfo, req.Symbol, req.OrderSn) if err != nil { - *errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", err.Error()))) + *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error())) continue } } else { err := futApi.CancelBatchFutOrder(apiUserInfo, order.Symbol, []string{order.OrderSn}) if err != nil { - *errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", err.Error()))) + *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error())) continue } } @@ -814,8 +861,9 @@ func (e *LinePreOrder) ClearAll() error { e.Log.Errorf("Service RemoveLinePreOrder error:%s \r\n", err) return err } - e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order") - e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") + e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order") //订单表 + e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") //订单拓展状态 + e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_ext") //订单拓展配置 return err }