1
This commit is contained in:
@ -606,7 +606,7 @@ func (e LinePreOrder) QueryAiCoinPrice(c *gin.Context) {
|
||||
// 计算回本盈利比例
|
||||
func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) {
|
||||
s := service.LinePreOrder{}
|
||||
req := dto.CalculateBreakEevenRatioReq{}
|
||||
req := dto.LineAddPreOrderReq{}
|
||||
|
||||
err := e.MakeContext(c).
|
||||
MakeOrm().
|
||||
@ -619,12 +619,12 @@ func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
data := dto.CalculateBreakEvenRatioResp{}
|
||||
err = s.CalculateBreakEvenRatio(&req, &data)
|
||||
// data := dto.CalculateBreakEvenRatioResp{}
|
||||
_, err = s.GenerateOrder(&req)
|
||||
if err != nil {
|
||||
e.Error(500, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
e.OK(data, "操作成功")
|
||||
e.OK(req, "操作成功")
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ type LinePreOrderExt struct {
|
||||
MainOrderId int `json:"mainOrderId" gorm:"type:bigint;comment:主单id"`
|
||||
OrderId int `json:"orderId" gorm:"type:bigint;comment:订单id"`
|
||||
TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" gorm:"type:decimal(10,2);comment:止盈百分比"`
|
||||
ReTakeRatio decimal.Decimal `json:"reTakeRatio" gorm:"type:decimal(10,2);comment:亏损回本止盈百分比"`
|
||||
ReduceOrderType string `json:"reduceOrderType" gorm:"type:varchar(20);comment:减仓类型 LIMIT-限价 MARKET-市价"`
|
||||
ReducePriceRatio decimal.Decimal `json:"reducePriceRatio" gorm:"type:decimal(10,2);comment:减仓价格百分比"`
|
||||
ReduceNumRatio decimal.Decimal `json:"reduceNumRatio" gorm:"type:decimal(10,2);comment:减仓数量百分比"`
|
||||
@ -21,6 +22,9 @@ type LinePreOrderExt struct {
|
||||
AddPositionPriceRatio decimal.Decimal `json:"addPositionPriceRatio" gorm:"type:decimal(10,2);comment:加仓价格百分比"`
|
||||
AddPositionType int `json:"addPositionType" gorm:"type:int;comment:加仓类型 1-百分比 2-实际金额"`
|
||||
AddPositionVal decimal.Decimal `json:"addPositionVal" gorm:"type:decimal(10,2);comment:加仓值"`
|
||||
ReduceReTakeRatio decimal.Decimal `json:"reduceReTakeRatio" gorm:"type:decimal(10,2);comment:减仓后亏损回本止盈百分比"`
|
||||
TotalAfterAdding decimal.Decimal `json:"totalAfterAdding" gorm:"-"` //加仓后总数
|
||||
TotalAfterReducing decimal.Decimal `json:"totalAfterReducing" gorm:"-"` //减仓后总数
|
||||
models.ModelTime
|
||||
models.ControlBy
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ func registerLinePreOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM
|
||||
r.POST("clearUnTriggered", actions.PermissionAction(), api.ClearUnTriggered) // 清除待触发的交易对
|
||||
r.POST("aiCoinPrice", actions.PermissionAction(), api.QueryAiCoinPrice) //获取aiCoin买入点
|
||||
|
||||
r.GET("/calculate", api.CalculateBreakEevenRatio) //计算亏损后止盈百分比
|
||||
r.POST("/calculate", api.CalculateBreakEevenRatio) //计算亏损后止盈百分比
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -191,18 +191,20 @@ type LineAddPreOrderReq struct {
|
||||
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"` //模板名字
|
||||
SymbolType int `json:"symbol_type"` //交易对类型 1-现货 2-合约
|
||||
CoverType int `json:"cover_type"` //对冲类型 0=无对冲 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"` //拓展字段
|
||||
PriceType string `json:"price_type"` //价格类型
|
||||
SaveTemplate string `json:"save_template"` //是否保存模板
|
||||
TemplateName string `json:"template_name"` //模板名字
|
||||
SymbolType int `json:"symbol_type"` //交易对类型 1-现货 2-合约
|
||||
CoverType int `json:"cover_type"` //对冲类型 0=无对冲 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"` //主单减仓后止损价百分比
|
||||
ReduceReTakeProfitRatio decimal.Decimal `json:"reTakeProfitRatio" comment:"减仓后亏损回本止盈百分比"`
|
||||
|
||||
Ext []LineAddPreOrderExtReq `json:"ext"` //拓展字段
|
||||
}
|
||||
|
||||
func (req LineAddPreOrderReq) CheckParams() error {
|
||||
@ -232,6 +234,11 @@ func (req LineAddPreOrderReq) CheckParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type LineTreeOrder struct {
|
||||
models.LinePreOrder
|
||||
Childs []models.LinePreOrder `json:"childs"`
|
||||
}
|
||||
|
||||
// LineBatchAddPreOrderReq 批量添加订单请求参数
|
||||
type LineBatchAddPreOrderReq struct {
|
||||
ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type
|
||||
|
||||
@ -37,15 +37,17 @@ func (m *LinePreOrderExtGetPageReq) GetNeedSearch() interface{} {
|
||||
}
|
||||
|
||||
type LineAddPreOrderExtReq struct {
|
||||
TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" comment:"止盈百分比"`
|
||||
ReducePriceRatio decimal.Decimal `json:"reducePriceRatio" comment:"减仓价格百分比"`
|
||||
ReduceNumRatio decimal.Decimal `json:"reduceNumRatio" comment:"减仓数量百分比"`
|
||||
ReduceTakeProfitRatio decimal.Decimal `json:"reduceTakeProfitRatio" comment:"减仓后止盈百分比"`
|
||||
ReduceStopLossRatio decimal.Decimal `json:"reduceStopLossRatio" comment:"减仓后止损百分比"`
|
||||
AddPositionPriceRatio decimal.Decimal `json:"addPositionPriceRatio" comment:"加仓价格百分比"`
|
||||
AddPositionOrderType string `json:"addPositionOrderType" comment:"加仓订单类型 LIMIT-限价 MARKET-市价"`
|
||||
AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"`
|
||||
AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"`
|
||||
TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" comment:"止盈百分比"`
|
||||
ReTakeProfitRatio decimal.Decimal `json:"reTakeProfitRatio" comment:"亏损回本止盈百分比"`
|
||||
ReducePriceRatio decimal.Decimal `json:"reducePriceRatio" comment:"减仓价格百分比"`
|
||||
ReduceNumRatio decimal.Decimal `json:"reduceNumRatio" comment:"减仓数量百分比"`
|
||||
ReduceTakeProfitRatio decimal.Decimal `json:"reduceTakeProfitRatio" comment:"减仓后止盈百分比"`
|
||||
ReduceStopLossRatio decimal.Decimal `json:"reduceStopLossRatio" comment:"减仓后止损百分比"`
|
||||
ReduceReTakeProfitRatio decimal.Decimal `json:"reduceReTakeProfitRatio" comment:"减仓后回本止盈百分比"`
|
||||
AddPositionPriceRatio decimal.Decimal `json:"addPositionPriceRatio" comment:"加仓价格百分比"`
|
||||
AddPositionOrderType string `json:"addPositionOrderType" comment:"加仓订单类型 LIMIT-限价 MARKET-市价"`
|
||||
AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"`
|
||||
AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"`
|
||||
}
|
||||
|
||||
type LinePreOrderExtInsertReq struct {
|
||||
|
||||
@ -347,11 +347,13 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
AddOrder.ExpireTime = time.Now().Add(time.Duration(req.ExpireHour) * time.Hour) //过期时间
|
||||
AddOrder.MainOrderType = req.MainOrderType
|
||||
AddOrder.Site = req.Site
|
||||
AddOrder.SignPrice = tickerPrice.String()
|
||||
|
||||
if req.PricePattern == "percentage" {
|
||||
AddOrder.Rate = req.Price
|
||||
orderPrice, _ := decimal.NewFromString(req.Price) //下单价百分比 10%
|
||||
priceRate := orderPrice.Div(decimal.NewFromInt(100)) //下单价除100 =0.1
|
||||
AddOrder.SignPrice = tickerPrice.String()
|
||||
|
||||
if strings.ToUpper(req.Site) == "BUY" { //购买方向
|
||||
//实际下单价格
|
||||
truncate := tickerPrice.Mul(decimal.NewFromInt(1).Sub(priceRate)).Truncate(int32(tradeSet.PriceDigit))
|
||||
@ -363,11 +365,10 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
|
||||
} else { //实际价格下单
|
||||
AddOrder.Price = utility.StringToDecimal(req.Price).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||
AddOrder.SignPrice = req.Price
|
||||
AddOrder.SignPriceType = req.PricePattern
|
||||
AddOrder.Rate = "0"
|
||||
}
|
||||
buyPrice, _ := decimal.NewFromString(req.BuyPrice) //购买多少U
|
||||
buyPrice := utility.StrToDecimal(req.BuyPrice) //购买多少U
|
||||
var symbolInfo models.LineSymbol
|
||||
e.Orm.Model(&models.LineSymbol{}).Where("type = ? AND symbol = ?", req.SymbolType, req.Symbol).Find(&symbolInfo)
|
||||
//计算购买数量 判断是否是否是U本位
|
||||
@ -426,9 +427,31 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
ReduceTakeProfitRatio: req.ReduceTakeProfitRatio,
|
||||
ReduceStopLossRatio: req.ReduceStopLossRatio,
|
||||
}
|
||||
mainPrice := utility.StringToDecimal(AddOrder.Price)
|
||||
mainAmount := buyPrice.Div(mainPrice)
|
||||
defultExt.TotalAfterReducing = mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio)).Div(decimal.NewFromInt(100)).Truncate(int32(tradeSet.AmountDigit))
|
||||
preOrderExts = append(preOrderExts, defultExt)
|
||||
|
||||
for _, addPosition := range req.Ext {
|
||||
calculateResp := dto.CalculateBreakEvenRatioResp{}
|
||||
mainParam := dto.CalculateBreakEevenRatioReq{
|
||||
Price: mainPrice,
|
||||
ExchangeType: req.ExchangeType,
|
||||
Symbol: req.Symbol,
|
||||
SymbolType: req.SymbolType,
|
||||
BuyPrice: buyPrice,
|
||||
LossBeginPercent: decimal.Zero,
|
||||
LossEndPercent: req.ReducePriceRatio,
|
||||
AddPositionType: 2,
|
||||
AddPositionVal: decimal.Zero,
|
||||
ReducePercent: req.ReduceNumRatio,
|
||||
}
|
||||
|
||||
//计算减仓后
|
||||
mainParam.LossBeginPercent = req.ReducePriceRatio
|
||||
mainParam.RemainingQuantity = mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
mainParam.TotalLossAmountU = buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit))
|
||||
|
||||
for index, addPosition := range req.Ext {
|
||||
ext := models.LinePreOrderExt{
|
||||
TakeProfitRatio: addPosition.TakeProfitRatio,
|
||||
ReducePriceRatio: addPosition.ReducePriceRatio,
|
||||
@ -441,6 +464,30 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
AddPositionVal: addPosition.AddPositionVal,
|
||||
}
|
||||
|
||||
mainParam.LossEndPercent = req.Ext[index].AddPositionPriceRatio
|
||||
mainParam.AddPositionType = req.Ext[index].AddPositionType
|
||||
mainParam.AddPositionVal = req.Ext[index].AddPositionVal
|
||||
mainParam.ReducePercent = decimal.Zero
|
||||
e.CalculateBreakEvenRatio(&mainParam, &calculateResp)
|
||||
|
||||
ext.TotalAfterAdding = calculateResp.RemainingQuantity
|
||||
req.Ext[index].ReTakeProfitRatio = calculateResp.Ratio
|
||||
mainParam.LossBeginPercent = req.Ext[index].AddPositionPriceRatio
|
||||
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
|
||||
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
|
||||
mainParam.LossEndPercent = req.Ext[index].ReducePriceRatio
|
||||
mainParam.AddPositionVal = decimal.Zero
|
||||
mainParam.ReducePercent = req.Ext[index].ReduceNumRatio
|
||||
e.CalculateBreakEvenRatio(&mainParam, &calculateResp)
|
||||
|
||||
req.Ext[index].ReduceReTakeProfitRatio = calculateResp.Ratio
|
||||
mainParam.LossBeginPercent = req.Ext[index].ReducePriceRatio
|
||||
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
|
||||
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
|
||||
|
||||
ext.TotalAfterReducing = calculateResp.RemainingQuantity
|
||||
ext.ReTakeRatio = req.Ext[index].ReTakeProfitRatio
|
||||
ext.ReduceReTakeRatio = req.Ext[index].ReduceReTakeProfitRatio
|
||||
preOrderExts = append(preOrderExts, ext)
|
||||
}
|
||||
|
||||
@ -520,10 +567,77 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
stopOrder.OrderType = 4
|
||||
stopOrder.Status = 0
|
||||
stopOrder.Rate = req.ReducePriceRatio.String()
|
||||
stopOrder.Num = utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
|
||||
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 {
|
||||
logger.Errorf("主单减仓生成止盈、减仓失败 err:%v", err)
|
||||
return err
|
||||
} else if len(newOrders) > 0 {
|
||||
if err := e.Orm.Create(&newOrders).Error; err != nil {
|
||||
logger.Errorf("主单减仓保存止盈、减仓失败 err:%v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//添加止盈单
|
||||
for index, v := range preOrderExts {
|
||||
preOrderExts[index].MainOrderId = AddOrder.Id
|
||||
if index == 0 {
|
||||
preOrderExts[index].OrderId = AddOrder.Id
|
||||
continue
|
||||
}
|
||||
|
||||
addPosition := createPreAddPosition(&AddOrder, v, tradeSet)
|
||||
|
||||
if addPosition.OrderSn == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
preOrderExts[index].OrderId = addPosition.Id
|
||||
if err := e.Orm.Create(&addPosition).Error; err != nil {
|
||||
logger.Error("保存加仓单失败")
|
||||
return err
|
||||
}
|
||||
|
||||
//止盈、减仓
|
||||
orders, err := makeFuturesTakeAndReduce(&addPosition, v, tradeSet)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("构造加仓单止盈、减仓失败")
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.Orm.Create(&orders).Error; err != nil {
|
||||
logger.Error("保存加仓单止盈、减仓失败")
|
||||
return err
|
||||
}
|
||||
|
||||
for index := range orders {
|
||||
//减仓单且 减仓比例大于0 小于100 就冲下止盈止损
|
||||
if orders[index].OrderType == 4 && v.ReduceNumRatio.Cmp(decimal.Zero) > 0 && v.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 {
|
||||
reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("生产加仓单止盈、减仓失败")
|
||||
return err
|
||||
}
|
||||
|
||||
if len(reduceChildOrders) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := e.Orm.Create(&reduceChildOrders).Error; err != nil {
|
||||
logger.Error("报错减仓后止盈止损失败")
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -531,6 +645,160 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
return nil
|
||||
}
|
||||
|
||||
// 生成加仓单
|
||||
func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderExt, tradeSet models2.TradeSet) models.LinePreOrder {
|
||||
data := models.LinePreOrder{}
|
||||
//主单类型
|
||||
if v.AddPositionVal.Cmp(decimal.Zero) <= 0 {
|
||||
logger.Errorf("预生成加仓单失败, 主订单号:%s 加仓数值不大于0", preOrder.OrderSn)
|
||||
return data
|
||||
}
|
||||
|
||||
price := utility.StrToDecimal(preOrder.Price)
|
||||
copier.Copy(&data, preOrder)
|
||||
|
||||
data.Id = 0
|
||||
data.Pid = preOrder.Id
|
||||
data.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
data.MainId = preOrder.Id
|
||||
data.CreatedAt = time.Now()
|
||||
data.MainOrderType = v.AddPositionOrderType
|
||||
data.Status = 0
|
||||
data.OrderCategory = 3
|
||||
data.Rate = v.AddPositionPriceRatio.String()
|
||||
var percentage decimal.Decimal
|
||||
|
||||
if data.Site == "BUY" {
|
||||
percentage = decimal.NewFromInt(1).Sub(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
|
||||
} else {
|
||||
percentage = decimal.NewFromInt(1).Add(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
|
||||
}
|
||||
|
||||
dataPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||
data.Price = dataPrice.String()
|
||||
|
||||
if v.AddPositionType == 1 {
|
||||
buyPrice := utility.StrToDecimal(preOrder.BuyPrice).Mul(v.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(2)
|
||||
data.Num = buyPrice.Div(dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
data.BuyPrice = buyPrice.String()
|
||||
} else {
|
||||
data.BuyPrice = v.AddPositionVal.Truncate(2).String()
|
||||
data.Num = v.AddPositionVal.Truncate(2).Div(dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// 构建合约止盈、减仓单
|
||||
func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) {
|
||||
num := ext.TotalAfterAdding
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
//止盈单
|
||||
profitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&profitOrder, preOrder)
|
||||
|
||||
profitOrder.Id = 0
|
||||
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
profitOrder.Pid = preOrder.Id
|
||||
profitOrder.OrderType = 1
|
||||
profitOrder.Status = 0
|
||||
profitOrder.MainId = preOrder.MainId
|
||||
profitOrder.Num = num.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
profitOrder.BuyPrice = "0"
|
||||
// profitOrder.Rate = ext.TakeProfitRatio.String()
|
||||
|
||||
//止盈需要累加之前的亏损
|
||||
profitOrder.Rate = ext.TakeProfitRatio.Add(ext.ReTakeRatio).Truncate(2).String()
|
||||
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
profitOrder.Site = "SELL"
|
||||
} else {
|
||||
profitOrder.Site = "BUY"
|
||||
}
|
||||
|
||||
binanceservice.SetPrice(&profitOrder, preOrder, tradeSet)
|
||||
orders = append(orders, profitOrder)
|
||||
|
||||
//减仓单
|
||||
if ext.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
|
||||
stopOrder := models.LinePreOrder{}
|
||||
copier.Copy(&stopOrder, preOrder)
|
||||
|
||||
stopOrder.Id = 0
|
||||
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
stopOrder.Pid = preOrder.Id
|
||||
stopOrder.MainId = preOrder.MainId
|
||||
stopOrder.OrderType = 4
|
||||
stopOrder.Status = 0
|
||||
stopOrder.Rate = ext.ReducePriceRatio.String()
|
||||
stopOrder.Num = num.String()
|
||||
stopOrder.BuyPrice = "0"
|
||||
|
||||
if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 {
|
||||
stopOrder.Num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
}
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
stopOrder.Site = "SELL"
|
||||
} else {
|
||||
stopOrder.Site = "BUY"
|
||||
}
|
||||
|
||||
binanceservice.SetPrice(&stopOrder, preOrder, tradeSet)
|
||||
orders = append(orders, stopOrder)
|
||||
}
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// 构建减仓后止盈止损
|
||||
func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) {
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
takeProfitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&takeProfitOrder, parentOrder)
|
||||
takeProfitOrder.Id = 0
|
||||
takeProfitOrder.Pid = parentOrder.Id
|
||||
takeProfitOrder.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
takeProfitOrder.Status = 0
|
||||
takeProfitOrder.OrderType = 1
|
||||
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
|
||||
takeProfitOrder.SignPrice = parentOrder.Price
|
||||
takeProfitOrder.CreatedAt = time.Now()
|
||||
takeProfitOrder.BuyPrice = "0"
|
||||
takeProfitOrder.MainOrderType = "LIMIT"
|
||||
takeProfitOrder.Num = ext.TotalAfterReducing.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
// takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
|
||||
//止盈需要累加之前的亏损
|
||||
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.Add(ext.ReduceReTakeRatio).String()
|
||||
takeProfitOrder.BuyPrice = "0"
|
||||
|
||||
binanceservice.SetPrice(&takeProfitOrder, parentOrder, tradeSet)
|
||||
orders = append(orders, takeProfitOrder)
|
||||
|
||||
//有止损单
|
||||
if ext.ReduceStopLossRatio.Cmp(decimal.Zero) > 0 {
|
||||
var stoploss models.LinePreOrder
|
||||
|
||||
copier.Copy(&stoploss, parentOrder)
|
||||
stoploss.Id = 0
|
||||
stoploss.Pid = parentOrder.Id
|
||||
stoploss.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
stoploss.Status = 0
|
||||
stoploss.CreatedAt = time.Now()
|
||||
stoploss.OrderType = 2
|
||||
stoploss.SignPrice = parentOrder.Price
|
||||
stoploss.BuyPrice = "0"
|
||||
stoploss.Rate = ext.ReduceStopLossRatio.String()
|
||||
stoploss.MainOrderType = "LIMIT"
|
||||
stoploss.Num = ext.TotalAfterReducing.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
stoploss.BuyPrice = "0"
|
||||
|
||||
binanceservice.SetPrice(&stoploss, parentOrder, tradeSet)
|
||||
orders = append(orders, stoploss)
|
||||
}
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// CheckRepeatOrder 检查重复下单 检查基础货币
|
||||
func (e *LinePreOrder) CheckRepeatOrder(orderType int, apiUserId, site, baseCoin string) int64 {
|
||||
var count int64
|
||||
@ -1317,6 +1585,83 @@ func (e *LinePreOrder) QueryAiCoinPrice(req *dto.QueryAiCoinPriceReq) (models.Li
|
||||
return info, err
|
||||
}
|
||||
|
||||
// 根据请求参数重新生成亏损回本止盈百分比
|
||||
func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) ([]models.LineDirection, error) {
|
||||
var tradeSet models2.TradeSet
|
||||
var tickerPrice decimal.Decimal
|
||||
|
||||
if req.SymbolType == 1 {
|
||||
tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 0)
|
||||
} else {
|
||||
tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 1)
|
||||
}
|
||||
|
||||
if tradeSet.LastPrice == "" {
|
||||
return nil, errors.New("获取不到交易对信息")
|
||||
}
|
||||
|
||||
var price decimal.Decimal
|
||||
tickerPrice = utility.StrToDecimal(tradeSet.LastPrice)
|
||||
if req.PricePattern == "percentage" {
|
||||
orderPrice, _ := decimal.NewFromString(req.Price) //下单价百分比 10%
|
||||
priceRate := orderPrice.Div(decimal.NewFromInt(100)) //下单价除100 =0.1
|
||||
if strings.ToUpper(req.Site) == "BUY" { //购买方向
|
||||
//实际下单价格
|
||||
price = tickerPrice.Mul(decimal.NewFromInt(1).Sub(priceRate)).Truncate(int32(tradeSet.PriceDigit))
|
||||
} else {
|
||||
price = tickerPrice.Mul(decimal.NewFromInt(1).Add(priceRate)).Truncate(int32(tradeSet.PriceDigit))
|
||||
}
|
||||
|
||||
} else { //实际价格下单
|
||||
price = utility.StringToDecimal(req.Price).Truncate(int32(tradeSet.PriceDigit))
|
||||
}
|
||||
|
||||
buyPrice := utility.StrToDecimal(req.BuyPrice)
|
||||
mainAmount := buyPrice.Div(price)
|
||||
calculateResp := dto.CalculateBreakEvenRatioResp{}
|
||||
mainParam := dto.CalculateBreakEevenRatioReq{
|
||||
Price: price,
|
||||
ExchangeType: req.ExchangeType,
|
||||
Symbol: req.Symbol,
|
||||
SymbolType: req.SymbolType,
|
||||
BuyPrice: buyPrice,
|
||||
LossBeginPercent: decimal.Zero,
|
||||
LossEndPercent: req.ReducePriceRatio,
|
||||
AddPositionType: 2,
|
||||
AddPositionVal: decimal.Zero,
|
||||
ReducePercent: req.ReduceNumRatio,
|
||||
}
|
||||
|
||||
//计算减仓后
|
||||
mainParam.LossBeginPercent = req.ReducePriceRatio
|
||||
mainParam.RemainingQuantity = mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
mainParam.TotalLossAmountU = buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit))
|
||||
|
||||
for index := range req.Ext {
|
||||
mainParam.LossEndPercent = req.Ext[index].AddPositionPriceRatio
|
||||
mainParam.AddPositionType = req.Ext[index].AddPositionType
|
||||
mainParam.AddPositionVal = req.Ext[index].AddPositionVal
|
||||
mainParam.ReducePercent = decimal.Zero
|
||||
e.CalculateBreakEvenRatio(&mainParam, &calculateResp)
|
||||
|
||||
req.Ext[index].ReTakeProfitRatio = calculateResp.Ratio
|
||||
mainParam.LossBeginPercent = req.Ext[index].AddPositionPriceRatio
|
||||
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
|
||||
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
|
||||
mainParam.LossEndPercent = req.Ext[index].ReducePriceRatio
|
||||
mainParam.AddPositionVal = decimal.Zero
|
||||
mainParam.ReducePercent = req.Ext[index].ReduceNumRatio
|
||||
e.CalculateBreakEvenRatio(&mainParam, &calculateResp)
|
||||
|
||||
req.Ext[index].ReduceReTakeProfitRatio = calculateResp.Ratio
|
||||
mainParam.LossBeginPercent = req.Ext[index].ReducePriceRatio
|
||||
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
|
||||
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 计算亏损百分比
|
||||
func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatioReq, data *dto.CalculateBreakEvenRatioResp) error {
|
||||
var tradeSet models2.TradeSet
|
||||
@ -1351,7 +1696,7 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio
|
||||
|
||||
var percentDiff decimal.Decimal
|
||||
var reduceAmount decimal.Decimal
|
||||
nowPrice := req.Price.Mul(decimal.NewFromInt(1).Sub(req.LossEndPercent.Div(decimal.NewFromInt(100).Truncate(4))))
|
||||
nowPrice := req.Price.Mul(decimal.NewFromInt(1).Sub(req.LossEndPercent.Div(decimal.NewFromInt(100)).Truncate(4))).Truncate(int32(tradeSet.PriceDigit))
|
||||
addPositionAmount := addPositionBuyPrice.Div(nowPrice).Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
//计算价格下跌价差
|
||||
@ -1360,7 +1705,7 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio
|
||||
}
|
||||
|
||||
totalAmount := req.RemainingQuantity.Add(addPositionAmount)
|
||||
lossAmountU := req.Price.Mul(percentDiff.Div(decimal.NewFromInt(100)).Truncate(4)).Mul(req.RemainingQuantity).Truncate(int32(tradeSet.AmountDigit))
|
||||
lossAmountU := req.Price.Mul(percentDiff.Div(decimal.NewFromInt(100).Truncate(4))).Mul(req.RemainingQuantity).Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
//计算减仓数量
|
||||
if req.ReducePercent.Cmp(decimal.NewFromInt(0)) > 0 {
|
||||
@ -1373,6 +1718,8 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio
|
||||
//计算百分比
|
||||
if data.RemainingQuantity.Cmp(decimal.Zero) > 0 {
|
||||
data.Ratio = data.TotalLossAmountU.Div(data.RemainingQuantity).Div(nowPrice).Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||
} else {
|
||||
data.Ratio = decimal.Zero
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -158,7 +158,7 @@ func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
||||
}
|
||||
limitOrderTimeoutDuration := utility.StringAsInt64(resp.ConfigValue)
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
err := db.Model(&models.LinePreOrder{}).Where("status = '5' AND main_order_type = 'LIMIT' AND order_type in ('0','4') AND order_category = 3 AND updated_at < ?", time.Now().Add(-time.Duration(limitOrderTimeoutDuration)*time.Second)).Find(&orders).Error
|
||||
err := db.Model(&models.LinePreOrder{}).Where("status = '5' AND main_order_type = 'LIMIT' AND order_type in ('4') AND order_category = 3 AND updated_at < ?", time.Now().Add(-time.Duration(limitOrderTimeoutDuration)*time.Second)).Find(&orders).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -12,14 +12,11 @@ import (
|
||||
"go-admin/common/helper"
|
||||
models2 "go-admin/models"
|
||||
"go-admin/pkg/utility"
|
||||
"go-admin/pkg/utility/snowflakehelper"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@ -115,12 +112,6 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta
|
||||
// 减仓回调
|
||||
func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
apiUserInfo, _ := GetApiInfo(preOrder.ApiId)
|
||||
mainId := preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
mainId = preOrder.MainId
|
||||
}
|
||||
|
||||
if apiUserInfo.Id == 0 {
|
||||
logger.Errorf("handleMainReduceFilled 获取api信息失败,订单号:%s", preOrder.OrderSn)
|
||||
return
|
||||
@ -161,74 +152,12 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
}
|
||||
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
rate := utility.StringAsFloat(preOrder.Rate)
|
||||
ext := models.LinePreOrderExt{}
|
||||
//获取订单配置
|
||||
db.Model(&ext).Where("order_id =?", preOrder.Pid).First(&ext)
|
||||
|
||||
// 不是100%减仓 就需要挂止盈止损
|
||||
if rate >= 100 {
|
||||
removeFutLossAndAddPosition(preOrder)
|
||||
ids := []int{preOrder.MainId, preOrder.Pid}
|
||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6", ids).Update("status", 9).Error; err != nil {
|
||||
logger.Info("100%减仓完毕,终结流程")
|
||||
}
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status = 0", preOrder.Id).Find(&orders).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 获取待触发订单失败,订单号:%s", preOrder.OrderSn)
|
||||
return
|
||||
}
|
||||
|
||||
totalLossAmountU, _ := GetTotalLossAmount(db, mainId)
|
||||
totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet)
|
||||
|
||||
takeProfitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&takeProfitOrder, &preOrder)
|
||||
takeProfitOrder.Id = 0
|
||||
takeProfitOrder.Pid = preOrder.Id
|
||||
takeProfitOrder.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
takeProfitOrder.Status = 0
|
||||
takeProfitOrder.Price = price.Mul(decimal.NewFromInt(1).Add(ext.TakeProfitRatio)).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||
takeProfitOrder.OrderType = 1
|
||||
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
|
||||
takeProfitOrder.SignPrice = preOrder.Price
|
||||
takeProfitOrder.CreatedAt = time.Now()
|
||||
takeProfitOrder.BuyPrice = "0"
|
||||
takeProfitOrder.MainOrderType = "LIMIT"
|
||||
takeProfitOrder.Num = totalNum.String()
|
||||
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
|
||||
//止盈需要累加之前的亏损
|
||||
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
|
||||
percent := totalLossAmountU.Div(totalNum).Div(price).Abs()
|
||||
takeProfitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.ReduceTakeProfitRatio).Truncate(2).String()
|
||||
}
|
||||
|
||||
setPrice(&takeProfitOrder, preOrder, tradeSet)
|
||||
orders = append(orders, takeProfitOrder)
|
||||
|
||||
//有止损单
|
||||
if ext.ReduceStopLossRatio.Cmp(decimal.Zero) > 0 {
|
||||
var stoploss models.LinePreOrder
|
||||
|
||||
copier.Copy(&stoploss, &preOrder)
|
||||
stoploss.Id = 0
|
||||
stoploss.Pid = preOrder.Id
|
||||
stoploss.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
stoploss.Status = 0
|
||||
stoploss.CreatedAt = time.Now()
|
||||
stoploss.OrderType = 2
|
||||
stoploss.SignPrice = preOrder.Price
|
||||
stoploss.BuyPrice = "0"
|
||||
stoploss.Rate = ext.ReduceStopLossRatio.String()
|
||||
stoploss.MainOrderType = "LIMIT"
|
||||
stoploss.Num = totalNum.String()
|
||||
|
||||
setPrice(&stoploss, preOrder, tradeSet)
|
||||
orders = append(orders, stoploss)
|
||||
}
|
||||
|
||||
if err := db.Create(&orders).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 创建止盈止损单失败:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
futApi := FutRestApi{}
|
||||
for _, v := range orders {
|
||||
if v.OrderType == 1 {
|
||||
@ -435,37 +364,27 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) {
|
||||
return
|
||||
}
|
||||
|
||||
//预生成加仓单
|
||||
shouldReturn := createFutPreAddPosition(preOrder, db, tradeSet)
|
||||
if shouldReturn {
|
||||
return
|
||||
}
|
||||
|
||||
if preOrder.OrderCategory == 3 {
|
||||
if err := cancelSymbolTakeAndStop(db, preOrder.MainId, preOrder.SymbolType); err != nil {
|
||||
logger.Errorf("取消止盈止损订单失败 orderSn:%s err:%v", preOrder.OrderSn, err)
|
||||
}
|
||||
}
|
||||
|
||||
apiInfo, err := GetApiInfo(preOrder.ApiId)
|
||||
if apiInfo.Id == 0 {
|
||||
logger.Error("订单回调查询apiuserinfo失败 err:", err)
|
||||
return
|
||||
}
|
||||
if err := db.Model(&DbModels.LinePreOrder{}).
|
||||
Where("pid = ? AND order_type > 0 AND status = '0' ", preOrder.Id).
|
||||
Find(&orders).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
logger.Error("订单回调查询止盈止损单失败:", err)
|
||||
return
|
||||
} else if len(orders) == 0 && preOrder.OrderCategory == 3 {
|
||||
orders, err = makeFuturesTakeAndReduce(preOrder, db, tradeSet, orders)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
futApi := FutRestApi{}
|
||||
num, _ := decimal.NewFromString(preOrder.Num)
|
||||
num := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet)
|
||||
|
||||
for i, order := range orders {
|
||||
if i >= 2 { // 最多处理 2 个订单
|
||||
break
|
||||
}
|
||||
for _, order := range orders {
|
||||
price := utility.StrToDecimal(order.Price).Truncate(int32(tradeSet.PriceDigit))
|
||||
num = num.Truncate(int32(tradeSet.AmountDigit))
|
||||
order.Price = price.String()
|
||||
@ -495,184 +414,6 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) {
|
||||
}
|
||||
}
|
||||
|
||||
// 生成加仓单
|
||||
func createFutPreAddPosition(preOrder *DbModels.LinePreOrder, db *gorm.DB, tradeSet models2.TradeSet) bool {
|
||||
//主单类型
|
||||
if preOrder.OrderCategory == 1 {
|
||||
orderExts, err := GetOrderExts(db, preOrder.Id)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("预生成加仓单失败, 回调订单号:%s 获取主单拓展配置失败:%v", preOrder.OrderSn, err)
|
||||
return true
|
||||
}
|
||||
|
||||
price := utility.StrToDecimal(preOrder.Price)
|
||||
for _, v := range orderExts {
|
||||
if v.OrderId == 0 {
|
||||
var data DbModels.LinePreOrder
|
||||
|
||||
copier.Copy(&data, &preOrder)
|
||||
|
||||
data.Id = 0
|
||||
data.Pid = preOrder.Id
|
||||
data.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
data.MainId = preOrder.Id
|
||||
data.CreatedAt = time.Now()
|
||||
data.MainOrderType = v.AddPositionOrderType
|
||||
data.Status = 0
|
||||
data.OrderCategory = 3
|
||||
data.Rate = v.AddPositionPriceRatio.String()
|
||||
var percentage decimal.Decimal
|
||||
|
||||
if data.Site == "BUY" {
|
||||
percentage = decimal.NewFromInt(1).Sub(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
|
||||
} else {
|
||||
percentage = decimal.NewFromInt(1).Add(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
|
||||
}
|
||||
|
||||
dataPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||
data.Price = dataPrice.String()
|
||||
|
||||
if v.AddPositionType == 1 {
|
||||
data.Num = utility.StrToDecimal(preOrder.Num).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
data.BuyPrice = "0"
|
||||
} else {
|
||||
data.BuyPrice = v.AddPositionVal.String()
|
||||
data.Num = v.AddPositionVal.Div(dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
}
|
||||
|
||||
err := db.Transaction(func(tx *gorm.DB) error {
|
||||
if err2 := tx.Create(&data).Error; err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
v.OrderId = data.Id
|
||||
if err2 := tx.Model(&v).Update("order_id", data.Id).Error; err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("预生成加仓单失败, 回调订单号:%s 预生成加仓单失败:%v", preOrder.OrderSn, err)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 构建合约止盈、减仓单
|
||||
func makeFuturesTakeAndReduce(preOrder *DbModels.LinePreOrder, db *gorm.DB, tradeSet models2.TradeSet, orders []DbModels.LinePreOrder) ([]DbModels.LinePreOrder, error) {
|
||||
ext := models.LinePreOrderExt{}
|
||||
apiInfo, err := GetApiInfo(preOrder.ApiId)
|
||||
price := utility.StrToDecimal(preOrder.Price)
|
||||
|
||||
if apiInfo.Id == 0 {
|
||||
logger.Error("订单回调查询apiuserinfo失败 err:", err)
|
||||
return nil, errors.New("订单回调查询apiuserinfo失败")
|
||||
}
|
||||
|
||||
if err := db.Model(&ext).Where("order_id = ?", preOrder.Id).First(&ext).Error; err != nil {
|
||||
logger.Error("订单回调查询止盈止损单扩展表失败:", err)
|
||||
return nil, errors.New("订单回调查询止盈止损单扩展表失败")
|
||||
}
|
||||
|
||||
totalLossAmountU, _ := GetTotalLossAmount(db, preOrder.MainId)
|
||||
num := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet)
|
||||
|
||||
//止盈单
|
||||
if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
||||
profitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&profitOrder, preOrder)
|
||||
|
||||
profitOrder.Id = 0
|
||||
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
profitOrder.Pid = preOrder.Id
|
||||
profitOrder.OrderType = 1
|
||||
profitOrder.Status = 0
|
||||
profitOrder.MainId = ext.MainOrderId
|
||||
profitOrder.Num = num.String()
|
||||
profitOrder.Rate = ext.TakeProfitRatio.String()
|
||||
|
||||
//止盈需要累加之前的亏损
|
||||
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
|
||||
percent := totalLossAmountU.Div(num).Div(price).Abs()
|
||||
profitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.TakeProfitRatio).Truncate(2).String()
|
||||
}
|
||||
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
profitOrder.Site = "SELL"
|
||||
} else {
|
||||
profitOrder.Site = "BUY"
|
||||
}
|
||||
|
||||
setPrice(&profitOrder, preOrder, tradeSet)
|
||||
orders = append(orders, profitOrder)
|
||||
}
|
||||
|
||||
//减仓单
|
||||
if ext.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
|
||||
stopOrder := models.LinePreOrder{}
|
||||
copier.Copy(&stopOrder, preOrder)
|
||||
|
||||
stopOrder.Id = 0
|
||||
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
stopOrder.Pid = preOrder.Id
|
||||
stopOrder.MainId = ext.MainOrderId
|
||||
stopOrder.OrderType = 4
|
||||
stopOrder.Status = 0
|
||||
stopOrder.Rate = ext.ReducePriceRatio.String()
|
||||
stopOrder.Num = num.String()
|
||||
|
||||
if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 {
|
||||
stopOrder.Num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
} else {
|
||||
stopOrder.Num = num.String()
|
||||
}
|
||||
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
stopOrder.Site = "SELL"
|
||||
} else {
|
||||
stopOrder.Site = "BUY"
|
||||
}
|
||||
|
||||
setPrice(&stopOrder, preOrder, tradeSet)
|
||||
orders = append(orders, stopOrder)
|
||||
}
|
||||
|
||||
for index := range orders {
|
||||
orderRate := utility.StrToDecimal(orders[index].Rate)
|
||||
orderType := orders[index].OrderType
|
||||
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
orders[index].Site = "SELL"
|
||||
} else {
|
||||
orders[index].Site = "BUY"
|
||||
}
|
||||
|
||||
switch {
|
||||
//做多止盈、做空止损或减仓
|
||||
case (orderType == 1 && preOrder.Site == "BUY"), ((orderType == 2 || orderType == 4) && preOrder.Site == "SELL"):
|
||||
orders[index].Price = utility.StrToDecimal(preOrder.Price).Mul(decimal.NewFromInt(1).Add(orderRate.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||
//做多止损或减仓、做空止盈
|
||||
case ((orderType == 2 || orderType == 4) && preOrder.Site == "BUY"), (orderType == 1 && preOrder.Site == "SELL"):
|
||||
orders[index].Price = utility.StrToDecimal(preOrder.Price).Mul(decimal.NewFromInt(1).Sub(orderRate.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||
}
|
||||
}
|
||||
|
||||
if len(orders) > 0 {
|
||||
if err := db.Create(&orders).Error; err != nil {
|
||||
logger.Error("主单回调,创建止盈、减仓单失败")
|
||||
return orders, errors.New("主单回调,创建止盈、减仓单失败")
|
||||
}
|
||||
}
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// 减仓单
|
||||
func processFutReduceOrder(order DbModels.LinePreOrder, price, num decimal.Decimal) {
|
||||
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
||||
|
||||
@ -12,14 +12,12 @@ import (
|
||||
"go-admin/common/helper"
|
||||
models2 "go-admin/models"
|
||||
"go-admin/pkg/utility"
|
||||
"go-admin/pkg/utility/snowflakehelper"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@ -144,11 +142,6 @@ func handleOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderStatus
|
||||
// 主单减仓完毕
|
||||
func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
apiUserInfo, _ := GetApiInfo(preOrder.ApiId)
|
||||
mainId := preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
mainId = preOrder.MainId
|
||||
}
|
||||
|
||||
if apiUserInfo.Id == 0 {
|
||||
logger.Errorf("handleMainReduceFilled 获取api信息失败,订单号:%s", preOrder.OrderSn)
|
||||
@ -162,13 +155,8 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
return
|
||||
}
|
||||
|
||||
price := utility.StrToDecimal(preOrder.Price)
|
||||
parentOrder, _ := GetOrderById(db, preOrder.Pid)
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
rate := utility.StringAsFloat(preOrder.Rate)
|
||||
ext := models.LinePreOrderExt{}
|
||||
//获取订单配置
|
||||
db.Model(&ext).Where("order_id =?", preOrder.Pid).First(&ext)
|
||||
|
||||
// 100%减仓 终止流程
|
||||
if rate >= 100 {
|
||||
@ -179,95 +167,36 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
}
|
||||
return
|
||||
}
|
||||
totalLossAmountU, _ := GetTotalLossAmount(db, mainId)
|
||||
|
||||
totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet)
|
||||
|
||||
takeProfitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&takeProfitOrder, &preOrder)
|
||||
takeProfitOrder.Id = 0
|
||||
takeProfitOrder.Pid = preOrder.Id
|
||||
takeProfitOrder.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
takeProfitOrder.Status = 0
|
||||
// takeProfitOrder.Price = price.Mul(decimal.NewFromInt(1).Add(ext.TakeProfitRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||
takeProfitOrder.OrderType = 1
|
||||
takeProfitOrder.Rate = "100"
|
||||
takeProfitOrder.SignPrice = preOrder.Price
|
||||
takeProfitOrder.CreatedAt = time.Now()
|
||||
takeProfitOrder.BuyPrice = "0"
|
||||
takeProfitOrder.MainOrderType = "LIMIT"
|
||||
takeProfitOrder.Num = totalNum.String()
|
||||
takeProfitOrder.Rate = ext.ReduceTakeProfitRatio.String()
|
||||
//止盈需要累加之前的亏损
|
||||
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
|
||||
percent := totalLossAmountU.Div(totalNum).Div(price).Abs()
|
||||
takeProfitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.ReduceTakeProfitRatio).Truncate(2).String()
|
||||
}
|
||||
|
||||
setPrice(&takeProfitOrder, preOrder, tradeSet)
|
||||
orders = append(orders, takeProfitOrder)
|
||||
|
||||
//有止损单
|
||||
if ext.ReduceStopLossRatio.Cmp(decimal.Zero) > 0 {
|
||||
var stoploss models.LinePreOrder
|
||||
|
||||
copier.Copy(&stoploss, &preOrder)
|
||||
stoploss.Id = 0
|
||||
stoploss.Pid = preOrder.Id
|
||||
stoploss.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
stoploss.Status = 0
|
||||
stoploss.CreatedAt = time.Now()
|
||||
stoploss.OrderType = 2
|
||||
stoploss.SignPrice = preOrder.Price
|
||||
stoploss.BuyPrice = "0"
|
||||
stoploss.Rate = ext.ReduceStopLossRatio.String()
|
||||
stoploss.MainOrderType = "LIMIT"
|
||||
stoploss.Num = totalNum.String()
|
||||
// stoploss.Price = price.Mul(decimal.NewFromInt(1).Sub(ext.ReduceStopLossRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
|
||||
setPrice(&stoploss, preOrder, tradeSet)
|
||||
orders = append(orders, stoploss)
|
||||
}
|
||||
|
||||
if err := db.Create(&orders).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 创建止盈止损单失败:%v", err)
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status=0", preOrder.Id).Find(&orders).Error; err != nil {
|
||||
logger.Errorf("获取减仓单止盈止损失败 err:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
spotApi := SpotRestApi{}
|
||||
paramsMap := OrderPlacementService{
|
||||
ApiId: takeProfitOrder.ApiId,
|
||||
Symbol: takeProfitOrder.Symbol,
|
||||
Side: takeProfitOrder.Site,
|
||||
Type: "LIMIT",
|
||||
TimeInForce: "GTC",
|
||||
Price: utility.StrToDecimal(takeProfitOrder.Price),
|
||||
Quantity: totalNum,
|
||||
NewClientOrderId: takeProfitOrder.OrderSn,
|
||||
StopPrice: utility.StrToDecimal(takeProfitOrder.Price),
|
||||
}
|
||||
if err := spotApi.OrderPlaceLoop(db, paramsMap, 3); err != nil {
|
||||
logger.Errorf("减仓后重下止盈失败 减仓order_sn:%s err:%v", preOrder.OrderSn, err)
|
||||
|
||||
if err2 := db.Model(&takeProfitOrder).Updates(map[string]interface{}{"status": 2, "": err.Error()}).Error; err2 != nil {
|
||||
logger.Errorf("handleMainReduceFilled 更新止盈单失败:%v", err2)
|
||||
}
|
||||
}
|
||||
for index := range orders {
|
||||
orders[index].Num = totalNum.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
|
||||
for _, item := range orders {
|
||||
if item.OrderType == 2 {
|
||||
processStopLossOrder(item)
|
||||
if orders[index].OrderType == 1 {
|
||||
processTakeProfitOrder(db, spotApi, orders[index])
|
||||
} else if orders[index].OrderType == 2 {
|
||||
processStopLossOrder(orders[index])
|
||||
}
|
||||
}
|
||||
|
||||
//计算实际亏损
|
||||
if parentOrder.Price != "" {
|
||||
parentPrice := utility.StrToDecimal(parentOrder.Price)
|
||||
reduceNum := utility.StrToDecimal(preOrder.Num)
|
||||
lossAmountU := price.Sub(parentPrice).Abs().Mul(reduceNum) //.Truncate(int32(tradeSet.PriceDigit))
|
||||
// if parentOrder.Price != "" {
|
||||
// parentPrice := utility.StrToDecimal(parentOrder.Price)
|
||||
// reduceNum := utility.StrToDecimal(preOrder.Num)
|
||||
// lossAmountU := price.Sub(parentPrice).Abs().Mul(reduceNum) //.Truncate(int32(tradeSet.PriceDigit))
|
||||
|
||||
if err := db.Model(&parentOrder).Update("loss_amount", lossAmountU).Error; err != nil {
|
||||
logger.Errorf("修改主单实际亏损失败 订单号:%s err:%v", parentOrder.OrderSn, err)
|
||||
}
|
||||
}
|
||||
// if err := db.Model(&parentOrder).Update("loss_amount", lossAmountU).Error; err != nil {
|
||||
// logger.Errorf("修改主单实际亏损失败 订单号:%s err:%v", parentOrder.OrderSn, err)
|
||||
// }
|
||||
// }
|
||||
|
||||
//加仓待触发
|
||||
addPositionOrder := DbModels.LinePreOrder{}
|
||||
@ -508,78 +437,6 @@ func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) {
|
||||
// 主单成交
|
||||
func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
processTakeProfitAndStopLossOrders(db, preOrder)
|
||||
tradeSet, _ := GetTradeSet(preOrder.Symbol, 0)
|
||||
|
||||
if tradeSet.Coin == "" {
|
||||
logger.Errorf("获取交易对配置失败, 回调订单号:%s", preOrder.OrderSn)
|
||||
return
|
||||
}
|
||||
|
||||
//主单类型
|
||||
if preOrder.OrderCategory == 1 {
|
||||
//预生成加仓单
|
||||
orderExts, err := GetOrderExts(db, preOrder.Id)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("预生成加仓单失败, 回调订单号:%s 获取主单拓展配置失败:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
}
|
||||
|
||||
price := utility.StrToDecimal(preOrder.Price)
|
||||
for _, v := range orderExts {
|
||||
if v.OrderId == 0 {
|
||||
var data DbModels.LinePreOrder
|
||||
|
||||
copier.Copy(&data, &preOrder)
|
||||
|
||||
data.Id = 0
|
||||
data.Pid = preOrder.Id
|
||||
data.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
data.MainId = preOrder.Id
|
||||
data.CreatedAt = time.Now()
|
||||
data.MainOrderType = v.AddPositionOrderType
|
||||
data.Status = 0
|
||||
data.OrderCategory = 3
|
||||
data.Rate = v.AddPositionPriceRatio.String()
|
||||
var percentage decimal.Decimal
|
||||
|
||||
if data.Site == "BUY" {
|
||||
percentage = decimal.NewFromInt(1).Sub(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
|
||||
} else {
|
||||
percentage = decimal.NewFromInt(1).Add(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100)))
|
||||
}
|
||||
|
||||
dataPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit))
|
||||
data.Price = dataPrice.String()
|
||||
|
||||
if v.AddPositionType == 1 {
|
||||
data.Num = preOrder.Num
|
||||
data.BuyPrice = "0"
|
||||
} else {
|
||||
data.BuyPrice = v.AddPositionVal.String()
|
||||
data.Num = v.AddPositionVal.Div(dataPrice).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
}
|
||||
|
||||
err := db.Transaction(func(tx *gorm.DB) error {
|
||||
if err2 := tx.Create(&data).Error; err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
v.OrderId = data.Id
|
||||
if err2 := tx.Model(&v).Update("order_id", data.Id).Error; err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("预生成加仓单失败, 回调订单号:%s 预生成加仓单失败:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 解析订单状态
|
||||
@ -674,12 +531,6 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
|
||||
Find(&orders).Error; err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
logger.Error("订单回调查询止盈止损单失败:", err)
|
||||
return
|
||||
} else if len(orders) == 0 && preOrder.OrderCategory == 3 {
|
||||
orders, err = makeSpotTakeAndReduce(preOrder, db, tradeSet, num)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
spotApi := SpotRestApi{}
|
||||
@ -711,88 +562,8 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
|
||||
}
|
||||
}
|
||||
|
||||
// 构建现货止盈、减仓单
|
||||
func makeSpotTakeAndReduce(preOrder *DbModels.LinePreOrder, db *gorm.DB, tradeSet models2.TradeSet, num decimal.Decimal) ([]DbModels.LinePreOrder, error) {
|
||||
ext := models.LinePreOrderExt{}
|
||||
price := utility.StrToDecimal(preOrder.Price)
|
||||
orders := make([]DbModels.LinePreOrder, 0)
|
||||
|
||||
if err := db.Model(&ext).Where("order_id = ?", preOrder.Id).First(&ext).Error; err != nil {
|
||||
logger.Error("订单回调查询止盈止损单扩展表失败:", err)
|
||||
return nil, errors.New("订单回调查询止盈止损单扩展表失败")
|
||||
}
|
||||
|
||||
totalLossAmountU, _ := GetTotalLossAmount(db, preOrder.MainId)
|
||||
|
||||
//止盈单
|
||||
if ext.TakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
||||
profitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&profitOrder, preOrder)
|
||||
|
||||
profitOrder.Id = 0
|
||||
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
profitOrder.Pid = preOrder.Id
|
||||
profitOrder.OrderType = 1
|
||||
profitOrder.Status = 0
|
||||
profitOrder.Rate = ext.TakeProfitRatio.String()
|
||||
profitOrder.MainId = ext.MainOrderId
|
||||
profitOrder.Num = num.String()
|
||||
|
||||
//止盈需要累加之前的亏损
|
||||
if totalLossAmountU.Cmp(decimal.Zero) > 0 {
|
||||
percent := totalLossAmountU.Div(num).Div(price).Abs()
|
||||
profitOrder.Rate = percent.Mul(decimal.NewFromInt(100)).Add(ext.TakeProfitRatio).Truncate(2).String()
|
||||
}
|
||||
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
profitOrder.Site = "SELL"
|
||||
} else {
|
||||
profitOrder.Site = "BUY"
|
||||
}
|
||||
|
||||
setPrice(&profitOrder, preOrder, tradeSet)
|
||||
orders = append(orders, profitOrder)
|
||||
}
|
||||
|
||||
//减仓单
|
||||
if ext.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
|
||||
stopOrder := models.LinePreOrder{}
|
||||
copier.Copy(&stopOrder, preOrder)
|
||||
|
||||
stopOrder.Id = 0
|
||||
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
stopOrder.Pid = preOrder.Id
|
||||
stopOrder.MainId = ext.MainOrderId
|
||||
stopOrder.OrderType = 4
|
||||
stopOrder.Status = 0
|
||||
stopOrder.Rate = ext.ReducePriceRatio.String()
|
||||
|
||||
if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 {
|
||||
stopOrder.Num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
} else {
|
||||
stopOrder.Num = num.String()
|
||||
}
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
stopOrder.Site = "SELL"
|
||||
} else {
|
||||
stopOrder.Site = "BUY"
|
||||
}
|
||||
|
||||
setPrice(&stopOrder, preOrder, tradeSet)
|
||||
orders = append(orders, stopOrder)
|
||||
}
|
||||
|
||||
if len(orders) > 0 {
|
||||
if err := db.Create(&orders).Error; err != nil {
|
||||
logger.Error("主单回调,创建止盈、减仓单失败")
|
||||
return orders, errors.New("主单回调,创建止盈、减仓单失败")
|
||||
}
|
||||
}
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// 根据下单百分比计算价格
|
||||
func setPrice(order *models.LinePreOrder, preOrder *models.LinePreOrder, tradeSet models2.TradeSet) {
|
||||
func SetPrice(order *models.LinePreOrder, preOrder *models.LinePreOrder, tradeSet models2.TradeSet) {
|
||||
orderType := order.OrderType
|
||||
itemSide := order.Site
|
||||
rate := utility.StrToDecimal(order.Rate)
|
||||
|
||||
Reference in New Issue
Block a user