mirror of
https://github.com/wassname/options_backtester.git
synced 2026-07-21 12:40:27 +08:00
2.3 MiB
2.3 MiB
In [1]:
import os
import sys
backtester_dir = os.path.realpath(os.path.join(os.getcwd(), '..', '..'))
sys.path.append(backtester_dir) # Add backtester base dir to $PYTHONPATHIn [2]:
from asset_backtester import Backtest, Portfolio, Asset
from asset_backtester.datahandler import HistoricalAssetData
from asset_backtester.charts import *In [3]:
import pandas_datareader as pdr
import datetimeIn [39]:
%env TIINGO_API_KEY=your_tiingo_api_keyenv: TIINGO_API_KEY=your_tiingo_api_key
In [21]:
api_key = os.environ["TIINGO_API_KEY"]
start = datetime.datetime(2019, 1, 1)
end = datetime.datetime(2019, 12, 31)
tickers = ["VOO", "TUR", "RSX", "EWY", "EWS", "VTIP", "TLT", "BWX", "PDBC", "IAU", "VNQI"]
symbols = pdr.get_data_tiingo(tickers, api_key=api_key, start=start, end=end)In [22]:
symbolsOut [22]:
| close | high | low | open | volume | adjClose | adjHigh | adjLow | adjOpen | adjVolume | divCash | splitFactor | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| symbol | date | ||||||||||||
| VOO | 2019-01-02 00:00:00+00:00 | 229.99 | 230.85 | 226.02 | 226.18 | 4891329 | 225.367394 | 226.210108 | 221.477187 | 221.633971 | 4891329 | 0.0 | 1.0 |
| 2019-01-03 00:00:00+00:00 | 224.50 | 228.42 | 223.97 | 228.10 | 3330026 | 219.987738 | 223.828949 | 219.468391 | 223.515381 | 3330026 | 0.0 | 1.0 | |
| 2019-01-04 00:00:00+00:00 | 231.91 | 232.62 | 227.15 | 227.54 | 5100088 | 227.248803 | 227.944533 | 222.584475 | 222.966637 | 5100088 | 0.0 | 1.0 | |
| 2019-01-07 00:00:00+00:00 | 233.65 | 235.23 | 231.32 | 232.29 | 3706014 | 228.953831 | 230.502074 | 226.670662 | 227.621166 | 3706014 | 0.0 | 1.0 | |
| 2019-01-08 00:00:00+00:00 | 235.92 | 236.46 | 233.43 | 236.05 | 3546649 | 231.178206 | 231.707352 | 228.738253 | 231.305593 | 3546649 | 0.0 | 1.0 | |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| VNQI | 2019-12-24 00:00:00+00:00 | 58.22 | 58.23 | 58.08 | 58.12 | 637517 | 58.220000 | 58.230000 | 58.080000 | 58.120000 | 637517 | 0.0 | 1.0 |
| 2019-12-26 00:00:00+00:00 | 58.54 | 58.54 | 58.25 | 58.28 | 355091 | 58.540000 | 58.540000 | 58.250000 | 58.280000 | 355091 | 0.0 | 1.0 | |
| 2019-12-27 00:00:00+00:00 | 58.96 | 58.96 | 58.77 | 58.78 | 322343 | 58.960000 | 58.960000 | 58.770000 | 58.780000 | 322343 | 0.0 | 1.0 | |
| 2019-12-30 00:00:00+00:00 | 58.71 | 59.02 | 58.71 | 59.00 | 294134 | 58.710000 | 59.020000 | 58.710000 | 59.000000 | 294134 | 0.0 | 1.0 | |
| 2019-12-31 00:00:00+00:00 | 59.09 | 59.09 | 58.85 | 58.95 | 219935 | 59.090000 | 59.090000 | 58.850000 | 58.950000 | 219935 | 0.0 | 1.0 |
2772 rows × 12 columns
In [4]:
data_dir = os.path.join(backtester_dir, 'data')
save_path = os.path.join(data_dir, 'portfolio_data.csv')
symbols.to_csv(save_path)In [5]:
data = HistoricalAssetData(save_path)
schema = data.schemaIn [6]:
dataOut [6]:
| symbol | date | close | high | low | open | volume | adjClose | adjHigh | adjLow | adjOpen | adjVolume | divCash | splitFactor | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | VOO | 2019-01-02 00:00:00+00:00 | 229.99 | 230.85 | 226.02 | 226.18 | 4891329 | 225.367394 | 226.210108 | 221.477187 | 221.633971 | 4891329 | 0.0 | 1.0 |
| 1 | VOO | 2019-01-03 00:00:00+00:00 | 224.50 | 228.42 | 223.97 | 228.10 | 3330026 | 219.987738 | 223.828949 | 219.468391 | 223.515381 | 3330026 | 0.0 | 1.0 |
| 2 | VOO | 2019-01-04 00:00:00+00:00 | 231.91 | 232.62 | 227.15 | 227.54 | 5100088 | 227.248803 | 227.944533 | 222.584475 | 222.966637 | 5100088 | 0.0 | 1.0 |
| 3 | VOO | 2019-01-07 00:00:00+00:00 | 233.65 | 235.23 | 231.32 | 232.29 | 3706014 | 228.953831 | 230.502074 | 226.670662 | 227.621166 | 3706014 | 0.0 | 1.0 |
| 4 | VOO | 2019-01-08 00:00:00+00:00 | 235.92 | 236.46 | 233.43 | 236.05 | 3546649 | 231.178206 | 231.707352 | 228.738253 | 231.305593 | 3546649 | 0.0 | 1.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2767 | VNQI | 2019-12-24 00:00:00+00:00 | 58.22 | 58.23 | 58.08 | 58.12 | 637517 | 58.220000 | 58.230000 | 58.080000 | 58.120000 | 637517 | 0.0 | 1.0 |
| 2768 | VNQI | 2019-12-26 00:00:00+00:00 | 58.54 | 58.54 | 58.25 | 58.28 | 355091 | 58.540000 | 58.540000 | 58.250000 | 58.280000 | 355091 | 0.0 | 1.0 |
| 2769 | VNQI | 2019-12-27 00:00:00+00:00 | 58.96 | 58.96 | 58.77 | 58.78 | 322343 | 58.960000 | 58.960000 | 58.770000 | 58.780000 | 322343 | 0.0 | 1.0 |
| 2770 | VNQI | 2019-12-30 00:00:00+00:00 | 58.71 | 59.02 | 58.71 | 59.00 | 294134 | 58.710000 | 59.020000 | 58.710000 | 59.000000 | 294134 | 0.0 | 1.0 |
| 2771 | VNQI | 2019-12-31 00:00:00+00:00 | 59.09 | 59.09 | 58.85 | 58.95 | 219935 | 59.090000 | 59.090000 | 58.850000 | 58.950000 | 219935 | 0.0 | 1.0 |
2772 rows × 14 columns
In [7]:
portfolio = Portfolio()In [8]:
VOO = Asset('VOO', 0.1)
TUR = Asset('TUR', 0.05)
RSX = Asset('RSX', 0.05)
EWY = Asset('EWY', 0.05)
EWS = Asset('EWS', 0.05)
VTIP = Asset('VTIP', 0.10)
TLT = Asset('TLT', 0.20)
BWX = Asset('BWX', 0.10)
PDBC = Asset('PDBC', 0.05)
IAU = Asset('IAU', 0.15)
VNQI = Asset('VNQI', 0.10)In [9]:
portfolio.add_assets([
VOO, TUR, RSX, EWY, EWS, VTIP, TLT, BWX,
PDBC, IAU, VNQI
])Out [9]:
<asset_backtester.portfolio.portfolio.Portfolio at 0x123375f90>
In [10]:
bt = Backtest(schema)
bt.portfolio = portfolio
bt.data = dataIn [11]:
bt.run(initial_capital=1_000_000, periods=None)Out [11]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:10
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2019-01-01 00:00:00+00:00 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2019-01-02 00:00:00+00:00 | 1.000000e+06 | 365.102886 | 9.996349e+05 | 0.000000 | 1.000000 |
| 2019-01-03 00:00:00+00:00 | 9.987002e+05 | 365.102886 | 9.983351e+05 | -0.001300 | 0.998700 |
| 2019-01-04 00:00:00+00:00 | 1.008706e+06 | 365.102886 | 1.008341e+06 | 0.010019 | 1.008706 |
| 2019-01-07 00:00:00+00:00 | 1.010930e+06 | 365.102886 | 1.010565e+06 | 0.002205 | 1.010930 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 00:00:00+00:00 | 1.157945e+06 | 365.102886 | 1.157580e+06 | 0.002707 | 1.157945 |
| 2019-12-26 00:00:00+00:00 | 1.163165e+06 | 365.102886 | 1.162800e+06 | 0.004508 | 1.163165 |
| 2019-12-27 00:00:00+00:00 | 1.165863e+06 | 365.102886 | 1.165498e+06 | 0.002319 | 1.165863 |
| 2019-12-30 00:00:00+00:00 | 1.163344e+06 | 365.102886 | 1.162979e+06 | -0.002161 | 1.163344 |
| 2019-12-31 00:00:00+00:00 | 1.163594e+06 | 365.102886 | 1.163229e+06 | 0.000215 | 1.163594 |
253 rows × 5 columns
In [12]:
returns_chart(bt.balance)Out [12]:
In [13]:
returns_histogram(bt.balance)Out [13]:
In [14]:
monthly_returns_heatmap(bt.balance)Out [14]:
In [18]:
tickers = ["VTI", "VEU", "BND", "VNQ", "DBC"]
start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2019, 12, 31)
ivy_data = pdr.get_data_tiingo(tickers, api_key=api_key, start=start, end=end)In [23]:
ivy_data_path = os.path.join(data_dir, 'ivy_portfolio_data.csv')
ivy_data.to_csv(ivy_data_path)In [24]:
data = HistoricalAssetData(ivy_data_path)
schema = data.schemaIn [25]:
dataOut [25]:
| symbol | date | close | high | low | open | volume | adjClose | adjHigh | adjLow | adjOpen | adjVolume | divCash | splitFactor | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | VTI | 2010-01-04 00:00:00+00:00 | 57.31 | 57.3799 | 56.84 | 56.86 | 2251461 | 47.189147 | 47.246703 | 46.802149 | 46.818617 | 2251461 | 0.0 | 1.0 |
| 1 | VTI | 2010-01-05 00:00:00+00:00 | 57.53 | 57.5400 | 57.11 | 57.34 | 1597643 | 47.370296 | 47.378530 | 47.024467 | 47.213849 | 1597643 | 0.0 | 1.0 |
| 2 | VTI | 2010-01-06 00:00:00+00:00 | 57.61 | 57.7150 | 57.41 | 57.50 | 2120206 | 47.436168 | 47.522625 | 47.271488 | 47.345594 | 2120206 | 0.0 | 1.0 |
| 3 | VTI | 2010-01-07 00:00:00+00:00 | 57.85 | 57.8890 | 57.29 | 57.55 | 1656639 | 47.633784 | 47.665897 | 47.172679 | 47.386764 | 1656639 | 0.0 | 1.0 |
| 4 | VTI | 2010-01-08 00:00:00+00:00 | 58.04 | 58.0461 | 57.56 | 57.70 | 1649919 | 47.790231 | 47.795253 | 47.394998 | 47.510274 | 1649919 | 0.0 | 1.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 12575 | DBC | 2019-12-24 00:00:00+00:00 | 15.93 | 15.9500 | 15.86 | 15.86 | 466153 | 15.930000 | 15.950000 | 15.860000 | 15.860000 | 466153 | 0.0 | 1.0 |
| 12576 | DBC | 2019-12-26 00:00:00+00:00 | 16.05 | 16.0500 | 15.97 | 15.97 | 679206 | 16.050000 | 16.050000 | 15.970000 | 15.970000 | 679206 | 0.0 | 1.0 |
| 12577 | DBC | 2019-12-27 00:00:00+00:00 | 16.08 | 16.0900 | 16.02 | 16.06 | 1250014 | 16.080000 | 16.090000 | 16.020000 | 16.060000 | 1250014 | 0.0 | 1.0 |
| 12578 | DBC | 2019-12-30 00:00:00+00:00 | 16.05 | 16.1800 | 15.98 | 16.16 | 976284 | 16.050000 | 16.180000 | 15.980000 | 16.160000 | 976284 | 0.0 | 1.0 |
| 12579 | DBC | 2019-12-31 00:00:00+00:00 | 15.95 | 16.0453 | 15.91 | 15.95 | 806115 | 15.950000 | 16.045300 | 15.910000 | 15.950000 | 806115 | 0.0 | 1.0 |
12580 rows × 14 columns
In [26]:
portfolio = Portfolio()In [27]:
VTI = Asset("VTI", 0.2)
VEU = Asset("VEU", 0.2)
BND = Asset("BND", 0.2)
VNQ = Asset("VNQ", 0.2)
DBC = Asset("DBC", 0.2)In [28]:
portfolio.add_assets([VTI, VEU, BND, VNQ, DBC])Out [28]:
<asset_backtester.portfolio.portfolio.Portfolio at 0x124662b50>
In [29]:
bt = Backtest(schema)
bt.portfolio = portfolio
bt.data = dataIn [30]:
# No rebalancing
bt.run(initial_capital=1_000_000, periods=None)Out [30]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:46
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2010-01-03 00:00:00+00:00 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2010-01-04 00:00:00+00:00 | 1.000000e+06 | 96.545508 | 9.999035e+05 | 0.000000 | 1.000000 |
| 2010-01-05 00:00:00+00:00 | 1.001321e+06 | 96.545508 | 1.001225e+06 | 0.001321 | 1.001321 |
| 2010-01-06 00:00:00+00:00 | 1.005603e+06 | 96.545508 | 1.005507e+06 | 0.004276 | 1.005603 |
| 2010-01-07 00:00:00+00:00 | 1.004723e+06 | 96.545508 | 1.004627e+06 | -0.000875 | 1.004723 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 00:00:00+00:00 | 2.039175e+06 | 96.545508 | 2.039079e+06 | 0.001159 | 2.039175 |
| 2019-12-26 00:00:00+00:00 | 2.048066e+06 | 96.545508 | 2.047969e+06 | 0.004360 | 2.048066 |
| 2019-12-27 00:00:00+00:00 | 2.050801e+06 | 96.545508 | 2.050705e+06 | 0.001336 | 2.050801 |
| 2019-12-30 00:00:00+00:00 | 2.045131e+06 | 96.545508 | 2.045035e+06 | -0.002765 | 2.045131 |
| 2019-12-31 00:00:00+00:00 | 2.051265e+06 | 96.545508 | 2.051168e+06 | 0.002999 | 2.051265 |
2517 rows × 5 columns
In [31]:
returns_chart(bt.balance)Out [31]:
In [32]:
monthly_returns_heatmap(bt.balance)Out [32]:
In [33]:
# Monthly rebalancing
bt.run(initial_capital=1_000_000, periods=1)Out [33]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:51
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2010-01-03 00:00:00+00:00 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2010-01-04 00:00:00+00:00 | 1.000000e+06 | 96.545508 | 9.999035e+05 | 0.000000 | 1.000000 |
| 2010-01-05 00:00:00+00:00 | 1.001321e+06 | 96.545508 | 1.001225e+06 | 0.001321 | 1.001321 |
| 2010-01-06 00:00:00+00:00 | 1.005603e+06 | 96.545508 | 1.005507e+06 | 0.004276 | 1.005603 |
| 2010-01-07 00:00:00+00:00 | 1.004723e+06 | 96.545508 | 1.004627e+06 | -0.000875 | 1.004723 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 00:00:00+00:00 | 1.697197e+06 | 189.028410 | 1.697008e+06 | 0.001499 | 1.697197 |
| 2019-12-26 00:00:00+00:00 | 1.704983e+06 | 189.028410 | 1.704794e+06 | 0.004587 | 1.704983 |
| 2019-12-27 00:00:00+00:00 | 1.707689e+06 | 189.028410 | 1.707500e+06 | 0.001587 | 1.707689 |
| 2019-12-30 00:00:00+00:00 | 1.703069e+06 | 189.028410 | 1.702880e+06 | -0.002706 | 1.703069 |
| 2019-12-31 00:00:00+00:00 | 1.704913e+06 | 189.028410 | 1.704724e+06 | 0.001083 | 1.704913 |
2517 rows × 5 columns
In [34]:
returns_chart(bt.balance)Out [34]:
In [35]:
# Bi-annual rebalancing
bt.run(initial_capital=1_000_000, periods=6)Out [35]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:53
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2010-01-03 00:00:00+00:00 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2010-01-04 00:00:00+00:00 | 1.000000e+06 | 96.545508 | 9.999035e+05 | 0.000000 | 1.000000 |
| 2010-01-05 00:00:00+00:00 | 1.001321e+06 | 96.545508 | 1.001225e+06 | 0.001321 | 1.001321 |
| 2010-01-06 00:00:00+00:00 | 1.005603e+06 | 96.545508 | 1.005507e+06 | 0.004276 | 1.005603 |
| 2010-01-07 00:00:00+00:00 | 1.004723e+06 | 96.545508 | 1.004627e+06 | -0.000875 | 1.004723 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 00:00:00+00:00 | 1.766451e+06 | 168.362295 | 1.766283e+06 | 0.001476 | 1.766451 |
| 2019-12-26 00:00:00+00:00 | 1.774559e+06 | 168.362295 | 1.774390e+06 | 0.004590 | 1.774559 |
| 2019-12-27 00:00:00+00:00 | 1.777363e+06 | 168.362295 | 1.777194e+06 | 0.001580 | 1.777363 |
| 2019-12-30 00:00:00+00:00 | 1.772492e+06 | 168.362295 | 1.772324e+06 | -0.002740 | 1.772492 |
| 2019-12-31 00:00:00+00:00 | 1.774520e+06 | 168.362295 | 1.774352e+06 | 0.001144 | 1.774520 |
2517 rows × 5 columns
In [36]:
returns_chart(bt.balance)Out [36]:
In [37]:
monthly_returns_heatmap(bt.balance)Out [37]:
In [38]:
returns_histogram(bt.balance)Out [38]:
In [ ]: