Vectorized Backtesting

Tip

This is a Jupyter Notebook, to accesss/download the ipynb file, please click the github/download icon button in the top right corner.

import pfund as pf
from IPython.display import display

pf.__version__
'0.0.2'

Create backtest() in Strategy

backtest() in strategy is only used for vectorized backtesting, which is for strategy prototyping.

class DemoStrategy(pf.Strategy):
    def backtest(self):
        # NOTE: in the future, this dataframe will change depending on your chosen data tool, e.g. pandas, polars, pyspark etc.
        # a dataframe with added data is prepared for you automatically
        print(f'Printing dataframe of Strategy "{self.name}":\n')
        display(self.df.head())

        # TODO: fill in strategy logic
        # TODO: show metrics using pyfolio

Workflow: engine -> strategy -> data -> run()

# Step 1. initialize backtest engine
engine = pf.BacktestEngine(mode='vectorized')

# Step 2. add strategy to engine
strategy = engine.add_strategy(DemoStrategy(), name='demo_strategy')

# Step 3. add data to strategy
## add yfinance data
'''
IB = Interactive Brokers
AAPL = Stock ticker for Apple Inc.
USD = Quote currency
STK = Stock
1d = 1-day data
'''
strategy.add_data(
    'IB', 'AAPL', 'USD', 'STK', resolutions=['1d'],
    backtest={
        # NOTE: since IB does not provide any historical data for backtesting purpose, use data from 'YAHOO_FINANCE'
        'data_source': 'YAHOO_FINANCE',
        'start_date': '2024-01-01',
        'end_date': '2024-02-01',
    }
)

## add crypto data
'''
BYBIT = Bybit Cryptocurrency Exchange
BTC = Bitcoin
USDT = Tether
PERP = Perpetual (a trading product)
2d = 2-day data
'''
strategy.add_data(
    'BYBIT', 'BTC', 'USDT', 'PERP', resolutions=['2d'],
    backtest={
        # NOTE: since BYBIT does provide historical data, no need to specify 'data_source'
        # since it will be downloading data on the fly from https://public.bybit.com/trading/, only get a few dates of data
        'start_date': '2024-01-01',
        'end_date': '2024-01-02',  
    }
)

# Step 4. run engine
engine.run()
Hide code cell output
BACKTEST Engine is running
created /home/runner/.local/share/pfund/hub/strategies
created /home/runner/.local/share/pfund/hub/models
created /home/runner/.local/share/pfund/hub/features
created /home/runner/.local/share/pfund/hub/indicators
created /home/runner/.local/share/pfund/backtests
created /home/runner/.local/share/pfund/templates/notebooks
created /home/runner/.local/share/pfund/templates/spreadsheets
created /home/runner/.local/share/pfund/templates/dashboards
created /home/runner/.local/state/log/pfund/BACKTEST
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[3], line 2
      1 # Step 1. initialize backtest engine
----> 2 engine = pf.BacktestEngine(mode='vectorized')
      4 # Step 2. add strategy to engine
      5 strategy = engine.add_strategy(DemoStrategy(), name='demo_strategy')

File /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/pfund/engines/backtest_engine.py:92, in BacktestEngine.__new__(cls, env, data_tool, mode, use_signal_df, assert_signals, commit_to_git, save_backtests, retention_period, num_chunks, use_ray, num_cpus, config, **settings)
     90             cls.num_chunks = cls.num_cpus
     91             print(f'num_chunks is adjusted to {num_cpus} because {num_cpus=}')
---> 92 return super().__new__(
     93     cls,
     94     env,
     95     data_tool=data_tool,
     96     config=config,
     97     **settings
     98 )

File /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/pfund/engines/base_engine.py:64, in BaseEngine.__new__(cls, env, data_tool, config, **settings)
     62     log_path = f'{cls.config.log_path}/{cls.env}'
     63     logging_config_file_path = cls.config.logging_config_file_path
---> 64     cls.logging_configurator: LoggingDictConfigurator  = set_up_loggers(log_path, logging_config_file_path, user_logging_config=cls.config.logging_config)
     65 if not hasattr(cls, 'settings'):
     66     from IPython import get_ipython

File /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/pfund/plogging/__init__.py:51, in set_up_loggers(log_path, logging_config_file_path, user_logging_config)
     48 # ≈ logging.config.dictConfig(logging_config) with a custom configurator
     50 logging_configurator = LoggingDictConfigurator(logging_config)
---> 51 logging_configurator.configure()
     52 return logging_configurator

File /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/logging/config.py:506, in DictConfigurator.configure(self)
    504 config = self.config
    505 if 'version' not in config:
