fix(trader+decision): prevent quantity=0 error with min notional checks

User encountered API error when opening BTC position:
- Account equity: 9.20 USDT
- AI suggested: ~7.36 USDT position
- Error: `code=-4003, msg=Quantity less than or equal to zero.`
```
quantity = 7.36 / 101808.2 ≈ 0.00007228 BTC
formatted (%.3f) → "0.000"  Rounded down to 0!
```
BTCUSDT precision is 3 decimals (stepSize=0.001), causing small quantities to round to 0.
-  CloseLong() and CloseShort() have CheckMinNotional()
-  OpenLong() and OpenShort() **missing** CheckMinNotional()
- AI could suggest position_size_usd < minimum notional value
- No validation prevented tiny positions that would fail
---
**OpenLong() and OpenShort()** - Added two checks:
```go
//  Check if formatted quantity became 0 (rounding issue)
quantityFloat, _ := strconv.ParseFloat(quantityStr, 64)
if quantityFloat <= 0 {
    return error("Quantity too small, formatted to 0...")
}
//  Check minimum notional value (Binance requires ≥10 USDT)
if err := t.CheckMinNotional(symbol, quantityFloat); err != nil {
    return err
}
```
**Impact**: Prevents API errors by catching invalid quantities before submission.
---
Added minimum position size validation:
```go
const minPositionSizeGeneral = 15.0   // Altcoins
const minPositionSizeBTCETH = 100.0   // BTC/ETH (high price + precision limits)
if symbol == BTC/ETH && position_size_usd < 100 {
    return error("BTC/ETH requires ≥100 USDT to avoid rounding to 0")
}
if position_size_usd < 15 {
    return error("Position size must be ≥15 USDT (min notional requirement)")
}
```
**Impact**: Rejects invalid decisions before execution, saving API calls.
---
Updated hard constraints in AI prompt:
```
6. 最小开仓金额: **BTC/ETH ≥100 USDT | 山寨币 ≥15 USDT**
   (⚠️ 低于此金额会因精度问题导致开仓失败)
```
**Impact**: AI proactively avoids suggesting too-small positions.
---
-  User equity 9.20 USDT → suggested 7.36 USDT BTC position → **FAIL**
-  No validation, error only at API level
-  AI validation rejects position_size_usd < 100 for BTC
-  Binance trader checks quantity != 0 before submission
-  Clear error: "BTC/ETH requires ≥100 USDT..."
| Symbol | position_size_usd | Price | quantity | Formatted | Result |
|--------|-------------------|-------|----------|-----------|--------|
| BTCUSDT | 7.36 | 101808.2 | 0.00007228 | "0.000" |  Rejected (validation) |
| BTCUSDT | 150 | 101808.2 | 0.00147 | "0.001" |  Pass |
| ADAUSDT | 15 | 1.2 | 12.5 | "12.500" |  Pass |
---
**Immediate**:
-  Prevents quantity=0 API errors
-  Clear error messages guide users
-  Saves wasted API calls
**Long-term**:
-  AI learns minimum position sizes
-  Better user experience for small accounts
-  Prevents confusion from cryptic API errors
---
- Diagnostic report: /tmp/quantity_zero_diagnosis.md
- Binance min notional: 10 USDT (hardcoded in GetMinNotional())
This commit is contained in:
ZhouYongyou
2025-11-05 01:13:06 +08:00
parent 735db88ae5
commit 1cb5c268c5
2 changed files with 43 additions and 3 deletions
+22
View File
@@ -237,6 +237,17 @@ func (t *FuturesTrader) OpenLong(symbol string, quantity float64, leverage int)
return nil, err
}
// ✅ 检查格式化后的数量是否为 0(防止四舍五入导致的错误)
quantityFloat, parseErr := strconv.ParseFloat(quantityStr, 64)
if parseErr != nil || quantityFloat <= 0 {
return nil, fmt.Errorf("开倉數量過小,格式化後為 0 (原始: %.8f → 格式化: %s)。建議增加開倉金額或選擇價格更低的幣種", quantity, quantityStr)
}
// ✅ 检查最小名义价值(Binance 要求至少 10 USDT
if err := t.CheckMinNotional(symbol, quantityFloat); err != nil {
return nil, err
}
// 创建市价买入订单
order, err := t.client.NewCreateOrderService().
Symbol(symbol).
@@ -280,6 +291,17 @@ func (t *FuturesTrader) OpenShort(symbol string, quantity float64, leverage int)
return nil, err
}
// ✅ 检查格式化后的数量是否为 0(防止四舍五入导致的错误)
quantityFloat, parseErr := strconv.ParseFloat(quantityStr, 64)
if parseErr != nil || quantityFloat <= 0 {
return nil, fmt.Errorf("开倉數量過小,格式化後為 0 (原始: %.8f → 格式化: %s)。建議增加開倉金額或選擇價格更低的幣種", quantity, quantityStr)
}
// ✅ 检查最小名义价值(Binance 要求至少 10 USDT
if err := t.CheckMinNotional(symbol, quantityFloat); err != nil {
return nil, err
}
// 创建市价卖出订单
order, err := t.client.NewCreateOrderService().
Symbol(symbol).