mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 16:26:57 +08:00
fix: 修复 AI 决策时收到的持仓盈亏百分比未考虑杠杆 (#819)
Fixes #818 ## 问题 传递给 AI 决策的持仓盈亏百分比只计算价格变动,未考虑杠杆倍数。 例如:10倍杠杆,价格上涨1%,AI看到的是1%而非实际的10%收益率。 ## 改动 1. 修复 buildTradingContext 中的盈亏百分比计算 - 从基于价格变动改为基于保证金计算 - 收益率 = 未实现盈亏 / 保证金 × 100% 2. 抽取公共函数 calculatePnLPercentage - 消除 buildTradingContext 和 GetPositions 的重复代码 - 确保两处使用相同的计算逻辑 3. 新增单元测试 (trader/auto_trader_test.go) - 9个基础测试用例(正常、边界、异常) - 3个真实场景测试(BTC/ETH/SOL不同杠杆) - 测试覆盖率:100% 4. 更新 .gitignore - 添加 SQLite WAL 相关文件 (config.db-shm, config.db-wal, nofx.db) ## 测试结果 ✅ 所有 12 个单元测试通过 ✅ 代码编译通过 ✅ 与 GetPositions 函数保持一致 ## 影响 - AI 现在能够准确评估持仓真实收益率 - 避免因错误数据导致的过早止盈或延迟止损
This commit is contained in:
@@ -622,14 +622,6 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
|
||||
unrealizedPnl := pos["unRealizedProfit"].(float64)
|
||||
liquidationPrice := pos["liquidationPrice"].(float64)
|
||||
|
||||
// 计算盈亏百分比
|
||||
pnlPct := 0.0
|
||||
if side == "long" {
|
||||
pnlPct = ((markPrice - entryPrice) / entryPrice) * 100
|
||||
} else {
|
||||
pnlPct = ((entryPrice - markPrice) / entryPrice) * 100
|
||||
}
|
||||
|
||||
// 计算占用保证金(估算)
|
||||
leverage := 10 // 默认值,实际应该从持仓信息获取
|
||||
if lev, ok := pos["leverage"].(float64); ok {
|
||||
@@ -638,6 +630,9 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
|
||||
marginUsed := (quantity * markPrice) / float64(leverage)
|
||||
totalMarginUsed += marginUsed
|
||||
|
||||
// 计算盈亏百分比(基于保证金,考虑杠杆)
|
||||
pnlPct := calculatePnLPercentage(unrealizedPnl, marginUsed)
|
||||
|
||||
// 跟踪持仓首次出现时间
|
||||
posKey := symbol + "_" + side
|
||||
currentPositionKeys[posKey] = true
|
||||
@@ -1382,11 +1377,7 @@ func (at *AutoTrader) GetPositions() ([]map[string]interface{}, error) {
|
||||
marginUsed := (quantity * markPrice) / float64(leverage)
|
||||
|
||||
// 计算盈亏百分比(基于保证金)
|
||||
// 收益率 = 未实现盈亏 / 保证金 × 100%
|
||||
pnlPct := 0.0
|
||||
if marginUsed > 0 {
|
||||
pnlPct = (unrealizedPnl / marginUsed) * 100
|
||||
}
|
||||
pnlPct := calculatePnLPercentage(unrealizedPnl, marginUsed)
|
||||
|
||||
result = append(result, map[string]interface{}{
|
||||
"symbol": symbol,
|
||||
@@ -1405,6 +1396,15 @@ func (at *AutoTrader) GetPositions() ([]map[string]interface{}, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// calculatePnLPercentage 计算盈亏百分比(基于保证金,自动考虑杠杆)
|
||||
// 收益率 = 未实现盈亏 / 保证金 × 100%
|
||||
func calculatePnLPercentage(unrealizedPnl, marginUsed float64) float64 {
|
||||
if marginUsed > 0 {
|
||||
return (unrealizedPnl / marginUsed) * 100
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
|
||||
// sortDecisionsByPriority 对决策排序:先平仓,再开仓,最后hold/wait
|
||||
// 这样可以避免换仓时仓位叠加超限
|
||||
func sortDecisionsByPriority(decisions []decision.Decision) []decision.Decision {
|
||||
|
||||
Reference in New Issue
Block a user