Finding Expired Options and Backtesting a Short Iron Condor Strategy

Haykaz Aramyan
LSEG Developer Community
6 min readMar 22, 2023

The full article can be found on LSEG’s Developer Portal. It was written by Haykaz Aramyan and Jonathan Legrand.

The Article is utilizing the depth and width of Refinitiv data and APIs, particularly RDP API to access corporate events and option pricing data.

Overview

This article explores how short iron condor strategies can be backtested. The important part of this article is the reconstruction of expired options, which used to be a challenge reported many times in the Developer community Q&A forum. The challenge is that one cannot directly access expired options through a single API call. To get historical data on options, one will need to reconstruct options Refinitiv Identification Codes (RIC) following the logic of RIC construction rules and the rules specified by the exchange where the option is traded.

In this article, we test and visualize the profit/loss of the short Iron Condor strategy with 10% and 20% Out of Money (OTM) sizes for NDX; however one can use the functions and codes of this article to backtest other OPRA exchange-traded indices (such as SPX) and equities (such as IBM, TWTR) at the same time specifying OTM sizes other than 10/20%. Additionally, we considered also the impact of the stock split event on the underlying price and strike price and adjusted the prices accordingly. Finally, we use a function to offset the transactions before expiration based on VIX movements.

Article in Brief

Install and import dependency packages

The article is started by importing required libraries and setting our credentials. Particularly we install refinitiv.dataplatform and import this and other pre-installed dependencies. The code are built using Python 3.9.

Section 1: Reconstruct expired option RICs

In this section we introduce RIC structure for options, including the ones expired. We also provide the data sources, including Refinitiv and exchange specific rules following which we reconstruct the expired option RICs.

Most of the RIC components are constructed via a separate functions introduced below.

1.1 Function for Expiration days

OPRA traded AM settled monthly options expire on the 3rd Friday of each month. Here, we define a function which accepts a year as an input, and returns 3rd Fridays of each month of the year as an output. The function also considers exchange holidays, and if a day is a holiday, the previous day is considered as suggested by the exchange rules.

1.2 Function for Transaction days

Next, we define a function returning a transaction day for each of 12 months. We provide two possible days for conducting option transactions controlled by the function parameter: 1. First business day of each month, 2. Third Friday (which matches with general expiration cycles) of each month. We always open options contract positions to be expiring on the following month of the purchase.

1.3 Function to get adjustment factor of stock split

Corporate events, such as stock split event affect the strike price component of the RIC rule. And since we have a backtesting usecase we need to check for historical non-adjusted prices for a given asset.

To do that, we built a function to check for stock split corporate events for equities and retrieve the adjustment factors. This is further used to adjust underlying prices and strike price of option contracts. The function takes asset RIC, either year or an exact date of the request as input and returns the adjustment factor(s). If no stock split event happened after the expiration date of an option, the function returns adjustment factor(s) of 1, which, in fact, doesn’t change the price values.

1.4 Function to get potential RICs

Finally, we put all functions together to reconstruct expired option RICs. This function calls the functions mentioned above to construct other components of RIC. The function takes the year, transaction day, asset name, OTM size, tolerated difference in OTM size, and option type as an input and returns a dictionary of potential RICs per month. For each month, it produces several RICs, which depend on the parameter of tolerated difference in OTM size. We use tolerated difference in OTM because it is mostly impossible to arrive at a valid strike price with any specified OTM.

The general workflow on how the function works is illustrated in the image below:

1.5 Function to validate potential RICs

Finally, in this section, we check the validity of reconstructed option RICs by requesting historical prices with get_historical_price_summaries function from the RDP API. We wrap this in a function which returns dictionary of valid RICs per month for a specified year.

Section 2: Option transactions and strategy outcome

After we have the list of potential RICs for each month, we trade them by taking long or short positions for a contract every month of a given year. That’s implemented via the following functions:

2.1 Function to open option positions

The trans_option function presented in the main article takes the year, transaction day (“first” or “third”), asset name, potential sorted RICs, option type and position (“short” or “long”) as an input and returns a dataframe consisting of transaction details.

2.2 Function to offset positions

One will not open positions in option trading strategies and wait until expiration to calculate the strategy outcome. Most of the time, traders use offset models, which create triggers for closing the open positions and calculate the outcome as of the position close day. In this article, we base our offset strategy on CBOE Volatility Index (VIX). Particularly, if the3-day MA exceeds the 2 standard deviations of the previous 30 days VIX change at any point after the position is open, we create an offset transaction to short RICs with long positions and long ones with short positions.

That is done via a function named exit_trans which takes the call and put option transactions as an input, and returns a dataframe containing the offset transactions.

2.3 Function to calculate and report the outcome of the strategy

After we have all transactions, we calculate the transaction’s outcome by calculating and summing up profit/loss over all traded options contracts. For that, we define function trans_outcome, which takes option transactions, asset name, and VIX consideration as an input and returns the same option transactions dataframe by adding the outcome details, including contract price, exercise outcome, and total profit/loss per options transaction.

Section 3: Implement and visualize short iron condor strategy outcome

This section implements the short iron condor strategy with 10%/20% legs for options on the NDX index and visualizes the trading outcome:

Although all the backtesting process and the outcome is showcased for NDX, we run the backtesting for SPX, IBM, TWTR and AAPL as well and you are welcome to test the strategy outcome for other OPRA traded equity and index options.

References

Downloads

Related Articles

--

--