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()
Show 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
Show 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 |