2025-04-03 18:32:23 +08:00
|
|
|
package binanceservice
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"go-admin/app/admin/models"
|
|
|
|
|
"go-admin/app/admin/service/dto"
|
|
|
|
|
"go-admin/common/const/rediskey"
|
|
|
|
|
"go-admin/common/global"
|
|
|
|
|
"go-admin/common/helper"
|
|
|
|
|
models2 "go-admin/models"
|
2025-04-07 18:36:36 +08:00
|
|
|
"go-admin/pkg/utility"
|
2025-04-03 18:32:23 +08:00
|
|
|
|
|
|
|
|
"github.com/bytedance/sonic"
|
|
|
|
|
"github.com/go-admin-team/go-admin-core/logger"
|
|
|
|
|
"github.com/shopspring/decimal"
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 缓存减仓节点和重新生成
|
|
|
|
|
// reduceOrder:原始减仓单
|
|
|
|
|
// reduceOrderStrategy:减仓策略
|
|
|
|
|
func CacheOrderStrategyAndReCreate(db *gorm.DB, reduceOrder ReduceListItem, symbolType int, tradeSet models2.TradeSet, setting models.LineSystemSetting) error {
|
2025-04-07 18:36:36 +08:00
|
|
|
reduceOrderStrategy := models.LineOrderReduceStrategy{}
|
2025-04-03 18:32:23 +08:00
|
|
|
var key string
|
|
|
|
|
|
|
|
|
|
if symbolType == 1 {
|
|
|
|
|
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
|
|
|
|
} else {
|
|
|
|
|
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 18:36:36 +08:00
|
|
|
if err := db.Model(&reduceOrderStrategy).Where("order_id =?", reduceOrder.Id).Find(&reduceOrderStrategy).Error; err != nil {
|
2025-04-03 18:32:23 +08:00
|
|
|
logger.Errorf("获取减仓策略失败,err:%v", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if reduceOrderStrategy.Id > 0 {
|
2025-04-07 18:36:36 +08:00
|
|
|
items := make([]models.LineReduceStrategyItem, 0)
|
2025-04-03 18:32:23 +08:00
|
|
|
strategyCache := dto.LineOrderReduceStrategyResp{
|
|
|
|
|
OrderId: reduceOrder.Id,
|
2025-04-07 18:36:36 +08:00
|
|
|
Symbol: reduceOrder.Symbol,
|
|
|
|
|
MainId: reduceOrder.MainId,
|
|
|
|
|
Side: reduceOrder.Side,
|
2025-04-03 18:32:23 +08:00
|
|
|
}
|
|
|
|
|
|
2025-04-07 18:36:36 +08:00
|
|
|
sonic.Unmarshal([]byte(reduceOrderStrategy.ItemContent), &items)
|
|
|
|
|
|
|
|
|
|
for _, item := range items {
|
2025-04-03 18:32:23 +08:00
|
|
|
var rate decimal.Decimal
|
|
|
|
|
var triggerRate decimal.Decimal
|
|
|
|
|
|
2025-04-07 18:36:36 +08:00
|
|
|
if reduceOrder.Side == "SELL" {
|
2025-04-03 18:32:23 +08:00
|
|
|
rate = (decimal.NewFromInt(100).Sub(item.LossPercent)).Div(decimal.NewFromInt(100))
|
|
|
|
|
|
|
|
|
|
if setting.ReduceEarlyTriggerPercent.Cmp(decimal.Zero) > 0 {
|
|
|
|
|
triggerRate = rate.Add(setting.ReduceEarlyTriggerPercent.Div(decimal.NewFromInt(100)))
|
|
|
|
|
} else {
|
|
|
|
|
triggerRate = rate
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
rate = (decimal.NewFromInt(100).Add(item.LossPercent)).Div(decimal.NewFromInt(100))
|
|
|
|
|
|
|
|
|
|
if setting.ReduceEarlyTriggerPercent.Cmp(decimal.Zero) > 0 {
|
|
|
|
|
triggerRate = rate.Sub(setting.ReduceEarlyTriggerPercent.Div(decimal.NewFromInt(100)))
|
|
|
|
|
} else {
|
|
|
|
|
triggerRate = rate
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
price := reduceOrder.Price.Mul(rate).Truncate(int32(tradeSet.PriceDigit))
|
|
|
|
|
triggerPrice := reduceOrder.Price.Mul(triggerRate).Truncate(int32(tradeSet.PriceDigit))
|
2025-04-07 18:36:36 +08:00
|
|
|
num := reduceOrder.Num
|
|
|
|
|
|
|
|
|
|
//百分比大于0就重新计算 否则就是主减仓单数量
|
|
|
|
|
if item.QuantityPercent.Cmp(decimal.Zero) > 0 {
|
|
|
|
|
num = reduceOrder.Num.Mul(item.QuantityPercent.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit))
|
|
|
|
|
}
|
2025-04-03 18:32:23 +08:00
|
|
|
|
|
|
|
|
strategyCache.Items = append(strategyCache.Items, dto.LineOrderReduceStrategyRespItem{
|
|
|
|
|
LossPercent: item.LossPercent,
|
|
|
|
|
OrderType: item.OrderType,
|
|
|
|
|
Price: price,
|
|
|
|
|
TriggerPrice: triggerPrice,
|
2025-04-07 18:36:36 +08:00
|
|
|
Num: num,
|
2025-04-03 18:32:23 +08:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-07 18:36:36 +08:00
|
|
|
str, _ := sonic.MarshalString(strategyCache)
|
2025-04-03 18:32:23 +08:00
|
|
|
|
|
|
|
|
if str != "" {
|
2025-04-07 18:36:36 +08:00
|
|
|
if err := helper.DefaultRedis.HSetField(key, utility.IntToString(reduceOrder.Id), str); err != nil {
|
2025-04-03 18:32:23 +08:00
|
|
|
logger.Errorf("减仓单缓存减仓策略,err:%v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据订单id获取订单减仓策略
|
|
|
|
|
func GetReduceStrategyById(db *gorm.DB, orderId int) (models.LineOrderReduceStrategy, error) {
|
|
|
|
|
result := models.LineOrderReduceStrategy{}
|
|
|
|
|
|
|
|
|
|
if err := db.Model(result).Where("order_id =?", orderId).Select("id", "order_id").First(&result).Error; err != nil {
|
|
|
|
|
return result, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 减仓单成功回调
|
|
|
|
|
func ReduceCallBack(db *gorm.DB, preOrder *models.LinePreOrder) error {
|
|
|
|
|
reduceOrderId := preOrder.Id
|
|
|
|
|
var key string
|
|
|
|
|
if preOrder.ReduceOrderId > 0 {
|
|
|
|
|
reduceOrderId = preOrder.ReduceOrderId
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch preOrder.SymbolType {
|
|
|
|
|
case 1:
|
|
|
|
|
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
|
|
|
|
case 2:
|
|
|
|
|
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
|
|
|
|
default:
|
|
|
|
|
return fmt.Errorf("交易对类型错误")
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:09:25 +08:00
|
|
|
arrays, _ := helper.DefaultRedis.HGetAllFields(key)
|
2025-04-03 18:32:23 +08:00
|
|
|
cache := dto.LineOrderReduceStrategyResp{}
|
|
|
|
|
|
|
|
|
|
for _, v := range arrays {
|
|
|
|
|
sonic.Unmarshal([]byte(v), &cache)
|
|
|
|
|
|
|
|
|
|
if cache.OrderId == reduceOrderId {
|
2025-04-09 09:09:25 +08:00
|
|
|
if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil {
|
2025-04-03 18:32:23 +08:00
|
|
|
logger.Errorf("移除减仓单减仓策略失败redis err:%v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orderReduceStrategy, _ := GetReduceStrategyById(db, reduceOrderId)
|
|
|
|
|
if orderReduceStrategy.Id > 0 {
|
|
|
|
|
if err := db.Model(&orderReduceStrategy).Update("actived", 1).Error; err != nil {
|
|
|
|
|
logger.Errorf("更新减仓单减仓策略状态失败 order_id:%d err:%v", orderReduceStrategy.OrderId, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2025-04-07 18:36:36 +08:00
|
|
|
|
|
|
|
|
// 移除减仓后减仓策略
|
|
|
|
|
// mainId 主单id
|
|
|
|
|
// symbolType 交易对类型
|
|
|
|
|
func RemoveReduceReduceCacheByMainId(mainId int, symbolType int) error {
|
|
|
|
|
var key string
|
|
|
|
|
switch symbolType {
|
|
|
|
|
case 1:
|
|
|
|
|
key = fmt.Sprintf(rediskey.SpotOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
|
|
|
|
case 2:
|
|
|
|
|
key = fmt.Sprintf(rediskey.FutOrderReduceStrategyList, global.EXCHANGE_BINANCE)
|
|
|
|
|
default:
|
|
|
|
|
return fmt.Errorf("交易对类型错误")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arrays, _ := helper.DefaultRedis.HGetAllFields(key)
|
|
|
|
|
cache := dto.LineOrderReduceStrategyResp{}
|
|
|
|
|
|
|
|
|
|
for _, v := range arrays {
|
|
|
|
|
sonic.Unmarshal([]byte(v), &cache)
|
|
|
|
|
|
|
|
|
|
if cache.MainId == mainId {
|
|
|
|
|
if err := helper.DefaultRedis.HDelField(key, utility.IntToString(cache.OrderId)); err != nil {
|
|
|
|
|
logger.Errorf("移除减仓单减仓策略失败redis err:%v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|