Pricing & Greeks of an American Option

Section contents

In this section, we will introduce the different steps in order to get the present value and sensitivities of an american option through a simple example.

Creating the instrument : American Option

First, one needs to create the american option, which is defined by its type (Call or Put), the exercise strike and the maturity.

The classes relevant to instrument creation are located in the module Products. We will first import the needed classes from there

>>> from Products.AmericanOption import AmericanOption
>>> from Products.OptionType import OptionType

We also need to import date module in order to define the maturity

>>> from Products.AmericanOption import AmericanOption
>>> from Products.OptionType import OptionType
>>> from datetime import date

From there, we can define the different parameters of the american option

>>> from Products.AmericanOption import AmericanOption
>>> from Products.OptionType import OptionType
>>> from datetime import date
>>> maturity = date(2018,1,15)
>>> option_type = OptionType.CALL
>>> strike = 50.0

And finally create the american option object

>>> from Products.AmericanOption import AmericanOption
>>> from Products.OptionType import OptionType
>>> from datetime import date
>>> maturity = date(2018,1,15)
>>> option_type = OptionType.CALL
>>> strike = 50.0
>>> american_option = AmericanOption(strike, option_type, maturity)

Creating the market data

In order to price an american option, we need market data. This section will help you to create a market for pricing purposes.

The classes relative to market data are situated in the module MarketQuotations. First, we will import the needed classes from there

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData

We will also need to import date module in order to define the date of the quotation of the market data

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date

The market data that are relevant to option pricing are : the underlying level, the volatility smile and the rate discount curve. First, we will define the underlying level:

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date
>>> underlying_level = 50.0

Then, we move to the definition of the volatility smile, the relevant classes are situated at the module Smile. For vectorial quantities, we will use numpy arrays. We need therefore the following import

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date
>>> underlying_level = 50.0
>>> import numpy as np

The volatility smile is defined by the At-The-Money implied volatility, and a mapping of deltas to relative volatility shifts (relatively to the At-The-Money volatility). We define it by:

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date
>>> underlying_level = 50.0
>>> import numpy as np
>>> atm_vol = 0.3055
>>> moneyness = np.array([0.05,0.25,0.5,0.75,0.95])
>>> vol_shifts = np.array([0.238, 0.117, 0, -0.110, -0.110])

Now, we move on to the definition of the discount rate curve. It is the curve that for each maturity, defines the discount factor to be applied to flows paid at that maturity in order to get their present value. The module Rates contains classes that provide definitions for this curve. We therefore import the following:

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date
>>> underlying_level = 50.0
>>> import numpy as np
>>> atm_vol = 0.3055
>>> moneyness = np.array([0.05,0.25,0.5,0.75,0.95])
>>> vol_shifts = np.array([0.238, 0.117, 0, -0.110, -0.110])
>>> from Rates.RawDiscountRateCurve import RawDiscountRateCurve
>>> from Rates.RateCurveId import RateCurveId

The class RawDiscountRateCurve describes a non-interpolated discount rate curve : it is identified by a RateCurveId and contains a mapping of durations to discount factors. We build the RawDiscountRateCurve as follows:

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date
>>> underlying_level = 50.0
>>> import numpy as np
>>> atm_vol = 0.3055
>>> moneyness = np.array([0.05,0.25,0.5,0.75,0.95])
>>> vol_shifts = np.array([0.238, 0.117, 0, -0.110, -0.110])
>>> from Rates.RawDiscountRateCurve import RawDiscountRateCurve
>>> from Rates.RateCurveId import RateCurveId
>>> rate_curve_id = RateCurveId("USD-LIBOR")
>>> durations = np.array([1.0,2.0,3.0])
>>> discounts = np.array([0.98,0.87,0.75])
>>> raw_discount_rate_curve = RawDiscountRateCurve(rate_curve_id, durations, discounts)

Having all the ingredients to build the market, we build it as follows:

