docs/pnl.md
定义: 创建trader时的账户净值(Total Equity),作为所有PNL计算的基准
设置时机:
存储位置:
traders.initial_balance 字段计算公式:
Initial Balance = Total Wallet Balance + Total Unrealized Profit
= 当前账户净值(创建时快照)
定义: 账户的实时总价值
计算公式:
Total Equity = Total Wallet Balance + Total Unrealized Profit
数据来源: 实时从交易所API获取
说明:
Total Wallet Balance: 账户中的实际USDT余额(包括已实现盈亏)Total Unrealized Profit: 所有持仓的未实现盈亏总和计算公式:
Total PNL = Current Equity - Initial Balance
Total PNL % = (Total PNL / Initial Balance) × 100%
示例:
Initial Balance: 10,000 USDT (创建时)
Current Equity: 11,500 USDT (实时)
-----------------------------------
Total PNL: +1,500 USDT
Total PNL %: +15%
定义: 当前所有持仓的未实现盈亏总和
来源: 直接从交易所API获取 totalUnrealizedProfit
计算公式:
Position PNL % = (Unrealized PnL / Margin Used) × 100%
其中:Margin Used = Position Value / Leverage
| 原则 | 说明 |
|---|---|
| ❌ 禁用自动同步 | 系统不会自动修改Initial Balance |
| ✅ 创建时自动获取 | 创建trader时从交易所获取真实equity |
| ✅ 允许手动更新 | 用户可通过前端主动同步(充值/提现后) |
| 🔒 常规更新保护 | UpdateTrader方法不允许修改Initial Balance |
文件: api/server.go:handleCreateTrader()
逻辑:
// 查询交易所余额
balanceInfo, _ := tempTrader.GetBalance()
// 提取钱包余额和未实现盈亏
totalWalletBalance := balanceInfo["totalWalletBalance"].(float64)
totalUnrealizedProfit := balanceInfo["totalUnrealizedProfit"].(float64)
// 计算Total Equity作为Initial Balance
initialEquity := totalWalletBalance + totalUnrealizedProfit
// 存入数据库
trader := &config.TraderRecord{
InitialBalance: initialEquity, // 自动设置
// ... 其他字段
}
修改: trader/auto_trader.go:autoSyncBalanceIfNeeded()
操作:
autoSyncBalanceIfNeeded_DEPRECATED()runCycle() 中注释掉调用效果: 系统运行过程中不会自动修改Initial Balance
文件: config/database.go:UpdateTrader()
修改: 从SQL UPDATE语句中移除 initial_balance 字段
效果: 常规的配置更新操作无法修改Initial Balance
端点: POST /traders/:id
实现: api/server.go:handleUpdateTrader()
用途: update trader, 包括Initial Balance基准值
请求体:
{
"initial_balance": 10000.0
}
流程:
1. 用户输入新的initial_balance值
2. 更新数据库的initial_balance字段
3. 重新加载trader到内存
4. 返回更新前后的对比信息
特点:
┌─────────────────────────────────────────┐
│ 1. 创建Trader │
│ - 用户配置AI模型、交易所 │
│ - 系统自动获取当前equity │
│ → initial_balance = Total Equity │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 2. 运行期间 │
│ - 系统不会自动修改initial_balance │
│ - 实时计算: │
│ current_equity = API获取 │
│ total_pnl = current - initial │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 3. 充值/提现后 │
│ - 用户点击"更新初始余额"按钮 │
│ - 更新initial_balance │
│ - PNL计算重新基于新的基准 │
└─────────────────────────────────────────┘
| 字段 | 定义 | 计算方式 | 存储位置 | 更新频率 |
|---|---|---|---|---|
| Initial Balance | 基准余额 | 创建/手动同步时获取equity | DB: traders.initial_balance | 创建时+手动 |
| Current Equity | 当前净值 | wallet + unrealized | 不存储(实时计算) | 实时 |
| Total PNL | 总盈亏 | current_equity - initial_balance | 不存储(实时计算) | 实时 |
| Total PNL % | 盈亏百分比 | (total_pnl / initial_balance) × 100 | 不存储(实时计算) | 实时 |
用户操作:填写基本配置(不需要输入余额)
系统行为:自动从交易所获取当前equity,设置为initial_balance
结果:initial_balance = 当前账户净值
用户操作:无
系统行为:实时计算PNL,不修改initial_balance
结果:PNL = 当前equity - initial_balance
用户操作:充值 → 输入新的Initial Balance(如:10000 + 5000 = 15000)
系统行为:更新initial_balance为15000
结果:PNL统计基于新的基准15000计算
用户操作:提现 → 输入新的Initial Balance(如:10000 - 2000 = 8000)
系统行为:更新initial_balance为8000
结果:PNL统计基于新的基准8000计算
用户操作:想重新开始统计PNL → 输入当前账户净值作为新基准
系统行为:更新initial_balance为用户输入的值
结果:PNL统计重置,从新基准开始计算
当前初始余额: 10,000 USDT
请输入新的初始余额(用于重新校准PNL统计)
| 功能 | 文件 | 行号/函数 |
|---|---|---|
| 创建时自动获取equity | api/server.go | handleCreateTrader:540-625 |
| 禁用自动同步 | trader/auto_trader.go | autoSyncBalanceIfNeeded_DEPRECATED:291 |
| 保护UpdateTrader | config/database.go | UpdateTrader:954-969 |
| 手动同步API | api/server.go | handleSyncBalance:937-1050 |
| 手动同步数据库方法 | config/database.go | UpdateTraderInitialBalance:977-982 |
这个设计平衡了稳定性和灵活性: