This commit is contained in:
2025-02-10 09:45:47 +08:00
parent 2954b8eb15
commit 7d906caadd
3 changed files with 123 additions and 75 deletions

View File

@ -27,7 +27,7 @@ type LinePreOrder struct {
OrderCategory int `json:"orderCategory" gorm:"type:int;comment:订单类型: 1=主单 2=对冲单"` OrderCategory int `json:"orderCategory" gorm:"type:int;comment:订单类型: 1=主单 2=对冲单"`
Site string `json:"site" gorm:"type:enum('BUY','SELL');omitempty;comment:购买方向:BUY=买;SELL=卖"` Site string `json:"site" gorm:"type:enum('BUY','SELL');omitempty;comment:购买方向:BUY=买;SELL=卖"`
OrderSn string `json:"orderSn" gorm:"type:varchar(255);omitempty;comment:订单号"` 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:订单描述"` 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=已平仓"` 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 合约对现货"` CoverType int `json:"coverType" gorm:"type:int unsigned;omitempty;comment:对冲类型 1= 现货对合约 2=合约对合约 3 合约对现货"`

View File

@ -181,16 +181,16 @@ func (s *LinePreOrderDeleteReq) GetId() interface{} {
} }
type LineAddPreOrderReq struct { type LineAddPreOrderReq struct {
ExchangeType string `json:"exchange_type"` //交易所类型 ExchangeType string `json:"exchange_type"` //交易所类型
OrderType int `json:"order_type"` //订单类型 OrderType int `json:"order_type"` //订单类型
Symbol string `json:"symbol"` //交易对 Symbol string `json:"symbol"` //交易对
ApiUserId string `json:"api_id"` //下单用户 ApiUserId string `json:"api_id"` //下单用户
Site string `json:"site"` //购买方向 Site string `json:"site"` //购买方向
BuyPrice string `json:"buy_price"` //购买金额 U BuyPrice string `json:"buy_price"` //购买金额 U
PricePattern string `json:"price_pattern"` //价格模式 PricePattern string `json:"price_pattern"` //价格模式
Price string `json:"price"` //下单价百分比 Price string `json:"price"` //下单价百分比
Profit string `json:"profit"` //止盈价 Profit string `json:"profit"` //止盈价
StopPrice string `json:"stop_price"` //止损价 // StopPrice string `json:"stop_price"` //止损价
PriceType string `json:"price_type"` //价格类型 PriceType string `json:"price_type"` //价格类型
SaveTemplate string `json:"save_template"` //是否保存模板 SaveTemplate string `json:"save_template"` //是否保存模板
TemplateName string `json:"template_name"` //模板名字 TemplateName string `json:"template_name"` //模板名字

View File

@ -378,7 +378,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
AddOrder.Num = buyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String() AddOrder.Num = buyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String()
} }
if utility.StringToFloat64(AddOrder.Num) < tradeSet.MinQty { 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 continue
} }
AddOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) 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(&profitOrder, &AddOrder)
copier.Copy(&stopOrder, &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 := models.LinePreOrderStatus{}
preOrderStatus.OrderId = AddOrder.Id
preOrderStatus.OrderSn = AddOrder.OrderSn preOrderStatus.OrderSn = AddOrder.OrderSn
e.Orm.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus) //订单配置信息
preOrderExts := make([]models.LinePreOrderExt, 0)
list := dto.PreOrderRedisList{ defultExt := models.LinePreOrderExt{
Id: AddOrder.Id, TakeProfitRatio: req.TakeProfitRatio,
Symbol: AddOrder.Symbol, ReducePriceRatio: req.ReducePriceRatio,
Price: AddOrder.Price, ReduceNumRatio: req.ReduceNumRatio,
Site: AddOrder.Site, ReduceTakeProfitRatio: req.ReduceTakeProfitRatio,
ApiId: AddOrder.ApiId, ReduceStopLossRatio: req.ReduceStopLossRatio,
OrderSn: AddOrder.OrderSn,
QuoteSymbol: AddOrder.QuoteSymbol,
} }
marshal, _ := sonic.Marshal(&list) preOrderExts = append(preOrderExts, defultExt)
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))
//是否有止盈止损订单 for _, addPosition := range req.Ext {
if req.Profit != "" { ext := models.LinePreOrderExt{
if strings.ToUpper(req.Site) == "BUY" { TakeProfitRatio: addPosition.TakeProfitRatio,
profitOrder.Site = "SELL" ReducePriceRatio: addPosition.ReducePriceRatio,
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() ReduceNumRatio: addPosition.ReduceNumRatio,
} else { ReduceTakeProfitRatio: addPosition.ReduceTakeProfitRatio,
profitOrder.Site = "BUY" ReduceStopLossRatio: addPosition.ReduceStopLossRatio,
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() 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" { e.Orm.Transaction(func(tx *gorm.DB) error {
stopOrder.Site = "SELL" err := tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&AddOrder).Error
stopOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.StopPrice)/100)).Truncate(int32(tradeSet.PriceDigit)).String() if err != nil {
} else { *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 生成订单失败", id, req.Symbol))
stopOrder.Site = "BUY" return err
stopOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.StopPrice)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
} }
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 return nil
@ -527,7 +570,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
//scriptLogs = append(scriptLogs, log) //scriptLogs = append(scriptLogs, log)
err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error err := e.Orm.Model(&models.LinePreScript{}).Create(&log).Error
if err != nil { if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("记录脚本失败:%+v", err.Error()))) *errs = append(*errs, fmt.Errorf("记录脚本失败:%+v", err.Error()))
return nil return nil
} }
helper.DefaultRedis.RPushList(rediskey.PreOrderScriptList, utility.IntToString(log.Id)) 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.PricePattern = batchReq.PricePattern
req.Price = batchReq.Price req.Price = batchReq.Price
req.Profit = batchReq.Profit req.Profit = batchReq.Profit
req.StopPrice = batchReq.StopPrice // req.StopPrice = batchReq.StopPrice
req.ReducePriceRatio = batchReq.ReducePriceRatio
req.PriceType = batchReq.PriceType req.PriceType = batchReq.PriceType
req.CoverType = batchReq.CoverType req.CoverType = batchReq.CoverType
req.ExpireHour = batchReq.ExpireHour req.ExpireHour = batchReq.ExpireHour
req.MainOrderType = batchReq.MainOrderType req.MainOrderType = batchReq.MainOrderType
req.ReduceNumRatio = batchReq.ReduceNumRatio
req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio
req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio
e.AddPreOrder(&req, p, errs, tickerSymbol) 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) err := e.AddPreOrder(&addPreOrderParams, p, errs, tickerSymbol)
if err != nil { 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 continue
} }
} }
@ -743,7 +790,7 @@ func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]erro
var orderInfo models.LinePreOrder var orderInfo models.LinePreOrder
e.Orm.Model(&models.LinePreOrder{}).Where("symbol = ? AND order_sn = ? AND status = '5'", req.Symbol, req.OrderSn).Find(&orderInfo) e.Orm.Model(&models.LinePreOrder{}).Where("symbol = ? AND order_sn = ? AND status = '5'", req.Symbol, req.OrderSn).Find(&orderInfo)
if orderInfo.Id <= 0 { if orderInfo.Id <= 0 {
*errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", "未找到可以取消的委托"))) *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", "未找到可以取消的委托"))
return return
} }
if req.OrderType == 1 { //现货 if req.OrderType == 1 { //现货
@ -753,14 +800,14 @@ func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]erro
err = futApi.CancelBatchFutOrder(apiUserInfo, req.Symbol, newClientOrderIdList) err = futApi.CancelBatchFutOrder(apiUserInfo, req.Symbol, newClientOrderIdList)
} }
if err != nil { if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", err.Error()))) *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error()))
return return
} }
} else { } else {
var orderList []models.LinePreOrder 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) 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 { if len(orderList) <= 0 {
*errs = append(*errs, errors.New(fmt.Sprintf("没有可撤销的委托"))) *errs = append(*errs, fmt.Errorf("没有可撤销的委托"))
return return
} }
for _, order := range orderList { for _, order := range orderList {
@ -768,13 +815,13 @@ func (e *LinePreOrder) CancelOpenOrder(req *dto.CancelOpenOrderReq, errs *[]erro
if order.OrderType == global.SYMBOL_SPOT { if order.OrderType == global.SYMBOL_SPOT {
err := spotApi.CancelOpenOrderByOrderSn(apiUserInfo, req.Symbol, req.OrderSn) err := spotApi.CancelOpenOrderByOrderSn(apiUserInfo, req.Symbol, req.OrderSn)
if err != nil { if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", err.Error()))) *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error()))
continue continue
} }
} else { } else {
err := futApi.CancelBatchFutOrder(apiUserInfo, order.Symbol, []string{order.OrderSn}) err := futApi.CancelBatchFutOrder(apiUserInfo, order.Symbol, []string{order.OrderSn})
if err != nil { if err != nil {
*errs = append(*errs, errors.New(fmt.Sprintf("取消委托失败:%+v", err.Error()))) *errs = append(*errs, fmt.Errorf("取消委托失败:%+v", err.Error()))
continue continue
} }
} }
@ -814,8 +861,9 @@ func (e *LinePreOrder) ClearAll() error {
e.Log.Errorf("Service RemoveLinePreOrder error:%s \r\n", err) e.Log.Errorf("Service RemoveLinePreOrder error:%s \r\n", err)
return 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") //订单表
e.Orm.Model(&models.LinePreOrder{}).Exec("TRUNCATE TABLE line_pre_order_status") 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 return err
} }