backtesting.py icon indicating copy to clipboard operation
backtesting.py copied to clipboard

Incorrect commission calculation

Open esaesa opened this issue 7 months ago • 2 comments

Expected behavior

It appears the commission is being added directly to the per-unit adjusted price in: https://github.com/kernc/backtesting.py/blob/d271812c61bf42cb5df93998939109a2b13c578f/backtesting/backtesting.py#L944

Python adjusted_price_plus_commission = adjusted_price + self._commission(order.size, price) If self._commission returns a total commission for the entire order (not per unit), this addition is not correct, since it adds the entire commission fee to each unit price. The commission should either be distributed per unit before adding, or added as a lump sum after computing the total order cost.

Expected behavior: Commission should be correctly applied to the order total, not to each unit, unless self._commission returns a per-unit commission.

Suggested fix: Change the calculation so that the commission is only added once per order, or ensure that self._commission returns a per-unit fee if this logic is intended.

Code sample

bt = Backtest(
        data,
        DCAStrategy,
        cash=1000,
        commission=0.0005,
        trade_on_close=True,
        finalize_trades=True,
        margin=1/1,
    )

Actual behavior

Image

Image

Additional info, steps to reproduce, full crash traceback, screenshots

No response

Software versions

  • backtesting.__version__: 0.6.4
  • pandas.__version__: 2.2.3
  • numpy.__version__: 2.1.3
  • bokeh.__version__: 3.7.0
  • OS: Win 10

esaesa avatar May 19 '25 19:05 esaesa

It's true that the adjusted_price is per-unit and not per-order ... https://github.com/kernc/backtesting.py/blob/d271812c61bf42cb5df93998939109a2b13c578f/backtesting/backtesting.py#L941-L944 https://github.com/kernc/backtesting.py/blob/d271812c61bf42cb5df93998939109a2b13c578f/backtesting/backtesting.py#L829-L834 But applying percent-based commission is irrespective of the amount—the percentages are fixed. It's just another multiplier?

But it does, however, have an erroneous effect when using a fixed or partly-fixed commission amount:

https://github.com/kernc/backtesting.py/blob/d271812c61bf42cb5df93998939109a2b13c578f/backtesting/backtesting.py#L743-L754 https://github.com/kernc/backtesting.py/blob/d271812c61bf42cb5df93998939109a2b13c578f/backtesting/backtesting.py#L768-L769

Can you confirm my reasoning is correct?

kernc avatar May 27 '25 14:05 kernc

abs(order_size) * price * self._commission_relative Alwayse return total amount of commission because we multiply by order_size so it can't be added to unit price in adjusted_price + self._commission(order.size, price) Assume 1000$ as follows price = 1$ size=1000 commission = 1% self._commission(order.size, price) will return 1000 * 1 * 0.01 = 10$ adjusted_price_plus_commission = 1 + 10 = 11$ "It should be 1.01$" and total size after commission = 11*1000 = 11000 which is wrong . I assume the correct answer should be 1 + 1 * 0.01 = 1.01$ so the total size after commission is 1.01 * 1000 = 1010

esaesa avatar Jun 02 '25 23:06 esaesa

There is a deeper issue with the commission parameter, because it acts like a spread and alters both your win rate and the number of trades.

With commission

Image

Without commission

Image

Commission should be applied as a fee, i.e., deducted from the PnL. Currently, the only way to properly calculate commissions is to export the trades, sum the absolute value of units, deduct the number of lots, and apply the commission per lot that your Broker charges.

NichitaCP avatar Jul 28 '25 11:07 NichitaCP

Suggested fix: Change the calculation so that the commission is only added once per order

Most brokers charge commission per "side" of the trade: once when you open and once when you close the position, so you pay it twice per trade back to your currency. If you want the commission applied once, you can model it with Backtest(..., spread=...).

Other than that, the commission computations has seemingly been fixed, according to the submitted test case. Please verify. 😅

Many thanks for clear guidance!

kernc avatar Jul 30 '25 05:07 kernc