2025-04-03 18:32:23 +08:00
package binanceservice
import (
"context"
"errors"
"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"
"go-admin/pkg/utility"
"go-admin/services/cacheservice"
2025-04-11 09:06:09 +08:00
"strings"
2025-04-03 18:32:23 +08:00
"time"
"github.com/bytedance/sonic"
2025-04-11 09:06:09 +08:00
"github.com/go-admin-team/go-admin-core/logger"
2025-04-03 18:32:23 +08:00
"github.com/go-admin-team/go-admin-core/sdk/service"
"github.com/shopspring/decimal"
2025-04-12 18:32:36 +08:00
"gorm.io/gorm"
2025-04-03 18:32:23 +08:00
)
type BinanceStrategyOrderService struct {
service . Service
2025-04-21 17:32:57 +08:00
Debug bool
2025-04-03 18:32:23 +08:00
}
// 判断是否触发波段订单
func ( e * BinanceStrategyOrderService ) TriggerStrategyOrder ( exchangeType string ) {
//现货
2025-04-21 17:32:57 +08:00
orderStrs , _ := helper . DefaultRedis . GetAllList ( fmt . Sprintf ( rediskey . StrategySpotOrderList , exchangeType ) )
if len ( orderStrs ) > 0 {
e . DoJudge ( orderStrs , 1 , exchangeType )
}
2025-04-03 18:32:23 +08:00
//合约
futOrdedrStrs , _ := helper . DefaultRedis . GetAllList ( fmt . Sprintf ( rediskey . StrategyFutOrderList , exchangeType ) )
2025-04-21 17:32:57 +08:00
if len ( futOrdedrStrs ) > 0 {
e . DoJudge ( futOrdedrStrs , 2 , exchangeType )
}
2025-04-03 18:32:23 +08:00
}
2025-04-12 18:32:36 +08:00
// 判断是否符合条件
2025-04-03 18:32:23 +08:00
func ( e * BinanceStrategyOrderService ) DoJudge ( orderStrs [ ] string , symbolType int , exchangeType string ) {
2025-04-12 18:32:36 +08:00
db := GetDBConnection ( )
2025-04-21 17:32:57 +08:00
// setting, _ := cacheservice.GetSystemSetting(db)
2025-04-12 18:32:36 +08:00
2025-04-03 18:32:23 +08:00
for _ , orderStr := range orderStrs {
var lockKey string
orderItem := dto . StrategyOrderRedisList { }
err := sonic . Unmarshal ( [ ] byte ( orderStr ) , & orderItem )
if err != nil || orderItem . Symbol == "" {
continue
}
if symbolType == 1 {
lockKey = rediskey . StrategySpotTriggerLock
} else {
lockKey = rediskey . StrategyFutTriggerLock
}
2025-04-21 17:32:57 +08:00
lock := helper . NewRedisLock ( fmt . Sprintf ( lockKey , orderItem . ApiId , orderItem . OrderSn ) , 60 , 20 , 300 * time . Millisecond )
2025-04-03 18:32:23 +08:00
if ok , err := lock . AcquireWait ( context . Background ( ) ) ; err != nil {
e . Log . Debug ( "获取锁失败" , err )
return
} else if ok {
defer lock . Release ( )
//判断是否符合条件
2025-04-21 17:32:57 +08:00
success , err := e . JudgeStrategy ( orderItem , symbolType , exchangeType )
2025-04-03 18:32:23 +08:00
if err != nil {
e . Log . Errorf ( "order_id:%d err:%v" , orderItem . Id , err )
}
2025-04-21 17:32:57 +08:00
if e . Debug || success {
2025-04-12 18:32:36 +08:00
e . TriggerOrder ( db , orderStr , orderItem , symbolType )
2025-04-03 18:32:23 +08:00
}
}
}
}
// 判断是否符合触发条件
func ( e * BinanceStrategyOrderService ) JudgeStrategy ( order dto . StrategyOrderRedisList , symbolType int , exchangeType string ) ( bool , error ) {
var symbolKey string
result := false
nowUtc := time . Now ( ) . UnixMilli ( )
switch symbolType {
case 1 :
symbolKey = fmt . Sprintf ( rediskey . SpotTickerLastPrice , exchangeType , order . Symbol )
case 2 :
symbolKey = fmt . Sprintf ( rediskey . FutureTickerLastPrice , exchangeType , order . Symbol )
}
lastUtc := nowUtc - ( int64 ( order . TimeSlotStart ) * 60 * 1000 )
beforePrice , _ := helper . DefaultRedis . GetNextAfterScore ( symbolKey , float64 ( lastUtc ) )
lastPrices , _ := helper . DefaultRedis . GetLastSortSet ( symbolKey )
if beforePrice == "" || len ( lastPrices ) == 0 {
return result , errors . New ( "获取交易对起止价格失败" )
}
score := lastPrices [ 0 ] . Score
2025-04-11 09:06:09 +08:00
var startPrice decimal . Decimal
var lastPrice decimal . Decimal
startPriceArgs := strings . Split ( beforePrice , ":" )
endPricecArgs := strings . Split ( lastPrices [ 0 ] . Member . ( string ) , ":" )
if len ( startPriceArgs ) == 0 || len ( endPricecArgs ) == 0 {
return result , errors . New ( "获取交易对起止价格失败" )
}
startPrice = utility . StrToDecimal ( startPriceArgs [ len ( startPriceArgs ) - 1 ] )
lastPrice = utility . StrToDecimal ( endPricecArgs [ len ( endPricecArgs ) - 1 ] )
2025-04-03 18:32:23 +08:00
//时间差超过10s
if ( nowUtc - int64 ( score ) ) / 1000 > 10 {
return result , fmt . Errorf ( "时间差超过 %ss" , "10" )
}
if startPrice . Cmp ( decimal . Zero ) == 0 || lastPrice . Cmp ( decimal . Zero ) == 0 {
return result , errors . New ( "获取交易对起止价格有一个为0" )
}
percentag := lastPrice . Div ( startPrice ) . Sub ( decimal . NewFromInt ( 1 ) ) . Truncate ( 6 )
2025-04-21 17:32:57 +08:00
logger . Infof ( "百分比:%s" , percentag . Mul ( decimal . NewFromInt ( 100 ) ) . String ( ) )
2025-04-03 18:32:23 +08:00
//价格没有变动
if percentag . Cmp ( decimal . Zero ) == 0 {
return result , nil
}
//满足条件
2025-04-21 17:32:57 +08:00
switch {
//涨价格大于0.5% 跌价格小于-0.5%
case order . CompareType == 1 && order . Direction == 1 && percentag . Cmp ( decimal . Zero ) > 0 ,
order . CompareType == 1 && order . Direction == 2 && percentag . Cmp ( decimal . Zero ) < 0 :
result = percentag . Abs ( ) . Mul ( decimal . NewFromInt ( 100 ) ) . Cmp ( order . Percentag ) > 0
case order . CompareType == 2 && order . Direction == 1 && percentag . Cmp ( decimal . Zero ) > 0 ,
order . CompareType == 2 && order . Direction == 2 && percentag . Cmp ( decimal . Zero ) < 0 :
result = percentag . Abs ( ) . Mul ( decimal . NewFromInt ( 100 ) ) . Cmp ( order . Percentag ) >= 0
case order . CompareType == 5 && order . Direction == 1 && percentag . Cmp ( decimal . Zero ) > 0 ,
order . CompareType == 5 && order . Direction == 2 && percentag . Cmp ( decimal . Zero ) < 0 :
result = percentag . Abs ( ) . Mul ( decimal . NewFromInt ( 100 ) ) . Cmp ( order . Percentag ) == 0
2025-04-03 18:32:23 +08:00
}
return result , nil
}
// 触发委托单
2025-04-12 18:32:36 +08:00
func ( e * BinanceStrategyOrderService ) TriggerOrder ( db * gorm . DB , cacheVal string , order dto . StrategyOrderRedisList , symbolType int ) error {
2025-04-03 18:32:23 +08:00
orders := make ( [ ] models . LinePreOrder , 0 )
2025-04-21 17:32:57 +08:00
if err := e . Orm . Model ( & models . LinePreOrder { } ) . Where ( "main_id =? or id =?" , order . Id , order . Id ) . Find ( & orders ) . Error ; err != nil {
2025-04-03 18:32:23 +08:00
e . Log . Errorf ( "order_id:%d 获取委托单失败:%s" , order . Id , err . Error ( ) )
return err
}
setting , _ := cacheservice . GetSystemSetting ( e . Orm )
if setting . Id == 0 {
return errors . New ( "获取系统设置失败" )
}
2025-04-21 17:32:57 +08:00
var tradeSet models2 . TradeSet
switch symbolType {
case 1 :
tradeSet , _ = cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , order . Symbol , 0 )
case 2 :
tradeSet , _ = cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , order . Symbol , 1 )
default :
return errors . New ( "获取交易对行情失败,交易对类型错误" )
}
2025-04-03 18:32:23 +08:00
if tradeSet . Coin == "" {
return errors . New ( "获取交易对行情失败" )
}
lastPrice := utility . StrToDecimal ( tradeSet . LastPrice )
if lastPrice . Cmp ( decimal . Zero ) <= 0 {
return errors . New ( "最新成交价小于等于0" )
}
2025-04-12 11:33:12 +08:00
mainOrder := models . LinePreOrder { }
2025-04-03 18:32:23 +08:00
for _ , v := range orders {
if v . MainId == 0 {
mainOrder = v
break
}
}
2025-04-21 17:32:57 +08:00
if mainOrder . Id == 0 {
return errors . New ( "获取主单失败" )
}
2025-04-03 18:32:23 +08:00
GetOrderByPid ( & mainOrder , orders , mainOrder . Id )
2025-04-12 11:33:12 +08:00
e . RecalculateOrder ( tradeSet , & mainOrder , setting )
2025-04-21 17:32:57 +08:00
//事务保存
err := e . Orm . Transaction ( func ( tx * gorm . DB ) error {
if err1 := tx . Save ( & mainOrder ) . Error ; err1 != nil {
return err1
}
for _ , v := range mainOrder . Childs {
if err1 := tx . Save ( & v ) . Error ; err1 != nil {
return err1
}
for _ , v2 := range v . Childs {
if err1 := tx . Save ( & v2 ) . Error ; err1 != nil {
return err1
}
}
}
return nil
} )
if err != nil {
2025-04-12 11:33:12 +08:00
e . Log . Errorf ( "order_id:%d 波段触发保存委托单失败:%s" , mainOrder . Id , err . Error ( ) )
2025-04-12 18:32:36 +08:00
return err
2025-04-12 11:33:12 +08:00
}
2025-04-12 18:32:36 +08:00
e . StrategyOrderPlace ( db , cacheVal , mainOrder , tradeSet )
2025-04-03 18:32:23 +08:00
return nil
}
2025-04-12 18:32:36 +08:00
// 策略触发订单
// 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 )
2025-04-21 17:32:57 +08:00
if _ , err := helper . DefaultRedis . LRem ( key , cacheVal ) ; err != nil {
logger . Error ( "删除redis 预下单失败:" , err )
}
2025-04-12 18:32:36 +08:00
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 ( "更新预下单状态失败" )
}
2025-04-21 17:32:57 +08:00
return
} else {
2025-04-12 18:32:36 +08:00
if _ , err := helper . DefaultRedis . LRem ( key , cacheVal ) ; err != nil {
logger . Error ( "删除redis 预下单失败:" , err )
}
2025-04-21 17:32:57 +08:00
}
if err := db . Model ( & models . LinePreOrder { } ) . Where ( "id =? " , mainOrder . Id ) . Updates ( map [ string ] interface { } { "trigger_time" : time . Now ( ) } ) . Error ; err != nil {
logger . Error ( "更新预下单状态失败 ordersn:" , mainOrder . OrderSn , " status:1" )
}
if err := db . Model ( & models . LinePreOrder { } ) . Where ( "id =? AND status ='0'" , mainOrder . Id ) . Updates ( map [ string ] interface { } { "status" : "1" } ) . Error ; err != nil {
logger . Error ( "更新预下单状态失败 ordersn:" , mainOrder . OrderSn , " status:1" )
2025-04-12 18:32:36 +08:00
}
}
2025-04-03 18:32:23 +08:00
// 重新计算订单单价、数量
// tradeSet 交易对行情
// mainOrder 主订单
// setting 系统设置
func ( e * BinanceStrategyOrderService ) RecalculateOrder ( tradeSet models2 . TradeSet , mainOrder * models . LinePreOrder , setting models . LineSystemSetting ) error {
exts := make ( [ ] models . LinePreOrderExt , 0 )
2025-04-12 18:32:36 +08:00
if err := e . Orm . Model ( models . LinePreOrderExt { } ) . Where ( "main_order_id =?" , mainOrder . Id ) . Find ( & exts ) . Error ; err != nil {
2025-04-03 18:32:23 +08:00
return errors . New ( "获取拓展信息失败" )
}
2025-04-21 17:32:57 +08:00
var newPrice decimal . Decimal
2025-04-03 18:32:23 +08:00
lastPrice := utility . StrToDecimal ( tradeSet . LastPrice )
rate := utility . StrToDecimal ( mainOrder . Rate )
2025-04-21 17:32:57 +08:00
newPrice = lastPrice . Mul ( decimal . NewFromInt ( 1 ) . Add ( rate . Div ( decimal . NewFromInt ( 100 ) ) . Truncate ( 4 ) ) ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
2025-04-03 18:32:23 +08:00
buyPrice := utility . StrToDecimal ( mainOrder . BuyPrice )
totalNum := buyPrice . Div ( newPrice ) . Truncate ( int32 ( tradeSet . AmountDigit ) )
mainOrder . SignPrice = lastPrice . String ( )
mainOrder . Price = newPrice . String ( )
mainOrder . Num = totalNum . String ( )
2025-04-11 09:06:09 +08:00
remainQuantity := totalNum
2025-04-21 17:32:57 +08:00
var totalLossAmount decimal . Decimal
prePrice := lastPrice
2025-04-03 18:32:23 +08:00
for index := range mainOrder . Childs {
2025-04-11 09:06:09 +08:00
var ext models . LinePreOrderExt
2025-04-21 17:32:57 +08:00
extOrderId := mainOrder . Childs [ index ] . Id
takeStopArray := [ ] int { 1 , 2 }
//止盈止损 ext拓展id为 pid
if utility . ContainsInt ( takeStopArray , mainOrder . Childs [ index ] . OrderType ) {
extOrderId = mainOrder . Childs [ index ] . Pid
}
2025-04-11 09:06:09 +08:00
for _ , v := range exts {
2025-04-21 17:32:57 +08:00
if v . OrderId == extOrderId {
2025-04-11 09:06:09 +08:00
ext = v
break
}
}
if ext . Id <= 0 {
2025-04-21 17:32:57 +08:00
logger . Errorf ( "子订单ext不存在 id:%d" , mainOrder . Childs [ index ] . Id )
2025-04-11 09:06:09 +08:00
continue
}
//主单止盈、止损
2025-04-21 17:32:57 +08:00
if mainOrder . Childs [ index ] . Pid == mainOrder . Childs [ index ] . MainId && ( mainOrder . Childs [ index ] . OrderType == 1 || mainOrder . Childs [ index ] . OrderType == 2 ) {
2025-04-11 09:06:09 +08:00
var percent decimal . Decimal
switch {
// 加价
2025-04-21 17:32:57 +08:00
case mainOrder . Childs [ index ] . OrderType == 1 && mainOrder . Site == "BUY" , mainOrder . Childs [ index ] . OrderType == 2 && mainOrder . Site == "SELL" :
2025-04-11 09:06:09 +08:00
percent = decimal . NewFromInt ( 100 ) . Add ( ext . TakeProfitRatio )
//减价
2025-04-21 17:32:57 +08:00
case mainOrder . Childs [ index ] . OrderType == 2 && mainOrder . Site == "BUY" , mainOrder . Childs [ index ] . OrderType == 1 && mainOrder . Site == "SELL" :
2025-04-11 09:06:09 +08:00
percent = decimal . NewFromInt ( 100 ) . Sub ( ext . StopLossRatio )
2025-04-03 18:32:23 +08:00
}
2025-04-11 09:06:09 +08:00
childPrice := lastPrice . Mul ( percent . Div ( decimal . NewFromInt ( 100 ) . Truncate ( 4 ) ) ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . Price = childPrice . String ( )
mainOrder . Childs [ index ] . Num = totalNum . String ( )
2025-04-11 09:06:09 +08:00
} else {
lastNum := remainQuantity
//过期时间
if ext . ExpirateHour <= 0 {
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . ExpireTime = time . Now ( ) . AddDate ( 10 , 0 , 0 )
2025-04-11 09:06:09 +08:00
} else {
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . ExpireTime = time . Now ( ) . Add ( time . Hour * time . Duration ( ext . ExpirateHour ) )
2025-04-11 09:06:09 +08:00
}
switch {
//加仓单
2025-04-21 17:32:57 +08:00
case mainOrder . Childs [ index ] . OrderType == 1 && mainOrder . Childs [ index ] . OrderCategory == 3 :
2025-04-11 09:06:09 +08:00
var percentage decimal . Decimal
2025-04-03 18:32:23 +08:00
if mainOrder . Site == "BUY" {
2025-04-11 09:06:09 +08:00
percentage = decimal . NewFromInt ( 1 ) . Sub ( ext . PriceRatio . Div ( decimal . NewFromInt ( 100 ) ) )
2025-04-03 18:32:23 +08:00
} else {
2025-04-11 09:06:09 +08:00
percentage = decimal . NewFromInt ( 1 ) . Add ( ext . PriceRatio . Div ( decimal . NewFromInt ( 100 ) ) )
2025-04-03 18:32:23 +08:00
}
2025-04-11 09:06:09 +08:00
dataPrice := utility . StrToDecimal ( mainOrder . Price ) . Mul ( percentage ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . Price = dataPrice . String ( )
priceDiff := dataPrice . Sub ( prePrice ) . Abs ( )
totalLossAmount = totalLossAmount . Add ( lastNum . Mul ( priceDiff ) )
2025-04-11 09:06:09 +08:00
if ext . AddPositionType == 1 {
buyPrice := utility . StrToDecimal ( mainOrder . BuyPrice ) . Mul ( utility . SafeDiv ( ext . AddPositionVal , decimal . NewFromInt ( 100 ) ) ) . Truncate ( 2 )
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . Num = utility . SafeDiv ( buyPrice , dataPrice ) . Truncate ( int32 ( tradeSet . AmountDigit ) ) . String ( )
2025-04-11 09:06:09 +08:00
} else {
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . Num = utility . SafeDiv ( ext . AddPositionVal . Truncate ( 2 ) , dataPrice ) . Truncate ( int32 ( tradeSet . AmountDigit ) ) . String ( )
2025-04-11 09:06:09 +08:00
}
//加库存
2025-04-21 17:32:57 +08:00
lastNum = lastNum . Add ( utility . StrToDecimal ( mainOrder . Childs [ index ] . Num ) )
2025-04-12 11:33:12 +08:00
// 计算子订单
2025-04-21 17:32:57 +08:00
if len ( mainOrder . Childs [ index ] . Childs ) > 0 {
calculateChildOrder ( & mainOrder . Childs [ index ] . Childs , & tradeSet , ext , lastNum , dataPrice , totalLossAmount , false )
2025-04-12 11:33:12 +08:00
}
2025-04-21 17:32:57 +08:00
//覆盖最近的订单价
prePrice = dataPrice
2025-04-11 09:06:09 +08:00
//减仓单
2025-04-21 17:32:57 +08:00
case mainOrder . Childs [ index ] . OrderType == 4 :
2025-04-12 11:33:12 +08:00
percentage := decimal . NewFromInt ( 1 )
if mainOrder . Site == "BUY" && ext . PriceRatio . Cmp ( decimal . Zero ) > 0 {
percentage = decimal . NewFromInt ( 1 ) . Sub ( ext . PriceRatio . Div ( decimal . NewFromInt ( 100 ) ) )
} else if ext . PriceRatio . Cmp ( decimal . Zero ) > 0 {
percentage = decimal . NewFromInt ( 1 ) . Add ( ext . PriceRatio . Div ( decimal . NewFromInt ( 100 ) ) )
}
dataPrice := utility . StrToDecimal ( mainOrder . Price ) . Mul ( percentage ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . Price = dataPrice . String ( )
priceDiff := dataPrice . Sub ( prePrice ) . Abs ( )
totalLossAmount = totalLossAmount . Add ( lastNum . Mul ( priceDiff ) )
2025-04-12 11:33:12 +08:00
//百分比减仓
if ext . AddPositionType == 1 {
2025-04-21 17:32:57 +08:00
mainOrder . Childs [ index ] . Num = lastNum . Mul ( ext . AddPositionVal . Div ( decimal . NewFromInt ( 100 ) ) ) . Truncate ( int32 ( tradeSet . AmountDigit ) ) . String ( )
2025-04-12 11:33:12 +08:00
} else {
logger . Error ( "减仓不能是固定数值" )
}
2025-04-11 09:06:09 +08:00
//减库存
2025-04-21 17:32:57 +08:00
lastNum = lastNum . Sub ( utility . StrToDecimal ( mainOrder . Childs [ index ] . Num ) )
2025-04-12 11:33:12 +08:00
// 计算子订单
2025-04-21 17:32:57 +08:00
if len ( mainOrder . Childs [ index ] . Childs ) > 0 {
calculateChildOrder ( & mainOrder . Childs [ index ] . Childs , & tradeSet , ext , lastNum , dataPrice , totalLossAmount , false )
2025-04-12 11:33:12 +08:00
}
2025-04-21 17:32:57 +08:00
//覆盖最近的订单价
prePrice = dataPrice
2025-04-12 11:33:12 +08:00
}
}
}
return nil
}
// 计算子订单信息
// isTpTp 是否是止盈后止损止盈
2025-04-21 17:32:57 +08:00
// totalLossAmount 累计亏损金额
func calculateChildOrder ( orders * [ ] models . LinePreOrder , tradeSet * models2 . TradeSet , ext models . LinePreOrderExt , lastNum decimal . Decimal , price decimal . Decimal , totalLossAmount decimal . Decimal , isTpTp bool ) error {
2025-04-12 11:33:12 +08:00
for index := range * orders {
orderQuantity := lastNum . Truncate ( int32 ( tradeSet . AmountDigit ) )
percentage := decimal . NewFromInt ( 1 )
var addPercentage decimal . Decimal
switch {
//止盈
case ! isTpTp && ( * orders ) [ index ] . OrderType == 1 :
addPercentage = ext . TakeProfitRatio
if ext . TakeProfitNumRatio . Cmp ( decimal . Zero ) > 0 {
orderQuantity = lastNum . Mul ( ext . TakeProfitNumRatio . Div ( decimal . NewFromInt ( 100 ) ) ) . Truncate ( int32 ( tradeSet . AmountDigit ) )
2025-04-03 18:32:23 +08:00
}
2025-04-12 11:33:12 +08:00
//止损
case ! isTpTp && ( * orders ) [ index ] . OrderType == 2 :
addPercentage = ext . StopLossRatio
//止盈后止盈
case isTpTp && ( * orders ) [ index ] . OrderType == 1 :
addPercentage = ext . TpTpPriceRatio
//止盈后止损
case isTpTp && ( * orders ) [ index ] . OrderType == 2 :
addPercentage = ext . TpSlPriceRatio
}
switch {
//做多止盈、做空止损
case ( * orders ) [ index ] . OrderType == 1 && ( * orders ) [ index ] . Site == "SELL" , ( * orders ) [ index ] . OrderType == 2 && ( * orders ) [ index ] . Site == "BUY" :
2025-04-21 17:32:57 +08:00
percentage = decimal . NewFromInt ( 100 ) . Add ( addPercentage )
2025-04-12 11:33:12 +08:00
//做多止损、做空止盈
case ( * orders ) [ index ] . OrderType == 2 && ( * orders ) [ index ] . Site == "SELL" , ( * orders ) [ index ] . OrderType == 1 && ( * orders ) [ index ] . Site == "BUY" :
2025-04-21 17:32:57 +08:00
percentage = decimal . NewFromInt ( 100 ) . Sub ( addPercentage )
}
//止盈亏损回本百分比
if ( * orders ) [ index ] . OrderType == 1 && totalLossAmount . Cmp ( decimal . Zero ) > 0 {
lossPercent := totalLossAmount . Div ( lastNum ) . Mul ( decimal . NewFromInt ( 100 ) ) . Truncate ( 2 )
percentage = percentage . Add ( lossPercent )
}
if percentage . Cmp ( decimal . Zero ) > 0 {
percentage = percentage . Div ( decimal . NewFromInt ( 100 ) )
2025-04-12 11:33:12 +08:00
}
orderPrice := price . Mul ( percentage ) . Truncate ( int32 ( tradeSet . PriceDigit ) )
( * orders ) [ index ] . Price = orderPrice . String ( )
( * orders ) [ index ] . Num = orderQuantity . String ( )
lastOrderQuantity := lastNum . Sub ( orderQuantity ) . Truncate ( int32 ( tradeSet . AmountDigit ) )
//止盈后止盈、止盈后止损
2025-04-21 17:32:57 +08:00
if len ( ( * orders ) [ index ] . Childs ) > 0 && lastOrderQuantity . Cmp ( decimal . Zero ) > 0 {
calculateChildOrder ( & ( * orders ) [ index ] . Childs , tradeSet , ext , lastOrderQuantity , orderPrice , decimal . Zero , true )
2025-04-03 18:32:23 +08:00
}
}
2025-04-12 11:33:12 +08:00
2025-04-03 18:32:23 +08:00
return nil
}
// 递归订单树
func GetOrderByPid ( order * models . LinePreOrder , orders [ ] models . LinePreOrder , pid int ) {
for _ , v := range orders {
if v . Pid == pid {
GetOrderByPid ( & v , orders , v . Id )
order . Childs = append ( order . Childs , v )
}
}
}