拆分加仓、减仓
This commit is contained in:
@ -277,6 +277,10 @@ func (req LineAddPreOrderReq) Valid() error {
|
||||
return errors.New("主单减仓数量百分比不能为空")
|
||||
}
|
||||
|
||||
if req.ReducePriceRatio.IsZero() || req.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) >= 0 {
|
||||
return errors.New("主单减仓价格百分比错误")
|
||||
}
|
||||
|
||||
for _, v := range req.Ext {
|
||||
name := "加仓"
|
||||
|
||||
@ -299,13 +303,17 @@ func (req LineAddPreOrderReq) Valid() error {
|
||||
return errors.New("止盈价格不正确")
|
||||
}
|
||||
|
||||
if v.TpTpPriceRatio.IsZero() || v.TpTpPriceRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
||||
if v.AddType == 1 && v.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 &&
|
||||
v.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 &&
|
||||
(v.TpTpPriceRatio.IsZero() || v.TpTpPriceRatio.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("止盈后止损价格不正确")
|
||||
}
|
||||
// if v.AddType == 1 && v.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 &&
|
||||
// v.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 &&
|
||||
// (v.TpSlPriceRatio.Cmp(decimal.Zero) <= 0 || v.TpSlPriceRatio.Cmp(decimal.NewFromInt(100)) > 0) {
|
||||
// return errors.New("止盈后止损价格不正确")
|
||||
// }
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -481,10 +481,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
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))
|
||||
defultExt2.ReTakeRatio = req.ReducePriceRatio.Div(decimal.NewFromInt(100).Sub(req.ReduceNumRatio).Div(decimal.NewFromInt(100))).Truncate(2)
|
||||
preOrderExts = append(preOrderExts, defultExt)
|
||||
|
||||
calculateResp := dto.CalculateBreakEvenRatioResp{}
|
||||
mainParam := dto.CalculateBreakEevenRatioReq{
|
||||
AddType: 2,
|
||||
Price: mainPrice,
|
||||
ExchangeType: req.ExchangeType,
|
||||
Symbol: req.Symbol,
|
||||
@ -492,8 +494,8 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
BuyPrice: buyPrice,
|
||||
LossBeginPercent: decimal.Zero,
|
||||
LossEndPercent: req.ReducePriceRatio,
|
||||
AddPositionType: 2,
|
||||
AddPositionVal: decimal.Zero,
|
||||
AddPositionType: 1,
|
||||
AddPositionVal: req.ReduceNumRatio,
|
||||
}
|
||||
|
||||
//计算减仓后
|
||||
@ -510,14 +512,17 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
ext := models.LinePreOrderExt{
|
||||
AddType: addPosition.AddType,
|
||||
OrderType: addPosition.OrderType,
|
||||
PriceRatio: addPosition.PriceRatio,
|
||||
TakeProfitRatio: addPosition.TakeProfitRatio,
|
||||
TakeProfitNumRatio: addPosition.TakeProfitNumRatio,
|
||||
StopLossRatio: addPosition.StopLossRatio,
|
||||
TpTpPriceRatio: addPosition.TpTpPriceRatio,
|
||||
TpSlPriceRatio: addPosition.TpSlPriceRatio,
|
||||
AddPositionType: addPosition.AddPositionType,
|
||||
AddPositionVal: addPosition.AddPositionVal,
|
||||
}
|
||||
|
||||
mainParam.AddType = addPosition.AddType
|
||||
mainParam.LossEndPercent = req.Ext[index].PriceRatio
|
||||
mainParam.AddPositionType = req.Ext[index].AddPositionType
|
||||
mainParam.AddPositionVal = req.Ext[index].AddPositionVal
|
||||
@ -623,7 +628,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
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 {
|
||||
if newOrders, err := makeReduceTakeAndStoploss(&stopOrder, defultExt2, tradeSet, false); err != nil {
|
||||
logger.Errorf("主单减仓生成止盈、减仓失败 err:%v", err)
|
||||
return err
|
||||
} else if len(newOrders) > 0 {
|
||||
@ -638,30 +643,30 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
//添加止盈单
|
||||
for index, v := range preOrderExts {
|
||||
preOrderExts[index].MainOrderId = AddOrder.Id
|
||||
if index == 0 {
|
||||
preOrderExts[index].OrderId = AddOrder.Id
|
||||
continue
|
||||
}
|
||||
var AddOrder models.LinePreOrder
|
||||
// if index == 0 {
|
||||
// preOrderExts[index].OrderId = AddOrder.Id
|
||||
// continue
|
||||
// }
|
||||
var newOrder models.LinePreOrder
|
||||
|
||||
if v.AddType == 1 {
|
||||
AddOrder = createPreAddPosition(&AddOrder, v, tradeSet)
|
||||
newOrder = createPreAddPosition(&AddOrder, v, tradeSet)
|
||||
} else if v.AddType == 2 {
|
||||
AddOrder = createPreReduceOrder(&AddOrder, v, tradeSet)
|
||||
newOrder = createPreReduceOrder(&AddOrder, v, tradeSet)
|
||||
}
|
||||
|
||||
if AddOrder.OrderSn == "" {
|
||||
if newOrder.OrderSn == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := e.Orm.Create(&AddOrder).Error; err != nil {
|
||||
if err := e.Orm.Create(&newOrder).Error; err != nil {
|
||||
logger.Error("保存加仓单失败")
|
||||
return err
|
||||
}
|
||||
|
||||
preOrderExts[index].OrderId = AddOrder.Id
|
||||
preOrderExts[index].OrderId = newOrder.Id
|
||||
//止盈、减仓
|
||||
orders, err := makeFuturesTakeAndReduce(&AddOrder, v, tradeSet)
|
||||
orders, err := makeFuturesTakeAndReduce(&newOrder, v, tradeSet)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("构造止盈、止损失败")
|
||||
@ -676,7 +681,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
||||
for index := range orders {
|
||||
//减仓单且 减仓比例大于0 小于100 就冲下止盈止损
|
||||
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)
|
||||
reduceChildOrders, err := makeReduceTakeAndStoploss(&(orders[index]), v, tradeSet, true)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("生产止盈后止盈、减仓失败")
|
||||
@ -722,6 +727,11 @@ func createPreAddPosition(preOrder *models.LinePreOrder, v models.LinePreOrderEx
|
||||
data.Pid = preOrder.Id
|
||||
data.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
data.MainId = preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
data.MainId = preOrder.MainId
|
||||
}
|
||||
|
||||
data.CreatedAt = time.Now()
|
||||
data.MainOrderType = v.OrderType
|
||||
data.Status = 0
|
||||
@ -761,12 +771,18 @@ func createPreReduceOrder(preOrder *models.LinePreOrder, ext models.LinePreOrder
|
||||
stopOrder.Id = 0
|
||||
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
|
||||
stopOrder.Pid = preOrder.Id
|
||||
stopOrder.MainId = preOrder.MainId
|
||||
stopOrder.MainId = preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
stopOrder.MainId = preOrder.MainId
|
||||
}
|
||||
|
||||
stopOrder.OrderType = 4
|
||||
stopOrder.Status = 0
|
||||
stopOrder.Rate = ext.PriceRatio.String()
|
||||
stopOrder.Num = ext.TotalAfter.Sub(ext.TotalBefore).Abs().Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
stopOrder.BuyPrice = "0"
|
||||
stopOrder.Rate = ext.PriceRatio.String()
|
||||
|
||||
if strings.ToUpper(preOrder.Site) == "BUY" {
|
||||
stopOrder.Site = "SELL"
|
||||
@ -801,7 +817,11 @@ func makeFuturesTakeAndReduce(preOrder *models.LinePreOrder, ext models.LinePreO
|
||||
profitOrder.Pid = preOrder.Id
|
||||
profitOrder.OrderType = 1
|
||||
profitOrder.Status = 0
|
||||
profitOrder.MainId = preOrder.MainId
|
||||
profitOrder.MainId = preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
profitOrder.MainId = preOrder.MainId
|
||||
}
|
||||
profitOrder.BuyPrice = "0"
|
||||
profitOrder.Site = side
|
||||
|
||||
@ -877,16 +897,25 @@ func makeTpOrder(parentOrder *models.LinePreOrder, reminQuantity decimal.Decimal
|
||||
}
|
||||
|
||||
// 构建减仓后止盈止损
|
||||
func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet) ([]models.LinePreOrder, error) {
|
||||
// isTpTp 是否止盈后止盈止损
|
||||
func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.LinePreOrderExt, tradeSet models2.TradeSet, isTpTp bool) ([]models.LinePreOrder, error) {
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
var num decimal.Decimal
|
||||
num := ext.TotalAfter
|
||||
var takeProfitRatio, slPriceRatio decimal.Decimal
|
||||
if isTpTp {
|
||||
takeProfitRatio = ext.TpTpPriceRatio
|
||||
slPriceRatio = ext.TpSlPriceRatio
|
||||
} else {
|
||||
takeProfitRatio = ext.TakeProfitRatio
|
||||
slPriceRatio = ext.StopLossRatio
|
||||
}
|
||||
|
||||
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 {
|
||||
if takeProfitRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 {
|
||||
takeProfitOrder := models.LinePreOrder{}
|
||||
copier.Copy(&takeProfitOrder, parentOrder)
|
||||
takeProfitOrder.Id = 0
|
||||
@ -894,21 +923,25 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line
|
||||
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()
|
||||
if isTpTp {
|
||||
takeProfitOrder.Rate = takeProfitRatio.Truncate(2).String()
|
||||
} else {
|
||||
takeProfitOrder.Rate = takeProfitRatio.Add(ext.ReTakeRatio).Truncate(2).String()
|
||||
}
|
||||
|
||||
takeProfitOrder.BuyPrice = "0"
|
||||
|
||||
binanceservice.SetPrice(&takeProfitOrder, parentOrder, tradeSet)
|
||||
orders = append(orders, takeProfitOrder)
|
||||
}
|
||||
//有止损单
|
||||
if ext.TpSlPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 {
|
||||
if slPriceRatio.Cmp(decimal.Zero) > 0 && num.Cmp(decimal.Zero) > 0 {
|
||||
var stoploss models.LinePreOrder
|
||||
|
||||
copier.Copy(&stoploss, parentOrder)
|
||||
@ -920,7 +953,7 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line
|
||||
stoploss.OrderType = 2
|
||||
stoploss.SignPrice = parentOrder.Price
|
||||
stoploss.BuyPrice = "0"
|
||||
stoploss.Rate = ext.TpSlPriceRatio.String()
|
||||
stoploss.Rate = slPriceRatio.String()
|
||||
stoploss.MainOrderType = "LIMIT"
|
||||
stoploss.Num = num.String()
|
||||
stoploss.BuyPrice = "0"
|
||||
@ -1658,6 +1691,7 @@ func (e *LinePreOrder) FutClosePosition(position *dto.ClosePosition, errs *[]err
|
||||
// ClearUnTriggered 清除待触发的交易对
|
||||
func (e *LinePreOrder) ClearUnTriggered() error {
|
||||
var orderLists []models.LinePreOrder
|
||||
positions := map[string]positiondto.LinePreOrderPositioinDelReq{}
|
||||
e.Orm.Model(&models.LinePreOrder{}).Where("main_id = 0 AND pid = 0 AND status = '0'").Find(&orderLists).Unscoped().Delete(&models.LinePreOrder{})
|
||||
|
||||
for _, order := range orderLists {
|
||||
@ -1680,8 +1714,43 @@ func (e *LinePreOrder) ClearUnTriggered() error {
|
||||
key := fmt.Sprintf(rediskey.PreSpotOrderList, order.ExchangeType)
|
||||
helper.DefaultRedis.LRem(key, string(marshal))
|
||||
}
|
||||
|
||||
//会影响持仓的
|
||||
removeSymbolKey := fmt.Sprintf("%v_%s_%s_%s_%v", order.ApiId, order.ExchangeType, order.Symbol, order.Site, order.SymbolType)
|
||||
|
||||
if _, ok := positions[removeSymbolKey]; !ok {
|
||||
positions[removeSymbolKey] = positiondto.LinePreOrderPositioinDelReq{
|
||||
ApiId: order.ApiId,
|
||||
Symbol: order.Symbol,
|
||||
ExchangeType: order.ExchangeType,
|
||||
Side: order.Site,
|
||||
SymbolType: order.SymbolType,
|
||||
}
|
||||
}
|
||||
|
||||
e.Orm.Model(&models.LinePreOrder{}).Where("main_id = ?", order.Id).Unscoped().Delete(&models.LinePreOrder{})
|
||||
}
|
||||
|
||||
//清理仓位缓存
|
||||
for _, v := range positions {
|
||||
var count int64
|
||||
e.Orm.Model(&models.LinePreOrder{}).
|
||||
Where("api_id =? AND site=? AND symbol=? AND symbol_type =? AND exchange_type =? AND status =6",
|
||||
v.ApiId, v.Side, v.Symbol, v.SymbolType, v.ExchangeType).Count(&count)
|
||||
|
||||
//没有已开仓的订单 直接清理仓位
|
||||
if count == 0 {
|
||||
var key string
|
||||
|
||||
if v.SymbolType == 1 {
|
||||
key = fmt.Sprintf(rediskey.SpotPosition, v.ExchangeType, v.ApiId, v.Symbol, v.Side)
|
||||
} else {
|
||||
key = fmt.Sprintf(rediskey.FuturePosition, v.ExchangeType, v.ApiId, v.Symbol, v.Side)
|
||||
}
|
||||
|
||||
helper.DefaultRedis.DeleteString(key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1774,8 +1843,8 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error {
|
||||
BuyPrice: buyPrice,
|
||||
LossBeginPercent: lossBeginPercent,
|
||||
LossEndPercent: req.ReducePriceRatio,
|
||||
AddPositionType: 2,
|
||||
AddPositionVal: decimal.Zero,
|
||||
AddPositionType: 1,
|
||||
AddPositionVal: req.ReduceNumRatio,
|
||||
}
|
||||
|
||||
//计算减仓后
|
||||
@ -1794,6 +1863,7 @@ func (e *LinePreOrder) GenerateOrder(req *dto.LineAddPreOrderReq) error {
|
||||
})
|
||||
|
||||
for index := range req.Ext {
|
||||
mainParam.AddType = req.Ext[index].AddType
|
||||
mainParam.LossBeginPercent = lossBeginPercent
|
||||
mainParam.LossEndPercent = req.Ext[index].PriceRatio
|
||||
mainParam.AddPositionType = req.Ext[index].AddPositionType
|
||||
@ -1819,9 +1889,9 @@ func (e *LinePreOrder) CalculateBreakEvenRatio(req *dto.CalculateBreakEevenRatio
|
||||
|
||||
var addPositionBuyPrice decimal.Decimal
|
||||
|
||||
if req.AddPositionType == 1 {
|
||||
if req.AddType == 1 && req.AddPositionType == 1 {
|
||||
addPositionBuyPrice = req.BuyPrice.Mul(req.AddPositionVal.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(2)
|
||||
} else {
|
||||
} else if req.AddType == 1 {
|
||||
addPositionBuyPrice = req.AddPositionVal.Truncate(2)
|
||||
}
|
||||
|
||||
@ -1839,7 +1909,7 @@ 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.AddPositionType == 2 && req.AddPositionVal.Cmp(decimal.NewFromInt(0)) > 0 {
|
||||
if req.AddType == 2 && req.AddPositionType == 1 && req.AddPositionVal.Cmp(decimal.NewFromInt(0)) > 0 {
|
||||
reduceAmount = totalAmount.Mul(req.AddPositionVal.Div(decimal.NewFromInt(100).Truncate(4))).Truncate(int32(tradeSet.AmountDigit))
|
||||
}
|
||||
|
||||
|
||||
@ -100,6 +100,9 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta
|
||||
//减仓回调
|
||||
case preOrder.OrderType == 4 && orderStatus == 6:
|
||||
handleReduceFilled(db, preOrder)
|
||||
//主单取消
|
||||
case preOrder.OrderType == 0 && preOrder.Pid == 0 && orderStatus == 4:
|
||||
handleMainOrderCancel(db, preOrder, 2)
|
||||
//止损成交
|
||||
case preOrder.OrderType == 2 && orderStatus == 6:
|
||||
handleStopLoss(db, preOrder)
|
||||
@ -154,6 +157,12 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
totalNum = totalNum.Truncate(int32(tradeSet.AmountDigit))
|
||||
price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit))
|
||||
futApi := FutRestApi{}
|
||||
mainId := preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
mainId = preOrder.MainId
|
||||
}
|
||||
|
||||
db.Model(&orderExt).Where("order_id =?", preOrder.Pid).First(&orderExt)
|
||||
|
||||
for _, v := range orders {
|
||||
@ -177,39 +186,46 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
processFutStopLossOrder(db, v, utility.StrToDecimal(v.Price), totalNum)
|
||||
}
|
||||
}
|
||||
nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet)
|
||||
}
|
||||
|
||||
//加仓待触发
|
||||
addPositionOrder := DbModels.LinePreOrder{}
|
||||
// 下一个合约待触发
|
||||
func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tradeSet models2.TradeSet) {
|
||||
nextOrder := DbModels.LinePreOrder{}
|
||||
nextExt := DbModels.LinePreOrderExt{}
|
||||
|
||||
if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
keyFutAddpositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE)
|
||||
|
||||
addPositionData := AddPositionList{
|
||||
Id: addPositionOrder.Id,
|
||||
OrderSn: addPositionOrder.OrderSn,
|
||||
MainId: addPositionOrder.MainId,
|
||||
Pid: addPositionOrder.Pid,
|
||||
Price: utility.StrToDecimal(addPositionOrder.Price),
|
||||
ApiId: addPositionOrder.ApiId,
|
||||
Symbol: addPositionOrder.Symbol,
|
||||
Side: addPositionOrder.Site,
|
||||
SymbolType: addPositionOrder.SymbolType,
|
||||
if err := db.Model(&models.LinePreOrderExt{}).Where("id =?", nextOrder.Id).First(&nextExt).Error; err != nil {
|
||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||
}
|
||||
|
||||
addVal, err := sonic.MarshalString(addPositionData)
|
||||
num := totalNum
|
||||
//移除缓存
|
||||
key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE)
|
||||
vals, _ := helper.DefaultRedis.GetAllList(key)
|
||||
item := ReduceListItem{}
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
for _, val := range vals {
|
||||
sonic.Unmarshal([]byte(val), &item)
|
||||
if item.MainId == mainId {
|
||||
if _, err := helper.DefaultRedis.LRem(key, val); err != nil {
|
||||
logger.Errorf("减仓单 redis删除失败 main_id:%v err:%v", mainId, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := helper.DefaultRedis.RPushList(keyFutAddpositionKey, addVal); err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
//
|
||||
if nextExt.AddPositionVal.Cmp(decimal.Zero) > 0 && nextExt.AddPositionVal.Cmp(decimal.Zero) < 100 {
|
||||
// 计算减仓数量
|
||||
num = totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
nextOrder.Num = num.String()
|
||||
}
|
||||
|
||||
processFutReduceOrder(nextOrder, utility.StrToDecimal(nextOrder.Price).Truncate(int32(tradeSet.PriceDigit)), num)
|
||||
}
|
||||
|
||||
// 获取合约可用数量
|
||||
@ -407,6 +423,7 @@ func removeFutLossAndAddPosition(mainId int, orderSn string) {
|
||||
func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) {
|
||||
// 获取交易对配置和API信息
|
||||
tradeSet, err := GetTradeSet(preOrder.Symbol, 1)
|
||||
mainId := preOrder.Id
|
||||
if err != nil || tradeSet.Coin == "" {
|
||||
logger.Errorf("获取交易对配置失败, 回调订单号:%s, 错误信息: %v", preOrder.OrderSn, err)
|
||||
return
|
||||
@ -418,6 +435,10 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
|
||||
return
|
||||
}
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
mainId = preOrder.MainId
|
||||
}
|
||||
|
||||
// 处理主单加仓
|
||||
if preOrder.OrderCategory == 3 {
|
||||
if err := handleMainOrderAddPosition(db, preOrder); err != nil {
|
||||
@ -430,6 +451,39 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
|
||||
logger.Errorf("取消主单相关订单失败, 订单号:%s, 错误信息: %v", preOrder.OrderSn, err)
|
||||
return
|
||||
}
|
||||
|
||||
//加仓待触发
|
||||
addPositionOrders := make([]DbModels.LinePreOrder, 0)
|
||||
|
||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.Id).Order("rate asc").Find(&addPositionOrders).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
}
|
||||
keyFutAddpositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE)
|
||||
|
||||
for _, addPositionOrder := range addPositionOrders {
|
||||
addPositionData := AddPositionList{
|
||||
Id: addPositionOrder.Id,
|
||||
OrderSn: addPositionOrder.OrderSn,
|
||||
MainId: addPositionOrder.MainId,
|
||||
Pid: addPositionOrder.Pid,
|
||||
Price: utility.StrToDecimal(addPositionOrder.Price),
|
||||
ApiId: addPositionOrder.ApiId,
|
||||
Symbol: addPositionOrder.Symbol,
|
||||
Side: addPositionOrder.Site,
|
||||
SymbolType: addPositionOrder.SymbolType,
|
||||
}
|
||||
|
||||
addVal, err := sonic.MarshalString(addPositionData)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := helper.DefaultRedis.RPushList(keyFutAddpositionKey, addVal); err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取止盈止损订单
|
||||
@ -493,10 +547,12 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
|
||||
}
|
||||
|
||||
processFutStopLossOrder(db, order, price, num)
|
||||
case 4: // 减仓
|
||||
processFutReduceOrder(order, price, num)
|
||||
// case 4: // 减仓
|
||||
// processFutReduceOrder(order, price, num)
|
||||
}
|
||||
}
|
||||
|
||||
nextFuturesReduceTrigger(db, mainId, num, tradeSet)
|
||||
}
|
||||
|
||||
// 处理主单加仓
|
||||
|
||||
@ -119,7 +119,7 @@ func handleOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderStatus
|
||||
handleMainReduceFilled(db, preOrder)
|
||||
//主单取消
|
||||
case preOrder.OrderType == 0 && preOrder.Pid == 0 && orderStatus == 4:
|
||||
handleMainOrderCancel(preOrder)
|
||||
handleMainOrderCancel(db, preOrder, 1)
|
||||
// 止盈成交
|
||||
case preOrder.OrderType == 1 && orderStatus == 6:
|
||||
handleSpotTakeProfitFilled(db, preOrder)
|
||||
@ -224,38 +224,57 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
}
|
||||
}
|
||||
|
||||
//加仓待触发
|
||||
addPositionOrder := DbModels.LinePreOrder{}
|
||||
mainId := preOrder.Id
|
||||
|
||||
if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
if preOrder.MainId > 0 {
|
||||
mainId = preOrder.MainId
|
||||
}
|
||||
|
||||
keySpotAddPosition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE)
|
||||
nextSpotReduceTrigger(db, mainId, totalNum, tradeSet)
|
||||
}
|
||||
|
||||
addPositionData := AddPositionList{
|
||||
Id: addPositionOrder.Id,
|
||||
OrderSn: addPositionOrder.OrderSn,
|
||||
MainId: addPositionOrder.MainId,
|
||||
Pid: addPositionOrder.Pid,
|
||||
Price: utility.StrToDecimal(addPositionOrder.Price),
|
||||
ApiId: addPositionOrder.ApiId,
|
||||
Symbol: addPositionOrder.Symbol,
|
||||
Side: addPositionOrder.Site,
|
||||
SymbolType: addPositionOrder.SymbolType,
|
||||
// 缓存下一个减仓单
|
||||
func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tradeSet models2.TradeSet) bool {
|
||||
nextOrder := DbModels.LinePreOrder{}
|
||||
nextExt := DbModels.LinePreOrderExt{}
|
||||
// var percentag decimal.Decimal
|
||||
|
||||
if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil {
|
||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||
return true
|
||||
}
|
||||
|
||||
addVal, err := sonic.MarshalString(addPositionData)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
if err := db.Model(&models.LinePreOrderExt{}).Where("id =?", nextOrder.Id).First(&nextExt).Error; err != nil {
|
||||
logger.Errorf("获取下一个单失败 err:%v", err)
|
||||
}
|
||||
|
||||
if err := helper.DefaultRedis.RPushList(keySpotAddPosition, addVal); err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
//移除缓存
|
||||
key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE)
|
||||
vals, _ := helper.DefaultRedis.GetAllList(key)
|
||||
item := ReduceListItem{}
|
||||
|
||||
for _, val := range vals {
|
||||
sonic.Unmarshal([]byte(val), &item)
|
||||
if item.MainId == mainId {
|
||||
if _, err := helper.DefaultRedis.LRem(key, val); err != nil {
|
||||
logger.Errorf("减仓单 redis删除失败 main_id:%v err:%v", mainId, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//减仓配置 且减仓比例大于0小于100
|
||||
if nextExt.Id > 0 && nextExt.AddType == 2 && nextExt.AddPositionVal.Cmp(decimal.Zero) > 0 && nextExt.AddPositionVal.Cmp(decimal.Zero) < 100 {
|
||||
num := totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
||||
// percentag = positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100)).Truncate(2)
|
||||
nextOrder.Num = num.String()
|
||||
}
|
||||
// percentag = nextExt.PriceRatio.Add(percentag)
|
||||
// nextOrder.Rate = percentag.String()
|
||||
// nextOrder.Price = price.Mul(decimal.NewFromInt(1).Add(percentag.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
|
||||
//减仓待触发
|
||||
processSpotReduceOrder(nextOrder)
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取主单可用数量
|
||||
@ -344,8 +363,16 @@ func getSpotPositionNum(apiUserInfo DbModels.LineApiUser, preOrder *DbModels.Lin
|
||||
}
|
||||
|
||||
// 主单取消
|
||||
func handleMainOrderCancel(preOrder *DbModels.LinePreOrder) {
|
||||
preOrderKey := fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE)
|
||||
// symbolType 1:现货 2:合约
|
||||
func handleMainOrderCancel(db *gorm.DB, preOrder *DbModels.LinePreOrder, symboType int) {
|
||||
var preOrderKey string
|
||||
|
||||
if symboType == 1 {
|
||||
preOrderKey = fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE)
|
||||
} else {
|
||||
preOrderKey = fmt.Sprintf(rediskey.PreFutOrderList, global.EXCHANGE_BINANCE)
|
||||
}
|
||||
|
||||
preSpotOrders, _ := helper.DefaultRedis.GetAllList(preOrderKey)
|
||||
preOrderCache := DbModels.LinePreOrder{}
|
||||
|
||||
@ -356,10 +383,17 @@ func handleMainOrderCancel(preOrder *DbModels.LinePreOrder) {
|
||||
|
||||
sonic.Unmarshal([]byte(v), &preOrderCache)
|
||||
if preOrderCache.Pid == preOrder.Id {
|
||||
_, err := helper.DefaultRedis.LRem(preOrderKey, v)
|
||||
var count int64
|
||||
db.Model(&models.LinePreOrder{}).
|
||||
Where("api_id =? AND site=? AND symbol=? AND symbol_type =? AND exchange_type =? AND status =6",
|
||||
preOrder.ApiId, preOrder.Site, preOrder.Symbol, preOrder.SymbolType, preOrder.ExchangeType).Count(&count)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("订单回调失败, 回调订单号:%s 删除缓存失败:%v", preOrder.OrderSn, err)
|
||||
if count == 0 {
|
||||
_, err := helper.DefaultRedis.LRem(preOrderKey, v)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("订单回调失败, 回调订单号:%s 删除缓存失败:%v", preOrder.OrderSn, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -549,9 +583,45 @@ func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//加仓待触发
|
||||
addPositionOrders := make([]DbModels.LinePreOrder, 0)
|
||||
|
||||
if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.Id).Order("rate asc").Find(&addPositionOrders).Error; err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
}
|
||||
|
||||
keySpotAddPosition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE)
|
||||
|
||||
for _, addPositionOrder := range addPositionOrders {
|
||||
addPositionData := AddPositionList{
|
||||
Id: addPositionOrder.Id,
|
||||
OrderSn: addPositionOrder.OrderSn,
|
||||
MainId: addPositionOrder.MainId,
|
||||
Pid: addPositionOrder.Pid,
|
||||
Price: utility.StrToDecimal(addPositionOrder.Price),
|
||||
ApiId: addPositionOrder.ApiId,
|
||||
Symbol: addPositionOrder.Symbol,
|
||||
Side: addPositionOrder.Site,
|
||||
SymbolType: addPositionOrder.SymbolType,
|
||||
}
|
||||
|
||||
addVal, err := sonic.MarshalString(addPositionData)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := helper.DefaultRedis.RPushList(keySpotAddPosition, addVal); err != nil {
|
||||
logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
processTakeProfitAndStopLossOrders(db, preOrder, &positionData, preOrder.Id, true)
|
||||
|
||||
}
|
||||
|
||||
// 解析订单状态
|
||||
@ -623,6 +693,11 @@ func updateOrderStatus(db *gorm.DB, preOrder *models.LinePreOrder, status int, r
|
||||
func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) {
|
||||
orders := []models.LinePreOrder{}
|
||||
tradeSet, _ := GetTradeSet(preOrder.Symbol, 0)
|
||||
mainId := preOrder.Id
|
||||
|
||||
if preOrder.MainId > 0 {
|
||||
mainId = preOrder.MainId
|
||||
}
|
||||
|
||||
if tradeSet.Coin == "" {
|
||||
logger.Error("获取交易对失败")
|
||||
@ -654,9 +729,11 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
|
||||
spotApi := SpotRestApi{}
|
||||
orderExt := models.LinePreOrderExt{}
|
||||
db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt)
|
||||
num = num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
//止盈止损
|
||||
for _, order := range orders {
|
||||
order.Num = num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
order.Num = num.String()
|
||||
|
||||
if fist && order.OrderCategory == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
|
||||
//主单第一次且止盈数量不是100% 止盈数量
|
||||
@ -694,10 +771,13 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
|
||||
}
|
||||
|
||||
processStopLossOrder(order)
|
||||
case 4: //减仓
|
||||
processSpotReduceOrder(order)
|
||||
// case 4: //减仓
|
||||
// processSpotReduceOrder(order)
|
||||
}
|
||||
}
|
||||
|
||||
//待触发减仓单
|
||||
nextSpotReduceTrigger(db, mainId, num, tradeSet)
|
||||
}
|
||||
|
||||
// 根据下单百分比计算价格
|
||||
|
||||
Reference in New Issue
Block a user