1、主单增加减仓、加仓状态
2、bug修复
This commit is contained in:
@ -625,6 +625,10 @@ func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Symbol == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// data := dto.CalculateBreakEvenRatioResp{}
|
// data := dto.CalculateBreakEvenRatioResp{}
|
||||||
_, err = s.GenerateOrder(&req)
|
_, err = s.GenerateOrder(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -183,7 +183,7 @@ func (s *LinePreOrderDeleteReq) GetId() interface{} {
|
|||||||
type LineAddPreOrderReq struct {
|
type LineAddPreOrderReq struct {
|
||||||
ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型
|
ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型
|
||||||
OrderType int `json:"order_type"` //订单类型
|
OrderType int `json:"order_type"` //订单类型
|
||||||
Symbol string `json:"symbol" vd:"len($)>0"` //交易对
|
Symbol string `json:"symbol"` //交易对
|
||||||
ApiUserId string `json:"api_id" ` //下单用户
|
ApiUserId string `json:"api_id" ` //下单用户
|
||||||
Site string `json:"site" ` //购买方向
|
Site string `json:"site" ` //购买方向
|
||||||
BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U
|
BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U
|
||||||
@ -341,15 +341,15 @@ func (req LineBatchAddPreOrderReq) CheckParams() error {
|
|||||||
return errors.New("加仓单下跌价格不能为空")
|
return errors.New("加仓单下跌价格不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.ReduceNumRatio.IsZero() || v.ReduceNumRatio.Cmp(decimal.Zero) > 0 {
|
if v.ReduceNumRatio.IsZero() || v.ReduceNumRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
||||||
return errors.New("减仓数量不正确")
|
return errors.New("减仓数量不正确")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.ReducePriceRatio.IsZero() || v.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
|
if v.ReducePriceRatio.IsZero() || v.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
||||||
return errors.New("减仓下跌价格不正确")
|
return errors.New("减仓下跌价格不正确")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.ReduceTakeProfitRatio.IsZero() || v.ReduceTakeProfitRatio.Cmp(decimal.Zero) > 0 {
|
if v.ReduceTakeProfitRatio.IsZero() || v.ReduceTakeProfitRatio.Cmp(decimal.NewFromInt(100)) > 0 {
|
||||||
return errors.New("减仓后止盈价格不正确")
|
return errors.New("减仓后止盈价格不正确")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,8 +371,8 @@ type LeverReq struct {
|
|||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Leverage int `json:"leverage"`
|
Leverage int `json:"leverage"`
|
||||||
GroupId int `json:"group_id"`
|
GroupId int `json:"group_id"`
|
||||||
IsAll int `json:"is_all"` // 1= 全部 0=不是全部
|
IsAll int `json:"is_all"` // 1= 全部 0=不是全部
|
||||||
ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type
|
ExchangeType string `json:"exchangeType"` //交易所类型 字典exchange_type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c LeverReq) CheckParams() error {
|
func (c LeverReq) CheckParams() error {
|
||||||
@ -387,11 +387,11 @@ func (c LeverReq) CheckParams() error {
|
|||||||
|
|
||||||
type MarginTypeReq struct {
|
type MarginTypeReq struct {
|
||||||
ApiUserIds string `json:"api_user_ids"`
|
ApiUserIds string `json:"api_user_ids"`
|
||||||
Symbol string `json:"symbol"` // 交易对
|
Symbol string `json:"symbol"` // 交易对
|
||||||
MarginType string `json:"margin_type"` //全仓 CROSSED 逐仓 ISOLATED
|
MarginType string `json:"margin_type"` //全仓 CROSSED 逐仓 ISOLATED
|
||||||
GroupId int `json:"group_id"` // 交易对组id
|
GroupId int `json:"group_id"` // 交易对组id
|
||||||
IsAll int `json:"is_all"` // 1= 全部 0=不是全部
|
IsAll int `json:"is_all"` // 1= 全部 0=不是全部
|
||||||
ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type
|
ExchangeType string `json:"exchangeType"` //交易所类型 字典exchange_type
|
||||||
}
|
}
|
||||||
|
|
||||||
type CancelOpenOrderReq struct {
|
type CancelOpenOrderReq struct {
|
||||||
@ -399,7 +399,7 @@ type CancelOpenOrderReq struct {
|
|||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
OrderSn string `json:"order_sn"`
|
OrderSn string `json:"order_sn"`
|
||||||
OrderType int `json:"order_type"`
|
OrderType int `json:"order_type"`
|
||||||
ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type
|
ExchangeType string `json:"exchangeType"` //交易所类型 字典exchange_type
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetChildOrderReq struct {
|
type GetChildOrderReq struct {
|
||||||
|
|||||||
@ -323,7 +323,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
|
|
||||||
//获取交易对
|
//获取交易对
|
||||||
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
|
tradeSet, _ := helper.GetObjString[models2.TradeSet](helper.DefaultRedis, key)
|
||||||
orderCount := e.CheckRepeatOrder(req.OrderType, id, req.Site, tradeSet.Coin)
|
orderCount := e.CheckRepeatOrder(req.SymbolType, id, req.Site, tradeSet.Coin)
|
||||||
if orderCount > 0 {
|
if orderCount > 0 {
|
||||||
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 该交易对已存在,请勿重复下单", id, req.Symbol))
|
*errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 该交易对已存在,请勿重复下单", id, req.Symbol))
|
||||||
continue
|
continue
|
||||||
@ -571,6 +571,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
stopOrder.MainId = AddOrder.Id
|
stopOrder.MainId = AddOrder.Id
|
||||||
stopOrder.OrderType = 4
|
stopOrder.OrderType = 4
|
||||||
stopOrder.Status = 0
|
stopOrder.Status = 0
|
||||||
|
stopOrder.BuyPrice = "0"
|
||||||
stopOrder.Rate = req.ReducePriceRatio.String()
|
stopOrder.Rate = req.ReducePriceRatio.String()
|
||||||
stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4))
|
stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4))
|
||||||
stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String()
|
stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
@ -807,9 +808,9 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CheckRepeatOrder 检查重复下单 检查基础货币
|
// CheckRepeatOrder 检查重复下单 检查基础货币
|
||||||
func (e *LinePreOrder) CheckRepeatOrder(orderType int, apiUserId, site, baseCoin string) int64 {
|
func (e *LinePreOrder) CheckRepeatOrder(symbolType int, apiUserId, site, baseCoin string) int64 {
|
||||||
var count int64
|
var count int64
|
||||||
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND pid=0 AND symbol like ? AND order_type = ? AND site = ? AND `status` IN (1,5,6)", apiUserId, baseCoin+"%", orderType, site).Count(&count)
|
e.Orm.Model(&models.LinePreOrder{}).Where("api_id = ? AND pid=0 AND symbol like ? AND symbol_type = ? AND site = ? AND `status` IN (1,5,6)", apiUserId, baseCoin+"%", symbolType, site).Count(&count)
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,6 +898,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
|
|||||||
req.Price = batchReq.Price
|
req.Price = batchReq.Price
|
||||||
req.Profit = batchReq.Profit
|
req.Profit = batchReq.Profit
|
||||||
req.Ext = batchReq.Ext
|
req.Ext = batchReq.Ext
|
||||||
|
req.SymbolType = batchReq.SymbolType
|
||||||
// req.StopPrice = batchReq.StopPrice
|
// req.StopPrice = batchReq.StopPrice
|
||||||
req.ReducePriceRatio = batchReq.ReducePriceRatio
|
req.ReducePriceRatio = batchReq.ReducePriceRatio
|
||||||
req.PriceType = batchReq.PriceType
|
req.PriceType = batchReq.PriceType
|
||||||
@ -1176,6 +1178,8 @@ func (e *LinePreOrder) ClearAll() error {
|
|||||||
"stop_loss_markt",
|
"stop_loss_markt",
|
||||||
"_PreSpotOrderList_",
|
"_PreSpotOrderList_",
|
||||||
"_PreFutOrderList_",
|
"_PreFutOrderList_",
|
||||||
|
"spot_reduce_list",
|
||||||
|
"futures_reduce_list",
|
||||||
}
|
}
|
||||||
err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...)
|
err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/sdk"
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
@ -225,19 +226,28 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
|||||||
logger.Error(fmt.Sprintf("取消现货委托失败:order_sn:%s err:%+v", order.OrderSn, err))
|
logger.Error(fmt.Sprintf("取消现货委托失败:order_sn:%s err:%+v", order.OrderSn, err))
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
var remainingQuantity decimal.Decimal
|
||||||
|
spotOrder, err := spotApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
origQty := utility.StrToDecimal(spotOrder.OrigQuoteOrderQty)
|
||||||
|
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
||||||
|
remainingQuantity = origQty.Sub(excuteQty).Abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
||||||
|
logger.Errorf("剩余数量为0 无需重新下市价单mainid:%v", order.MainId)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||||
newClientOrderId := snowflakehelper.GetOrderId()
|
newClientOrderId := snowflakehelper.GetOrderId()
|
||||||
|
|
||||||
|
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn)
|
||||||
order.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
order.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId())
|
||||||
order.MainOrderType = "MARKET"
|
order.MainOrderType = "MARKET"
|
||||||
// var newOrder models.LinePreOrder
|
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).Error
|
||||||
// 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
|
|
||||||
err := db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).Error
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err))
|
||||||
@ -251,7 +261,7 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li
|
|||||||
TimeInForce: "GTC",
|
TimeInForce: "GTC",
|
||||||
Price: utility.StringToDecimal(order.Price),
|
Price: utility.StringToDecimal(order.Price),
|
||||||
StopPrice: utility.StrToDecimal(order.Price),
|
StopPrice: utility.StrToDecimal(order.Price),
|
||||||
Quantity: utility.StringToDecimal(order.Num),
|
Quantity: remainingQuantity,
|
||||||
NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
||||||
}
|
}
|
||||||
if err := spotApi.OrderPlace(db, params); err != nil {
|
if err := spotApi.OrderPlace(db, params); err != nil {
|
||||||
@ -281,8 +291,24 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
|||||||
logger.Error(fmt.Sprintf("取消现货委托失败:order_sn:%s err:%+v", order.OrderSn, err))
|
logger.Error(fmt.Sprintf("取消现货委托失败:order_sn:%s err:%+v", order.OrderSn, err))
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
var remainingQuantity decimal.Decimal
|
||||||
|
spotOrder, err := futApi.GetOrderByOrderSnLoop(order.Symbol, order.OrderSn, apiUserinfo, 4)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
origQty := utility.StrToDecimal(spotOrder.OrigQty)
|
||||||
|
excuteQty := utility.StrToDecimal(spotOrder.ExecutedQty)
|
||||||
|
remainingQuantity = origQty.Sub(excuteQty).Abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if remainingQuantity.Cmp(decimal.Zero) <= 0 {
|
||||||
|
logger.Errorf("剩余数量为0 无需重新下市价单mainid:%v", order.MainId)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tradeSet, _ := binanceservice.GetTradeSet(order.Symbol, 0)
|
||||||
|
|
||||||
newClientOrderId := snowflakehelper.GetOrderId()
|
newClientOrderId := snowflakehelper.GetOrderId()
|
||||||
orderType := "MARKET"
|
order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String()
|
||||||
order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn)
|
||||||
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
order.OrderSn = utility.Int64ToString(newClientOrderId)
|
||||||
|
|
||||||
@ -294,31 +320,32 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin
|
|||||||
// newOrder.MainOrderType = "MARKET"
|
// newOrder.MainOrderType = "MARKET"
|
||||||
// err = db.Model(&models.LinePreOrder{}).Create(&newOrder).Error
|
// 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
|
err = db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(fmt.Sprintf("生成合约新市价单失败 err:%+v", err))
|
logger.Error(fmt.Sprintf("生成合约新市价单失败 err:%+v", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if order.OrderType == 4 {
|
// params := binanceservice.FutOrderPlace{
|
||||||
orderType = "STOP_MARKET"
|
// 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),
|
||||||
|
// }
|
||||||
|
|
||||||
params := binanceservice.FutOrderPlace{
|
if err := futApi.ClosePositionLoop(order.Symbol, order.OrderSn, remainingQuantity, order.Site, positionSide, apiUserinfo, "MARKET", "0", decimal.Zero, 3); err != nil {
|
||||||
ApiId: order.ApiId,
|
|
||||||
Symbol: order.Symbol,
|
|
||||||
Side: order.Site,
|
|
||||||
Quantity: utility.StringToDecimal(order.Num),
|
|
||||||
Price: utility.StringToDecimal(order.Price),
|
|
||||||
SideType: "MARKET",
|
|
||||||
OpenOrder: 0,
|
|
||||||
StopPrice: utility.StringToDecimal(order.Price),
|
|
||||||
Profit: utility.StringToDecimal(order.Price),
|
|
||||||
OrderType: orderType,
|
|
||||||
NewClientOrderId: utility.Int64ToString(newClientOrderId),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := futApi.OrderPlace(db, params); err != nil {
|
|
||||||
logger.Error(fmt.Sprintf("重新下合约市价单失败 err:%+v", err))
|
logger.Error(fmt.Sprintf("重新下合约市价单失败 err:%+v", err))
|
||||||
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + " err:" + err.Error()}).Error
|
err := db.Model(&order).Updates(map[string]interface{}{"status": "2", "desc": order.Desc + " err:" + err.Error()}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -22,3 +22,55 @@ type StoplossMarket struct {
|
|||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Type int `json:"type" comment:"对冲类型 1-现货 2-合约"`
|
Type int `json:"type" comment:"对冲类型 1-现货 2-合约"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BinanceSpotOrder struct {
|
||||||
|
Symbol string `json:"symbol"` // 交易对
|
||||||
|
OrderID int64 `json:"orderId"` // 系统的订单ID
|
||||||
|
OrderListID int64 `json:"orderListId"` // 除非此单是订单列表的一部分, 否则此值为 -1
|
||||||
|
ClientOrderID string `json:"clientOrderId"` // 客户自己设置的ID
|
||||||
|
Price string `json:"price"` // 订单价格
|
||||||
|
OrigQty string `json:"origQty"` // 用户设置的原始订单数量
|
||||||
|
ExecutedQty string `json:"executedQty"` // 交易的订单数量
|
||||||
|
OrigQuoteOrderQty string `json:"origQuoteOrderQty"` // 原始的交易金额
|
||||||
|
CummulativeQuoteQty string `json:"cummulativeQuoteQty"` // 累计交易的金额
|
||||||
|
Status string `json:"status"` // 订单状态
|
||||||
|
TimeInForce string `json:"timeInForce"` // 订单的时效方式
|
||||||
|
Type string `json:"type"` // 订单类型,比如市价单,现价单等
|
||||||
|
Side string `json:"side"` // 订单方向,买还是卖
|
||||||
|
StopPrice string `json:"stopPrice"` // 止损价格
|
||||||
|
IcebergQty string `json:"icebergQty"` // 冰山数量
|
||||||
|
Time int64 `json:"time"` // 订单时间
|
||||||
|
UpdateTime int64 `json:"updateTime"` // 最后更新时间
|
||||||
|
IsWorking bool `json:"isWorking"` // 订单是否出现在orderbook中
|
||||||
|
WorkingTime int64 `json:"workingTime"` // 订单添加到 order book 的时间
|
||||||
|
SelfTradePreventionMode string `json:"selfTradePreventionMode"` // 如何处理自我交易模式
|
||||||
|
}
|
||||||
|
|
||||||
|
type BinanceFutureOrder struct {
|
||||||
|
AvgPrice string `json:"avgPrice"` // 平均成交价
|
||||||
|
ClientOrderID string `json:"clientOrderId"` // 用户自定义的订单号
|
||||||
|
CumQuote string `json:"cumQuote"` // 成交金额
|
||||||
|
ExecutedQty string `json:"executedQty"` // 成交量
|
||||||
|
OrderID int64 `json:"orderId"` // 系统订单号
|
||||||
|
OrigQty string `json:"origQty"` // 原始委托数量
|
||||||
|
OrigType string `json:"origType"` // 触发前订单类型
|
||||||
|
Price string `json:"price"` // 委托价格
|
||||||
|
ReduceOnly bool `json:"reduceOnly"` // 是否仅减仓
|
||||||
|
Side string `json:"side"` // 买卖方向
|
||||||
|
PositionSide string `json:"positionSide"` // 持仓方向
|
||||||
|
Status string `json:"status"` // 订单状态
|
||||||
|
StopPrice string `json:"stopPrice"` // 触发价,对`TRAILING_STOP_MARKET`无效
|
||||||
|
ClosePosition bool `json:"closePosition"` // 是否条件全平仓
|
||||||
|
Symbol string `json:"symbol"` // 交易对
|
||||||
|
Time int64 `json:"time"` // 订单时间
|
||||||
|
TimeInForce string `json:"timeInForce"` // 有效方法
|
||||||
|
Type string `json:"type"` // 订单类型
|
||||||
|
ActivatePrice string `json:"activatePrice"` // 跟踪止损激活价格, 仅`TRAILING_STOP_MARKET` 订单返回此字段
|
||||||
|
PriceRate string `json:"priceRate"` // 跟踪止损回调比例, 仅`TRAILING_STOP_MARKET` 订单返回此字段
|
||||||
|
UpdateTime int64 `json:"updateTime"` // 更新时间
|
||||||
|
WorkingType string `json:"workingType"` // 条件价格触发类型
|
||||||
|
PriceProtect bool `json:"priceProtect"` // 是否开启条件单触发保护
|
||||||
|
PriceMatch string `json:"priceMatch"` // 盘口价格下单模式
|
||||||
|
SelfTradePreventionMode string `json:"selfTradePreventionMode"` // 订单自成交保护模式
|
||||||
|
GoodTillDate int64 `json:"goodTillDate"` // 订单TIF为GTD时的自动取消时间
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
"go-admin/models"
|
"go-admin/models"
|
||||||
|
"go-admin/models/binancedto"
|
||||||
"go-admin/models/spot"
|
"go-admin/models/spot"
|
||||||
"go-admin/pkg/httputils"
|
"go-admin/pkg/httputils"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
@ -529,3 +530,61 @@ func (e SpotRestApi) GetSpotSymbolLastPrice(targetSymbol string) (lastPrice deci
|
|||||||
// }
|
// }
|
||||||
return lastPrice
|
return lastPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e SpotRestApi) GetOrderByOrderSn(symbol, orderSn string, apiUserInfo DbModels.LineApiUser) (order binancedto.BinanceSpotOrder, err error) {
|
||||||
|
result := binancedto.BinanceSpotOrder{}
|
||||||
|
params := map[string]string{
|
||||||
|
"symbol": symbol,
|
||||||
|
"origClientOrderId": orderSn,
|
||||||
|
}
|
||||||
|
|
||||||
|
client := GetClient(&apiUserInfo)
|
||||||
|
|
||||||
|
body, code, err := client.SendSpotAuth("/api/v3/order", "GET", params)
|
||||||
|
if err != nil || code != 200 {
|
||||||
|
log.Error("查询现货委托 参数:", params)
|
||||||
|
log.Error("查询现货委托失败 code:", code)
|
||||||
|
log.Error("查询现货委托失败 err:", err)
|
||||||
|
dataMap := make(map[string]interface{})
|
||||||
|
if err.Error() != "" {
|
||||||
|
if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
code, ok := dataMap["code"]
|
||||||
|
if ok {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%s", apiUserInfo.Id, symbol, ErrorMaps[code.(float64)])
|
||||||
|
}
|
||||||
|
if strings.Contains(err.Error(), "Unknown order sent.") {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, ErrorMaps[-2011])
|
||||||
|
}
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
sonic.Unmarshal(body, &result)
|
||||||
|
|
||||||
|
if result.OrderID == 0 {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, "订单不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
查询现货委托
|
||||||
|
*/
|
||||||
|
func (e SpotRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo DbModels.LineApiUser, retryCount int) (order binancedto.BinanceSpotOrder, err error) {
|
||||||
|
result, err := e.GetOrderByOrderSn(symbol, ordersn, apiUserInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
for x := 1; x < retryCount; x++ {
|
||||||
|
result, err = e.GetOrderByOrderSn(symbol, ordersn, apiUserInfo)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|||||||
@ -215,3 +215,35 @@ func TestFutOrderPlace(t *testing.T) {
|
|||||||
fmt.Println("err:", err)
|
fmt.Println("err:", err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFutureQueryOrder(t *testing.T) {
|
||||||
|
futureApi := FutRestApi{}
|
||||||
|
// dsn := "root:root@tcp(192.168.1.12:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
// db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("192.168.1.12:6379", "", 2)
|
||||||
|
apiUserInfo, _ := GetApiInfo(49)
|
||||||
|
order, err := futureApi.GetOrderByOrderSnLoop("TRUMPUSDT", "380211842506555392", apiUserInfo, 3)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("future order:", order)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSpotQueryOrder(t *testing.T) {
|
||||||
|
spotApi := SpotRestApi{}
|
||||||
|
// dsn := "root:root@tcp(192.168.1.12:3306)/go_exchange_single?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
// db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("192.168.1.12:6379", "", 2)
|
||||||
|
apiUserInfo, _ := GetApiInfo(49)
|
||||||
|
order, err := spotApi.GetOrderByOrderSnLoop("ADAUSDT", "380577197825458177", apiUserInfo, 3)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("spot order:", order)
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/helper"
|
"go-admin/common/helper"
|
||||||
"go-admin/models"
|
"go-admin/models"
|
||||||
|
"go-admin/models/binancedto"
|
||||||
"go-admin/models/futuresdto"
|
"go-admin/models/futuresdto"
|
||||||
"go-admin/pkg/httputils"
|
"go-admin/pkg/httputils"
|
||||||
"go-admin/pkg/utility"
|
"go-admin/pkg/utility"
|
||||||
@ -936,3 +937,66 @@ func (e FutRestApi) GetFutSymbolLastPrice(targetSymbol string) (lastPrice decima
|
|||||||
// }
|
// }
|
||||||
return lastPrice
|
return lastPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e FutRestApi) GetOrderByOrderSn(symbol, orderSn string, apiUserInfo DbModels.LineApiUser) (order binancedto.BinanceFutureOrder, err error) {
|
||||||
|
result := binancedto.BinanceFutureOrder{}
|
||||||
|
params := map[string]string{
|
||||||
|
"symbol": symbol,
|
||||||
|
"origClientOrderId": orderSn,
|
||||||
|
}
|
||||||
|
|
||||||
|
client := GetClient(&apiUserInfo)
|
||||||
|
|
||||||
|
body, code, err := client.SendFuturesAuth("/fapi/v1/order", "GET", params)
|
||||||
|
if err != nil || code != 200 {
|
||||||
|
log.Error("查询合约委托 参数:", params)
|
||||||
|
log.Error("查询合约委托失败 code:", code)
|
||||||
|
log.Error("查询合约委托失败 err:", err)
|
||||||
|
dataMap := make(map[string]interface{})
|
||||||
|
if err.Error() != "" {
|
||||||
|
if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
code, ok := dataMap["code"]
|
||||||
|
if ok {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%s", apiUserInfo.Id, symbol, ErrorMaps[code.(float64)])
|
||||||
|
}
|
||||||
|
if strings.Contains(err.Error(), "Unknown order sent.") {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, ErrorMaps[-2011])
|
||||||
|
}
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
sonic.Unmarshal(body, &result)
|
||||||
|
|
||||||
|
if result.OrderID == 0 {
|
||||||
|
return result, fmt.Errorf("api_id:%d 交易对:%s 查询订单失败:%+v", apiUserInfo.Id, symbol, "订单不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
查询现货委托
|
||||||
|
*/
|
||||||
|
// 根据订单号获取订单信息,如果获取失败,则进行重试
|
||||||
|
func (e FutRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo DbModels.LineApiUser, retryCount int) (order binancedto.BinanceFutureOrder, err error) {
|
||||||
|
result, err := e.GetOrderByOrderSn(symbol, ordersn, apiUserInfo)
|
||||||
|
// 如果获取失败,则进行重试
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// 调用GetOrderByOrderSn方法获取订单信息
|
||||||
|
for x := 1; x < retryCount; x++ {
|
||||||
|
// 如果获取成功,则跳出循环
|
||||||
|
result, err = e.GetOrderByOrderSn(symbol, ordersn, apiUserInfo)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 返回订单信息和错误信息
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|||||||
@ -88,7 +88,7 @@ func futTriggerOrder(db *gorm.DB, v *dto.PreOrderRedisList, item string, futApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
//判断是否有已触发交易对
|
//判断是否有已触发交易对
|
||||||
count, _ := GetSymbolTriggerCount(db, v.Symbol, 2)
|
count, _ := GetSymbolTriggerCount(db, v.Symbol, v.ApiId, 2)
|
||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
return
|
return
|
||||||
@ -316,7 +316,7 @@ func FutAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, futApi
|
|||||||
defer lock.Release()
|
defer lock.Release()
|
||||||
|
|
||||||
setting, _ := GetSystemSetting(db)
|
setting, _ := GetSystemSetting(db)
|
||||||
tradeSet, _ := GetTradeSet(v.Symbol, 0)
|
tradeSet, _ := GetTradeSet(v.Symbol, 1)
|
||||||
|
|
||||||
if tradeSet.LastPrice == "" {
|
if tradeSet.LastPrice == "" {
|
||||||
log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
|
log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn)
|
||||||
|
|||||||
@ -111,16 +111,20 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta
|
|||||||
|
|
||||||
// 减仓回调
|
// 减仓回调
|
||||||
func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||||
|
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id =? ", preOrder.MainId).Update("reduce_status", 1).Error; err != nil {
|
||||||
|
logger.Errorf("handleReduceFilled 更新主单减仓状态失败,订单号:%s", preOrder.OrderSn)
|
||||||
|
}
|
||||||
|
|
||||||
apiUserInfo, _ := GetApiInfo(preOrder.ApiId)
|
apiUserInfo, _ := GetApiInfo(preOrder.ApiId)
|
||||||
if apiUserInfo.Id == 0 {
|
if apiUserInfo.Id == 0 {
|
||||||
logger.Errorf("handleMainReduceFilled 获取api信息失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleReduceFilled 获取api信息失败,订单号:%s", preOrder.OrderSn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeSet, err := GetTradeSet(preOrder.Symbol, 1)
|
tradeSet, err := GetTradeSet(preOrder.Symbol, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("handleMainReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +132,7 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
parentOrder, err := GetOrderById(db, preOrder.Pid)
|
parentOrder, err := GetOrderById(db, preOrder.Pid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("handleMainReduceFilled 获取主单失败,订单号:%s", preOrder.OrderSn)
|
logger.Errorf("handleReduceFilled 获取主单失败,订单号:%s", preOrder.OrderSn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
parentPrice := utility.StrToDecimal(parentOrder.Price)
|
parentPrice := utility.StrToDecimal(parentOrder.Price)
|
||||||
@ -353,7 +357,7 @@ func removeFutLossAndAddPosition(preOrder *DbModels.LinePreOrder) {
|
|||||||
// preOrder 主单
|
// preOrder 主单
|
||||||
func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) {
|
func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) {
|
||||||
orders := []models.LinePreOrder{}
|
orders := []models.LinePreOrder{}
|
||||||
tradeSet, _ := GetTradeSet(preOrder.Symbol, 0)
|
tradeSet, _ := GetTradeSet(preOrder.Symbol, 1)
|
||||||
|
|
||||||
if tradeSet.Coin == "" {
|
if tradeSet.Coin == "" {
|
||||||
logger.Error("获取交易对失败")
|
logger.Error("获取交易对失败")
|
||||||
@ -366,6 +370,10 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if preOrder.OrderCategory == 3 {
|
if preOrder.OrderCategory == 3 {
|
||||||
|
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id = ?", preOrder.MainId).Update("add_position_status", 1).Error; err != nil {
|
||||||
|
logger.Errorf("更新主单加仓状态失败, 主单号:%s, 错误信息:%v", preOrder.MainId, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := cancelSymbolTakeAndStop(db, preOrder.MainId, preOrder.SymbolType); err != nil {
|
if err := cancelSymbolTakeAndStop(db, preOrder.MainId, preOrder.SymbolType); err != nil {
|
||||||
logger.Errorf("取消止盈止损订单失败 orderSn:%s err:%v", preOrder.OrderSn, err)
|
logger.Errorf("取消止盈止损订单失败 orderSn:%s err:%v", preOrder.OrderSn, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,10 +144,10 @@ func GetSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) ([]models.Lin
|
|||||||
// 获取交易对触发数量
|
// 获取交易对触发数量
|
||||||
// symbol 交易对
|
// symbol 交易对
|
||||||
// symbolType 交易对类型 1-现货 2-合约
|
// symbolType 交易对类型 1-现货 2-合约
|
||||||
func GetSymbolTriggerCount(db *gorm.DB, symbol string, symbolType int) (int64, error) {
|
func GetSymbolTriggerCount(db *gorm.DB, symbol string, apiId, symbolType int) (int64, error) {
|
||||||
var count int64
|
var count int64
|
||||||
|
|
||||||
if err := db.Model(&models.LinePreOrder{}).Where("symbol =? AND symbol_type =? AND order_type =0 AND pid=0 AND status IN (1,5,6)", symbol, symbolType).Count(&count).Error; err != nil {
|
if err := db.Model(&models.LinePreOrder{}).Where("symbol =? AND api_id =? AND symbol_type =? AND order_type =0 AND pid=0 AND status IN (1,5,6)", symbol, apiId, symbolType).Count(&count).Error; err != nil {
|
||||||
logger.Error("查询交易对触发数量失败:", err)
|
logger.Error("查询交易对触发数量失败:", err)
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ func SpotOrderLock(db *gorm.DB, v *dto.PreOrderRedisList, item string, spotApi S
|
|||||||
}
|
}
|
||||||
|
|
||||||
//判断是否有已触发交易对
|
//判断是否有已触发交易对
|
||||||
count, _ := GetSymbolTriggerCount(db, v.Symbol, 2)
|
count, _ := GetSymbolTriggerCount(db, v.Symbol, v.ApiId, 1)
|
||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -158,6 +158,10 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
|||||||
orders := make([]models.LinePreOrder, 0)
|
orders := make([]models.LinePreOrder, 0)
|
||||||
rate := utility.StringAsFloat(preOrder.Rate)
|
rate := utility.StringAsFloat(preOrder.Rate)
|
||||||
|
|
||||||
|
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id =? ", preOrder.MainId).Update("reduce_status", 1).Error; err != nil {
|
||||||
|
logger.Errorf("handleMainReduceFilled 更新主单减仓状态失败,订单号:%s", preOrder.OrderSn)
|
||||||
|
}
|
||||||
|
|
||||||
// 100%减仓 终止流程
|
// 100%减仓 终止流程
|
||||||
if rate >= 100 {
|
if rate >= 100 {
|
||||||
removeSpotLossAndAddPosition(preOrder)
|
removeSpotLossAndAddPosition(preOrder)
|
||||||
@ -436,6 +440,12 @@ func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) {
|
|||||||
|
|
||||||
// 主单成交
|
// 主单成交
|
||||||
func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) {
|
||||||
|
if preOrder.OrderCategory == 3 {
|
||||||
|
if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id = ?", preOrder.MainId).Update("add_position_status", 1).Error; err != nil {
|
||||||
|
logger.Errorf("更新主单加仓状态失败, 主单号:%s, 错误信息:%v", preOrder.MainId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
processTakeProfitAndStopLossOrders(db, preOrder)
|
processTakeProfitAndStopLossOrders(db, preOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user