115 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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,
 | |
| 		"quantity":         params.Quantity.String(),
 | |
| 		"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"
 | |
| 	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"
 | |
| 	case "STOP":
 | |
| 		paramsMaps["price"] = params.Price.String()
 | |
| 		paramsMaps["stopprice"] = params.StopPrice.String()
 | |
| 		paramsMaps["workingType"] = "MARK_PRICE"
 | |
| 		paramsMaps["timeInForce"] = "GTC"
 | |
| 	}
 | |
| 
 | |
| 	// 获取 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 = err.Error()
 | |
| 			}
 | |
| 			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())
 | |
| }
 |