Multi-dataset `backtesting.backtesting.Backtest` wrapper. Run supplied `backtesting.backtesting.Strategy` on several instruments, in parallel. Used for comparing strategy runs across many instruments or classes of instruments. Example: from backtesting.test import EURUSD,
| 566 | |
| 567 | |
| 568 | class MultiBacktest: |
| 569 | """ |
| 570 | Multi-dataset `backtesting.backtesting.Backtest` wrapper. |
| 571 | |
| 572 | Run supplied `backtesting.backtesting.Strategy` on several instruments, |
| 573 | in parallel. Used for comparing strategy runs across many instruments |
| 574 | or classes of instruments. Example: |
| 575 | |
| 576 | from backtesting.test import EURUSD, BTCUSD, SmaCross |
| 577 | btm = MultiBacktest([EURUSD, BTCUSD], SmaCross) |
| 578 | stats_per_ticker: pd.DataFrame = btm.run(fast=10, slow=20) |
| 579 | heatmap_per_ticker: pd.DataFrame = btm.optimize(...) |
| 580 | """ |
| 581 | def __init__(self, df_list, strategy_cls, **kwargs): |
| 582 | self._dfs = df_list |
| 583 | self._strategy = strategy_cls |
| 584 | self._bt_kwargs = kwargs |
| 585 | |
| 586 | def run(self, **kwargs): |
| 587 | """ |
| 588 | Wraps `backtesting.backtesting.Backtest.run`. Returns `pd.DataFrame` with |
| 589 | currency indexes in columns. |
| 590 | """ |
| 591 | from . import Pool |
| 592 | with Pool() as pool, \ |
| 593 | SharedMemoryManager() as smm: |
| 594 | shm = [smm.df2shm(df) for df in self._dfs] |
| 595 | results = _tqdm( |
| 596 | pool.imap(self._mp_task_run, |
| 597 | ((df_batch, self._strategy, self._bt_kwargs, kwargs) |
| 598 | for df_batch in _batch(shm))), |
| 599 | total=len(shm), |
| 600 | desc=self.run.__qualname__, |
| 601 | mininterval=2 |
| 602 | ) |
| 603 | df = pd.DataFrame(list(chain(*results))).transpose() |
| 604 | return df |
| 605 | |
| 606 | @staticmethod |
| 607 | def _mp_task_run(args): |
| 608 | data_shm, strategy, bt_kwargs, run_kwargs = args |
| 609 | dfs, shms = zip(*(SharedMemoryManager.shm2df(i) for i in data_shm)) |
| 610 | try: |
| 611 | return [stats.filter(regex='^[^_]') if stats['# Trades'] else None |
| 612 | for stats in (Backtest(df, strategy, **bt_kwargs).run(**run_kwargs) |
| 613 | for df in dfs)] |
| 614 | finally: |
| 615 | for shmem in chain(*shms): |
| 616 | shmem.close() |
| 617 | |
| 618 | def optimize(self, **kwargs) -> pd.DataFrame: |
| 619 | """ |
| 620 | Wraps `backtesting.backtesting.Backtest.optimize`, but returns `pd.DataFrame` with |
| 621 | currency indexes in columns. |
| 622 | |
| 623 | heamap: pd.DataFrame = btm.optimize(...) |
| 624 | from backtesting.plot import plot_heatmaps |
| 625 | plot_heatmaps(heatmap.mean(axis=1)) |
no outgoing calls