Skip to content

The equity incorrectly increases when buying on the last day with trade_on_close = True #588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Clifford-Yen opened this issue Feb 1, 2022 · 2 comments

Comments

@Clifford-Yen
Copy link

Expected Behavior

The equity should not change when buying on the last day with trade_on_close = True.

Actual Behavior

The equity increases by data.Close[-1]/data.Close[-2] (assuming data.Close[-1] > data.Close[-2])

Steps to Reproduce

  1. Make the strategy that buys at the last candle
  2. Set trade_on_close = True

Additional info

For example, my strategy buys at the last candle and trades on close. The last closing price is 170.33 and data.Close[-2] is 159.22. And the equity was 862.479%, but it incorrectly becomes 922.584% at the last candle, which is approximately equal to 862.479%*170.33/159.22 (the error is presumably the remaining cash that is not sufficient to buy a share).
Screen Shot 2022-01-31 at 23 59 09

The possible reason for this behavior might be

class _Broker:
...
    def _process_orders(self):
        data = self._data
        open, high, low = data.Open[-1], data.High[-1], data.Low[-1]
        prev_close = data.Close[-2]
...
            else:
                # Market-if-touched / market order
                price = prev_close if self._trade_on_close else open

in backtesting.py.

This should not cause any problem if the strategy is not buying at the last candle. But when it buys at the last candle, it incorrectly takes the previous closing price as the buying price on the day it decides to buy.

I tentatively fixed it by modifying the code as follows.

class _Broker:
    def __init__(self, *, data, cash, commission, margin,
...
        self._data: _Data = data
        self._totalLengthOfData = len(data)
...
    def _process_orders(self):
        data = self._data
        open, high, low, close = data.Open[-1], data.High[-1], data.Low[-1], data.Close[-1]
        prev_close = data.Close[-2]
...
            else:
                # Market-if-touched / market order
                if self._trade_on_close:
                    price = prev_close if len(data) != self._totalLengthOfData else close
                else:
                    price = open

But I am not sure whether that would cause any other issue. I appreciate any help you can provide!

  • Backtesting version: 0.3.3
@kernc
Copy link
Owner

kernc commented Feb 5, 2022

But I am not sure whether that would cause any other issue. I appreciate any help you can provide!

It's that I'm not either. I think there are other issues related to current trade_on_close= implementation, namely:
#304
#521
#582

Someone needs to investigate. 😅

@kernc
Copy link
Owner

kernc commented Feb 4, 2025

Hopefully fixed in 4aee89a.

@kernc kernc closed this as completed Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants