Implied Volatility with C++ and Python Pt. 1

Let's take a well deserved break from thinking about data and get to some code.

Implied Volatility in Words

Volatility is a critical component to pricing options. Unfortunately it is a latent (or unobserved) quantity. Options traders therefore need a way to understand what the market says about volatility. Traders will look at the market price of an option and use a pricing model to figure out what volatility must be input into the model to match the price observed in the market. Whatever that volatility ends up being is called the implied volatility. In other words, the volatility implied by market prices.

Implied volatility is used by options traders as a way to understand the relative value of an option. Traders might have their own proprietary volatility model and if the volatility implied by the options market is cheap compared to their model, they will enter a position that benefits when volatility increases. If the volatility implied by the options market is expensive compared to their model, they will enter a position that benefits when volatility decreases. One can also create a chart of implied volatility against strike prices, which is called volatility smile or volatility skew depending on the shape of the curve. If plotted against expiration dates it's called the term structure of volatility.

Implied Volatility Smile - Bespoke Options Implied Volatility Term Structure - Bespoke Options

I want to compute implied volatility on a large set of options at the same time. I decided to code up the venerable Black-Scholes pricing model in C++ to make this operation fast. Along with Brent's method for finding roots of functions, we're able to compute implied volatility quickly.

Implied Volatility in C++

I'm going to create two C++ header files and two C++ source files and use Make to compile and link the source. One of these source files will contain the code for pricing options and finding roots. The other will be the statistical functions required by the Black-Scholes model. Our goal is to create a shared library (.so file on Mac OSX) that can be used with Python.

Let's start with building a directory tree to layout the files. Use the following commands

bin will hold the .so (or binary) file after compiling and linking the source, inc contains the (included) .h header files, obj contains the .o (object) files and src contains our .cc C++ (source) files.

Let's begin with the header files which contains the declarations for the functions we'll be using. Header files come in handy when many source files need use of functions in a single file. The optlib.h file contains the the declarations for our pricing functions as well as the functions that will compute the implied volatility. Save this file in the inc directory.

The stats.h file contains the declarations for the two statistical functions used in the Black-Scholes pricing model. Save this file in inc as well.

Now that we've got that out of the way, let's create our source files. These can be expanded with additional pricing models which is one of the benefits of separating code into different files. If you add a new function to this file, just include its declaration in optlib.h. Save this file in the src directory.

Let's walk through this a bit.

First we need to include header files for functions that we'll use throughout the pricing library. These are all part of the C++ standard library with the exception of stats.h which we created above. There are some nuances with some of these files in how OSX handles them. Look around on Stackoverflow if you get stuck.

The next line is extremely important for using C++ with Python. extern "C" { ... } makes a function name in C++ have C linkage so that client C code can use the function using a C compatible header file that contains just the declaration of your function. This is required when using ctypes which we'll be doing later.

The next function simply returns a positive a if b is greater than or equal to 0.0 and a negative a otherwise. This is used in Brent's method.

The next three functions are for valuing call options and are identical for valuing put options. For the sake of brevity, I show only the call options.

This is the Black-Scholes option pricing formula. It is arguably the most basic valuation model and rarely used for actually pricing options to trade. Rather, it is more often used to calculate the sensitivities (greeks) for hedging and of course to compute implied volatility.

black_scholes_call_implied_volatility_brent is the root finding method. It essentially searches between a lower and upper bound for the value that makes the function zero. In our case, we want to search for a value for volatility that sets the model price for the option (e.g. price that the Black-Scholes formula generates) to the observed market price for the option. For this, we need a helper function that returns the difference between the market price and the model price. This is the purpose of black_scholes_call_iv_obj_function. black_scholes_call_implied_volatility_brent will now search between the lower and upper bound for the value of volatility that sets the difference between the market price and the model price to 0.0 (or close to 0.0 defined by a tolerance). This value is the implied volatility.

Next we'll move to stats.cc which is pretty straight forward. Save this file in your src directory.

Next we'll put together a quick Makefile to compile and link our code. There are plenty of Web links at the top of the file to help explain exactly what this does, but essentially it automates the process of compiling and linking the files. Put this file directly under optlib. Note if you named the files or file extensions differently you'll need to modify this file.

Let's create a quick helper file that cleans up a bit. First we remove any .so files that might exist in the bin directory. Then we remove stray object files. Finally, we use the make utility to automagically create our .so file. Save this file in the optlib directory with the Makefile file.

Type the following command:

The following should print to the screen:

If everything went correctly, there should be no errors and you should have optlib.so in your bin directory. This is the file we'll interface with using Python, which I will describe in the next post. Until next time, happy trading.

Leave a Reply