{ "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", "DATA_DIR = os.path.join(BACKTESTER_DIR, 'data')\n", "OPTIONS_DATA = os.path.join(DATA_DIR, 'options_data_clean_v2.h5')\n", "STOCKS_DATA = os.path.join(DATA_DIR, 'ivy_5assets.csv')\n", "\n", "sys.path.append(BACKTESTER_DIR) # Add backtester base dir to $PYTHONPATH" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/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.\n", " from pandas.util.testing import assert_frame_equal\n", "/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.\n", " 'Module \"zipline.assets\" not found; mutltipliers will not be applied' +\n" ] } ], "source": [ "import pyfolio as pf\n", "\n", "from backtester import Backtest, Type, Direction, Stock\n", "from backtester.strategy import Strategy, StrategyLeg\n", "from backtester.datahandler import HistoricalOptionsData, TiingoData\n", "\n", "# Cleaned up data\n", "options_data = HistoricalOptionsData(\n", " OPTIONS_DATA,\n", " key=\"/SPX\",\n", " where='quotedate >= \"2012-01-01\" & quotedate <= \"2014-01-01\"')\n", "options_schema = options_data.schema" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "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))" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "put_otm = Strategy(options_schema)\n", "\n", "leg_1 = StrategyLeg(\"leg_1\", options_schema, option_type=Type.PUT, direction=Direction.BUY)\n", "leg_1.entry_filter = (options_schema.underlying == \"SPX\") & (options_schema.dte >= 60)\n", "leg_1.exit_filter = (options_schema.dte <= 30)\n", "\n", "leg_2 = StrategyLeg(\"leg_2\", options_schema, option_type=Type.CALL, direction=Direction.BUY)\n", "leg_2.entry_filter = (options_schema.underlying == \"SPX\") & (options_schema.dte >= 60)\n", "leg_2.exit_filter = (options_schema.dte <= 30)\n", "put_otm.add_legs([leg_1, leg_2])" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "asset_data = TiingoData(STOCKS_DATA)\n", "asset_data._data = asset_data.query('date >= \"2012-01-01\" & date <= \"2014-01-01\"')\n", "\n", "VTI = Stock(\"VTI\", 0.2)\n", "VEU = Stock(\"VEU\", 0.2)\n", "BND = Stock(\"BND\", 0.2)\n", "VNQ = Stock(\"VNQ\", 0.2)\n", "DBC = Stock(\"DBC\", 0.2)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "0% [██████████████████████████████] 100% | ETA: 00:00:00\n", "Total time elapsed: 00:00:07\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
total capitalcashVTIVEUBNDVNQDBCoptions qtycalls capitalputs capitalstocks qtyoptions capitalstocks capital% changeaccumulated return
2010-01-031.000000e+061000000.000000NaNNaNNaNNaNNaNNaNNaNNaNNaN0.00.000000e+00NaNNaN
2012-01-039.978700e+052233.455073193990.075633193976.304225193986.878802193966.992283193976.2939856.025740.00.024257.025740.09.698965e+05-0.0021300.997870
2012-01-049.949656e+052233.455073194079.321182193451.915101194080.052134190650.750322195450.0646706.025020.00.024257.025020.09.677121e+05-0.0029110.994966
2012-01-059.927494e+052233.455073194942.028158191259.015126194010.172135192441.520981192783.2415266.025080.00.024257.025080.09.654360e+05-0.0022270.992749
2012-01-069.887005e+052233.455073194495.800412188827.756460194126.638801191811.435009193625.3962026.023580.00.024257.023580.09.628870e+05-0.0040790.988700
................................................
2013-12-241.276243e+06273.097958248730.685735246256.243708242926.387533245754.530575246032.4462807.046270.00.027125.046270.01.229700e+060.0034011.276243
2013-12-261.282165e+06273.097958249907.026341247293.424036242562.316514245944.449069246414.7810847.049770.00.027125.049770.01.232122e+060.0046401.282165
2013-12-271.284267e+06273.097958249750.180927248281.214826242562.316514246476.220851247083.8669907.049840.00.027125.049840.01.234154e+060.0016391.284267
2013-12-301.284806e+06273.097958249828.603634249565.342851242956.726785246552.188248245650.1114767.049980.00.027125.049980.01.234553e+060.0004201.284806
2013-12-311.288826e+06273.097958250743.535215250553.133640242865.709030245222.758794245267.7766727.053900.00.027125.053900.01.234653e+060.0031291.288826
\n", "

503 rows × 15 columns

\n", "
" ], "text/plain": [ " total capital cash VTI VEU \\\n", "2010-01-03 1.000000e+06 1000000.000000 NaN NaN \n", "2012-01-03 9.978700e+05 2233.455073 193990.075633 193976.304225 \n", "2012-01-04 9.949656e+05 2233.455073 194079.321182 193451.915101 \n", "2012-01-05 9.927494e+05 2233.455073 194942.028158 191259.015126 \n", "2012-01-06 9.887005e+05 2233.455073 194495.800412 188827.756460 \n", "... ... ... ... ... \n", "2013-12-24 1.276243e+06 273.097958 248730.685735 246256.243708 \n", "2013-12-26 1.282165e+06 273.097958 249907.026341 247293.424036 \n", "2013-12-27 1.284267e+06 273.097958 249750.180927 248281.214826 \n", "2013-12-30 1.284806e+06 273.097958 249828.603634 249565.342851 \n", "2013-12-31 1.288826e+06 273.097958 250743.535215 250553.133640 \n", "\n", " BND VNQ DBC options qty \\\n", "2010-01-03 NaN NaN NaN NaN \n", "2012-01-03 193986.878802 193966.992283 193976.293985 6.0 \n", "2012-01-04 194080.052134 190650.750322 195450.064670 6.0 \n", "2012-01-05 194010.172135 192441.520981 192783.241526 6.0 \n", "2012-01-06 194126.638801 191811.435009 193625.396202 6.0 \n", "... ... ... ... ... \n", "2013-12-24 242926.387533 245754.530575 246032.446280 7.0 \n", "2013-12-26 242562.316514 245944.449069 246414.781084 7.0 \n", "2013-12-27 242562.316514 246476.220851 247083.866990 7.0 \n", "2013-12-30 242956.726785 246552.188248 245650.111476 7.0 \n", "2013-12-31 242865.709030 245222.758794 245267.776672 7.0 \n", "\n", " calls capital puts capital stocks qty options capital \\\n", "2010-01-03 NaN NaN NaN 0.0 \n", "2012-01-03 25740.0 0.0 24257.0 25740.0 \n", "2012-01-04 25020.0 0.0 24257.0 25020.0 \n", "2012-01-05 25080.0 0.0 24257.0 25080.0 \n", "2012-01-06 23580.0 0.0 24257.0 23580.0 \n", "... ... ... ... ... \n", "2013-12-24 46270.0 0.0 27125.0 46270.0 \n", "2013-12-26 49770.0 0.0 27125.0 49770.0 \n", "2013-12-27 49840.0 0.0 27125.0 49840.0 \n", "2013-12-30 49980.0 0.0 27125.0 49980.0 \n", "2013-12-31 53900.0 0.0 27125.0 53900.0 \n", "\n", " stocks capital % change accumulated return \n", "2010-01-03 0.000000e+00 NaN NaN \n", "2012-01-03 9.698965e+05 -0.002130 0.997870 \n", "2012-01-04 9.677121e+05 -0.002911 0.994966 \n", "2012-01-05 9.654360e+05 -0.002227 0.992749 \n", "2012-01-06 9.628870e+05 -0.004079 0.988700 \n", "... ... ... ... \n", "2013-12-24 1.229700e+06 0.003401 1.276243 \n", "2013-12-26 1.232122e+06 0.004640 1.282165 \n", "2013-12-27 1.234154e+06 0.001639 1.284267 \n", "2013-12-30 1.234553e+06 0.000420 1.284806 \n", "2013-12-31 1.234653e+06 0.003129 1.288826 \n", "\n", "[503 rows x 15 columns]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "allocation = {'cash': 0, 'stocks': 97, 'options': 3}\n", "\n", "bt = Backtest(allocation=allocation)\n", "bt.options_data = options_data\n", "bt.options_strategy = put_otm\n", "\n", "bt.stocks = [VTI, VEU, BND, VNQ, DBC]\n", "bt.stocks_data = asset_data\n", "\n", "bt.run(rebalance_freq=1)\n", "bt.balance" ] }, { "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", "
Start date2012-01-03
End date2013-12-31
Total months23
Backtest
Annual return13.6%
Cumulative returns28.9%
Annual volatility14.3%
Sharpe ratio0.96
Calmar ratio1.14
Stability0.83
Max drawdown-11.9%
Omega ratio1.18
Sortino ratio1.37
Skew-0.52
Kurtosis3.88
Tail ratio0.97
Daily value at risk-1.7%
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "ename": "AttributeError", "evalue": "'numpy.int64' object has no attribute 'to_pydatetime'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mpf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_returns_tear_sheet\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mreturns\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbalance\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'% change'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdropna\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/plotting.py\u001b[0m in \u001b[0;36mcall_w_context\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mset_context\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mplotting_context\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxes_style\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 52\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 53\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/tears.py\u001b[0m in \u001b[0;36mcreate_returns_tear_sheet\u001b[0;34m(returns, positions, transactions, live_start_date, cone_std, benchmark_rets, bootstrap, turnover_denom, header_rows, return_fig)\u001b[0m\n\u001b[1;32m 502\u001b[0m header_rows=header_rows)\n\u001b[1;32m 503\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 504\u001b[0;31m \u001b[0mplotting\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshow_worst_drawdown_periods\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mreturns\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 505\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 506\u001b[0m \u001b[0mvertical_sections\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/plotting.py\u001b[0m in \u001b[0;36mshow_worst_drawdown_periods\u001b[0;34m(returns, top)\u001b[0m\n\u001b[1;32m 1662\u001b[0m \"\"\"\n\u001b[1;32m 1663\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1664\u001b[0;31m \u001b[0mdrawdown_df\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtimeseries\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgen_drawdown_table\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mreturns\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtop\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtop\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1665\u001b[0m utils.print_table(\n\u001b[1;32m 1666\u001b[0m \u001b[0mdrawdown_df\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msort_values\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Net drawdown in %'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mascending\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/.local/share/virtualenvs/backtester_options-33KCFJeg/lib/python3.7/site-packages/pyfolio/timeseries.py\u001b[0m in \u001b[0;36mgen_drawdown_table\u001b[0;34m(returns, top)\u001b[0m\n\u001b[1;32m 1006\u001b[0m df_drawdowns.loc[i, 'Peak date'] = (peak.to_pydatetime()\n\u001b[1;32m 1007\u001b[0m .strftime('%Y-%m-%d'))\n\u001b[0;32m-> 1008\u001b[0;31m df_drawdowns.loc[i, 'Valley date'] = (valley.to_pydatetime()\n\u001b[0m\u001b[1;32m 1009\u001b[0m .strftime('%Y-%m-%d'))\n\u001b[1;32m 1010\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecovery\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfloat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAttributeError\u001b[0m: 'numpy.int64' object has no attribute 'to_pydatetime'" ] } ], "source": [ "pf.create_returns_tear_sheet(returns=bt.balance['% change'].dropna())" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 4 }