From 126193df36739fb8a12f3f1f730dac37debc6bb6 Mon Sep 17 00:00:00 2001 From: hucan <951870319@qq.com> Date: Thu, 6 Mar 2025 18:16:35 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BA=A4=E6=98=93=E5=AF=B9=E9=BB=91?= =?UTF-8?q?=E5=90=8D=E5=8D=95=20=E4=BA=A4=E6=98=93=E6=89=80=E4=B8=8B?= =?UTF-8?q?=E6=9E=B6=E7=9A=84=E4=BA=A4=E6=98=93=E5=AF=B9=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/apis/line_pre_order.go | 53 +- app/admin/apis/line_symbol_black.go | 28 + app/admin/models/line_pre_order_ext.go | 31 +- app/admin/router/line_pre_order.go | 4 +- app/admin/router/line_symbol_black.go | 6 +- app/admin/service/dto/line_pre_order.go | 107 ++-- app/admin/service/dto/line_pre_order_ext.go | 88 +-- app/admin/service/line_pre_order.go | 668 +++++++++++--------- app/admin/service/line_symbol.go | 67 +- app/admin/service/line_symbol_black.go | 19 +- services/binanceservice/commonservice.go | 2 +- services/binanceservice/futuresrest.go | 89 ++- services/binanceservice/orderservice.go | 11 + services/binanceservice/spotreset.go | 101 +-- 14 files changed, 731 insertions(+), 543 deletions(-) diff --git a/app/admin/apis/line_pre_order.go b/app/admin/apis/line_pre_order.go index 40a2c1f..1f18111 100644 --- a/app/admin/apis/line_pre_order.go +++ b/app/admin/apis/line_pre_order.go @@ -306,34 +306,34 @@ func (e LinePreOrder) AddPreOrder(c *gin.Context) { e.OK(nil, "操作成功") } -// 手动加仓 -func (e LinePreOrder) AddPosition(c *gin.Context) { - s := service.LinePreOrder{} - req := dto.LinePreOrderAddPositionReq{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } +// // 手动加仓 +// func (e LinePreOrder) AddPosition(c *gin.Context) { +// s := service.LinePreOrder{} +// req := dto.LinePreOrderAddPositionReq{} +// err := e.MakeContext(c). +// MakeOrm(). +// Bind(&req). +// MakeService(&s.Service). +// Errors +// if err != nil { +// e.Logger.Error(err) +// e.Error(500, err, err.Error()) +// return +// } - if err := req.Valid(); err != nil { - e.Error(500, err, err.Error()) - return - } +// if err := req.Valid(); err != nil { +// e.Error(500, err, err.Error()) +// return +// } - err = s.AddPosition(&req) +// err = s.AddPosition(&req) - if err != nil { - e.Error(500, nil, err.Error()) - return - } - e.OK(nil, "操作成功") -} +// if err != nil { +// e.Error(500, nil, err.Error()) +// return +// } +// e.OK(nil, "操作成功") +// } // BatchAddOrder 批量添加 func (e LinePreOrder) BatchAddOrder(c *gin.Context) { @@ -654,8 +654,7 @@ func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) { return } - // data := dto.CalculateBreakEvenRatioResp{} - _, err = s.GenerateOrder(&req) + err = s.GenerateOrder(&req) if err != nil { e.Error(500, err, err.Error()) return diff --git a/app/admin/apis/line_symbol_black.go b/app/admin/apis/line_symbol_black.go index b8ca9a4..9659f94 100644 --- a/app/admin/apis/line_symbol_black.go +++ b/app/admin/apis/line_symbol_black.go @@ -192,3 +192,31 @@ func (e LineSymbolBlack) Delete(c *gin.Context) { } e.OK(req.GetId(), "删除成功") } + +// 重置交易对 +func (e LineSymbolBlack) RelodSymbol(c *gin.Context) { + s := service.LineSymbolBlack{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + err = s.ReloadSymbol("1") + if err != nil { + e.Error(500, err, fmt.Sprintf("重置现货交易对失败,\r\n失败信息 %s", err.Error())) + return + } + + err = s.ReloadSymbol("2") + if err != nil { + e.Error(500, err, fmt.Sprintf("重置合约交易对失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(nil, "重置成功") +} diff --git a/app/admin/models/line_pre_order_ext.go b/app/admin/models/line_pre_order_ext.go index 308e109..9836848 100644 --- a/app/admin/models/line_pre_order_ext.go +++ b/app/admin/models/line_pre_order_ext.go @@ -9,22 +9,21 @@ import ( type LinePreOrderExt struct { models.Model - 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:减仓数量百分比"` - ReduceTakeProfitRatio decimal.Decimal `json:"reduceTakeProfitRatio" gorm:"type:decimal(10,2);comment:减仓后止盈百分比"` - ReduceStopLossRatio decimal.Decimal `json:"reduceStopLossRatio" gorm:"type:decimal(10,2);comment:减仓后止损百分比"` - AddPositionOrderType string `json:"addPositionOrderType" gorm:"type:varchar(20);comment:加仓类型 LIMIT-限价 MARKET-市价"` - 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:"-"` //减仓后总数 + MainOrderId int `json:"mainOrderId" gorm:"type:bigint;comment:主单id"` + OrderId int `json:"orderId" gorm:"type:bigint;comment:订单id"` + AddType int `json:"addType" gorm:"type:tinyint;comment:类型 1-加仓 2-减仓"` + OrderType string `json:"orderType" gorm:"type:varchar(20);comment:订单类型 LIMIT-限价 MARKET-市价"` + PriceRatio decimal.Decimal `json:"priceRatio" 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:加仓值"` + TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" gorm:"type:decimal(10,2);comment:止盈百分比"` + StopLossRatio decimal.Decimal `json:"stopLossRatio" gorm:"type:decimal(10,2);comment:止损百分比"` + TakeProfitNumRatio decimal.Decimal `json:"takeProfitNumRatio" gorm:"type:decimal(10,2);comment:止盈数量百分比"` + TpTpPriceRatio decimal.Decimal `json:"tpTpPriceRatio" gorm:"type:decimal(10,2);comment:止盈后止盈百分比"` + TpSlPriceRatio decimal.Decimal `json:"tpSlPriceRatio" gorm:"type:decimal(10,2);comment:止盈后止损百分比"` + ReTakeRatio decimal.Decimal `json:"reTakeRatio" gorm:"type:decimal(10,2);comment:亏损回本止盈百分比"` + TotalBefore decimal.Decimal `gorm:"-" comment:"初始总数"` + TotalAfter decimal.Decimal `gorm:"-" comment:"剩余总数"` models.ModelTime models.ControlBy } diff --git a/app/admin/router/line_pre_order.go b/app/admin/router/line_pre_order.go index d1c759f..d912362 100644 --- a/app/admin/router/line_pre_order.go +++ b/app/admin/router/line_pre_order.go @@ -25,8 +25,8 @@ func registerLinePreOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM r.PUT("/:id", actions.PermissionAction(), api.Update) r.DELETE("", api.Delete) - r.POST("addOrder", actions.PermissionAction(), api.AddPreOrder) //添加订单 - r.POST("position", actions.PermissionAction(), api.AddPosition) //手动加仓 + r.POST("addOrder", actions.PermissionAction(), api.AddPreOrder) //添加订单 + // r.POST("position", actions.PermissionAction(), api.AddPosition) //手动加仓 r.POST("batchAddOrder", actions.PermissionAction(), api.BatchAddOrder) //批量添加订单 r.POST("quickAddPreOrder", actions.PermissionAction(), api.QuickAddPreOrder) //快捷下单 r.POST("lever", actions.PermissionAction(), api.Lever) //设置杠杆 diff --git a/app/admin/router/line_symbol_black.go b/app/admin/router/line_symbol_black.go index 681a0b7..9990e59 100644 --- a/app/admin/router/line_symbol_black.go +++ b/app/admin/router/line_symbol_black.go @@ -5,8 +5,8 @@ import ( jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" "go-admin/app/admin/apis" - "go-admin/common/middleware" "go-admin/common/actions" + "go-admin/common/middleware" ) func init() { @@ -23,5 +23,7 @@ func registerLineSymbolBlackRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJ r.POST("", api.Insert) r.PUT("/:id", actions.PermissionAction(), api.Update) r.DELETE("", api.Delete) + + r.GET("reload-symbol", api.RelodSymbol) } -} \ No newline at end of file +} diff --git a/app/admin/service/dto/line_pre_order.go b/app/admin/service/dto/line_pre_order.go index a4e3801..2199b32 100644 --- a/app/admin/service/dto/line_pre_order.go +++ b/app/admin/service/dto/line_pre_order.go @@ -2,6 +2,7 @@ package dto import ( "errors" + "fmt" "strconv" "go-admin/app/admin/models" @@ -182,27 +183,29 @@ func (s *LinePreOrderDeleteReq) GetId() interface{} { } type LineAddPreOrderReq struct { - ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型 - OrderType int `json:"order_type"` //订单类型 - Symbol string `json:"symbol"` //交易对 - ApiUserId string `json:"api_id" ` //下单用户 - Site string `json:"site" ` //购买方向 - BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U - PricePattern string `json:"price_pattern"` //价格模式 - Price string `json:"price" vd:"$>0"` //下单价百分比 - Profit string `json:"profit" vd:"$>0"` //止盈价 - // 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" vd:"$>0"` //交易对类型 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"` //主单减仓后止损价百分比 + ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型 + OrderType int `json:"order_type"` //订单类型 + Symbol string `json:"symbol"` //交易对 + ApiUserId string `json:"api_id" ` //下单用户 + Site string `json:"site" ` //购买方向 + BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U + PricePattern string `json:"price_pattern"` //价格模式 + Price string `json:"price" vd:"$>0"` //下单价百分比 + Profit string `json:"profit" vd:"$>0"` //止盈价 + 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"` //止盈后止损价百分比 + PriceType string `json:"price_type"` //价格类型 + SaveTemplate string `json:"save_template"` //是否保存模板 + TemplateName string `json:"template_name"` //模板名字 + SymbolType int `json:"symbol_type" vd:"$>0"` //交易对类型 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:"re_take_profit_ratio" comment:"减仓后亏损回本止盈百分比"` Ext []LineAddPreOrderExtReq `json:"ext" ` //拓展字段 @@ -275,23 +278,33 @@ func (req LineAddPreOrderReq) Valid() error { } for _, v := range req.Ext { + name := "加仓" + + if v.AddType < 1 || v.AddType > 2 { + return errors.New("加、减仓单类型错误") + } + + if v.AddType == 2 { + name = "减仓" + } + if v.AddPositionVal.IsZero() { - return errors.New("加仓单数量不能为空") + return fmt.Errorf("%s单数量不能为空", name) } - if v.AddPositionPriceRatio.IsZero() { - return errors.New("加仓单下跌价格不能为空") + if v.PriceRatio.Cmp(decimal.Zero) <= 0 || v.PriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 { + return fmt.Errorf("%s单下跌价格不能为空", name) } - if v.ReduceNumRatio.IsZero() || v.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) > 0 { - return errors.New("减仓数量不正确") + if v.TakeProfitRatio.IsZero() || v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 { + return errors.New("止盈价格不正确") } - if v.ReducePriceRatio.IsZero() || v.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { - return errors.New("减仓下跌价格不正确") + if v.TpTpPriceRatio.IsZero() || v.TpTpPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { + return errors.New("止盈后止盈价格不正确") } - if v.ReduceTakeProfitRatio.IsZero() || v.ReduceTakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 { - return errors.New("减仓后止盈价格不正确") + if v.TpSlPriceRatio.Cmp(decimal.Zero) <= 0 || v.TpSlPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { + return errors.New("止盈后止损价格不正确") } } @@ -392,23 +405,33 @@ func (req LineBatchAddPreOrderReq) CheckParams() error { } for _, v := range req.Ext { + name := "加仓" + + if v.AddType < 1 || v.AddType > 2 { + return errors.New("加、减仓单类型错误") + } + + if v.AddType == 2 { + name = "减仓" + } + if v.AddPositionVal.IsZero() { - return errors.New("加仓单数量不能为空") + return fmt.Errorf("%s单数量不能为空", name) } - if v.AddPositionPriceRatio.IsZero() { - return errors.New("加仓单下跌价格不能为空") + if v.PriceRatio.Cmp(decimal.Zero) <= 0 || v.PriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 { + return fmt.Errorf("%s单下跌价格不能为空", name) } - if v.ReduceNumRatio.IsZero() || v.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) > 0 { - return errors.New("减仓数量不正确") + if v.TakeProfitRatio.IsZero() || v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 { + return errors.New("止盈价格不正确") } - if v.ReducePriceRatio.IsZero() || v.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { - return errors.New("减仓下跌价格不正确") + if v.TpTpPriceRatio.IsZero() || v.TpTpPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { + return errors.New("止盈后止盈价格不正确") } - if v.ReduceTakeProfitRatio.IsZero() || v.ReduceTakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 { - return errors.New("减仓后止盈价格不正确") + if v.TpSlPriceRatio.Cmp(decimal.Zero) <= 0 || v.TpSlPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { + return errors.New("止盈后止损价格不正确") } } @@ -579,12 +602,12 @@ type CalculateBreakEevenRatioReq struct { Symbol string `form:"symbol"` //交易对 ExchangeType string `form:"exchangeType"` //交易所类型 字典exchange_type SymbolType int `form:"symbolType"` + AddType int `form:"addType" comment:"类型 1-加仓 2-减仓"` BuyPrice decimal.Decimal `form:"buyPrice"` //主单购买总金额 LossBeginPercent decimal.Decimal `form:"lossBeginPercent"` //亏损开始百分比 LossEndPercent decimal.Decimal `form:"lossEndPercent"` //亏损截至百分比 - AddPositionType int `form:"addPositionType"` //加仓类型 1-百分比 2-实际金额 - AddPositionVal decimal.Decimal `form:"addPositionVal"` //加仓金额 - ReducePercent decimal.Decimal `form:"reducePercent"` //减仓百分比 + AddPositionType int `form:"addPositionType"` //加仓/减仓 类型 1-百分比 2-实际金额 + AddPositionVal decimal.Decimal `form:"addPositionVal"` //加仓/减仓 金额 RemainingQuantity decimal.Decimal `form:"remainingQuantity"` //剩余数量 TotalLossAmountU decimal.Decimal `form:"totalLossAmountU"` //累计亏损金额 } diff --git a/app/admin/service/dto/line_pre_order_ext.go b/app/admin/service/dto/line_pre_order_ext.go index 6b8e033..5d8c630 100644 --- a/app/admin/service/dto/line_pre_order_ext.go +++ b/app/admin/service/dto/line_pre_order_ext.go @@ -37,31 +37,32 @@ func (m *LinePreOrderExtGetPageReq) GetNeedSearch() interface{} { } type LineAddPreOrderExtReq struct { - 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:"加仓值"` + AddType int `json:"addType" comment:"类型 1-加仓 2-减仓"` + OrderType string `json:"orderType" comment:"订单类型 LIMIT-限价 MARKET-市价"` + PriceRatio decimal.Decimal `json:"priceRatio" comment:"价格百分比"` + AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"` + AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"` + TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" comment:"止盈百分比"` + StopLossRatio decimal.Decimal `json:"stopLossRatio" comment:"止损百分比"` + TakeProfitNumRatio decimal.Decimal `json:"takeProfitNumRatio" comment:"止盈数量百分比"` + TpTpPriceRatio decimal.Decimal `json:"tpTpPriceRatio" comment:"止盈后止盈价格百分比"` + TpSlPriceRatio decimal.Decimal `json:"tpSlPriceRatio" comment:"止盈后止损价格百分比"` + ReTakeProfitRatio decimal.Decimal `json:"reTakeProfitRatio" comment:"亏损回本止盈百分比"` } type LinePreOrderExtInsertReq struct { - Id int `json:"-" comment:"主键id"` // 主键id - MainOrderId int `json:"mainOrderId" comment:"主单id"` - OrderId int `json:"orderId" comment:"订单id"` - 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:"加仓价格百分比"` - AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"` - AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"` + Id int `json:"-" comment:"主键id"` // 主键id + MainOrderId int `json:"mainOrderId" comment:"主单id"` + OrderId int `json:"orderId" comment:"订单id"` + AddType int `json:"addType" comment:"类型 1-加仓 2-减仓"` + OrderType string `json:"orderType" comment:"类型 LIMIT-限价 MARKET-市价"` + PriceRatio decimal.Decimal `json:"priceRatio" comment:"价格百分比"` + TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" comment:"止盈百分比"` + TakeProfitNumRatio decimal.Decimal `json:"takeProfitNumRatio" comment:"止盈数量百分比"` + TpTpPriceRatio decimal.Decimal `json:"tpTpPriceRatio" comment:"止盈后止盈价格百分比"` + TpSlPriceRatio decimal.Decimal `json:"tpSlPriceRatio" comment:"止盈后止损价格百分比"` + AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"` + AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"` common.ControlBy } @@ -72,11 +73,11 @@ func (s *LinePreOrderExtInsertReq) Generate(model *models.LinePreOrderExt) { model.MainOrderId = s.MainOrderId model.OrderId = s.OrderId model.TakeProfitRatio = s.TakeProfitRatio - model.ReducePriceRatio = s.ReducePriceRatio - model.ReduceNumRatio = s.ReduceNumRatio - model.ReduceTakeProfitRatio = s.ReduceTakeProfitRatio - model.ReduceStopLossRatio = s.ReduceStopLossRatio - model.AddPositionPriceRatio = s.AddPositionPriceRatio + model.AddType = s.AddType + model.OrderType = s.OrderType + model.PriceRatio = s.PriceRatio + model.TpSlPriceRatio = s.TpSlPriceRatio + model.TpSlPriceRatio = s.TpSlPriceRatio model.AddPositionType = s.AddPositionType model.AddPositionVal = s.AddPositionVal model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 @@ -87,17 +88,18 @@ func (s *LinePreOrderExtInsertReq) GetId() interface{} { } type LinePreOrderExtUpdateReq struct { - Id int `uri:"id" comment:"主键id"` // 主键id - MainOrderId int `json:"mainOrderId" comment:"主单id"` - OrderId int `json:"orderId" comment:"订单id"` - 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:"加仓价格百分比"` - AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"` - AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"` + Id int `uri:"id" comment:"主键id"` // 主键id + MainOrderId int `json:"mainOrderId" comment:"主单id"` + OrderId int `json:"orderId" comment:"订单id"` + AddType int `json:"addType" comment:"类型 1-加仓 2-减仓"` + OrderType string `json:"orderType" comment:"类型 LIMIT-限价 MARKET-市价"` + PriceRatio decimal.Decimal `json:"priceRatio" comment:"价格百分比"` + TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" comment:"止盈百分比"` + TakeProfitNumRatio decimal.Decimal `json:"takeProfitNumRatio" comment:"止盈数量百分比"` + TpTpPriceRatio decimal.Decimal `json:"tpTpPriceRatio" comment:"止盈后止盈价格百分比"` + TpSlPriceRatio decimal.Decimal `json:"tpSlPriceRatio" comment:"止盈后止损价格百分比"` + AddPositionType int `json:"addPositionType" comment:"加仓类型 1-百分比 2-实际金额"` + AddPositionVal decimal.Decimal `json:"addPositionVal" comment:"加仓值"` common.ControlBy } @@ -108,11 +110,11 @@ func (s *LinePreOrderExtUpdateReq) Generate(model *models.LinePreOrderExt) { model.MainOrderId = s.MainOrderId model.OrderId = s.OrderId model.TakeProfitRatio = s.TakeProfitRatio - model.ReducePriceRatio = s.ReducePriceRatio - model.ReduceNumRatio = s.ReduceNumRatio - model.ReduceTakeProfitRatio = s.ReduceTakeProfitRatio - model.ReduceStopLossRatio = s.ReduceStopLossRatio - model.AddPositionPriceRatio = s.AddPositionPriceRatio + model.AddType = s.AddType + model.OrderType = s.OrderType + model.PriceRatio = s.PriceRatio + model.TpSlPriceRatio = s.TpSlPriceRatio + model.TpSlPriceRatio = s.TpSlPriceRatio model.AddPositionType = s.AddPositionType model.AddPositionVal = s.AddPositionVal model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 diff --git a/app/admin/service/line_pre_order.go b/app/admin/service/line_pre_order.go index 0676804..78af479 100644 --- a/app/admin/service/line_pre_order.go +++ b/app/admin/service/line_pre_order.go @@ -11,6 +11,7 @@ import ( "go-admin/pkg/utility" "go-admin/pkg/utility/snowflakehelper" "go-admin/services/binanceservice" + "sort" "strconv" "strings" "time" @@ -338,6 +339,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP if req.SaveTemplate == "2" { return nil } + + //重新排序下跌比例(顺序) + sort.Slice(req.Ext, func(i, j int) bool { + return req.Ext[i].PriceRatio.Cmp(req.Ext[j].PriceRatio) < 0 + }) + var key string if req.SymbolType == global.SYMBOL_SPOT { key = fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, req.Symbol) @@ -356,11 +363,6 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP //获取交易对 tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key) - // orderCount := e.CheckRepeatOrder(req.SymbolType, id, req.Site, tradeSet.Coin) - // if orderCount > 0 { - // *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 该交易对已存在,请勿重复下单", id, req.Symbol)) - // continue - // } tickerPrice := utility.StrToDecimal(tradeSet.LastPrice) if tickerPrice.Equal(decimal.Zero) { //redis 没有这个值 *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 交易行情出错", id, req.Symbol)) @@ -454,15 +456,31 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP //订单配置信息 preOrderExts := make([]models.LinePreOrderExt, 0) defultExt := models.LinePreOrderExt{ - TakeProfitRatio: utility.StringToDecimal(req.Profit), - ReducePriceRatio: req.ReducePriceRatio, - ReduceNumRatio: req.ReduceNumRatio, - ReduceTakeProfitRatio: req.ReduceTakeProfitRatio, - ReduceStopLossRatio: req.ReduceStopLossRatio, + AddType: 1, //主单等同于加仓0 + AddPositionType: 1, + AddPositionVal: decimal.Zero, + OrderType: req.PriceType, + TakeProfitRatio: utility.StringToDecimal(req.Profit), + TakeProfitNumRatio: req.ProfitNumRatio, + TpTpPriceRatio: req.ProfitTpTpPriceRatio, + TpSlPriceRatio: req.ProfitTpSlPriceRatio, + } + //减仓单 + defultExt2 := models.LinePreOrderExt{ + AddType: 2, + OrderType: "LIMIT", + PriceRatio: req.ReducePriceRatio, + AddPositionType: 1, + AddPositionVal: req.ReduceNumRatio, + TakeProfitRatio: req.ReduceTakeProfitRatio, + TakeProfitNumRatio: decimal.NewFromInt(100), //减仓止盈默认100% + StopLossRatio: 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)) + defultExt.TotalAfter = utility.StrToDecimal(AddOrder.Num).Truncate(int32(tradeSet.AmountDigit)) + defultExt2.TotalBefore = defultExt.TotalAfter + defultExt2.TotalAfter = mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio)).Div(decimal.NewFromInt(100)).Truncate(int32(tradeSet.AmountDigit)) preOrderExts = append(preOrderExts, defultExt) calculateResp := dto.CalculateBreakEvenRatioResp{} @@ -476,56 +494,42 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP LossEndPercent: req.ReducePriceRatio, AddPositionType: 2, AddPositionVal: decimal.Zero, - ReducePercent: req.ReduceNumRatio, } //计算减仓后 mainParam.LossEndPercent = req.ReducePriceRatio mainParam.RemainingQuantity = mainAmount - e.CalculateBreakEvenRatio(&mainParam, &calculateResp) + e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet) mainParam.RemainingQuantity = calculateResp.RemainingQuantity //mainAmount.Mul(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU //buyPrice.Mul(req.ReducePriceRatio.Div(decimal.NewFromInt(100)).Truncate(4)).Truncate(int32(tradeSet.PriceDigit)) req.ReduceReTakeProfitRatio = calculateResp.Ratio mainParam.LossBeginPercent = req.ReducePriceRatio - defultExt.ReduceReTakeRatio = calculateResp.Ratio + defultExt.ReTakeRatio = calculateResp.Ratio for index, 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, - AddPositionOrderType: addPosition.AddPositionOrderType, - AddPositionType: addPosition.AddPositionType, - AddPositionVal: addPosition.AddPositionVal, + AddType: addPosition.AddType, + OrderType: addPosition.OrderType, + TakeProfitRatio: addPosition.TakeProfitRatio, + TakeProfitNumRatio: addPosition.TakeProfitNumRatio, + TpTpPriceRatio: addPosition.TpTpPriceRatio, + TpSlPriceRatio: addPosition.TpSlPriceRatio, + AddPositionType: addPosition.AddPositionType, + AddPositionVal: addPosition.AddPositionVal, } - mainParam.LossEndPercent = req.Ext[index].AddPositionPriceRatio + mainParam.LossEndPercent = req.Ext[index].PriceRatio 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 + e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet) + + ext.TotalBefore = mainParam.RemainingQuantity //初始数量 + ext.TotalAfter = calculateResp.RemainingQuantity //计算后数量 + ext.ReTakeRatio = calculateResp.Ratio + mainParam.LossBeginPercent = addPosition.PriceRatio 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) } @@ -576,7 +580,26 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP profitOrder.Rate = req.Profit profitOrder.MainId = AddOrder.Id + if req.ProfitNumRatio.Cmp(decimal.Zero) > 0 { + numPercent := req.ProfitNumRatio.Div(decimal.NewFromInt(100)) + profitOrder.Num = utility.StrToDecimal(profitOrder.Num).Mul(numPercent).Truncate(int32(tradeSet.AmountDigit)).String() + + } tx.Model(&models.LinePreOrder{}).Omit("id", "save_template", "template_name").Create(&profitOrder) + + //不全部止盈的时候 + if req.ProfitNumRatio.Cmp(decimal.Zero) > 0 && req.ProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { + reminQuantity := utility.StrToDecimal(AddOrder.Num).Sub(utility.StrToDecimal(profitOrder.Num)) + + childrens, err := makeTpOrder(&profitOrder, reminQuantity, req.ProfitTpTpPriceRatio, req.ProfitTpSlPriceRatio, &tradeSet) + + if err != nil { + logger.Error("生成止盈后子订单失败") + return err + } + + tx.Create(&childrens) + } } if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 { @@ -619,39 +642,44 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP preOrderExts[index].OrderId = AddOrder.Id continue } + var AddOrder models.LinePreOrder - addPosition := createPreAddPosition(&AddOrder, v, tradeSet) + if v.AddType == 1 { + AddOrder = createPreAddPosition(&AddOrder, v, tradeSet) + } else if v.AddType == 2 { + AddOrder = createPreReduceOrder(&AddOrder, v, tradeSet) + } - if addPosition.OrderSn == "" { + if AddOrder.OrderSn == "" { continue } - if err := e.Orm.Create(&addPosition).Error; err != nil { + if err := e.Orm.Create(&AddOrder).Error; err != nil { logger.Error("保存加仓单失败") return err } - preOrderExts[index].OrderId = addPosition.Id + preOrderExts[index].OrderId = AddOrder.Id //止盈、减仓 - orders, err := makeFuturesTakeAndReduce(&addPosition, v, tradeSet) + orders, err := makeFuturesTakeAndReduce(&AddOrder, v, tradeSet) if err != nil { - logger.Error("构造加仓单止盈、减仓失败") + logger.Error("构造止盈、止损失败") return err } if err := e.Orm.Create(&orders).Error; err != nil { - logger.Error("保存加仓单止盈、减仓失败") + 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 { + if orders[index].OrderType == 1 && v.TakeProfitRatio.Cmp(decimal.Zero) > 0 && v.TakeProfitRatio.Cmp(decimal.NewFromInt(100)) < 0 { reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet) if err != nil { - logger.Error("生产加仓单止盈、减仓失败") + logger.Error("生产止盈后止盈、减仓失败") return err } @@ -660,7 +688,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP } if err := e.Orm.Create(&reduceChildOrders).Error; err != nil { - logger.Error("报错减仓后止盈止损失败") + logger.Error("报错止盈后止盈止损失败") return err } } @@ -695,16 +723,16 @@ func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderEx data.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) data.MainId = preOrder.Id data.CreatedAt = time.Now() - data.MainOrderType = v.AddPositionOrderType + data.MainOrderType = v.OrderType data.Status = 0 data.OrderCategory = 3 - data.Rate = v.AddPositionPriceRatio.String() + data.Rate = v.PriceRatio.String() var percentage decimal.Decimal if data.Site == "BUY" { - percentage = decimal.NewFromInt(1).Sub(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100))) + percentage = decimal.NewFromInt(1).Sub(v.PriceRatio.Div(decimal.NewFromInt(100))) } else { - percentage = decimal.NewFromInt(1).Add(v.AddPositionPriceRatio.Div(decimal.NewFromInt(100))) + percentage = decimal.NewFromInt(1).Add(v.PriceRatio.Div(decimal.NewFromInt(100))) } dataPrice := price.Mul(percentage).Truncate(int32(tradeSet.PriceDigit)) @@ -722,39 +750,12 @@ func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderEx return data } -// 构建合约止盈、减仓单 -func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) { - num := ext.TotalAfterAdding.Truncate(int32(tradeSet.AmountDigit)) - 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.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) +// 生成减仓单 +func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) models.LinePreOrder { + var stopOrder models.LinePreOrder //减仓单 - if ext.ReducePriceRatio.Cmp(decimal.Zero) > 0 { - stopOrder := models.LinePreOrder{} + if ext.PriceRatio.Cmp(decimal.Zero) > 0 { copier.Copy(&stopOrder, preOrder) stopOrder.Id = 0 @@ -763,14 +764,10 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO stopOrder.MainId = preOrder.MainId stopOrder.OrderType = 4 stopOrder.Status = 0 - stopOrder.Rate = ext.ReducePriceRatio.String() - stopOrder.Num = num.String() + stopOrder.Rate = ext.PriceRatio.String() + stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String() stopOrder.BuyPrice = "0" - if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { - stopNum := num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))) - stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String() - } if strings.ToUpper(preOrder.Site) == "BUY" { stopOrder.Site = "SELL" } else { @@ -778,38 +775,140 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO } binanceservice.SetPrice(&stopOrder, preOrder, tradeSet) - orders = append(orders, stopOrder) + } + + return stopOrder +} + +// 构建止盈、止盈止损 +func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) { + orders := make([]models.LinePreOrder, 0) + var side string + + if strings.ToUpper(preOrder.Site) == "BUY" { + side = "SELL" + } else { + side = "BUY" + } + + 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 = preOrder.MainId + profitOrder.BuyPrice = "0" + profitOrder.Site = side + + if ext.TakeProfitNumRatio.Cmp(decimal.Zero) <= 0 || ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) >= 0 { + profitOrder.Num = ext.TotalAfter.Truncate(int32(tradeSet.AmountDigit)).String() + } else { + profitOrder.Num = ext.TotalAfter.Mul(ext.TakeProfitNumRatio).Div(decimal.NewFromInt(100)).Truncate(int32(tradeSet.AmountDigit)).String() + } + + // 止盈需要累加之前的亏损 + profitOrder.Rate = ext.TakeProfitRatio.Add(ext.ReTakeRatio).Truncate(2).String() + + binanceservice.SetPrice(&profitOrder, preOrder, tradeSet) + orders = append(orders, profitOrder) + } + + if ext.StopLossRatio.Cmp(decimal.Zero) > 0 { + lossOrder := models.LinePreOrder{} + copier.Copy(&lossOrder, preOrder) + + lossOrder.Id = 0 + lossOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) + lossOrder.Pid = preOrder.Id + lossOrder.OrderType = 2 + lossOrder.Status = 0 + lossOrder.MainId = preOrder.MainId + lossOrder.BuyPrice = "0" + lossOrder.Num = ext.TotalAfter.Truncate(int32(tradeSet.AmountDigit)).String() + lossOrder.Rate = ext.StopLossRatio.Truncate(2).String() + lossOrder.Site = side + + binanceservice.SetPrice(&lossOrder, preOrder, tradeSet) + orders = append(orders, lossOrder) } return orders, nil } +// 构建止盈后止盈止损 +// parentOrder 父订单 +// remainQuantity 剩余数量 +// tpPriceRatio 止盈价格比例 +// slPriceRatio 止损价格比例 +func makeTpOrder(parentOrder *models.LinePreOrder, reminQuantity decimal.Decimal, tpPriceRatio, slPriceRatio decimal.Decimal, tradeSet *models2.TradeSet) ([]models.LinePreOrder, error) { + result := make([]models.LinePreOrder, 0) + tp := models.LinePreOrder{} + sl := models.LinePreOrder{} + copier.Copy(&tp, parentOrder) + + tp.Id = 0 + tp.Pid = parentOrder.Id + tp.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) + tp.OrderType = 1 + tp.Status = 0 + tp.Rate = tpPriceRatio.String() + tp.Num = reminQuantity.String() + binanceservice.SetPrice(&tp, parentOrder, *tradeSet) + result = append(result, tp) + + if (slPriceRatio).Cmp(decimal.Zero) > 0 { + copier.Copy(&sl, parentOrder) + sl.Pid = parentOrder.Id + sl.Id = 0 + sl.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) + sl.OrderType = 2 + sl.Num = reminQuantity.Truncate(int32(tradeSet.AmountDigit)).String() + sl.Rate = slPriceRatio.String() + binanceservice.SetPrice(&sl, parentOrder, *tradeSet) + result = append(result, sl) + } + + return result, 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" + var num decimal.Decimal - binanceservice.SetPrice(&takeProfitOrder, parentOrder, tradeSet) - orders = append(orders, takeProfitOrder) + if ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { + percent := decimal.NewFromInt(1).Sub(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))) + num = ext.TotalAfter.Mul(percent).Truncate(int32(tradeSet.AmountDigit)) + } + if ext.TpTpPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 { + 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.TpTpPriceRatio.String() + takeProfitOrder.SignPrice = parentOrder.Price + takeProfitOrder.CreatedAt = time.Now() + takeProfitOrder.BuyPrice = "0" + takeProfitOrder.MainOrderType = "LIMIT" + takeProfitOrder.Num = num.String() + //止盈需要累加之前的亏损 + takeProfitOrder.Rate = ext.TpTpPriceRatio.Truncate(2).String() + takeProfitOrder.BuyPrice = "0" + + binanceservice.SetPrice(&takeProfitOrder, parentOrder, tradeSet) + orders = append(orders, takeProfitOrder) + } //有止损单 - if ext.ReduceStopLossRatio.Cmp(decimal.Zero) > 0 { + if ext.TpSlPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 { var stoploss models.LinePreOrder copier.Copy(&stoploss, parentOrder) @@ -821,9 +920,9 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line stoploss.OrderType = 2 stoploss.SignPrice = parentOrder.Price stoploss.BuyPrice = "0" - stoploss.Rate = ext.ReduceStopLossRatio.String() + stoploss.Rate = ext.TpSlPriceRatio.String() stoploss.MainOrderType = "LIMIT" - stoploss.Num = ext.TotalAfterReducing.Truncate(int32(tradeSet.AmountDigit)).String() + stoploss.Num = num.String() stoploss.BuyPrice = "0" binanceservice.SetPrice(&stoploss, parentOrder, tradeSet) @@ -1633,7 +1732,7 @@ func (e *LinePreOrder) QueryAiCoinPrice(req *dto.QueryAiCoinPriceReq) (models.Li } // 根据请求参数重新生成亏损回本止盈百分比 -func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) ([]models.LineDirection, error) { +func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error { var tradeSet models2.TradeSet var tickerPrice decimal.Decimal @@ -1644,7 +1743,7 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) ([]models.Line } if tradeSet.LastPrice == "" { - return nil, errors.New("获取不到交易对信息") + return errors.New("获取不到交易对信息") } var price decimal.Decimal @@ -1666,77 +1765,58 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) ([]models.Line buyPrice := utility.StrToDecimal(req.BuyPrice) mainAmount := buyPrice.Div(price).Truncate(int32(tradeSet.AmountDigit)) calculateResp := dto.CalculateBreakEvenRatioResp{} + lossBeginPercent := decimal.Zero mainParam := dto.CalculateBreakEevenRatioReq{ Price: price, ExchangeType: req.ExchangeType, Symbol: req.Symbol, SymbolType: req.SymbolType, BuyPrice: buyPrice, - LossBeginPercent: decimal.Zero, + LossBeginPercent: lossBeginPercent, LossEndPercent: req.ReducePriceRatio, AddPositionType: 2, AddPositionVal: decimal.Zero, - ReducePercent: req.ReduceNumRatio, } //计算减仓后 mainParam.LossEndPercent = req.ReducePriceRatio mainParam.RemainingQuantity = mainAmount - e.CalculateBreakEvenRatio(&mainParam, &calculateResp) + mainParam.AddType = 2 + e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet) mainParam.RemainingQuantity = calculateResp.RemainingQuantity mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU req.ReduceReTakeProfitRatio = calculateResp.Ratio - mainParam.LossBeginPercent = req.ReducePriceRatio + lossBeginPercent = req.ReducePriceRatio + + //顺序排序 + sort.Slice(req.Ext, func(i, j int) bool { + return req.Ext[i].PriceRatio.Cmp(req.Ext[j].PriceRatio) < 0 + }) for index := range req.Ext { - mainParam.LossEndPercent = req.Ext[index].AddPositionPriceRatio + mainParam.LossBeginPercent = lossBeginPercent + mainParam.LossEndPercent = req.Ext[index].PriceRatio mainParam.AddPositionType = req.Ext[index].AddPositionType mainParam.AddPositionVal = req.Ext[index].AddPositionVal - mainParam.ReducePercent = decimal.Zero - e.CalculateBreakEvenRatio(&mainParam, &calculateResp) + + e.CalculateBreakEvenRatio(&mainParam, &calculateResp, tradeSet) 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 + lossBeginPercent = req.Ext[index].PriceRatio mainParam.RemainingQuantity = calculateResp.RemainingQuantity mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU } - return nil, nil + return nil } // 计算亏损百分比 -func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatioReq, data *dto.CalculateBreakEvenRatioResp) error { - var tradeSet models2.TradeSet +func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatioReq, data *dto.CalculateBreakEvenRatioResp, tradeSet models2.TradeSet) error { if req.LossEndPercent.Cmp(req.LossBeginPercent) < 0 { return errors.New("截至亏损百分比必须大于开始亏损百分比") } - if req.SymbolType == 1 { - val, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, req.Symbol)) - - sonic.Unmarshal([]byte(val), &tradeSet) - } else if req.SymbolType == 2 { - val, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_FUTURES, req.ExchangeType, req.Symbol)) - - sonic.Unmarshal([]byte(val), &tradeSet) - } else { - return errors.New("symbolType error") - } - - if tradeSet.LastPrice == "" { - return errors.New("没有找到交易对行情") - } - var addPositionBuyPrice decimal.Decimal if req.AddPositionType == 1 { @@ -1759,8 +1839,8 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio lossAmountU := req.Price.Mul(percentDiff.Div(decimal.NewFromInt(100).Truncate(4))).Mul(req.RemainingQuantity).Truncate(int32(tradeSet.PriceDigit)) //计算减仓数量 - if req.ReducePercent.Cmp(decimal.NewFromInt(0)) > 0 { - reduceAmount = totalAmount.Mul(req.ReducePercent.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.AmountDigit)) + if req.AddPositionType == 2 && req.AddPositionVal.Cmp(decimal.NewFromInt(0)) > 0 { + reduceAmount = totalAmount.Mul(req.AddPositionVal.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.AmountDigit)) } data.RemainingQuantity = totalAmount.Sub(reduceAmount) @@ -1776,163 +1856,163 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio return nil } -// 手动加仓 -func (e *LinePreOrder) AddPosition(req *dto.LinePreOrderAddPositionReq) error { - lastPositionOrder := models.LinePreOrder{} - var tradeSet models2.TradeSet +// // 手动加仓 +// func (e *LinePreOrder) AddPosition(req *dto.LinePreOrderAddPositionReq) error { +// lastPositionOrder := models.LinePreOrder{} +// var tradeSet models2.TradeSet - if req.OrderType == 1 { - tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 0) - } else if req.OrderType == 2 { - tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 1) - } else { - return fmt.Errorf("交易对:%s 订单类型错误", req.Symbol) - } +// if req.OrderType == 1 { +// tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 0) +// } else if req.OrderType == 2 { +// tradeSet, _ = binanceservice.GetTradeSet(req.Symbol, 1) +// } else { +// return fmt.Errorf("交易对:%s 订单类型错误", req.Symbol) +// } - if tradeSet.LastPrice == "" { - return fmt.Errorf("交易对:%s 交易对配置错误", req.Symbol) - } +// if tradeSet.LastPrice == "" { +// return fmt.Errorf("交易对:%s 交易对配置错误", req.Symbol) +// } - if err := e.Orm.Model(&lastPositionOrder).Where("symbol =? AND status = 6 AND site =? AND api_id =? AND symbol_type =? AND exchange_type=?", - req.Symbol, req.Site, req.ApiUserId, req.OrderType, req.ExchangeType).Error; err != nil { - logger.Errorf("交易对:%s查询已开仓订单失败", req.Symbol) - return fmt.Errorf("交易对:%s 没有已开仓的订单", req.Symbol) - } +// if err := e.Orm.Model(&lastPositionOrder).Where("symbol =? AND status = 6 AND site =? AND api_id =? AND symbol_type =? AND exchange_type=?", +// req.Symbol, req.Site, req.ApiUserId, req.OrderType, req.ExchangeType).Error; err != nil { +// logger.Errorf("交易对:%s查询已开仓订单失败", req.Symbol) +// return fmt.Errorf("交易对:%s 没有已开仓的订单", req.Symbol) +// } - ext := models.LinePreOrderExt{ - MainOrderId: lastPositionOrder.Id, - TakeProfitRatio: req.Profit, - ReducePriceRatio: req.ReducePriceRatio, - ReduceNumRatio: req.ReduceNumRatio, - ReduceTakeProfitRatio: req.ReduceTakeProfitRatio, - ReduceStopLossRatio: req.ReduceStopLossRatio, - AddPositionOrderType: req.AddPositionOrderType, - AddPositionType: 2, - AddPositionVal: req.BuyPrice, - } +// ext := models.LinePreOrderExt{ +// MainOrderId: lastPositionOrder.Id, +// TakeProfitRatio: req.Profit, +// ReducePriceRatio: req.ReducePriceRatio, +// ReduceNumRatio: req.ReduceNumRatio, +// ReduceTakeProfitRatio: req.ReduceTakeProfitRatio, +// ReduceStopLossRatio: req.ReduceStopLossRatio, +// AddPositionOrderType: req.AddPositionOrderType, +// AddPositionType: 2, +// AddPositionVal: req.BuyPrice, +// } - addPosition := models.LinePreOrder{ - SignPrice: tradeSet.LastPrice, - Pid: lastPositionOrder.Id, - MainId: lastPositionOrder.Id, - Symbol: req.Symbol, - QuoteSymbol: tradeSet.Currency, - SignPriceU: utility.StrToDecimal(tradeSet.LastPrice), - ApiId: req.ApiUserId, - Site: req.Site, - ExchangeType: req.ExchangeType, - OrderType: 0, - OrderCategory: 3, - BuyPrice: req.BuyPrice.String(), - Status: 0, - SymbolType: req.OrderType, - MainOrderType: req.AddPositionOrderType, - ExpireTime: time.Now().Add(4), - OrderSn: utility.Int64ToString(snowflakehelper.GetOrderId()), - } +// addPosition := models.LinePreOrder{ +// SignPrice: tradeSet.LastPrice, +// Pid: lastPositionOrder.Id, +// MainId: lastPositionOrder.Id, +// Symbol: req.Symbol, +// QuoteSymbol: tradeSet.Currency, +// SignPriceU: utility.StrToDecimal(tradeSet.LastPrice), +// ApiId: req.ApiUserId, +// Site: req.Site, +// ExchangeType: req.ExchangeType, +// OrderType: 0, +// OrderCategory: 3, +// BuyPrice: req.BuyPrice.String(), +// Status: 0, +// SymbolType: req.OrderType, +// MainOrderType: req.AddPositionOrderType, +// ExpireTime: time.Now().Add(4), +// OrderSn: utility.Int64ToString(snowflakehelper.GetOrderId()), +// } - tickerPrice := utility.StrToDecimal(tradeSet.LastPrice) - if req.PricePattern == "percentage" { - addPosition.Rate = req.Price.String() - priceRate := req.Price.Div(decimal.NewFromInt(100)) //下单价除100 =0.1 +// tickerPrice := utility.StrToDecimal(tradeSet.LastPrice) +// if req.PricePattern == "percentage" { +// addPosition.Rate = req.Price.String() +// priceRate := req.Price.Div(decimal.NewFromInt(100)) //下单价除100 =0.1 - if strings.ToUpper(req.Site) == "BUY" { //购买方向 - //实际下单价格 - truncate := tickerPrice.Mul(decimal.NewFromInt(1).Sub(priceRate)).Truncate(int32(tradeSet.PriceDigit)) - addPosition.Price = truncate.String() - } else { - truncate := tickerPrice.Mul(decimal.NewFromInt(1).Add(priceRate)).Truncate(int32(tradeSet.PriceDigit)) - addPosition.Price = truncate.String() - } +// if strings.ToUpper(req.Site) == "BUY" { //购买方向 +// //实际下单价格 +// truncate := tickerPrice.Mul(decimal.NewFromInt(1).Sub(priceRate)).Truncate(int32(tradeSet.PriceDigit)) +// addPosition.Price = truncate.String() +// } else { +// truncate := tickerPrice.Mul(decimal.NewFromInt(1).Add(priceRate)).Truncate(int32(tradeSet.PriceDigit)) +// addPosition.Price = truncate.String() +// } - } else { //实际价格下单 - addPosition.Price = req.Price.Truncate(int32(tradeSet.PriceDigit)).String() - addPosition.SignPriceType = req.PricePattern - addPosition.Rate = "0" - } - if tradeSet.Currency != "USDT" { //不是U本位 - //获取币本位兑换u的价格 - ticker2 := models2.TradeSet{} - tickerVal, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, strings.ToUpper(tradeSet.Coin+"USDT"))) +// } else { //实际价格下单 +// addPosition.Price = req.Price.Truncate(int32(tradeSet.PriceDigit)).String() +// addPosition.SignPriceType = req.PricePattern +// addPosition.Rate = "0" +// } +// if tradeSet.Currency != "USDT" { //不是U本位 +// //获取币本位兑换u的价格 +// ticker2 := models2.TradeSet{} +// tickerVal, _ := helper.DefaultRedis.GetString(fmt.Sprintf(global.TICKER_SPOT, req.ExchangeType, strings.ToUpper(tradeSet.Coin+"USDT"))) - if tickerVal == "" { - logger.Error("查询行情失败") - return fmt.Errorf("交易对:%s 获取u本位行情失败", req.Symbol) - } +// if tickerVal == "" { +// logger.Error("查询行情失败") +// return fmt.Errorf("交易对:%s 获取u本位行情失败", req.Symbol) +// } - err := sonic.Unmarshal([]byte(tickerVal), &ticker2) +// err := sonic.Unmarshal([]byte(tickerVal), &ticker2) - if ticker2.LastPrice == "" { - logger.Errorf("查询行情失败 %s err:%v", strings.ToUpper(tradeSet.Coin+"USDT"), err) - return fmt.Errorf("交易对:%s 获取u本位行情 反序列化失败", req.Symbol) - } - //LTCBTC --> LTCUSDT - uTickerPrice := utility.StrToDecimal(ticker2.LastPrice) //94069 - //换算成U - //div := decimal.NewFromInt(1).Div(uTickerPrice) //0.0000106365 - //在换算成对应交易对对应的价值 - //LTCBTC --> LTCUSDT == LTCUSDT -- 100.502 - div := tickerPrice.Div(decimal.NewFromInt(1).Div(uTickerPrice)) - //计算下单数量 - addPosition.Num = req.BuyPrice.Div(div).Truncate(int32(tradeSet.AmountDigit)).String() - } else { - fromString, _ := decimal.NewFromString(addPosition.Price) - addPosition.Num = req.BuyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String() - } - //事务保存 - err := e.Orm.Transaction(func(tx *gorm.DB) error { - //添加加仓单 - if err := tx.Create(&addPosition).Error; err != nil { - return err - } +// if ticker2.LastPrice == "" { +// logger.Errorf("查询行情失败 %s err:%v", strings.ToUpper(tradeSet.Coin+"USDT"), err) +// return fmt.Errorf("交易对:%s 获取u本位行情 反序列化失败", req.Symbol) +// } +// //LTCBTC --> LTCUSDT +// uTickerPrice := utility.StrToDecimal(ticker2.LastPrice) //94069 +// //换算成U +// //div := decimal.NewFromInt(1).Div(uTickerPrice) //0.0000106365 +// //在换算成对应交易对对应的价值 +// //LTCBTC --> LTCUSDT == LTCUSDT -- 100.502 +// div := tickerPrice.Div(decimal.NewFromInt(1).Div(uTickerPrice)) +// //计算下单数量 +// addPosition.Num = req.BuyPrice.Div(div).Truncate(int32(tradeSet.AmountDigit)).String() +// } else { +// fromString, _ := decimal.NewFromString(addPosition.Price) +// addPosition.Num = req.BuyPrice.Div(fromString).Truncate(int32(tradeSet.AmountDigit)).String() +// } +// //事务保存 +// err := e.Orm.Transaction(func(tx *gorm.DB) error { +// //添加加仓单 +// if err := tx.Create(&addPosition).Error; err != nil { +// return err +// } - //止盈、减仓 - orders, err := makeFuturesTakeAndReduce(&addPosition, ext, tradeSet) +// //止盈、减仓 +// orders, err := makeFuturesTakeAndReduce(&addPosition, ext, tradeSet) - if err != nil { - logger.Error("构造加仓单止盈、减仓失败") - return err - } +// if err != nil { +// logger.Error("构造加仓单止盈、减仓失败") +// return err +// } - if err := e.Orm.Create(&orders).Error; 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 && ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 && ext.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { - reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), ext, tradeSet) +// //处理减仓单 +// for index := range orders { +// //减仓单且 减仓比例大于0 小于100 就冲下止盈止损 +// if orders[index].OrderType == 4 && ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 && ext.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { +// reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), ext, tradeSet) - if err != nil { - logger.Error("生产加仓单止盈、减仓失败") - return err - } +// if err != nil { +// logger.Error("生产加仓单止盈、减仓失败") +// return err +// } - if len(reduceChildOrders) == 0 { - continue - } +// if len(reduceChildOrders) == 0 { +// continue +// } - if err := e.Orm.Create(&reduceChildOrders).Error; err != nil { - logger.Error("报错减仓后止盈止损失败") - return err - } - } - } +// if err := e.Orm.Create(&reduceChildOrders).Error; err != nil { +// logger.Error("报错减仓后止盈止损失败") +// return err +// } +// } +// } - ext.OrderId = addPosition.Id - if err := tx.Create(&ext).Error; err != nil { - return err - } +// ext.OrderId = addPosition.Id +// if err := tx.Create(&ext).Error; err != nil { +// return err +// } - return nil - }) +// return nil +// }) - if err != nil { - logger.Errorf("交易对:%s 添加加仓订单失败", req.Symbol) - return fmt.Errorf("交易对:%s 添加加仓订单失败", req.Symbol) - } +// if err != nil { +// logger.Errorf("交易对:%s 添加加仓订单失败", req.Symbol) +// return fmt.Errorf("交易对:%s 添加加仓订单失败", req.Symbol) +// } - return nil -} +// return nil +// } diff --git a/app/admin/service/line_symbol.go b/app/admin/service/line_symbol.go index 9a8f2d7..362e65f 100644 --- a/app/admin/service/line_symbol.go +++ b/app/admin/service/line_symbol.go @@ -294,17 +294,14 @@ func (e *LineSymbol) ResetSpotSymbol() error { logger.Error("获取币安现货交易对失败") return err } - symbols := make([]models.LineSymbol, 0) - + insertSymbols := make([]models.LineSymbol, 0) sysConfig := SysConfig{Service: service.Service{Orm: e.Orm}} var req = new(dto.SysConfigByKeyReq) var resp = new(dto.GetSysConfigByKEYForServiceResp) req.ConfigKey = "quote_volume_24hr" sysConfig.GetWithKey(req, resp) - symbolBlack := make([]models.LineSymbolBlack, 0) - e.Orm.Model(&models.LineSymbolBlack{}).Where("type = '1'").Find(&symbolBlack) - + symbolBlackMap := getSymbolBlackMap(e, "1") type Ticker struct { Symbol string `json:"symbol"` Price string `json:"price"` @@ -317,17 +314,16 @@ func (e *LineSymbol) ResetSpotSymbol() error { return err } + //判断是否在黑名单、是否需要修改 for symbol, tradeSet := range tradeSets { key := fmt.Sprintf(global.TICKER_SPOT, global.EXCHANGE_BINANCE, symbol) //判断是否在黑名单里面 - for _, black := range symbolBlack { - if black.Symbol == symbol { - helper.DefaultRedis.DeleteString(key) - deleteSymbols = append(deleteSymbols, symbol) - continue - } + if _, ok := symbolBlackMap[symbol]; ok { + helper.DefaultRedis.DeleteString(key) + deleteSymbols = append(deleteSymbols, symbol) + continue } val := helper.DefaultRedis.Get(key).Val() @@ -369,7 +365,14 @@ func (e *LineSymbol) ResetSpotSymbol() error { if lineSymbol.Symbol == "" { continue } - symbols = append(symbols, lineSymbol) + insertSymbols = append(insertSymbols, lineSymbol) + } + } + + //判断已经移除的交易对 + for _, v := range oldMapSymbols { + if _, ok := tradeSets[v.Symbol]; !ok && !utility.ContainsStr(deleteSymbols, v.Symbol) { + deleteSymbols = append(deleteSymbols, v.Symbol) } } @@ -393,8 +396,8 @@ func (e *LineSymbol) ResetSpotSymbol() error { batchDeleteBySymbols(deleteSymbols, "1", e) } - if len(symbols) > 0 { - err := e.Orm.Model(&models.LineSymbol{}).Omit("api_id").Create(&symbols).Error + if len(insertSymbols) > 0 { + err := e.Orm.Model(&models.LineSymbol{}).Omit("api_id").Create(&insertSymbols).Error if err != nil { return err } @@ -403,6 +406,18 @@ func (e *LineSymbol) ResetSpotSymbol() error { return nil } +func getSymbolBlackMap(e *LineSymbol, symbolType string) map[string]models.LineSymbolBlack { + symbolBlack := make([]models.LineSymbolBlack, 0) + symbolBlackMap := make(map[string]models.LineSymbolBlack) + + e.Orm.Model(&models.LineSymbolBlack{}).Where("type = ?", symbolType).Find(&symbolBlack) + + for _, v := range symbolBlack { + symbolBlackMap[v.Symbol] = v + } + return symbolBlackMap +} + // 批量删除 根据交易对名 // symbolType 1-现货 2-合约 func batchDeleteBySymbols(deleteSymbols []string, symbolType string, e *LineSymbol) { @@ -459,8 +474,7 @@ func (e *LineSymbol) ResetFuturesSymbol() error { req.ConfigKey = "quote_volume_24hr" sysConfig.GetWithKey(req, resp) symbols := make([]models.LineSymbol, 0) - symbolBlack := make([]models.LineSymbolBlack, 0) - + symbolBlackMap := getSymbolBlackMap(e, "2") type Ticker struct { Symbol string `json:"symbol"` Price string `json:"price"` @@ -473,19 +487,17 @@ func (e *LineSymbol) ResetFuturesSymbol() error { return err } - e.Orm.Model(&models.LineSymbolBlack{}).Where("type = 2").Find(&symbolBlack) + //判断是否在黑名单、是否需要新增 for symbol, tradeSet := range tradeSets { - key := fmt.Sprintf(global.TICKER_FUTURES, global.EXCHANGE_BINANCE, symbol) //判断是否在黑名单里面 - for _, black := range symbolBlack { - if black.Symbol == symbol { - helper.DefaultRedis.DeleteString(key) - deleteSymbols = append(deleteSymbols, symbol) - continue - } + if _, ok := symbolBlackMap[symbol]; ok { + helper.DefaultRedis.DeleteString(key) + deleteSymbols = append(deleteSymbols, symbol) + continue } + val := helper.DefaultRedis.Get(key).Val() var spotTicker24h commonModels.TradeSet sonic.Unmarshal([]byte(val), &spotTicker24h) @@ -528,6 +540,13 @@ func (e *LineSymbol) ResetFuturesSymbol() error { } } + //交易所已经没有的交易对直接去除 + for _, v := range oldMapSymbols { + if _, ok := tradeSets[v.Symbol]; !ok && !utility.ContainsStr(deleteSymbols, v.Symbol) { + deleteSymbols = append(deleteSymbols, v.Symbol) + } + } + groups, err := getSymbolGroups(e, "2") if err != nil { return err diff --git a/app/admin/service/line_symbol_black.go b/app/admin/service/line_symbol_black.go index 4c1e7f9..b65ec9e 100644 --- a/app/admin/service/line_symbol_black.go +++ b/app/admin/service/line_symbol_black.go @@ -79,15 +79,11 @@ func (e *LineSymbolBlack) Insert(c *dto.LineSymbolBlackInsertReq) error { } err = e.Orm.Create(&data).Error - if err != nil { - e.Log.Errorf("LineSymbolBlackService Insert error:%s \r\n", err) - return err - } - return e.reloadSymbol(c.Type) + return err } -func (e *LineSymbolBlack) reloadSymbol(symbolType string) error { +func (e *LineSymbolBlack) ReloadSymbol(symbolType string) error { symbolService := LineSymbol{Service: e.Service} if symbolType == "1" { @@ -133,21 +129,12 @@ func (e *LineSymbolBlack) Update(c *dto.LineSymbolBlackUpdateReq, p *actions.Dat if db.RowsAffected == 0 { return errors.New("无权更新该数据") } - return e.reloadSymbol(c.Type) + return nil } // Remove 删除LineSymbolBlack func (e *LineSymbolBlack) Remove(d *dto.LineSymbolBlackDeleteReq, p *actions.DataPermission) error { var data models.LineSymbolBlack - types := make([]string, 0) - - e.Orm.Model(&data).Where("id in ?", d.GetId()).Select("type").Distinct().Find(&types) - - for _, v := range types { - if v != "" { - e.reloadSymbol(v) - } - } db := e.Orm.Model(&data). Scopes( diff --git a/services/binanceservice/commonservice.go b/services/binanceservice/commonservice.go index 091f1c6..adcd648 100644 --- a/services/binanceservice/commonservice.go +++ b/services/binanceservice/commonservice.go @@ -461,7 +461,7 @@ func getOpenPositionMainOrderId(db *gorm.DB, newId, apiId, symbolType int, excha mainOrders := make([]DbModels.LinePreOrder, 0) if err := db.Model(&DbModels.LinePreOrder{}). - Where("api_id =? AND status>4 AND status<7 AND symbol=? AND symbol_type =? AND site= ? AND exchange_type=? AND id!=?", + Where("api_id =? AND status>4 AND order_type =0 AND status<7 AND symbol=? AND symbol_type =? AND site= ? AND exchange_type=? AND id!=?", apiId, symbol, symbolType, side, exchangeType, newId). Select("id", "main_id", "order_sn").Find(&mainOrders).Error; err != nil { return nil, err diff --git a/services/binanceservice/futuresrest.go b/services/binanceservice/futuresrest.go index 8c32a08..6f075ac 100644 --- a/services/binanceservice/futuresrest.go +++ b/services/binanceservice/futuresrest.go @@ -93,7 +93,7 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta switch { //主单成交 case preOrder.OrderType == 0 && orderStatus == 6: - handleFutMainOrderFilled(db, preOrder) + handleFutMainOrderFilled(db, preOrder, preOrder.Id, true) //止盈成交 case preOrder.OrderType == 1 && orderStatus == 6: handleTakeProfit(db, preOrder) @@ -327,22 +327,30 @@ func handleStopLoss(db *gorm.DB, preOrder *DbModels.LinePreOrder) { // 止盈单成交 func handleTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder) { - removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) - removePosition(db, preOrder) + childCount, _ := GetChildTpOrder(db, preOrder.Id) - futApi := FutRestApi{} - apiUserInfo, _ := GetApiInfo(preOrder.ApiId) + if childCount > 0 { + extOrderId := preOrder.Pid //ext主单id - if apiUserInfo.Id > 0 { - if err := futApi.CancelAllFutOrder(apiUserInfo, preOrder.Symbol); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + handleFutMainOrderFilled(db, preOrder, extOrderId, false) + } else { + 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) + } } - } - ids := []int{preOrder.Pid, preOrder.MainId} - //主单止盈成交 - if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND order_type=0", ids).Update("status", 9).Error; err != nil { - logger.Errorf("主单止盈成功修改主单状态失败 订单号:%s:", err) + ids := []int{preOrder.Pid, preOrder.MainId} + //主单止盈成交 + if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND order_type=0", ids).Update("status", 9).Error; err != nil { + logger.Errorf("主单止盈成功修改主单状态失败 订单号:%s:", err) + } } } @@ -396,7 +404,7 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) { } // 处理主单成交,处理止盈、止损、减仓订单 -func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) { +func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) { // 获取交易对配置和API信息 tradeSet, err := GetTradeSet(preOrder.Symbol, 1) if err != nil || tradeSet.Coin == "" { @@ -434,7 +442,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) { // 获取和保存持仓数据 positionData := savePosition(db, preOrder) orderExt := models.LinePreOrderExt{} - db.Model(&orderExt).Where("order_id =?", preOrder.Id).First(&orderExt) + db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt) num := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet).Truncate(int32(tradeSet.AmountDigit)) // 更新订单数量并处理止盈、止损、减仓 @@ -443,13 +451,13 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) { order.Price = price.String() // 更新止盈止损订单数量 - num = updateOrderQuantity(db, order, preOrder, num, tradeSet) + num = updateOrderQuantity(db, order, preOrder, &orderExt, num, first, tradeSet) // 根据订单类型处理 switch order.OrderType { case 1: // 止盈 //亏损大于0 重新计算比例 - if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { + if first && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100)) percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) order.Rate = percentag.String() @@ -460,10 +468,30 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) { } else { order.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() } + } else if !first && orderExt.TpTpPriceRatio.Cmp(decimal.Zero) > 0 { + //止盈后止盈 + order.Rate = orderExt.TpTpPriceRatio.String() + + if positionData.PositionSide == "LONG" { + order.Price = price.Mul(decimal.NewFromInt(1).Add(orderExt.TpTpPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + order.Price = price.Mul(decimal.NewFromInt(1).Sub(orderExt.TpTpPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } } processFutTakeProfitOrder(db, FutRestApi{}, order, num) case 2: // 止损 + if !first && orderExt.TpSlPriceRatio.Cmp(decimal.Zero) > 0 { + //止盈后止损 + order.Rate = orderExt.TpSlPriceRatio.String() + + if positionData.PositionSide == "LONG" { + order.Price = price.Mul(decimal.NewFromInt(1).Sub(orderExt.TpSlPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + order.Price = price.Mul(decimal.NewFromInt(1).Add(orderExt.TpSlPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } + } + processFutStopLossOrder(db, order, price, num) case 4: // 减仓 processFutReduceOrder(order, price, num) @@ -541,19 +569,18 @@ func getStopOrders(db *gorm.DB, preOrder *models.LinePreOrder) ([]models.LinePre } // 更新订单数量 -func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *models.LinePreOrder, num decimal.Decimal, tradeSet models2.TradeSet) decimal.Decimal { +func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *models.LinePreOrder, ext *models.LinePreOrderExt, num decimal.Decimal, first bool, tradeSet models2.TradeSet) decimal.Decimal { // 处理减仓比例 - if order.OrderType == 4 { - ext := DbModels.LinePreOrderExt{} - if err := db.Model(&ext).Where("order_id=?", preOrder.Id).Find(&ext).Error; err != nil { - logger.Errorf("查询减仓比例失败, 订单号:%s, 错误信息: %v", order.OrderSn, err) - } + // if order.OrderType == 4 && ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { + // // 计算减仓数量 + // num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) + // order.Num = num.String() + // } else - // 计算减仓数量 - if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { - num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) - order.Num = num.String() - } + if first && order.OrderCategory == 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() } // 更新订单数量 @@ -613,17 +640,17 @@ func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.Line if err != nil { logger.Error("合约止盈下单失败:", order.OrderSn, " err:", err) if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ?", order.Id). - Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity}).Error; err != nil { + Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity, "rate": order.Rate, "price": order.Price}).Error; err != nil { logger.Error("合约止盈下单失败,更新状态失败:", order.OrderSn, " err:", err) } } else { if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", order.Id). - Updates(map[string]interface{}{"trigger_time": time.Now(), "rate": order.Rate}).Error; err != nil { + Updates(map[string]interface{}{"trigger_time": time.Now(), "rate": order.Rate, "num": num.String(), "price": order.Price}).Error; err != nil { logger.Error("更新合约止盈单触发事件 ordersn:", order.OrderSn) } if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ? and status =0", order.Id). - Updates(map[string]interface{}{"status": "1", "num": num.String(), "price": order.Price}).Error; err != nil { + Updates(map[string]interface{}{"status": "1"}).Error; err != nil { logger.Error("合约止盈下单成功,更新状态失败:", order.OrderSn, " err:", err) } } diff --git a/services/binanceservice/orderservice.go b/services/binanceservice/orderservice.go index 9fba597..5ae881a 100644 --- a/services/binanceservice/orderservice.go +++ b/services/binanceservice/orderservice.go @@ -159,3 +159,14 @@ func GetSymbolTriggerCount(db *gorm.DB, symbol string, apiId, symbolType int) (i // func GetOpenedOrders(db *gorm.DB, apiId int, exchange, symbol, symbolType, side string) ([]models.LinePreOrder, error) { // } + +// 获取子订单止盈止损数量 +func GetChildTpOrder(db *gorm.DB, pid int) (int, error) { + var count int64 + + if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type>0 and order_type <3 and status =0", pid).Count(&count).Error; err != nil { + return 0, err + } + + return int(count), nil +} diff --git a/services/binanceservice/spotreset.go b/services/binanceservice/spotreset.go index 3cdbb45..3a9dbb6 100644 --- a/services/binanceservice/spotreset.go +++ b/services/binanceservice/spotreset.go @@ -404,40 +404,41 @@ func handleMainOrderClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) // 止盈成交 func handleSpotTakeProfitFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { - removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + childCount, _ := GetChildTpOrder(db, preOrder.Id) - spotApi := SpotRestApi{} - apiUserInfo, _ := GetApiInfo(preOrder.ApiId) + if childCount > 0 { + extOrderId := preOrder.Pid //ext主单id + positionData := savePosition(db, preOrder) + processTakeProfitAndStopLossOrders(db, preOrder, &positionData, extOrderId, false) + } else { + removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) - if apiUserInfo.Id > 0 { - req := CancelOpenOrdersReq{ - Symbol: preOrder.Symbol, - ApiId: preOrder.ApiId, - } - if err := spotApi.CancelOpenOrders(db, req); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + 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) + } } + + removePosition(db, preOrder) + + db.Transaction(func(tx *gorm.DB) error { + ids := []int{preOrder.Pid, preOrder.MainId} + if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6 AND order_type=0", ids).Update("status", 9).Error; err != nil { + logger.Errorf("止盈订单回调失败, 回调订单号:%s 更新主单失败:%v", preOrder.OrderSn, err) + + return err + } + + return nil + }) } - - removePosition(db, preOrder) - - db.Transaction(func(tx *gorm.DB) error { - ids := []int{preOrder.Pid, preOrder.MainId} - if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6 AND order_type=0", ids).Update("status", 9).Error; err != nil { - logger.Errorf("止盈订单回调失败, 回调订单号:%s 更新主单失败:%v", preOrder.OrderSn, err) - - return err - } - - // if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND status=0",).Update("status", 4).Error; err != nil { - // logger.Errorf("止盈订单回调失败, 回调订单号:%s 更新取消状态失败:%v", preOrder.OrderSn, err) - - // return err - // } - - return nil - }) - } // 移除仓位信息 @@ -550,7 +551,7 @@ func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { } } - processTakeProfitAndStopLossOrders(db, preOrder, &positionData) + processTakeProfitAndStopLossOrders(db, preOrder, &positionData, preOrder.Id, true) } // 解析订单状态 @@ -618,7 +619,8 @@ func updateOrderStatus(db *gorm.DB, preOrder *models.LinePreOrder, status int, r // 主单成交 处理止盈止损订单 // preOrder 主单 // positionData 持仓缓存信息 -func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto) { +// fist 首次止盈止损 +func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) { orders := []models.LinePreOrder{} tradeSet, _ := GetTradeSet(preOrder.Symbol, 0) @@ -651,18 +653,14 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd price := utility.StrToDecimal(preOrder.Price) spotApi := SpotRestApi{} orderExt := models.LinePreOrderExt{} - db.Model(&orderExt).Where("order_id =?", preOrder.Id).First(&orderExt) + db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt) for _, order := range orders { order.Num = num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)).String() - if order.OrderType == 4 { - ext := DbModels.LinePreOrderExt{} - db.Model(&ext).Where("order_id=?", preOrder.Id).Find(&ext) - - if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { - order.Num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String() - } + if fist && order.OrderCategory == 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() } if err := db.Model(&order).Update("num", order.Num).Error; err != nil { @@ -672,16 +670,29 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd switch order.OrderType { case 1: // 止盈 //亏损大于0 重新计算比例 - if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { + if fist && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100)) - percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) + + if fist { + percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) + } + order.Rate = percentag.String() percentag = percentag.Div(decimal.NewFromInt(100)) order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() + } else if orderExt.Id > 0 { + percentag := orderExt.TpTpPriceRatio + order.Rate = percentag.String() + order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() } processTakeProfitOrder(db, spotApi, order) case 2: // 止损 + if !fist { + order.Rate = orderExt.TpSlPriceRatio.Truncate(2).String() + order.Price = price.Mul(decimal.NewFromInt(1).Sub(orderExt.TpSlPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } + processStopLossOrder(order) case 4: //减仓 processSpotReduceOrder(order) @@ -761,16 +772,16 @@ func processTakeProfitOrder(db *gorm.DB, spotApi SpotRestApi, order models.LineP if err != nil { logger.Error("现货止盈下单失败:", order.OrderSn, " err:", err) if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ?", order.Id). - Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity}).Error; err != nil { + Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity, "rate": order.Rate, "price": order.Price}).Error; err != nil { logger.Error("现货止盈下单失败,更新状态失败:", order.OrderSn, " err:", err) } } else { if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", order.Id). - Updates(map[string]interface{}{"trigger_time": time.Now(), "rate": order.Rate}).Error; err != nil { + Updates(map[string]interface{}{"trigger_time": time.Now(), "rate": order.Rate, "price": order.Price, "num": order.Num}).Error; err != nil { logger.Error("更新现货止盈单触发事件 ordersn:", order.OrderSn) } if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ? and status ='0'", order.Id). - Updates(map[string]interface{}{"status": "1", "num": order.Num, "price": order.Price}).Error; err != nil { + Updates(map[string]interface{}{"status": "1"}).Error; err != nil { logger.Error("现货止盈下单成功,更新状态失败:", order.OrderSn, " err:", err) } }