@ -14,6 +14,7 @@ import (
"strconv"
"time"
"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"
@ -108,26 +109,36 @@ func (e *ReverseService) ReverseOrder(apiKey string, mapData map[string]interfac
switch {
case mainOrder . PositionSide == "LONG" && mainOrder . Side == "BUY" , mainOrder . PositionSide == "SHORT" && mainOrder . Side == "SELL" :
if mainOrder . Category == 0 {
if err1 := e . savePosition ( & mainOrder , reverseApiInfo . Id , true , false , false ) ; err1 != nil {
needReverseOrder , closePosition , err1 := e . savePosition ( & mainOrder , & apiInfo , true , false )
if err1 != nil {
return true , err1
}
e . DoAd dReverseOrder( & mainOrder , & reverseApiInfo , apiInfo . OrderProportion , false , false )
if nee dReverseOrder {
e . DoAddReverseOrder ( & mainOrder , & reverseApiInfo , apiInfo . OrderProportion , false , closePosition )
}
}
case mainOrder . PositionSide == "SHORT" && mainOrder . Side == "BUY" , mainOrder . PositionSide == "LONG" && mainOrder . Side == "SELL" :
if mainOrder . Category == 0 {
closePosition := maphelper . GetBool ( mapData , "R" )
if err1 := e . savePosition ( & mainOrder , reverseApiInfo . Id , true , true , closePosition ) ; err1 != nil {
needReverseOrder , closePosition , err1 := e . savePosition ( & mainOrder , & apiInfo , true , true )
if err1 != nil {
e . Log . Errorf ( "保存主订单失败: %v" , err1 )
return true , err1
}
e . DoAddReverseOrder ( & mainOrder , & reverseApiInfo , apiInfo . OrderProportion , true , closePosition )
if needReverseOrder {
e . DoAddReverseOrder ( & mainOrder , & reverseApiInfo , apiInfo . OrderProportion , true , closePosition )
}
}
default :
return true , errors . New ( "不支持的订单类型" )
}
return true , nil
} else if apiInfo . Subordinate == "2" {
e . changeOrderStatus ( 3 , orderSn , mapData )
symbol , err := maphelper . GetString ( mapData , "s" )
if err != nil {
@ -153,20 +164,19 @@ func (e *ReverseService) ReverseOrder(apiKey string, mapData map[string]interfac
TotalNum : totalNum ,
Side : side ,
Price : price ,
FinalPrice : price ,
}
e . changeOrderStatus ( 3 , orderSn , mapData )
switch {
case mainOrder . PositionSide == "LONG" && mainOrder . Side == "BUY" , mainOrder . PositionSide == "SHORT" && mainOrder . Side == "SELL" :
if mainOrder . Category == 0 {
if err1 := e . savePosition ( & mainOrder , 0 , false , false , false ) ; err1 != nil {
if _ , _ , err1 := e . savePosition ( & mainOrder , & apiInfo , false , false ) ; err1 != nil {
return true , err1
}
}
case mainOrder . PositionSide == "SHORT" && mainOrder . Side == "BUY" , mainOrder . PositionSide == "LONG" && mainOrder . Side == "SELL" :
case mainOrder . PositionSide == "SHORT" && mainOrder . Side == "BUY" , mainOrder . PositionSide == "LONG" && mainOrder . Side == "Srget ELL" :
if mainOrder . Category == 0 {
closePosition := maphelper . GetBool ( mapData , "R" )
if err1 := e . savePosition ( & mainOrder , 0 , false , true , closePosition ) ; err1 != nil {
if _ , _ , err1 := e . savePosition ( & mainOrder , & apiInfo , false , true ) ; err1 != nil {
return true , err1
}
}
@ -298,17 +308,23 @@ func (e *ReverseService) SaveMainOrder(mapData map[string]interface{}, apiInfo D
}
// 更新仓位信息
// apiInfo: 当前下单api信息
// return
// neeReverseOrder: 是否需要反单
// closePosition: true=平仓, false=减仓
func ( e * ReverseService ) savePosition ( reverseOrder * DbModels . LineReverseOrder , reverseApiId int , isMain , reducePosition , closePosition bool ) error {
// err error 错误信息
func ( e * ReverseService ) savePosition ( order * DbModels . LineReverseOrder , apiInfo * DbModels . LineApiUser , isMain , reducePosition bool ) ( bool , bool , error ) {
position := DbModels . LineReversePosition { }
positionSide := reverseO rder. PositionSide
side := reverseO rder. Side
totalNum := reverseO rder. TotalNum
positionSide := o rder. PositionSide
side := o rder. Side
totalNum := o rder. TotalNum
closePosition := false
needReverseOrder := false
symbol , err1 := cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , reverseO rder. Symbol , 1 )
symbol , err1 := cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , o rder. Symbol , 1 )
if err1 != nil {
e . Log . Errorf ( "获取交易对失败 symbol:%s err:%v" , reverseO rder. Symbol , err1 )
e . Log . Errorf ( "获取交易对失败 symbol:%s err:%v" , o rder. Symbol , err1 )
}
var querySql string
@ -316,12 +332,15 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
//如果是主单,存储仓位则是反单的持仓方向
if isMain {
if reverseO rder. PositionSide == "LONG" {
if o rder. PositionSide == "LONG" {
positionSide = "SHORT"
} else {
positionSide = "LONG"
}
//减仓 判断是否为平仓
closePosition = e . getClosePosition ( reducePosition , apiInfo , order , order . PositionSide , isMain )
if ! reducePosition {
//反单止盈止损方向相反
if side == "SELL" {
@ -330,14 +349,14 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
side = "SELL"
}
position . ReverseApiId = r everseApiId
position . ReverseApiId = apiInfo . R everseApiId
position . Side = side
position . ApiId = reverseO rder. ApiId
position . Symbol = reverseO rder. Symbol
position . ApiId = o rder. ApiId
position . Symbol = o rder. Symbol
position . Status = 1
position . ReverseStatus = 0
position . PositionSide = positionSide
position . AveragePrice = reverseO rder. FinalPrice
position . AveragePrice = o rder. FinalPrice
position . PositionNo = snowflakehelper . GetOrderNo ( )
}
querySql = "api_id =? and position_side =? and symbol =? and status =1"
@ -354,6 +373,8 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
}
} else {
querySql = "reverse_api_id =? and position_side =? and symbol =? and reverse_status in (0,1)"
//减仓 判断是否为平仓
closePosition = e . getClosePosition ( reducePosition , apiInfo , order , order . PositionSide , isMain )
if closePosition {
totalNum = decimal . Zero
@ -366,10 +387,11 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
}
var averagePrice decimal . Decimal
var remainQuantity decimal . Decimal
err := e . Orm . Transaction ( func ( tx * gorm . DB ) error {
err1 := tx . Model ( & position ) . Where ( querySql ,
reverseO rder. ApiId , positionSide , reverseO rder. Symbol ) . First ( & position ) . Error
o rder. ApiId , positionSide , o rder. Symbol ) . First ( & position ) . Error
if err1 != nil {
//主单仓位不存在,创建新仓位
@ -397,12 +419,12 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
//加仓
if ! reducePosition {
totalPrice = totalPrice . Add ( reverseO rder. Price . Mul ( reverseO rder. TotalNum ) )
totalAmount = totalAmount . Add ( reverseO rder. TotalNum )
totalPrice = totalPrice . Add ( o rder. Price . Mul ( o rder. TotalNum ) )
totalAmount = totalAmount . Add ( o rder. TotalNum )
} else if reducePosition && ! closePosition {
//只减仓
totalPrice = totalPrice . Sub ( reverseO rder. Price . Mul ( reverseO rder. TotalNum ) )
totalAmount = totalAmount . Sub ( reverseO rder. TotalNum )
totalPrice = totalPrice . Sub ( o rder. Price . Mul ( o rder. TotalNum ) )
totalAmount = totalAmount . Sub ( o rder. TotalNum )
}
}
@ -411,7 +433,7 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
averagePrice = position . AveragePrice
} else {
if position . ReverseAveragePrice . IsZero ( ) {
averagePrice = reverseO rder. Price
averagePrice = o rder. Price
} else {
averagePrice = position . ReverseAveragePrice
}
@ -431,7 +453,7 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
}
//关联订单的仓位id
if err2 := tx . Exec ( "UPDATE line_reverse_order set position_id=@positionId where id=@orderId and position_id = 0" , sql . Named ( "positionId" , position . Id ) , sql . Named ( "orderId" , reverseO rder. Id ) ) . Error ; err2 != nil {
if err2 := tx . Exec ( "UPDATE line_reverse_order set position_id=@positionId where id=@orderId and position_id = 0" , sql . Named ( "positionId" , position . Id ) , sql . Named ( "orderId" , o rder. Id ) ) . Error ; err2 != nil {
return err2
}
@ -440,16 +462,63 @@ func (e *ReverseService) savePosition(reverseOrder *DbModels.LineReverseOrder, r
return dbResult . Error
}
reverseO rder. PositionId = position . Id
o rder. PositionId = position . Id
if dbResult . RowsAffected == 0 {
e . Log . Errorf ( "减仓数据 是否平仓单:%v :%v" , closePosition , reverseO rder)
e . Log . Errorf ( "减仓数据 是否平仓单:%v :%v" , closePosition , o rder)
return errors . New ( "没有找到对应的持仓信息" )
}
if reducePosition && ! isMain {
remainQuantity = position . ReverseAmount . Sub ( totalNum )
} else if ! isMain {
remainQuantity = position . ReverseAmount . Add ( totalNum )
}
//主单且对手单没有平仓
if isMain && position . ReverseStatus != 2 {
needReverseOrder = true
}
return nil
} )
return err
if ! isMain && ! closePosition {
e . doDefaultTakeStop ( order , apiInfo , remainQuantity )
} else if ! isMain && closePosition {
//取消剩余的委托
e . DoCancelTakeAndStop ( order . Symbol , position . PositionSide , apiInfo )
}
return needReverseOrder , closePosition , err
}
// 获取是否为平仓状态
func ( e * ReverseService ) getClosePosition ( reducePosition bool , apiInfo * DbModels . LineApiUser , order * DbModels . LineReverseOrder , positionSide string , isMain bool ) bool {
closePosition := false
if reducePosition {
futApi := FutRestApi { }
holdData := HoldeData { }
err := futApi . GetPositionData ( apiInfo , order . Symbol , positionSide , & holdData )
if err != nil {
e . Log . Errorf ( "获取剩余持仓信息失败 symbol:%s err:%v" , order . Symbol , err )
lastPosition := DbModels . LineReversePosition { }
if err2 := e . Orm . Model ( & DbModels . LineReversePosition { } ) . Where ( "position_side =? and symbol =? and status =1" , positionSide , order . Symbol ) . First ( & lastPosition ) . Error ; err2 != nil {
e . Log . Errorf ( "获取上一次持仓信息失败 symbol:%s err:%v" , order . Symbol , err2 )
} else if isMain && lastPosition . Amount . Cmp ( order . TotalNum ) <= 0 {
//如果剩余仓位小于等于
closePosition = true
} else if ! isMain && lastPosition . ReverseAmount . Cmp ( order . TotalNum ) <= 0 {
closePosition = true
}
} else if holdData . TotalQuantity . IsZero ( ) {
closePosition = true
}
}
return closePosition
}
// 反向下单
@ -556,8 +625,11 @@ func (e *ReverseService) DoAddReverseOrder(mainOrder *DbModels.LineReverseOrder,
//反向下单百分比
proportion = proportion . Div ( decimal . NewFromInt ( 100 ) ) . Truncate ( 4 )
amount = mainOrder . TotalNum . Mul ( proportion ) . Truncate ( int32 ( symbol . AmountDigit ) )
logger . Info ( "反向下单比例 %d ,原始数量:%d, 反向下单数量: %d" , proportion , mainOrder . TotalNum , amount )
if amount . Cmp ( decimal . Zero ) <= 0 {
e . Log . Errorf ( "计算数量失败 symbol:%s custom:%s 数量小于0" , mainOrder . Symbol , mainOrder . OrderSn )
return errors . New ( "计算数量失败" )
@ -620,6 +692,24 @@ func (e *ReverseService) DoCancelTakeProfitBatch(symbol, positionSide, side stri
return nil
}
// 取消止盈和止损单
func ( e * ReverseService ) DoCancelTakeAndStop ( symbol , positionSide string , apiInfo * DbModels . LineApiUser ) error {
var orderSns [ ] string
e . Orm . Model ( & DbModels . LineReverseOrder { } ) . Where ( "symbol =? and position_side =? and status =2" , symbol , positionSide ) . Pluck ( "order_sn" , & orderSns )
if len ( orderSns ) > 0 {
futApi := FutRestApi { }
if err := futApi . CancelBatchFutOrderLoop ( * apiInfo , symbol , orderSns ) ; err != nil {
e . Log . Errorf ( "币安撤单失败 symbol:%s custom:%v :%v" , symbol , orderSns , err )
return err
}
}
return nil
}
// 获取止盈止损订单
// symbol: 交易对
// positionSide: 持仓方向
@ -681,41 +771,92 @@ func (e *ReverseService) DoBianceOrder(order *DbModels.LineReverseOrder, apiInfo
return nil
}
// 处理默认止盈止损
// order: 订单信息
// apiInfo: api信息
// Optimized Reverse Order Handling
// File: reverse_order_handler.go
func ( e * ReverseService ) doDefaultTakeStop ( order * DbModels . LineReverseOrder , apiInfo * DbModels . LineApiUser , totalNum decimal . Decimal ) error {
if totalNum . LessThanOrEqual ( decimal . Zero ) {
return nil
}
orders , err := e . getActiveReverseOrders ( order . PositionId )
if err != nil {
return err
}
if len ( orders ) == 2 {
return nil
}
setting , err := GetReverseSetting ( e . Orm )
if err != nil {
e . Log . Errorf ( "获取反单设置失败:%v" , err )
return err
}
symbol , err := cacheservice . GetTradeSet ( global . EXCHANGE_BINANCE , order . Symbol , 1 )
if err != nil {
e . Log . Errorf ( "获取交易对信息失败:%v" , err )
return err
}
side := e . getOppositeSide ( order . Side )
lastPrice , _ := decimal . NewFromString ( symbol . LastPrice )
now := time . Now ( )
types := [ ] struct {
Enabled bool
CheckTypes [ ] string
OrderType string
Ratio decimal . Decimal
IsTakeProfit bool
} {
{ ! setting . TakeProfitRatio . IsZero ( ) , [ ] string { "TAKE_PROFIT_MARKET" , "TAKE_PROFIT" } , "TAKE_PROFIT_MARKET" , setting . TakeProfitRatio , true } ,
{ ! setting . StopLossRatio . IsZero ( ) , [ ] string { "STOP_MARKET" , "STOP" } , "STOP_MARKET" , setting . StopLossRatio , false } ,
}
for _ , t := range types {
if t . Enabled && ! e . hasOrderType ( orders , t . CheckTypes ... ) {
price := e . calculatePrice ( order . PositionSide , order . FinalPrice , t . Ratio , t . IsTakeProfit )
err := e . createReverseOrder ( CreateOrderParams {
Order : order ,
ApiInfo : apiInfo ,
Symbol : & symbol ,
Side : side ,
OrderType : t . OrderType ,
Price : price ,
TotalNum : totalNum ,
Now : now ,
LastPrice : lastPrice ,
Close : true ,
PositionId : order . PositionId ,
} )
if err != nil {
e . Log . Errorf ( "止盈止损下单失败:%v" , err )
}
}
}
return nil
}
// 重下止盈止损
// mapData: 主单止盈止损回调
// mapData:
func ( e * ReverseService ) ReTakeOrStopOrder ( mapData * map [ string ] interface { } , orderSn string , mainApiInfo * DbModels . LineApiUser , symbol * models . TradeSet ) error {
orderType := 0 //订单类型 1-止盈 2-止损
side , err := maphelper . GetString ( * mapData , "S" )
if err != nil {
return err
}
ot , err := maphelper . GetString ( * mapData , "ot" )
if err != nil {
return err
}
//反单止盈止损方向相反
if side == "SELL" {
side = "BUY"
} else {
side = "SELL"
}
positionSide , err := maphelper . GetString ( * mapData , "ps" )
if err != nil {
return err
}
if positionSide == "LONG" {
positionSide = "SHORT"
} else {
positionSide = "LONG"
}
close := maphelper . GetBool ( * mapData , "cp" )
stopPrice := maphelper . GetDecimal ( * mapData , "sp" )
if stopPrice . IsZero ( ) {
@ -723,12 +864,19 @@ func (e *ReverseService) ReTakeOrStopOrder(mapData *map[string]interface{}, orde
return err
}
apiInfo , err := GetApiInfo ( mainApiInfo . ReverseApiId )
if err != nil {
e . Log . Errorf ( "根据主单api获取反单api失败 symbol:%s custom:%s :%v" , symbol , orderSn , err )
return err
}
side = e . getOppositeSide ( side )
if positionSide == "LONG" {
positionSide = "SHORT"
} else {
positionSide = "LONG"
}
var orderType int
switch ot {
case "STOP_MARKET" , "STOP" :
orderType = 2
@ -739,26 +887,19 @@ func (e *ReverseService) ReTakeOrStopOrder(mapData *map[string]interface{}, orde
}
var reversePosition DbModels . LineReversePosition
e . Orm . Model ( & reversePosition ) .
Where ( "symbol =? and reverse_api_id =? and position_side =? and reverse_status =1" , symbol . GetSymbol ( ) , apiInfo . Id , positionSide ) .
First ( & reversePosition )
if reversePosition . Id == 0 {
e . Log . Errorf ( "获取反单持仓失败 symbol:%s custom:%s :%v" , symbol , orderSn , err )
return err
}
mainPercent := decimal . NewFromInt ( 1 )
if ! stopPrice . IsZero ( ) && ! reversePosition . AveragePrice . IsZero ( ) {
mainPercent = stopPrice . Div ( reversePosition . AveragePrice )
mainPercent = ( mainPercent . Sub ( decimal . NewFromInt ( 1 ) ) ) . Abs ( ) . Truncate ( 4 )
}
mainPercent := stopPrice . Div ( reversePosition . AveragePrice )
mainPercent = ( mainPercent . Sub ( decimal . NewFromInt ( 1 ) ) ) . Abs ( ) . Truncate ( 4 )
var percent decimal . Decimal
switch {
//做多止损
case orderType == 2 && positionSide == "LONG" , orderType == 1 && positionSide == "SHORT" :
percent = decimal . NewFromInt ( 1 ) . Sub ( mainPercent )
case orderType == 2 && positionSide == "SHORT" , orderType == 1 && positionSide == "LONG" :
@ -770,55 +911,286 @@ func (e *ReverseService) ReTakeOrStopOrder(mapData *map[string]interface{}, orde
now := time . Now ( )
price := reversePosition . AveragePrice . Mul ( percent ) . Truncate ( int32 ( symbol . PriceDigit ) )
lastPrice , _ := decimal . NewFromString ( symbol . LastPrice )
newOrder := DbModels . LineReverseOrder {
PositionId : reversePosition . Id ,
OrderSn : helper . GetOrderNo ( ) ,
OrderType : orderType ,
Status : 1 ,
Price : price ,
TotalNum : reversePosition . TotalReverseAmount ,
Symbol : symbol . GetSymbol ( ) ,
Side : side ,
PositionSide : positionSide ,
FollowOrderSn : orderSn ,
Type : ot ,
SignPrice : lastPrice ,
Category : 1 ,
ApiId : apiInfo . Id ,
IsAddPosition : 2 ,
TriggerTime : & now ,
BuyPrice : reversePosition . TotalReverseAmount . Mul ( price ) . Truncate ( int32 ( symbol . PriceDigit ) ) ,
}
if err1 := e . Orm . Create ( & newOrder ) . Error ; err1 != nil {
e . Log . Errorf ( "保存反单止盈止损失败 symbol:%s custom:%s :%v" , symbol , orderSn , err1 )
return err1
}
params := FutOrderPlace {
ApiId : apiInfo . Id ,
Symbol : symbol . GetSymbol ( ) ,
PositionSide : positionSide ,
Sid e: sid e ,
OrderTyp e: ot ,
Quantity : reversePosition . TotalReverseAmount ,
Price : price ,
StopPrice : pric e,
Profit : price ,
NewClientOrderId : newOrder . OrderSn ,
ClosePosition : close ,
}
futApiV2 := FuturesResetV2 { Service : e . Service }
err = futApiV2 . OrderPlaceLoop ( & apiInfo , params )
return e . createReverseOrder ( CreateOrderParams {
ApiInfo : & apiInfo ,
Symbol : symbol ,
Side : side ,
OrderType : ot ,
Price : price ,
TotalNum : reversePosition . TotalReverseAmount ,
Now : now ,
LastPric e: lastPric e,
Clos e: close ,
PositionId : reversePosition . Id ,
OrderSn : orderSn ,
PositionSide : positionSid e,
} )
}
func ( e * ReverseService ) getActiveReverseOrders ( positionId int ) ( [ ] DbModels . LineReverseOrder , error ) {
var orders [ ] DbModels . LineReverseOrder
err := e . Orm . Model ( & DbModels . LineReverseOrder { } ) .
Where ( "position_id =? and status =2" , positionId ) .
Select ( "id,position_side,side,type" ) . Find ( & orders ) . Error
if err != nil {
e . Log . Errorf ( "币安下单失败 symbol:%s custom:%s :%v" , symbol . GetSymbol ( ) , orderSn , err )
e . Log . Errorf ( "获取订单信息失败:%v" , err )
}
return orders , err
}
if err1 := e . Orm . Model ( & newOrder ) . Updates ( map [ string ] interface { } { "status" : 8 , "remark" : err . Error ( ) , "updated_at" : time . Now ( ) } ) . Error ; err1 != nil {
e . Log . Errorf ( "更新订单状态失败 symbol:%s custom:%s :%v" , newOrder . Symbol , newOrder . OrderSn , err1 )
func ( e * ReverseService ) getOppositeSide ( side string ) string {
if side == "SELL" {
return "BUY"
}
return "SELL"
}
func ( e * ReverseService ) hasOrderType ( orders [ ] DbModels . LineReverseOrder , types ... string ) bool {
typeSet := make ( map [ string ] bool )
for _ , t := range types {
typeSet [ t ] = true
}
for _ , o := range orders {
if typeSet [ o . Type ] {
return true
}
}
return false
}
func ( e * ReverseService ) calculatePrice ( positionSide string , base decimal . Decimal , ratio decimal . Decimal , isTakeProfit bool ) decimal . Decimal {
adjust := decimal . NewFromInt ( 100 )
if positionSide == "LONG" {
if isTakeProfit {
return base . Mul ( adjust . Add ( ratio ) . Div ( adjust ) ) . Truncate ( 4 )
}
return base . Mul ( adjust . Sub ( ratio ) . Div ( adjust ) ) . Truncate ( 4 )
}
if isTakeProfit {
return base . Mul ( adjust . Sub ( ratio ) . Div ( adjust ) ) . Truncate ( 4 )
}
return base . Mul ( adjust . Add ( ratio ) . Div ( adjust ) ) . Truncate ( 4 )
}
type CreateOrderParams struct {
ApiInfo * DbModels . LineApiUser
Order * DbModels . LineReverseOrder
Symbol * models . TradeSet
Side string
OrderType string
Price decimal . Decimal
TotalNum decimal . Decimal
Now time . Time
LastPrice decimal . Decimal
Close bool
PositionId int
OrderSn string
PositionSide string
}
func ( e * ReverseService ) createReverseOrder ( params CreateOrderParams ) error {
orderSn := params . OrderSn
if orderSn == "" {
orderSn = helper . GetOrderNo ( )
}
if params . PositionSide == "" && params . Order != nil {
params . PositionSide = params . Order . PositionSide
}
newOrder := DbModels . LineReverseOrder {
PositionId : params . PositionId ,
OrderSn : orderSn ,
OrderType : getOrderType ( params . OrderType ) ,
Status : 1 ,
Price : params . Price ,
TotalNum : params . TotalNum ,
Symbol : params . Symbol . GetSymbol ( ) ,
Side : params . Side ,
PositionSide : params . PositionSide ,
FollowOrderSn : params . OrderSn ,
Type : params . OrderType ,
SignPrice : params . LastPrice ,
Category : 1 ,
ApiId : params . ApiInfo . Id ,
IsAddPosition : 2 ,
TriggerTime : & params . Now ,
BuyPrice : params . TotalNum . Mul ( params . Price ) . Truncate ( int32 ( params . Symbol . PriceDigit ) ) ,
}
if err := e . Orm . Create ( & newOrder ) . Error ; err != nil {
e . Log . Errorf ( "保存反单止盈止损失败 symbol:%s custom:%s :%v" , params . Symbol . GetSymbol ( ) , newOrder . OrderSn , err )
return err
}
e . DoCancelTakeProfitBatch ( symbol . GetSymbol ( ) , positionSid e, side , orderType , & apiInfo )
futApiV2 := FuturesResetV2 { Servic e: e . Service }
params2 := FutOrderPlace {
ApiId : params . ApiInfo . Id ,
Symbol : params . Symbol . GetSymbol ( ) ,
PositionSide : newOrder . PositionSide ,
Side : newOrder . Side ,
OrderType : newOrder . Type ,
Quantity : newOrder . TotalNum ,
Price : newOrder . Price ,
StopPrice : newOrder . Price ,
Profit : newOrder . Price ,
NewClientOrderId : newOrder . OrderSn ,
ClosePosition : params . Close ,
}
err := futApiV2 . OrderPlaceLoop ( params . ApiInfo , params2 )
if err != nil {
e . Log . Errorf ( "币安下单失败 symbol:%s custom:%s :%v" , params . Symbol . GetSymbol ( ) , newOrder . OrderSn , err )
e . Orm . Model ( & newOrder ) . Updates ( map [ string ] interface { } { "status" : 8 , "remark" : err . Error ( ) , "updated_at" : time . Now ( ) } )
return err
}
e . DoCancelTakeProfitBatch ( params . Symbol . GetSymbol ( ) , newOrder . PositionSide , newOrder . Side , newOrder . OrderType , params . ApiInfo )
return nil
}
func getOrderType ( t string ) int {
if t == "TAKE_PROFIT_MARKET" || t == "TAKE_PROFIT" {
return 1
}
return 2
}
// // 重下止盈止损
// // mapData: 主单止盈止损回调
// func (e *ReverseService) ReTakeOrStopOrder(mapData *map[string]interface{}, orderSn string, mainApiInfo *DbModels.LineApiUser, symbol *models.TradeSet) error {
// orderType := 0 //订单类型 1-止盈 2-止损
// side, err := maphelper.GetString(*mapData, "S")
// if err != nil {
// return err
// }
// ot, err := maphelper.GetString(*mapData, "ot")
// if err != nil {
// return err
// }
// //反单止盈止损方向相反
// if side == "SELL" {
// side = "BUY"
// } else {
// side = "SELL"
// }
// positionSide, err := maphelper.GetString(*mapData, "ps")
// if err != nil {
// return err
// }
// if positionSide == "LONG" {
// positionSide = "SHORT"
// } else {
// positionSide = "LONG"
// }
// close := maphelper.GetBool(*mapData, "cp")
// stopPrice := maphelper.GetDecimal(*mapData, "sp")
// if stopPrice.IsZero() {
// e.Log.Errorf("获取止盈止损单触发价失败 symbol:%s custom:%s :%v", symbol, orderSn, err)
// return err
// }
// apiInfo, err := GetApiInfo(mainApiInfo.ReverseApiId)
// if err != nil {
// e.Log.Errorf("根据主单api获取反单api失败 symbol:%s custom:%s :%v", symbol, orderSn, err)
// return err
// }
// switch ot {
// case "STOP_MARKET", "STOP":
// orderType = 2
// case "TAKE_PROFIT_MARKET", "TAKE_PROFIT":
// orderType = 1
// default:
// return fmt.Errorf("不支持的订单类型 ot:%s", ot)
// }
// var reversePosition DbModels.LineReversePosition
// e.Orm.Model(&reversePosition).
// Where("symbol =? and reverse_api_id =? and position_side =? and reverse_status =1", symbol.GetSymbol(), apiInfo.Id, positionSide).
// First(&reversePosition)
// if reversePosition.Id == 0 {
// e.Log.Errorf("获取反单持仓失败 symbol:%s custom:%s :%v", symbol, orderSn, err)
// return err
// }
// mainPercent := decimal.NewFromInt(1)
// if !stopPrice.IsZero() && !reversePosition.AveragePrice.IsZero() {
// mainPercent = stopPrice.Div(reversePosition.AveragePrice)
// mainPercent = (mainPercent.Sub(decimal.NewFromInt(1))).Abs().Truncate(4)
// }
// var percent decimal.Decimal
// switch {
// //做多止损
// case orderType == 2 && positionSide == "LONG", orderType == 1 && positionSide == "SHORT":
// percent = decimal.NewFromInt(1).Sub(mainPercent)
// case orderType == 2 && positionSide == "SHORT", orderType == 1 && positionSide == "LONG":
// percent = decimal.NewFromInt(1).Add(mainPercent)
// default:
// return fmt.Errorf("不支持的订单类型 ot:%s, ps:%s", ot, positionSide)
// }
// now := time.Now()
// price := reversePosition.AveragePrice.Mul(percent).Truncate(int32(symbol.PriceDigit))
// lastPrice, _ := decimal.NewFromString(symbol.LastPrice)
// newOrder := DbModels.LineReverseOrder{
// PositionId: reversePosition.Id,
// OrderSn: helper.GetOrderNo(),
// OrderType: orderType,
// Status: 1,
// Price: price,
// TotalNum: reversePosition.TotalReverseAmount,
// Symbol: symbol.GetSymbol(),
// Side: side,
// PositionSide: positionSide,
// FollowOrderSn: orderSn,
// Type: ot,
// SignPrice: lastPrice,
// Category: 1,
// ApiId: apiInfo.Id,
// IsAddPosition: 2,
// TriggerTime: &now,
// BuyPrice: reversePosition.TotalReverseAmount.Mul(price).Truncate(int32(symbol.PriceDigit)),
// }
// if err1 := e.Orm.Create(&newOrder).Error; err1 != nil {
// e.Log.Errorf("保存反单止盈止损失败 symbol:%s custom:%s :%v", symbol, orderSn, err1)
// return err1
// }
// params := FutOrderPlace{
// ApiId: apiInfo.Id,
// Symbol: symbol.GetSymbol(),
// PositionSide: newOrder.PositionSide,
// Side: newOrder.Side,
// OrderType: ot,
// Quantity: newOrder.TotalNum,
// Price: price,
// StopPrice: price,
// Profit: price,
// NewClientOrderId: newOrder.OrderSn,
// ClosePosition: close,
// }
// futApiV2 := FuturesResetV2{Service: e.Service}
// err = futApiV2.OrderPlaceLoop(&apiInfo, params)
// if err != nil {
// e.Log.Errorf("币安下单失败 symbol:%s custom:%s :%v", symbol.GetSymbol(), orderSn, err)
// if err1 := e.Orm.Model(&newOrder).Updates(map[string]interface{}{"status": 8, "remark": err.Error(), "updated_at": time.Now()}).Error; err1 != nil {
// e.Log.Errorf("更新订单状态失败 symbol:%s custom:%s :%v", newOrder.Symbol, newOrder.OrderSn, err1)
// }
// return err
// }
// e.DoCancelTakeProfitBatch(symbol.GetSymbol(), newOrder.PositionSide, newOrder.Side, newOrder.OrderType, &apiInfo)
// return nil
// }