Options#

This page shows how individual options and volatility surfaces work on the platform.

Learn more: 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

import datetime as dtm
import pandas as pd
import seaborn as sns

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

Learn more: Setting up the environment

Vanilla Options#

Overview#

To create a vanilla option on the platform, the user needs to perform the following steps:

1) Get option group#

The available option groups can be viewed in the Market Data Browser. To retrieve an option group the following syntax is used, where the user inserts the relevant option group name:

option_group = sig.obj.get('<Insert Relevant Option Group Name>')

2) Create option#

The option is then retrieved by calling the .get_option() method on the option group object. Below is an example of such script:

option = option_group.get_option(
    option_type='Call',
    strike=1100,
    start_date=dtm.date(2010, 4, 6),
    maturity=dtm.date(2011, 4, 6)
)

If you’re getting an option for a futures group (such as CO COMDTY OTC OPTION GROUP) the maturity date must match an expiration date of one of the futures in the group. To find a valid maturity date that is closest to a given a date, use the following method: option.available_maturity(dtm.date(2011,4,6)).

Example: Index OTC option#

Input:

# Step 1) Getting the option group
equity_option_group = sig.obj.get('SPX INDEX OTC OPTION GROUP')

# Step 2) Creating the option
spx_call_option = equity_option_group.get_option(
    option_type='Call',
    strike=1100,
    start_date=dtm.date(2010, 4, 6),
    maturity=dtm.date(2011, 4, 6)
)
spx_call_option

Output:

SPX 20110406 CALL 1100 604506EC INDEX <class 'sigtech.framework.instruments.options.EquityIndexOTCOption'>[4534898352]

We can also plot the valuation of each option. This is compared below to the underlying minus the strike.

pd.concat({
    'Spot - strike (1100)': spx_call_option.underlying_object.history() - 1100,
    'Option price': spx_call_option.history()
}, axis=1).dropna().plot();

Example: FX OTC option #

# Step 1) Getting the option group
eur_usd_group = sig.FXOTCOptionsGroup.get_group('USDEUR')

# Step 2) Creating the option
eurusd_call_option = eur_usd_group.get_option('Call', 1.3, dtm.date(2010, 4, 6),
                                              dtm.date(2011, 4, 6))
pd.concat({
    'Spot - strike (1.3)': eurusd_call_option.underlying_object.history() - 1.3,
    'Option price': eurusd_call_option.history()
}, axis=1).dropna().plot();

Alternative way of creating options#

Options can also be created explicitly from an option class without using the option group. Some of the option classes available:

  • EquityIndexOTCOption

  • FXOTCOption

  • CommodityFutureOTCOption

Input:

equity_option = sig.EquityIndexOTCOption(
    currency='USD',
    maturity_date=dtm.date(2011, 4, 6),
    option_type='Call',
    start_date=dtm.date(2010, 4, 6),
    strike=1100,
    underlying='SPX INDEX',
)
equity_option

Output:

SPX 20110406 CALL 1100 A6D17D99 INDEX <class 'sigtech.framework.instruments.options.EquityIndexOTCOption'>[5966872832]

Exotic options#

Overview#

When dealing with other options apart from vanilla options, it’s easy to modify the .get_options() method depending on use case. The available exotic options are:

  • Digital

  • Barriers (KO & KI)

  • One-touch & No-touch

Digital #

# Step 2)
digital = eur_usd_group.get_option('Call', 1.3, dtm.date(2010, 4, 6),
                                   dtm.date(2011, 4, 6), digital=True)
pd.concat({
    'Spot - strike (1.3)': digital.underlying_object.history() - 1.3,
    'Option price': digital.history()
}, axis=1).dropna().plot(subplots=True);

Barriers: KO & KI #

ki_barrier_1 = eur_usd_group.get_option('Call', 1.3,
                                        dtm.date(2010, 4, 6), dtm.date(2011, 4, 6),
                                        barrier_type='KI', barrier=1.5)
ki_barrier_2 = eur_usd_group.get_option('Call', 1.3,
                                        dtm.date(2010, 4, 6), dtm.date(2011, 4, 6),
                                        barrier_type='KI', barrier=1.4)
pd.concat({
    'Spot - strike (1.3)': ki_barrier_1.underlying_object.history() - 1.3,
    'Option price (1.4 barr.)': ki_barrier_2.history(),
    'Option price (1.5 barr.)': ki_barrier_1.history()
}, axis=1).dropna().plot(subplots=True);

