Rolling Option Strategies#

Introduction #

The purpose of this primer is to show the building blocks within the option space that are available on the SigTech platform. All of the building blocks in this notebook are strategies. For more information on how to construct individual options, see Options.

A notebook containing all the code used in this page can be accessed in the research environment: Example Notebooks.

Environment#

Setting up your environment takes three steps:

  • Import the relevant internal and external libraries

  • Configure the environment parameters

  • Initialise the environment

import sigtech.framework as sig
from sigtech.framework.utils.numeric_utils import date_to_datetime
from sigtech.framework.strategies.rolling_options_baskets import RollingOption

from typing import Dict
from uuid import uuid4
import datetime as dtm
import seaborn as sns

sns.set(rc={'figure.figsize': (18, 6)})
sig.config.init()

Learn more: setting up the environment.

The different option strategy building blocks #

The following strategy building blocks for options are available on the platform:

  • Straddle

  • Strangle

  • RollingOption

  • DynamicOptionsStrategy

  • DynamicMultiOptionsStrategy

Where each of them is inheriting from the RollingOptionsStrategyBase class, thus allowing for maintaining exposure via options contracts over time.

Straddle #

A Straddle is a rolling option strategy that takes the same position in both a call option and a put option with the same expiration and strike price.

A long straddle strategy buys both a call option and a put option. This generally profits if the stock price increase or decrease, or if volatility increases. Whereas a short straddle strategy sells both a call option and a put option. This generally profits if the stock price and volatility remain steady.

Python:

start_date = dtm.date(2018, 10, 1)
end_date = dtm.date(2020, 1, 4)

# Create option group
equity_option_group = sig.obj.get('SPX INDEX OTC OPTION GROUP')

# Create strategy
straddle = sig.Straddle(
    currency=sig.obj.get(equity_option_group.underlying).currency,
    start_date=start_date,
    end_date=end_date,
    group_name=equity_option_group.name,
    strike_type='Delta',
    strike=0.5,
    maturity='3M',
    rolling_frequencies=['1M'],
    target_quantity=1.0,
    target_type = 'StrikeNotionalAsProportionOfNAV', # 'SpotNotionalAsProportionOfNAV' and other options also available,
    close_out_at_roll=True,
)

# Query and plot performance
straddle.history().plot();

Output:

Strangle #

Takes the same position in both a call option and a put option with the same expiration but different strike price.

A long strangle strategy buys both a call option and a put option. This strategy generally profits if the stock price increase or decrease, or if volatility increases. On the other hand, a short strangle strategy sells both a call option and a put option. This generally profits if the stock price and volatility remain steady during the life of the options.

Python:

# Create option group
nky_option_group = sig.obj.get('NKY INDEX OTC OPTION GROUP')

# Create strategy
strangle = sig.Strangle(
    currency='USD',
    start_date=start_date,
    end_date=end_date,
    group_name=nky_option_group.name,
    strike_type='SPOT',
    put_strike=-0.05,
    call_strike=0.25,
    maturity='3M',
    rolling_frequencies=['1M']
)

# Query and plot performance
strangle.history().plot();

Output:

Rolling Option#

A RollingOption strategy takes the same position in either a call or put option with the same expiration and strike price and holds it from the start date to the end date defined in the strategy object.

Python:

# Create option group
gbpusd_group = sig.FXOTCOptionsGroup.get_group('GBPUSD')

# Create strategy
rolling_put = RollingOption(
    currency='USD',
    start_date=start_date,
    end_date=end_date,
    group_name=gbpusd_group.name,
    option_type='Put',
    strike_type='SPOT',
    maturity='3M',
    rolling_frequencies=['1M'],
    initial_cash=0
)

# Query and plot performance
rolling_put.history().plot();

Output:

Dynamic Options Strategy #

To trade an arbitrary selection of options in the same group, a DynamicOptionsStrategy is available. This can either take a callback method, which gets called for each rebalance date to determine the options to trade, or a dictionary of trades for each date can be provided. In the example below we use this strategy with a method to trade 10 Put options each month.

In the below example the basket_creation_method function gets passed in to the DynamicOptionsStrategy, then gets called on each roll date and provides a dictionary or tuple of options to trade. The method should take the strategy, decision time and positions as input and provide a dictionary of options.

def basket_creation_method(strategy, dt, positions):
    size_date = strategy.size_date_from_decision_dt(dt)
    return {
        eur_usd_group.get_option(
            option_type='Put',
            strike=sig.obj.get(eur_usd_group.underlying).history().asof(
                date_to_datetime(size_date)),
            start_date=size_date,
            maturity='1M'
        ): 10
    }

Python:

# Create option group
eur_usd_group = sig.FXOTCOptionsGroup.get_group('EURUSD')

# Create strategy
method_strategy = sig.DynamicOptionsStrategy(
    currency=eur_usd_group.over,
    start_date=dtm.date(2010, 1, 6),
    end_date=dtm.date(2012, 1, 20),
    group_name=eur_usd_group.name,
    basket_creation_method=basket_creation_method,
    rolling_frequencies=['1M'],
    ticker=f'ROLLING PUT {str(uuid4())[:4]}',
    initial_cash=0,
)

# Query and plot performance
method_strategy.history().plot();

Output:

Dynamic Multi Options Strategy #

Similar to the dynamic options strategy, use DynamicMultiOptionsStrategy to trade a basket of options. However, this building block allows you to trade options from multiple groups (whereas DynamicMultiOptionsStrategy trades options from within the same group.

When using this building block, you need to use the abstract roll_options method to create the desired behaviour. This is best achieved using a custom function. See the code example below.

# Custom function for the DynamicMultiOptionsStrategy
class ExampleDynamicMultiOptionsStrategy(sig.DynamicMultiOptionsStrategy):
    def roll_options(self, dt):
        size_date = self.size_date_from_decision_dt(dt)

        usdeur = sig.FXOTCOptionsGroup.get_group('USDEUR')
        usdeur_maturity_date = usdeur.convert_maturity_tenor_to_date(size_date, '1M')
        usdeur_atm = usdeur.atm_from_type('Call', size_date,
                                          usdeur_maturity_date, 'DN')
        usdeur_call = usdeur.get_option('Call', usdeur_atm,
                                        size_date, usdeur_maturity_date)

        usdgbp = sig.FXOTCOptionsGroup.get_group('USDGBP')
        usdgbp_maturity_date = usdgbp.convert_maturity_tenor_to_date(size_date, '1M')
        usdgbp_atm = usdgbp.atm_from_type('Call',
                                          size_date, usdgbp_maturity_date, 'DN')
        usdgbp_call = usdgbp.get_option('Call', usdgbp_atm,
                                        size_date, usdgbp_maturity_date)

        self.set_option_positions(dt, ((usdeur_call, 1), (usdgbp_call, 1)))

# Using the custom function in to build the DynamicMultiOptionsStrategy

rs = ExampleDynamicMultiOptionsStrategy(currency='USD',
        start_date=dtm.date(2012, 1, 3),
        end_date=dtm.date(2013, 9, 24),
        group_names=[sig.FXOTCOptionsGroup.get_group('USDEUR').name,
                     sig.FXOTCOptionsGroup.get_group('USDGBP').name],
        target_type='Fixed',
        roll_dates=[dtm.date(2012, 2, 16),
                    dtm.date(2012, 3, 20),
                    dtm.date(2012, 4, 18)],)

#prints the strategy progress
rs.history()

API Documentation#

For more information on the RollingOptionStrategyBase class, see the corresponding API reference.