Files
exchange_go/services/binanceservice/futures_reset_v2.go
2025-07-26 09:09:09 +08:00

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(&paramsMaps)
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())
}