{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import os\n", "import sys\n", "\n", "backtester_dir = os.path.realpath(os.path.join(os.getcwd(), '..', '..'))\n", "sys.path.append(backtester_dir) # Add backtester base dir to $PYTHONPATH" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from asset_backtester import Backtest, Portfolio, Asset\n", "from asset_backtester.datahandler import HistoricalAssetData\n", "from asset_backtester.charts import *" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import pandas_datareader as pdr\n", "import datetime" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a first example, we run a backtest of a portfolio with the following tickers during the year 2019. Data is taken from [Tiingo](https://api.tiingo.com)." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "env: TIINGO_API_KEY=your_tiingo_api_key\n" ] } ], "source": [ "%env TIINGO_API_KEY=your_tiingo_api_key" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "api_key = os.environ[\"TIINGO_API_KEY\"]\n", "\n", "start = datetime.datetime(2019, 1, 1)\n", "end = datetime.datetime(2019, 12, 31)\n", "tickers = [\"VOO\", \"TUR\", \"RSX\", \"EWY\", \"EWS\", \"VTIP\", \"TLT\", \"BWX\", \"PDBC\", \"IAU\", \"VNQI\"]\n", "\n", "symbols = pdr.get_data_tiingo(tickers, api_key=api_key, start=start, end=end)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
closehighlowopenvolumeadjCloseadjHighadjLowadjOpenadjVolumedivCashsplitFactor
symboldate
VOO2019-01-02 00:00:00+00:00229.99230.85226.02226.184891329225.367394226.210108221.477187221.63397148913290.01.0
2019-01-03 00:00:00+00:00224.50228.42223.97228.103330026219.987738223.828949219.468391223.51538133300260.01.0
2019-01-04 00:00:00+00:00231.91232.62227.15227.545100088227.248803227.944533222.584475222.96663751000880.01.0
2019-01-07 00:00:00+00:00233.65235.23231.32232.293706014228.953831230.502074226.670662227.62116637060140.01.0
2019-01-08 00:00:00+00:00235.92236.46233.43236.053546649231.178206231.707352228.738253231.30559335466490.01.0
..........................................
VNQI2019-12-24 00:00:00+00:0058.2258.2358.0858.1263751758.22000058.23000058.08000058.1200006375170.01.0
2019-12-26 00:00:00+00:0058.5458.5458.2558.2835509158.54000058.54000058.25000058.2800003550910.01.0
2019-12-27 00:00:00+00:0058.9658.9658.7758.7832234358.96000058.96000058.77000058.7800003223430.01.0
2019-12-30 00:00:00+00:0058.7159.0258.7159.0029413458.71000059.02000058.71000059.0000002941340.01.0
2019-12-31 00:00:00+00:0059.0959.0958.8558.9521993559.09000059.09000058.85000058.9500002199350.01.0
\n", "

2772 rows × 12 columns

\n", "
" ], "text/plain": [ " close high low open volume \\\n", "symbol date \n", "VOO 2019-01-02 00:00:00+00:00 229.99 230.85 226.02 226.18 4891329 \n", " 2019-01-03 00:00:00+00:00 224.50 228.42 223.97 228.10 3330026 \n", " 2019-01-04 00:00:00+00:00 231.91 232.62 227.15 227.54 5100088 \n", " 2019-01-07 00:00:00+00:00 233.65 235.23 231.32 232.29 3706014 \n", " 2019-01-08 00:00:00+00:00 235.92 236.46 233.43 236.05 3546649 \n", "... ... ... ... ... ... \n", "VNQI 2019-12-24 00:00:00+00:00 58.22 58.23 58.08 58.12 637517 \n", " 2019-12-26 00:00:00+00:00 58.54 58.54 58.25 58.28 355091 \n", " 2019-12-27 00:00:00+00:00 58.96 58.96 58.77 58.78 322343 \n", " 2019-12-30 00:00:00+00:00 58.71 59.02 58.71 59.00 294134 \n", " 2019-12-31 00:00:00+00:00 59.09 59.09 58.85 58.95 219935 \n", "\n", " adjClose adjHigh adjLow \\\n", "symbol date \n", "VOO 2019-01-02 00:00:00+00:00 225.367394 226.210108 221.477187 \n", " 2019-01-03 00:00:00+00:00 219.987738 223.828949 219.468391 \n", " 2019-01-04 00:00:00+00:00 227.248803 227.944533 222.584475 \n", " 2019-01-07 00:00:00+00:00 228.953831 230.502074 226.670662 \n", " 2019-01-08 00:00:00+00:00 231.178206 231.707352 228.738253 \n", "... ... ... ... \n", "VNQI 2019-12-24 00:00:00+00:00 58.220000 58.230000 58.080000 \n", " 2019-12-26 00:00:00+00:00 58.540000 58.540000 58.250000 \n", " 2019-12-27 00:00:00+00:00 58.960000 58.960000 58.770000 \n", " 2019-12-30 00:00:00+00:00 58.710000 59.020000 58.710000 \n", " 2019-12-31 00:00:00+00:00 59.090000 59.090000 58.850000 \n", "\n", " adjOpen adjVolume divCash splitFactor \n", "symbol date \n", "VOO 2019-01-02 00:00:00+00:00 221.633971 4891329 0.0 1.0 \n", " 2019-01-03 00:00:00+00:00 223.515381 3330026 0.0 1.0 \n", " 2019-01-04 00:00:00+00:00 222.966637 5100088 0.0 1.0 \n", " 2019-01-07 00:00:00+00:00 227.621166 3706014 0.0 1.0 \n", " 2019-01-08 00:00:00+00:00 231.305593 3546649 0.0 1.0 \n", "... ... ... ... ... \n", "VNQI 2019-12-24 00:00:00+00:00 58.120000 637517 0.0 1.0 \n", " 2019-12-26 00:00:00+00:00 58.280000 355091 0.0 1.0 \n", " 2019-12-27 00:00:00+00:00 58.780000 322343 0.0 1.0 \n", " 2019-12-30 00:00:00+00:00 59.000000 294134 0.0 1.0 \n", " 2019-12-31 00:00:00+00:00 58.950000 219935 0.0 1.0 \n", "\n", "[2772 rows x 12 columns]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symbols" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "data_dir = os.path.join(backtester_dir, 'data')\n", "save_path = os.path.join(data_dir, 'portfolio_data.csv')\n", "symbols.to_csv(save_path)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use *HistoricalAssetData* to load your csv. Data must include `date`, `adjClose` and `symbol` columns to work." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "data = HistoricalAssetData(save_path)\n", "schema = data.schema" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
symboldateclosehighlowopenvolumeadjCloseadjHighadjLowadjOpenadjVolumedivCashsplitFactor
0VOO2019-01-02 00:00:00+00:00229.99230.85226.02226.184891329225.367394226.210108221.477187221.63397148913290.01.0
1VOO2019-01-03 00:00:00+00:00224.50228.42223.97228.103330026219.987738223.828949219.468391223.51538133300260.01.0
2VOO2019-01-04 00:00:00+00:00231.91232.62227.15227.545100088227.248803227.944533222.584475222.96663751000880.01.0
3VOO2019-01-07 00:00:00+00:00233.65235.23231.32232.293706014228.953831230.502074226.670662227.62116637060140.01.0
4VOO2019-01-08 00:00:00+00:00235.92236.46233.43236.053546649231.178206231.707352228.738253231.30559335466490.01.0
.............................................
2767VNQI2019-12-24 00:00:00+00:0058.2258.2358.0858.1263751758.22000058.23000058.08000058.1200006375170.01.0
2768VNQI2019-12-26 00:00:00+00:0058.5458.5458.2558.2835509158.54000058.54000058.25000058.2800003550910.01.0
2769VNQI2019-12-27 00:00:00+00:0058.9658.9658.7758.7832234358.96000058.96000058.77000058.7800003223430.01.0
2770VNQI2019-12-30 00:00:00+00:0058.7159.0258.7159.0029413458.71000059.02000058.71000059.0000002941340.01.0
2771VNQI2019-12-31 00:00:00+00:0059.0959.0958.8558.9521993559.09000059.09000058.85000058.9500002199350.01.0
\n", "

2772 rows × 14 columns

\n", "
" ], "text/plain": [ " symbol date close high low open \\\n", "0 VOO 2019-01-02 00:00:00+00:00 229.99 230.85 226.02 226.18 \n", "1 VOO 2019-01-03 00:00:00+00:00 224.50 228.42 223.97 228.10 \n", "2 VOO 2019-01-04 00:00:00+00:00 231.91 232.62 227.15 227.54 \n", "3 VOO 2019-01-07 00:00:00+00:00 233.65 235.23 231.32 232.29 \n", "4 VOO 2019-01-08 00:00:00+00:00 235.92 236.46 233.43 236.05 \n", "... ... ... ... ... ... ... \n", "2767 VNQI 2019-12-24 00:00:00+00:00 58.22 58.23 58.08 58.12 \n", "2768 VNQI 2019-12-26 00:00:00+00:00 58.54 58.54 58.25 58.28 \n", "2769 VNQI 2019-12-27 00:00:00+00:00 58.96 58.96 58.77 58.78 \n", "2770 VNQI 2019-12-30 00:00:00+00:00 58.71 59.02 58.71 59.00 \n", "2771 VNQI 2019-12-31 00:00:00+00:00 59.09 59.09 58.85 58.95 \n", "\n", " volume adjClose adjHigh adjLow adjOpen adjVolume \\\n", "0 4891329 225.367394 226.210108 221.477187 221.633971 4891329 \n", "1 3330026 219.987738 223.828949 219.468391 223.515381 3330026 \n", "2 5100088 227.248803 227.944533 222.584475 222.966637 5100088 \n", "3 3706014 228.953831 230.502074 226.670662 227.621166 3706014 \n", "4 3546649 231.178206 231.707352 228.738253 231.305593 3546649 \n", "... ... ... ... ... ... ... \n", "2767 637517 58.220000 58.230000 58.080000 58.120000 637517 \n", "2768 355091 58.540000 58.540000 58.250000 58.280000 355091 \n", "2769 322343 58.960000 58.960000 58.770000 58.780000 322343 \n", "2770 294134 58.710000 59.020000 58.710000 59.000000 294134 \n", "2771 219935 59.090000 59.090000 58.850000 58.950000 219935 \n", "\n", " divCash splitFactor \n", "0 0.0 1.0 \n", "1 0.0 1.0 \n", "2 0.0 1.0 \n", "3 0.0 1.0 \n", "4 0.0 1.0 \n", "... ... ... \n", "2767 0.0 1.0 \n", "2768 0.0 1.0 \n", "2769 0.0 1.0 \n", "2770 0.0 1.0 \n", "2771 0.0 1.0 \n", "\n", "[2772 rows x 14 columns]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create a portfolio, use the Portfolio class and then create assets with Asset(*name*, *percentage*), where *name* should match the name given in the `symbol` column and *percentage* is the percentage (from 0 to 1) allocated to that specific asset." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "portfolio = Portfolio()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "VOO = Asset('VOO', 0.1)\n", "TUR = Asset('TUR', 0.05)\n", "RSX = Asset('RSX', 0.05)\n", "EWY = Asset('EWY', 0.05)\n", "EWS = Asset('EWS', 0.05)\n", "VTIP = Asset('VTIP', 0.10)\n", "TLT = Asset('TLT', 0.20)\n", "BWX = Asset('BWX', 0.10)\n", "PDBC = Asset('PDBC', 0.05)\n", "IAU = Asset('IAU', 0.15)\n", "VNQI = Asset('VNQI', 0.10)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "portfolio.add_assets([\n", " VOO, TUR, RSX, EWY, EWS, VTIP, TLT, BWX,\n", " PDBC, IAU, VNQI\n", "])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a *Backtest* object passing it the schema of your data, add the portfolio and data to it and then run it. The *run* method takes the initial capital (default value *1.000.000*) and **periods** as arguments. **periods** defines how often, in months, a rebalancing of the portfolio is made, so that a value of '1' means a monthly rebalancing and '6' a bi-annual one. Note that its value should be a string and it defaults to '1'. For a backtest with no rebalancing use None." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "bt = Backtest(schema)\n", "bt.portfolio = portfolio\n", "bt.data = data" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "0% [██████████████████████████████] 100% | ETA: 00:00:00\n", "Total time elapsed: 00:00:10\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
capitalcashtotal_value% changeaccumulated return
2019-01-01 00:00:00+00:001.000000e+061000000.000000NaNNaNNaN
2019-01-02 00:00:00+00:001.000000e+06365.1028869.996349e+050.0000001.000000
2019-01-03 00:00:00+00:009.987002e+05365.1028869.983351e+05-0.0013000.998700
2019-01-04 00:00:00+00:001.008706e+06365.1028861.008341e+060.0100191.008706
2019-01-07 00:00:00+00:001.010930e+06365.1028861.010565e+060.0022051.010930
..................
2019-12-24 00:00:00+00:001.157945e+06365.1028861.157580e+060.0027071.157945
2019-12-26 00:00:00+00:001.163165e+06365.1028861.162800e+060.0045081.163165
2019-12-27 00:00:00+00:001.165863e+06365.1028861.165498e+060.0023191.165863
2019-12-30 00:00:00+00:001.163344e+06365.1028861.162979e+06-0.0021611.163344
2019-12-31 00:00:00+00:001.163594e+06365.1028861.163229e+060.0002151.163594
\n", "

253 rows × 5 columns

\n", "
" ], "text/plain": [ " capital cash total_value \\\n", "2019-01-01 00:00:00+00:00 1.000000e+06 1000000.000000 NaN \n", "2019-01-02 00:00:00+00:00 1.000000e+06 365.102886 9.996349e+05 \n", "2019-01-03 00:00:00+00:00 9.987002e+05 365.102886 9.983351e+05 \n", "2019-01-04 00:00:00+00:00 1.008706e+06 365.102886 1.008341e+06 \n", "2019-01-07 00:00:00+00:00 1.010930e+06 365.102886 1.010565e+06 \n", "... ... ... ... \n", "2019-12-24 00:00:00+00:00 1.157945e+06 365.102886 1.157580e+06 \n", "2019-12-26 00:00:00+00:00 1.163165e+06 365.102886 1.162800e+06 \n", "2019-12-27 00:00:00+00:00 1.165863e+06 365.102886 1.165498e+06 \n", "2019-12-30 00:00:00+00:00 1.163344e+06 365.102886 1.162979e+06 \n", "2019-12-31 00:00:00+00:00 1.163594e+06 365.102886 1.163229e+06 \n", "\n", " % change accumulated return \n", "2019-01-01 00:00:00+00:00 NaN NaN \n", "2019-01-02 00:00:00+00:00 0.000000 1.000000 \n", "2019-01-03 00:00:00+00:00 -0.001300 0.998700 \n", "2019-01-04 00:00:00+00:00 0.010019 1.008706 \n", "2019-01-07 00:00:00+00:00 0.002205 1.010930 \n", "... ... ... \n", "2019-12-24 00:00:00+00:00 0.002707 1.157945 \n", "2019-12-26 00:00:00+00:00 0.004508 1.163165 \n", "2019-12-27 00:00:00+00:00 0.002319 1.165863 \n", "2019-12-30 00:00:00+00:00 -0.002161 1.163344 \n", "2019-12-31 00:00:00+00:00 0.000215 1.163594 \n", "\n", "[253 rows x 5 columns]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bt.run(periods=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When done, the backtester returns a balance sheet with the daily returns and wealth values. Pass this balance dataframe to \n", "the functions *returns_chart*, *returns_histogram* and *monthly_returns_heatmap* for better visualization. " ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.VConcatChart(...)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "returns_chart(bt.balance)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "returns_histogram(bt.balance)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "monthly_returns_heatmap(bt.balance)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now run a backtest of a portfolio from the book \"The Ivy Portfolio\" by Faber and Richardson, consisting of an even allocation in domestic (US) stocks (VTI), foreign stocks (VEU), bonds (BND), real estate (VNQ) and commodities (DBC).\n", "\n", "The data we'll use consists of the last 10 years (2010-2019), once again taken from Tiingo." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "tickers = [\"VTI\", \"VEU\", \"BND\", \"VNQ\", \"DBC\"]\n", "start = datetime.datetime(2010, 1, 1)\n", "end = datetime.datetime(2019, 12, 31)\n", "\n", "ivy_data = pdr.get_data_tiingo(tickers, api_key=api_key, start=start, end=end)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "ivy_data_path = os.path.join(data_dir, 'ivy_portfolio_data.csv')\n", "ivy_data.to_csv(ivy_data_path)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "data = HistoricalAssetData(ivy_data_path)\n", "schema = data.schema" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
symboldateclosehighlowopenvolumeadjCloseadjHighadjLowadjOpenadjVolumedivCashsplitFactor
0VTI2010-01-04 00:00:00+00:0057.3157.379956.8456.86225146147.18914747.24670346.80214946.81861722514610.01.0
1VTI2010-01-05 00:00:00+00:0057.5357.540057.1157.34159764347.37029647.37853047.02446747.21384915976430.01.0
2VTI2010-01-06 00:00:00+00:0057.6157.715057.4157.50212020647.43616847.52262547.27148847.34559421202060.01.0
3VTI2010-01-07 00:00:00+00:0057.8557.889057.2957.55165663947.63378447.66589747.17267947.38676416566390.01.0
4VTI2010-01-08 00:00:00+00:0058.0458.046157.5657.70164991947.79023147.79525347.39499847.51027416499190.01.0
.............................................
12575DBC2019-12-24 00:00:00+00:0015.9315.950015.8615.8646615315.93000015.95000015.86000015.8600004661530.01.0
12576DBC2019-12-26 00:00:00+00:0016.0516.050015.9715.9767920616.05000016.05000015.97000015.9700006792060.01.0
12577DBC2019-12-27 00:00:00+00:0016.0816.090016.0216.06125001416.08000016.09000016.02000016.06000012500140.01.0
12578DBC2019-12-30 00:00:00+00:0016.0516.180015.9816.1697628416.05000016.18000015.98000016.1600009762840.01.0
12579DBC2019-12-31 00:00:00+00:0015.9516.045315.9115.9580611515.95000016.04530015.91000015.9500008061150.01.0
\n", "

12580 rows × 14 columns

\n", "
" ], "text/plain": [ " symbol date close high low open volume \\\n", "0 VTI 2010-01-04 00:00:00+00:00 57.31 57.3799 56.84 56.86 2251461 \n", "1 VTI 2010-01-05 00:00:00+00:00 57.53 57.5400 57.11 57.34 1597643 \n", "2 VTI 2010-01-06 00:00:00+00:00 57.61 57.7150 57.41 57.50 2120206 \n", "3 VTI 2010-01-07 00:00:00+00:00 57.85 57.8890 57.29 57.55 1656639 \n", "4 VTI 2010-01-08 00:00:00+00:00 58.04 58.0461 57.56 57.70 1649919 \n", "... ... ... ... ... ... ... ... \n", "12575 DBC 2019-12-24 00:00:00+00:00 15.93 15.9500 15.86 15.86 466153 \n", "12576 DBC 2019-12-26 00:00:00+00:00 16.05 16.0500 15.97 15.97 679206 \n", "12577 DBC 2019-12-27 00:00:00+00:00 16.08 16.0900 16.02 16.06 1250014 \n", "12578 DBC 2019-12-30 00:00:00+00:00 16.05 16.1800 15.98 16.16 976284 \n", "12579 DBC 2019-12-31 00:00:00+00:00 15.95 16.0453 15.91 15.95 806115 \n", "\n", " adjClose adjHigh adjLow adjOpen adjVolume divCash \\\n", "0 47.189147 47.246703 46.802149 46.818617 2251461 0.0 \n", "1 47.370296 47.378530 47.024467 47.213849 1597643 0.0 \n", "2 47.436168 47.522625 47.271488 47.345594 2120206 0.0 \n", "3 47.633784 47.665897 47.172679 47.386764 1656639 0.0 \n", "4 47.790231 47.795253 47.394998 47.510274 1649919 0.0 \n", "... ... ... ... ... ... ... \n", "12575 15.930000 15.950000 15.860000 15.860000 466153 0.0 \n", "12576 16.050000 16.050000 15.970000 15.970000 679206 0.0 \n", "12577 16.080000 16.090000 16.020000 16.060000 1250014 0.0 \n", "12578 16.050000 16.180000 15.980000 16.160000 976284 0.0 \n", "12579 15.950000 16.045300 15.910000 15.950000 806115 0.0 \n", "\n", " splitFactor \n", "0 1.0 \n", "1 1.0 \n", "2 1.0 \n", "3 1.0 \n", "4 1.0 \n", "... ... \n", "12575 1.0 \n", "12576 1.0 \n", "12577 1.0 \n", "12578 1.0 \n", "12579 1.0 \n", "\n", "[12580 rows x 14 columns]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "portfolio = Portfolio()" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "VTI = Asset(\"VTI\", 0.2)\n", "VEU = Asset(\"VEU\", 0.2)\n", "BND = Asset(\"BND\", 0.2)\n", "VNQ = Asset(\"VNQ\", 0.2)\n", "DBC = Asset(\"DBC\", 0.2)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "portfolio.add_assets([VTI, VEU, BND, VNQ, DBC])" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "bt = Backtest(schema)\n", "bt.portfolio = portfolio\n", "bt.data = data" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "0% [██████████████████████████████] 100% | ETA: 00:00:00\n", "Total time elapsed: 00:00:46\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
capitalcashtotal_value% changeaccumulated return
2010-01-03 00:00:00+00:001.000000e+061000000.000000NaNNaNNaN
2010-01-04 00:00:00+00:001.000000e+0696.5455089.999035e+050.0000001.000000
2010-01-05 00:00:00+00:001.001321e+0696.5455081.001225e+060.0013211.001321
2010-01-06 00:00:00+00:001.005603e+0696.5455081.005507e+060.0042761.005603
2010-01-07 00:00:00+00:001.004723e+0696.5455081.004627e+06-0.0008751.004723
..................
2019-12-24 00:00:00+00:002.039175e+0696.5455082.039079e+060.0011592.039175
2019-12-26 00:00:00+00:002.048066e+0696.5455082.047969e+060.0043602.048066
2019-12-27 00:00:00+00:002.050801e+0696.5455082.050705e+060.0013362.050801
2019-12-30 00:00:00+00:002.045131e+0696.5455082.045035e+06-0.0027652.045131
2019-12-31 00:00:00+00:002.051265e+0696.5455082.051168e+060.0029992.051265
\n", "

2517 rows × 5 columns

\n", "
" ], "text/plain": [ " capital cash total_value \\\n", "2010-01-03 00:00:00+00:00 1.000000e+06 1000000.000000 NaN \n", "2010-01-04 00:00:00+00:00 1.000000e+06 96.545508 9.999035e+05 \n", "2010-01-05 00:00:00+00:00 1.001321e+06 96.545508 1.001225e+06 \n", "2010-01-06 00:00:00+00:00 1.005603e+06 96.545508 1.005507e+06 \n", "2010-01-07 00:00:00+00:00 1.004723e+06 96.545508 1.004627e+06 \n", "... ... ... ... \n", "2019-12-24 00:00:00+00:00 2.039175e+06 96.545508 2.039079e+06 \n", "2019-12-26 00:00:00+00:00 2.048066e+06 96.545508 2.047969e+06 \n", "2019-12-27 00:00:00+00:00 2.050801e+06 96.545508 2.050705e+06 \n", "2019-12-30 00:00:00+00:00 2.045131e+06 96.545508 2.045035e+06 \n", "2019-12-31 00:00:00+00:00 2.051265e+06 96.545508 2.051168e+06 \n", "\n", " % change accumulated return \n", "2010-01-03 00:00:00+00:00 NaN NaN \n", "2010-01-04 00:00:00+00:00 0.000000 1.000000 \n", "2010-01-05 00:00:00+00:00 0.001321 1.001321 \n", "2010-01-06 00:00:00+00:00 0.004276 1.005603 \n", "2010-01-07 00:00:00+00:00 -0.000875 1.004723 \n", "... ... ... \n", "2019-12-24 00:00:00+00:00 0.001159 2.039175 \n", "2019-12-26 00:00:00+00:00 0.004360 2.048066 \n", "2019-12-27 00:00:00+00:00 0.001336 2.050801 \n", "2019-12-30 00:00:00+00:00 -0.002765 2.045131 \n", "2019-12-31 00:00:00+00:00 0.002999 2.051265 \n", "\n", "[2517 rows x 5 columns]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# No rebalancing\n", "bt.run(periods=None)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.VConcatChart(...)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "returns_chart(bt.balance)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "monthly_returns_heatmap(bt.balance)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For comparison, you can run the same backtest on [Portfolio Visualizer.](https://www.portfoliovisualizer.com/backtest-portfolio)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "0% [██████████████████████████████] 100% | ETA: 00:00:00\n", "Total time elapsed: 00:00:51\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
capitalcashtotal_value% changeaccumulated return
2010-01-03 00:00:00+00:001.000000e+061000000.000000NaNNaNNaN
2010-01-04 00:00:00+00:001.000000e+0696.5455089.999035e+050.0000001.000000
2010-01-05 00:00:00+00:001.001321e+0696.5455081.001225e+060.0013211.001321
2010-01-06 00:00:00+00:001.005603e+0696.5455081.005507e+060.0042761.005603
2010-01-07 00:00:00+00:001.004723e+0696.5455081.004627e+06-0.0008751.004723
..................
2019-12-24 00:00:00+00:001.697197e+06189.0284101.697008e+060.0014991.697197
2019-12-26 00:00:00+00:001.704983e+06189.0284101.704794e+060.0045871.704983
2019-12-27 00:00:00+00:001.707689e+06189.0284101.707500e+060.0015871.707689
2019-12-30 00:00:00+00:001.703069e+06189.0284101.702880e+06-0.0027061.703069
2019-12-31 00:00:00+00:001.704913e+06189.0284101.704724e+060.0010831.704913
\n", "

2517 rows × 5 columns

\n", "
" ], "text/plain": [ " capital cash total_value \\\n", "2010-01-03 00:00:00+00:00 1.000000e+06 1000000.000000 NaN \n", "2010-01-04 00:00:00+00:00 1.000000e+06 96.545508 9.999035e+05 \n", "2010-01-05 00:00:00+00:00 1.001321e+06 96.545508 1.001225e+06 \n", "2010-01-06 00:00:00+00:00 1.005603e+06 96.545508 1.005507e+06 \n", "2010-01-07 00:00:00+00:00 1.004723e+06 96.545508 1.004627e+06 \n", "... ... ... ... \n", "2019-12-24 00:00:00+00:00 1.697197e+06 189.028410 1.697008e+06 \n", "2019-12-26 00:00:00+00:00 1.704983e+06 189.028410 1.704794e+06 \n", "2019-12-27 00:00:00+00:00 1.707689e+06 189.028410 1.707500e+06 \n", "2019-12-30 00:00:00+00:00 1.703069e+06 189.028410 1.702880e+06 \n", "2019-12-31 00:00:00+00:00 1.704913e+06 189.028410 1.704724e+06 \n", "\n", " % change accumulated return \n", "2010-01-03 00:00:00+00:00 NaN NaN \n", "2010-01-04 00:00:00+00:00 0.000000 1.000000 \n", "2010-01-05 00:00:00+00:00 0.001321 1.001321 \n", "2010-01-06 00:00:00+00:00 0.004276 1.005603 \n", "2010-01-07 00:00:00+00:00 -0.000875 1.004723 \n", "... ... ... \n", "2019-12-24 00:00:00+00:00 0.001499 1.697197 \n", "2019-12-26 00:00:00+00:00 0.004587 1.704983 \n", "2019-12-27 00:00:00+00:00 0.001587 1.707689 \n", "2019-12-30 00:00:00+00:00 -0.002706 1.703069 \n", "2019-12-31 00:00:00+00:00 0.001083 1.704913 \n", "\n", "[2517 rows x 5 columns]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Monthly rebalancing\n", "bt.run(periods=1)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.VConcatChart(...)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "returns_chart(bt.balance)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "0% [██████████████████████████████] 100% | ETA: 00:00:00\n", "Total time elapsed: 00:00:53\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
capitalcashtotal_value% changeaccumulated return
2010-01-03 00:00:00+00:001.000000e+061000000.000000NaNNaNNaN
2010-01-04 00:00:00+00:001.000000e+0696.5455089.999035e+050.0000001.000000
2010-01-05 00:00:00+00:001.001321e+0696.5455081.001225e+060.0013211.001321
2010-01-06 00:00:00+00:001.005603e+0696.5455081.005507e+060.0042761.005603
2010-01-07 00:00:00+00:001.004723e+0696.5455081.004627e+06-0.0008751.004723
..................
2019-12-24 00:00:00+00:001.766451e+06168.3622951.766283e+060.0014761.766451
2019-12-26 00:00:00+00:001.774559e+06168.3622951.774390e+060.0045901.774559
2019-12-27 00:00:00+00:001.777363e+06168.3622951.777194e+060.0015801.777363
2019-12-30 00:00:00+00:001.772492e+06168.3622951.772324e+06-0.0027401.772492
2019-12-31 00:00:00+00:001.774520e+06168.3622951.774352e+060.0011441.774520
\n", "

2517 rows × 5 columns

\n", "
" ], "text/plain": [ " capital cash total_value \\\n", "2010-01-03 00:00:00+00:00 1.000000e+06 1000000.000000 NaN \n", "2010-01-04 00:00:00+00:00 1.000000e+06 96.545508 9.999035e+05 \n", "2010-01-05 00:00:00+00:00 1.001321e+06 96.545508 1.001225e+06 \n", "2010-01-06 00:00:00+00:00 1.005603e+06 96.545508 1.005507e+06 \n", "2010-01-07 00:00:00+00:00 1.004723e+06 96.545508 1.004627e+06 \n", "... ... ... ... \n", "2019-12-24 00:00:00+00:00 1.766451e+06 168.362295 1.766283e+06 \n", "2019-12-26 00:00:00+00:00 1.774559e+06 168.362295 1.774390e+06 \n", "2019-12-27 00:00:00+00:00 1.777363e+06 168.362295 1.777194e+06 \n", "2019-12-30 00:00:00+00:00 1.772492e+06 168.362295 1.772324e+06 \n", "2019-12-31 00:00:00+00:00 1.774520e+06 168.362295 1.774352e+06 \n", "\n", " % change accumulated return \n", "2010-01-03 00:00:00+00:00 NaN NaN \n", "2010-01-04 00:00:00+00:00 0.000000 1.000000 \n", "2010-01-05 00:00:00+00:00 0.001321 1.001321 \n", "2010-01-06 00:00:00+00:00 0.004276 1.005603 \n", "2010-01-07 00:00:00+00:00 -0.000875 1.004723 \n", "... ... ... \n", "2019-12-24 00:00:00+00:00 0.001476 1.766451 \n", "2019-12-26 00:00:00+00:00 0.004590 1.774559 \n", "2019-12-27 00:00:00+00:00 0.001580 1.777363 \n", "2019-12-30 00:00:00+00:00 -0.002740 1.772492 \n", "2019-12-31 00:00:00+00:00 0.001144 1.774520 \n", "\n", "[2517 rows x 5 columns]" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Bi-annual rebalancing\n", "bt.run(periods=6)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.VConcatChart(...)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "returns_chart(bt.balance)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "monthly_returns_heatmap(bt.balance)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "returns_histogram(bt.balance)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 4 }