1撤销限价后 市价分单

This commit is contained in:
2025-03-27 16:18:32 +08:00
parent 8cede57a70
commit ee148ed144
31 changed files with 1627 additions and 248 deletions

View File

@ -11,12 +11,14 @@ import (
"go-admin/common/global"
"go-admin/common/helper"
models2 "go-admin/models"
"go-admin/models/positiondto"
"go-admin/pkg/utility"
"strings"
"time"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/logger"
log "github.com/go-admin-team/go-admin-core/logger"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
@ -148,26 +150,53 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
return
}
positionData := savePosition(db, preOrder)
lock := helper.NewRedisLock(fmt.Sprintf(rediskey.FutReducecCallback, preOrder.ApiId, preOrder.Symbol), 120, 20, 100*time.Millisecond)
if ok, err := lock.AcquireWait(context.Background()); err != nil {
log.Error("获取锁失败", err)
return
} else if ok {
defer lock.Release()
positionData := savePosition(db, preOrder)
//市价单就跳出 市价减仓不设止盈止损
if preOrder.MainOrderType == "MARKET" {
return
}
//亏损大于0 重新计算比例
FutTakeProfit(db, preOrder, apiUserInfo, tradeSet, positionData, orderExt, decimal.Zero, decimal.Zero)
//处理下一个减仓
HandleNextFuturesReduce(db, apiUserInfo, *preOrder, tradeSet)
}
}
// 减仓处理止盈止损
func FutTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder, apiUserInfo DbModels.LineApiUser, tradeSet models2.TradeSet,
positionData positiondto.PositionDto, orderExt DbModels.LinePreOrderExt, manualTakeRatio, manualStopRatio decimal.Decimal) bool {
orders := make([]models.LinePreOrder, 0)
if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status = 0", preOrder.Id).Find(&orders).Error; err != nil {
logger.Errorf("handleMainReduceFilled 获取待触发订单失败,订单号:%s", preOrder.OrderSn)
return
return true
}
totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet)
price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit))
futApi := FutRestApi{}
mainId := preOrder.Id
if preOrder.MainId > 0 {
mainId = preOrder.MainId
}
for _, v := range orders {
if v.OrderType == 1 {
//亏损大于0 重新计算比例
if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
//手动设置百分比
if manualTakeRatio.Cmp(decimal.Zero) > 0 {
v.Rate = manualTakeRatio.String()
percentag := manualTakeRatio.Div(decimal.NewFromInt(100))
if positionData.PositionSide == "LONG" {
v.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
} else {
v.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
}
} else if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100))
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
v.Rate = percentag.String()
@ -182,9 +211,32 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
processFutTakeProfitOrder(db, futApi, v, totalNum)
} else if v.OrderType == 2 {
if manualStopRatio.Cmp(decimal.Zero) > 0 {
v.Rate = manualStopRatio.String()
percentag := manualStopRatio.Div(decimal.NewFromInt(100))
if positionData.PositionSide == "LONG" {
v.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
} else {
v.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
}
}
processFutStopLossOrder(db, v, utility.StrToDecimal(v.Price), totalNum)
}
}
return false
}
// 处理下一个待触发
func HandleNextFuturesReduce(db *gorm.DB, apiUserInfo DbModels.LineApiUser, preOrdedr DbModels.LinePreOrder, tradeSet models2.TradeSet) {
mainId := preOrdedr.Id
if preOrdedr.MainId > 0 {
mainId = preOrdedr.MainId
}
totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, &preOrdedr, tradeSet)
nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet)
}
@ -307,7 +359,7 @@ func handleClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
if apiUserInfo.Id > 0 {
mainIds := []int{preOrder.MainId}
if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
if err := CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
logger.Errorf("平仓单成功 取消其它订单失败 订单号:%s:", err)
}
}
@ -328,7 +380,7 @@ func handleStopLoss(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
if apiUserInfo.Id > 0 {
mainIds := []int{preOrder.MainId}
if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
if err := CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err)
}
}
@ -356,7 +408,7 @@ func handleTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
if apiUserInfo.Id > 0 {
mainIds := []int{preOrder.MainId}
if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
if err := CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil {
logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err)
}
}
@ -508,7 +560,7 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrd
switch order.OrderType {
case 1: // 止盈
//亏损大于0 重新计算比例
if first && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 {
if first && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 && preOrder.SignPriceType != "mixture" {
percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100))
percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2)
order.Rate = percentag.String()
@ -591,14 +643,14 @@ func cancelPositionOtherOrders(apiUserInfo DbModels.LineApiUser, db *gorm.DB, pr
// 批量取消订单
err = cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, changeMainOrderStatus)
err = CancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, changeMainOrderStatus)
return err
}
// 根据mainid 取消订单
// @changeMainOrderStatus 是否更新主单状态
func cancelMainOrders(mainIds []int, db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, changeMainOrderStatus bool) error {
func CancelMainOrders(mainIds []int, db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, changeMainOrderStatus bool) error {
if len(mainIds) > 0 {
orderSns, err := GetOpenOrderSns(db, mainIds)
if err != nil {