1、主单增加减仓、加仓状态
2、bug修复
This commit is contained in:
		| @ -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 { | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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时的自动取消时间 | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
|  | ||||
| @ -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) | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
| 		} | ||||
|  | ||||
| @ -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 | ||||
| 	} | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user