>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> from datetime import date
>>> underlying_level = 50.0
>>> import numpy as np
>>> atm_vol = 0.3055
>>> moneyness = np.array([0.05,0.25,0.5,0.75,0.95])
>>> vol_shifts = np.array([0.238, 0.117, 0, -0.110, -0.110])
>>> from Rates.RawDiscountRateCurve import RawDiscountRateCurve
>>> from Rates.RateCurveId import RateCurveId
>>> rate_curve_id = RateCurveId("USD-LIBOR")
>>> durations = np.array([1.0,2.0,3.0])
>>> discounts = np.array([0.98,0.87,0.75])
>>> raw_discount_rate_curve = RawDiscountRateCurve(rate_curve_id, durations, discounts)
>>> market_data = MarketData(underlying_level, atm_vol, moneyness, vol_shifts, raw_discount_rate_curve)
>>> value_date = date(2017,5,21)
>>> market = Market(value_date, market_data)

Creating the model

In order to price american options we need to specify a model which will specify how implied volatilities evolve through time. The classes relevant to smile dynamics description are situated in the module Smile.Dynamics. First, we will import the needed classes from there

>>> from Smile.Dynamics.LogLinearVolatilityDynamicsModel import LogLinearVolatilityDynamicsModel

The class LogLinearVolatilityDynamicsModel describes the evolution of the At-The-Money implied volatility by a simple model: \(d\sigma = \kappa d\ln F\). This means that the absolute change in the implied volatility is linearly related to the absolute change of the natural logarithm of the underlying level. The linearity coefficient \(kappa\) is called the steepness parameter. Consequently, the description of the dynamics is obtained by specifying the steepness parameter and the reference underlying level corresponding to the last observed smile on the market.

>>> from Smile.Dynamics.LogLinearVolatilityDynamicsModel import LogLinearVolatilityDynamicsModel
>>> ref_underlying_level = 50.0
>>> steepness = -0.25
>>> vol_dynamics = LogLinearVolatilityDynamicsModel(ref_underlying_level, steepness)

Creating the user configuration

When pricing an option, some parameters need to be passed to the pricer such as the bumps that need to be applied for greeks computation, or the numerical parameters of the pricing algorithm. The classes relevant to user configuration are located in the module Configurations.Configurations. First, we will import the needed classes from there:

>>> from Configurations import Configurations

For ease of use, default parameters are defined in the Configurations module, which we can call using these lines of code:

>>> from Configurations import Configurations
>>> pricing_parameters = Configurations.Pricing.DEFAULT_PRICING_PARAMETERS
>>> greeks_definition = Configurations.Greeks.DEFAULT_GREEKS_DEFINITION

The object Configurations.Pricing.DEFAULT_PRICING_PARAMETERS contains the numerical paramters to be passed to the pricer. Those parameters determine the accuracy and the performance of the pricing algorithm. The object Configurations.Greeks.DEFAULT_GREEKS_DEFINITION contains the definition of the bumps to be performed on market data when calculating greeks by finite differences.

Running a price & greeks

In order to run a price and greeks, the four previously presented elements (product, market data, model and configuration) should be passed to a runner situated in the module Greeks.Runners. To import it, one should add the following lines

>>> from Greeks.Runners.GreeksRunner import GreeksRunner

Utilizing the different steps presented previously, one gets the following script

>>> #Creating the product
>>> from Products.AmericanOption import AmericanOption
>>> from Products.OptionType import OptionType
>>> from datetime import date
>>> maturity = date(2018,1,15)
>>> option_type = OptionType.CALL
>>> strike = 50.0
>>> american_option = AmericanOption(strike, option_type, maturity)
>>>
>>> #Creating the market data
>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> underlying_level = 50.0
>>> import numpy as np
>>> atm_vol = 0.3055
>>> moneyness = np.array([0.05,0.25,0.5,0.75,0.95])
>>> vol_shifts = np.array([0.238, 0.117, 0, -0.110, -0.110])
>>> from Rates.RawDiscountRateCurve import RawDiscountRateCurve
>>> from Rates.RateCurveId import RateCurveId
>>> rate_curve_id = RateCurveId("USD-LIBOR")
>>> durations = np.array([1.0,2.0,3.0])
>>> discounts = np.array([0.98,0.87,0.75])
>>> raw_discount_rate_curve = RawDiscountRateCurve(rate_curve_id, durations, discounts)
>>> market_data = MarketData(underlying_level, atm_vol, moneyness, vol_shifts, raw_discount_rate_curve)
>>> value_date = date(2017,5,21)
>>> market = Market(value_date, market_data)
>>>
>>> #Creating the model
>>> from Smile.Dynamics.LogLinearVolatilityDynamicsModel import LogLinearVolatilityDynamicsModel
>>> ref_underlying_level = 50.0
>>> steepness = -0.25
>>> vol_dynamics = LogLinearVolatilityDynamicsModel(ref_underlying_level, steepness)
>>>
>>> #Creating the configuration
>>> from Configurations import Configurations
>>> pricing_parameters = Configurations.Pricing.DEFAULT_PRICING_PARAMETERS
>>> greeks_definition = Configurations.Greeks.DEFAULT_GREEKS_DEFINITION
>>>
>>> #Creating the runner
>>> from Greeks.Runners.GreeksRunner import GreeksRunner
>>> greeks_runner = GreeksRunner(pricing_parameters, greeks_definition)
>>> greeks_result = greeks_runner.run(market, vol_dynamics, american_option)

The object greeks_result is a dictionary mapping a result key into a number (price, delta, gamma, etc...). In order to display the results, move on to the next section.

Formatting Results

In order to format greeks results, a class is provided in the module Greeks.Runners which one can import as follows:

>>> from Greeks.Formatters.ResultsFormatter import ResultsFormatter

The formatter converts the dictionary of results into a string that can be printed in order to display the results in a readable way. We complete the previous script with the following lines

>>> #Creating the product
>>> from Products.AmericanOption import AmericanOption
>>> from Products.OptionType import OptionType
>>> from datetime import date
>>> maturity = date(2018,1,15)
>>> option_type = OptionType.CALL
>>> strike = 50.0
>>> american_option = AmericanOption(strike, option_type, maturity)
>>>
>>> #Creating the market data
>>> from MarketQuotations.Market import Market
>>> from MarketQuotations.MarketData import MarketData
>>> underlying_level = 50.0
>>> import numpy as np
>>> atm_vol = 0.3055
>>> moneyness = np.array([0.05,0.25,0.5,0.75,0.95])
>>> vol_shifts = np.array([0.238, 0.117, 0, -0.110, -0.110])
>>> from Rates.RawDiscountRateCurve import RawDiscountRateCurve
>>> from Rates.RateCurveId import RateCurveId
>>> rate_curve_id = RateCurveId("USD-LIBOR")
>>> durations = np.array([1.0,2.0,3.0])
>>> discounts = np.array([0.98,0.87,0.75])
>>> raw_discount_rate_curve = RawDiscountRateCurve(rate_curve_id, durations, discounts)
>>> market_data = MarketData(underlying_level, atm_vol, moneyness, vol_shifts, raw_discount_rate_curve)
>>> value_date = date(2017,5,21)
>>> market = Market(value_date, market_data)
>>>
>>> #Creating the model
>>> from Smile.Dynamics.LogLinearVolatilityDynamicsModel import LogLinearVolatilityDynamicsModel
>>> ref_underlying_level = 50.0
>>> steepness = -0.25
>>> vol_dynamics = LogLinearVolatilityDynamicsModel(ref_underlying_level, steepness)
>>>
>>> #Creating the configuration
>>> from Configurations import Configurations
>>> pricing_parameters = Configurations.Pricing.DEFAULT_PRICING_PARAMETERS
>>> greeks_definition = Configurations.Greeks.DEFAULT_GREEKS_DEFINITION
>>>
>>> #Creating the runner
>>> from Greeks.Runners.GreeksRunner import GreeksRunner
>>> greeks_runner = GreeksRunner(pricing_parameters, greeks_definition)
>>> greeks_result = greeks_runner.run(market, vol_dynamics, american_option)
>>>
>>> #Formatting the results
>>> results_formatter = ResultsFormatter()
>>> print(results_formatter.format(greeks_result))
F: 50.0
ATM: 0.3055
Option Vol: 0.3055
PV: 4.9246867528
Delta: 0.544915595657
Gamma: 0.0292956471848
Vega: 0.160383273209
Theta: -0.00983808889416
Vanna: 0.00153128975639
Volga: -7.993002591e-05
5P: 0.0
25P: 0.0
25C: 0.0
5C: 0.0