Swaptions

Introduction

A swaption is an option to enter an interest rate swap at some point in the future, on the swaption expiry date.

There are two types of swaption:

1) Payer swaption 2) Receiver swaption

A payer swaption is an option to enter into a swap as a fixed rate payer. A receiver swaption is an option to enter into a swap as a fixed-rate receiver.

The fixed rate of the swap is determined by the strike of the swaption.

Example: a 3Mx5Y 2% receiver swaption gives the holder the right to enter into a 5 year swap, starting 3 months after the swaption start date, and receiving a 2% fixed rate whilst paying a floating (LIBOR) rate according to the usual currency conventions.

Settlement

A Swaption can be settled in cash, or in a physical swap. The style of the settlement is determined by the swaption currency. All currencies in the SigTech framework assume a physical settlement, with the exception of GBP and EUR.

Previously, cash settlement was calculated as a function of the swap par (forward) rate. As of 26 November 2018, EUR swaptions have been settled at the fair value for standard collateralised EUR swaps and are, as far as valuation is concerned, indistinguishable from physically settled swaptions.

If the swaption survives to the exercise date and is in the money, it is settled physically for USD but in cash for EUR. GBP swaptions continue to use the swap rate based formula.

Modelling & pricing

Swaptions use the normal model. As rates are generally close to zero, and can even be negative, the log-normal assumption used for options is inappropriate.

Some market participants use a shifted log-normal model, where instead of an underlying rate of r, a shifted rate is applied, such as r+2%. Such an approach assumes that the process is log-normal.

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)})

if not sig.config.is_initialised():
    env = sig.init()

SABR

The SABR model is a stochastic volatility model which attempts to capture the volatility smile in derivatives markets. The model is widely used by participants in interest rate derivative markets. The standard approach when interpolating swaption volatilities is to first calibrate the SABR parameters, keeping expiry and swap tenor constant, varying the strikes, and then using them to recover the volatilities.

To price an option with a tenor existing on the (SABR) volatility surface, the normal volatility from parameters is inferred, and is used as a Bachelier (normal) pricer. If the expiry is not part of the surface, the corresponding normal volatilities for neighbouring tenors is found on the surface and linearly interpolate between them.

To view all tenors for a particular currency, the following code block can be used:

single_surface = sig.obj.get('USD SWAPTION SABR VOLSURFACE').get_handle(dtm.date(2021,11,10))
single_surface.market_quotes['Tenor'].squeeze().unique()

The following call will give all the (currency) SABR parameters for a given date:

single_surface.market_quotes

Framework functionality

A Swaption can be constructed directly from sig.Swaption() or by using a group get_swaption() function.

The group itself is easily obtainable via sig.SwaptionGroup.get_group('USD'). Expiry can be passed as a date or as a tenor. Strike can be numerical or offset in basis points from an at-the-money forward.

Note: ATM is the equivalent of forward. 'ATM+25bp' is forward plus 0.0025.

The following command can be used to retrieve the docstrings associated with the swaption class:

sig.Swaption?

To retrieve the SwaptionGroup, the get_group function is used:

usd_swaption_group = sig.SwaptionGroup.get_group('USD')

This group name can then be passed into sig.Swaption() when building your instrument:

s = sig.Swaption(
        start_date=dtm.date(2019, 12, 19),
        strike='ATM+10bp',
        expiry='3M',
        swap_tenor='5Y',
        option_type='Receiver',
        swaption_group=usd_swaption_group.name,
        currency='USD'
    )

The history for our swaption is then tabulated:

s.history()

Spot vs forward premium

All swaptions in the framework are modelled using spot premium as default. Spot premium refers to when payment occurs at the time of entering the contract. This can be contrasted with the forward premium which refers to when payment occurs at the time of exercising the option. A forward premium implies that no initial payment, or spot premium, for the swaption is made.

This can be modelled by setting forward_premium to True, which automatically infers a forward premium from the swaption value. Or, forward_premium can be set to the actual pre-agreed premium, so that it is taken into account when retrieving the resulting swaption’s present value and greeks.

s_fp = sig.Swaption(
        start_date=dtm.date(2019, 12, 19),
        strike='ATM+10bp',
        expiry='3M',
        swap_tenor='5Y',
        option_type='Receiver',
        swaption_group=usd_swaption_group.name,
        currency='USD',
        forward_premium = True
    )

We can then comparatively plot the histories of both swaptions.

s.history().plot()
s_fp.history().plot()

Cash vs physical settlement

The swaption group determines whether the swaption is cash or swap settled. As mentioned above, all swaptions - apart from EUR and GBP - are swap settled. Resetting the cash_settled field of the swaption group resets this behaviour.

It is possible to cash settle EUR swaptions (or any other currency) by setting the cash_settled_with_swap_rate input of the Swaption class to True.

Metrics