ko_barrier_1 = eur_usd_group.get_option('Call', 1.3,
                                        dtm.date(2010, 4, 6), dtm.date(2011, 4, 6),
                                        barrier_type='KO', barrier=1.5)
ko_barrier_2 = eur_usd_group.get_option('Call', 1.3,
                                        dtm.date(2010, 4, 6), dtm.date(2011, 4, 6),
                                        barrier_type='KO', barrier=1.4)
pd.concat({
    'Spot - strike (1.3)': ko_barrier_1.underlying_object.history() - 1.3,
    'Option price (1.4 barr.)': ko_barrier_2.history(),
    'Option price (1.5 barr.)': ko_barrier_1.history()
}, axis=1).dropna().plot(subplots=True);

One-touch & no-touch #

ot_barrier = eur_usd_group.get_option('Call', 1.4,
                                      dtm.date(2010, 4, 6), dtm.date(2011, 4, 6),
                                      barrier_type='OT', digital=True)
nt_barrier = eur_usd_group.get_option('Call', 1.4,
                                      dtm.date(2010, 4, 6), dtm.date(2011, 4, 6),
                                      barrier_type='NT', digital=True)
pd.concat({
    'Spot - strike (1.3)': ot_barrier.underlying_object.history() - 1.3,
    'Option price (One-touch 1.4)': ot_barrier.history(),
    'Option price (No-touch 1.4)': nt_barrier.history()
}, axis=1).dropna().plot(subplots=True);

Greeks#

The greeks for each option can be queried in the following way:

equity_option.option_metrics().head()

The vol can be overwritten in the greek calculation. This override can be specified as a float or time series of vols.

equity_option.option_metrics(
    fields=['Delta', 'ImpliedVolatility'], vol_override=0.12).head()

Vol surface #

Retrieve vol surface object #

Input:

vs = sig.obj.get('EURUSD VOLSURFACE')
vs

Output:

EURUSD VOLSURFACE <class 'sigtech.framework.infra.vol_surfaces.vol_surface.FXVolSurface'>[5572896224]
vs.plot_surface(d=vs.history_dates_actual()[-1], z_name='Vol')

get_vol based on the effective date, expiry date and strike.

Input:

vs.get_vol(dtm.date(2019, 3, 29), dtm.date(2019, 4, 28), 1.34)

Output:

0.05693914182317497

Vol surface iterator#

A FXVolSurfaceIterator class is available to simplify the retrieval of a set of volatility surfaces for a selection of currencies and associated data.

Input:

vol_iterator = sig.FXVolSurfaceIterator(['USD', 'EUR', 'GBP'])
list(vol_iterator.iterate_surfaces())

Output:

[EURUSD VOLSURFACE <class 'sigtech.framework.infra.vol_surfaces.vol_surface.FXVolSurface'>[5572896224],
 GBPUSD VOLSURFACE <class 'sigtech.framework.infra.vol_surfaces.vol_surface.FXVolSurface'>[5973002656],
 EURGBP VOLSURFACE <class 'sigtech.framework.infra.vol_surfaces.vol_surface.FXVolSurface'>[5981535392]]

A list of all available surfaces can be generated using the iterator class:

Input:

sig.FXVolSurfaceIterator.get_all_available_surfaces_names()[:5]

Output:

['AUDBRL VOLSURFACE',
 'AUDCAD VOLSURFACE',
 'AUDCHF VOLSURFACE',
 'AUDCNH VOLSURFACE',
 'AUDHKF VOLSURFACE']

Using the FXVolSurfaceIterator instance, you can obtain the historical implied ATM volatilities and risk reversals:

implied_1m_vol_history_df = vol_iterator.atm_vols_for_tenor('1M')
implied_1m_vol_history_df.plot(title='Historical Implied Volatilities');

rr_history_df = vol_iterator.risk_reversal('1M', 25)
rr_history_df.plot(title='Historical Risk Reversal (25 Delta)');

The available tenors can be listed with the get_all_available_tenors method:

Input:

vol_iterator.get_all_available_tenors()[:10]

Output:

['-', 'O/N', 'ON', '1W', '1WK', '2WK', '2W', '3WK', '3W', '1M']