From ade768c28a2878315c32109b7fba8f233a15f68f Mon Sep 17 00:00:00 2001 From: hucan <951870319@qq.com> Date: Thu, 20 Feb 2025 12:00:04 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=B8=BB=E5=8D=95=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=87=8F=E4=BB=93=E3=80=81=E5=8A=A0=E4=BB=93=E7=8A=B6=E6=80=81?= =?UTF-8?q?=202=E3=80=81bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/apis/line_pre_order.go | 4 + app/admin/service/dto/line_pre_order.go | 24 +++--- app/admin/service/line_pre_order.go | 10 ++- app/jobs/jobs.go | 83 ++++++++++++------- models/binancedto/binance.go | 52 ++++++++++++ services/binanceservice/binancerest.go | 59 +++++++++++++ .../binanceservice/binanceservice_test.go | 32 +++++++ services/binanceservice/futuresbinancerest.go | 64 ++++++++++++++ .../binanceservice/futuresjudgeservice.go | 4 +- services/binanceservice/futuresrest.go | 16 +++- services/binanceservice/orderservice.go | 4 +- services/binanceservice/spotjudgeservice.go | 2 +- services/binanceservice/spotreset.go | 10 +++ 13 files changed, 312 insertions(+), 52 deletions(-) diff --git a/app/admin/apis/line_pre_order.go b/app/admin/apis/line_pre_order.go index 6139aed..145687a 100644 --- a/app/admin/apis/line_pre_order.go +++ b/app/admin/apis/line_pre_order.go @@ -625,6 +625,10 @@ func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) { return } + if req.Symbol == "" { + return + } + // data := dto.CalculateBreakEvenRatioResp{} _, err = s.GenerateOrder(&req) if err != nil { diff --git a/app/admin/service/dto/line_pre_order.go b/app/admin/service/dto/line_pre_order.go index 24324dc..b5eefe6 100644 --- a/app/admin/service/dto/line_pre_order.go +++ b/app/admin/service/dto/line_pre_order.go @@ -183,7 +183,7 @@ func (s *LinePreOrderDeleteReq) GetId() interface{} { type LineAddPreOrderReq struct { ExchangeType string `json:"exchange_type" vd:"len($)>0"` //交易所类型 OrderType int `json:"order_type"` //订单类型 - Symbol string `json:"symbol" vd:"len($)>0"` //交易对 + Symbol string `json:"symbol"` //交易对 ApiUserId string `json:"api_id" ` //下单用户 Site string `json:"site" ` //购买方向 BuyPrice string `json:"buy_price" vd:"$>0"` //购买金额 U @@ -341,15 +341,15 @@ func (req LineBatchAddPreOrderReq) CheckParams() error { 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("减仓数量不正确") } - if v.ReducePriceRatio.IsZero() || v.ReducePriceRatio.Cmp(decimal.Zero) > 0 { + if v.ReducePriceRatio.IsZero() || v.ReducePriceRatio.Cmp(decimal.NewFromInt(100)) > 0 { 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("减仓后止盈价格不正确") } } @@ -371,8 +371,8 @@ type LeverReq struct { Symbol string `json:"symbol"` Leverage int `json:"leverage"` GroupId int `json:"group_id"` - IsAll int `json:"is_all"` // 1= 全部 0=不是全部 - ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type + IsAll int `json:"is_all"` // 1= 全部 0=不是全部 + ExchangeType string `json:"exchangeType"` //交易所类型 字典exchange_type } func (c LeverReq) CheckParams() error { @@ -387,11 +387,11 @@ func (c LeverReq) CheckParams() error { type MarginTypeReq struct { ApiUserIds string `json:"api_user_ids"` - Symbol string `json:"symbol"` // 交易对 - MarginType string `json:"margin_type"` //全仓 CROSSED 逐仓 ISOLATED - GroupId int `json:"group_id"` // 交易对组id - IsAll int `json:"is_all"` // 1= 全部 0=不是全部 - ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type + Symbol string `json:"symbol"` // 交易对 + MarginType string `json:"margin_type"` //全仓 CROSSED 逐仓 ISOLATED + GroupId int `json:"group_id"` // 交易对组id + IsAll int `json:"is_all"` // 1= 全部 0=不是全部 + ExchangeType string `json:"exchangeType"` //交易所类型 字典exchange_type } type CancelOpenOrderReq struct { @@ -399,7 +399,7 @@ type CancelOpenOrderReq struct { Symbol string `json:"symbol"` OrderSn string `json:"order_sn"` OrderType int `json:"order_type"` - ExchangeType string `json:"exchange_type"` //交易所类型 字典exchange_type + ExchangeType string `json:"exchangeType"` //交易所类型 字典exchange_type } type GetChildOrderReq struct { diff --git a/app/admin/service/line_pre_order.go b/app/admin/service/line_pre_order.go index e5081a6..7f9fcdf 100644 --- a/app/admin/service/line_pre_order.go +++ b/app/admin/service/line_pre_order.go @@ -323,7 +323,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP //获取交易对 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 { *errs = append(*errs, fmt.Errorf("api_id:%s 获取交易对:%s 该交易对已存在,请勿重复下单", id, req.Symbol)) continue @@ -571,6 +571,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP stopOrder.MainId = AddOrder.Id stopOrder.OrderType = 4 stopOrder.Status = 0 + stopOrder.BuyPrice = "0" stopOrder.Rate = req.ReducePriceRatio.String() stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4)) stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String() @@ -807,9 +808,9 @@ func makeReduceTakeAndStoploss(parentOrder *models.LinePreOrder, ext models.Line } // 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 - 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 } @@ -897,6 +898,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p req.Price = batchReq.Price req.Profit = batchReq.Profit req.Ext = batchReq.Ext + req.SymbolType = batchReq.SymbolType // req.StopPrice = batchReq.StopPrice req.ReducePriceRatio = batchReq.ReducePriceRatio req.PriceType = batchReq.PriceType @@ -1176,6 +1178,8 @@ func (e *LinePreOrder) ClearAll() error { "stop_loss_markt", "_PreSpotOrderList_", "_PreFutOrderList_", + "spot_reduce_list", + "futures_reduce_list", } err = helper.DefaultRedis.DeleteKeysByPrefix(prefixs...) if err != nil { diff --git a/app/jobs/jobs.go b/app/jobs/jobs.go index 7567501..344657f 100644 --- a/app/jobs/jobs.go +++ b/app/jobs/jobs.go @@ -25,6 +25,7 @@ import ( "time" "github.com/bytedance/sonic" + "github.com/shopspring/decimal" "gorm.io/driver/mysql" "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)) return err } 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() + order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String() order.Desc = fmt.Sprintf("取消限价单,重下市价单源订单号:%s ", order.OrderSn) order.OrderSn = utility.Int64ToString(snowflakehelper.GetOrderId()) order.MainOrderType = "MARKET" - // 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 - err := db.Model(&order).Updates(map[string]interface{}{"desc": order.Desc, "order_sn": order.OrderSn, "main_order_type": order.MainOrderType}).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 { logger.Error(fmt.Sprintf("生成新市价单失败 err:%+v", err)) @@ -251,7 +261,7 @@ func (t LimitOrderTimeoutDuration) ReSpotOrderPlace(db *gorm.DB, order models.Li TimeInForce: "GTC", Price: utility.StringToDecimal(order.Price), StopPrice: utility.StrToDecimal(order.Price), - Quantity: utility.StringToDecimal(order.Num), + Quantity: remainingQuantity, NewClientOrderId: utility.Int64ToString(newClientOrderId), } 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)) return err } 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() - orderType := "MARKET" + order.Num = remainingQuantity.Truncate(int32(tradeSet.AmountDigit)).String() order.Desc = fmt.Sprintf("取消限价单,重下市价单 源订单号:%s", order.OrderSn) order.OrderSn = utility.Int64ToString(newClientOrderId) @@ -294,31 +320,32 @@ func (t LimitOrderTimeoutDuration) ReFutOrderPlace(db *gorm.DB, order models.Lin // 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 } - if order.OrderType == 4 { - orderType = "STOP_MARKET" - } + // 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), + // } - params := binanceservice.FutOrderPlace{ - 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 { + 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 { diff --git a/models/binancedto/binance.go b/models/binancedto/binance.go index da9423c..fdb64ce 100644 --- a/models/binancedto/binance.go +++ b/models/binancedto/binance.go @@ -22,3 +22,55 @@ type StoplossMarket struct { Symbol string `json:"symbol"` 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时的自动取消时间 +} diff --git a/services/binanceservice/binancerest.go b/services/binanceservice/binancerest.go index a7e50db..c08d49f 100644 --- a/services/binanceservice/binancerest.go +++ b/services/binanceservice/binancerest.go @@ -9,6 +9,7 @@ import ( "go-admin/common/global" "go-admin/common/helper" "go-admin/models" + "go-admin/models/binancedto" "go-admin/models/spot" "go-admin/pkg/httputils" "go-admin/pkg/utility" @@ -529,3 +530,61 @@ func (e SpotRestApi) GetSpotSymbolLastPrice(targetSymbol string) (lastPrice deci // } 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 +} diff --git a/services/binanceservice/binanceservice_test.go b/services/binanceservice/binanceservice_test.go index 402cdb5..2d3bbf5 100644 --- a/services/binanceservice/binanceservice_test.go +++ b/services/binanceservice/binanceservice_test.go @@ -215,3 +215,35 @@ func TestFutOrderPlace(t *testing.T) { 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) +} diff --git a/services/binanceservice/futuresbinancerest.go b/services/binanceservice/futuresbinancerest.go index 3b9bc95..5130133 100644 --- a/services/binanceservice/futuresbinancerest.go +++ b/services/binanceservice/futuresbinancerest.go @@ -9,6 +9,7 @@ import ( "go-admin/common/global" "go-admin/common/helper" "go-admin/models" + "go-admin/models/binancedto" "go-admin/models/futuresdto" "go-admin/pkg/httputils" "go-admin/pkg/utility" @@ -936,3 +937,66 @@ func (e FutRestApi) GetFutSymbolLastPrice(targetSymbol string) (lastPrice decima // } 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 +} diff --git a/services/binanceservice/futuresjudgeservice.go b/services/binanceservice/futuresjudgeservice.go index 9ef8194..413fee4 100644 --- a/services/binanceservice/futuresjudgeservice.go +++ b/services/binanceservice/futuresjudgeservice.go @@ -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 { return @@ -316,7 +316,7 @@ func FutAddPositionTrigger(db *gorm.DB, v *AddPositionList, item string, futApi defer lock.Release() setting, _ := GetSystemSetting(db) - tradeSet, _ := GetTradeSet(v.Symbol, 0) + tradeSet, _ := GetTradeSet(v.Symbol, 1) if tradeSet.LastPrice == "" { log.Errorf("合约加仓触发 查询交易对失败 交易对:%s ordersn:%s", v.Symbol, v.OrderSn) diff --git a/services/binanceservice/futuresrest.go b/services/binanceservice/futuresrest.go index 997ac06..c1e7f2a 100644 --- a/services/binanceservice/futuresrest.go +++ b/services/binanceservice/futuresrest.go @@ -111,16 +111,20 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta // 减仓回调 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) if apiUserInfo.Id == 0 { - logger.Errorf("handleMainReduceFilled 获取api信息失败,订单号:%s", preOrder.OrderSn) + logger.Errorf("handleReduceFilled 获取api信息失败,订单号:%s", preOrder.OrderSn) return } tradeSet, err := GetTradeSet(preOrder.Symbol, 1) if err != nil { - logger.Errorf("handleMainReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn) + logger.Errorf("handleReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn) return } @@ -128,7 +132,7 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { parentOrder, err := GetOrderById(db, preOrder.Pid) if err != nil { - logger.Errorf("handleMainReduceFilled 获取主单失败,订单号:%s", preOrder.OrderSn) + logger.Errorf("handleReduceFilled 获取主单失败,订单号:%s", preOrder.OrderSn) return } parentPrice := utility.StrToDecimal(parentOrder.Price) @@ -353,7 +357,7 @@ func removeFutLossAndAddPosition(preOrder *DbModels.LinePreOrder) { // preOrder 主单 func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) { orders := []models.LinePreOrder{} - tradeSet, _ := GetTradeSet(preOrder.Symbol, 0) + tradeSet, _ := GetTradeSet(preOrder.Symbol, 1) if tradeSet.Coin == "" { logger.Error("获取交易对失败") @@ -366,6 +370,10 @@ func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.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) + } + if err := cancelSymbolTakeAndStop(db, preOrder.MainId, preOrder.SymbolType); err != nil { logger.Errorf("取消止盈止损订单失败 orderSn:%s err:%v", preOrder.OrderSn, err) } diff --git a/services/binanceservice/orderservice.go b/services/binanceservice/orderservice.go index 8454c8f..1d242a3 100644 --- a/services/binanceservice/orderservice.go +++ b/services/binanceservice/orderservice.go @@ -144,10 +144,10 @@ func GetSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) ([]models.Lin // 获取交易对触发数量 // symbol 交易对 // 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 - 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) return count, err } diff --git a/services/binanceservice/spotjudgeservice.go b/services/binanceservice/spotjudgeservice.go index 9836eeb..f23753f 100644 --- a/services/binanceservice/spotjudgeservice.go +++ b/services/binanceservice/spotjudgeservice.go @@ -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 { return diff --git a/services/binanceservice/spotreset.go b/services/binanceservice/spotreset.go index 916eead..216564f 100644 --- a/services/binanceservice/spotreset.go +++ b/services/binanceservice/spotreset.go @@ -158,6 +158,10 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { orders := make([]models.LinePreOrder, 0) 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%减仓 终止流程 if rate >= 100 { removeSpotLossAndAddPosition(preOrder) @@ -436,6 +440,12 @@ func removeSpotLossAndAddPosition(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) }