Merge pull request #273 from zhouyongyou/feat/logger-dynamic-tpsl

feat(logger): 添加動態 TP/SL 日誌支持 [依賴 #415]
This commit is contained in:
Icyoung
2025-11-05 15:42:33 +08:00
committed by GitHub

View File

@@ -50,9 +50,9 @@ type PositionSnapshot struct {
// DecisionAction 决策动作 // DecisionAction 决策动作
type DecisionAction struct { type DecisionAction struct {
Action string `json:"action"` // open_long, open_short, close_long, close_short Action string `json:"action"` // open_long, open_short, close_long, close_short, update_stop_loss, update_take_profit, partial_close
Symbol string `json:"symbol"` // 币种 Symbol string `json:"symbol"` // 币种
Quantity float64 `json:"quantity"` // 数量 Quantity float64 `json:"quantity"` // 数量(部分平仓时使用)
Leverage int `json:"leverage"` // 杠杆(开仓时) Leverage int `json:"leverage"` // 杠杆(开仓时)
Price float64 `json:"price"` // 执行价格 Price float64 `json:"price"` // 执行价格
OrderID int64 `json:"order_id"` // 订单ID OrderID int64 `json:"order_id"` // 订单ID
@@ -243,8 +243,9 @@ func (l *DecisionLogger) GetStatistics() (*Statistics, error) {
switch action.Action { switch action.Action {
case "open_long", "open_short": case "open_long", "open_short":
stats.TotalOpenPositions++ stats.TotalOpenPositions++
case "close_long", "close_short": case "close_long", "close_short", "partial_close":
stats.TotalClosePositions++ stats.TotalClosePositions++
// update_stop_loss 和 update_take_profit 不計入統計
} }
} }
} }
@@ -348,11 +349,22 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
symbol := action.Symbol symbol := action.Symbol
side := "" side := ""
if action.Action == "open_long" || action.Action == "close_long" { if action.Action == "open_long" || action.Action == "close_long" || action.Action == "partial_close" {
side = "long" side = "long"
} else if action.Action == "open_short" || action.Action == "close_short" { } else if action.Action == "open_short" || action.Action == "close_short" {
side = "short" side = "short"
} }
// partial_close 需要根據持倉判斷方向
if action.Action == "partial_close" && side == "" {
for key, pos := range openPositions {
if posSymbol, _ := pos["side"].(string); key == symbol+"_"+posSymbol {
side = posSymbol
break
}
}
}
posKey := symbol + "_" + side posKey := symbol + "_" + side
switch action.Action { switch action.Action {
@@ -368,6 +380,7 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
case "close_long", "close_short": case "close_long", "close_short":
// 移除已平仓记录 // 移除已平仓记录
delete(openPositions, posKey) delete(openPositions, posKey)
// partial_close 不處理,保留持倉記錄
} }
} }
} }
@@ -382,11 +395,23 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
symbol := action.Symbol symbol := action.Symbol
side := "" side := ""
if action.Action == "open_long" || action.Action == "close_long" { if action.Action == "open_long" || action.Action == "close_long" || action.Action == "partial_close" {
side = "long" side = "long"
} else if action.Action == "open_short" || action.Action == "close_short" { } else if action.Action == "open_short" || action.Action == "close_short" {
side = "short" side = "short"
} }
// partial_close 需要根據持倉判斷方向
if action.Action == "partial_close" {
// 從 openPositions 中查找持倉方向
for key, pos := range openPositions {
if posSymbol, _ := pos["side"].(string); key == symbol+"_"+posSymbol {
side = posSymbol
break
}
}
}
posKey := symbol + "_" + side // 使用symbol_side作为key区分多空持仓 posKey := symbol + "_" + side // 使用symbol_side作为key区分多空持仓
switch action.Action { switch action.Action {
@@ -400,7 +425,7 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
"leverage": action.Leverage, "leverage": action.Leverage,
} }
case "close_long", "close_short": case "close_long", "close_short", "partial_close":
// 查找对应的开仓记录(可能来自预填充或当前窗口) // 查找对应的开仓记录(可能来自预填充或当前窗口)
if openPos, exists := openPositions[posKey]; exists { if openPos, exists := openPositions[posKey]; exists {
openPrice := openPos["openPrice"].(float64) openPrice := openPos["openPrice"].(float64)
@@ -478,8 +503,10 @@ func (l *DecisionLogger) AnalyzePerformance(lookbackCycles int) (*PerformanceAna
stats.LosingTrades++ stats.LosingTrades++
} }
// 移除已平仓记录 // 移除已平仓记录partial_close 不刪除,因為還有剩餘倉位)
delete(openPositions, posKey) if action.Action != "partial_close" {
delete(openPositions, posKey)
}
} }
} }
} }