Options Backtesting in Python: An Introductory Walkthrough

Trading strategies are systematic approaches to buying and selling securities, with the goal of reaping a profit. But the catch is right there in the name. They're strategies, and they don't always succeed. This is especially true with potentially volatile securities like options. The wrong strategy can lose a lot of money very quickly.

There's no way to be completely sure that a strategy will work, but one of the best steps you can take before implementing a strategy is backtesting. You heard that past performance is no guarantee of future returns, but historical data is a good stake in the ground.

In this article, you'll learn how to get started with options backtesting in Python. We'll start with a brief discussion about options, discuss why Python is a good choice, then dive right into how to use one of the best libraries for backtesting.

Before we proceed, please note that this blog is about setting up a backtesting environment for options. It's not intended to provide advice on trading or trading strategies.

What are Options?

An option is a contract that gives the owner the right to buy (call) or sell (put) a quantity of an underlying financial instrument at a set price at a specified date. With some contracts, you may be able to exercise before the expiration date. In all cases, you have the right to exercise the option but are never required to. You can buy options for nearly every type of financial instrument, but to keep things simple, we'll stick to stocks, also known as equities. 

Superficially, options look simple. If a stock is currently trading at $10 and you think its price will go up in six months, then an option to call (buy) at $9 six months from now is a good deal. The same logic follows for a put (sell) option. If you think the underlying equities are going to drop in price, an option at the same or higher price looks good.

But in practice, options are complex, and you can implement a wide variety of different trading strategies. Backtesting is a tool for testing those strategies.

Why Use Python?

Python is a popular tool for backtesting trading strategies for several important reasons.

  • Two popular python libraries, NumPy and Pandas, make t easy to process financial data, even when you're working on sets that span many years
  • Jupyter Notebook makes it easy to write and test code on the fly, in a visual environment
  • You can easily call C and C++ code inside a Python program for external algorithms

It's also a remarkably easy language to learn, with a simple syntax. Many traders pick it up on the job, using it to express complicated trading algorithms with a few lines of code.

Python Options Backtesting libraries

We're going to use OptionSuite to test a simple trading strategy, but once you understand the basics, you can plug in any one of the many backtesting libraries for Python. Let's cover a few before we start coding.

QuantConnect

QuantConnect is a commercial library for backtesting Equities, Forex, Options, Futures, and Cryptocurrencies. One of its key features, and a reason why it's a commercial product, is that it comes with historical pricing information. This makes it very easy to get the library up and running.

Depending on your needs, QuantConnect has pricing for individuals, trading teams, firms, and institutions.

Optopsy

Optopsy is an open-source library for testing option strategies. Unlike QuantConnect, and like all the open-source offerings, you need to supply your own data. As of this writing, it has built-in support for:

  • Calls/Puts
  • Straddles/Strangles
  • Vertical Call/Put Spreads

OptionSuite

We're going to use OptionSuite below. It's a modular library that makes it easy to add custom strategies, and comes with just enough test data that we can run a quick tutorial.

Let's get started!

A Basic Backtesting Setup

OptionSuite comes with a basic backtesting example. Let's download the code, make a few tweaks, and run it against the included sample data. 

Create and Prepare a Python Virtual Environment

First, you need a Python environment with the Pandas library to run your code. Rather than install Pandas and its many dependencies in your system's default environment, a virtual environment is considered a best practice.

There are many tools for managing virtual environments. Here is how you can prepare one using the standard {% c-line %}venv{% c-line-end %} tools on Linux. Ensure they're installed on your system before proceeding.

You can use an IDE like PyCharm to create the environment, but here's a command line example.

1. Create a directory for your project.

2. Move into the directory.

3. Use {% c-line %}python3 -m venv ./venv{% c-line-end %} to create a virtual environment in the {% c-line %}.venv{% c-line-end %} subdirectory.

4. Activate the environment with {% c-line %}source .venv/bin/activate{% c-line-end %}

5. Install Pandas with {% c-line %}pip install pandas{% c-line-end %}

You can verify that Pandas is working with a quick test.

Get OptionSuite

Next, check out OptionSuite from GitHub. The repository is here.

Small Code and Configuration Changes

OptionSuite's example is included in {% c-line %}backtester.py{% c-line-end %}. It executes a simple strangle strategy. But before running it, we need to make a few changes.

First, check line 10 for an out-of-date reference. I submitted a pull request, but it may not have been merged yet.

It should be:

Make the same fix on line #53, where the class is used.

Next, you need to set the script up with sample data. The README has instructions for using purchased data, but we can modify them to use the test data included with the source code.

The data is in {% c-line %}marketData/iVolatility/SPX/SPX_2011_2017/RawIV_5day_sample_updated.csv{% c-line-end %} 

Use this path, appended to the directory to where you checked out the code in, on line #11 of {% c-line %}backtester.py{% c-line-end %}: 

So, the code will load the sample data.

Finally, the data stamps in this data don't agree with the format specified in the data handler configuration, which gives us a chance to see how OptionSuite manages historical market data.

Open {% c-line %}datahandler/dataProviders.json{% c-line-end %}: 

This file maps the columns in your CSV marketdata to field names in OptionSuite, and allows you to use any data source that provides the data needed for your trading strategy.

The {% c-line %}data_time_format{% c-line-end %} setting on line #31 doesn't match the sample data. Change it to {% c-line %}"%m/%d/%y"{% c-line-end %}

You'll find information on how these date fields work here.

Finally, we need to adjust the strategy parameters so there's enough capital to make some trades.

They start on line #34.

First, raise the amount of startingCapital to 500000 on line #47.

Then, double the amount of capital per trade to 0.20.

Run a Backtest

Finally, we can run a test.

Here is a command session in PyCharm:

The backtester creates two log files. {% c-line %}positions_strangle_XXXXX.log{% c-line-end %} has messages from the Python classes. {% c-line %}positions_strangle_XXXXX.csv{% c-line-end %} has trading information and results:

So, we can see that the strategy lost money with a strike price of 1270.2 and 1271.5, but made a small profit at 1276.56 and 1273.85.

Write Your Own Tests

From here, you can create your own strategies by extending the strategy.Strategy class similar to how {% c-line %}StrangleStrat{% c-line-end %} does.

Backtesting Options With Python

In this post we covered the how and why of backtesting options with Python. We covered a few of the library options and then we set up a simple test using OptionSuite and its sample data. Now that you understand how to get started with backtesting options with Python, give it a try on your own!

And, when you need to run multiple tests at once, take a look at Pipekit and how you can supercharge your backtesting with Agile Workflows and Kubernetes.

Subscribe for Pipekit updates.

Get the latest articles on all things Pipekit & data orchestration delivered straight to your inbox.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Follow Pipekit

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

More

Guides

5 Ways to Reduce YAML File Size

5 min read
Guides

Upgrade to K8s 1.27+ to Take Advantage of Argo Workflows Performance Improvements

3 min read
Guides

How to Set Up a MinIO Artifact Repository for Argo Workflows

6 min read