1撤销限价后 市价分单
This commit is contained in:
261
app/jobs/jobs.go
261
app/jobs/jobs.go
@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/driver/mysql"
|
||||
|
||||
@ -158,7 +159,6 @@ func (t AutoPlaceOrder) Exec(arg interface{}) error {
|
||||
}
|
||||
|
||||
func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
||||
|
||||
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
||||
defer logger.Info(str)
|
||||
var db *gorm.DB
|
||||
@ -188,7 +188,10 @@ func (t LimitOrderTimeoutDuration) Exec(arg interface{}) error {
|
||||
defer lock.Release()
|
||||
limitOrderTimeoutDuration := utility.StringAsInt64(resp.ConfigValue)
|
||||
orders := make([]models.LinePreOrder, 0)
|
||||
err := db.Model(&models.LinePreOrder{}).Where("status = '5' AND main_order_type = 'LIMIT' AND order_type in ('4') AND updated_at < ?", time.Now().Add(-time.Duration(limitOrderTimeoutDuration)*time.Second)).Find(&orders).Error
|
||||
err := db.Model(&models.LinePreOrder{}).
|
||||
Where("status = '5' AND main_order_type = 'LIMIT' AND order_type in ('4') AND updated_at < ?", time.Now().Add(-time.Duration(limitOrderTimeoutDuration)*time.Second)).
|
||||
Preload("Childs").
|
||||
Find(&orders).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -228,6 +231,7 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
for i := 0; i < 3; i++ {
|
||||
err = spotApi.CancelOpenOrderByOrderSn(apiUserinfo, order.Symbol, order.OrderSn)
|
||||
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -237,11 +241,12 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
} else {
|
||||
var remainingQuantity decimal.Decimal
|
||||
spotOrder, err := spotApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||
|
||||
if err == nil {
|
||||
origQty := utility.StrToDecimal(spotOrder.OrigQuoteOrderQty)
|
||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
||||
remainingQuantity = origQty.Sub(excuteQty).Abs()
|
||||
remainingQuantity = origQty.Sub(excuteQty).Abs().Truncate(int32(tradeSet.AmountDigit))
|
||||
}
|
||||
|
||||
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
||||
@ -249,36 +254,62 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
return nil
|
||||
}
|
||||
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||
newClientOrderId := snowflakehelper.GetOrderId()
|
||||
maxMarketQty := decimal.NewFromFloat(tradeSet.MarketMaxQty).Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
||||
order.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
order.MainOrderType = "MARKET"
|
||||
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).Error
|
||||
// if config.ApplicationConfig.Mode == "dev" {
|
||||
// maxMarketQty = decimal.NewFromFloat(10)
|
||||
// }
|
||||
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
||||
return err
|
||||
}
|
||||
params := binanceservice.OrderPlacementService{
|
||||
ApiId: order.ApiId,
|
||||
Symbol: order.Symbol,
|
||||
Side: order.Site,
|
||||
Type: "MARKET",
|
||||
TimeInForce: "GTC",
|
||||
Price: utility.StringToDecimal(order.Price),
|
||||
StopPrice: utility.StrToDecimal(order.Price),
|
||||
Quantity: remainingQuantity,
|
||||
NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
||||
}
|
||||
if err := spotApi.OrderPlace(db, params); err != nil {
|
||||
logger.Error(fmt.Sprintf("重新下市价单失败 err:%+v", err))
|
||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + "err:" + err.Error()}).Error
|
||||
if remainingQuantity.Cmp(maxMarketQty) > 0 && maxMarketQty.Cmp(decimal.Zero) > 0 {
|
||||
multiple := remainingQuantity.Div(maxMarketQty).Abs().IntPart()
|
||||
remainder := remainingQuantity.Mod(maxMarketQty)
|
||||
saveOrders := make([]models.LinePreOrder, 0)
|
||||
|
||||
desc := fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||
|
||||
// 创建 multiple 个订单
|
||||
for i := 0; i < int(multiple); i++ {
|
||||
saveOrders = append(saveOrders, createNewOrder(order, maxMarketQty, desc))
|
||||
}
|
||||
|
||||
// 处理余数
|
||||
if remainder.Cmp(decimal.Zero) > 0 {
|
||||
saveOrders = append(saveOrders, createNewOrder(order, remainder.Truncate(int32(tradeSet.AmountDigit)), desc))
|
||||
}
|
||||
|
||||
if err := db.Create(&saveOrders).Error; err != nil {
|
||||
logger.Errorf("市价订单拆分后保存失败,err:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for index := range saveOrders {
|
||||
newNum := utility.StrToDecimal(saveOrders[index].Num)
|
||||
|
||||
if err := newSpotOrderClosePosition(saveOrders[index], newNum, spotApi, db); err != nil {
|
||||
logger.Errorf("市价订单拆分后保存失败,err:", err)
|
||||
}
|
||||
|
||||
if index == len(saveOrders)-1 {
|
||||
orderCopy := saveOrders[index] // 复制数据
|
||||
|
||||
binanceservice.HandleSpotMarketSliceTakeProfit(db, orderCopy, order.Id, apiUserinfo, tradeSet)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newClientOrderId := snowflakehelper.GetOrderId()
|
||||
|
||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
||||
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||
order.MainOrderType = "MARKET"
|
||||
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).Error
|
||||
|
||||
if err != nil {
|
||||
logger.Error("下单失败后修改订单失败")
|
||||
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
if err := newSpotOrderClosePosition(order, remainingQuantity, spotApi, db); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -287,12 +318,38 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
||||
return nil
|
||||
}
|
||||
|
||||
// 现货市价单平仓
|
||||
func newSpotOrderClosePosition(order models.LinePreOrder, remainingQuantity decimal.Decimal, spotApi binanceservice.SpotRestApi, db *gorm.DB) error {
|
||||
params := binanceservice.OrderPlacementService{
|
||||
ApiId: order.ApiId,
|
||||
Symbol: order.Symbol,
|
||||
Side: order.Site,
|
||||
Type: "MARKET",
|
||||
TimeInForce: "GTC",
|
||||
Price: utility.StringToDecimal(order.Price),
|
||||
StopPrice: utility.StrToDecimal(order.Price),
|
||||
Quantity: remainingQuantity,
|
||||
NewClientOrderId: order.OrderSn,
|
||||
}
|
||||
if err := spotApi.OrderPlaceLoop(db, params, 3); err != nil {
|
||||
logger.Error(fmt.Sprintf("重新下市价单失败 err:%+v", err))
|
||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + "err:" + err.Error()}).Error
|
||||
|
||||
if err != nil {
|
||||
logger.Error("下单失败后修改订单失败")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReFutOrderPlace 重下合约市价单
|
||||
func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.LinePreOrder, apiUserinfo models.LineApiUser, futApi binanceservice.FutRestApi) error {
|
||||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
err := futApi.CancelFutOrder(apiUserinfo, order.Symbol, order.OrderSn)
|
||||
if err == nil || strings.Contains(err.Error(), "该交易对没有订单") {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -302,11 +359,12 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
||||
} else {
|
||||
var remainingQuantity decimal.Decimal
|
||||
spotOrder, err := futApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 1)
|
||||
|
||||
if err == nil {
|
||||
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
||||
remainingQuantity = origQty.Sub(excuteQty).Abs()
|
||||
remainingQuantity = origQty.Sub(excuteQty).Abs().Truncate(int32(tradeSet.AmountDigit))
|
||||
}
|
||||
|
||||
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
||||
@ -314,51 +372,62 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
||||
return nil
|
||||
}
|
||||
|
||||
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||
qty := decimal.NewFromFloat(tradeSet.MarketMaxQty)
|
||||
maxMarketQty := qty.Truncate(int32(tradeSet.AmountDigit))
|
||||
|
||||
newClientOrderId := snowflakehelper.GetOrderId()
|
||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||
|
||||
// var newOrder models.LinePreOrder
|
||||
// copier.Copy(&newOrder, order)
|
||||
// newOrder.Id = 0
|
||||
// newOrder.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||
// newOrder.CreatedAt = time.Now()
|
||||
// newOrder.MainOrderType = "MARKET"
|
||||
// err = db.Model(&models.LinePreOrder{}).Create(&newOrder).Error
|
||||
|
||||
var positionSide string
|
||||
|
||||
if order.Site == "BUY" {
|
||||
positionSide = "SHORT"
|
||||
} else {
|
||||
positionSide = "LONG"
|
||||
}
|
||||
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn}).Error
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("生成合约新市价单失败 err:%+v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
// params := binanceservice.FutOrderPlace{
|
||||
// ApiId: order.ApiId,
|
||||
// Symbol: order.Symbol,
|
||||
// Side: order.Site,
|
||||
// Quantity: remainingQuantity,
|
||||
// Price: utility.StringToDecimal(order.Price),
|
||||
// SideType: "MARKET",
|
||||
// OpenOrder: 0,
|
||||
// OrderType: "MARKET",
|
||||
// NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
||||
// if config.ApplicationConfig.Mode == "dev" {
|
||||
// maxMarketQty = decimal.NewFromFloat(10)
|
||||
// }
|
||||
|
||||
if err := futApi.ClosePositionLoop(order.Symbol, order.OrderSn, remainingQuantity, order.Site, positionSide, apiUserinfo, "MARKET", "0", decimal.Zero, 3); err != nil {
|
||||
logger.Error(fmt.Sprintf("重新下合约市价单失败 err:%+v", err))
|
||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + " err:" + err.Error()}).Error
|
||||
//数量超过最大数量,则拆单
|
||||
if remainingQuantity.Cmp(maxMarketQty) > 0 && maxMarketQty.Cmp(decimal.Zero) > 0 {
|
||||
multiple := remainingQuantity.Div(maxMarketQty).Abs().IntPart()
|
||||
remainder := remainingQuantity.Mod(maxMarketQty)
|
||||
saveOrders := make([]models.LinePreOrder, 0)
|
||||
|
||||
desc := fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||
|
||||
// 创建 multiple 个订单
|
||||
for i := 0; i < int(multiple); i++ {
|
||||
saveOrders = append(saveOrders, createNewOrder(order, maxMarketQty, desc))
|
||||
}
|
||||
|
||||
// 处理余数
|
||||
if remainder.Cmp(decimal.Zero) > 0 {
|
||||
saveOrders = append(saveOrders, createNewOrder(order, remainder.Truncate(int32(tradeSet.AmountDigit)), desc))
|
||||
}
|
||||
|
||||
if err := db.Create(&saveOrders).Error; err != nil {
|
||||
logger.Errorf("市价订单拆分后保存失败,err:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for index := range saveOrders {
|
||||
newNum := utility.StrToDecimal(saveOrders[index].Num)
|
||||
|
||||
if err := newOrderClosePosition(saveOrders[index], futApi, newNum.Truncate(int32(tradeSet.AmountDigit)), apiUserinfo, db); err != nil {
|
||||
logger.Errorf("市价单拆分后下单失败 orderSn:%s, err:%s", saveOrders[index].OrderSn, err)
|
||||
}
|
||||
|
||||
if index == len(saveOrders)-1 {
|
||||
orderCopy := saveOrders[index] // 复制数据
|
||||
binanceservice.HandleMarketSliceTakeProfit(db, orderCopy, order.Id, apiUserinfo, tradeSet)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newClientOrderId := snowflakehelper.GetOrderId()
|
||||
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||
|
||||
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn}).Error
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("生成合约新市价单失败 err:%+v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
err = newOrderClosePosition(order, futApi, remainingQuantity, apiUserinfo, db)
|
||||
if err != nil {
|
||||
logger.Error("下单失败后修改订单失败")
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -366,6 +435,54 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
||||
return err
|
||||
}
|
||||
|
||||
// 复制订单
|
||||
func createNewOrder(order models.LinePreOrder, num decimal.Decimal, desc string) models.LinePreOrder {
|
||||
newOrder := models.LinePreOrder{}
|
||||
copier.Copy(&newOrder, order)
|
||||
|
||||
newOrder.Id = 0
|
||||
newOrder.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
newOrder.Num = num.String()
|
||||
newOrder.Desc = desc
|
||||
newOrder.MainOrderType = "MARKET"
|
||||
newOrder.Status = 0
|
||||
|
||||
// 重新创建 Childs,并正确赋值 `Pid`
|
||||
var newChilds []models.LinePreOrder
|
||||
for _, child := range order.Childs {
|
||||
newChild := child
|
||||
newChild.Id = 0
|
||||
newChild.Pid = 0
|
||||
newChild.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||
newChild.CreatedAt = time.Now()
|
||||
newChilds = append(newChilds, newChild)
|
||||
}
|
||||
newOrder.Childs = newChilds // 重新赋值子订单,避免浅拷贝问题
|
||||
|
||||
return newOrder
|
||||
}
|
||||
|
||||
// 新市价单
|
||||
func newOrderClosePosition(order models.LinePreOrder, futApi binanceservice.FutRestApi, remainingQuantity decimal.Decimal, apiUserinfo models.LineApiUser, db *gorm.DB) error {
|
||||
var positionSide string
|
||||
|
||||
if order.Site == "BUY" {
|
||||
positionSide = "SHORT"
|
||||
} else {
|
||||
positionSide = "LONG"
|
||||
}
|
||||
|
||||
if err := futApi.ClosePositionLoop(order.Symbol, order.OrderSn, remainingQuantity, order.Site, positionSide, apiUserinfo, "MARKET", "0", decimal.Zero, 3); err != nil {
|
||||
logger.Error(fmt.Sprintf("重新下合约市价单失败 err:%+v", err))
|
||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + " err:" + err.Error()}).Error
|
||||
if err != nil {
|
||||
logger.Error("下单失败后修改订单失败")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l ListenSymbol) Exec(arg interface{}) error {
|
||||
str := time.Now().Format(timeFormat) + " [INFO] JobCore ClearLogJob exec success"
|
||||
defer logger.Info(str)
|
||||
|
||||
Reference in New Issue
Block a user