# options_backtester
**Repository Path**: triobox/options_backtester
## Basic Information
- **Project Name**: options_backtester
- **Description**: Simple backtesting software for options
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-06-05
- **Last Updated**: 2021-06-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
[](https://travis-ci.com/lambdaclass/options_backtester)
Options Backtester
==============================
Simple backtester to evaluate and analyse options strategies over historical price data.
- [Requirements](#requirements)
- [Setup](#setup)
- [Usage](#usage)
- [Recommended Reading](#recommended-reading)
- [Data Sources](#data-sources)
## Requirements
- Python >= 3.6
- pipenv
## Setup
Install [pipenv](https://pipenv.pypa.io/en/latest/)
```shell
$> pip install pipenv
```
Create environment and download dependencies
```shell
$> make install
```
Activate environment
```shell
$> make env
```
Run [Jupyter](https://jupyter.org) notebook
```shell
$> make notebook
```
Run tests
```shell
$> make test
```
## Usage
### Sample backtest
You can run this example by putting the code into a Jupyter Notebook/Lab file in this directory.
```python
import os
import sys
BACKTESTER_DIR = os.getcwd()
TEST_DATA_DIR = os.path.join(BACKTESTER_DIR, 'backtester', 'test', 'test_data')
SAMPLE_STOCK_DATA = os.path.join(TEST_DATA_DIR, 'test_data_stocks.csv')
SAMPLE_OPTIONS_DATA = os.path.join(TEST_DATA_DIR, 'test_data_options.csv')
```
```python
from backtester import Backtest, Stock, Type, Direction
from backtester.datahandler import HistoricalOptionsData, TiingoData
from backtester.strategy import Strategy, StrategyLeg
```
First we construct an options datahandler.
```python
options_data = HistoricalOptionsData(SAMPLE_OPTIONS_DATA)
options_schema = options_data.schema
```
Next, we'll create a toy options strategy. It will simply buy a call and a put with `dte` between $80$ and $52$ and exit them a month later.
```python
sample_strategy = Strategy(options_schema)
leg1 = StrategyLeg('leg_1', options_schema, option_type=Type.CALL, direction=Direction.BUY)
leg1.entry_filter = (options_schema.dte < 80) & (options_schema.dte > 52)
leg1.exit_filter = (options_schema.dte <= 52)
leg2 = StrategyLeg('leg_2', options_schema, option_type=Type.PUT, direction=Direction.BUY)
leg2.entry_filter = (options_schema.dte < 80) & (options_schema.dte > 52)
leg2.exit_filter = (options_schema.dte <= 52)
sample_strategy.add_legs([leg1, leg2]);
```
We do the same for stocks: create a datahandler together with a list of the stocks we want in our inventory and their corresponding weights. In this case, we will hold `VOO`, `TUR` and `RSX`, with $0.4$, $0.1$ and $0.5$ weights respectively.
```python
stocks_data = TiingoData(SAMPLE_STOCK_DATA)
stocks = [Stock('VOO', 0.4), Stock('TUR', 0.1), Stock('RSX', 0.5)]
```
We set our portfolio allocation, i.e. how much of our capital will be invested in stocks, options and cash. We'll allocate 50% of our capital to stocks and the rest to options.
```python
allocation = {'stocks': 0.5, 'options': 0.5, 'cash': 0.0}
```
Finally, we create the `Backtest` object.
```python
bt = Backtest(allocation, initial_capital=1_000_000)
bt.stocks = stocks
bt.stocks_data = stocks_data
bt.options_strategy = sample_strategy
bt.options_data = options_data
```
And run the backtest with a rebalancing period of one month.
```python
bt.run(rebalance_freq=1)
```
0% [██████████████████████████████] 100% | ETA: 00:00:00
Total time elapsed: 00:00:00
|
leg_1 |
leg_2 |
totals |
|
contract |
underlying |
expiration |
type |
strike |
cost |
order |
contract |
underlying |
expiration |
type |
strike |
cost |
order |
cost |
qty |
date |
| 0 |
SPX170317C00300000 |
SPX |
2017-03-17 |
call |
300 |
195010.0 |
Order.BTO |
SPX170317P00300000 |
SPX |
2017-03-17 |
put |
300 |
5.0 |
Order.BTO |
195015.0 |
2.0 |
2017-01-03 |
| 1 |
SPX170317C00300000 |
SPX |
2017-03-17 |
call |
300 |
-197060.0 |
Order.STC |
SPX170317P00300000 |
SPX |
2017-03-17 |
put |
300 |
-0.0 |
Order.STC |
-197060.0 |
2.0 |
2017-02-01 |
| 2 |
SPX170421C00500000 |
SPX |
2017-04-21 |
call |
500 |
177260.0 |
Order.BTO |
SPX170421P01375000 |
SPX |
2017-04-21 |
put |
1375 |
60.0 |
Order.BTO |
177320.0 |
2.0 |
2017-02-01 |
| 3 |
SPX170421C00500000 |
SPX |
2017-04-21 |
call |
500 |
-188980.0 |
Order.STC |
SPX170421P01375000 |
SPX |
2017-04-21 |
put |
1375 |
-5.0 |
Order.STC |
-188985.0 |
2.0 |
2017-03-01 |
| 4 |
SPX170519C01000000 |
SPX |
2017-05-19 |
call |
1000 |
138940.0 |
Order.BTO |
SPX170519P01650000 |
SPX |
2017-05-19 |
put |
1650 |
100.0 |
Order.BTO |
139040.0 |
3.0 |
2017-03-01 |
| 5 |
SPX170519C01000000 |
SPX |
2017-05-19 |
call |
1000 |
-135290.0 |
Order.STC |
SPX170519P01650000 |
SPX |
2017-05-19 |
put |
1650 |
-20.0 |
Order.STC |
-135310.0 |
3.0 |
2017-04-03 |
The trade log (`bt.trade_log`) shows we executed 6 trades: we bought one call and one put on _2017-01-03_, _2017-02-01_ and _2017-03-01_, and exited those positions on _2017-02-01_, _2017-03-01_ and _2017-04-03_ respectively.
The balance data structure shows how our positions evolved over time:
- We started with $1000000 on _2017-01-02_
- `total capital` is the sum of `cash`, `stocks capital` and `options capital`
- `% change` shows the inter day change in `total capital`
- `accumulated return` gives the compounded return in `total capital` since the start of the backtest
```python
bt.balance.head()
```
|
total capital |
cash |
VOO |
TUR |
RSX |
options qty |
calls capital |
puts capital |
stocks qty |
VOO qty |
TUR qty |
RSX qty |
options capital |
stocks capital |
% change |
accumulated return |
| 2017-01-02 |
1.000000e+06 |
1000000.00000 |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
0.0 |
0.000000 |
NaN |
NaN |
| 2017-01-03 |
9.990300e+05 |
110117.40592 |
199872.763320 |
49993.281167 |
249986.549593 |
2.0 |
389060.0 |
0.0 |
16186.0 |
1025.0 |
1758.0 |
13403.0 |
389060.0 |
499852.594080 |
-0.000970 |
0.999030 |
| 2017-01-04 |
1.004228e+06 |
110117.40592 |
201052.238851 |
50072.862958 |
251605.333911 |
2.0 |
391380.0 |
0.0 |
16186.0 |
1025.0 |
1758.0 |
13403.0 |
391380.0 |
502730.435720 |
0.005203 |
1.004228 |
| 2017-01-05 |
1.002706e+06 |
110117.40592 |
200897.553535 |
49865.950301 |
250564.686850 |
2.0 |
391260.0 |
0.0 |
16186.0 |
1025.0 |
1758.0 |
13403.0 |
391260.0 |
501328.190686 |
-0.001516 |
1.002706 |
| 2017-01-06 |
1.003201e+06 |
110117.40592 |
201680.647945 |
49372.543196 |
248830.275081 |
2.0 |
393200.0 |
0.0 |
16186.0 |
1025.0 |
1758.0 |
13403.0 |
393200.0 |
499883.466222 |
0.000494 |
1.003201 |
Evolution of our total capital over time:
```python
bt.balance['total capital'].plot();
```

Evolution of our stock positions over time:
```python
bt.balance[[stock.symbol for stock in stocks]].plot();
```

More plots and statistics are available in the `backtester.statistics` module.
### Other strategies
The `Strategy` and `StrategyLeg` classes allow for more complex strategies; for instance, a [long strangle](https://www.investopedia.com/terms/s/strangle.asp) could be implemented like so:
```python
# Long strangle
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) & (options_schema.underlying_last <= 1.1 * options_schema.strike)
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) & (options_schema.underlying_last >= 0.9 * options_schema.strike)
leg_2.exit_filter = (options_schema.dte <= 30)
strategy = Strategy(options_schema)
strategy.add_legs([leg_1, leg_2]);
```
You can explore more usage examples in the Jupyter [notebooks](backtester/examples/).
## Recommended reading
For complete novices in finance and economics, this [post](https://notamonadtutorial.com/how-to-earn-your-macroeconomics-and-finance-white-belt-as-a-software-developer-136e7454866f) gives a comprehensive introduction.
### Books
#### Introductory
- Option Volatility and Pricing 2nd Ed. - Natemberg, 2014
- Options, Futures, and Other Derivatives 10th Ed. - Hull 2017
- Trading Options Greeks: How Time, Volatility, and Other Pricing Factors Drive Profits 2nd Ed. - Passarelli 2012
#### Intermediate
- Trading Volatility - Bennet 2014
- Volatility Trading 2nd Ed. - Sinclair 2013
#### Advanced
- Dynamic Hedging - Taleb 1997
- The Volatility Surface: A Practitioner's Guide - Gatheral 2006
- The Volatility Smile - Derman & Miller 2016
### Papers
- [Volatility: A New Return Driver?](http://static.squarespace.com/static/53974e3ae4b0039937edb698/t/53da6400e4b0d5d5360f4918/1406821376095/Directional%20Volatility%20Research.pdf)
- [Easy Volatility Investing](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2255327)
- [Everybody’s Doing It: Short Volatility Strategies and Shadow Financial Insurers](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3071457)
- [Volatility-of-Volatility Risk](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2497759)
- [The Distribution of Returns](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2828744)
- [Safe Haven Investing Part I - Not all risk mitigation is created equal](https://www.universa.net/UniversaResearch_SafeHavenPart1_RiskMitigation.pdf)
- [Safe Haven Investing Part II - Not all risk is created equal](https://www.universa.net/UniversaResearch_SafeHavenPart2_NotAllRisk.pdf)
- [Safe Haven Investing Part III - Those wonderful tenbaggers](https://www.universa.net/UniversaResearch_SafeHavenPart3_Tenbaggers.pdf)
- [Insurance makes wealth grow faster](https://arxiv.org/abs/1507.04655)
- [Ergodicity economics](https://ergodicityeconomics.files.wordpress.com/2018/06/ergodicity_economics.pdf)
- [The Rate of Return on Everything, 1870–2015](https://economics.harvard.edu/files/economics/files/ms28533.pdf)
- [Volatility and the Alchemy of Risk](https://static1.squarespace.com/static/5581f17ee4b01f59c2b1513a/t/59ea16dbbe42d6ff1cae589f/1508513505640/Artemis_Volatility+and+the+Alchemy+of+Risk_2017.pdf)
## Data sources
### Exchanges
- [IEX](https://iextrading.com/developer/)
- [Tiingo](https://api.tiingo.com/)
- [CBOE Options Data](http://www.cboe.com/delayedquote/quote-table-download)
### Historical Data
- [Shiller's US Stocks, Dividends, Earnings, Inflation (CPI), and long term interest rates](http://www.econ.yale.edu/~shiller/data.htm)
- [Fama/French US Stock Index Data](http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html)
- [FRED CPI, Interest Rates, Trade Data](https://fred.stlouisfed.org)
- [REIT Data](https://www.reit.com/data-research/reit-market-data/reit-industry-financial-snapshot)