--> 506     raise ValueError("dictionary doesn't specify a version")
    507 if config['version'] != 1:
    508     raise ValueError("Unsupported version: %s" % config['version'])

ValueError: dictionary doesn't specify a version

Warning

You can’t run engine.run() again since all the raw data have been erased. For some reason, if you want to get the df of the strategy, you can:

df = strategy.get_df()
df
Hide code cell output
open high low close volume dividends stock_splits index
ts product resolution
2023-12-31 00:00:00 CRYPTO-BYBIT-BTC_USDT_PERP 2d 42324.900000 44284.900000 42211.200000 44235.500000 7.912344e+04 NaN NaN 0.0
2024-01-02 05:00:00 IB-SMART-AAPL_USD_STK 1d 186.911482 188.199846 183.655642 185.403412 8.248870e+07 0.0 0.0 NaN
2024-01-03 05:00:00 IB-SMART-AAPL_USD_STK 1d 183.985237 185.643125 183.196235 184.015198 5.841450e+07 0.0 0.0 NaN
2024-01-04 05:00:00 IB-SMART-AAPL_USD_STK 1d 181.917861 182.856666 180.649491 181.678177 7.198360e+07 0.0 0.0 NaN
2024-01-05 05:00:00 IB-SMART-AAPL_USD_STK 1d 181.758077 182.527085 179.940389 180.949097 6.230330e+07 0.0 0.0 NaN
2024-01-08 05:00:00 IB-SMART-AAPL_USD_STK 1d 181.857938 185.363474 181.268693 185.323517 5.914450e+07 0.0 0.0 NaN
2024-01-09 05:00:00 IB-SMART-AAPL_USD_STK 1d 183.685606 184.914035 182.497120 184.904053 4.284180e+07 0.0 0.0 NaN
2024-01-10 05:00:00 IB-SMART-AAPL_USD_STK 1d 184.115062 186.162437 183.685602 185.952713 4.679290e+07 0.0 0.0 NaN
2024-01-11 05:00:00 IB-SMART-AAPL_USD_STK 1d 186.302271 186.811631 183.385994 185.353485 4.912840e+07 0.0 0.0 NaN
2024-01-12 05:00:00 IB-SMART-AAPL_USD_STK 1d 185.822881 186.502022 184.953994 185.683060 4.044470e+07 0.0 0.0 NaN
2024-01-16 05:00:00 IB-SMART-AAPL_USD_STK 1d 181.927853 184.025168 180.699410 183.395981 6.560300e+07 0.0 0.0 NaN
2024-01-17 05:00:00 IB-SMART-AAPL_USD_STK 1d 181.038998 182.696871 180.070233 182.447189 4.731740e+07 0.0 0.0 NaN
2024-01-18 05:00:00 IB-SMART-AAPL_USD_STK 1d 185.852846 188.898962 185.593183 188.389618 7.800580e+07 0.0 0.0 NaN
2024-01-19 05:00:00 IB-SMART-AAPL_USD_STK 1d 189.088718 191.705375 188.579374 191.315872 6.874100e+07 0.0 0.0 NaN
2024-01-22 05:00:00 IB-SMART-AAPL_USD_STK 1d 192.054929 195.081066 192.014971 193.642899 6.013390e+07 0.0 0.0 NaN
2024-01-23 05:00:00 IB-SMART-AAPL_USD_STK 1d 194.771475 195.500540 193.582989 194.931259 4.235560e+07 0.0 0.0 NaN
2024-01-24 05:00:00 IB-SMART-AAPL_USD_STK 1d 195.170947 196.129730 194.092321 194.252121 5.363130e+07 0.0 0.0 NaN
2024-01-25 05:00:00 IB-SMART-AAPL_USD_STK 1d 194.971211 196.019876 192.863900 193.922546 5.482210e+07 0.0 0.0 NaN
2024-01-26 05:00:00 IB-SMART-AAPL_USD_STK 1d 194.022423 194.511788 191.695390 192.174774 4.459400e+07 0.0 0.0 NaN
2024-01-29 05:00:00 IB-SMART-AAPL_USD_STK 1d 191.765299 191.955059 189.338403 191.485657 4.714560e+07 0.0 0.0 NaN
2024-01-30 05:00:00 IB-SMART-AAPL_USD_STK 1d 190.696667 191.555572 187.231088 187.800354 5.585940e+07 0.0 0.0 NaN
2024-01-31 05:00:00 IB-SMART-AAPL_USD_STK 1d 186.801628 186.861565 184.115069 184.164993 5.546780e+07 0.0 0.0 NaN