The main valuation function is swaption_metrics which computes various metrics for required dates. By default, all history dates are used and if fields are omitted, all current possible metrics—'NPV', 'Delta', 'Gamma', 'Theta', 'Vega', 'ParRate' and 'ImpliedVolatility'—are computed.

s.swaption_metrics()

To plot the time series for a particular metric by specifying a field:

s.swaption_metrics(fields = 'ATMVol').plot()

Greeks

  • Vega is sensitivity to a 1bp change in volatility.

  • Delta is sensitivity to a 1bp change in swap rate.

  • Gamma is change in delta per 1bp change in swap rate.

s.pnl_explain()

To plot the time series for a particular value by specifying a field:

s.pnl_explain(fields='Actual').plot()

Building blocks

Like for options, we support basic functionality for rolling swaptions, straddle and strangle with sig.RollingSwaption, sig.SwaptionStraddle and sig.SwaptionStrangle. The parameters are the same as those used in the corresponding option strategies, with the only differences being that swaption strategies require an underlying swap_tenor and don’t require a group_name—which can be obtained by default from currency.

The functionality for the option strategies—option_position_greeks, portfolio_greeks, output_option_position_diagnostics—is largely the same.

RollingSwaption

from sigtech.framework.strategies.rolling_swaption_baskets import RollingSwaption
usd_rolling_swaption  = RollingSwaption(
    start_date=dtm.date(2016, 3, 5),
    maturity='6M',
    currency='USD',
    group_name=sig.SwaptionGroup.get_group('USD').name,
    rolling_frequencies=["3M"],
    swaption_type='Payer',
    target_type='Fixed',
    target_quantity=1000,
    include_trading_costs=False,
    total_return=False,
    swap_tenor='30Y'
)
usd_rolling_swaption.history().plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f2b02a34390>
usd_rolling_swaption.plot.timeline()
usd_rolling_swaption.option_position_greeks(dtm.datetime(2018,1,5),field = 'Vega')

sig.SwaptionStraddle

usd_rolling_straddle = sig.SwaptionStraddle(
    start_date=dtm.date(2016, 3, 5),
    maturity='6M',
    currency='USD',
    group_name=sig.SwaptionGroup.get_group('USD').name,
    rolling_frequencies=["3M"],
    strike_type='SPOT',
    close_out_at_roll=True,
    include_trading_costs=False,
    total_return=False,
    target_type = 'Fixed',
    target_quantity= 10000,
    swap_tenor='5Y'
)
usd_rolling_straddle.history().plot()
usd_rolling_straddle.portfolio_greeks()

sig.SwaptionStrangle

usd_rolling_strangle = sig.SwaptionStrangle(
    start_date=dtm.date(2016, 3, 5),
    maturity='6M',
    currency='USD',
    group_name=sig.SwaptionGroup.get_group('USD').name,
    rolling_frequencies=["3M"],
    receiver_strike = 'ATM+10bp',
    payer_strike = 'ATM-10bp',
    close_out_at_roll=True,
    include_trading_costs=False,
    total_return=False,
    target_type = 'Fixed',
    target_quantity= 10000,
    swap_tenor='5Y'
)
usd_rolling_strangle.history().plot()

Delta-hedging

Like with strategies inheriting from the rolling_options_basket class, all swaption strategies, including SwaptionStraddle and SwaptionStrangle, can use the DeltaHedgingStrategy as an input with hedging_instrument_type set to 'UNDERLYING'.

If include_option_strategy is set to False it will produce an equivalent strategy obtained by trading the delta amounts of the underlying swap.

If include_option_strategy is set to True it will produce a delta hedge of the original strategy.

sig.DeltaHedgingStrategy?
usd_strangle_dh = sig.DeltaHedgingStrategy(
    currency = 'USD',
    start_date = dtm.date(2016,3,5),
    option_strategy_name = usd_rolling_strangle.name,
    hedging_instrument_type = 'UNDERLYING',
    include_option_strategy = False,
    rebalance_hedge_on_roll= False 
    # you can choose for hedge adjustments to occur only on dates when the options are rolled
)
usd_strangle_dh.history().plot()
usd_strangle_dh.plot.portfolio_table()
usd_strangle_dh.plot.timeline()

Additional building blocks

from sigtech.framework.strategies.rolling_swaption_baskets import *
DynamicSwaptionsStrategy?
DynamicMultiSwaptionsStrategy?

Transaction costs

A vega-based transaction cost is used, with scaling parameters defined in the SWAPTION_VOL_TCOST dictionary of sigtech/framework/transaction_cost/constants.py. There is a default scale of 5 vega basis points, and a currency specific scale of 2bp for USD and EUR (i.e. t-cost is vega*0.0002).

sig.TradePricer.get_tc_model(s.name)

Last updated

© 2023 SIG Technologies Limited