mirror of
https://github.com/wassname/options_backtester.git
synced 2026-07-26 13:28:06 +08:00
25 KiB
25 KiB
In [1]:
import os
import sys
BACKTESTER_DIR = os.path.realpath(os.path.join(os.getcwd(), '..', '..'))
DATA_DIR = os.path.join(BACKTESTER_DIR, 'data')
OPTIONS_DATA = os.path.join(DATA_DIR, 'options_data_clean_v2.h5')
STOCKS_DATA = os.path.join(DATA_DIR, 'ivy_5assets.csv')
sys.path.append(BACKTESTER_DIR) # Add backtester base dir to $PYTHONPATHIn [2]:
import pyfolio as pf
from backtester import Backtest, Type, Direction, Stock
from backtester.strategy import Strategy, StrategyLeg
from backtester.datahandler import HistoricalOptionsData, TiingoData
# Cleaned up data
options_data = HistoricalOptionsData(
OPTIONS_DATA,
key="/SPX",
where='quotedate >= "2012-01-01" & quotedate <= "2014-01-01"')
options_schema = options_data.schema/Users/jamoroso/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pandas_datareader/compat/__init__.py:7: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead. from pandas.util.testing import assert_frame_equal /Users/jamoroso/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/pos.py:27: UserWarning: Module "zipline.assets" not found; mutltipliers will not be applied to position notionals. 'Module "zipline.assets" not found; mutltipliers will not be applied' +
In [3]:
put_otm = Strategy(options_schema)
leg_1 = StrategyLeg("leg_1", options_schema, option_type=Type.PUT, direction=Direction.BUY)
leg_1.entry_filter = (options_schema.underlying == "SPX") & (options_schema.dte >= 60)
leg_1.exit_filter = (options_schema.dte <= 30)
leg_2 = StrategyLeg("leg_2", options_schema, option_type=Type.CALL, direction=Direction.BUY)
leg_2.entry_filter = (options_schema.underlying == "SPX") & (options_schema.dte >= 60)
leg_2.exit_filter = (options_schema.dte <= 30)
put_otm.add_legs([leg_1, leg_2])Out [3]:
Strategy(legs=[StrategyLeg(name=leg_1, type=Type.PUT, direction=Direction.BUY, entry_filter=Filter(query='((type == 'put') & (ask > 0)) & ((underlying == 'SPX') & (dte >= 60))'), exit_filter=Filter(query='(type == 'put') & (dte <= 30)')), StrategyLeg(name=leg_2, type=Type.CALL, direction=Direction.BUY, entry_filter=Filter(query='((type == 'call') & (ask > 0)) & ((underlying == 'SPX') & (dte >= 60))'), exit_filter=Filter(query='(type == 'call') & (dte <= 30)'))], exit_thresholds=(inf, inf))
In [4]:
asset_data = TiingoData(STOCKS_DATA)
asset_data._data = asset_data.query('date >= "2012-01-01" & date <= "2014-01-01"')
VTI = Stock("VTI", 0.2)
VEU = Stock("VEU", 0.2)
BND = Stock("BND", 0.2)
VNQ = Stock("VNQ", 0.2)
DBC = Stock("DBC", 0.2)In [5]:
allocation = {'cash': 0, 'stocks': 97, 'options': 3}
bt = Backtest(allocation=allocation)
bt.options_data = options_data
bt.options_strategy = put_otm
bt.stocks = [VTI, VEU, BND, VNQ, DBC]
bt.stocks_data = asset_data
bt.run(rebalance_freq=1)
bt.balanceOut [5]:
0% [██████████████████████████████] 100% | ETA: 00:00:00 Total time elapsed: 00:00:07
| total capital | cash | VTI | VEU | BND | VNQ | DBC | options qty | calls capital | puts capital | stocks qty | options capital | stocks capital | % change | accumulated return | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010-01-03 | 1.000000e+06 | 1000000.000000 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.0 | 0.000000e+00 | NaN | NaN |
| 2012-01-03 | 9.978700e+05 | 2233.455073 | 193990.075633 | 193976.304225 | 193986.878802 | 193966.992283 | 193976.293985 | 6.0 | 25740.0 | 0.0 | 24257.0 | 25740.0 | 9.698965e+05 | -0.002130 | 0.997870 |
| 2012-01-04 | 9.949656e+05 | 2233.455073 | 194079.321182 | 193451.915101 | 194080.052134 | 190650.750322 | 195450.064670 | 6.0 | 25020.0 | 0.0 | 24257.0 | 25020.0 | 9.677121e+05 | -0.002911 | 0.994966 |
| 2012-01-05 | 9.927494e+05 | 2233.455073 | 194942.028158 | 191259.015126 | 194010.172135 | 192441.520981 | 192783.241526 | 6.0 | 25080.0 | 0.0 | 24257.0 | 25080.0 | 9.654360e+05 | -0.002227 | 0.992749 |
| 2012-01-06 | 9.887005e+05 | 2233.455073 | 194495.800412 | 188827.756460 | 194126.638801 | 191811.435009 | 193625.396202 | 6.0 | 23580.0 | 0.0 | 24257.0 | 23580.0 | 9.628870e+05 | -0.004079 | 0.988700 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2013-12-24 | 1.276243e+06 | 273.097958 | 248730.685735 | 246256.243708 | 242926.387533 | 245754.530575 | 246032.446280 | 7.0 | 46270.0 | 0.0 | 27125.0 | 46270.0 | 1.229700e+06 | 0.003401 | 1.276243 |
| 2013-12-26 | 1.282165e+06 | 273.097958 | 249907.026341 | 247293.424036 | 242562.316514 | 245944.449069 | 246414.781084 | 7.0 | 49770.0 | 0.0 | 27125.0 | 49770.0 | 1.232122e+06 | 0.004640 | 1.282165 |
| 2013-12-27 | 1.284267e+06 | 273.097958 | 249750.180927 | 248281.214826 | 242562.316514 | 246476.220851 | 247083.866990 | 7.0 | 49840.0 | 0.0 | 27125.0 | 49840.0 | 1.234154e+06 | 0.001639 | 1.284267 |
| 2013-12-30 | 1.284806e+06 | 273.097958 | 249828.603634 | 249565.342851 | 242956.726785 | 246552.188248 | 245650.111476 | 7.0 | 49980.0 | 0.0 | 27125.0 | 49980.0 | 1.234553e+06 | 0.000420 | 1.284806 |
| 2013-12-31 | 1.288826e+06 | 273.097958 | 250743.535215 | 250553.133640 | 242865.709030 | 245222.758794 | 245267.776672 | 7.0 | 53900.0 | 0.0 | 27125.0 | 53900.0 | 1.234653e+06 | 0.003129 | 1.288826 |
503 rows × 15 columns
In [6]:
pf.create_returns_tear_sheet(returns=bt.balance['% change'].dropna())| Start date | 2012-01-03 | |
|---|---|---|
| End date | 2013-12-31 | |
| Total months | 23 | |
| Backtest | ||
| Annual return | 13.6% | |
| Cumulative returns | 28.9% | |
| Annual volatility | 14.3% | |
| Sharpe ratio | 0.96 | |
| Calmar ratio | 1.14 | |
| Stability | 0.83 | |
| Max drawdown | -11.9% | |
| Omega ratio | 1.18 | |
| Sortino ratio | 1.37 | |
| Skew | -0.52 | |
| Kurtosis | 3.88 | |
| Tail ratio | 0.97 | |
| Daily value at risk | -1.7% | |
[0;31m---------------------------------------------------------------------------[0m [0;31mAttributeError[0m Traceback (most recent call last) [0;32m<ipython-input-6-ea8302e3d94e>[0m in [0;36m<module>[0;34m[0m [0;32m----> 1[0;31m [0mpf[0m[0;34m.[0m[0mcreate_returns_tear_sheet[0m[0;34m([0m[0mreturns[0m[0;34m=[0m[0mbt[0m[0;34m.[0m[0mbalance[0m[0;34m[[0m[0;34m'% change'[0m[0;34m][0m[0;34m.[0m[0mdropna[0m[0;34m([0m[0;34m)[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [0m [0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/plotting.py[0m in [0;36mcall_w_context[0;34m(*args, **kwargs)[0m [1;32m 50[0m [0;32mif[0m [0mset_context[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m [1;32m 51[0m [0;32mwith[0m [0mplotting_context[0m[0;34m([0m[0;34m)[0m[0;34m,[0m [0maxes_style[0m[0;34m([0m[0;34m)[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m [0;32m---> 52[0;31m [0;32mreturn[0m [0mfunc[0m[0;34m([0m[0;34m*[0m[0margs[0m[0;34m,[0m [0;34m**[0m[0mkwargs[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [0m[1;32m 53[0m [0;32melse[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m [1;32m 54[0m [0;32mreturn[0m [0mfunc[0m[0;34m([0m[0;34m*[0m[0margs[0m[0;34m,[0m [0;34m**[0m[0mkwargs[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/tears.py[0m in [0;36mcreate_returns_tear_sheet[0;34m(returns, positions, transactions, live_start_date, cone_std, benchmark_rets, bootstrap, turnover_denom, header_rows, return_fig)[0m [1;32m 502[0m header_rows=header_rows) [1;32m 503[0m [0;34m[0m[0m [0;32m--> 504[0;31m [0mplotting[0m[0;34m.[0m[0mshow_worst_drawdown_periods[0m[0;34m([0m[0mreturns[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [0m[1;32m 505[0m [0;34m[0m[0m [1;32m 506[0m [0mvertical_sections[0m [0;34m=[0m [0;36m11[0m[0;34m[0m[0;34m[0m[0m [0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/plotting.py[0m in [0;36mshow_worst_drawdown_periods[0;34m(returns, top)[0m [1;32m 1662[0m """ [1;32m 1663[0m [0;34m[0m[0m [0;32m-> 1664[0;31m [0mdrawdown_df[0m [0;34m=[0m [0mtimeseries[0m[0;34m.[0m[0mgen_drawdown_table[0m[0;34m([0m[0mreturns[0m[0;34m,[0m [0mtop[0m[0;34m=[0m[0mtop[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [0m[1;32m 1665[0m utils.print_table( [1;32m 1666[0m [0mdrawdown_df[0m[0;34m.[0m[0msort_values[0m[0;34m([0m[0;34m'Net drawdown in %'[0m[0;34m,[0m [0mascending[0m[0;34m=[0m[0;32mFalse[0m[0;34m)[0m[0;34m,[0m[0;34m[0m[0;34m[0m[0m [0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/timeseries.py[0m in [0;36mgen_drawdown_table[0;34m(returns, top)[0m [1;32m 1006[0m df_drawdowns.loc[i, 'Peak date'] = (peak.to_pydatetime() [1;32m 1007[0m .strftime('%Y-%m-%d')) [0;32m-> 1008[0;31m df_drawdowns.loc[i, 'Valley date'] = (valley.to_pydatetime() [0m[1;32m 1009[0m .strftime('%Y-%m-%d')) [1;32m 1010[0m [0;32mif[0m [0misinstance[0m[0;34m([0m[0mrecovery[0m[0;34m,[0m [0mfloat[0m[0;34m)[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m [0;31mAttributeError[0m: 'numpy.int64' object has no attribute 'to_pydatetime'