2025-02-11 14:49:16 +08:00
package binanceservice
import (
"context"
"errors"
"fmt"
DbModels "go-admin/app/admin/models"
"go-admin/app/admin/service/dto"
"go-admin/common/const/rediskey"
"go-admin/common/global"
"go-admin/common/helper"
"go-admin/models"
2025-10-14 19:58:59 +08:00
"go-admin/models/positiondto"
2025-04-07 18:36:36 +08:00
"go-admin/pkg/utility"
2025-04-03 18:32:23 +08:00
"go-admin/services/cacheservice"
2025-10-14 19:58:59 +08:00
"go-admin/services/commonservice"
"go-admin/services/orderservice"
2025-02-11 14:49:16 +08:00
"strings"
"time"
"github.com/bytedance/sonic"
2025-11-05 16:26:21 +08:00
"github.com/go-admin-team/go-admin-core/logger"
2025-02-11 14:49:16 +08:00
log "github.com/go-admin-team/go-admin-core/logger"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
/ *
判断合约触发
* /
func JudgeFuturesPrice ( tradeSet models . TradeSet ) {
preOrderVal , _ := helper . DefaultRedis . GetAllList ( fmt . Sprintf ( rediskey . PreFutOrderList , global . EXCHANGE_BINANCE ) )
2025-10-14 19:58:59 +08:00
db := commonservice . GetDBConnection ( )
2025-02-11 14:49:16 +08:00
if len ( preOrderVal ) == 0 {
return
}
futApi := FutRestApi { }
2025-11-05 16:26:21 +08:00
orderService := orderservice . OrderService { }
orderService . Orm = db
2025-02-11 14:49:16 +08:00
for _ , item := range preOrderVal {
preOrder := dto . PreOrderRedisList { }
if err := sonic . Unmarshal ( [ ] byte ( item ) , & preOrder ) ; err != nil {
log . Error ( "反序列化失败" )
continue
}
if preOrder . Symbol != tradeSet . Coin + tradeSet . Currency {
continue
}
orderPrice , _ := decimal . NewFromString ( preOrder . Price )
tradePrice , _ := decimal . NewFromString ( tradeSet . LastPrice )
if orderPrice . Cmp ( decimal . Zero ) == 0 || tradePrice . Cmp ( decimal . Zero ) == 0 {
continue
}
//多
if ( strings . ToUpper ( preOrder . Site ) == "BUY" && orderPrice . Cmp ( tradePrice ) >= 0 ) ||
( strings . ToUpper ( preOrder . Site ) == "SELL" && orderPrice . Cmp ( tradePrice ) <= 0 ) {
2025-11-05 16:26:21 +08:00
apiInfo , _ := GetApiInfo ( preOrder . ApiId )
if err := commonservice . JudgeWebsocketTimeout ( apiInfo . ApiKey , 2 ) ; err != nil {
log . Errorf ( "合约行情订阅超时,apiKey:%s err:%v" , apiInfo . ApiKey , err )
if err1 := orderService . ErrorTrigger ( preOrder . Id , 2 ,
global . EXCHANGE_BINANCE , item ,
fmt . Sprintf ( "行情触发失败,err:%v" , err ) ) ; err1 != nil {
log . Error ( "触发失败" , err1 )
}
continue
} else {
futTriggerOrder ( db , & preOrder , item , futApi )
}
2025-02-11 14:49:16 +08:00
}
}
}
2025-11-05 16:26:21 +08:00
// 分布式锁下单(合约预设主单触发)
// 参数说明:
// - db: 数据库连接,用于查询与更新预下单状态
// - v: 预下单信息(包含价格、数量、订单号等)
// - item: 从 Redis 列表读取的原始字符串,用于幂等删除
// - futApi: 合约下单 API 封装
// 逻辑:在 FutTrigger 锁下校验订单有效性,执行下单并更新状态,最后用原始 item 删除缓存,避免序列化差异导致删除失败。
2025-02-11 14:49:16 +08:00
func futTriggerOrder ( db * gorm . DB , v * dto . PreOrderRedisList , item string , futApi FutRestApi ) {
2025-11-05 16:26:21 +08:00
lock := helper . NewRedisLock ( fmt . Sprintf ( rediskey . FutTrigger , v . ApiId , v . Symbol ) , 200 , 5 , 100 * time . Millisecond )
2025-02-11 14:49:16 +08:00
if ok , err := lock . AcquireWait ( context . Background ( ) ) ; err != nil {
log . Debug ( "获取锁失败" , err )
return
} else if ok {
defer lock . Release ( )
key := fmt . Sprintf ( rediskey . PreFutOrderList , global . EXCHANGE_BINANCE )
preOrder := DbModels . LinePreOrder { }
if err := db . Where ( "id = ?" , v . Id ) . First ( & preOrder ) . Error ; err != nil {
log . Error ( "获取预下单失败" , err )
if errors . Is ( err , gorm . ErrRecordNotFound ) {
log . Error ( "不存在待触发主单" , item )
helper . DefaultRedis . LRem ( key , item )
}
return
}
hasrecord , _ := helper . DefaultRedis . IsElementInList ( key , item )
if ! hasrecord {
log . Debug ( "预下单缓存中不存在" , item )
return
}
price , _ := decimal . NewFromString ( v . Price )
num , _ := decimal . NewFromString ( preOrder . Num )
if price . Cmp ( decimal . Zero ) == 0 {
log . Error ( "价格不能为0" )
return
}
params := FutOrderPlace {
ApiId : v . ApiId ,
Symbol : v . Symbol ,
Side : v . Site ,
OrderType : preOrder . MainOrderType ,
SideType : preOrder . MainOrderType ,
Price : price ,
Quantity : num ,
NewClientOrderId : v . OrderSn ,
}
2025-02-14 09:43:49 +08:00
if err := futApi . OrderPlaceLoop ( db , params , 3 ) ; err != nil {
2025-02-11 14:49:16 +08:00
log . Error ( "下单失败" , v . Symbol , " err:" , err )
2025-11-05 16:26:21 +08:00
err = db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? and status='0'" , preOrder . Id ) . Updates ( map [ string ] interface { } { "status" : "2" , "desc" : err . Error ( ) } ) . Error
2025-02-11 14:49:16 +08:00
if err != nil {
log . Error ( "更新预下单状态失败" )
}
2025-11-05 16:26:21 +08:00
if _ , err := helper . DefaultRedis . LRem ( key , item ) ; err != nil {
log . Error ( "删除redis 预下单失败:" , err )
2025-02-11 14:49:16 +08:00
}
return
}
2025-11-05 16:26:21 +08:00
if _ , err := helper . DefaultRedis . LRem ( key , item ) ; err != nil {
log . Error ( "删除redis 预下单失败:" , err )
2025-02-11 14:49:16 +08:00
}
2025-02-22 11:24:08 +08:00
if err := db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? " , preOrder . Id ) . Updates ( map [ string ] interface { } { "trigger_time" : time . Now ( ) } ) . Error ; err != nil {
log . Error ( "更新预下单状态失败 ordersn:" , preOrder . OrderSn , " status:1" )
}
if err := db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? AND status ='0'" , preOrder . Id ) . Updates ( map [ string ] interface { } { "status" : "1" } ) . Error ; err != nil {
2025-02-11 14:49:16 +08:00
log . Error ( "更新预下单状态失败 ordersn:" , v . OrderSn , " status:1" )
}
return
} else {
log . Error ( "获取锁失败" )
return
}
}
// 判断是否触发合约减仓
func JudgeFuturesReduce ( trade models . TradeSet ) {
key := fmt . Sprintf ( rediskey . FuturesReduceList , global . EXCHANGE_BINANCE )
reduceVal , _ := helper . DefaultRedis . GetAllList ( key )
2025-10-14 19:58:59 +08:00
db := commonservice . GetDBConnection ( )
2025-02-11 18:03:30 +08:00
futApi := FutRestApi { }
2025-04-03 18:32:23 +08:00
setting , err := cacheservice . GetSystemSetting ( db )
2025-02-11 14:49:16 +08:00
if err != nil {
log . Error ( "获取系统设置失败" )
return
}
2025-10-14 19:58:59 +08:00
reduceOrder := positiondto . ReduceListItem { }
2025-04-03 18:32:23 +08:00
tradePrice , _ := decimal . NewFromString ( trade . LastPrice )
//减仓单减仓策略
2025-04-07 18:36:36 +08:00
reduceReduceListKey := fmt . Sprintf ( rediskey . FutOrderReduceStrategyList , global . EXCHANGE_BINANCE )
orderReduceVal , _ := helper . DefaultRedis . HGetAllFields ( reduceReduceListKey )
2025-04-03 18:32:23 +08:00
reduceOrderStrategy := dto . LineOrderReduceStrategyResp { }
2025-10-14 19:58:59 +08:00
orderService := orderservice . OrderService { }
orderService . Orm = db
2025-04-03 18:32:23 +08:00
for _ , item := range orderReduceVal {
sonic . Unmarshal ( [ ] byte ( item ) , & reduceOrderStrategy )
2025-04-07 18:36:36 +08:00
for index , item2 := range reduceOrderStrategy . Items {
if reduceOrderStrategy . Symbol == trade . Coin + trade . Currency && ! item2 . Actived {
2025-04-03 18:32:23 +08:00
//买入
if item2 . TriggerPrice . Cmp ( decimal . Zero ) > 0 &&
tradePrice . Cmp ( decimal . Zero ) > 0 &&
( ( strings . ToUpper ( reduceOrderStrategy . Side ) == "SELL" && item2 . TriggerPrice . Cmp ( tradePrice ) >= 0 ) ||
( strings . ToUpper ( reduceOrderStrategy . Side ) == "BUY" && item2 . TriggerPrice . Cmp ( tradePrice ) <= 0 ) ) {
2025-04-07 18:36:36 +08:00
lock := helper . NewRedisLock ( fmt . Sprintf ( rediskey . ReduceStrategyFutTriggerLock , reduceOrder . ApiId , reduceOrder . Symbol ) , 50 , 15 , 100 * time . Millisecond )
if ok , err := lock . AcquireWait ( context . Background ( ) ) ; err != nil {
log . Error ( "获取锁失败" , err )
return
} else if ok {
defer lock . Release ( )
2025-04-09 09:09:25 +08:00
hasrecord , _ := helper . DefaultRedis . HExists ( reduceReduceListKey , utility . IntToString ( reduceOrderStrategy . OrderId ) , item )
2025-04-07 18:36:36 +08:00
if ! hasrecord {
log . Debug ( "减仓缓存中不存在" , item )
return
}
2025-10-14 19:58:59 +08:00
order , err := orderService . CreateReduceReduceOrder ( db , reduceOrderStrategy . OrderId , item2 . Price , item2 . Num , trade . PriceDigit )
2025-04-07 18:36:36 +08:00
if err != nil {
log . Errorf ( "%d 生成订单失败" , reduceOrderStrategy . OrderId )
}
reduceOrder . ApiId = order . ApiId
reduceOrder . Id = order . Id
reduceOrder . Pid = order . Pid
reduceOrder . MainId = order . MainId
reduceOrder . Symbol = order . Symbol
reduceOrder . Side = reduceOrderStrategy . Side
reduceOrder . OrderSn = order . OrderSn
reduceOrder . Price = item2 . Price
reduceOrder . Num = item2 . Num
//下单成功修改策略节点状态
2025-04-09 09:09:25 +08:00
if FuturesReduceTrigger ( db , reduceOrder , futApi , setting , reduceReduceListKey , item , true , reduceOrderStrategy . OrderId ) {
2025-04-07 18:36:36 +08:00
reduceOrderStrategy . Items [ index ] . Actived = true
allActive := true
orderId := utility . IntToString ( reduceOrderStrategy . OrderId )
for _ , item3 := range reduceOrderStrategy . Items {
if ! item3 . Actived {
allActive = false
break
}
}
if allActive {
if err := helper . DefaultRedis . HDelField ( reduceReduceListKey , orderId ) ; err != nil {
log . Errorf ( "删除redis reduceReduceListKey失败 %s" , err . Error ( ) )
}
} else {
str , _ := sonic . MarshalString ( reduceOrderStrategy )
if err := helper . DefaultRedis . HSetField ( reduceReduceListKey , orderId , str ) ; err != nil {
log . Errorf ( "更新redis reduceReduceListKey失败 %s" , err . Error ( ) )
}
}
}
}
2025-04-03 18:32:23 +08:00
}
}
}
}
2025-02-11 14:49:16 +08:00
for _ , item := range reduceVal {
if err := sonic . Unmarshal ( [ ] byte ( item ) , & reduceOrder ) ; err != nil {
log . Error ( "反序列化失败" )
continue
}
if reduceOrder . Symbol == trade . Coin + trade . Currency {
orderPrice := reduceOrder . Price
//买入
if orderPrice . Cmp ( decimal . Zero ) > 0 &&
tradePrice . Cmp ( decimal . Zero ) > 0 &&
( ( strings . ToUpper ( reduceOrder . Side ) == "SELL" && orderPrice . Cmp ( tradePrice ) >= 0 ) ||
( strings . ToUpper ( reduceOrder . Side ) == "BUY" && orderPrice . Cmp ( tradePrice ) <= 0 ) ) {
2025-04-09 09:09:25 +08:00
FuturesReduceTrigger ( db , reduceOrder , futApi , setting , key , item , false , 0 )
2025-02-11 14:49:16 +08:00
}
}
}
}
// 触发合约减仓
2025-04-07 18:36:36 +08:00
// isStrategy 是否是策略减仓
2025-04-09 09:09:25 +08:00
// reduceId 父减仓单id
2025-10-14 19:58:59 +08:00
func FuturesReduceTrigger ( db * gorm . DB , reduceOrder positiondto . ReduceListItem , futApi FutRestApi , setting DbModels . LineSystemSetting , key , item string , isStrategy bool , reduceId int ) bool {
tradeSet , _ := cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , reduceOrder . Symbol , 2 )
2025-04-07 18:36:36 +08:00
result := true
2025-02-11 18:03:30 +08:00
if tradeSet . LastPrice == "" {
2025-04-07 18:36:36 +08:00
return false
2025-02-11 18:03:30 +08:00
}
2025-02-11 14:49:16 +08:00
lock := helper . NewRedisLock ( fmt . Sprintf ( rediskey . FutTrigger , reduceOrder . ApiId , reduceOrder . Symbol ) , 20 , 5 , 100 * time . Millisecond )
if ok , err := lock . AcquireWait ( context . Background ( ) ) ; err != nil {
log . Error ( "获取锁失败" , err )
2025-04-07 18:36:36 +08:00
return false
2025-02-11 14:49:16 +08:00
} else if ok {
defer lock . Release ( )
2025-03-10 11:13:08 +08:00
takeOrders := make ( [ ] DbModels . LinePreOrder , 0 )
2025-04-07 18:36:36 +08:00
if err := db . Model ( & DbModels . LinePreOrder { } ) . Where ( "main_id =? AND order_type IN (1,2,4) AND status IN (1,5)" , reduceOrder . MainId ) . Find ( & takeOrders ) . Error ; err != nil {
2025-02-11 14:49:16 +08:00
log . Error ( "查询止盈单失败" )
2025-04-07 18:36:36 +08:00
return false
2025-02-11 14:49:16 +08:00
}
2025-04-09 09:09:25 +08:00
var hasrecord bool
if isStrategy {
hasrecord , _ = helper . DefaultRedis . HExists ( key , utility . IntToString ( reduceId ) , item )
} else {
hasrecord , _ = helper . DefaultRedis . IsElementInList ( key , item )
}
2025-02-11 18:03:30 +08:00
if ! hasrecord {
log . Debug ( "减仓缓存中不存在" , item )
2025-04-07 18:36:36 +08:00
return false
2025-02-11 18:03:30 +08:00
}
2025-03-10 11:13:08 +08:00
apiInfo , _ := GetApiInfo ( reduceOrder . ApiId )
2025-02-11 14:49:16 +08:00
if apiInfo . Id == 0 {
2025-11-05 16:26:21 +08:00
log . Error ( "合约减仓 查询api用户不存在" )
2025-04-07 18:36:36 +08:00
return false
2025-02-11 14:49:16 +08:00
}
2025-03-10 11:13:08 +08:00
for _ , takeOrder := range takeOrders {
err := CancelFutOrderByOrderSnLoop ( apiInfo , takeOrder . Symbol , takeOrder . OrderSn )
2025-02-11 14:49:16 +08:00
2025-03-10 11:13:08 +08:00
if err != nil {
2025-04-07 18:36:36 +08:00
log . Error ( "撤单失败" , err )
return false
2025-03-10 11:13:08 +08:00
}
2025-02-11 14:49:16 +08:00
}
2025-02-14 09:43:49 +08:00
2025-02-11 14:49:16 +08:00
price := reduceOrder . Price . Mul ( decimal . NewFromInt ( 1 ) . Sub ( setting . ReducePremium . Div ( decimal . NewFromInt ( 100 ) ) ) ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
2025-02-15 18:38:58 +08:00
num := reduceOrder . Num . Truncate ( int32 ( tradeSet . AmountDigit ) )
2025-02-14 09:43:49 +08:00
var positionSide string
2025-02-11 14:49:16 +08:00
2025-02-14 09:43:49 +08:00
if reduceOrder . Side == "BUY" {
positionSide = "SHORT"
} else {
positionSide = "LONG"
2025-02-11 14:49:16 +08:00
}
2025-02-14 09:43:49 +08:00
if err := futApi . ClosePositionLoop ( reduceOrder . Symbol , reduceOrder . OrderSn , num , reduceOrder . Side , positionSide , apiInfo , "LIMIT" , "0" , price , 3 ) ; err != nil {
2025-04-07 18:36:36 +08:00
result = false
2025-02-11 14:49:16 +08:00
log . Errorf ( "合约减仓挂单失败 id: %s err:%v" , reduceOrder . Id , err )
2025-02-18 15:40:45 +08:00
if err2 := db . Model ( & DbModels . LinePreOrder { } ) .
Where ( "id = ? AND status =0" , reduceOrder . Id ) .
Updates ( map [ string ] interface { } { "status" : 2 , "desc" : err . Error ( ) } ) . Error ; err2 != nil {
log . Errorf ( "合约减仓更新状态失败 id: %s err:%v" , reduceOrder . Id , err2 )
}
2025-02-22 09:51:45 +08:00
} else {
2025-02-22 11:24:08 +08:00
if err := db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? " , reduceOrder . Id ) . Updates ( map [ string ] interface { } { "trigger_time" : time . Now ( ) } ) . Error ; err != nil {
log . Error ( "更新减仓单状态失败 ordersn:" , reduceOrder . OrderSn , " status:1" )
}
2025-02-22 09:51:45 +08:00
if err := db . Model ( & DbModels . LinePreOrder { } ) .
2025-02-22 11:24:08 +08:00
Where ( "id = ? AND status =0" , reduceOrder . Id ) . Updates ( map [ string ] interface { } { "status" : 1 } ) . Error ; err != nil {
2025-02-22 09:51:45 +08:00
log . Errorf ( "合约减仓更新状态失败 id: %s err:%v" , reduceOrder . Id , err )
}
2025-04-03 18:32:23 +08:00
//处理减仓单减仓策略
2025-04-07 18:36:36 +08:00
if err := CacheOrderStrategyAndReCreate ( db , reduceOrder , 2 , tradeSet , setting ) ; err != nil {
log . Errorf ( "合约减仓策略处理失败 id: %s err:%v" , reduceOrder . Id , err )
}
2025-02-11 14:49:16 +08:00
}
2025-04-07 18:36:36 +08:00
if ! isStrategy {
if _ , err := helper . DefaultRedis . LRem ( key , item ) ; err != nil {
log . Errorf ( "合约减仓 删除缓存失败 id:%v err:%v" , reduceOrder . Id , err )
}
2025-02-11 14:49:16 +08:00
}
} else {
log . Error ( "获取锁失败" )
2025-04-07 18:36:36 +08:00
result = false
2025-02-11 14:49:16 +08:00
}
2025-04-07 18:36:36 +08:00
return result
2025-02-11 14:49:16 +08:00
}
2025-02-22 09:51:45 +08:00
// 判断合约加仓
2025-02-11 14:49:16 +08:00
func JudgeFutAddPosition ( trade models . TradeSet ) {
key := fmt . Sprintf ( rediskey . FuturesAddPositionList , global . EXCHANGE_BINANCE )
preOrderVal , _ := helper . DefaultRedis . GetAllList ( key )
2025-10-14 19:58:59 +08:00
db := commonservice . GetDBConnection ( )
2025-02-11 14:49:16 +08:00
if len ( preOrderVal ) == 0 {
return
}
futApi := FutRestApi { }
for _ , item := range preOrderVal {
2025-10-14 19:58:59 +08:00
preOrder := positiondto . AddPositionList { }
2025-02-11 14:49:16 +08:00
if err := sonic . Unmarshal ( [ ] byte ( item ) , & preOrder ) ; err != nil {
log . Error ( "反序列化失败" )
continue
}
if preOrder . Symbol == trade . Coin + trade . Currency {
orderPrice := preOrder . Price
tradePrice , _ := decimal . NewFromString ( trade . LastPrice )
if orderPrice . Cmp ( decimal . Zero ) == 0 || tradePrice . Cmp ( decimal . Zero ) == 0 {
continue
}
//多
if ( strings . ToUpper ( preOrder . Side ) == "BUY" && orderPrice . Cmp ( tradePrice ) >= 0 ) ||
( strings . ToUpper ( preOrder . Side ) == "SELL" && orderPrice . Cmp ( tradePrice ) <= 0 ) {
FutAddPositionTrigger ( db , & preOrder , item , futApi )
}
}
}
}
// 合约加仓触发
2025-11-05 16:26:21 +08:00
// 参数说明:
// - db: 数据库连接
// - v: 加仓触发信息
// - item: Redis 列表原始条目,用于精确删除
// - futApi: 合约下单 API 封装
// 逻辑:在 FutTrigger 锁下校验缓存与订单有效性,按系统加仓溢价调整价格,触发限价下单并删除原始缓存条目。
2025-10-14 19:58:59 +08:00
func FutAddPositionTrigger ( db * gorm . DB , v * positiondto . AddPositionList , item string , futApi FutRestApi ) {
2025-02-11 14:49:16 +08:00
lock := helper . NewRedisLock ( fmt . Sprintf ( rediskey . FutTrigger , v . ApiId , v . Symbol ) , 20 , 5 , 100 * time . Millisecond )
if ok , err := lock . AcquireWait ( context . Background ( ) ) ; err != nil {
log . Error ( "获取锁失败" , err )
return
} else if ok {
defer lock . Release ( )
2025-04-03 18:32:23 +08:00
setting , _ := cacheservice . GetSystemSetting ( db )
2025-10-14 19:58:59 +08:00
tradeSet , _ := cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , v . Symbol , 2 )
2025-02-11 14:49:16 +08:00
if tradeSet . LastPrice == "" {
log . Errorf ( "合约加仓触发 查询交易对失败 交易对:%s ordersn:%s" , v . Symbol , v . OrderSn )
return
}
key := fmt . Sprintf ( rediskey . FuturesAddPositionList , global . EXCHANGE_BINANCE )
preOrder := DbModels . LinePreOrder { }
if err := db . Where ( "id = ?" , v . Id ) . First ( & preOrder ) . Error ; err != nil {
log . Error ( "获取预下单失败" , err )
if errors . Is ( err , gorm . ErrRecordNotFound ) {
log . Error ( "不存在待触发加仓主单" , item )
helper . DefaultRedis . LRem ( key , item )
}
return
}
hasrecord , _ := helper . DefaultRedis . IsElementInList ( key , item )
if ! hasrecord {
log . Error ( "不存在待触发加仓主单" , item )
return
}
2025-02-15 18:38:58 +08:00
price := v . Price . Truncate ( int32 ( tradeSet . PriceDigit ) )
2025-02-11 14:49:16 +08:00
num , _ := decimal . NewFromString ( preOrder . Num )
if setting . AddPositionPremium . Cmp ( decimal . Zero ) > 0 {
price = price . Mul ( decimal . NewFromInt ( 1 ) . Sub ( setting . AddPositionPremium . Div ( decimal . NewFromInt ( 100 ) ) ) ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
}
params := FutOrderPlace {
ApiId : v . ApiId ,
Symbol : v . Symbol ,
Side : v . Side ,
OrderType : "LIMIT" ,
Price : price ,
2025-02-15 18:38:58 +08:00
Quantity : num . Truncate ( int32 ( tradeSet . AmountDigit ) ) ,
2025-02-11 14:49:16 +08:00
NewClientOrderId : v . OrderSn ,
}
2025-02-14 09:43:49 +08:00
if err := futApi . OrderPlaceLoop ( db , params , 3 ) ; err != nil {
2025-02-11 14:49:16 +08:00
log . Error ( "下单失败" , v . Symbol , " err:" , err )
2025-11-05 16:26:21 +08:00
err = db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? AND status =0" , preOrder . Id ) . Updates ( map [ string ] interface { } { "status" : "2" , "desc" : err . Error ( ) } ) . Error
2025-02-11 14:49:16 +08:00
if err != nil {
log . Error ( "下单失败后修改订单失败" )
}
2025-11-05 16:26:21 +08:00
if _ , err := helper . DefaultRedis . LRem ( key , item ) ; err != nil {
log . Error ( "删除redis 预下单失败:" , err )
2025-02-11 14:49:16 +08:00
}
return
}
2025-11-05 16:26:21 +08:00
if _ , err := helper . DefaultRedis . LRem ( key , item ) ; err != nil {
log . Error ( "删除redis 预下单失败:" , err )
2025-02-11 14:49:16 +08:00
}
2025-02-22 11:24:08 +08:00
if err := db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? " , preOrder . Id ) . Updates ( map [ string ] interface { } { "trigger_time" : time . Now ( ) } ) . Error ; err != nil {
log . Error ( "更新预下单状态失败 ordersn:" , v . OrderSn , " status:1" )
}
if err := db . Model ( & DbModels . LinePreOrder { } ) . Where ( "id =? AND status ='0'" , preOrder . Id ) . Updates ( map [ string ] interface { } { "status" : "1" } ) . Error ; err != nil {
2025-02-11 14:49:16 +08:00
log . Error ( "更新预下单状态失败 ordersn:" , v . OrderSn , " status:1" )
}
return
} else {
log . Error ( "获取锁失败" )
return
}
}
2025-11-05 16:26:21 +08:00
// 触发止盈单
// Deprecated 暂时不用了
func FuturesTakeTrigger ( db * gorm . DB , spotApi * SpotRestApi , takeOrder dto . TakeProfitRedisList , key , item string , futApi FutRestApi ) {
// tradeSet, err := cacheservice.GetTradeSet(global.EXCHANGE_BINANCE, takeOrder.Symbol, 2)
// if err != nil {
// logger.Errorf("触发止盈单 查询交易对失败 交易对:%s ordersn:%s err:%v", takeOrder.Symbol, takeOrder.OrderSn, err)
// }
lock := helper . NewRedisLock ( fmt . Sprintf ( rediskey . FutTrigger , takeOrder . ApiId , takeOrder . Symbol ) , 20 , 5 , 100 * time . Millisecond )
if ok , err := lock . AcquireWait ( context . Background ( ) ) ; err != nil {
log . Error ( "获取锁失败" , err )
return
} else if ok {
defer lock . Release ( )
hasrecord , _ := helper . DefaultRedis . IsElementInList ( key , item )
if ! hasrecord {
log . Debug ( "止损缓存中不存在" , item )
return
}
apiInfo , _ := GetApiInfo ( takeOrder . ApiId )
if apiInfo . Id == 0 {
log . Error ( "现货止盈 查询api用户不存在" )
return
}
// price := takeOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.StopLossPremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit))
// num := utility.StrToDecimal(stopOrder.Num).Truncate(int32(tradeSet.AmountDigit))
params := OrderPlacementService {
ApiId : takeOrder . ApiId ,
Side : takeOrder . Site ,
Type : "LIMIT" ,
TimeInForce : "GTC" ,
Symbol : takeOrder . Symbol ,
// Price: price,
// Quantity: num,
NewClientOrderId : takeOrder . OrderSn ,
}
if err := spotApi . OrderPlaceLoop ( db , params , 3 ) ; err != nil {
log . Errorf ( "现货止盈挂单失败 id: %s err:%v" , takeOrder . Id , err )
} else {
if err := db . Model ( & DbModels . LinePreOrder { } ) .
Where ( "id = ? " , takeOrder . Id ) .
Updates ( map [ string ] interface { } { "trigger_time" : time . Now ( ) } ) . Error ; err != nil {
log . Errorf ( "现货止盈更新状态失败 id: %s err:%v" , takeOrder . Id , err )
}
}
if _ , err := helper . DefaultRedis . LRem ( key , item ) ; err != nil {
log . Errorf ( "现货止盈 删除缓存失败 id:%v err:%v" , takeOrder . Id , err )
}
} else {
logger . Errorf ( "触发止盈单 不存在待触发主单 %s" , item )
}
}