Backtest.plot() fails with resampling
Expected Behavior
charts plotted
Actual Behavior
following exception:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[52], line 1
----> 1 bt.plot(resample='2H')
File [~/miniforge3/lib/python3.10/site-packages/backtesting/backtesting.py:1592](https://file+.vscode-resource.vscode-cdn.net/Users/pgm/Projects/crypto-dl/src/model/~/miniforge3/lib/python3.10/site-packages/backtesting/backtesting.py:1592), in Backtest.plot(self, results, filename, plot_width, plot_equity, plot_return, plot_pl, plot_volume, plot_drawdown, smooth_equity, relative_equity, superimpose, resample, reverse_indicators, show_legend, open_browser)
1589 raise RuntimeError('First issue `backtest.run()` to obtain results.')
1590 results = self._results
-> 1592 return plot(
1593 results=results,
1594 df=self._data,
1595 indicators=results._strategy._indicators,
1596 filename=filename,
1597 plot_width=plot_width,
1598 plot_equity=plot_equity,
1599 plot_return=plot_return,
1600 plot_pl=plot_pl,
1601 plot_volume=plot_volume,
1602 plot_drawdown=plot_drawdown,
1603 smooth_equity=smooth_equity,
1604 relative_equity=relative_equity,
1605 superimpose=superimpose,
1606 resample=resample,
1607 reverse_indicators=reverse_indicators,
1608 show_legend=show_legend,
...
147 mean_time = int(bars.loc[s.index].view(int).mean())
--> 148 new_bar_idx = new_index.get_loc(mean_time, method='nearest')
149 return new_bar_idx
TypeError: Index.get_loc() got an unexpected keyword argument 'method'
Steps to Reproduce
class WhateverStrategy(Strategy):
def init(self):
pass
def next(self):
close = self.data.Close[-1]
if close > 55 and (not self.position.is_short):
self.sell()
elif close < 25 and (not self.position.is_long):
self.buy()
bt = Backtest(df, WhateverStrategy, commission=0.0002, cash=100)
bt.run()
bt.plot(resample='2H')
Additional info
- Backtesting: 0.3.3
- bokeh: 3.1.1
- pandas: 2.0.1
- OS: macOS Ventura 13.3.1 arm64
however, if I change next method to following:
def next(self):
pass
chart would be plotted successfully without equity curve
the dataset contains 800k+ of 1M candles
Hi there @bellerofonte , I tried to reproduce your error but without success.
However this seems to be related to your pandas version as in version 2.0.1 the get_loc function no longer takes method as parameter
https://pandas.pydata.org/docs/reference/api/pandas.Index.get_loc.html
I used pandas version 1.4.4 https://pandas.pydata.org/pandas-docs/version/1.4/reference/api/pandas.Index.get_loc.html
However after upgrading to 2.0.1 the error still did not appear. Would need your data and code on how you created your dataframe to dive deeper.
You can try to downgrade pandas to 1.4.4 to see if it'll work.
Here is my code and data for reference.
CODE
from backtesting import Strategy, Backtest
import pandas as pd
link_to_issue = 'https://github.com/kernc/backtesting.py/issues/987'
df = pd.read_csv('../market_data/BTCUSDT-5m-data.csv', parse_dates=True, index_col=0)
df = df[['open', 'high', 'low', 'close']]
df.columns = map(lambda x: str(x).capitalize(), df.columns)
print(df)
class WhateverStrategy(Strategy):
def init(self):
pass
def next(self):
close = self.data.Close[-1]
if close > 55 and (not self.position.is_short):
self.sell()
elif close < 25 and (not self.position.is_long):
self.buy()
bt = Backtest(df, WhateverStrategy, commission=0.0002, cash=100)
bt.run()
bt.plot(resample='2H')
OUPUT
/Users/dominik/Desktop/vola_statistics/venv/bin/python /Users/dominik/Desktop/vola_statistics/tests/stackoverflow_issue.py
Open High Low Close
timestamp
2017-08-17 04:00:00 4261.48 4280.56 4261.48 4261.48
2017-08-17 04:05:00 4261.48 4261.48 4261.48 4261.48
2017-08-17 04:10:00 4261.48 4261.48 4261.48 4261.48
2017-08-17 04:15:00 4261.48 4264.88 4261.48 4261.48
2017-08-17 04:20:00 4264.88 4266.29 4264.88 4266.29
... ... ... ... ...
2023-05-04 08:45:00 29060.07 29078.22 29058.24 29073.02
2023-05-04 08:50:00 29073.02 29085.62 29073.02 29078.52
2023-05-04 08:55:00 29078.51 29094.02 29077.75 29089.26
2023-05-04 09:00:00 29089.26 29109.65 29082.49 29084.84
2023-05-04 09:05:00 29084.83 29084.84 29078.18 29078.18
[599127 rows x 4 columns]
/Users/dominik/Desktop/vola_statistics/tests/stackoverflow_issue.py:24: UserWarning: Some prices are larger than initial cash value. Note that fractional trading is not supported. If you want to trade Bitcoin, increase initial cash, or trade μBTC or satoshis instead (GH-134).
bt = Backtest(df, WhateverStrategy, commission=0.0002, cash=100)
Process finished with exit code 0
Candles have been successfully resampled to 2H
I used 5min data.
I'm getting the same error. Of note, if I reset the index in the dataframe from a datetime index to a regular integer index then the plot works. My pandas was also v 2.0.1
I just needed something quick so I haven't had a chance to deal with it and doubt I will. I just thought I would share here in case it helps you all to diagnose it.
Not sure if this would work, but it seems like they cover this issue here.
I will volunteer to do pr if it is as simple as changing the line in _plotting.py
from new_bar_idx = new_index.get_loc(mean_time, method='nearest') to
new_bar_idx = new_index.get_indexer(mean_time, method='nearest')[0] but I doubt anything is that simple.
cc @kernc
@eervin123 Thank you for sharing. Additionally could you send your code and data you used. Because I struggle to reproduce on my side. Will help me to better diagnose why it works with my data and df setup. I volunteer to create and propose some unit-tests for this. Regards, Dominik
Okay @DominikBerger01 I'll try to get to that tonight. PST
fyi, I was able to get it to work with bt.plot(resample=False)
@DominikBerger01 here you go. the error_example.ipynb file should be enough to isolate the problem. I also included two environment files, one which is my regular env. the other is a clean test environment where i just pip installed backtesting and scikit-optimize.
Happy hunting 😊
@eervin123 Many thanks, will start exploring tomorrow morning. ;)
I was able to reproduce the bug. After trying to solve it I have found that it already was solved and pushed to main back in Dezember 2022. But it is not yet reflected in the latest distributed version.
This was the PR: https://github.com/kernc/backtesting.py/commit/dfba4615e851e7895aab7456f909dad45e6a0134
Also looks to me like the correct implementation as all tests passed:
OLD (causing error and tests to fail)
NEW
So I guess we'll have to wait for the next release. Which in my opinion should happen sooner than later as most of the people getting the current version will be bugged by this. :)
@DominikBerger01 @eervin123 thank you for your effort spent on finding the problem!
Is it a good idea to add [0] directly into _plotting.py in my packages directory until new release appears?
@bellerofonte You also would need to change it from get_loc to get_indexer then add the [0]
I haven't tried this yet but it is pretty simple to make the change and then try it out. If it doesn't work you can undo the change and all will be as before.
Thank you to you @DominikBerger01 for investigating. Open source FTW!
@DominikBerger01 @eervin123 thank you for your effort spent on finding the problem!
Is it a good idea to add
[0]directly into_plotting.pyin my packages directory until new release appears?
You could change the source code. However I wouldn't recommend it. A more common approach would be to pip install the latest changes directly from Github.
Here is how:
Step 1
Uninstall your current backtesting installation:
pip uninstall Backtesting
Step 2
get the link from the repo and add git+ in front and pip install it
pip install git+https://github.com/kernc/backtesting.py.git
This should install the latest changes from master branch
Step 3
run pip freeze and you should see
Backtesting @ git+https://github.com/kernc/backtesting.py.git@0ce24d80b1bcb8120d95d31dc3bb351b1052a27d your new backtesting installation along with your other installed packages.
The hash you see at the end btw refers to the hash of the latest commit: (0ce24d80b1bcb8120d95d31dc3bb351b1052a27d)
Now you have the latest version with unreleased changes which should fix your bug. Hope this helps. If yes, you can accept the answer and close the issue. ;)
Step 2 get the link from the repo and add git+ in front and pip install it
pip install git+https://github.com/kernc/backtesting.py.git
@DominikBerger01 I can confirm your method solves the issue. Thanks a lot!
Just wanted to help out, Index.get_loc() method got deprecated after pandas 1.4. You can just downgrade pandas to 1.4.0 and it should work :)
Source: https://pandas.pydata.org/pandas-docs/version/1.5/reference/api/pandas.Index.get_loc.html
@DominikBerger01 @eervin123 thank you for your effort spent on finding the problem! Is it a good idea to add
[0]directly into_plotting.pyin my packages directory until new release appears?You could change the source code. However I wouldn't recommend it. A more common approach would be to pip install the latest changes directly from Github.
Here is how:
Step 1 Uninstall your current backtesting installation:
pip uninstall BacktestingStep 2 get the link from the repo and add
git+in front and pip install itpip install git+https://github.com/kernc/backtesting.py.gitThis should install the latest changes from
masterbranchStep 3 run
pip freezeand you should seeBacktesting @ git+https://github.com/kernc/backtesting.py.git@0ce24d80b1bcb8120d95d31dc3bb351b1052a27dyour new backtesting installation along with your other installed packages.The hash you see at the end btw refers to the hash of the latest commit: (0ce24d8)
Now you have the latest version with unreleased changes which should fix your bug. Hope this helps. If yes, you can accept the answer and close the issue. ;)
I just got this error, and the steps quoted above from a prior post fixed my issue. Thanks! I'm looking forward to the next release so this issue is fixed without the work around.
