vectorbt icon indicating copy to clipboard operation
vectorbt copied to clipboard

Metric shows incorrect value in portfolio statistics

Open tradermachina-web opened this issue 5 months ago • 2 comments

I found an inconsistency in the portfolio statistics calculation. The Best Trade [%] metric displays 0.929219%, but when I analyze my actual trades using pf.trades.records_readable, the best trade is actually 1.157143% (Trade ID 153), not 0.93%.

context: My backtest uses negative capital (short-only strategy), which may be related to this calculation error.At first, I thought Portfolio Statistics might be using the current capital value for the calculation, but since the backtest keeps the account always in negative, this wouldn't be consistent either.

issue: On the trades plot/chart, many trades are also missing and not visible, which suggests a broader problem with how trades are being processed or displayed.

capital used: The capital I'm using is the same that I passed in init_cash=CAPITAL and for the calculation trades_clean['PnL %'], which is 1,000,000.

Statistics :

Start                               2025-01-02 09:00:00
End                                 2025-11-05 00:55:00
Period                                139 days 21:45:00
Start Value                                   1000000.0
End Value                                 968867.126509
Total Return [%]                              -3.113287
Benchmark Return [%]                          19.514706
Max Gross Exposure [%]                       517.763041
Total Fees Paid                                     0.0
Max Drawdown [%]                               5.361855
Max Drawdown Duration                 127 days 05:50:00
Total Trades                                        198
Total Closed Trades                                 198
Total Open Trades                                     0
Open Trade PnL                                      0.0
Win Rate [%]                                  19.191919
Best Trade [%]                                 0.929219  ← ERROR
Worst Trade [%]                               -0.323281
Avg Winning Trade [%]                          0.141278
Avg Losing Trade [%]                          -0.054745
Avg Winning Trade Duration    0 days 01:25:23.684210526
Avg Losing Trade Duration     0 days 00:27:08.025477707
Profit Factor                                  0.790508
Expectancy                                  -171.578702
Sharpe Ratio                                  -1.128709
Calmar Ratio                                  -1.477118
Omega Ratio                                    0.942158
Sortino Ratio                                 -1.637499

Trades Records :

CAPITAL = 1000000.0  # Initial capital
trades = pf.trades.records_readable
trades_clean = trades.copy()
trades_clean['PnL %'] = trades_clean['PnL'] / CAPITAL * 100
top_10_trades = trades_clean.sort_values(by='PnL %', ascending=False).head(10)
print(top_10_trades.to_string(index=False))

PnL% ERROR ----------------------------------->------------------------------------------------------------------------------------------------->--------------------------------------------v                                                                                                                                                                                                                                                           
Exit Trade Id  Column         Size     Entry Timestamp  Avg Entry Price  Entry Fees      Exit Timestamp  Avg Exit Price  Exit Fees          PnL   Return Direction Status  Position Id    PnL %
          153       0  7142.857143 2025-09-02 09:35:00           566.73         0.0 2025-09-02 10:25:00        565.1100        0.0 11571.428571 0.002859     Short Closed          153 1.157143
           13       0 33333.333333 2025-01-24 09:35:00           532.24         0.0 2025-01-24 10:15:00        531.9300        0.0 10333.333333 0.000582     Short Closed           13 1.033333
          169       0  3333.333333 2025-09-25 09:35:00           595.60         0.0 2025-09-25 11:55:00        592.6100        0.0  9966.666667 0.005020     Short Closed          169 0.996667
          146       0 11111.111111 2025-08-19 09:35:00           577.23         0.0 2025-08-19 10:50:00        576.3700        0.0  9555.555556 0.001490     Short Closed          146 0.955556
           53       0 50000.000000 2025-03-26 09:35:00           492.81         0.0 2025-03-26 09:45:00        492.6300        0.0  9000.000000 0.000365     Short Closed           53 0.900000

Trades PnL and Cumulative Return : Image

tradermachina-web avatar Nov 06 '25 18:11 tradermachina-web

All trade statistics, including "Best Trade [%]", are computed from the internal trade records associated with the portfolio object (pf.trades). The stats are a direct aggregation of those records, where the percent return per trade is typically based on trade PnL relative to position sizing. In this context, the "Best Trade [%]" metric represents the highest positive value in the "Return" column of the closed pf.trades object. Each trade return is calculated relative to its own position value, so the statistic is self contained. I am not sure what your graphs are intended to show. Trade PnL is plotted correctly, and the equity curve probably just needs some zooming, but with positive trades it should generally track the benchmark.

polakowo avatar Nov 07 '25 09:11 polakowo

Exactly, this is the Trade Return, calculated relative to the position value, and not the PnL relative to total capital.

Image

I found 0.929219%

Thanks for clarifying!

tradermachina-web avatar Nov 07 '25 17:11 tradermachina-web