Files
nofx/trader
ZhouYongyou d2cf05c4e1 fix(trader): 修复余额自动同步逻辑,使用净资产追踪防止误同步
## 问题背景

原有的 autoSyncBalanceIfNeeded() 函数存在严重 Bug:
1. 使用"可用余额"而非"总资产"
2. 开仓时可用余额下降,触发错误同步
3. 将 initial_balance 从 400 改为 220(可用余额)
4. 导致盈亏计算完全错误

实际案例:
- 初始余额:400 USDT
- 开仓后可用余额:220 USDT
- 错误同步:initial_balance = 220 
- 显示盈亏:+169 USDT(错误,应该是 -14 USDT)

## 解决方案:净资产追踪法

### 核心算法
```
净资产 = 总资产 - 未实现盈亏

净资产变化 = (当前净资产 - initial_balance) / initial_balance

如果:
  - 净资产变化 > 10%
  - 且净资产增加
则:
  - 同步 initial_balance = 净资产
```

### 关键改进

1. **使用总资产而非可用余额**
   - 优先使用 total_wallet_balance
   - fallback: totalWalletBalance, balance

2. **计算净资产(排除交易盈亏)**
   - 提取所有持仓的未实现盈亏
   - 净资产 = 总资产 - 未实现盈亏
   - 这个值不受开仓影响,只受充值/提现影响

3. **即使有持仓也能检测充值**
   - 场景:有持仓时充值 100 USDT
   - 旧方案:跳过检测(需要等平仓)
   - 新方案:净资产 +100,立即检测 ✓

4. **字段缺失保护**
   - 支持多种字段名:unrealizedProfit, unRealizedProfit
   - 支持 string 类型的 PNL
   - 如果无法获取 PNL,安全地跳过同步

5. **只在净资产增加时同步**
   - 充值:净资产 +100 → 同步 ✓
   - 盈利:净资产 +50 → 同步 ✓
   - 亏损:净资产 -50 → 跳过(保留原始 initial_balance)

6. **详细的日志输出**
   - 显示:总资产、未实现盈亏、净资产
   - 原因分析:"可能是用户充值"、"可能是交易盈利"

## 测试验证

### 场景 1:开仓交易(原 Bug)
```
初始:400 USDT
开仓后:
  - 总资产:385 USDT
  - 未实现盈亏:-15 USDT
  - 净资产:385 - (-15) = 400 USDT

结果:净资产不变,不触发同步 ✓
```

### 场景 2:有持仓时充值(关键改进)
```
初始:400 USDT
有持仓(浮盈 +20)时充值 100 USDT:
  - 总资产:520 USDT
  - 未实现盈亏:+20 USDT
  - 净资产:520 - 20 = 500 USDT

结果:检测到净资产 +100 (+25%),同步 ✓
日志:在有持仓的情况下净资产增加,很可能是用户充值
```

### 场景 3:交易亏损
```
初始:400 USDT
亏损 100 USDT 后平仓:
  - 总资产:300 USDT
  - 未实现盈亏:0
  - 净资产:300 USDT

结果:净资产减少,跳过同步 ✓
initial_balance 保持 400,显示正确的亏损 -100 USDT
```

## 技术细节

- 同步间隔:10 分钟
- 触发阈值:净资产变化 > 10%
- 字段支持:unrealizedProfit (float64/string), unRealizedProfit
- 错误处理:API 失败或字段缺失时安全跳过
- 日志级别:详细(便于排查问题)

## 影响范围

- 修复了 initial_balance 被错误修改的根本原因
- 支持有持仓时检测充值(之前无法检测)
- 不会因交易亏损而错误更新 initial_balance
- 向后兼容,不影响现有用户

## 后续优化建议

1. 添加手动同步按钮(前端)
2. 记录同步日志到数据库(审计)
3. 添加配置选项(可禁用、调整阈值)
4. 考虑添加累计盈亏字段(避免语义冲突)

Related: #issue-initial-balance-incorrect
Related: commit 8a1e931 (API 层保护,本次修复底层逻辑)
2025-11-05 03:05:51 +08:00
..