3. Backtest
Once the data and strategy have both been defined, the backtests can be run. Coin-test allows for running many backtests in parallel with a variety of parameters to modify the simulation.
3.1. Running Backtest
Backtests can be run using the coin_test.run function. This function takes in all of the following arguments for backtesting:
all_datasets: A list of list of datasets, where each list of datasets is all price data for one backtest. For example, one list can include aDatasetfor BTC/USDT data, and another can have ETH/USDT data. Each list of datasets is used to create a different backtest for the user.all_strategies: A list of list of strategies, where each list of strategies is a group of strategies that runs together, and multiple lists of strategies can be run alongside each other to compare different strategies in the same backtesting conditions.starting_portfolio: APortfoliowith the starting monetary value of all assets.backtest_length: A pandasTimedeltaobject which represents how long a backtest should take.n_parallel: The number of parallel backtests to run. When1, backtests are run in sequence.output_folder: Where the report and saved backtest results should be saved. The report will be atoutput_folder/report.htmland the results will be atoutput_folder/backtest_resultsslippage_calculator: ASlippageCalculatorto compute slippage.tx_calculator: ATransactionFeeCalculatorto compute transaction fees.build_from_save_results: A path to load the backtest results from. If specified, backtests are not run, and analysis is built from the specified save data.
To use default values, consider the following example:
from coin_test import run
datasets = Datasaver.load("datasets.pkl")
strategies = [
[strategy1, strategy2, strategy3], # first test these three strategies working together
[strategy4], # then test this strategy all by itself
]
btc, usdt = btc_usdt = AssetPair.from_str("BTC", "USDT")
starting_portfolio = Portfolio(base_currency=usdt, assets={usdt: Money(100000, usdt)})
backtest_length = pd.Timedelta(days=90) # 90 day backtests
run(datasets, strategies, starting_portfolio, backtest_length)
To add slippage or transaction fees, consider the following example, where custom functions can add this flexibility. Currently, ConstantTransactionFeeCalculator, ConstantSlippage, and GaussianSlippage are implemented.
from coin_test.backtest import ConstantTransactionFeeCalculator, ConstantSlippage
transaction_fee = ConstantTransactionFeeCalculator(basis_points=100)
slippage = ConstantSlippage(basis_points=25)
run(datasets, strategies, starting_portfolio, backtest_length,
slippage_calculator=slippage,
tx_calculator=transaction_fee
)
To allocate more cores to process simultaneous backtests and run the process faster, consider using the n_parallel argument.
run(datasets, strategies, starting_portfolio, backtest_length, n_parallel=8)
3.2. Saving and Loading
It is also possible to save and load backtest results. When an output_folder is specified, the output_folder/backtest_results folder will be generated. Analysis can be re-generated from this folder using the build_from_save_results argument:
run(build_from_save_results="out_folder/backtest_results")
Doing so will generate the analysis from the saved results and will not run any backtests. Any other arguments passed to run will be ignored.