package binanceservice import ( "fmt" "strings" DbModels "go-admin/app/admin/models" "go-admin/pkg/retryhelper" "github.com/bytedance/sonic" log "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/service" ) type FuturesResetV2 struct { service.Service } // 带重试机制的合约下单 func (e *FuturesResetV2) OrderPlaceLoop(apiUserInfo *DbModels.LineApiUser, params FutOrderPlace) error { opts := retryhelper.DefaultRetryOptions() opts.RetryableErrFn = func(err error) bool { if strings.Contains(err.Error(), "LOT_SIZE") { return false } //重试 return true } err := retryhelper.Retry(func() error { return e.OrderPlace(apiUserInfo, params) }, opts) if err != nil { return err } return nil } // 合约下单 func (e *FuturesResetV2) OrderPlace(apiUserInfo *DbModels.LineApiUser, params FutOrderPlace) error { if err := params.CheckParams(); err != nil { return err } orderType := strings.ToUpper(params.OrderType) side := strings.ToUpper(params.Side) paramsMaps := map[string]string{ "symbol": params.Symbol, "side": side, "type": orderType, "newClientOrderId": params.NewClientOrderId, "positionSide": params.PositionSide, } // 设置市价和限价等类型的参数 switch orderType { case "LIMIT": paramsMaps["price"] = params.Price.String() paramsMaps["timeInForce"] = "GTC" case "TAKE_PROFIT_MARKET": paramsMaps["timeInForce"] = "GTC" paramsMaps["stopprice"] = params.Profit.String() paramsMaps["workingType"] = "MARK_PRICE" if params.ClosePosition { paramsMaps["closePosition"] = "true" } case "TAKE_PROFIT": paramsMaps["price"] = params.Price.String() paramsMaps["stopprice"] = params.Profit.String() paramsMaps["timeInForce"] = "GTC" case "STOP_MARKET": paramsMaps["stopprice"] = params.StopPrice.String() paramsMaps["workingType"] = "MARK_PRICE" paramsMaps["timeInForce"] = "GTC" if params.ClosePosition { paramsMaps["closePosition"] = "true" } case "STOP": paramsMaps["price"] = params.Price.String() paramsMaps["stopprice"] = params.StopPrice.String() paramsMaps["workingType"] = "MARK_PRICE" paramsMaps["timeInForce"] = "GTC" } //不是平仓 if !params.ClosePosition { paramsMaps["quantity"] = params.Quantity.String() } // 获取 API 信息和发送下单请求 client := GetClient(apiUserInfo) _, statusCode, err := client.SendFuturesRequestAuth("/fapi/v1/order", "POST", paramsMaps) if err != nil { return parseOrderError(err, paramsMaps, statusCode, apiUserInfo) } return nil } // 拆出的错误解析函数 func parseOrderError(err error, paramsMaps map[string]string, statusCode int, apiUserInfo *DbModels.LineApiUser) error { var dataMap map[string]interface{} if err2 := sonic.Unmarshal([]byte(err.Error()), &dataMap); err2 == nil { if code, ok := dataMap["code"]; ok { paramsVal, _ := sonic.MarshalString(¶msMaps) log.Error("下单失败 参数:", paramsVal) errContent := FutErrorMaps[code.(float64)] if errContent == "" { errContent, _ = dataMap["msg"].(string) } return fmt.Errorf("api_id:%d 交易对:%s 下单失败:%s", apiUserInfo.Id, paramsMaps["symbol"], errContent) } } // 特殊处理保证金不足 if strings.Contains(err.Error(), "Margin is insufficient.") { return fmt.Errorf("api_id:%d 交易对:%s 下单失败:%s", apiUserInfo.Id, paramsMaps["symbol"], FutErrorMaps[-2019]) } return fmt.Errorf("api_id:%d 交易对:%s statusCode:%v 下单失败:%s", apiUserInfo.Id, paramsMaps["symbol"], statusCode, err.Error()) }