mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-06-06 05:51:19 +08:00
Fix: Correct PnL calculation in trade history analysis
Fixed critical issues in historical trade record and performance analysis: 1. PnL Calculation: Changed from percentage-only to actual USDT amount - Now correctly calculates: positionValue × priceChange% × leverage - Previously: 100U@5% and 1000U@5% both showed 5.0 - Now: Properly reflects different position sizes and leverage 2. Position Tracking: Added quantity and leverage to open position records - Store complete trade data for accurate PnL calculation - Previously only stored: side, openPrice, openTime - Now includes: quantity, leverage for proper accounting 3. Position Key: Fixed to distinguish long/short positions - Changed from symbol to symbol_side (e.g., BTCUSDT_long) - Prevents conflicts when holding both long and short positions 4. Sharpe Ratio: Replaced custom Newton's method with math.Sqrt - Simplified standard deviation calculation - More reliable and maintainable Impact: Win rate, profit factor, and Sharpe ratio now based on accurate USDT amounts Co-Authored-By: tinkle-community <tinklefund@gmail.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -326,7 +327,7 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
|
||||
SymbolStats: make(map[string]*SymbolPerformance),
|
||||
}
|
||||
|
||||
// 追踪持仓状态:symbol -> {side, openPrice, openTime}
|
||||
// 追踪持仓状态:symbol_side -> {side, openPrice, openTime, quantity, leverage}
|
||||
openPositions := make(map[string]map[string]interface{})
|
||||
|
||||
// 遍历所有记录
|
||||
@@ -337,15 +338,23 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
|
||||
}
|
||||
|
||||
symbol := action.Symbol
|
||||
posKey := symbol // 使用symbol作为key(假设同一时间一个币种只有一个方向的仓位)
|
||||
side := ""
|
||||
if action.Action == "open_long" || action.Action == "close_long" {
|
||||
side = "long"
|
||||
} else if action.Action == "open_short" || action.Action == "close_short" {
|
||||
side = "short"
|
||||
}
|
||||
posKey := symbol + "_" + side // 使用symbol_side作为key,区分多空持仓
|
||||
|
||||
switch action.Action {
|
||||
case "open_long", "open_short":
|
||||
// 记录开仓
|
||||
// 记录开仓(包括数量和杠杆)
|
||||
openPositions[posKey] = map[string]interface{}{
|
||||
"side": action.Action[5:], // "long" or "short"
|
||||
"side": side,
|
||||
"openPrice": action.Price,
|
||||
"openTime": action.Timestamp,
|
||||
"quantity": action.Quantity,
|
||||
"leverage": action.Leverage,
|
||||
}
|
||||
|
||||
case "close_long", "close_short":
|
||||
@@ -354,16 +363,21 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
|
||||
openPrice := openPos["openPrice"].(float64)
|
||||
openTime := openPos["openTime"].(time.Time)
|
||||
side := openPos["side"].(string)
|
||||
quantity := openPos["quantity"].(float64)
|
||||
leverage := openPos["leverage"].(int)
|
||||
|
||||
// 计算盈亏
|
||||
pnl := 0.0
|
||||
// 计算盈亏百分比
|
||||
pnlPct := 0.0
|
||||
if side == "long" {
|
||||
pnlPct = ((action.Price - openPrice) / openPrice) * 100
|
||||
} else {
|
||||
pnlPct = ((openPrice - action.Price) / openPrice) * 100
|
||||
}
|
||||
pnl = pnlPct // 简化:用百分比代表盈亏
|
||||
|
||||
// 计算实际盈亏(USDT)
|
||||
// PnL = 仓位价值 × 价格变化百分比 × 杠杆倍数
|
||||
positionValue := quantity * openPrice
|
||||
pnl := positionValue * (pnlPct / 100) * float64(leverage)
|
||||
|
||||
// 记录交易结果
|
||||
outcome := TradeOutcome{
|
||||
@@ -513,14 +527,7 @@ func (l *DecisionLogger) calculateSharpeRatio(records []*DecisionRecord) float64
|
||||
sumSquaredDiff += diff * diff
|
||||
}
|
||||
variance := sumSquaredDiff / float64(len(returns))
|
||||
stdDev := 0.0
|
||||
if variance > 0 {
|
||||
stdDev = 1.0
|
||||
// 简单的平方根计算(牛顿迭代法)
|
||||
for i := 0; i < 10; i++ {
|
||||
stdDev = (stdDev + variance/stdDev) / 2
|
||||
}
|
||||
}
|
||||
stdDev := math.Sqrt(variance)
|
||||
|
||||
// 避免除以零
|
||||
if stdDev == 0 {
|
||||
|
||||
Reference in New Issue
Block a user