fix(binance): initialize dual-side position mode to prevent code=-4061 errors

## Problem
When opening positions with explicit `PositionSide` parameter (LONG/SHORT), Binance API returned **code=-4061** error:
```
"No need to change position side."
"code":-4061
```

**Root cause:**
- Binance accounts default to **single-side position mode** ("One-Way Mode")
- In this mode, `PositionSide` parameter is **not allowed**
- Code使用了 `PositionSide` 參數 (LONG/SHORT),但帳戶未啟用雙向持倉模式

**Position Mode Comparison:**
| Mode | PositionSide Required | Can Hold Long+Short Simultaneously |
|------|----------------------|------------------------------------|
| One-Way (default) |  No |  No |
| Hedge Mode |  **Required** |  Yes |

## Solution

### 1. Added setDualSidePosition() function
Automatically enables Hedge Mode during trader initialization:

```go
func (t *FuturesTrader) setDualSidePosition() error {
    err := t.client.NewChangePositionModeService().
        DualSide(true). // Enable Hedge Mode
        Do(context.Background())

    if err != nil {
        // Ignore "No need to change" error (already in Hedge Mode)
        if strings.Contains(err.Error(), "No need to change position side") {
            log.Printf("✓ Account already in Hedge Mode")
            return nil
        }
        return err
    }

    log.Printf("✓ Switched to Hedge Mode")
    return nil
}
```

### 2. Called in NewFuturesTrader()
Runs automatically when creating trader instance:

```go
func NewFuturesTrader(apiKey, secretKey string) *FuturesTrader {
    trader := &FuturesTrader{...}

    // Initialize Hedge Mode
    if err := trader.setDualSidePosition(); err != nil {
        log.Printf("⚠️ Failed to set Hedge Mode: %v", err)
    }

    return trader
}
```

## Impact
-  Prevents code=-4061 errors when opening positions
-  Enables simultaneous long+short positions (if needed)
-  Fails gracefully if account already in Hedge Mode
- ⚠️ **One-time change**: Once enabled, cannot revert to One-Way Mode with open positions

## Testing
-  Compiles successfully
- ⚠️ Requires Binance testnet/mainnet validation:
  - [ ] First initialization → switches to Hedge Mode
  - [ ] Subsequent initializations → ignores "No need to change" error
  - [ ] Open long position with PositionSide=LONG → succeeds
  - [ ] Open short position with PositionSide=SHORT → succeeds

## Code Changes
```
trader/binance_futures.go:
- Line 3-12: Added strings import
- Line 33-47: Modified NewFuturesTrader() to call setDualSidePosition()
- Line 49-69: New function setDualSidePosition()
Total: +25 lines
```

## References
- Binance Futures API: https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade
- Error code=-4061: "No need to change position side."
- PositionSide ENUM: BOTH (One-Way) | LONG | SHORT (Hedge Mode)
This commit is contained in:
ZhouYongyou
2025-11-04 19:07:58 +08:00
parent 5649cb7496
commit 140a9543f8

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"log"
"strconv"
"strings"
"sync"
"time"
@@ -32,10 +33,40 @@ type FuturesTrader struct {
// NewFuturesTrader 创建合约交易器
func NewFuturesTrader(apiKey, secretKey string) *FuturesTrader {
client := futures.NewClient(apiKey, secretKey)
return &FuturesTrader{
trader := &FuturesTrader{
client: client,
cacheDuration: 15 * time.Second, // 15秒缓存
}
// 设置双向持仓模式Hedge Mode
// 这是必需的,因为代码中使用了 PositionSide (LONG/SHORT)
if err := trader.setDualSidePosition(); err != nil {
log.Printf("⚠️ 设置双向持仓模式失败: %v (如果已是双向模式则忽略此警告)", err)
}
return trader
}
// setDualSidePosition 设置双向持仓模式(初始化时调用)
func (t *FuturesTrader) setDualSidePosition() error {
// 尝试设置双向持仓模式
err := t.client.NewChangePositionModeService().
DualSide(true). // true = 双向持仓Hedge Mode
Do(context.Background())
if err != nil {
// 如果错误信息包含"No need to change",说明已经是双向持仓模式
if strings.Contains(err.Error(), "No need to change position side") {
log.Printf(" ✓ 账户已是双向持仓模式Hedge Mode")
return nil
}
// 其他错误则返回(但在调用方不会中断初始化)
return err
}
log.Printf(" ✓ 账户已切换为双向持仓模式Hedge Mode")
log.Printf(" 双向持仓模式允许同时持有多单和空单")
return nil
}
// GetBalance 获取账户余额(带缓存)