Source code for putcall.calibration.hw_calibration

# -*- coding: utf-8 -*-

# putcall
# -------
# Collection of classical option pricing formulas.
# 
# Author:   sonntagsgesicht, based on a fork of Deutsche Postbank [pbrisk]
# Version:  0.2, copyright Wednesday, 18 September 2019
# Website:  https://github.com/sonntagsgesicht/putcall
# License:  Apache License 2.0 (see LICENSE file)


from putcall.formulas import hw_cap_floor_let

EPS = 1e-12


def _frange(start, stop=None, step=None):
    if step is None:
        step = 1.0
    if stop is None:
        stop = start
        start = 0.0
    res = list()
    current = start
    if step > 0.0:
        while current < stop:
            res.append(current)
            current += step
    else:
        while stop < current:
            res.append(current)
            current += step
    return res


def _hw_price_dict(price_dict, mean_reversion, volatility, error_func=None):
    if error_func is None:
        error_func = (lambda x: x * x)
    error = 0.00
    for i in range(len(price_dict['strike'])):
        error += error_func(hw_cap_floor_let(price_dict['forward_values'][i], price_dict['strike'][i], volatility,
                                             price_dict['time_value'][i], price_dict['bool'][i],
                                             price_dict['year_fraction'][i], mean_reversion,
                                             price_dict['discfact'][i]) - price_dict['price'][i])
    return error


[docs]def binary_vol_hw_calibration_cap_floor(price_dict, mean_reversion_start=0.0, mean_reversion_stop=0.01, mean_reversion_step=0.0001, volatility_start=0.0001, volatility_stop=0.01, volatility_step=0.0001): """ Binary search based calibration of the Hull White model using caps and floors :param price_dict: contains prices, time_values, year_fractions,forward values :type price_dict: dictionary :param mean_reversion_start: mean reversion error mean_reversion_start :type mean_reversion_start: real :param mean_reversion_stop: mean reversion error mean_reversion_stop :type mean_reversion_stop: real :param mean_reversion_step: step for the mean reversion optimisation loop :type mean_reversion_step: real :param volatility_start: volatility error mean_reversion_start :type volatility_start: real :param volatility_stop: volatility error mean_reversion_stop :type volatility_stop: real :param volatility_step: step for the volatility optimisation loop :type volatility_step: real :return: optimal mean reversion, optimal volatility, vector of errors :rtype: list(list()) remarks: price_dict is a dictionary s.t.: price_dict['time_value'] contains the year fractions between start date and maturity price_dict['year_fraction'] contains the year fractions between start and maturity price_dict['forward_values'] contains the rate forward values price_dict['price'] price of the lets price_dict['strike'] list of strikes price_dict['bool'] list of booleans (True if call False if put) threshold_vol mean_reversion_stop on the vola mean_reversion_stop is the mean_reversion_stop on the mean revertion """ if not 0.0 <= mean_reversion_start <= mean_reversion_stop and not mean_reversion_step > 0.0: raise AssertionError("Mean reversion either negative or greater expected or negative step.") if not 0.0 <= volatility_start <= volatility_stop and not volatility_step > 0.0: raise AssertionError("Volatility either negative or greater expected or negative step.") last = [None, None, None] for vol in _frange(volatility_start, volatility_stop + volatility_step, volatility_step): res = brute_hw_calibration_cap_floor(price_dict, mean_reversion_start, mean_reversion_stop, mean_reversion_step, vol, vol, volatility_step) if last[2] is None or last[2] > res[2]: last = res else: return last print('Mean reversion calibration of Hull White failed.') return last
[docs]def binary_mr_hw_calibration_cap_floor(price_dict, mean_reversion_start=0.0, mean_reversion_stop=0.01, mean_reversion_step=0.0001, volatility_start=0.0001, volatility_stop=0.01, volatility_step=0.0001): """ Binary search based calibration of the Hull White model using caps and floors :param price_dict: contains prices, time_values, year_fractions,forward values :type price_dict: dictionary :param mean_reversion_start: mean reversion error mean_reversion_start :type mean_reversion_start: real :param mean_reversion_stop: mean reversion error mean_reversion_stop :type mean_reversion_stop: real :param mean_reversion_step: step for the mean reversion optimisation loop :type mean_reversion_step: real :param volatility_start: volatility error mean_reversion_start :type volatility_start: real :param volatility_stop: volatility error mean_reversion_stop :type volatility_stop: real :param volatility_step: step for the volatility optimisation loop :type volatility_step: real :return: optimal mean reversion, optimal volatility, vector of errors :rtype: list(list()) remarks: price_dict is a dictionary s.t.: price_dict['time_value'] contains the year fractions between start date and maturity price_dict['year_fraction'] contains the year fractions between start and maturity price_dict['forward_values'] contains the rate forward values price_dict['price'] price of the lets price_dict['strike'] list of strikes price_dict['bool'] list of booleans (True if call False if put) threshold_vol mean_reversion_stop on the vola mean_reversion_stop is the mean_reversion_stop on the mean revertion """ if not 0.0 <= mean_reversion_start <= mean_reversion_stop and not mean_reversion_step > 0.0: raise AssertionError("Mean reversion either negative or greater expected or negative step.") if not 0.0 <= volatility_start <= volatility_stop and not volatility_step > 0.0: raise AssertionError("Volatility either negative or greater expected or negative step.") last = [None, None, None] for mr in _frange(mean_reversion_start, mean_reversion_stop + mean_reversion_step, mean_reversion_step): res = binary_vol_hw_calibration_cap_floor(price_dict, mr, mr, mean_reversion_step, volatility_start, volatility_stop, volatility_step) if last[2] is None or last[2] > res[2]: last = res else: return last print('Mean reversion calibration of Hull White failed.') return last
[docs]def brute_hw_calibration_cap_floor(price_dict, mean_reversion_start=0.00, mean_reversion_stop=0.01, mean_reversion_step=0.0001, volatility_start=0.0001, volatility_stop=0.01, volatility_step=0.0001, error_func=None): """ Brute force based calibration of the Hull White model using caps and floors :param price_dict: contains prices as a price_dict :type price_dict: dictionary :param mean_reversion_start: mean reversion starting point :type mean_reversion_start: float :param mean_reversion_stop: mean reversion threshold :type mean_reversion_stop: float :param mean_reversion_step: mean reversion step :type mean_reversion_step: float :param volatility_start: volatility starting point :type volatility_start: float :param volatility_stop: volatility reversion threshold :type volatility_stop: float :param volatility_step: volatility reversion step :type volatility_step: float :param error_func: function to aggregate errors :type error_func: function :return: optimal mean reversion, optimal volatility, corresponding error calculates the error for different choices of mean rev and volatility which will make it possible for the user to pick the values for which the error is minimal remarks: price_dict is a dictionary s.t.: price_dict['time_value'] contains the year fractions between start date and maturity price_dict['year_fraction'] contains the year fractions between start and maturity price_dict['forward_values'] contains the rate forward values price_dict['price'] price of the lets price_dict['strike'] list of strikes price_dict['bool'] list of booleans (True if call False if put) threshold_vol threshold on the vola threshold is the threshold on the mean reversion """ if not 0.0 <= mean_reversion_start <= mean_reversion_stop and not mean_reversion_step > 0.0: raise AssertionError("Mean reversion either negative or greater expected or negative step.") if not 0.0 <= volatility_start <= volatility_stop and not volatility_step > 0.0: raise AssertionError("Volatility either negative or greater expected or negative step.") mean_reversion_opt = None volatility_opt = None error_opt = None for mr in _frange(mean_reversion_start, mean_reversion_stop + mean_reversion_step, mean_reversion_step): mr = EPS if mr == 0.00 else mr for vol in _frange(volatility_start, volatility_stop + volatility_step, volatility_step): vol = EPS if vol == 0.00 else vol err = _hw_price_dict(price_dict, mr, vol, error_func) if error_opt is None or error_opt > err: mean_reversion_opt = mr volatility_opt = vol error_opt = err return [mean_reversion_opt, volatility_opt, error_opt]