@@ -113,9 +113,12 @@ def _calc_pnl_percent(entry_price: float, size: float, pnl: float, leverage: flo
113113 return 0.0
114114
115115
116- def _compute_performance_stats (trades : List [Dict [str , Any ]]) -> Dict [str , Any ]:
116+ def _compute_performance_stats (trades : List [Dict [str , Any ]], initial_capital : float = 0.0 ) -> Dict [str , Any ]:
117117 """
118118 Compute performance statistics from trade history.
119+ Args:
120+ trades: List of trade records
121+ initial_capital: Initial capital for calculating equity curve (default: 0.0, will use cumulative profit peak as baseline)
119122 Returns: {
120123 total_trades, winning_trades, losing_trades, win_rate,
121124 total_profit, total_loss, profit_factor,
@@ -163,23 +166,49 @@ def _compute_performance_stats(trades: List[Dict[str, Any]]) -> Dict[str, Any]:
163166 max_win = max (profits ) if profits else 0.0
164167 max_loss = min (profits ) if profits else 0.0
165168
166- # Calculate max drawdown from cumulative equity
167- cumulative = []
168- acc = 0.0
169+ # Calculate max drawdown from equity curve (initial_capital + cumulative profit)
170+ # This ensures proper percentage calculation even when cumulative profit is negative
171+ cumulative_profit = 0.0
172+ equity_curve = []
169173 for p in profits :
170- acc += p
171- cumulative .append (acc )
174+ cumulative_profit += p
175+ equity = initial_capital + cumulative_profit
176+ equity_curve .append (equity )
172177
173- peak = 0.0
178+ # Calculate max drawdown from equity curve
179+ peak_equity = initial_capital if initial_capital > 0 else (equity_curve [0 ] if equity_curve else 0.0 )
174180 max_drawdown = 0.0
175- for val in cumulative :
176- if val > peak :
177- peak = val
178- dd = peak - val
179- if dd > max_drawdown :
180- max_drawdown = dd
181-
182- max_drawdown_pct = (max_drawdown / peak * 100 ) if peak > 0 else 0.0
181+ for equity in equity_curve :
182+ if equity > peak_equity :
183+ peak_equity = equity
184+ # Drawdown is the drop from peak
185+ drawdown = peak_equity - equity
186+ if drawdown > max_drawdown :
187+ max_drawdown = drawdown
188+
189+ # Calculate drawdown percentage: drawdown / peak_equity * 100
190+ # If peak_equity is 0 or very small, use a fallback calculation
191+ if peak_equity > 0 :
192+ max_drawdown_pct = (max_drawdown / peak_equity * 100 )
193+ elif initial_capital > 0 :
194+ # Fallback: use initial capital as baseline
195+ max_drawdown_pct = (max_drawdown / initial_capital * 100 ) if initial_capital > 0 else 0.0
196+ else :
197+ # Last resort: if no initial capital and peak is 0, calculate from cumulative profit peak
198+ cumulative = []
199+ acc = 0.0
200+ for p in profits :
201+ acc += p
202+ cumulative .append (acc )
203+ peak_profit = max (cumulative ) if cumulative else 0.0
204+ if peak_profit > 0 :
205+ max_drawdown_pct = (max_drawdown / peak_profit * 100 )
206+ else :
207+ max_drawdown_pct = 0.0
208+
209+ # Cap drawdown percentage at reasonable maximum (e.g., 10000%) to avoid display issues
210+ if max_drawdown_pct > 10000 :
211+ max_drawdown_pct = 10000.0
183212
184213 # Best/worst day
185214 day_profits : Dict [str , float ] = {}
@@ -243,9 +272,9 @@ def _compute_strategy_stats(trades: List[Dict[str, Any]], strategies: List[Dict[
243272
244273 result = []
245274 for sid , strades in sid_to_trades .items ():
246- stats = _compute_performance_stats (strades )
247- total_pnl = sum (_safe_float (t .get ("profit" ), 0.0 ) for t in strades )
248275 capital = sid_to_capital .get (sid , 0.0 )
276+ stats = _compute_performance_stats (strades , initial_capital = capital )
277+ total_pnl = sum (_safe_float (t .get ("profit" ), 0.0 ) for t in strades )
249278 roi = (total_pnl / capital * 100 ) if capital > 0 else 0.0
250279
251280 result .append ({
@@ -374,20 +403,20 @@ def _truthy(v: Any) -> bool:
374403 trade ['created_at' ] = int (trade ['created_at' ].timestamp ())
375404 recent_trades .append (trade )
376405
377- # Compute performance statistics
378- perf_stats = _compute_performance_stats (recent_trades )
379-
380- # Compute per-strategy statistics
381- strategy_stats = _compute_strategy_stats (recent_trades , strategies )
382-
383- # Total equity/pnl (best-effort)
406+ # Total equity/pnl (best-effort) - calculate before performance stats for drawdown calculation
384407 total_initial_capital = 0.0
385408 for s in strategies :
386409 try :
387410 total_initial_capital += float (s .get ("initial_capital" ) or 0.0 )
388411 except Exception :
389412 pass
390413
414+ # Compute performance statistics with initial capital for proper drawdown calculation
415+ perf_stats = _compute_performance_stats (recent_trades , initial_capital = total_initial_capital )
416+
417+ # Compute per-strategy statistics
418+ strategy_stats = _compute_strategy_stats (recent_trades , strategies )
419+
391420 # Include realized PnL from trades
392421 total_realized_pnl = sum (_safe_float (t .get ("profit" ), 0.0 ) for t in recent_trades )
393422 total_pnl = float (total_unrealized_pnl + total_realized_pnl )
0 commit comments