Files
options_backtester/backtester/examples/2legs_example.ipynb
T

25 KiB
Raw Blame History

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 $PYTHONPATH
In [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.balance
Out [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 date2012-01-03
End date2013-12-31
Total months23
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%
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-ea8302e3d94e> in <module>
----> 1 pf.create_returns_tear_sheet(returns=bt.balance['% change'].dropna())

~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/plotting.py in call_w_context(*args, **kwargs)
     50         if set_context:
     51             with plotting_context(), axes_style():
---> 52                 return func(*args, **kwargs)
     53         else:
     54             return func(*args, **kwargs)

~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/tears.py in create_returns_tear_sheet(returns, positions, transactions, live_start_date, cone_std, benchmark_rets, bootstrap, turnover_denom, header_rows, return_fig)
    502                              header_rows=header_rows)
    503 
--> 504     plotting.show_worst_drawdown_periods(returns)
    505 
    506     vertical_sections = 11

~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/plotting.py in show_worst_drawdown_periods(returns, top)
   1662     """
   1663 
-> 1664     drawdown_df = timeseries.gen_drawdown_table(returns, top=top)
   1665     utils.print_table(
   1666         drawdown_df.sort_values('Net drawdown in %', ascending=False),

~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/timeseries.py in gen_drawdown_table(returns, top)
   1006         df_drawdowns.loc[i, 'Peak date'] = (peak.to_pydatetime()
   1007                                             .strftime('%Y-%m-%d'))
-> 1008         df_drawdowns.loc[i, 'Valley date'] = (valley.to_pydatetime()
   1009                                               .strftime('%Y-%m-%d'))
   1010         if isinstance(recovery, float):

AttributeError: 'numpy.int64' object has no attribute 'to_pydatetime'