From 79af1ab2c185aaf14d7de201be0c15cd5d1b2208 Mon Sep 17 00:00:00 2001 From: hucan <951870319@qq.com> Date: Sat, 12 Apr 2025 18:32:36 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E7=A7=BB=E9=99=A4=E7=AD=96=E7=95=A5u?= =?UTF-8?q?=E4=B8=8B=E5=8D=95=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/service/line_pre_order.go | 1 + app/jobs/examples.go | 1 + app/jobs/strategy_job.go | 25 ++++++++ config/serverinit/business_init.go | 25 ++++++++ services/binanceservice/commonservice.go | 26 ++++++++ .../binanceservice/strategy_order_service.go | 62 +++++++++++++++++-- 6 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 app/jobs/strategy_job.go diff --git a/app/admin/service/line_pre_order.go b/app/admin/service/line_pre_order.go index 4a64b7b..e4ca38c 100644 --- a/app/admin/service/line_pre_order.go +++ b/app/admin/service/line_pre_order.go @@ -363,6 +363,7 @@ func (e *LinePreOrder) Remove(d *dto.LinePreOrderDeleteReq, p *actions.DataPermi } binanceservice.MainClosePositionClearCache(order.Id, order.SymbolType) + binanceservice.RemoveReduceReduceCacheByMainId(order.Id, order.SymbolType) ints = append(ints, order.Id) } diff --git a/app/jobs/examples.go b/app/jobs/examples.go index a5a9406..a2a78b3 100644 --- a/app/jobs/examples.go +++ b/app/jobs/examples.go @@ -38,6 +38,7 @@ func InitJob() { "MemberExpirationJob": MemberExpirationJob{}, //会员到期处理 "MemberRenwalOrderExpirationJob": MemberRenwalOrderExpirationJob{}, //会员续费订单过期处理 "TrxQueryJobs": TrxQueryJobs{}, //订单支付监听 + "StrategyJob": StrategyJob{}, //下单策略触发 } } diff --git a/app/jobs/strategy_job.go b/app/jobs/strategy_job.go new file mode 100644 index 0000000..3d2d54c --- /dev/null +++ b/app/jobs/strategy_job.go @@ -0,0 +1,25 @@ +package jobs + +import ( + "go-admin/common/global" + "go-admin/services/binanceservice" + + "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" +) + +type StrategyJob struct { +} + +// 策略下单任务 +func (j StrategyJob) Exec(arg interface{}) error { + strategyService := binanceservice.BinanceStrategyOrderService{} + db := getDefaultDb() + strategyService.Orm = db + strategyService.Log = logger.NewHelper(sdk.Runtime.GetLogger()).WithFields(map[string]interface{}{}) + + //触发币安策略下单 + strategyService.TriggerStrategyOrder(global.EXCHANGE_BINANCE) + + return nil +} diff --git a/config/serverinit/business_init.go b/config/serverinit/business_init.go index c48c5fe..95a0518 100644 --- a/config/serverinit/business_init.go +++ b/config/serverinit/business_init.go @@ -13,6 +13,7 @@ import ( "go-admin/services/futureservice" "go-admin/services/scriptservice" "os" + "time" "github.com/bytedance/sonic" "github.com/go-admin-team/go-admin-core/logger" @@ -37,6 +38,9 @@ func BusinessInit(db *gorm.DB) { symbolPriceService.Log = logger.NewHelper(sdk.Runtime.GetLogger()).WithFields(map[string]interface{}{}) symbolPriceService.InitCache() + //清理交易对缓存价格 + clearSymbolPrice() + //初始化订单配置 cacheservice.ResetSystemSetting(db) lineApiUser := service.LineApiUser{} @@ -145,3 +149,24 @@ func loadApiUser(db *gorm.DB) error { return nil } + +// 清理交易对价格缓存 +func clearSymbolPrice() error { + spotAll, _ := helper.DefaultRedis.ScanKeys("spot_ticker_last_price:*") + futAllKey, _ := helper.DefaultRedis.ScanKeys("fut_ticker_last_price:*") + beforeTimeUtc := time.Now().UnixMilli() + + for _, item := range spotAll { + if _, err := helper.DefaultRedis.RemoveBeforeScore(item, float64(beforeTimeUtc)); err != nil { + logger.Error("现货 清理交易对价格缓存失败:", err) + } + } + + for _, item := range futAllKey { + if _, err := helper.DefaultRedis.RemoveBeforeScore(item, float64(beforeTimeUtc)); err != nil { + logger.Error("合约 清理交易对价格缓存失败:", err) + } + } + + return nil +} diff --git a/services/binanceservice/commonservice.go b/services/binanceservice/commonservice.go index fa6fca1..3937550 100644 --- a/services/binanceservice/commonservice.go +++ b/services/binanceservice/commonservice.go @@ -251,11 +251,15 @@ func (e *AddPosition) CalculateAmount(req dto.ManuallyCover, totalNum, lastPrice // mainOrderId 主单id // symbolType 1现货 2合约 func MainClosePositionClearCache(mainId int, symbolType int) { + strategyDto := dto.StrategyOrderRedisList{} + if symbolType == 1 { keySpotStop := fmt.Sprintf(rediskey.SpotStopLossList, global.EXCHANGE_BINANCE) keySpotAddposition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) spotStopArray, _ := helper.DefaultRedis.GetAllList(keySpotStop) spotAddpositionArray, _ := helper.DefaultRedis.GetAllList(keySpotAddposition) + spotStrategyKey := fmt.Sprintf(rediskey.StrategySpotOrderList, global.EXCHANGE_BINANCE) + spotStrategyList, _ := helper.DefaultRedis.GetAllList(spotStrategyKey) var position AddPositionList var stop dto.StopLossRedisList @@ -279,11 +283,23 @@ func MainClosePositionClearCache(mainId int, symbolType int) { } } + for _, item := range spotStrategyList { + sonic.Unmarshal([]byte(item), &strategyDto) + + if strategyDto.Id == mainId { + if _, err := helper.DefaultRedis.LRem(spotStrategyKey, item); err != nil { + logger.Errorf("id:%d 移除缓存失败,err:%v", mainId, err) + } + } + } } else { keyFutStop := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) keyFutAddposition := fmt.Sprintf(rediskey.FuturesStopLossList, global.EXCHANGE_BINANCE) futAddpositionArray, _ := helper.DefaultRedis.GetAllList(keyFutStop) futStopArray, _ := helper.DefaultRedis.GetAllList(keyFutAddposition) + + futStrategyKey := fmt.Sprintf(rediskey.StrategyFutOrderList, global.EXCHANGE_BINANCE) + futStrategyList, _ := helper.DefaultRedis.GetAllList(futStrategyKey) var position AddPositionList var stop dto.StopLossRedisList @@ -306,6 +322,16 @@ func MainClosePositionClearCache(mainId int, symbolType int) { helper.DefaultRedis.LRem(keyFutStop, item) } } + + for _, item := range futStrategyList { + sonic.Unmarshal([]byte(item), &strategyDto) + + if strategyDto.Id == mainId { + if _, err := helper.DefaultRedis.LRem(futStrategyKey, item); err != nil { + logger.Errorf("id:%d 移除缓存失败,err:%v", mainId, err) + } + } + } } } diff --git a/services/binanceservice/strategy_order_service.go b/services/binanceservice/strategy_order_service.go index 158b683..7b61bdc 100644 --- a/services/binanceservice/strategy_order_service.go +++ b/services/binanceservice/strategy_order_service.go @@ -19,6 +19,7 @@ import ( "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/service" "github.com/shopspring/decimal" + "gorm.io/gorm" ) type BinanceStrategyOrderService struct { @@ -36,8 +37,10 @@ func (e *BinanceStrategyOrderService) TriggerStrategyOrder(exchangeType string) e.DoJudge(futOrdedrStrs, 2, exchangeType) } -// 处理订单 +// 判断是否符合条件 func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int, exchangeType string) { + db := GetDBConnection() + for _, orderStr := range orderStrs { var lockKey string orderItem := dto.StrategyOrderRedisList{} @@ -69,7 +72,7 @@ func (e *BinanceStrategyOrderService) DoJudge(orderStrs []string, symbolType int } if success { - e.TriggerOrder(orderItem, symbolType) + e.TriggerOrder(db, orderStr, orderItem, symbolType) } } } @@ -118,7 +121,7 @@ func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedis } percentag := lastPrice.Div(startPrice).Sub(decimal.NewFromInt(1)).Truncate(6) - + fmt.Printf("百分比:%s", percentag.Mul(decimal.NewFromInt(100)).String()) //价格没有变动 if percentag.Cmp(decimal.Zero) == 0 { return result, nil @@ -140,7 +143,7 @@ func (e *BinanceStrategyOrderService) JudgeStrategy(order dto.StrategyOrderRedis } // 触发委托单 -func (e *BinanceStrategyOrderService) TriggerOrder(order dto.StrategyOrderRedisList, symbolType int) error { +func (e *BinanceStrategyOrderService) TriggerOrder(db *gorm.DB, cacheVal string, order dto.StrategyOrderRedisList, symbolType int) error { orders := make([]models.LinePreOrder, 0) if err := e.Orm.Model(&models.LinePreOrder{}).Where("main_id =?", order.Id).Find(&orders).Error; err != nil { e.Log.Errorf("order_id:%d 获取委托单失败:%s", order.Id, err.Error()) @@ -180,18 +183,67 @@ func (e *BinanceStrategyOrderService) TriggerOrder(order dto.StrategyOrderRedisL if err := e.Orm.Save(&mainOrder).Error; err != nil { e.Log.Errorf("order_id:%d 波段触发保存委托单失败:%s", mainOrder.Id, err.Error()) + return err } + e.StrategyOrderPlace(db, cacheVal, mainOrder, tradeSet) + return nil } +// 策略触发订单 +// cacheVal:缓存值 +// mainOrder:主订单 +// tradeSet:交易对行情 +func (e *BinanceStrategyOrderService) StrategyOrderPlace(db *gorm.DB, cacheVal string, mainOrder models.LinePreOrder, tradeSet models2.TradeSet) { + price := utility.StringToDecimal(mainOrder.Price).Truncate(int32(tradeSet.PriceDigit)) + num := utility.StringToDecimal(mainOrder.Num).Truncate(int32(tradeSet.AmountDigit)) + futApi := FutRestApi{} + var key string + + switch mainOrder.SymbolType { + case 1: + key = fmt.Sprintf(rediskey.StrategySpotOrderList, global.EXCHANGE_BINANCE) + case 2: + key = fmt.Sprintf(rediskey.StrategyFutOrderList, global.EXCHANGE_BINANCE) + default: + logger.Errorf("id:%d 交易对类型不存在:%d", mainOrder.Id, mainOrder.SymbolType) + return + } + + params := FutOrderPlace{ + ApiId: mainOrder.ApiId, + Symbol: mainOrder.Symbol, + Side: mainOrder.Site, + OrderType: mainOrder.MainOrderType, + SideType: mainOrder.MainOrderType, + Price: price, + Quantity: num, + NewClientOrderId: mainOrder.OrderSn, + } + + if err := futApi.OrderPlaceLoop(db, params, 3); err != nil { + logger.Error("下单失败", mainOrder.Symbol, " err:", err) + err := db.Model(&models.LinePreOrder{}).Where("id =? and status='0'", mainOrder.Id).Updates(map[string]interface{}{"status": "2", "desc": err.Error()}).Error + + if err != nil { + logger.Error("更新预下单状态失败") + } + + if _, err := helper.DefaultRedis.LRem(key, cacheVal); err != nil { + logger.Error("删除redis 预下单失败:", err) + } + return + } +} + // 重新计算订单单价、数量 // tradeSet 交易对行情 // mainOrder 主订单 // setting 系统设置 func (e *BinanceStrategyOrderService) RecalculateOrder(tradeSet models2.TradeSet, mainOrder *models.LinePreOrder, setting models.LineSystemSetting) error { exts := make([]models.LinePreOrderExt, 0) - if err := e.Orm.Model(models.LinePreOrderExt{}).Where("main_id =?", mainOrder.Id).Find(&exts).Error; err != nil { + if err := e.Orm.Model(models.LinePreOrderExt{}).Where("main_order_id =?", mainOrder.Id).Find(&exts).Error; err != nil { return errors.New("获取拓展信息失败") }