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

Issue with bt.plot()

Open btk-42 opened this issue 1 year ago • 4 comments

Expected Behavior

bt.plot() doesn't show up and returns error.

Actual Behavior

error:

/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/test/__init__.py:8: FutureWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
  return pd.read_csv(join(dirname(__file__), filename),
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/test/__init__.py:8: FutureWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
  return pd.read_csv(join(dirname(__file__), filename),
Traceback (most recent call last):
  File "/home/my_login/test/app.py", line 28, in <module>
    bt.plot()
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/backtesting.py", line 1592, in plot
    return plot(
           ^^^^^
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/_plotting.py", line 250, in plot
    formatter=DatetimeTickFormatter(days=['%d %b', '%a %d'],
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/models/formatters.py", line 593, in __init__
    super().__init__(*args, **kwargs)
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/models/formatters.py", line 93, in __init__
    super().__init__(*args, **kwargs)
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/model/model.py", line 119, in __init__
    super().__init__(**kwargs)
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/core/has_props.py", line 304, in __init__
    setattr(self, name, value)
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/core/has_props.py", line 336, in __setattr__
    return super().__setattr__(name, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/core/property/descriptors.py", line 330, in __set__
    value = self.property.prepare_value(obj, self.name, value)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/bokeh/core/property/bases.py", line 363, in prepare_value
    raise ValueError(f"failed to validate {obj_repr}.{name}: {error}")
ValueError: failed to validate DatetimeTickFormatter(id='p1046', ...).days: expected a value of type str, got ['%d %b', '%a %d'] of type list

Steps to Reproduce

  1. Install backtesting
  2. run example code

code:

from backtesting import Backtest, Strategy
from backtesting.lib import crossover

from backtesting.test import SMA, GOOG


class SmaCross(Strategy):
    n1 = 10
    n2 = 20

    def init(self):
        close = self.data.Close
        self.sma1 = self.I(SMA, close, self.n1)
        self.sma2 = self.I(SMA, close, self.n2)

    def next(self):
        if crossover(self.sma1, self.sma2):
            self.buy()
        elif crossover(self.sma2, self.sma1):
            self.sell()


bt = Backtest(GOOG, SmaCross,
              cash=10000, commission=.002,
              exclusive_orders=True)

output = bt.run()
bt.plot()

Additional info

Installing bokeh==3.4.2 fix the issue but makes everything lag and some other errors appears

/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/test/__init__.py:8: FutureWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
  return pd.read_csv(join(dirname(__file__), filename),
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/test/__init__.py:8: FutureWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
  return pd.read_csv(join(dirname(__file__), filename),
BokehDeprecationWarning: Passing lists of formats for DatetimeTickFormatter scales was deprecated in Bokeh 3.0. Configure a single string format for each scale
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/_plotting.py:250: UserWarning: DatetimeFormatter scales now only accept a single format. Using the first provided: '%d %b'
  formatter=DatetimeTickFormatter(days=['%d %b', '%a %d'],
BokehDeprecationWarning: Passing lists of formats for DatetimeTickFormatter scales was deprecated in Bokeh 3.0. Configure a single string format for each scale
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/_plotting.py:250: UserWarning: DatetimeFormatter scales now only accept a single format. Using the first provided: '%m/%Y'
  formatter=DatetimeTickFormatter(days=['%d %b', '%a %d'],
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/_plotting.py:456: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  .resample(resample_rule, label='left')
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/_plotting.py:659: UserWarning: found multiple competing values for 'toolbar.active_drag' property; using the latest value
  fig = gridplot(
/home/my_login/.virtualenvs/test-gwyt/lib/python3.12/site-packages/backtesting/_plotting.py:659: UserWarning: found multiple competing values for 'toolbar.active_scroll' property; using the latest value
  fig = gridplot(

btk-42 avatar Jul 13 '24 22:07 btk-42

Install the latest version from GitHub to incorporate recent fixes: pip install git+https://github.com/kernc/backtesting.py.git

The PyPI version (0.3.3) may not include the necessary fix

sirkuredda avatar Jul 17 '24 10:07 sirkuredda

The solution is : In the file named _plotting.py

if is_datetime_index:
       fig_ohlc.xaxis.formatter = CustomJSTickFormatter(
        args=dict(axis=fig_ohlc.xaxis[0],
                  formatter=DatetimeTickFormatter(
                      days="%d %b %Y",     # Example format for days
                      months="%b %Y",      # Example format for months
                      hours="%H:%M",       # Example format for hours
                      minutes="%H:%M",     # Example format for minutes
                      seconds="%H:%M:%S"   # Example format for seconds
                  ),
                  source=source)

Best regards

Dante-Berth avatar Aug 09 '24 19:08 Dante-Berth

Install the latest version from GitHub to incorporate recent fixes: pip install git+https://github.com/kernc/backtesting.py.git

The PyPI version (0.3.3) may not include the necessary fix

This helped me a lot, i was pulling out my hair yesterday trying to get this to work i tried everything under the sun, thank you so much, when will PyPi be updated to reflect the new changes?

ghost avatar Aug 13 '24 14:08 ghost

I experienced the same issue and came across this thread.

THe solution here works perfectly (https://github.com/kernc/backtesting.py/issues/1158#issuecomment-2232993016)

When will we have the update in PyPI please?

Thank you!!

kenho811 avatar Sep 18 '24 11:09 kenho811

if is_datetime_index: fig_ohlc.xaxis.formatter = CustomJSTickFormatter( args=dict(axis=fig_ohlc.xaxis[0], formatter=DatetimeTickFormatter( days="%d %b %Y", # Example format for days months="%b %Y", # Example format for months hours="%H:%M", # Example format for hours minutes="%H:%M", # Example format for minutes seconds="%H:%M:%S" # Example format for seconds ),

installing from git returning same error

S1x-Data-Team avatar Oct 26 '24 20:10 S1x-Data-Team

Not sure if this is still relevant but I had the same error until I made some adjustments to the initial data frame.

Initially, df = yf.Ticker("SPY").history(start='2010-01-01', end='2021-01-01').tz_localize(None) df.drop('Dividends', axis=1, inplace=True) df.drop('Stock Splits', axis=1, inplace=True) df.drop('Capital Gains', axis=1, inplace=True) df=df[df.High!=df.Low]

returned "ValueError: failed to validate DatetimeTickFormatter(id='p1996', ...).days: expected a value of type str, got ['%d %b', '%a %d'] of type list" for bt.plot()

But once I reset the index:

df = yf.Ticker("SPY").history(start='2010-01-01', end='2021-01-01').tz_localize(None)

df=df[df.High!=df.Low] df.drop('Dividends', axis=1, inplace=True) df.drop('Stock Splits', axis=1, inplace=True) df.drop('Capital Gains', axis=1, inplace=True) df.reset_index(inplace=True)

bt.plot() returns the figures

jkim12johnkim avatar Nov 19 '24 15:11 jkim12johnkim

pip install git... resolved it for me. thanks!

CoyoteCute avatar Nov 28 '24 20:11 CoyoteCute

pip install git+.. is the solution

yttasdfghjk avatar Dec 23 '24 02:12 yttasdfghjk

Is there any particular reason why you don't update the release on pypi?

rbarghou avatar Jan 06 '25 02:01 rbarghou

The original issue has been fixed and 3fcb4ac526b07f22eb0b2f64496eff56b79848cc. Fix released. 🎆

kernc avatar Feb 01 '25 15:02 kernc