mirror of
https://github.com/wassname/options_backtester.git
synced 2026-08-09 12:20:07 +08:00
3.1 MiB
3.1 MiB
In [1]:
import pandas as pd
import numpy as np
import osIn [2]:
from backtester import Backtest
from portfolio.portfolio import Portfolio
from portfolio.asset import Asset
from datahandler import HistoricalAssetData
from statistics.charts import returns_chart, returns_histogram, monthly_returns_heatmapIn [3]:
%config InlineBackend.figure_format="retina"
%matplotlib inlineIn [4]:
import pandas_datareader.data as web
import datetimeIn [5]:
start = datetime.datetime(2019, 1, 1)
end = datetime.datetime(2019, 12, 31)
tickers = ["VOO", "TUR", "RSX", "EWY", "EWS", "VTIP", "TLT", "BWX", "PDBC", "IAU", "VNQI"]
dfs = []
for ticker in tickers:
df = web.DataReader(ticker, 'yahoo', start, end).reset_index().rename(columns={'Date': 'date', 'High': 'high', 'Low': 'low', 'Open': 'open', 'Close': 'close', 'Volume': 'volume'})
df['symbol'] = ticker
dfs.append(df)
In [9]:
df = pd.concat(dfs)In [10]:
df = df.sort_values(by='date').reset_index(drop=True)In [11]:
df.to_csv("data/portfolio_data.csv", index=False)In [12]:
data = HistoricalAssetData("data/portfolio_data.csv")
schema = data.schemaIn [13]:
dataOut [13]:
| date | high | low | open | close | volume | Adj Close | symbol | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2019-01-02 | 230.850006 | 226.020004 | 226.179993 | 229.990005 | 4891300.0 | 225.350449 | VOO |
| 1 | 2019-01-02 | 15.333000 | 14.890000 | 14.920000 | 15.120000 | 1382500.0 | 14.909319 | PDBC |
| 2 | 2019-01-02 | 122.160004 | 121.339996 | 121.660004 | 122.150002 | 19841500.0 | 119.344078 | TLT |
| 3 | 2019-01-02 | 47.910000 | 47.860001 | 47.860001 | 47.910000 | 771400.0 | 46.986149 | VTIP |
| 4 | 2019-01-02 | 22.100000 | 21.850000 | 21.930000 | 22.100000 | 876200.0 | 21.076557 | EWS |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2767 | 2019-12-31 | 27.180000 | 27.000000 | 27.110001 | 27.090000 | 132900.0 | 27.090000 | TUR |
| 2768 | 2019-12-31 | 16.650000 | 16.510000 | 16.520000 | 16.559999 | 1780800.0 | 16.559999 | PDBC |
| 2769 | 2019-12-31 | 295.989990 | 294.170013 | 294.529999 | 295.799988 | 2512700.0 | 295.799988 | VOO |
| 2770 | 2019-12-31 | 136.460007 | 135.380005 | 136.210007 | 135.479996 | 10707400.0 | 135.479996 | TLT |
| 2771 | 2019-12-31 | 59.090000 | 58.849998 | 58.950001 | 59.090000 | 219900.0 | 59.090000 | VNQI |
2772 rows × 8 columns
In [14]:
portfolio = Portfolio()In [15]:
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 [16]:
portfolio.add_assets([
VOO, TUR, RSX, EWY, EWS, VTIP, TLT, BWX,
PDBC, IAU, VNQI
])Out [16]:
<portfolio.portfolio.Portfolio at 0x1165ef750>
In [17]:
bt = Backtest(schema)
bt.portfolio = portfolio
bt.data = dataIn [18]:
bt.run(initial_capital=1_000_000, periods=None)Out [18]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:04
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2019-01-01 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2019-01-02 | 1.000000e+06 | 403.112655 | 9.995969e+05 | 0.000000 | 1.000000 |
| 2019-01-03 | 9.987008e+05 | 403.112655 | 9.982976e+05 | -0.001299 | 0.998701 |
| 2019-01-04 | 1.008706e+06 | 403.112655 | 1.008302e+06 | 0.010018 | 1.008706 |
| 2019-01-07 | 1.010929e+06 | 403.112655 | 1.010526e+06 | 0.002205 | 1.010929 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 | 1.158018e+06 | 403.112655 | 1.157615e+06 | 0.002707 | 1.158018 |
| 2019-12-26 | 1.163238e+06 | 403.112655 | 1.162835e+06 | 0.004508 | 1.163238 |
| 2019-12-27 | 1.165936e+06 | 403.112655 | 1.165533e+06 | 0.002319 | 1.165936 |
| 2019-12-30 | 1.163417e+06 | 403.112655 | 1.163014e+06 | -0.002160 | 1.163417 |
| 2019-12-31 | 1.163667e+06 | 403.112655 | 1.163264e+06 | 0.000215 | 1.163667 |
253 rows × 5 columns
In [19]:
returns_chart(bt.balance)Out [19]:
In [20]:
returns_histogram(bt.balance)Out [20]:
In [21]:
monthly_returns_heatmap(bt.balance)Out [21]:
In [22]:
tickers = ["VTI", "VEU", "BND", "VNQ", "DBC"]
dfs = []
for ticker in tickers:
start = datetime.datetime(2020, 1, 1)
end = datetime.datetime(2020, 12, 31)
for i in range(10):
start = start.replace(year = start.year - 1)
end = end.replace(year = end.year - 1)
df = web.DataReader(ticker, 'yahoo', start, end).reset_index().rename(columns={'Date': 'date', 'High': 'high', 'Low': 'low', 'Open': 'open', 'Close': 'close', 'Volume': 'volume'})
df['symbol'] = ticker
dfs.append(df)
In [23]:
ivy_df = pd.concat(dfs)In [24]:
ivy_df = ivy_df.sort_values(by='date').reset_index(drop=True)In [25]:
ivy_df.to_csv("data/ivy_portfolio_data.csv", index=False)In [ ]:
In [26]:
data = HistoricalAssetData("data/ivy_portfolio_data.csv")
schema = data.schemaIn [27]:
dataOut [27]:
| date | high | low | open | close | volume | Adj Close | symbol | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2010-01-04 | 57.380001 | 56.840000 | 56.860001 | 57.310001 | 2251500.0 | 47.202740 | VTI |
| 1 | 2010-01-04 | 78.730003 | 78.540001 | 78.599998 | 78.680000 | 1098100.0 | 58.797794 | BND |
| 2 | 2010-01-04 | 44.959999 | 44.400002 | 44.660000 | 44.959999 | 1692500.0 | 33.440495 | VEU |
| 3 | 2010-01-04 | 45.419998 | 44.200001 | 45.220001 | 44.549999 | 2408400.0 | 29.869335 | VNQ |
| 4 | 2010-01-04 | 25.240000 | 25.070000 | 25.170000 | 25.240000 | 2046900.0 | 24.523520 | DBC |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 12575 | 2019-12-31 | 16.049999 | 15.910000 | 15.950000 | 15.950000 | 806100.0 | 15.950000 | DBC |
| 12576 | 2019-12-31 | 53.790001 | 53.480000 | 53.619999 | 53.750000 | 1688400.0 | 53.750000 | VEU |
| 12577 | 2019-12-31 | 92.830002 | 92.000000 | 92.089996 | 92.790001 | 4649500.0 | 92.790001 | VNQ |
| 12578 | 2019-12-31 | 83.919998 | 83.769997 | 83.849998 | 83.860001 | 5931300.0 | 83.860001 | BND |
| 12579 | 2019-12-31 | 163.759995 | 162.720001 | 163.000000 | 163.619995 | 3262400.0 | 163.619995 | VTI |
12580 rows × 8 columns
In [28]:
portfolio = Portfolio()In [29]:
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 [30]:
portfolio.add_assets([VTI, VEU, BND, VNQ, DBC])Out [30]:
<portfolio.portfolio.Portfolio at 0x116500490>
In [31]:
bt = Backtest(schema)
bt.portfolio = portfolio
bt.data = dataIn [32]:
# No rebalancing
bt.run(initial_capital = 1_000_000, periods=None)Out [32]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:19
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2010-01-03 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2010-01-04 | 1.000000e+06 | 92.035288 | 9.999080e+05 | 0.000000 | 1.000000 |
| 2010-01-05 | 1.001321e+06 | 92.035288 | 1.001229e+06 | 0.001321 | 1.001321 |
| 2010-01-06 | 1.005620e+06 | 92.035288 | 1.005528e+06 | 0.004293 | 1.005620 |
| 2010-01-07 | 1.004723e+06 | 92.035288 | 1.004631e+06 | -0.000892 | 1.004723 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 | 2.039190e+06 | 92.035288 | 2.039098e+06 | 0.001160 | 2.039190 |
| 2019-12-26 | 2.048080e+06 | 92.035288 | 2.047988e+06 | 0.004360 | 2.048080 |
| 2019-12-27 | 2.050816e+06 | 92.035288 | 2.050724e+06 | 0.001336 | 2.050816 |
| 2019-12-30 | 2.045149e+06 | 92.035288 | 2.045056e+06 | -0.002764 | 2.045149 |
| 2019-12-31 | 2.051284e+06 | 92.035288 | 2.051192e+06 | 0.003000 | 2.051284 |
2517 rows × 5 columns
In [33]:
returns_chart(bt.balance)Out [33]:
In [34]:
monthly_returns_heatmap(bt.balance)Out [34]:
In [35]:
# Monthly rebalancing
bt.run(initial_capital = 1_000_000, periods='1')Out [35]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:22
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2010-01-03 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2010-01-04 | 1.000000e+06 | 92.035288 | 9.999080e+05 | 0.000000 | 1.000000 |
| 2010-01-05 | 1.001321e+06 | 92.035288 | 1.001229e+06 | 0.001321 | 1.001321 |
| 2010-01-06 | 1.005620e+06 | 92.035288 | 1.005528e+06 | 0.004293 | 1.005620 |
| 2010-01-07 | 1.004723e+06 | 92.035288 | 1.004631e+06 | -0.000892 | 1.004723 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 | 1.817790e+06 | 57.640553 | 1.817733e+06 | 0.001500 | 1.817790 |
| 2019-12-26 | 1.826130e+06 | 57.640553 | 1.826072e+06 | 0.004588 | 1.826130 |
| 2019-12-27 | 1.829028e+06 | 57.640553 | 1.828970e+06 | 0.001587 | 1.829028 |
| 2019-12-30 | 1.824079e+06 | 57.640553 | 1.824021e+06 | -0.002706 | 1.824079 |
| 2019-12-31 | 1.826055e+06 | 57.640553 | 1.825997e+06 | 0.001083 | 1.826055 |
2517 rows × 5 columns
In [36]:
returns_chart(bt.balance)Out [36]:
In [ ]:
In [37]:
# Bi-annual rebalancing
bt.run(initial_capital = 1_000_000, periods='6')Out [37]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:21
| capital | cash | total_value | % change | accumulated return | |
|---|---|---|---|---|---|
| 2010-01-03 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN |
| 2010-01-04 | 1.000000e+06 | 92.035288 | 9.999080e+05 | 0.000000 | 1.000000 |
| 2010-01-05 | 1.001321e+06 | 92.035288 | 1.001229e+06 | 0.001321 | 1.001321 |
| 2010-01-06 | 1.005620e+06 | 92.035288 | 1.005528e+06 | 0.004293 | 1.005620 |
| 2010-01-07 | 1.004723e+06 | 92.035288 | 1.004631e+06 | -0.000892 | 1.004723 |
| ... | ... | ... | ... | ... | ... |
| 2019-12-24 | 1.823260e+06 | 131.209041 | 1.823129e+06 | 0.001476 | 1.823260 |
| 2019-12-26 | 1.831628e+06 | 131.209041 | 1.831497e+06 | 0.004590 | 1.831628 |
| 2019-12-27 | 1.834523e+06 | 131.209041 | 1.834392e+06 | 0.001580 | 1.834523 |
| 2019-12-30 | 1.829496e+06 | 131.209041 | 1.829364e+06 | -0.002740 | 1.829496 |
| 2019-12-31 | 1.831590e+06 | 131.209041 | 1.831458e+06 | 0.001145 | 1.831590 |
2517 rows × 5 columns
In [38]:
returns_chart(bt.balance)Out [38]:
In [39]:
monthly_returns_heatmap(bt.balance)Out [39]:
In [40]:
returns_histogram(bt.balance)Out [40]:
In [ ]: