拆分加仓、减仓

This commit is contained in:
2025-03-07 16:48:55 +08:00
parent 126193df36
commit 0aa2ab7355
4 changed files with 303 additions and 89 deletions

View File

@ -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)
}
// 处理主单加仓

View File

@ -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)
}
// 根据下单百分比计算价格