From cdcdaf6d255b39ed938543a6abfe5e23b295479d Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Mon, 24 Feb 2020 10:58:19 +0100 Subject: [PATCH 1/8] initial commit --- tf_quant_finance/volatility/bachelier_tf.py | 248 ++++++++++++++ .../volatility/sabr_approx_hagan_tf_test.py | 150 +++++++++ tf_quant_finance/volatility/sabr_approx_tf.py | 304 ++++++++++++++++++ .../volatility/volbachelier_tf.py | 174 ++++++++++ 4 files changed, 876 insertions(+) create mode 100644 tf_quant_finance/volatility/bachelier_tf.py create mode 100644 tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py create mode 100644 tf_quant_finance/volatility/sabr_approx_tf.py create mode 100644 tf_quant_finance/volatility/volbachelier_tf.py diff --git a/tf_quant_finance/volatility/bachelier_tf.py b/tf_quant_finance/volatility/bachelier_tf.py new file mode 100644 index 000000000..303804ca8 --- /dev/null +++ b/tf_quant_finance/volatility/bachelier_tf.py @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- +""" +"" +Created on Fri Nov 22 15:22:13 2019 + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import tensorflow as tf +import tensorflow_probability as tfp + +# straight fwd implementation of the Bachelier pricing +# there is a version with just one call to exp !! + + +def option_price(spots, + strikes, + volatilities, + expiries, + rates, + is_call_options=None, + dtype = None, + name = None): + """ Compute the Bachelier price for a batch of European options. + + ## References: + [1] Kienitz, J. "Interest Rate Derivatives Explained I", Plagrave McMillan (2014) p.119 + [2] https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428994 + + Parameters + ---------- + spots : A real `Tensor` of any shape. The current spot prices to + expiry. + strikes : A real `Tensor` of the same shape and dtype as `spots`. The + strikes of the options to be priced. + volatilities : A real `Tensor` of same shape and dtype as `spots`. The + volatility to expiry. + expiries : A real `Tensor` of same shape and dtype as `spots`. The expiry + for each option. The units should be such that `expiry * volatility**2` is + dimensionless. + rates : A real `Tensor` of the same shape and dtype as `spots`. The + rates of the options to be priced. + is_call_options: A boolean `Tensor` of a shape compatible with `forwards`. + Indicates whether to compute the price of a call (if True) or a put (if + False). If not supplied, it is assumed that every element is a call. + dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion + of any supplied non-`Tensor` arguments to `Tensor`. + Default value: None which maps to the default dtype inferred by TensorFlow + (float32). + name: str. The name for the ops created by this function. + Default value: None which is mapped to the default name `option_price`. + + Returns + ------- + option_prices: A `Tensor` of the same shape as `spots`. The Bachelier + price of the options. + + #### Examples + ```python + spots = np.array([0.03, 0.02]) + strikes = np.array([.02, .02]) + volatilities = np.array([.004, .005]) + expiries = 2.0 + rates = [0.02, 0.01] + computed_prices = option_price( + spots, + strikes, + volatilities, + expiries, + rates, + dtype=tf.float64) + # Expected print output of computed prices: + # + ``` + + """ + with tf.compat.v1.name_scope( + name, + default_name='option_price', + values=[ + spots, strikes, volatilities, expiries, rates, + is_call_options + ]): + + spots = tf.convert_to_tensor(spots, dtype=tf.float64, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + volatilities = tf.convert_to_tensor(volatilities, tf.float64, name='volatilities') + expiries = tf.convert_to_tensor(expiries, tf.float64, name='expiries') + rates = tf.convert_to_tensor(rates, tf.float64, name='rates') + + z = tf.zeros_like(strikes) + + normal = tfp.distributions.Normal( + loc=tf.zeros([], dtype=spots.dtype), scale=1) + + df = tf.math.exp(-rates*expiries) + vt = volatilities * tf.math.sqrt(expiries) + + z = tf.where(rates == 0., (spots - strikes)/vt, + (spots-strikes*df)/(volatilities + * tf.math.sqrt(0.5*(1.-tf.math.exp(-2.*rates*expiries))/rates))) + + n1 = normal.cdf(z) + n2 = normal.prob(z) + calls = tf.where(rates==0., (spots - strikes) * n1 + vt * n2, + (spots - strikes*df)*n1 + + volatilities*tf.math.sqrt(0.5*(1-tf.math.exp(-2*rates*expiries))/rates)) + + + if is_call_options is None: + return calls + + puts = calls - spots + strikes * tf.math.exp(-rates*expiries) + + return tf.where(is_call_options, calls, puts) + + + +def option_price_dawson_tf(forwards, + strikes, + volatilities, + expiries, + discount_factors = None, + is_call_options=None, + dtype = None, + name = None): + + """Computes the Black Scholes price for a batch of European options. + + ## References: + [1] Dawson, P., Blake, D., Cairns, A. J. G. and Dowd, K.: Options on normal under- + lyings, CRIS Discussion Paper Series – 2007.VII, 2007. + + Args: + forwards: A real `Tensor` of any shape. The current forward prices to + expiry. + strikes: A real `Tensor` of the same shape and dtype as `forwards`. The + strikes of the options to be priced. + volatilities: A real `Tensor` of same shape and dtype as `forwards`. The + volatility to expiry. + expiries: A real `Tensor` of same shape and dtype as `forwards`. The expiry + for each option. The units should be such that `expiry * volatility**2` is + dimensionless. + discount_factors: A real `Tensor` of same shape and dtype as the `forwards`. + The discount factors to expiry (i.e. e^(-rT)). If not specified, no + discounting is applied (i.e. the undiscounted option price is returned). + Default value: None, interpreted as discount factors = 1. + is_call_options: A boolean `Tensor` of a shape compatible with `forwards`. + Indicates whether to compute the price of a call (if True) or a put (if + False). If not supplied, it is assumed that every element is a call. + dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion + of any supplied non-`Tensor` arguments to `Tensor`. + Default value: None which maps to the default dtype inferred by TensorFlow + (float32). + name: str. The name for the ops created by this function. + Default value: None which is mapped to the default name `option_price`. + + Returns: + option_prices: A `Tensor` of the same shape as `forwards`. The Bachelier + price of the options. + + + #### Examples + ```python + spots = np.array([0.03, 0.02]) + strikes = np.array([.02, .02]) + volatilities = np.array([.004, .005]) + expiries = 2.0 + expiries = 1.0 + computed_prices = option_price( + forwards, + strikes, + volatilities, + expiries, + dtype=tf.float64) + # Expected print output of computed prices: + # + ``` + """ + with tf.compat.v1.name_scope( + name, + default_name='option_price_dawson', + values=[ + forwards, strikes, volatilities, expiries, discount_factors, + is_call_options + ]): + + forwards = tf.convert_to_tensor(forwards, dtype=None, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=None, name='strikes') + volatilities = tf.convert_to_tensor(volatilities, dtype=None, name='volatilities') + expiries = tf.convert_to_tensor(expiries, dtype=None, name='expiries') + + if discount_factors is None: + discount_factors = 1. + discount_factors = tf.convert_to_tensor( + discount_factors, dtype=dtype, name='discount_factors') + + vt = volatilities * tf.math.sqrt(expiries) + normal = tfp.distributions.Normal( + loc=tf.zeros([], dtype=forwards.dtype), scale=1) + + z = (forwards - strikes) / vt + + n1 = normal.cdf(z) + n2 = normal.prob(z) + undiscounted_calls = (forwards-strikes) * n1 + vt * n2 + + if is_call_options is None: + return discount_factors * undiscounted_calls + undiscounted_forward = forwards - strikes + undiscounted_puts = undiscounted_calls - undiscounted_forward + + return discount_factors * tf.where(is_call_options, undiscounted_calls, + undiscounted_puts) + + + \ No newline at end of file diff --git a/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py new file mode 100644 index 000000000..c73e171eb --- /dev/null +++ b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +""" + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz +""" + +import sabr_approx_tf as sabr +import bachelier_tf as vptf +import volbachelier_tf as bvtf + +import numpy as np +import matplotlib.pyplot as plt + +# SABR parameters +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.2632859 +rho_org = -0.32978014 +T = 5 + +displacement_org = 0. #0.005 +kmin = -displacement_org +kmax = 10 +kval = np.arange(kmin, kmax, 0.01) +kval[0] = (kval[0] + kval[1])/2 +vol = np.zeros(len(kval)) + +alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] +displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] + +print('alpha varies') +for alpha in alpha_vec: + print('alpha: ', alpha) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha, beta_org, rho_org,nu_org) + cval = vptf.option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(alpha) + label2 = 'iv ' + str(alpha) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('alpha varies') +plt.legend() +plt.show() + + +print('beta varies') +for beta in beta_vec: + print('parameters: ', beta) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta, rho_org,nu_org) + cval = vptf.option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(beta) + label2 = 'iv ' + str(beta) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('beta varies') +plt.legend() +plt.show() + +print('rho varies') +for rho in rho_vec: + print('parameters: ', rho) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho,nu_org) + cval = vptf.option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(rho) + label2 = 'iv ' + str(rho) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('rho varies') +plt.legend() +plt.show() + +print('nu varies') +for nu in nu_vec: + print('parameters: ', nu) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu) + cval = vptf.option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(nu) + label2 = 'iv ' + str(nu) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('nu varies') +plt.legend() +plt.show() + +print('displacement varies') +for displacement in displacement_vec: + print('parameters: ', displacement) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) + label1 = 'approx ' + str(displacement) + plt.plot(kval,yval,label= label1) +plt.title('displacement varies') +plt.legend() +plt.show() + +# different approximation techniques for SABR and Mean Reverting SABR +kappa = 0.5 +cap = 3. + +yval1 = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) +yval2 = sabr.volsabr_mr_n_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, kappa) +yval3 = sabr.volsabr_h_n_cap_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, cap) + +label1 = 'Hagan approx ' +label2 = 'MR SABR approx ' +label3 = 'Capped SABR approx ' + +plt.plot(kval,yval1,label= label1) +plt.plot(kval,yval2,label= label2) +plt.plot(kval,yval3,label= label3) +plt.title('different SABR approximation') +plt.legend() +plt.show() + + + diff --git a/tf_quant_finance/volatility/sabr_approx_tf.py b/tf_quant_finance/volatility/sabr_approx_tf.py new file mode 100644 index 000000000..1c370fee1 --- /dev/null +++ b/tf_quant_finance/volatility/sabr_approx_tf.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- +""" +"" +Created on Fri Nov 22 15:22:13 2019 + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import tensorflow as tf + +# straight fwd implementation of the Bachelier pricing +# there is a version with just one call to exp !! + +def volsabr_h_n_tf( + forwards, + strikes, + expiries, + displacements, + alpha, + beta, + rho, + nu, + name = None): + """ + Standard Hagan SABR approximation for the Bachelier/Normal volatility + + parameters: + forwards - forward rate + strikes - strike as array + expiries - maturity + displacements - displacement + alpha - SABR parameter (initial vol) + beta - SABR parameter (CEV coefficient) + rho - SABR parameter (correlation) + nu - SABR parameter (vol of vol) + + For SABR we can always use f=1 and apply the scaling: + + if f = f0 + knew -> k/f + alphanew -> f**(beta-1) * alpha + ivol1 = sabrapprox.volsabr_h_n(f, kval, T, displacement, alpha, beta, rho, nu) + price1 = vp.vanilla_n(f,kval,implVolApprox1,0,0,T,1) + + ivol2 = f * sabrapprox.volsabr_h_n(1, knew, T, displacement, alphanew, beta, rho, nu) + ivol3 = sabrapprox.volsabr_h_n(1, knew, T, displacement, alphanew, beta, rho, nu) + price2 = vp.vanilla_n(f,kval,ivol2,0,0,T,1) + price3 = f * vp.vanilla_n(1,kvalnew,ivol3,0,0,T,1) + + price1 = price2 = price3 + ivol1 = ivol2 = f * ivol3 + """ + with tf.compat.v1.name_scope( + name, + default_name='sabr_implied_vol_hagan', + values=[ + forwards, strikes, expiries, displacements, alpha, beta, rho, nu + ]): + # conversion maybe outside function!!!! + forwards = tf.convert_to_tensor(forwards, dtype=tf.float64, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + expiries = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') + displacements = tf.convert_to_tensor(displacements, dtype=tf.float64, name='displacement') + alpha = tf.convert_to_tensor(alpha, dtype=tf.float64, name='alpha') + beta = tf.convert_to_tensor(beta, dtype=tf.float64, name='beta') + rho = tf.convert_to_tensor(rho, dtype=tf.float64, name='rho') + nu = tf.convert_to_tensor(nu, dtype=tf.float64, name='nu') + + + # identify ATM and non ATM strikes + eps = tf.constant(1.0e-06, dtype = tf.float64) # small number + index_natm = (tf.math.abs(forwards-strikes) > eps) # itm/otm strikes + + # case rho = 1 may cause divide by zero problems + # case rho = 1 may cause divide by zero problems + # for rho == 1 + # xik = log(2) * log(x+1) -> x > -1 + # for rho == -1 + # xik = log(2) * log(x-1) -> x > 1 + # this means only certain strikes are feasible for calculating implied vols! + # to this end we only consider the SABR model for correlation values + # between rho = -0.99 and rho = 0.99 + rho = tf.where(rho == 1., 0.999,tf.where(rho == -1., -0.999, rho)) + + betam = tf.constant(1.0 - beta) # often used + + fa = forwards+displacements # account for displacement for forward + ka = strikes+displacements # account for displacement for strikes + + # different cases due to normal, cev, log-normal + if 0. < beta and beta < 1.: # case of true CEV SABR + gk = tf.zeros_like(strikes) + gk = tf.where(index_natm,(beta**2 -2.*beta)/24. + * fa**(-betam)*ka**(-betam)*alpha**2, gk) + xik = nu / alpha * (fa**betam - ka**betam) / betam + xxik = tf.math.log((tf.math.sqrt(1.0- 2.0 * rho * xik + xik**2) - rho + xik) + / (1 - rho))/nu + vol = tf.where(index_natm, + (fa - ka) / xxik * (1. + (gk + 0.25 * rho * nu * alpha * beta * fa**(0.5*(beta-1.))*ka**(0.5*(beta-1.)) + + (2. - 3. * rho**2) / 24 * nu**2) * expiries), + alpha * fa**beta * (1 + (beta*(beta-2.) * alpha**2 / 24. / fa**(2.*betam) + + 0.25 * rho*nu*alpha*beta / fa**(betam) + + (2.-3.*rho**2)/24. * nu**2)*expiries) ) + return vol + + elif beta == 0.: # case of a Gaussian SV model (normal SABR) + xik = nu / alpha * (fa - ka) + xxik = tf.math.log((tf.math.sqrt(1.0- 2.0 * rho * xik + xik**2) - rho + xik) / (1-rho)) + vol = tf.where(index_natm, alpha * xik / xxik * (1 + (1 / 24 * (2 - 3 * rho**2) * nu ** 2) * expiries), + alpha * (1+ (2.-3.*rho**2)/24.*nu**2*expiries)) + return vol + + else: # case of log-normal SV model (log-normal SABR) + gk = - 1. / 24. * alpha**2 + xik = nu / alpha * tf.math.log(fa / ka) + sum2 = 0.25 * rho * nu * alpha + xxik = tf.math.log((tf.math.sqrt(1.0- 2.0 * rho * xik + xik**2) - rho + xik) + / (1. - rho))/nu + vol = tf.where(index_natm, + (fa - ka) / xxik * (1 + (gk + sum2 + 1. / 24. * (2. - 3.*rho**2) * nu**2) * expiries), + alpha * fa * (1.+ (gk + sum2 + (2.-3.*rho**2)/24.*nu**2)*expiries)) + return vol + + +def volsabr_mr_n_tf(forwards, strikes, expiries, displacements, alpha, beta, rho, nu, kappa, name = None): + """ + ' f is the forward + ' k is the strike + ' t is maturity + ' a is displacement + ' alpha is ATM vol -> sigma in Hagan paper + ' beta is cev coefficient + ' rho is correlation + ' nu is vol of vol + ' kappa is mean reversion + """ + with tf.compat.v1.name_scope( + name, + default_name='sabr_implied_vol_hagan', + values=[ + forwards, strikes, expiries, displacements, alpha, beta, rho, nu + ]): + # conversion maybe outside function!!!! + forwards = tf.convert_to_tensor(forwards, dtype=tf.float64, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + expiries = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') + displacements = tf.convert_to_tensor(displacements, dtype=tf.float64, name='displacement') + alpha = tf.convert_to_tensor(alpha, dtype=tf.float64, name='alpha') + beta = tf.convert_to_tensor(beta, dtype=tf.float64, name='beta') + rho = tf.convert_to_tensor(rho, dtype=tf.float64, name='rho') + nu = tf.convert_to_tensor(nu, dtype=tf.float64, name='nu') + kappa = tf.convert_to_tensor(kappa, dtype=tf.float64, name='kappa') + + + if kappa > 0.: + bbar = 2. * rho * nu / alpha * (kappa * expiries - 1. + + tf.math.exp(-kappa * expiries)) / (kappa ** 2 * expiries ** 2) + cbar = 1.5 * nu ** 2 / alpha ** 2. * (1. + rho ** 2) * (1. + 2. * kappa * expiries - (2. - tf.math.exp(-kappa * expiries)) ** 2) \ + / (kappa ** 3 * expiries ** 3) + 12. * rho ** 2 * nu ** 2 / alpha ** 2 * (kappa ** 2 * expiries ** 2 * tf.math.exp(-kappa * expiries) + - (1. - tf.math.exp(-kappa * expiries)) ** 2) / (kappa ** 4 * expiries ** 4) + Gstar = (-0.5 * cbar + nu ** 2 / alpha ** 2 * (2. * kappa * expiries - 1. + tf.math.exp(-2. * kappa * expiries)) \ + / (4. * kappa ** 2 * expiries ** 2)) * alpha ** 2 * expiries + + # std case + astd = alpha * tf.math.exp(0.5 * Gstar) + rhostd = bbar / tf.math.sqrt(cbar) + nustd = alpha * tf.math.sqrt(cbar) + + return volsabr_h_n_tf(forwards, strikes, expiries, displacements, astd, beta, rhostd, nustd) + else: + return volsabr_h_n_tf(forwards, strikes, expiries, displacements, alpha, beta, rho, nu) + + +def volsabr_h_n_cap_tf( + forwards, + strikes, + expiries, + displacements, + alpha, + beta, + rho, + nu, + cap, + name = None): + + with tf.compat.v1.name_scope( + name, + default_name='sabr_implied_vol_hagan', + values=[ + forwards, strikes, expiries, displacements, alpha, beta, rho, nu + ]): + # conversion maybe outside function!!!! + forwards = tf.convert_to_tensor(forwards, dtype=tf.float64, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + expiries = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') + displacements = tf.convert_to_tensor(displacements, dtype=tf.float64, name='displacement') + alpha = tf.convert_to_tensor(alpha, dtype=tf.float64, name='alpha') + beta = tf.convert_to_tensor(beta, dtype=tf.float64, name='beta') + rho = tf.convert_to_tensor(rho, dtype=tf.float64, name='rho') + nu = tf.convert_to_tensor(nu, dtype=tf.float64, name='nu') + cap = tf.convert_to_tensor(cap, dtype=tf.float64, name='cap') + + eps = 1.0e-06 + index_atm = tf.math.abs(forwards - strikes) < eps + + vol = tf.zeros_like(strikes) + fa = forwards + displacements + ka = strikes + displacements + + betam = 1. - beta + # atm but different cases due to normal, cev, log-normal + if 0. < beta and beta < 1.: # case of true CEV SABR + volatm = alpha * fa**beta * (1 + (beta*(beta-2.) * alpha**2 / 24. / fa**(2.*betam) + + 0.25 * rho*nu*alpha*beta / fa**(betam) + + (2.-3.*rho**2)/24. * nu**2)*expiries) + + elif beta == 0.: # case of a Gaussian SV model (normal SABR) + volatm = alpha * (1. + (2.-3.*rho**2)/24.*nu**2*expiries) + else: # case of log-normal SV model (log-normal SABR) + volatm = alpha * fa * (1.+ (-1. / 24. * alpha**2 + 0.25 * rho * nu * alpha + (2.-3.*rho**2)/24.*nu**2)*expiries) + + + if beta == 1: + beta = 0.999 + + rho = tf.where(rho == 1, 0.999, tf.where(rho == -1, -0.999,rho)) + + # the cap can only be applied if the term under sqrt is positive + term = tf.math.sqrt(tf.math.maximum(cap ** 2 - 1. + rho**2,0.)) + + xip = -rho + term + xim = -rho - term + + Yp = -tf.math.log((cap - term) / (1. - rho)) + Ym = -tf.math.log((cap + term) / (1. - rho)) + + # here we need ATM consideration + ic = ((ka) ** (1. - beta) - (fa) ** (1. - beta)) / (1. - beta) + + f0 = 0.5 * ((forwards + strikes) + displacements) # 2* displace? + + gamma = beta * f0 ** (beta-1.) + + Delta0 = (beta ** 2 - 2. * beta) * f0 ** (2. * beta-2) + + xi = nu / alpha * ic + + Yxi = tf.where(xi > xip, + Yp + (xi - xip)/cap, + tf.where(xi < xim, + Ym + (xi -xim)/cap, + -tf.math.log((tf.math.sqrt(1. + 2. * rho * xi + xi ** 2) - rho - xi) / (1 - rho)) + ) + ) + + sK0 = tf.where(xi > xip, + nu ** 2 / (8. * alpha ** 2 * Yxi) * (-Yp + 3. * (-rho * cap + term) / cap) \ + + Delta0 / (16. * Yxi) * (2. * cap ** 2 * (Yxi - Yp) + (1 - rho ** 2) * Yp + cap * term - rho), + tf.where(xi < xim, + nu ** 2 / (8 * alpha ** 2 * Yxi) * (-Ym - 3 * (rho * cap + term) / cap) + Delta0 / (16. * Yxi) * (2 * cap ** 2 * (Yxi - Ym) + (1 - rho ** 2) * Ym - cap * term - rho), + nu ** 2 / (8. * alpha ** 2 * Yxi) * (-Yxi + 3 * (xi + rho - rho * tf.math.sqrt(1 + 2 * rho * xi + xi ** 2)) / tf.math.sqrt(1 + 2 * rho * xi + xi ** 2)) \ + + Delta0 / (16. * Yxi) * ((1 - rho ** 2) * Yxi + (xi + rho) * tf.math.sqrt(1 + 2 * rho * xi + xi ** 2) - rho) + ) + ) + + theta = -0.5 * rho * nu * alpha * gamma - 2. / 3. * alpha ** 2 * sK0 + highorder = tf.where(theta <0., + tf.math.sqrt(1. - theta * expiries), + 1. / tf.math.sqrt(1. + theta * expiries) + ) + vol = tf.where(index_atm, volatm, nu * (strikes - forwards) / Yxi * highorder) + return vol + \ No newline at end of file diff --git a/tf_quant_finance/volatility/volbachelier_tf.py b/tf_quant_finance/volatility/volbachelier_tf.py new file mode 100644 index 000000000..bf1d30c05 --- /dev/null +++ b/tf_quant_finance/volatility/volbachelier_tf.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +""" + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz + + + + # aLFK4 = [0.06155371425063157, 2.723711658728403, 10.83806891491789, 301.0827907126612 , 1082.864564205999 , 790.7079667603721 , 109.330638190985 , 0.1515726686825187 , 1.436062756519326 , 118.6674859663193 , 441.1914221318738 , 313.4771127147156 , 40.90187645954703]; + # c0=0.6409168551974356; + # c1=776.7622553541449; d1=640.570978803313; + # c2=431496.7672664836; d2=206873.1616020722; + # c3=142810081.2530825; d3=40411807.74439474; + # c4=30593703611.75923; d4=5007804896.265911; + # c5=4296256150040.825; d5=379858284395.2218; + # c6=377808909050483.9; d6=15253797078346.91; + # c7=1.799539603508817e+16; d7=211469320780659.9; + # c8=2.864267851212242e+17; + # c9=1.505975341130321e+16; + + # e0=0.6421698396894946; + # e1=639.0799338046976; f1=428.4860093838116; + # e2=278070.4504753253; f2=86806.89002606465; + # e3=64309618.34521588; f3=8635134.393384729; + # e4=8434470508.516712; f4=368872214.1525768; + # e5=429163238246.6056; f5=6359299149.626331; + # e6=8127970878235.127; f6=39926015967.88848; + # e7=53601225394979.81; f7=67434966969.06365; + # e8=92738918006503.35; + # e9=54928597545.97237; + + # g0=0.9419766804760195; + # g1=319.5904313022832; h1=170.3825619167351; + # g2=169280.1584005307; h2=6344.159541465554; + # g3=7680298.116948191; h3=78484.04408022196; + # g4=102052455.1237945; h4=370696.1131305614; + # g5=497528976.6077898; h5=682908.5433659635; + # g6=930641173.0039455; h6=451067.0450625782; + # g7=619268950.1849232; h7=79179.06152239779; + # g8=109068992.0230439; + # g9=672.856898188759; + + # bLFK4 = [c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, d1, d2, d3, d4, d5, d6, d7] + # cLFK4 = [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, f1, f2, f3, f4, f5, f6, f7] + # dLFK4 = [g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, h1, h2, h3, h4, h5, h6, h7] + + +""" +import math as m +import tensorflow as tf + +def func1(t,x,z,betaStart,betaEnd,cut_off2,cut_off3,bLFK4,cLFK4,dLFK4): + u = -(tf.math.log(z)+ betaStart) /(betaEnd - betaStart) + + num = tf.where(u < cut_off2, + bLFK4[0] + u *(bLFK4[1] +u *(bLFK4[2] +u *(bLFK4[3] + u *(bLFK4[4] +u *(bLFK4[5] +u *(bLFK4[6] + u *(bLFK4[7] +u *(bLFK4[8] +u * bLFK4[9] )))) )))), + tf.where(u < cut_off3, + cLFK4[0] + u *(cLFK4[1] +u *(cLFK4[2] +u *(cLFK4[3] +u *(cLFK4[4] +u *(cLFK4[5] +u *(cLFK4[6] + u *(cLFK4[7] +u *(cLFK4[8] +u * cLFK4[9] )))) )))), + dLFK4[0] + u *(dLFK4[1] +u *(dLFK4[2] +u *(dLFK4[3] +u *( dLFK4[4] +u *( dLFK4[5] +u *( dLFK4[6] + u *( dLFK4[7] +u *(dLFK4[8]+u * dLFK4[9] )))) )))) + ) + ) + + den = tf.where(u < cut_off2, + 1.0 + u *(bLFK4[10] +u *(bLFK4[11] + u *(bLFK4[12] +u *(bLFK4[13] +u *(bLFK4[14] +u *(bLFK4[15] +u *(bLFK4[16] ) ))))) ), + tf.where(u < cut_off3, + 1.0 + u *(cLFK4[10] +u *(cLFK4[11] + u *(cLFK4[12] +u *(cLFK4[13] +u *(cLFK4[14] +u *(cLFK4[15] +u *(cLFK4[16]))))))), + 1.0 + u *(dLFK4[10] +u *(dLFK4[11] + u *(dLFK4[12] +u *( dLFK4[13] +u *( dLFK4[14] +u *( dLFK4[15] +u *( dLFK4[16] ) ))))) ) + ) + ) + hz = num / den + return tf.math.abs(x) / (tf.math.sqrt(hz * t ) ) + +def func2(price,t,x,aLFK4): + p = tf.where(x < 0., price - x, price) + u = eta(tf.math.abs(x) / p ) + num = aLFK4[0] + u *( aLFK4[1] +u *( aLFK4[2] +u *( aLFK4[3] +u *( aLFK4[4] + u *( aLFK4[5] +u *( aLFK4[6] + u *( aLFK4[7]))) )))) + den = 1.0 + u *( aLFK4[8] +u *( aLFK4[9] + u *( aLFK4[10] +u *( aLFK4[11] +u *( aLFK4[12] ))))) + return p * num / den / tf.math.sqrt(t) + +def eta(z): +# case for avoiding incidents of 0/0, z close to zero... + return tf.where(z < 1e-2, + 1 -z *(0.5+ z *(1.0/12+ z *(1.0/24+ z *(19.0/720+ z *(3.0/160+ z *(863.0/60480+ z *(275.0/24192) )))))), + -z/ tf.math.log1p(-z) ) + +def vol_atm(price, t): + # atm case + return price * tf.math.sqrt(2. * m.pi / t) + +def vol_iotm(x,betaStart,betaEnd,price, t, cut_off1,cut_off2,cut_off3, aLFK4,bLFK4,cLFK4,dLFK4): + # other cases (ITM/OTM) + z = tf.where(x>=0.,(price-x)/x, -price/x) + + return tf.where(z <= cut_off1, + func1(t,x,z,betaStart,betaEnd,cut_off2,cut_off3,bLFK4,cLFK4,dLFK4), + func2(price,t,x,aLFK4) + ) + + + + +def volbachelier_tf(sign, strike, forward, t, price): + sign = tf.convert_to_tensor(sign, dtype=tf.float64, name='forwards') + strike = tf.convert_to_tensor(strike, dtype=tf.float64, name='strikes') + forward = tf.convert_to_tensor(forward, dtype=tf.float64, name='expiries') + t = tf.convert_to_tensor(t, dtype=tf.float64, name='displacement') + price = tf.convert_to_tensor(price, dtype=tf.float64, name='nu') + + # for rational expansion + aLFK4 = tf.constant([0.06155371425063157,2.723711658728403,10.83806891491789, + 301.0827907126612,1082.864564205999, 790.7079667603721, + 109.330638190985, 0.1515726686825187, 1.436062756519326, + 118.6674859663193, 441.1914221318738, 313.4771127147156, + 40.90187645954703], dtype=tf.float64) + bLFK4 = tf.constant([0.6409168551974357, 788.5769356915809, 445231.8217873989, + 149904950.4316367, 32696572166.83277, 4679633190389.852, + 420159669603232.9, 2.053009222143781e+16, 3.434507977627372e+17, + 2.012931197707014e+16, 644.3895239520736, 211503.4461395385, + 42017301.42101825, 5311468782.258145, 411727826816.0715, + 17013504968737.03, 247411313213747.3], dtype=tf.float64) + cLFK4 = tf.constant([0.6421106629595358, 654.5620600001645, 291531.4455893533, 69009535.38571493, 9248876215.120627, + 479057753706.175, 9209341680288.471, 61502442378981.76, 107544991866857.5, 63146430757.94501, + 437.9924136164148, 90735.89146171122, 9217405.224889684, 400973228.1961834, 7020390994.356452, + 44654661587.93606, 76248508709.85633], dtype=tf.float64) + dLFK4 = tf.constant([0.936024443848096, 328.5399326371301, 177612.3643595535, 8192571.038267588, 110475347.0617102, + 545792367.0681282, 1033254933.287134, 695066365.5403566, 123629089.1036043, 756.3653755877336, + 173.9755977685531, 6591.71234898389, 82796.56941455391, 396398.9698566103, 739196.7396982114, + 493626.035952601, 87510.31231623856], dtype=tf.float64) + + #eps = tf.cast(tf.constant(np.finfo(float).tiny),tf.float32) + # constants + cut_off_atm = tf.constant(1.0e-10, dtype=tf.float64) # ATM Cutoff level #np.finfo(float).eps + cut_off1 = tf.constant(0.15, dtype=tf.float64) # cut-off for -C(x)/x + cut_off2 = tf.constant(0.0091, dtype=tf.float64) # 1st cut-off for tilde(eta) + cut_off3 = tf.constant(0.088, dtype=tf.float64) # 2nd cut-off for tilde(eta) + + betaStart = - tf.math.log(cut_off1) ; betaEnd = 708.3964185322641#- tf.math.log(machine eps) + + x = ( forward - strike) * sign # intrinsic value of the Call (sign=1) + # or Put (sign = -1) + + + return tf.where(tf.math.abs(x) < cut_off_atm, + vol_atm(price,t), + vol_iotm(x,betaStart,betaEnd,price, t, cut_off1,cut_off2,cut_off3, aLFK4,bLFK4,cLFK4,dLFK4) + ) + + From 60aa672ae02eb5e07d475617e56907d67b63ea51 Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Thu, 27 Feb 2020 12:37:08 +0100 Subject: [PATCH 2/8] changes made after inspection --- tf_quant_finance/volatility/bachelier_tf.py | 273 ++++++++++---------- 1 file changed, 140 insertions(+), 133 deletions(-) diff --git a/tf_quant_finance/volatility/bachelier_tf.py b/tf_quant_finance/volatility/bachelier_tf.py index 303804ca8..3838339c5 100644 --- a/tf_quant_finance/volatility/bachelier_tf.py +++ b/tf_quant_finance/volatility/bachelier_tf.py @@ -1,138 +1,142 @@ -# -*- coding: utf-8 -*- """ "" Created on Fri Nov 22 15:22:13 2019 'Copyright 2020 Joerg Kienitz -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. +@author: Joerg Kienitz +""" -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. +import tensorflow.compat.v2 as tf +import numpy as np -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +def _ncdf(x): + return (tf.math.erf(x / _SQRT_2) + 1.) / 2.0 -@author: Joerg Kienitz -""" +def _npdf(x): + return tf.math.exp(-x**2/2)/_SQRT_2/_SQRT_pi -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import tensorflow as tf -import tensorflow_probability as tfp +_SQRT_2 = tf.math.sqrt(tf.constant(2.0,dtype=tf.float64)) #1.4142135623730951 +_SQRT_pi = tf.math.sqrt(tf.constant(np.pi,dtype=tf.float64)) # straight fwd implementation of the Bachelier pricing # there is a version with just one call to exp !! -def option_price(spots, +def bachelier_option_price(spots, strikes, volatilities, expiries, - rates, + discount_rates = None, + discount_factors = None, is_call_options=None, dtype = None, name = None): - """ Compute the Bachelier price for a batch of European options. - + """ computes the Bachelier price for a batch of European options. + We assume a standard Brownian motion of the form + dS = r dt + sigma dW + for the underlying + ## References: [1] Kienitz, J. "Interest Rate Derivatives Explained I", Plagrave McMillan (2014) p.119 - [2] https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428994 + [2] Terakado, Satoshi: On the Option Pricing Formula Based on the Bachelier Model + Link: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428994 + + #### Examples + + spots = np.array([0.03, 0.02]) + strikes = np.array([.02, .02]) + volatilities = np.array([.004, .005]) + expiries = 2.0 + discount_rates = [0.02, 0.01] + computed_prices = bachelier_option_price( + spots, + strikes, + volatilities, + expiries, + dtype=tf.float64) + # Expected print output of computed prices: + # + + Args: - Parameters - ---------- spots : A real `Tensor` of any shape. The current spot prices to expiry. strikes : A real `Tensor` of the same shape and dtype as `spots`. The strikes of the options to be priced. volatilities : A real `Tensor` of same shape and dtype as `spots`. The volatility to expiry. - expiries : A real `Tensor` of same shape and dtype as `spots`. The expiry - for each option. The units should be such that `expiry * volatility**2` is - dimensionless. - rates : A real `Tensor` of the same shape and dtype as `spots`. The - rates of the options to be priced. - is_call_options: A boolean `Tensor` of a shape compatible with `forwards`. - Indicates whether to compute the price of a call (if True) or a put (if - False). If not supplied, it is assumed that every element is a call. - dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion - of any supplied non-`Tensor` arguments to `Tensor`. - Default value: None which maps to the default dtype inferred by TensorFlow - (float32). - name: str. The name for the ops created by this function. - Default value: None which is mapped to the default name `option_price`. + expiries : A real `Tensor` of same shape and dtype as `spots`. + discount_rates : rates from which discount factor via + discount factor = exp(-discount rate * T) are calculated + discountr_factors : A real 'Tensor' of same shape and dtype as 'spots' The + discounting factor; discount_rates = -log(discount factor) * expiries + is_call_options : A boolean `Tensor` of a shape compatible with + `volatilities`. Indicates whether the option is a call (if True) or a put + (if False). If not supplied, call options are assumed. + dtype: supplied dtype but converted to tf.float64 + name: name of the function Returns - ------- + option_prices: A `Tensor` of the same shape as `spots`. The Bachelier price of the options. - #### Examples - ```python - spots = np.array([0.03, 0.02]) - strikes = np.array([.02, .02]) - volatilities = np.array([.004, .005]) - expiries = 2.0 - rates = [0.02, 0.01] - computed_prices = option_price( - spots, - strikes, - volatilities, - expiries, - rates, - dtype=tf.float64) - # Expected print output of computed prices: - # - ``` + """ with tf.compat.v1.name_scope( name, - default_name='option_price', + default_name='bachelier_option_price', values=[ - spots, strikes, volatilities, expiries, rates, - is_call_options - ]): - + spots, strikes, volatilities, expiries, discount_rates, + discount_factors, is_call_options + ]): + spots = tf.convert_to_tensor(spots, dtype=tf.float64, name='forwards') strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') volatilities = tf.convert_to_tensor(volatilities, tf.float64, name='volatilities') expiries = tf.convert_to_tensor(expiries, tf.float64, name='expiries') - rates = tf.convert_to_tensor(rates, tf.float64, name='rates') + if (discount_rates != None and discount_factors != None): + raise ValueError('Either discount rates or discount factors have to be used.') + if (discount_rates != None and discount_factors == None): + rates = tf.convert_to_tensor(discount_rates, tf.float64, name='rates') + df = tf.math.exp(-rates*expiries) + elif (discount_factors != None and discount_rates == None): + rates = -tf.math.log(tf.convert_to_tensor(discount_rates, tf.float64, name='rates'))/expiries + df = discount_factors + else: + rates = 0.0 + df = tf.convert_to_tensor(rates, dtype=tf.float64, name='discount_rates') + + z = tf.zeros_like(strikes) - normal = tfp.distributions.Normal( - loc=tf.zeros([], dtype=spots.dtype), scale=1) - - df = tf.math.exp(-rates*expiries) + #normal = tfp.distributions.Normal( + # loc=tf.zeros([], dtype=spots.dtype), scale=1) + vt = volatilities * tf.math.sqrt(expiries) z = tf.where(rates == 0., (spots - strikes)/vt, (spots-strikes*df)/(volatilities * tf.math.sqrt(0.5*(1.-tf.math.exp(-2.*rates*expiries))/rates))) - n1 = normal.cdf(z) - n2 = normal.prob(z) + n1 = _ncdf(z) + n2 = _npdf(z) calls = tf.where(rates==0., (spots - strikes) * n1 + vt * n2, (spots - strikes*df)*n1 + volatilities*tf.math.sqrt(0.5*(1-tf.math.exp(-2*rates*expiries))/rates)) @@ -147,93 +151,97 @@ def option_price(spots, -def option_price_dawson_tf(forwards, +def dawson_option_price(forwards, strikes, volatilities, expiries, + discount_rates = None, discount_factors = None, is_call_options=None, dtype = None, name = None): - """Computes the Black Scholes price for a batch of European options. - - ## References: - [1] Dawson, P., Blake, D., Cairns, A. J. G. and Dowd, K.: Options on normal under- + """Computes the Bachelier price for a batch of European options. + We assume a standard Brownian motion of the form + dS = r dt + sigma dW + for the underlying + + ## References: + [1] Dawson, P., Blake, D., Cairns, A. J. G. and Dowd, K.: Options on normal under- lyings, CRIS Discussion Paper Series – 2007.VII, 2007. - + + #### Examples + spots = np.array([0.03, 0.02]) + strikes = np.array([.02, .02]) + volatilities = np.array([.004, .005]) + expiries = 2.0 + expiries = 1.0 + computed_prices = dawson_option_price( + forwards, + strikes, + volatilities, + expiries, + dtype=tf.float64) + # Expected print output of computed prices: + # + Args: + forwards: A real `Tensor` of any shape. The current forward prices to expiry. strikes: A real `Tensor` of the same shape and dtype as `forwards`. The strikes of the options to be priced. volatilities: A real `Tensor` of same shape and dtype as `forwards`. The volatility to expiry. - expiries: A real `Tensor` of same shape and dtype as `forwards`. The expiry - for each option. The units should be such that `expiry * volatility**2` is - dimensionless. - discount_factors: A real `Tensor` of same shape and dtype as the `forwards`. - The discount factors to expiry (i.e. e^(-rT)). If not specified, no - discounting is applied (i.e. the undiscounted option price is returned). - Default value: None, interpreted as discount factors = 1. - is_call_options: A boolean `Tensor` of a shape compatible with `forwards`. - Indicates whether to compute the price of a call (if True) or a put (if - False). If not supplied, it is assumed that every element is a call. - dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion - of any supplied non-`Tensor` arguments to `Tensor`. - Default value: None which maps to the default dtype inferred by TensorFlow - (float32). - name: str. The name for the ops created by this function. - Default value: None which is mapped to the default name `option_price`. + expiries : A real `Tensor` of same shape and dtype as `spots`. + discount_rates : rates from which discount factor via + discount factor = exp(-discount rate * T) are calculated + discount_factors : A real 'Tensor' of same shape and dtype as 'spots' The + discounting factor; discount_rates = -log(discount factor) * expiries + is_call_options : A boolean `Tensor` of a shape compatible with + `volatilities`. Indicates whether the option is a call (if True) or a put + (if False). If not supplied, call options are assumed. + dtype: supplied dtype but converted to tf.float64 + name: name of the function Returns: option_prices: A `Tensor` of the same shape as `forwards`. The Bachelier price of the options. - #### Examples - ```python - spots = np.array([0.03, 0.02]) - strikes = np.array([.02, .02]) - volatilities = np.array([.004, .005]) - expiries = 2.0 - expiries = 1.0 - computed_prices = option_price( - forwards, - strikes, - volatilities, - expiries, - dtype=tf.float64) - # Expected print output of computed prices: - # - ``` + """ with tf.compat.v1.name_scope( name, - default_name='option_price_dawson', + default_name='dawson_option_price', values=[ forwards, strikes, volatilities, expiries, discount_factors, - is_call_options + discount_rates, is_call_options ]): - forwards = tf.convert_to_tensor(forwards, dtype=None, name='forwards') - strikes = tf.convert_to_tensor(strikes, dtype=None, name='strikes') - volatilities = tf.convert_to_tensor(volatilities, dtype=None, name='volatilities') - expiries = tf.convert_to_tensor(expiries, dtype=None, name='expiries') + forwards = tf.convert_to_tensor(forwards, dtype=tf.float64, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + volatilities = tf.convert_to_tensor(volatilities, dtype=tf.float64, name='volatilities') + expiries = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') - if discount_factors is None: - discount_factors = 1. - discount_factors = tf.convert_to_tensor( - discount_factors, dtype=dtype, name='discount_factors') + if (discount_rates != None and discount_factors != None): + raise ValueError('Either discount rates or discount factors have to be used.') + if (discount_rates != None and discount_factors == None): + discount_factors = tf.math.exp(-tf.convert_to_tensor(discount_rates, tf.float64, name='discount factors')*expiries) + else: + if (discount_factors == None and discount_rates == None): + discount_factors = 1.0 + discount_factors = tf.convert_to_tensor(discount_factors, dtype=tf.float64, name='discount_factors') + vt = volatilities * tf.math.sqrt(expiries) - normal = tfp.distributions.Normal( - loc=tf.zeros([], dtype=forwards.dtype), scale=1) + #normal = tfp.distributions.Normal( + # loc=tf.zeros([], dtype=forwards.dtype), scale=1) z = (forwards - strikes) / vt - n1 = normal.cdf(z) - n2 = normal.prob(z) + n1 = _ncdf(z) + n2 = _npdf(z) undiscounted_calls = (forwards-strikes) * n1 + vt * n2 if is_call_options is None: @@ -245,4 +253,3 @@ def option_price_dawson_tf(forwards, undiscounted_puts) - \ No newline at end of file From c828d8385d4eb578822195a5b668f9ef97d58024 Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Tue, 24 Mar 2020 09:39:37 +0100 Subject: [PATCH 3/8] commit after several changes --- tf_quant_finance/volatility/bachelier_tf.py | 32 +- .../volatility/sabr_approx_hagan_tf_test.py | 51 ++-- tf_quant_finance/volatility/sabr_approx_tf.py | 277 +++++++++++------- .../volatility/volbachelier_tf.py | 208 ++++++------- 4 files changed, 318 insertions(+), 250 deletions(-) diff --git a/tf_quant_finance/volatility/bachelier_tf.py b/tf_quant_finance/volatility/bachelier_tf.py index 3838339c5..d071d95b5 100644 --- a/tf_quant_finance/volatility/bachelier_tf.py +++ b/tf_quant_finance/volatility/bachelier_tf.py @@ -1,8 +1,7 @@ """ -"" Created on Fri Nov 22 15:22:13 2019 -'Copyright 2020 Joerg Kienitz +# Copyright 2020 Joerg Kienitz # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,7 +50,8 @@ def bachelier_option_price(spots, for the underlying ## References: - [1] Kienitz, J. "Interest Rate Derivatives Explained I", Plagrave McMillan (2014) p.119 + [1] Kienitz, J. "Interest Rate Derivatives Explained I", Palgrave McMillan (2014) p.119 + Link: https://www.palgrave.com/gp/book/9781137360069 [2] Terakado, Satoshi: On the Option Pricing Formula Based on the Bachelier Model Link: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428994 @@ -115,9 +115,9 @@ def bachelier_option_price(spots, if (discount_rates != None and discount_factors == None): rates = tf.convert_to_tensor(discount_rates, tf.float64, name='rates') - df = tf.math.exp(-rates*expiries) + df = tf.math.exp(-rates * expiries) elif (discount_factors != None and discount_rates == None): - rates = -tf.math.log(tf.convert_to_tensor(discount_rates, tf.float64, name='rates'))/expiries + rates = -tf.math.log(tf.convert_to_tensor(discount_rates, tf.float64, name='rates')) / expiries df = discount_factors else: rates = 0.0 @@ -132,20 +132,20 @@ def bachelier_option_price(spots, vt = volatilities * tf.math.sqrt(expiries) z = tf.where(rates == 0., (spots - strikes)/vt, - (spots-strikes*df)/(volatilities - * tf.math.sqrt(0.5*(1.-tf.math.exp(-2.*rates*expiries))/rates))) + (spots - strikes * df) / (volatilities + * tf.math.sqrt(0.5 * (1.-tf.math.exp(-2. * rates*expiries)) / rates))) n1 = _ncdf(z) n2 = _npdf(z) calls = tf.where(rates==0., (spots - strikes) * n1 + vt * n2, - (spots - strikes*df)*n1 - + volatilities*tf.math.sqrt(0.5*(1-tf.math.exp(-2*rates*expiries))/rates)) + (spots - strikes * df) * n1 + + volatilities * tf.math.sqrt(0.5 * (1 - tf.math.exp(-2 * rates * expiries)) / rates)) if is_call_options is None: return calls - puts = calls - spots + strikes * tf.math.exp(-rates*expiries) + puts = calls - spots + strikes * tf.math.exp(-rates * expiries) return tf.where(is_call_options, calls, puts) @@ -224,6 +224,7 @@ def dawson_option_price(forwards, volatilities = tf.convert_to_tensor(volatilities, dtype=tf.float64, name='volatilities') expiries = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') + # check if discount rates or discount factor version is used if (discount_rates != None and discount_factors != None): raise ValueError('Either discount rates or discount factors have to be used.') @@ -235,20 +236,21 @@ def dawson_option_price(forwards, discount_factors = tf.convert_to_tensor(discount_factors, dtype=tf.float64, name='discount_factors') vt = volatilities * tf.math.sqrt(expiries) - #normal = tfp.distributions.Normal( - # loc=tf.zeros([], dtype=forwards.dtype), scale=1) z = (forwards - strikes) / vt - + + # calculate constituents of Bachelier formula n1 = _ncdf(z) n2 = _npdf(z) - undiscounted_calls = (forwards-strikes) * n1 + vt * n2 - + undiscounted_calls = (forwards - strikes) * n1 + vt * n2 # Bachelier option price + + # check if calls or puts need to be considered if is_call_options is None: return discount_factors * undiscounted_calls undiscounted_forward = forwards - strikes undiscounted_puts = undiscounted_calls - undiscounted_forward + # return call, resp. put prices return discount_factors * tf.where(is_call_options, undiscounted_calls, undiscounted_puts) diff --git a/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py index c73e171eb..58a1df8de 100644 --- a/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py +++ b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py @@ -1,32 +1,19 @@ -# -*- coding: utf-8 -*- """ - -'Copyright 2020 Joerg Kienitz - -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: - -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. - -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. - -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. - -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Created on Fri Nov 22 15:22:13 2019 + +# Copyright 2020 Joerg Kienitz + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. @author: Joerg Kienitz """ @@ -64,7 +51,7 @@ for alpha in alpha_vec: print('alpha: ', alpha) yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha, beta_org, rho_org,nu_org) - cval = vptf.option_price(f,kval,yval,T,0.) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) label1 = 'approx ' + str(alpha) label2 = 'iv ' + str(alpha) @@ -79,7 +66,7 @@ for beta in beta_vec: print('parameters: ', beta) yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta, rho_org,nu_org) - cval = vptf.option_price(f,kval,yval,T,0.) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) label1 = 'approx ' + str(beta) label2 = 'iv ' + str(beta) @@ -93,7 +80,7 @@ for rho in rho_vec: print('parameters: ', rho) yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho,nu_org) - cval = vptf.option_price(f,kval,yval,T,0.) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) label1 = 'approx ' + str(rho) label2 = 'iv ' + str(rho) @@ -107,7 +94,7 @@ for nu in nu_vec: print('parameters: ', nu) yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu) - cval = vptf.option_price(f,kval,yval,T,0.) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) label1 = 'approx ' + str(nu) label2 = 'iv ' + str(nu) diff --git a/tf_quant_finance/volatility/sabr_approx_tf.py b/tf_quant_finance/volatility/sabr_approx_tf.py index 1c370fee1..d76d72a0c 100644 --- a/tf_quant_finance/volatility/sabr_approx_tf.py +++ b/tf_quant_finance/volatility/sabr_approx_tf.py @@ -1,42 +1,22 @@ # -*- coding: utf-8 -*- """ -"" -Created on Fri Nov 22 15:22:13 2019 +# Copyright 2020 Joerg Kienitz -'Copyright 2020 Joerg Kienitz - -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: - -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. - -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. - -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. - -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. @author: Joerg Kienitz """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import tensorflow as tf # straight fwd implementation of the Bachelier pricing @@ -55,10 +35,28 @@ def volsabr_h_n_tf( """ Standard Hagan SABR approximation for the Bachelier/Normal volatility + We assume a SABR model dynamic given by + dS = r dt + alpha * (S+d)^beta sigma dW + dalpha = nu * alpha * dZ + = rho dt + S(0) = forward + alpha(0) = alpha + + ## References: + [1] Hagan, S. Patrick, Deep Kumar, Andrew Lesniewski and Diana E. Woodward, 2002. - “Managing Smile Risk”. Wilmott Magazine, September/October. + and on Researchgate + Link: https://www.researchgate.net/publication/235622441_Managing_Smile_Risk + [2] Patrick S. Hagan Deep Kumar Andrew S. Lesniewski Diana E. Woodward, " Universal Smiles" + Link: https://onlinelibrary.wiley.com/doi/abs/10.1002/wilm.10523 + [3] Kienitz, J. "Interest Rate Derivatives Explained I", Palgrave McMillan (2014) p.119 + Link: https://www.palgrave.com/gp/book/9781137360069 + [4] Kienitz, J. "Interest Rate Derivatives Explained II", Palgrave McMillan (2017), p. + Link: https://www.palgrave.com/gp/book/9781137360182 + parameters: - forwards - forward rate - strikes - strike as array - expiries - maturity + forwards - forward rates + strikes - strikes as array + expiries - expiry/maturity displacements - displacement alpha - SABR parameter (initial vol) beta - SABR parameter (CEV coefficient) @@ -66,9 +64,8 @@ def volsabr_h_n_tf( nu - SABR parameter (vol of vol) For SABR we can always use f=1 and apply the scaling: - if f = f0 - knew -> k/f + we knew -> k/f alphanew -> f**(beta-1) * alpha ivol1 = sabrapprox.volsabr_h_n(f, kval, T, displacement, alpha, beta, rho, nu) price1 = vp.vanilla_n(f,kval,implVolApprox1,0,0,T,1) @@ -80,6 +77,12 @@ def volsabr_h_n_tf( price1 = price2 = price3 ivol1 = ivol2 = f * ivol3 + + Returns + + vol_sabr_approx: A `Tensor` of the same shape as `forwards`. The implied + Bachelier volatility approximation for the SABR model. + """ with tf.compat.v1.name_scope( name, @@ -99,7 +102,7 @@ def volsabr_h_n_tf( # identify ATM and non ATM strikes - eps = tf.constant(1.0e-06, dtype = tf.float64) # small number + eps = tf.constant(1.0e-06, dtype = tf.float64) # small number index_natm = (tf.math.abs(forwards-strikes) > eps) # itm/otm strikes # case rho = 1 may cause divide by zero problems @@ -111,7 +114,7 @@ def volsabr_h_n_tf( # this means only certain strikes are feasible for calculating implied vols! # to this end we only consider the SABR model for correlation values # between rho = -0.99 and rho = 0.99 - rho = tf.where(rho == 1., 0.999,tf.where(rho == -1., -0.999, rho)) + rho = tf.where(rho == 1., 0.999, tf.where(rho == -1., -0.999, rho)) betam = tf.constant(1.0 - beta) # often used @@ -121,57 +124,96 @@ def volsabr_h_n_tf( # different cases due to normal, cev, log-normal if 0. < beta and beta < 1.: # case of true CEV SABR gk = tf.zeros_like(strikes) - gk = tf.where(index_natm,(beta**2 -2.*beta)/24. - * fa**(-betam)*ka**(-betam)*alpha**2, gk) + gk = tf.where(index_natm,(beta**2 - 2. * beta) / 24. + * fa**(-betam) * ka**(-betam)*alpha**2, gk) xik = nu / alpha * (fa**betam - ka**betam) / betam - xxik = tf.math.log((tf.math.sqrt(1.0- 2.0 * rho * xik + xik**2) - rho + xik) - / (1 - rho))/nu - vol = tf.where(index_natm, - (fa - ka) / xxik * (1. + (gk + 0.25 * rho * nu * alpha * beta * fa**(0.5*(beta-1.))*ka**(0.5*(beta-1.)) - + (2. - 3. * rho**2) / 24 * nu**2) * expiries), - alpha * fa**beta * (1 + (beta*(beta-2.) * alpha**2 / 24. / fa**(2.*betam) - + 0.25 * rho*nu*alpha*beta / fa**(betam) - + (2.-3.*rho**2)/24. * nu**2)*expiries) ) - return vol + xxik = tf.math.log((tf.math.sqrt(1.0 - 2.0 * rho * xik + xik**2) - rho + xik) + / (1 - rho)) / nu + vol_sabr_approx = tf.where(index_natm, + (fa - ka) / xxik * (1. + (gk + 0.25 * rho * nu * alpha * beta * fa**(0.5 * (beta-1.)) * ka**(0.5 * (beta - 1.)) + + (2. - 3. * rho**2) / 24. * nu**2) * expiries), + alpha * fa**beta * (1 + (beta * (beta-2.) * alpha**2 / 24. / fa**(2. * betam) + + 0.25 * rho * nu * alpha * beta / fa**(betam) + + (2. - 3. * rho**2) / 24. * nu**2) * expiries) ) elif beta == 0.: # case of a Gaussian SV model (normal SABR) xik = nu / alpha * (fa - ka) - xxik = tf.math.log((tf.math.sqrt(1.0- 2.0 * rho * xik + xik**2) - rho + xik) / (1-rho)) - vol = tf.where(index_natm, alpha * xik / xxik * (1 + (1 / 24 * (2 - 3 * rho**2) * nu ** 2) * expiries), - alpha * (1+ (2.-3.*rho**2)/24.*nu**2*expiries)) - return vol + xxik = tf.math.log((tf.math.sqrt(1.0 - 2.0 * rho * xik + xik**2) - rho + xik) / (1 - rho)) + vol_sabr_approx = tf.where(index_natm, alpha * xik / xxik * (1. + (1. / 24. * (2. - 3. * rho**2) * nu**2) * expiries), + alpha * (1. + (2. - 3. * rho**2) / 24. * nu**2 * expiries)) else: # case of log-normal SV model (log-normal SABR) gk = - 1. / 24. * alpha**2 xik = nu / alpha * tf.math.log(fa / ka) sum2 = 0.25 * rho * nu * alpha - xxik = tf.math.log((tf.math.sqrt(1.0- 2.0 * rho * xik + xik**2) - rho + xik) - / (1. - rho))/nu - vol = tf.where(index_natm, + xxik = tf.math.log((tf.math.sqrt(1. - 2. * rho * xik + xik**2) - rho + xik) + / (1. - rho)) / nu + vol_sabr_approx = tf.where(index_natm, (fa - ka) / xxik * (1 + (gk + sum2 + 1. / 24. * (2. - 3.*rho**2) * nu**2) * expiries), - alpha * fa * (1.+ (gk + sum2 + (2.-3.*rho**2)/24.*nu**2)*expiries)) - return vol - + alpha * fa * (1.+ (gk + sum2 + (2. - 3. * rho**2) / 24. * nu**2) * expiries)) + return vol_sabr_approx -def volsabr_mr_n_tf(forwards, strikes, expiries, displacements, alpha, beta, rho, nu, kappa, name = None): - """ - ' f is the forward - ' k is the strike - ' t is maturity - ' a is displacement - ' alpha is ATM vol -> sigma in Hagan paper - ' beta is cev coefficient - ' rho is correlation - ' nu is vol of vol - ' kappa is mean reversion - """ +def volsabr_mr_n_tf(forwards, + strikes, + expiries, + displacements, + alpha, + beta, + rho, + nu, + kappa, + name = None): + """ computes the Bachelier implied volatility batch of European options. + We assume a SABR model dynamic given by + dS = alpha * (S+d)^beta sigma dW + dalpha = kappa (1-alpha) dt + nu * alpha * dZ + = rho dt + S(0) = forward + alpha(0) = alpha + + ## References: + [1] Kienitz, J. "Interest Rate Derivatives Explained I", Plagrave McMillan (2014) p.119 + Link: https://www.palgrave.com/gp/book/9781137360069 + [2] Terakado, Satoshi: On the Option Pricing Formula Based on the Bachelier Model + Link: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428994 + + + Args: + + forwards : A real `Tensor` of any shape. The current spot prices to + expiry. + strikes : A real `Tensor` of the same shape and dtype as `forwards`. The + strikes of the options to be priced. + expiries : A real `Tensor` of the same shape and dtype as `forwards`. The + expiries of the options to be priced. + expiries : A real `Tensor` of same shape and dtype as `spots`. + displacements:A real `Tensor` of the same shape and dtype as `forwards`. The + displacements for the forwards. + alpha : A real `Tensor` of the same shape and dtype as `forwards`. Initial + volatility of the stochastic volatility component. + beta : A real `Tensor` of the same shape and dtype as `forwards`. CEV + parameter of the SABR model. + rho : A real `Tensor` of the same shape and dtype as `forwards`. correlation + of the Brownian motions driving the forward and the volatility. + nu : A real `Tensor` of the same shape and dtype as `forwards`. volatiltiy + of volatility. + kappa: A real `Tensor` of the same shape and dtype as `forwards`. mean + reversion that is applied. + name: name of the function + + Returns + + vol_sabr_mr: A `Tensor` of the same shape as `forwards`. The Bachelier + implied volatiltiy for the approximation in the mean reverting SABR model. + + """ with tf.compat.v1.name_scope( name, default_name='sabr_implied_vol_hagan', values=[ forwards, strikes, expiries, displacements, alpha, beta, rho, nu ]): - # conversion maybe outside function!!!! + forwards = tf.convert_to_tensor(forwards, dtype=tf.float64, name='forwards') strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') expiries = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') @@ -185,21 +227,22 @@ def volsabr_mr_n_tf(forwards, strikes, expiries, displacements, alpha, beta, rho if kappa > 0.: bbar = 2. * rho * nu / alpha * (kappa * expiries - 1. - + tf.math.exp(-kappa * expiries)) / (kappa ** 2 * expiries ** 2) - cbar = 1.5 * nu ** 2 / alpha ** 2. * (1. + rho ** 2) * (1. + 2. * kappa * expiries - (2. - tf.math.exp(-kappa * expiries)) ** 2) \ - / (kappa ** 3 * expiries ** 3) + 12. * rho ** 2 * nu ** 2 / alpha ** 2 * (kappa ** 2 * expiries ** 2 * tf.math.exp(-kappa * expiries) - - (1. - tf.math.exp(-kappa * expiries)) ** 2) / (kappa ** 4 * expiries ** 4) - Gstar = (-0.5 * cbar + nu ** 2 / alpha ** 2 * (2. * kappa * expiries - 1. + tf.math.exp(-2. * kappa * expiries)) \ - / (4. * kappa ** 2 * expiries ** 2)) * alpha ** 2 * expiries + + tf.math.exp(-kappa * expiries)) / (kappa**2 * expiries**2) + cbar = 1.5 * nu ** 2 / alpha**2. * (1. + rho**2) * (1. + 2. * kappa * expiries - (2. - tf.math.exp(-kappa * expiries))**2) \ + / (kappa**3 * expiries**3) + 12. * rho**2 * nu**2 / alpha**2 * (kappa**2 * expiries**2 * tf.math.exp(-kappa * expiries) + - (1. - tf.math.exp(-kappa * expiries))**2) / (kappa**4 * expiries**4) + Gstar = (-0.5 * cbar + nu**2 / alpha**2 * (2. * kappa * expiries - 1. + tf.math.exp(-2. * kappa * expiries)) \ + / (4. * kappa**2 * expiries**2)) * alpha**2 * expiries # std case astd = alpha * tf.math.exp(0.5 * Gstar) rhostd = bbar / tf.math.sqrt(cbar) nustd = alpha * tf.math.sqrt(cbar) - - return volsabr_h_n_tf(forwards, strikes, expiries, displacements, astd, beta, rhostd, nustd) + vol_sabr_mr = volsabr_h_n_tf(forwards, strikes, expiries, displacements, astd, beta, rhostd, nustd) else: - return volsabr_h_n_tf(forwards, strikes, expiries, displacements, alpha, beta, rho, nu) + vol_sabr_mr = volsabr_h_n_tf(forwards, strikes, expiries, displacements, alpha, beta, rho, nu) + + return vol_sabr_mr def volsabr_h_n_cap_tf( @@ -213,7 +256,39 @@ def volsabr_h_n_cap_tf( nu, cap, name = None): + """ + Standard Hagan SABR approximation for the Bachelier/Normal volatility with + capping the volatility to reduce the right wing of the smile + + We assume a SABR model dynamic given by + dS = alpha * (S+d)^beta * sigma * dW + dalpha = nu * alpha * dZ + = rho dt + S(0) = forward + alpha(0) = alpha + + ## References: + [1] Patrick S. Hagan Deep Kumar Andrew S. Lesniewski Diana E. Woodward, " Universal Smiles" + Link: https://onlinelibrary.wiley.com/doi/abs/10.1002/wilm.10523 + [2] Kienitz, J. "Interest Rate Derivatives Explained II", Palgrave McMillan (2017) + https://www.palgrave.com/gp/book/9781137360182 + parameters: + forwards - forward rates + strikes - strikes as array + expiries - expiry/maturity + displacements - displacement + alpha - SABR parameter (initial vol) + beta - SABR parameter (CEV coefficient) + rho - SABR parameter (correlation) + nu - SABR parameter (vol of vol) + cap - parameter for capping volatility + + Returns + + sabr_vol_capped : A `Tensor` of the same shape as `forwards'. The Bachelier + implied volatility for the capped SABR model. + """ with tf.compat.v1.name_scope( name, default_name='sabr_implied_vol_hagan', @@ -234,21 +309,21 @@ def volsabr_h_n_cap_tf( eps = 1.0e-06 index_atm = tf.math.abs(forwards - strikes) < eps - vol = tf.zeros_like(strikes) + sabr_vol_capped = tf.zeros_like(strikes) fa = forwards + displacements ka = strikes + displacements betam = 1. - beta # atm but different cases due to normal, cev, log-normal if 0. < beta and beta < 1.: # case of true CEV SABR - volatm = alpha * fa**beta * (1 + (beta*(beta-2.) * alpha**2 / 24. / fa**(2.*betam) - + 0.25 * rho*nu*alpha*beta / fa**(betam) - + (2.-3.*rho**2)/24. * nu**2)*expiries) + volatm = alpha * fa**beta * (1 + (beta * (beta - 2.) * alpha**2 / 24. / fa**(2. * betam) + + 0.25 * rho * nu * alpha * beta / fa**(betam) + + (2. - 3. * rho**2) / 24. * nu**2) * expiries) elif beta == 0.: # case of a Gaussian SV model (normal SABR) - volatm = alpha * (1. + (2.-3.*rho**2)/24.*nu**2*expiries) + volatm = alpha * (1. + (2. - 3. * rho**2) / 24. * nu**2 * expiries) else: # case of log-normal SV model (log-normal SABR) - volatm = alpha * fa * (1.+ (-1. / 24. * alpha**2 + 0.25 * rho * nu * alpha + (2.-3.*rho**2)/24.*nu**2)*expiries) + volatm = alpha * fa * (1.+ (-1. / 24. * alpha**2 + 0.25 * rho * nu * alpha + (2. - 3. * rho**2) / 24. * nu**2) * expiries) if beta == 1: @@ -257,7 +332,7 @@ def volsabr_h_n_cap_tf( rho = tf.where(rho == 1, 0.999, tf.where(rho == -1, -0.999,rho)) # the cap can only be applied if the term under sqrt is positive - term = tf.math.sqrt(tf.math.maximum(cap ** 2 - 1. + rho**2,0.)) + term = tf.math.sqrt(tf.math.maximum(cap**2 - 1. + rho**2,0.)) xip = -rho + term xim = -rho - term @@ -266,31 +341,31 @@ def volsabr_h_n_cap_tf( Ym = -tf.math.log((cap + term) / (1. - rho)) # here we need ATM consideration - ic = ((ka) ** (1. - beta) - (fa) ** (1. - beta)) / (1. - beta) + ic = ((ka)**(1. - beta) - (fa)**(1. - beta)) / (1. - beta) f0 = 0.5 * ((forwards + strikes) + displacements) # 2* displace? - gamma = beta * f0 ** (beta-1.) + gamma = beta * f0**(beta-1.) - Delta0 = (beta ** 2 - 2. * beta) * f0 ** (2. * beta-2) + Delta0 = (beta**2 - 2. * beta) * f0 ** (2. * beta-2.) xi = nu / alpha * ic Yxi = tf.where(xi > xip, - Yp + (xi - xip)/cap, + Yp + (xi - xip) / cap, tf.where(xi < xim, - Ym + (xi -xim)/cap, + Ym + (xi -xim) / cap, -tf.math.log((tf.math.sqrt(1. + 2. * rho * xi + xi ** 2) - rho - xi) / (1 - rho)) ) ) sK0 = tf.where(xi > xip, - nu ** 2 / (8. * alpha ** 2 * Yxi) * (-Yp + 3. * (-rho * cap + term) / cap) \ - + Delta0 / (16. * Yxi) * (2. * cap ** 2 * (Yxi - Yp) + (1 - rho ** 2) * Yp + cap * term - rho), + nu**2 / (8. * alpha**2 * Yxi) * (-Yp + 3. * (-rho * cap + term) / cap) \ + + Delta0 / (16. * Yxi) * (2. * cap**2 * (Yxi - Yp) + (1 - rho**2) * Yp + cap * term - rho), tf.where(xi < xim, - nu ** 2 / (8 * alpha ** 2 * Yxi) * (-Ym - 3 * (rho * cap + term) / cap) + Delta0 / (16. * Yxi) * (2 * cap ** 2 * (Yxi - Ym) + (1 - rho ** 2) * Ym - cap * term - rho), - nu ** 2 / (8. * alpha ** 2 * Yxi) * (-Yxi + 3 * (xi + rho - rho * tf.math.sqrt(1 + 2 * rho * xi + xi ** 2)) / tf.math.sqrt(1 + 2 * rho * xi + xi ** 2)) \ - + Delta0 / (16. * Yxi) * ((1 - rho ** 2) * Yxi + (xi + rho) * tf.math.sqrt(1 + 2 * rho * xi + xi ** 2) - rho) + nu**2 / (8 * alpha**2 * Yxi) * (-Ym - 3. * (rho * cap + term) / cap) + Delta0 / (16. * Yxi) * (2. * cap**2 * (Yxi - Ym) + (1. - rho**2) * Ym - cap * term - rho), + nu**2 / (8. * alpha**2 * Yxi) * (-Yxi + 3. * (xi + rho - rho * tf.math.sqrt(1. + 2. * rho * xi + xi**2)) / tf.math.sqrt(1. + 2. * rho * xi + xi**2)) \ + + Delta0 / (16. * Yxi) * ((1. - rho**2) * Yxi + (xi + rho) * tf.math.sqrt(1. + 2. * rho * xi + xi**2) - rho) ) ) @@ -299,6 +374,6 @@ def volsabr_h_n_cap_tf( tf.math.sqrt(1. - theta * expiries), 1. / tf.math.sqrt(1. + theta * expiries) ) - vol = tf.where(index_atm, volatm, nu * (strikes - forwards) / Yxi * highorder) - return vol + sabr_vol_capped = tf.where(index_atm, volatm, nu * (strikes - forwards) / Yxi * highorder) + return sabr_vol_capped \ No newline at end of file diff --git a/tf_quant_finance/volatility/volbachelier_tf.py b/tf_quant_finance/volatility/volbachelier_tf.py index bf1d30c05..3fc70ee5a 100644 --- a/tf_quant_finance/volatility/volbachelier_tf.py +++ b/tf_quant_finance/volatility/volbachelier_tf.py @@ -1,113 +1,80 @@ -# -*- coding: utf-8 -*- """ - -'Copyright 2020 Joerg Kienitz - -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: - -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. - -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. - -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. - -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Created on Fri Nov 22 15:22:13 2019 + +# Copyright 2020 Joerg Kienitz + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. @author: Joerg Kienitz +""" - - # aLFK4 = [0.06155371425063157, 2.723711658728403, 10.83806891491789, 301.0827907126612 , 1082.864564205999 , 790.7079667603721 , 109.330638190985 , 0.1515726686825187 , 1.436062756519326 , 118.6674859663193 , 441.1914221318738 , 313.4771127147156 , 40.90187645954703]; - # c0=0.6409168551974356; - # c1=776.7622553541449; d1=640.570978803313; - # c2=431496.7672664836; d2=206873.1616020722; - # c3=142810081.2530825; d3=40411807.74439474; - # c4=30593703611.75923; d4=5007804896.265911; - # c5=4296256150040.825; d5=379858284395.2218; - # c6=377808909050483.9; d6=15253797078346.91; - # c7=1.799539603508817e+16; d7=211469320780659.9; - # c8=2.864267851212242e+17; - # c9=1.505975341130321e+16; - - # e0=0.6421698396894946; - # e1=639.0799338046976; f1=428.4860093838116; - # e2=278070.4504753253; f2=86806.89002606465; - # e3=64309618.34521588; f3=8635134.393384729; - # e4=8434470508.516712; f4=368872214.1525768; - # e5=429163238246.6056; f5=6359299149.626331; - # e6=8127970878235.127; f6=39926015967.88848; - # e7=53601225394979.81; f7=67434966969.06365; - # e8=92738918006503.35; - # e9=54928597545.97237; - - # g0=0.9419766804760195; - # g1=319.5904313022832; h1=170.3825619167351; - # g2=169280.1584005307; h2=6344.159541465554; - # g3=7680298.116948191; h3=78484.04408022196; - # g4=102052455.1237945; h4=370696.1131305614; - # g5=497528976.6077898; h5=682908.5433659635; - # g6=930641173.0039455; h6=451067.0450625782; - # g7=619268950.1849232; h7=79179.06152239779; - # g8=109068992.0230439; - # g9=672.856898188759; - - # bLFK4 = [c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, d1, d2, d3, d4, d5, d6, d7] - # cLFK4 = [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, f1, f2, f3, f4, f5, f6, f7] - # dLFK4 = [g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, h1, h2, h3, h4, h5, h6, h7] - - -""" + import math as m -import tensorflow as tf - -def func1(t,x,z,betaStart,betaEnd,cut_off2,cut_off3,bLFK4,cLFK4,dLFK4): - u = -(tf.math.log(z)+ betaStart) /(betaEnd - betaStart) +import tensorflow.compat.v2 as tf + +def func1(t, + x, + z, + betaStart, + betaEnd, + cut_off2, + cut_off3, + bLFK4, + cLFK4, + dLFK4): + """ helper function + + """ + + u = -(tf.math.log(z) + betaStart) / (betaEnd - betaStart) num = tf.where(u < cut_off2, - bLFK4[0] + u *(bLFK4[1] +u *(bLFK4[2] +u *(bLFK4[3] + u *(bLFK4[4] +u *(bLFK4[5] +u *(bLFK4[6] + u *(bLFK4[7] +u *(bLFK4[8] +u * bLFK4[9] )))) )))), + bLFK4[0] + u * (bLFK4[1] +u * (bLFK4[2] +u * (bLFK4[3] + u * (bLFK4[4] +u * (bLFK4[5] +u * (bLFK4[6] + u * (bLFK4[7] +u * (bLFK4[8] +u * bLFK4[9] )))) )))), tf.where(u < cut_off3, - cLFK4[0] + u *(cLFK4[1] +u *(cLFK4[2] +u *(cLFK4[3] +u *(cLFK4[4] +u *(cLFK4[5] +u *(cLFK4[6] + u *(cLFK4[7] +u *(cLFK4[8] +u * cLFK4[9] )))) )))), - dLFK4[0] + u *(dLFK4[1] +u *(dLFK4[2] +u *(dLFK4[3] +u *( dLFK4[4] +u *( dLFK4[5] +u *( dLFK4[6] + u *( dLFK4[7] +u *(dLFK4[8]+u * dLFK4[9] )))) )))) + cLFK4[0] + u * (cLFK4[1] +u * (cLFK4[2] +u * (cLFK4[3] +u * (cLFK4[4] +u * (cLFK4[5] +u * (cLFK4[6] + u * (cLFK4[7] + u * (cLFK4[8] + u * cLFK4[9] )))))))), + dLFK4[0] + u * (dLFK4[1] +u * (dLFK4[2] +u * (dLFK4[3] +u * (dLFK4[4] +u * (dLFK4[5] +u * (dLFK4[6] + u * (dLFK4[7] + u * (dLFK4[8] + u * dLFK4[9] )))))))) ) ) den = tf.where(u < cut_off2, - 1.0 + u *(bLFK4[10] +u *(bLFK4[11] + u *(bLFK4[12] +u *(bLFK4[13] +u *(bLFK4[14] +u *(bLFK4[15] +u *(bLFK4[16] ) ))))) ), + 1.0 + u * (bLFK4[10] + u * (bLFK4[11] + u * (bLFK4[12] + u * (bLFK4[13] + u * (bLFK4[14] + u * (bLFK4[15] + u * (bLFK4[16] ) ))))) ), tf.where(u < cut_off3, - 1.0 + u *(cLFK4[10] +u *(cLFK4[11] + u *(cLFK4[12] +u *(cLFK4[13] +u *(cLFK4[14] +u *(cLFK4[15] +u *(cLFK4[16]))))))), - 1.0 + u *(dLFK4[10] +u *(dLFK4[11] + u *(dLFK4[12] +u *( dLFK4[13] +u *( dLFK4[14] +u *( dLFK4[15] +u *( dLFK4[16] ) ))))) ) + 1.0 + u * (cLFK4[10] + u * (cLFK4[11] + u * (cLFK4[12] + u * (cLFK4[13] + u * (cLFK4[14] + u * (cLFK4[15] + u * (cLFK4[16]))))))), + 1.0 + u * (dLFK4[10] + u * (dLFK4[11] + u * (dLFK4[12] + u * (dLFK4[13] + u * (dLFK4[14] + u * (dLFK4[15] + u * (dLFK4[16]))))))) ) ) hz = num / den return tf.math.abs(x) / (tf.math.sqrt(hz * t ) ) -def func2(price,t,x,aLFK4): +def func2(price, + t, + x, + aLFK4): + """ helper function + + """ p = tf.where(x < 0., price - x, price) u = eta(tf.math.abs(x) / p ) - num = aLFK4[0] + u *( aLFK4[1] +u *( aLFK4[2] +u *( aLFK4[3] +u *( aLFK4[4] + u *( aLFK4[5] +u *( aLFK4[6] + u *( aLFK4[7]))) )))) - den = 1.0 + u *( aLFK4[8] +u *( aLFK4[9] + u *( aLFK4[10] +u *( aLFK4[11] +u *( aLFK4[12] ))))) + num = aLFK4[0] + u * (aLFK4[1] + u * (aLFK4[2] + u * (aLFK4[3] + u * (aLFK4[4] + u * (aLFK4[5] + u * (aLFK4[6] + u * (aLFK4[7]))))))) + den = 1.0 + u * (aLFK4[8] + u * (aLFK4[9] + u * (aLFK4[10] + u * (aLFK4[11] + u * (aLFK4[12]))))) return p * num / den / tf.math.sqrt(t) def eta(z): -# case for avoiding incidents of 0/0, z close to zero... +# case for avoiding incidents of 0/0, z close to zero return tf.where(z < 1e-2, - 1 -z *(0.5+ z *(1.0/12+ z *(1.0/24+ z *(19.0/720+ z *(3.0/160+ z *(863.0/60480+ z *(275.0/24192) )))))), - -z/ tf.math.log1p(-z) ) + 1 -z *(0.5+ z * (1.0 / 12.0 + z * (1.0 / 24.0 + z * (19.0 / 720.0 + z * (3.0 / 160.0 + z * (863.0/60480.0 + z * (275.0/24192.0))))))), + -z / tf.math.log1p(-z)) def vol_atm(price, t): # atm case @@ -115,7 +82,7 @@ def vol_atm(price, t): def vol_iotm(x,betaStart,betaEnd,price, t, cut_off1,cut_off2,cut_off3, aLFK4,bLFK4,cLFK4,dLFK4): # other cases (ITM/OTM) - z = tf.where(x>=0.,(price-x)/x, -price/x) + z = tf.where(x>=0.,(price - x) / x, -price / x) return tf.where(z <= cut_off1, func1(t,x,z,betaStart,betaEnd,cut_off2,cut_off3,bLFK4,cLFK4,dLFK4), @@ -125,12 +92,42 @@ def vol_iotm(x,betaStart,betaEnd,price, t, cut_off1,cut_off2,cut_off3, aLFK4,bLF -def volbachelier_tf(sign, strike, forward, t, price): - sign = tf.convert_to_tensor(sign, dtype=tf.float64, name='forwards') - strike = tf.convert_to_tensor(strike, dtype=tf.float64, name='strikes') - forward = tf.convert_to_tensor(forward, dtype=tf.float64, name='expiries') - t = tf.convert_to_tensor(t, dtype=tf.float64, name='displacement') - price = tf.convert_to_tensor(price, dtype=tf.float64, name='nu') +def volbachelier_tf(signs, + strikes, + forwards, + expiries, + prices): + """ computes the Bachelier implied volatility for a batch of prices of + European Call or Put options. + We assume a standard Brownian motion of the form + dS = sigma dW + for the underlying. sigma is the implied volatility. + + sign : A `Tensor` of any shape. The current sign that specifies if the + prices are Call (sign=1) or Put (sign=-1). + strikes : A real `Tensor`. The strikes of the options to be priced. + forwards : A real `Tensor` of same shape and dtype as `strikes`. + expiries : A real `Tensor` of same shape and dtype as `strikes`. + prices : A real `Tensor` of same shape and dtype as `strikes`. The prices + of the European Call, resp. Put prices + + Returns + + implied_bachelier_vols: A `Tensor` of the same shape as `strieks`. + The Bachelier implied volatilties of the Call, resp. Put options. + + +References: + [1] Fabien Le Floc'h, "Fast and Accurate Analytic Basis Point Volatility" + Link: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2420757 + + +""" + sign = tf.convert_to_tensor(signs, dtype=tf.float64, name='sign') + strike = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + forward = tf.convert_to_tensor(forwards, dtype=tf.float64, name='forward') + t = tf.convert_to_tensor(expiries, dtype=tf.float64, name='expiries') + price = tf.convert_to_tensor(prices, dtype=tf.float64, name='price') # for rational expansion aLFK4 = tf.constant([0.06155371425063157,2.723711658728403,10.83806891491789, @@ -144,13 +141,19 @@ def volbachelier_tf(sign, strike, forward, t, price): 2.012931197707014e+16, 644.3895239520736, 211503.4461395385, 42017301.42101825, 5311468782.258145, 411727826816.0715, 17013504968737.03, 247411313213747.3], dtype=tf.float64) - cLFK4 = tf.constant([0.6421106629595358, 654.5620600001645, 291531.4455893533, 69009535.38571493, 9248876215.120627, - 479057753706.175, 9209341680288.471, 61502442378981.76, 107544991866857.5, 63146430757.94501, - 437.9924136164148, 90735.89146171122, 9217405.224889684, 400973228.1961834, 7020390994.356452, + cLFK4 = tf.constant([0.6421106629595358, 654.5620600001645, 291531.4455893533, + 69009535.38571493, 9248876215.120627, + 479057753706.175, 9209341680288.471, 61502442378981.76, + 107544991866857.5, 63146430757.94501, + 437.9924136164148, 90735.89146171122, 9217405.224889684, + 400973228.1961834, 7020390994.356452, 44654661587.93606, 76248508709.85633], dtype=tf.float64) - dLFK4 = tf.constant([0.936024443848096, 328.5399326371301, 177612.3643595535, 8192571.038267588, 110475347.0617102, - 545792367.0681282, 1033254933.287134, 695066365.5403566, 123629089.1036043, 756.3653755877336, - 173.9755977685531, 6591.71234898389, 82796.56941455391, 396398.9698566103, 739196.7396982114, + dLFK4 = tf.constant([0.936024443848096, 328.5399326371301, 177612.3643595535, + 8192571.038267588, 110475347.0617102, + 545792367.0681282, 1033254933.287134, 695066365.5403566, + 123629089.1036043, 756.3653755877336, + 173.9755977685531, 6591.71234898389, 82796.56941455391, + 396398.9698566103, 739196.7396982114, 493626.035952601, 87510.31231623856], dtype=tf.float64) #eps = tf.cast(tf.constant(np.finfo(float).tiny),tf.float32) @@ -164,11 +167,12 @@ def volbachelier_tf(sign, strike, forward, t, price): x = ( forward - strike) * sign # intrinsic value of the Call (sign=1) # or Put (sign = -1) - - - return tf.where(tf.math.abs(x) < cut_off_atm, + implied_bachelier_vols = tf.where(tf.math.abs(x) < cut_off_atm, vol_atm(price,t), vol_iotm(x,betaStart,betaEnd,price, t, cut_off1,cut_off2,cut_off3, aLFK4,bLFK4,cLFK4,dLFK4) - ) + ) + + # return the full tensor of implied Bachelier volatilities due to atm and itm/otm + return implied_bachelier_vols From 338a0571d97c03971b3e07f208f923c8c7cf62a2 Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Tue, 31 Mar 2020 08:46:31 +0200 Subject: [PATCH 4/8] hagan test --- .../volatility/test_sabr_hagan_tf.py | 105 ++++++++ tf_quant_finance/volatility/vanilla_n_tf.py | 248 ++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 tf_quant_finance/volatility/test_sabr_hagan_tf.py create mode 100644 tf_quant_finance/volatility/vanilla_n_tf.py diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf.py b/tf_quant_finance/volatility/test_sabr_hagan_tf.py new file mode 100644 index 000000000..0e5d3e471 --- /dev/null +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +""" +"" + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz +""" +# f = 1.0 is sufficient due to scaling property + +import volsabr_h_n_tf as sabr + +import matplotlib.pyplot as plt +#import numpy as np +import autograd.numpy as np +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.0632859 +rho_org = -0.32978014 +T = 5 + +displacement = 0 #0.005 +kmin = -displacement +kmax = 10 +kval = np.arange(kmin, kmax, 0.01) + +alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] +displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] + +print('alpha varies') +for alpha in alpha_vec: + print('alpha:', alpha) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta_org, rho_org, nu_org) + plt.plot(kval,yval,label=alpha) +plt.title('alpha varies') +plt.legend() +plt.show() + + +print('beta varies') +for beta in beta_vec: + print('beta:', beta) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta, rho_org, nu_org) + plt.plot(kval,yval,label=beta) +plt.title('beta varies') +plt.legend() +plt.show() + +print('rho varies') +for rho in rho_vec: + print('rho:', rho) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho, nu_org) + plt.plot(kval,yval,label=rho) +plt.title('rho varies') +plt.legend() +plt.show() + +print('nu varies') +for nu in nu_vec: + print('nu:' nu) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta, rho_org,nu) + plt.plot(kval,yval,label=nu) +plt.title('nu varies') +plt.legend() +plt.show() + +print('displacement varies') +for displacement in displacement_vec: + print('displacement:', displacement) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho_org,nu_org) + plt.plot(kval,yval,label=displacement) +plt.title('displacement varies') +plt.legend() +plt.show() + diff --git a/tf_quant_finance/volatility/vanilla_n_tf.py b/tf_quant_finance/volatility/vanilla_n_tf.py new file mode 100644 index 000000000..302e0fc77 --- /dev/null +++ b/tf_quant_finance/volatility/vanilla_n_tf.py @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- +""" +"" +Created on Fri Nov 22 15:22:13 2019 + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import tensorflow as tf +import tensorflow_probability as tfp + +# straight fwd implementation of the Bachelier pricing +# there is a version with just one call to exp !! + + +def option_price(spots, + strikes, + volatilities, + expiries, + rates, + is_call_options=None, + dtype = None, + name = None): + """ Compute the Bachelier price for a batch of European options. + + ## References: + [1] Kienitz, J. "Interest Rate Derivatives Explained I", Plagrave McMillan (2014) p.119 + [2] https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428994 + + Parameters + ---------- + spots : A real `Tensor` of any shape. The current spot prices to + expiry. + strikes : A real `Tensor` of the same shape and dtype as `spots`. The + strikes of the options to be priced. + volatilities : A real `Tensor` of same shape and dtype as `spots`. The + volatility to expiry. + expiries : A real `Tensor` of same shape and dtype as `spots`. The expiry + for each option. The units should be such that `expiry * volatility**2` is + dimensionless. + rates : A real `Tensor` of the same shape and dtype as `spots`. The + rates of the options to be priced. + is_call_options: A boolean `Tensor` of a shape compatible with `forwards`. + Indicates whether to compute the price of a call (if True) or a put (if + False). If not supplied, it is assumed that every element is a call. + dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion + of any supplied non-`Tensor` arguments to `Tensor`. + Default value: None which maps to the default dtype inferred by TensorFlow + (float32). + name: str. The name for the ops created by this function. + Default value: None which is mapped to the default name `option_price`. + + Returns + ------- + option_prices: A `Tensor` of the same shape as `spots`. The Bachelier + price of the options. + + #### Examples + ```python + spots = np.array([0.03, 0.02]) + strikes = np.array([.02, .02]) + volatilities = np.array([.004, .005]) + expiries = 2.0 + rates = [0.02, 0.01] + computed_prices = option_price( + spots, + strikes, + volatilities, + expiries, + rates, + dtype=tf.float64) + # Expected print output of computed prices: + # + ``` + + """ + with tf.compat.v1.name_scope( + name, + default_name='option_price', + values=[ + spots, strikes, volatilities, expiries, rates, + is_call_options + ]): + + spots = tf.convert_to_tensor(spots, dtype=tf.float64, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=tf.float64, name='strikes') + volatilities = tf.convert_to_tensor(volatilities, tf.float64, name='volatilities') + expiries = tf.convert_to_tensor(expiries, tf.float64, name='expiries') + rates = tf.convert_to_tensor(rates, tf.float64, name='rates') + + z = tf.zeros_like(strikes) + + normal = tfp.distributions.Normal( + loc=tf.zeros([], dtype=spots.dtype), scale=1) + + df = tf.math.exp(-rates*expiries) + vt = volatilities * tf.math.sqrt(expiries) + + z = tf.where(rates == 0., (spots - strikes)/vt, + (spots-strikes*df)/(volatilities + * tf.math.sqrt(0.5*(1.-tf.math.exp(-2.*rates*expiries))/rates))) + + n1 = normal.cdf(z) + n2 = normal.prob(z) + calls = tf.where(rates==0., (spots - strikes) * n1 + vt * n2, + (spots - strikes*df)*n1 + + volatilities*tf.math.sqrt(0.5*(1-tf.math.exp(-2*rates*expiries))/rates)) + + + if is_call_options is None: + return calls + + puts = calls - spots + strikes * tf.math.exp(-rates*expiries) + + return tf.where(is_call_options, calls, puts) + + + +def vanilla_n_dawson_tf(forwards, + strikes, + volatilities, + expiries, + discount_factors = None, + is_call_options=None, + dtype = None, + name = None): + + """Computes the Black Scholes price for a batch of European options. + + ## References: + [1] Dawson, P., Blake, D., Cairns, A. J. G. and Dowd, K.: Options on normal under- + lyings, CRIS Discussion Paper Series – 2007.VII, 2007. + + Args: + forwards: A real `Tensor` of any shape. The current forward prices to + expiry. + strikes: A real `Tensor` of the same shape and dtype as `forwards`. The + strikes of the options to be priced. + volatilities: A real `Tensor` of same shape and dtype as `forwards`. The + volatility to expiry. + expiries: A real `Tensor` of same shape and dtype as `forwards`. The expiry + for each option. The units should be such that `expiry * volatility**2` is + dimensionless. + discount_factors: A real `Tensor` of same shape and dtype as the `forwards`. + The discount factors to expiry (i.e. e^(-rT)). If not specified, no + discounting is applied (i.e. the undiscounted option price is returned). + Default value: None, interpreted as discount factors = 1. + is_call_options: A boolean `Tensor` of a shape compatible with `forwards`. + Indicates whether to compute the price of a call (if True) or a put (if + False). If not supplied, it is assumed that every element is a call. + dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion + of any supplied non-`Tensor` arguments to `Tensor`. + Default value: None which maps to the default dtype inferred by TensorFlow + (float32). + name: str. The name for the ops created by this function. + Default value: None which is mapped to the default name `option_price`. + + Returns: + option_prices: A `Tensor` of the same shape as `forwards`. The Bachelier + price of the options. + + + #### Examples + ```python + spots = np.array([0.03, 0.02]) + strikes = np.array([.02, .02]) + volatilities = np.array([.004, .005]) + expiries = 2.0 + expiries = 1.0 + computed_prices = option_price( + forwards, + strikes, + volatilities, + expiries, + dtype=tf.float64) + # Expected print output of computed prices: + # + ``` + """ + with tf.compat.v1.name_scope( + name, + default_name='option_price_dawson', + values=[ + forwards, strikes, volatilities, expiries, discount_factors, + is_call_options + ]): + + forwards = tf.convert_to_tensor(forwards, dtype=None, name='forwards') + strikes = tf.convert_to_tensor(strikes, dtype=None, name='strikes') + volatilities = tf.convert_to_tensor(volatilities, dtype=None, name='volatilities') + expiries = tf.convert_to_tensor(expiries, dtype=None, name='expiries') + + if discount_factors is None: + discount_factors = 1. + discount_factors = tf.convert_to_tensor( + discount_factors, dtype=dtype, name='discount_factors') + + vt = volatilities * tf.math.sqrt(expiries) + normal = tfp.distributions.Normal( + loc=tf.zeros([], dtype=forwards.dtype), scale=1) + + z = (forwards - strikes) / vt + + n1 = normal.cdf(z) + n2 = normal.prob(z) + undiscounted_calls = (forwards-strikes) * n1 + vt * n2 + + if is_call_options is None: + return discount_factors * undiscounted_calls + undiscounted_forward = forwards - strikes + undiscounted_puts = undiscounted_calls - undiscounted_forward + + return discount_factors * tf.where(is_call_options, undiscounted_calls, + undiscounted_puts) + + + \ No newline at end of file From 241dc722872304ff61f28e3a25f5bab8d1bf13c3 Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Mon, 24 Aug 2020 08:42:10 +0200 Subject: [PATCH 5/8] cpyright change --- tf_quant_finance/volatility/bachelier_tf.py | 11 +- .../volatility/sabr_approx_hagan_tf_test.py | 137 ------------------ tf_quant_finance/volatility/sabr_approx_tf.py | 10 +- .../volatility/test_sabr_hagan_tf.py | 105 -------------- tf_quant_finance/volatility/vanilla_n_tf.py | 48 ++---- .../volatility/volbachelier_tf.py | 11 +- 6 files changed, 23 insertions(+), 299 deletions(-) delete mode 100644 tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py delete mode 100644 tf_quant_finance/volatility/test_sabr_hagan_tf.py diff --git a/tf_quant_finance/volatility/bachelier_tf.py b/tf_quant_finance/volatility/bachelier_tf.py index d071d95b5..e7a9d7af7 100644 --- a/tf_quant_finance/volatility/bachelier_tf.py +++ b/tf_quant_finance/volatility/bachelier_tf.py @@ -1,8 +1,6 @@ -""" -Created on Fri Nov 22 15:22:13 2019 - -# Copyright 2020 Joerg Kienitz - +# Lint as: python3 +# Copyright 2020 Google LLC +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -15,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -@author: Joerg Kienitz -""" - import tensorflow.compat.v2 as tf import numpy as np diff --git a/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py deleted file mode 100644 index 58a1df8de..000000000 --- a/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py +++ /dev/null @@ -1,137 +0,0 @@ -""" -Created on Fri Nov 22 15:22:13 2019 - -# Copyright 2020 Joerg Kienitz - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -@author: Joerg Kienitz -""" - -import sabr_approx_tf as sabr -import bachelier_tf as vptf -import volbachelier_tf as bvtf - -import numpy as np -import matplotlib.pyplot as plt - -# SABR parameters -# SABR parameters -f = 1.0 #0.00434015 -alpha_org = 0.16575423 -beta_org = .6#0.7#0.16415365 -nu_org = 0.2632859 -rho_org = -0.32978014 -T = 5 - -displacement_org = 0. #0.005 -kmin = -displacement_org -kmax = 10 -kval = np.arange(kmin, kmax, 0.01) -kval[0] = (kval[0] + kval[1])/2 -vol = np.zeros(len(kval)) - -alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] -beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] -rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] -nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] -displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] - -print('alpha varies') -for alpha in alpha_vec: - print('alpha: ', alpha) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha, beta_org, rho_org,nu_org) - cval = vptf.bachelier_option_price(f,kval,yval,T,0.) - yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) - label1 = 'approx ' + str(alpha) - label2 = 'iv ' + str(alpha) - plt.plot(kval,yval,label= label1) - plt.plot(kval, yval1, label=label2) -plt.title('alpha varies') -plt.legend() -plt.show() - - -print('beta varies') -for beta in beta_vec: - print('parameters: ', beta) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta, rho_org,nu_org) - cval = vptf.bachelier_option_price(f,kval,yval,T,0.) - yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) - label1 = 'approx ' + str(beta) - label2 = 'iv ' + str(beta) - plt.plot(kval,yval,label= label1) - plt.plot(kval, yval1, label=label2) -plt.title('beta varies') -plt.legend() -plt.show() - -print('rho varies') -for rho in rho_vec: - print('parameters: ', rho) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho,nu_org) - cval = vptf.bachelier_option_price(f,kval,yval,T,0.) - yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) - label1 = 'approx ' + str(rho) - label2 = 'iv ' + str(rho) - plt.plot(kval,yval,label= label1) - plt.plot(kval, yval1, label=label2) -plt.title('rho varies') -plt.legend() -plt.show() - -print('nu varies') -for nu in nu_vec: - print('parameters: ', nu) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu) - cval = vptf.bachelier_option_price(f,kval,yval,T,0.) - yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) - label1 = 'approx ' + str(nu) - label2 = 'iv ' + str(nu) - plt.plot(kval,yval,label= label1) - plt.plot(kval, yval1, label=label2) -plt.title('nu varies') -plt.legend() -plt.show() - -print('displacement varies') -for displacement in displacement_vec: - print('parameters: ', displacement) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) - label1 = 'approx ' + str(displacement) - plt.plot(kval,yval,label= label1) -plt.title('displacement varies') -plt.legend() -plt.show() - -# different approximation techniques for SABR and Mean Reverting SABR -kappa = 0.5 -cap = 3. - -yval1 = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) -yval2 = sabr.volsabr_mr_n_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, kappa) -yval3 = sabr.volsabr_h_n_cap_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, cap) - -label1 = 'Hagan approx ' -label2 = 'MR SABR approx ' -label3 = 'Capped SABR approx ' - -plt.plot(kval,yval1,label= label1) -plt.plot(kval,yval2,label= label2) -plt.plot(kval,yval3,label= label3) -plt.title('different SABR approximation') -plt.legend() -plt.show() - - - diff --git a/tf_quant_finance/volatility/sabr_approx_tf.py b/tf_quant_finance/volatility/sabr_approx_tf.py index d76d72a0c..38fe13855 100644 --- a/tf_quant_finance/volatility/sabr_approx_tf.py +++ b/tf_quant_finance/volatility/sabr_approx_tf.py @@ -1,7 +1,6 @@ -# -*- coding: utf-8 -*- -""" -# Copyright 2020 Joerg Kienitz - +# Lint as: python3 +# Copyright 2020 Google LLC +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -14,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -@author: Joerg Kienitz -""" - import tensorflow as tf # straight fwd implementation of the Bachelier pricing diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf.py b/tf_quant_finance/volatility/test_sabr_hagan_tf.py deleted file mode 100644 index 0e5d3e471..000000000 --- a/tf_quant_finance/volatility/test_sabr_hagan_tf.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -""" -"" - -'Copyright 2020 Joerg Kienitz - -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: - -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. - -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. - -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. - -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -@author: Joerg Kienitz -""" -# f = 1.0 is sufficient due to scaling property - -import volsabr_h_n_tf as sabr - -import matplotlib.pyplot as plt -#import numpy as np -import autograd.numpy as np -# SABR parameters -f = 1.0 #0.00434015 -alpha_org = 0.16575423 -beta_org = .6#0.7#0.16415365 -nu_org = 0.0632859 -rho_org = -0.32978014 -T = 5 - -displacement = 0 #0.005 -kmin = -displacement -kmax = 10 -kval = np.arange(kmin, kmax, 0.01) - -alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] -beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] -rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] -nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] -displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] - -print('alpha varies') -for alpha in alpha_vec: - print('alpha:', alpha) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta_org, rho_org, nu_org) - plt.plot(kval,yval,label=alpha) -plt.title('alpha varies') -plt.legend() -plt.show() - - -print('beta varies') -for beta in beta_vec: - print('beta:', beta) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta, rho_org, nu_org) - plt.plot(kval,yval,label=beta) -plt.title('beta varies') -plt.legend() -plt.show() - -print('rho varies') -for rho in rho_vec: - print('rho:', rho) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho, nu_org) - plt.plot(kval,yval,label=rho) -plt.title('rho varies') -plt.legend() -plt.show() - -print('nu varies') -for nu in nu_vec: - print('nu:' nu) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta, rho_org,nu) - plt.plot(kval,yval,label=nu) -plt.title('nu varies') -plt.legend() -plt.show() - -print('displacement varies') -for displacement in displacement_vec: - print('displacement:', displacement) - yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho_org,nu_org) - plt.plot(kval,yval,label=displacement) -plt.title('displacement varies') -plt.legend() -plt.show() - diff --git a/tf_quant_finance/volatility/vanilla_n_tf.py b/tf_quant_finance/volatility/vanilla_n_tf.py index 302e0fc77..8868bf4f0 100644 --- a/tf_quant_finance/volatility/vanilla_n_tf.py +++ b/tf_quant_finance/volatility/vanilla_n_tf.py @@ -1,37 +1,17 @@ -# -*- coding: utf-8 -*- -""" -"" -Created on Fri Nov 22 15:22:13 2019 - -'Copyright 2020 Joerg Kienitz - -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: - -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. - -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. - -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. - -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -@author: Joerg Kienitz -""" +# Lint as: python3 +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. from __future__ import absolute_import from __future__ import division diff --git a/tf_quant_finance/volatility/volbachelier_tf.py b/tf_quant_finance/volatility/volbachelier_tf.py index 3fc70ee5a..589a1081e 100644 --- a/tf_quant_finance/volatility/volbachelier_tf.py +++ b/tf_quant_finance/volatility/volbachelier_tf.py @@ -1,8 +1,6 @@ -""" -Created on Fri Nov 22 15:22:13 2019 - -# Copyright 2020 Joerg Kienitz - +# Lint as: python3 +# Copyright 2020 Google LLC +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -15,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -@author: Joerg Kienitz -""" - import math as m From bd65833ba80b284fe95fa58334bd0edeb5411525 Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Mon, 14 Sep 2020 10:37:49 +0200 Subject: [PATCH 6/8] example bachelier implied vol added --- .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 1760 bytes .../math/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 1089 bytes .../math/__pycache__/piecewise.cpython-37.pyc | Bin 0 -> 2811 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 590 bytes .../cubic/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 695 bytes .../cubic_interpolation.cpython-37.pyc | Bin 0 -> 8972 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 585 bytes .../linear_interpolation.cpython-37.pyc | Bin 0 -> 3636 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 1010 bytes .../conjugate_gradient.cpython-37.pyc | Bin 0 -> 14039 bytes .../pde/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 820 bytes .../__pycache__/grid_stepper.cpython-37.pyc | Bin 0 -> 12077 bytes .../__pycache__/pde_kernels.cpython-37.pyc | Bin 0 -> 13140 bytes .../grids/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 818 bytes .../__pycache__/grids_impl.cpython-37.pyc | Bin 0 -> 19311 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 194 bytes ...e_marching_schemes_internal.cpython-37.pyc | Bin 0 -> 2336 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 1019 bytes .../pde_time_marching_scheme.cpython-37.pyc | Bin 0 -> 2830 bytes .../pde_time_marching_schemes.cpython-37.pyc | Bin 0 -> 9652 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 867 bytes .../__pycache__/stateless.cpython-37.pyc | Bin 0 -> 1515 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 560 bytes .../__pycache__/halton_impl.cpython-37.pyc | Bin 0 -> 23506 bytes .../sobol/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 556 bytes .../__pycache__/sobol_impl.cpython-37.pyc | Bin 0 -> 6471 bytes .../__pycache__/bachelier_tf.cpython-36.pyc | Bin 0 -> 7663 bytes .../__pycache__/sabr_approx_tf.cpython-36.pyc | Bin 0 -> 11306 bytes .../__pycache__/sabr_approx_tf.cpython-37.pyc | Bin 0 -> 10661 bytes .../__pycache__/vanilla_n_tf.cpython-37.pyc | Bin 0 -> 6784 bytes .../volbachelier_tf.cpython-36.pyc | Bin 0 -> 5840 bytes .../volbachelier_tf.cpython-37.pyc | Bin 0 -> 5092 bytes .../volatility/sabr_approx_hagan_tf_test.py | 137 ++++++++++++++++++ .../volatility/test_sabr_hagan_tf.py | 105 ++++++++++++++ .../volatility/test_sabr_hagan_tf_1.py | 90 ++++++++++++ .../volatility/test_sabr_hagan_tf_2.py | 132 +++++++++++++++++ .../volatility/test_volbachelier_tf.py | 80 ++++++++++ 37 files changed, 544 insertions(+) create mode 100644 tf_quant_finance/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/__pycache__/piecewise.cpython-37.pyc create mode 100644 tf_quant_finance/math/interpolation/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/interpolation/cubic/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/interpolation/cubic/__pycache__/cubic_interpolation.cpython-37.pyc create mode 100644 tf_quant_finance/math/interpolation/linear/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/interpolation/linear/__pycache__/linear_interpolation.cpython-37.pyc create mode 100644 tf_quant_finance/math/optimizer/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/optimizer/__pycache__/conjugate_gradient.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/__pycache__/grid_stepper.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/__pycache__/pde_kernels.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/grids/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/grids/__pycache__/grids_impl.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/internal/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/internal/__pycache__/pde_time_marching_schemes_internal.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/time_marching_schemes/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/time_marching_schemes/__pycache__/pde_time_marching_scheme.cpython-37.pyc create mode 100644 tf_quant_finance/math/pde/time_marching_schemes/__pycache__/pde_time_marching_schemes.cpython-37.pyc create mode 100644 tf_quant_finance/math/random_ops/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/random_ops/__pycache__/stateless.cpython-37.pyc create mode 100644 tf_quant_finance/math/random_ops/halton/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/random_ops/halton/__pycache__/halton_impl.cpython-37.pyc create mode 100644 tf_quant_finance/math/random_ops/sobol/__pycache__/__init__.cpython-37.pyc create mode 100644 tf_quant_finance/math/random_ops/sobol/__pycache__/sobol_impl.cpython-37.pyc create mode 100644 tf_quant_finance/volatility/__pycache__/bachelier_tf.cpython-36.pyc create mode 100644 tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-36.pyc create mode 100644 tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-37.pyc create mode 100644 tf_quant_finance/volatility/__pycache__/vanilla_n_tf.cpython-37.pyc create mode 100644 tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-36.pyc create mode 100644 tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-37.pyc create mode 100644 tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py create mode 100644 tf_quant_finance/volatility/test_sabr_hagan_tf.py create mode 100644 tf_quant_finance/volatility/test_sabr_hagan_tf_1.py create mode 100644 tf_quant_finance/volatility/test_sabr_hagan_tf_2.py create mode 100644 tf_quant_finance/volatility/test_volbachelier_tf.py diff --git a/tf_quant_finance/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f62270a2217d0432792c6fd437446f2bfdb4adb GIT binary patch literal 1760 zcmZ`)O>f*b5S6rAt*rg9K=#X+H z`(W4^fn(0`xGm5quk9k7Fe<5yb#V!})p%Pi4DQ5XZNDWgyVP{M+!2u5@l5vgG zf+regF5G+Jz0VW#t+^byeYhXMtx_=4UX=&y(t2v~JFcbe(?H&}L8)zNhqSJ2+j?a^ zv$*qPow3%X{n9>h|7gFoPQ2F*)}7b(sU?TnChm!^J7$fve{rttSCD1U=Ux2$jn*`u zXru+I14p`2oPy$26mx=LSV)SPR_KgMqX#jCRFS4EVU+7I2oO4mnWAa~5JEdu0=A?S zas#mxQKrXK&heV>xzLTnc$iTn2a**t2pz`m5wt*F`Obo)40eqIv-PxrlLTsUPXu7b=7C(Mj0E*SWZK9 zI0hn<2T^+{6yydaF$c1Q5o)+<*^tRlaYk3nCFMyok)>TO2QSV^k**0PV@1~LK)m>E4y7T{=|Zzig^la7 zGXuScLMZyA?)|chakGGN`3XMQdUUjNu(gQ~w{{=z9c(|`dy1cI9X#II+bz9R$UN2% zlcUpe;o8MtmRyEb{_oj?jpHNJH^)D~Mq>KndqL&scvB=r4w}{Rz7!xf&!K3?I$eXE z!1Y>MpFA*us|h@tz?cCE#^GdIF5`OJVtA{`?Pun2`2dX7aqONwaD2~qdglO|wF~})Bpeg literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de4a2d14751d62ce8fffe26a63b46550a5e93bce GIT binary patch literal 1089 zcmZ{i&2AGh5XU#!G}(NAHf{MRx%SXpK@~y>P!Av>5OA?pwYIT0wXoNV?M>8Pc>r#_ z1Fy7KPDnff5)v~`gH%!0%0Iuc$1~%xpLM&f0KTtZPR@SUgWx+F+pi7q6n^$62n$HS zDy%9is!FOA!}mP1+MG(gp1m!S%n6q`vEs8+ktNxJ&z3yn zCXq9hxQkg@WD6&BX6HYkRl!lE>?h||%ffLgRIZJKsfdY{u;2yU%ZB8yF4hlS`z%)=Ikg~oh*5GS19Ta?BW`NQMd3|(HHYkNql$I?DopFWXl$t7fgeWx- zvg=a%3GaiZn~Rv^1>Ba>G;z}i#V5slYtE>>ROedSGNLp~6dd$hVD>Q@%CEEMC-Dc% zjg4PHw}rcUskvFkFRmMH<2Ob_IZBCa8N2k@cjWlGBQSBZMKQK0rc^*AN};?mdaN`n cB!7aZu#Z4$)lLP*Mv-ogYA38#{vGx34=UU#0ssI2 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/__pycache__/piecewise.cpython-37.pyc b/tf_quant_finance/math/__pycache__/piecewise.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f801b83158d1836376b207e35f4c16018769b268 GIT binary patch literal 2811 zcmaJ@&2Jk;6yIHYZO2X14-gc@VMH#q7EDU7NJ5z2mpD@B97U^L&2sV$;F(%ggN_9$a>u zKlQ`xs(|4+S9?`M`-$JHu@zQlji23Ko%xTQ zR`bP24`UwjqgZlMs5pt$G3gg+q~a`fc0wDR&-SHG)bufi&) z-idv3r%x{4`QUa~mHDR?R=eh$_{#aMHgV5fR{y{;J2i0C!Brbzk2Ov!Cw1^NaIZ}K zN$t!7)r5umnRn)$G$xw=!UXRRRu3*}tI)avp0$bQyabt*GjHObRUSLvI**+19k!x# zM*pfg&dxMRL}jEOr;Ml}C-~)KlJ%z#ii<;UD*05-RPd^ z?bNcQZHV_lGcF?$?{h}>k7wrQ>Z}Gxy%vAgfx<^z6(U`T%tm4(%?oudrVjb4PsZfV zZS6suz;{W6QNo$_kRng9=C}n0gtF0Hq9l`?g_=`xrSly=5d{ym zLhXtcm?vpD3D2~U(Urpu1WzTg>d5stjgo@J>A+;m6k~mToqRE-qdeidHend%$7-0R zpyv)H*%24PSd!c1>1Jo^W}9qwuyi{JXGH18QE~Q06Fms{>+4Z@!_NYxhG2abZK*smw%ZV3-~g8Nc9do8c)q$0W)!ft*prCFy6vXd?i491WK-Z#x0mN4fSn zc#D*E$P<(c9Z^7fRG?~jBbA6Fl^jo1p(=1jqAVJKZ^--H=S6ol3?v<48Pc2^m@##% zDLK^}&axOTd0|kf+ed={5m1FrK@s?JG*VHa(6HL0x8QSILw^~cHg`+tT!!P+w>c=S z0ps~L`6kyhSl31MJNI=oa9!Id@*LxX+0xiBQ3~=pLLL7s>~oL_tr0@*^FGy}GxgXe zyBUJEg&fh`)J| zs^c?#XXnfmoOg*bIJDImQ56jV7gJ$VTnx#DP>*6YB*wYh2=&Gm5Sl6)rvQ*~OUnU^ zaReRznadajb6(r7)9KtH;YK$kBTiFm*kH$~GvnJ#Z(tW$2f~tM-j~uKFT@OfEe%9z z9~J~-Gf|B?GrG=CdJHE7`4*s=K^X4PMDnmjPK=cQpd@fhl+_lQPm8I05^2W1UOa2J9)2hAl0KN4c zc%@u9@d}(6M@49DdGwpH{hz;mv0gU`jr+UvZ!e1^`4y9YBPV!6%kLzQZB7&f0K=5n@*4T&RaDG1gQt>0+nhZucW6##HWL!d$1o(AFokm z(T_XX6O>9C?F3{tgRDTv@I5}h6c<@Oo{ z_#3^m%1cb}a-IIguchc4{T xW}{~hMyYV@yo=7eBj+7}BwYY9JJqkW6{Et}r_|d&p-^P2lxB?CD$mj~{|gA5tZ)DT literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/interpolation/cubic/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/interpolation/cubic/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba78ce5db1d54f178f8387522033e3518335e296 GIT binary patch literal 695 zcmY+A&2G~`5Xb$M#EG4>5)xM;amt~7fC>lN@EA5Bbk5=uq55SFg z;FWyk#4B(>%x(%*YOfFr6rqmJn6Pp3-1_kIcVcBRZ@P# zEfyoM27~uu=T#rBV`j4TTu_ASsWHRj=~Wze*_jS!Fk>?boF{t4{T-k)6A4p2VQc zrVk4^L^%3mCZW+hg#VMr7mg{b%}(gsX1K%ssKz@knobA^U`nhXPXW*RmQk>Ga;t?M zO8|vt0e&RrB(x0Sx4AfPKU-Wt`;jxn-Tep6%)Wj9xB=T<8okFQNv`&-+nq%-XOCtu vaqO-Q?%E>{ZFJWHI^zxiC6DDRsi_z2%?cIR=NO8tPVqg&w9d0MOQ-o?Ob5^N literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/interpolation/cubic/__pycache__/cubic_interpolation.cpython-37.pyc b/tf_quant_finance/math/interpolation/cubic/__pycache__/cubic_interpolation.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48782b6ce8cc6db19d3c8e66eda405aa6f2ba33c GIT binary patch literal 8972 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 G+5ZFVuXM%$ literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/interpolation/linear/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/interpolation/linear/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3a26912715645b4eed56db4b06d1554bae194fc GIT binary patch literal 585 zcmY*VOKub~5Osg1r)Tm*Labpsi}V2^1QBEvq6i7tv@A-_bj`$)Ka;XMQL^O#?6^a& z)LT}$0xQbRplICc@~g6|-h2LVa4;9Ve*HZ8J}rg#os$2nU~tNR_{yOZt?05YH<``b zJWIG>T(rfAOU7kej(B1wwrZ;pS7vJKwq`tCXYCAYoa5|A>aV|u#q8nLg?6aujdl@f zu(Wy z*ZE~{kx4q5@a)UQ-Y^B=D!?!Y9ua#&0LuB0l5yhK5bgW8f}36?677^*Vq;ajZk}0^ zS~FVMZm@GUk`1pTy5MPL{9UuTkJsGOM{OEq3?x7ma}6(mbAN{&gnN7CO&Dqbr!32Q z6ttf-rSK$~3IyF-=`QYiENjK36%s`v{nkh2j0 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/interpolation/linear/__pycache__/linear_interpolation.cpython-37.pyc b/tf_quant_finance/math/interpolation/linear/__pycache__/linear_interpolation.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f55f28b93f564608a3f854334dce2df1ff0a2272 GIT binary patch literal 3636 zcmd5<%WoV>8Sn0SdOWrhuk!*9B?U-Eni<9MCV&MiHoFM%PzakvpjkstyQ^lVcl$+E zjXjRq;=(mrPMnh?{{a6AQp1e{%D=D|_?Uw!qx>wC1H?Cf+LT)+SP z_*Z|r;W&S##qz2H_%3es9v<8oIo#!5>?YpGa|x~iu8nF2t^=-*>IQDajZu?t@fL6Y z)*ZEY-?JF)ys8)OYnRtS>zSQeMQiEm)v6B4M&a_t zYwxlJy5^^?SM8!T1uwKdHd?n}jl-MR?eNyi`el11y?w{I+`?+RX!9*d=vcTQc)RfU z)*T04kgYZ7z{+qs)~?&m0YY%u1s&uR^%WgfSJ3T1O83=x}}i*V4n z2fjU6y9@YQ1@8gAZeY*g_bZt2?-bXIYqy=t1K_R|onrfmQylQdEj(Y>E^ie3h&T3& zcZz+owz%!Yq?K zN&_tv3#35uvhl*_feyxoWPD*4eF)UENU>#VGAZ<2rV2vNf_M&gvSTsW6ljEv*;y2@ zJQATekCcF%tGqB4uQVrfrP--qO3NtJ@deBZr3h4%PTA>Pv!zvxXX!o7QUT9(MjWRi z4Ce6goD|tzDSkbV;F_L^we>-s%WM%PaGbN#3)%#ijgggzTc~>=Q;7(EV`u z*j_MW0ISI&#ET*|eAifZ_-OdPkVFB{@dUX$;-7AQyB%%Yw4XVlmOa zinClCvyV{>2Bf;7f}!w=-r@GMdi*w@^%xE*SGGRm)HWi*?Zdzd~Vrz9JST<&W78-X1U+3MJH5k?b?r|R6P$Y>-{M~>2bPIIX`eWW6{ zXOspB^7NVMu`~#VCT9tYZX+hq!uEWUk>!ffd|37JjX6cRS6TOOGmsgn_v~Eq-|83l z7-U(aAmt-F^K8%imqxPD36Q!HO)$?=4A&{u7}>d4j!HWi$C)>)V zow4{rY?#9#z*PAgd;vOTosI)cbro?@wzIkRDaLR9j!P27)86&c)0478(tH)72b9-Q zUS~prH1oCThGq9uW&sZaMM$|tqPGL3h)4$MXJykinbJEuEDyl0WfuEf*9x4bYqdFJ##`$5ZrfmF}W!+5uNK zZHF9n)(JP--pDf9HvW@aqidGOkCd_2KOF7gvq(ssD33y+M%xvEie89OGtfRPuevt)+zJN%AjG$V;C`H)Z-`oA-&WAA6d2mka%E^nUF(UJvs&4`rC~gpOh(;FjE^!O zqOdBv>vRZW!Pk(`jLCc12T-Ij zKr%cLw0lf`H7u+pn3hdSu_~oyo8s>H!UCnX8Zv4@>L_I2gLcL) zq&cH&Yi4XFr10Bpy~P>m%v{U`Y&7-%|B`2ZK~D=7W+61wbI26)tD73xzb!?twioOS zP|7DacCIWGUdRlmMg!P>$Qp(znlqfH+p3w7u1qP_OksaN5<3mmg8W$>ALXAMSeL)U z2?&4w*5Dz?Uteyu%TKJq%~d#%W$qV;(fr}1c?{g`CJ)`@*E^C^iU-V7ibl)yxiY+v a@FMtg8A`p{t>As3fo|Sv)ymzwQTq$RG#`=x literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/optimizer/__pycache__/conjugate_gradient.cpython-37.pyc b/tf_quant_finance/math/optimizer/__pycache__/conjugate_gradient.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3de122d0b45e1c1369a61f331f62c24ef8bccb80 GIT binary patch literal 14039 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 Qs#}(YT0j4_>Psj8A6TN;1^@s6 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/__pycache__/pde_kernels.cpython-37.pyc b/tf_quant_finance/math/pde/__pycache__/pde_kernels.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..144dadbf4dc29ad4933b508c1fae2a74e4df557d GIT binary patch literal 13140 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 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/grids/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/pde/grids/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c9b1accf54b1e4f045ea2cdc617b1ae4d1d2402 GIT binary patch literal 818 zcmaKp%We}f6o%)LWG0tMQnE%AiA|6?D^?Xk2#SzELX|2u)`+8N>`W~AGPOMk?Un~% z$BGx=m1fI|S762Qq!qNPu;pK$kL~00+pn^06kz-I_4w1XK@j}(lbeSjLzvnm5?dR*o;lT_&Oe(15x z-lg5Ee=+g@3)@GIDXYy|=v`i4;?t|Vaa`o35a7X#@xFErIM+Ky!CuO9Eo_?ts8V8S zKLT^$>+XqmCad(IShSMM}4RdI4{-xjAvSEiJbtEzD8qt3(8wFeB`HdT02 r1)3^4Qw0FWoB&v8n?9GCHiEsF;=T3>N-vs(*!Swma~y?#`yl=U#qH-| literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/grids/__pycache__/grids_impl.cpython-37.pyc b/tf_quant_finance/math/pde/grids/__pycache__/grids_impl.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f610b55eb4cead0445971eb82510a6f1bf84236c GIT binary patch literal 19311 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 HDdheiCr(+w literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/internal/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/pde/internal/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6dc08485a8f8d4731621524367755314993df8b1 GIT binary patch literal 194 zcmZ?b<>g`kf@%F$aXw58439w^7+?f49Dul(1xTbY1T$zd`mJOr0tq9CU)j!9F`>n& zMa41RnW=f1B~@PesYU5AF8Rr&xv6<2#W4Xz`RPT8xw)Bn=`kf~x`m~Qc_q4OnR$tM z$*Dkrc(6b`OdvP0BqOFEB{e29uOzi7FEJ-3K0Xs@Y<#?4LFFwDo80`A(wtN~kRv_= GF#`afF%+! zD|5nV_r{GgIr2aF6?5gpU*JSlkB8WaF$!&UZB0L_zWS=Gd}nU1ZNT{D=iYbAp#6a# z^>9GB4O4D{U`F3yCbMEQvHF&Yx(&MBx3%to?(`k4yRqAEz z9`}B<`z_{f8J*Vn?sk-LlK3Lni_%>pgFT*bNy1E!FiIoE35&vz3!VmWjH|tjRlB(_ z{9zVH0oh#pQg;6Yct*!8FZe^5#f9QDO7cu7Sn^o3AIT_7L7&e>lqwn)X`o@SC)Za# z>h#F{Bp2B}WHt+m1PuC^3Pg_)ox>eOaFzHHp#T&6T#O(hUjwR5an^-X0lr!s_-nyj zg(+VHacCYI)Ht+2nuj(>$Ry;<8vlMD9$Vzc(U=R3oRBZXuIzy|96AlO;*V;sdSv4t z*7X8Wna<9L?3_Hk17skk=dJX}x=!uRi*ID7K3^s7*lmw&={%Buzp>G=OIL#_XHQ}% z=T2GbIHei)u9z+~S8h@2>u{&5hPM#cW zifmW-NdomdP~p?NSy7{Q| zD11hW()R(BY=AJlhS@O3@165vy7i^?07JroF`v84U#z z2Oa2h3__D`&YO-o{_H%`^}X)RI1Bt(-s+w(^Z&`gl!| zr{j1XLB3HVec9+RTbi2{P^x&^SKKS^_?`cZ2mS%BcN$n+sSg!M%QmG+#)=sAS&FqA zAMZ3Ng)U2}n5*4Yv|>J<5iIbLT&{6=ZO8I1>9tNyGIwhM;97K_soWYJ7=~M;i40Sb{6K+yIIA23)3QzPRE)x;m`7{ GS^IBFq>T#z literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/time_marching_schemes/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/pde/time_marching_schemes/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68a5cc6d3b950ef5ae9affc89ade267b19fe911d GIT binary patch literal 1019 zcmb`F&2H2%5XZCM+0SgZ^a2v>4fW7GK!p&3u0%ngN(CWV5u-Hr?ppXG*iLub8{z@D z@eJ@vxpLwaI5Ey{L6nLUi8A`xGak?UCy$52UVzW%Pls=r+#rpLo5)SlthgmwvQ63*w?#*WB&@iD+$G(LL*yRmRoq4HlYYfL zV?ITnVY5nJbiXWacheP_0I zCe8IG_ODwbtohoByKfj@EFGiATi0xx^jE37hDm+Spioq2g=7kYO$*g9ZEyUnP3TS6 z8~;<7KAM;Nld=PVX8_6`pd_v^48YWVM8lgV8uHZ5;eC;M(YQ)g#$uVeWt>wM`$@pn zB(_aj?}3{ DnE5j> literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/time_marching_schemes/__pycache__/pde_time_marching_scheme.cpython-37.pyc b/tf_quant_finance/math/pde/time_marching_schemes/__pycache__/pde_time_marching_scheme.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1ea092639385e9deb08bbecf9eaff309fc9485b GIT binary patch literal 2830 zcmb7G&vP3!6yEi(IB8R8%Yota7%uUUxJ?Sf)I*uNNm~ju?a(kVZeT61WLssuyGUB+ z$C38HjT>h;^7nA_l@tF0Cq8L+9j6X6u$fh4y_Megz4z%!_tw|fJUqYr-1+X-WzYN5 z{wSY1I(PBvZ_seB=W(A`B7aipReam8qF?P*UB8BYtygpXdQ|V#VXsGxUPCl~T@m#c z&ENco9&hlKR~}yxt1qiB{oWd{Kl576)9#)a%2;SJV?i=DLJe6cXqYH^x_6(9oCumQ z6^>;*A{~y!#D1HQoTL%@v1$JWfL_a=y}<@Li83Ps*b-$h)Z}t1wM=64ucQjg2g585 z4Mz4uJFR?b=-kDt361c2J{VWH->Zt+i#m{3dF_=C)D4GvWp?cVxE>d`2#IzzA(8}lE8tH5j@``^dAi&r<%81F})`v`M|{n7BeZkk52i1bBxY*<;2 z)FoodB8QOZ(UAJthH3RlYSJkZw8f3eW3D&8E zbf!XSMiP(*Ed2h6DX#Avs7&vj>n z#h%%;I89m!vq6GSN**>rND-ikV`de*i4L+5N>hlL!bCwPX%ch0#+=el3*3srW z+9GhYvDj|8Xn=5mv#UnB<7N>dVVMX+c#Y8q%^W1bMTfo+ zT8nuq%~9gM(8TR7bwUP5ZA3bsv}1hzSJ6R=4WFoq0Ob8_GRRkPCYqZ- zf`&|$F7rGEA);lv>=JqaxB7f-pC@^>j8U2PkFAg3T+!f}9JUZ8{jAal~q4mWtwYeTHI^ zX=B-F2FWwGUjIx=5L(X2w&(CXZ@1f1>$q~mO^jo^$x)mr!OK;mLeJ(3%Nr*L6EG<81)ZajQS-z3vLdi&&^3H5MND;NF9zNX~qT91zX#3f8GJwbA-Mu zi?pUasbn~g1Y%L3vpV9^Ro!CSIP`OS$tg>brGMe1(JL@)LU$)^Ob&-pwiC2!hxIHH}WHsp(0>6&VkI&Tf3>8@TQX6J(kx1-71Pu zq3*H{m9@u-NR!Kmn_~r*ix8PRli23DFxce_1SpJIWUK^mVnip)^=BUk`}O_AJSuMk zg5OsvQLWWkO^ayQTRZbItC(%PJH6`{RG;3p<*L%Vx|Fcq)umj|R_EdT-BXuv?Ed}J zZs+hTlu>>7xfHQ9r=KN4jSlyUb6g)jRmn)P$pnNB&2S5cUTn5dU|Adr3OFKQ8)m_})wHJa48gKLT?SrM8OWS>fP(Em_%$h+EBTYdt zTML3o!n4TsF9#M=R9IGm0Cy4$SJ@z(UBSJ}-Fxx_UaiBAi^D>L+oh-MmGT|D8g~(| zS+7-Ut8T1yNnOQ=bvVpW0pL(sw5n5cG7ogcn_ulSf{F*hA o!3$hN+=2^^Z9bIsK5KrQv-#vr{L)v@)GC*K{8gHMv-+0*588Bp&Hw-a literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/pde/time_marching_schemes/__pycache__/pde_time_marching_schemes.cpython-37.pyc b/tf_quant_finance/math/pde/time_marching_schemes/__pycache__/pde_time_marching_schemes.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..534b0f97d888247b5ecd0de8bd1b9a05efc0c906 GIT binary patch literal 9652 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 cWGE9V!Z literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/random_ops/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/random_ops/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76bbadbd032684a6f8910b883e7ccc43acd2a8bb GIT binary patch literal 867 zcmah{yN(kv6rD#hnYhZhA7KRDp7%iMG3{h0eLYv~EC6?dBmdHkM zwJCqW2+=C;=H%RJ(K?2?Y_xHZ$|>J*%e4YNYYbNo*R5K+Lnhl2;Xct)yxS%N z=oWH!ycGxi%;df{1bDl;*9|a+-!Se*7=*gkFpN#&Poy4t0H|;^1|$3^ToJWqr6g`! z9+l|E-nK(e?mAokXI?Y#y~ZBAIP~bwOaA&12I(F;rmQx#(3fSicU!H>)^Sl1A+RUL zzsqicA=a0SV!M~%zU^|16_GIVkH{>2dk??)%d_gUWyV%-I8)qRz1GZZs#iyQZS~&h zjUiIPTc})p8oW6@dIO1n&8oav)vZ|-#vCri7?gJTQ>key*s~clwhsV$$s~q-K+oby Kn#6~lrGEgmn*-JW literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/random_ops/__pycache__/stateless.cpython-37.pyc b/tf_quant_finance/math/random_ops/__pycache__/stateless.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dda42908602d0c4e42319748981d0eb839006c4b GIT binary patch literal 1515 zcmZ`(NpIXX6sDG0JarrdFuEKH@X&(?7!P9C$YIa~&C)|!z{ujF#dKOp7O5E;lBkkY z> zte*hHml*m1CPv1DdCbqf!XNvdqXW>vIB4h)bT|$hx|O%aZPsON*7?;NcUbEs>F>P$ z<)ujs&$-rAB_)#um6aa$dQXcg=LIhf)w1AJX4K3$)f-_*4d~@eq%&G6$?BA^&zE&^ z&XuMKz8>R-t3s4Q8k09>C|b?*|7IFVjz9b-cHW7%xl9VQB+bHu)0jV5*pH= z_bMey6RppmrVa%6gcv&*k1@2uWXSK{!e`!sEWD|I6TE%ofp_6A2=iHR?Y~*BJQg-9 z4|~Byh*PZvx$#)*6EgJ{j@xGK>)=iB9buj4Fy!`j4ifv9o+Z;v6npe z33;|eL2qHS0#wiHEXy|-9%)0F0JJVPheT3RQC78~XW&T%@F_i;2~F`OTk2i`)zy*M zWW%NQXr(^KkPebBGW)KqFF8z^Esp&;@-&s`&d({9C7c29vwc};OLIKxJT~`ErD)s;Vh{* z{o(k>VPmWWSR?wZiJivUsF*qyaO0V{;*1*U>Vu|=qiPsEp94vxX?-yp9A9u#t8(T3 z!<9Fi3UcanV-@8_nVG{rN+sToGj`tCkN*!wySpun@(7)i_JcLp2w8ckg??aLjVT*C z7;LMtc6!$LZ5z7Jb8f@rO6dNM^-X4bPD`XyS#f(Ol_l;QfR`)mZF{NS-uch1x)hmI zg>n^WJFAq~_B27SP_~mGiLRDI)rNp_Elr`Dk#To*Q2#;HhhY43@pv@(R^xt8z7f0> z=JnT-tLfy4Ol#MJ^aRy4RY`$PGM$+0@aH-y&0!|Wq)a&&QNxJVi~3gUBuI)q-lW7#$UWBHDbn+-tC~~4)<58~b*xvF^ mBI--E=eSOB6VBH3k(2CxQJ_QS{J}m}+QAU|yB=P@8~h9AI?>wz literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/random_ops/halton/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/random_ops/halton/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5841059dcd5e39d274a964123e19c00bc496b79a GIT binary patch literal 560 zcmY*VJ8l~>5aoWfTFGA^2XI;y-X@)41VQY=uz?^z>}Ek^Kxs!30e&_l*M{Bt0PcJT zUuoM^X>x#69hHe&Io69HsG9aUgrZIsgW+~V!(wO>#{Bhk5@@O!4ju9d5rJNA8a;xIJ^)lSo6^f z-70BT)gPM0W=Ve_=H997pPP=@>Y6j4dMOPNfTh%nMK%Cih%;D_ramIw+NkS z?4r|X0yb_$wBKes{TP6%0R0r`b?6)dxRjbM+I2aF`cqiKuTDgMX@pr|rA1g*P7t96 z+xlufsNP;tp&ADCM*)quZmH~D)!v7-HB}d+s)SMyfh&l=KLpC{9X83p^<_Sk{$_G2Rr7*XR6-0 zX|BGz$xU~SSEjejyuQvgxEXFH?`OGL?x-tMTaMybqnquH=Gbg^jQbqNj?OjiIL6I! z$GYR(=iTuxa3{DE-CTE)o9BMS&36l2tNVgm=oY!fuFWlROI^EL=9arJx|7{0ZiV}j zJJqdpr@7NzhdaZa>Avh%xv#j@?ku;)o$bzXUv+EU*W9`8>u#M}?>4ye-1+VTx6xhb zHo0%Oi`>O-v)kgfx=Y+P_f3~^oi6LPyDsNk&UL#U*Xu&J!}Ym-H{kNF;0E1JS9B#; zc0=w`H|#ERyWDPfxf^k#?nm7o_haq~_bs>AUFoiJKklw}*SKrlPq^#cPr7~Xr`&#b zy}QBvw7b!L+uh{8<8F38<8E<3>uz;F=WcU9?{0T@xC8DN+@0`DP z-Ba$5+|%xl-81e_+_Uaa-E;2G-1F|w-3#t7+>7on-AnGT+{^B--7Bu*UUh%tzU%(h zz2^STz3%?rz2W}Bz3KkZz2&~=4!VDGZ@YhX@3?<)@4A0=@40_-@4J6@AGrT;AG-f^ zAGz=^8G*c|Lw>^SW6*zs6^oq(N)&Bac_=3zgA&BqpCt=Jc^h1eo&G1i7H z!Iom}*fMN6_C@Su>=bMT_9g68Y$bLYb~@I9oq?T+eHmMYeFa;MorSHz&c@EczKX5I zzJ{HPeH~ket;aTC=V9k#7hoH)3$abuH?WJai?Pkv7Hlha3APRUCYHfEu`IS7>%ttC z!@98^tQQNh9ataMj}2gXtbh$-JFy~G!phhXb}2TDU54$#c4L=gBiJbRqu3to$FM7~ zZ()0}E3vDvAIGl7uEDOwegeA=`$=pc_EXq??0W15?5D9Cv2SBHVc)@S#(oC71^Zd- zR_y1n+pwRU={3D>~FB|Vtf-@7M>}e_$VC|A~EseINT6`!DPh z?7y*3uQ%x5pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e z-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>Tr zH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@ z4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4! zgZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws` zpnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy! z=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F z`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek z{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD> ze}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e z-=Kek{tfy!=-;4!gZ>TrH|XD>e}n!F`Zws`pnrq@4f;3e-=Kek{tfy!=-;4!gZ>Tr zH|XD>e}n!F`nTxcqJNA2E&8|U-=cqu{w?~q=-;A$i~cS8x9H!Ze~bPt`nTxcqJNA2 zE&8|U-=cqu{w?~q=-;A$i~cS8x9H!Ze~bPt`nTxcqJNA2E&8|U-=cqu{w?~q=-;A$ zi~cS8x9H!Ze~bPt`nTxcqJNA2E&8|U-=cqu{w?~q=-;A$i~cS8x9H!Ze~bPt`nTxc zqJNA2E&8|U-=cqu{w?~q=-;A$i~cS8x9H!Ze~bPt`nTxcqJNA2E&8|U-=cqu{w?~q z=-;A$i~cS8x9H!Ze~bPt`nTxcqJNA2E&8|U-=cqu{w?~q=-;A$i~cS8x9H!Ze~bPt z`nTxcqJNA2E&8|U-=cqu{w?~q=-;A$i~cS8x9H!Ze~bPt`nTxcqJNA2E&8|U-=cqu z{w?~q=-;A$i~cS8x9H!Ze~bPt`nTxcqJNA2E&8|U-=cqu{w?~q=-;A$i~cS8x9H!Z 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 D1BX;x literal 0 HcmV?d00001 diff --git a/tf_quant_finance/math/random_ops/sobol/__pycache__/__init__.cpython-37.pyc b/tf_quant_finance/math/random_ops/sobol/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9fa55d3b4618f153f8d557b070273b5c0dbb01de GIT binary patch literal 556 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 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/__pycache__/bachelier_tf.cpython-36.pyc b/tf_quant_finance/volatility/__pycache__/bachelier_tf.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfe2982afbcc5b17287bf2046fb52df7887c1a78 GIT binary patch literal 7663 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 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-36.pyc b/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0617a5cbd85a35013d83de6fd64e253870657025 GIT binary patch literal 11306 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 YZq?0e1T$U2yh$xHoc#kOnf>U$0iZ;Og#Z8m literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-37.pyc b/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f3e61a4de5700fdc9075aa8b761d108a3ab7d15 GIT binary patch literal 10661 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 CeZLO? literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/__pycache__/vanilla_n_tf.cpython-37.pyc b/tf_quant_finance/volatility/__pycache__/vanilla_n_tf.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8f0e8abbef038832f67589550a93d26609b84df GIT binary patch literal 6784 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 literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-36.pyc b/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..303dcb7b02a1d0f67737f0e491d95d2e2cdbdb57 GIT binary patch literal 5840 zcma)AeQ;ex6~Fg=-uLqL+NMoQ3M?u8cx{t5FDZKppT1a8UR7p10pK%G?5$8yrB9(M4HVSAfS|#V z&`7v1LW4APNa>5xFpU7!Xq0L|V>CwNK;yKA)&i}eb+jI6Ee-T4$p-zCAUxj14c##) zu}Wk!H%X6mfTU8SeQjqd)!E)bQmfn7$K#7gmsK9)CL4C3C$*YfYZ;u8Ev8X2opF4> z)yx|u8{||<)ZoM!Hb}Ot=YhyKE6Hwy+a{<4R3nx6vO~)*;mBhA&oKc+{pqZMs!_C18T7BAD zav1~`J#zrqOD~a@Y%l5VZ6UdAZ+GuXkg=zG=QZ1Q?Ie4$J9cDyc6M*-CEIq8u5CRV zyLWbP>w(s0lI^*kZ0YXVxRMxPE7%m{V436mVUi}=(V%FwUIT4i-6t{xud!{Hjl4Nz z=3!kWR?(S3n03J5C0GtA8@y=RxSKXikAjqfSu`Ep5k3F2sJ3`KqgR|^i+7%boHKxG zr6(Up0#7}Z3!rpCv7ZNcI?9MT5^w{PsvB%lY7{r*2Iniy%0wLA1l_nB-mkb(sxDA~ zkJ5moK}kcBh9!+i8kJO&G$v_$fzqfneQ1%oBcNN8x;3d=qrPs9`nomh>(;2R8_uTC zrBPqEMt$8H{fN5VnA8}P8e>vpOlpitjWMY)CN;*SM(_$^2H+b$+G;0*lfj9aX?xQe zVe49HvpPxZC2f#2A?YkhXMeD^X`2f98ujIC)R(VOU%p0t`5N`*Yt)yo(GQU?q{gJw zn3NimQe#qTOiGPOsj&}}Dr{5h*0{BR$vRkrIudf#NmX!Rx6TDDO{&cb_}e+-7m#72 z07r)mRZ4k0Dsgl|qT(tb{*0*5rivxMFrItE0? zz*NTps{r1nU^-*{zz*U~0}hQ3I74maF)xf3ZbwgIW2Mwz5QwW>#d0tdS9b%qTkQ{O zDqjX~^Jr*%(70$X;eLJt3~r+fS1lZL#SP4d8jeE92_RTuqtPvenqh+{!fsF;N2KTg zkfH-XiVgrNIsl~T0Fa^sKnln4gPhJpgo2xcaW!&09t>>b!9a=!11TJg^U0Zrg42vN zf}3o{^#n)42v7mZ#0NoA0!&c^HaWtQBP=;uiz6&K!jdB_Ia;oYNRIgA2uqHzDua*Mm zZ+YrUU~O@mMCYlEYQLIMc`Nkg@o3?L6z3qexDOby#Sm5PS7^XhXb?&RlmwJnP-a7! z1EukNruF*}7Bwg*05=kFXxzylocOst?B>RYuYP&_P+FKz8t8PoYAMMq%SdM36w@J@ zPu)7zqfIeXGVk6lnZs{MX7x>yx%*Ux?Gn#pY02E5W;Z+?J%g!7k^&s}|6IvJYYAh9=I7`#P$IjM3yN9Wj_C!wz!ij6=};D~jqqA!nN!3QbA zMOYgpxWe8eaHJeKKmba#mD-5@G0-E8pk$I^e;NWE2nVm3{wVhvx zFD}Ar1y+y~D4bw*30CLX2~We-o0e1Tg%LKMMkPRCL*}cz1Nb~1SA6iORpI|Q90uPA z2wqGm?g&nVMGszJ0Z1#bCn9>#=LKj;^h8BZQ1paFk0yFTq9-DHV!(s1qY&Uwk$_wB6=xZ%w|=; z5WxstLYLBIG)b4!6?7$SrEPQ-T}|6*igwU7bS=GX#uvDmL3%k|N7vI%dIi0bZlG7u zG|kW~&CxEpk#3@!>D4p7!1)E~HC3JUqTO9>H;DGN)pkO(w^Z9WTS(5_hDo(XnV3zt zPRs$|L;z;tMrEQA-lAPYBT=^zZjt)^ilYInw8?-Ia~s{+?i_5n4Q|4ng4gI32iq$SvC1NxZxaE^9)sw%4OcbMiS0nluX9Rr+!`%GI!1~X4xP%hAcH81 zk083Cy<`KiO;*$i-6J}u@(YnA6vp7XZ<7Nc^})nL<|Z>{5BUR#0x2cZNwQ?$PDnK^ zz7O^3r7>a;>t&;j?1XRg70w}=@W(pCI&gj(12!`KJaB4eWXcGTmHF#lh8i}sC#MYH zw_Dqjz6mgE+YfSZ3Xn7xs`KzwPra7urnDaBfrEyx3eqhM_`m>=3DWZj!Ufqn*jTIx zGb=)!u`-&T?342M`9dIC!B4#TPNk}WoOYS#y*LpeaNeeQOP#B_#*q+N{t_P#cMNjRtfdlDS9n4BU)edf&G z2lsehgXu8&ARP~eahwmdhkOE$(HoO zm;-5ZPPYNj+bt8|xVsvywxF=BW@&$C_1A|opqJZiw#`dz@B_yx+bVRdlAZaXVj5y} zhwFJ~z@!^eYf`H(Uwe5x9*3|U(3%W*VF3{@R06YjQHc^SDpBTXQ%Dgv4SW8{p5LFH zd?d}>AAN3j^7(LvJ#=E^#-?vB&aj8S)3>nqB+sxbj$OCC^7|thcK4j|Hy?cLaE3j$ zX zr%zwk#jg9+iSJ*y=un1re&t)AzxiY=%T8W(<2MqqLs_=>lGl37=l+^yM?(B1V z!9)|MZu`r_IX1FH`Qu&W4>|V6jhzp!_$*B9*>&3&e9{3q+m2rI-%I|UVcwS11CM+`&$2n|QxENZ{kvHf{m$b1moI%U z%esF1z{QytF3quZFD^dwgQwebjDPFrhtK@=tu)*8HFo6Q!%l|rJ!{__d^ntCum6KT zb7y8C%idX?-um+HFK1ct*x~OcHa?wYKYjYX_`(-{l4ZlopZ&z29{*vMrJF_$9UHqV z%f6V2UHgZ7Zp*McpZe+ibx#=?w)ojk^*{d9@eH%99Sfhk>~9&?-_-K*iT3$fw)^<; z@qgU8B+D*)=4Y4wj$D*wZ*EKfhwgnR!%jST>Q}#YU)&&LNdUw%O-p*i_ui6bPjuG? zR^0Y@n*IEH$Il2F z0WKm-@N)x<<3t>joacoR_BOv9x;$;lmGbq_?2Gu$g|ESP5&tCcb@;7FCq$%mo`9;a zM&`B{KJpZfpANvL12xP>`sT^Y=^Qt8PGIacfbW`iWRSeVw>HL{%Ehx)`4^0<5%E_K z*{IJ&)CBM$X!+%wRwx1Q;V)3HgaWmJ*{Y_J5YK?rWStis7@$^uV8A!vD(LhYeJg{F zN71pAb*Jq>%8U4{7dVjeqwH#MDq?pLGz()3$um|a0`8?KSi7=l(MrL%3IlW-Gv-i8 QQ)>fSi&m#aw2)T&U(^Bx+W-In literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-37.pyc b/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..add1ff992e717f21db75d3cea120dae32544e90c GIT binary patch literal 5092 zcmbVPeQ*`k72l8dvG3*UkpvP5!WupwkYEDgBZ}`MfC`8R3T+4`n|C)ikGwDM?gJ7x zwj-Is)T%hN(-|FR5p`UP$TpQO<_>Bf|j>Ou>3?EFM#YPlFMb6dtB~y zxzFW(mn$w0xI8#ss1&Ncv$?i?U|Vr*E3R#YIJOny*j9*RTOp2Zg*djsFWe@0$K~JC zwiR$K23(5)*J8l67;r5HT#EtMV!*W+a4kYazTa+#( z@{r5NxV-$^t&RGW>sN@QUm=cug*f^Z;^Gu&xb1<*SosS0t`*<*r37#LdyWU&hDjzdxfB&^up97`s2R*ggBf!JQnfmM#x;@A`z@vo^a$ExsaVrQs#Bi(izzt>zM26;p=7r{i=7*+03tY;z z&KSa?2wf||jRX=pcSwd4A6!jutK4_ZnZAJtcc1H^(-C?zfA)_E4@c<6$Gz}>e}vBC z&+Z7_{qos&XD+@gLi^26PQGx>j!4)u>OJl_+Y3jzAr}@Ig8U+furQ1*g=S!s1i*i@ z$j1^GNqmrF7`ZD@gN2)b>z0V7yx9YY!HtNOn7pLb?&5`L*y}8VhYq7=i)mZRCBqV% z1wAKp7X`-;XS7{2(<@+t!R>D8o{F{yO&Pw#H_CPo569>pgs-_0Qve4^xP(KF)!+b@ zA)^~AWW5G<8NQf=WHu5gmjtFFxg5zQB4I1I`()NkV+Cd4Q4u5+0#Yrqc_1e+2>9SR zC}8sdAQi*Gg90HT(p_@Dmyh7>0@W5D@$nH%ND@?DILFUNWIp2MBMKk!@DU#$34jcV z2x~K}%djRRrKF66$QV*iDk$D$5~;jP!a56PjwRzr6{#lU$plhECX&m@Br=((j{+x#SAcKpM$BGM_Y&1s8k)!Gtdsl0{@O zX(m^atH=^^HHnZYiIF&IAxp_JvYcFV!56qbnOs}2S<3s@75ZhozoO6&@&3v}A6M&v zL|8T?776|3WL19!0LKR~^HvJ|l>jdEt7p(}RYK)i+9Q|>z)IOJnE|WPDz_@IXO&qY zYYc)7z*n-p7+^Wp8ViTzdhK7bAgGCKI+r(fLp8f~H9m4fsmXK>ZYrXV-e781mZ_TB zshNpxHQS}~6lkEtYlCHZmd)u}Ms3kjDHW!!$(w36hXsUD&u47VRn0Kq9tACisbz@9 zh#F_vt(hczmd@f-REG-zTWS6glpbWAxcX7QtA?fVn zo2#!6;+LQ$qc*ECwc{o|V`Nze+S4+jc+(s+mOhY>Dhf_@cmFj&%>j2Axq1#NcRHWHRyXr3WANaPV77g<&I0rr7l#{xbD@V^zvw+i zN4>KpT+{zN2_|~XT_QsL!j*ju?!n+%y$i}$C=88eTH z=cu*IHN)g_iX{MgnyIU?jF##(lL=Ua0f1hUO#&R(7fQ)mRJJOa>1kHGO*3aS&z+kC z^fIH~Fj%G@4)k0jo0>N=nCMDJpnx`+mN46sWJ%-v#w!*!Eer;OP*Ve1!;e_eSZXhd19+_1kGty6?%>iR(_X zD82IFjcfAn?~2mFioW;u?%x@u`r+gfJ;Fkt`MaDj!GnPi7dT4@shd%hut`NE7?FfDAP=42* zhd}S~2kyA;$efxOwZ3{i^~@VXF?#H#8nVrp6sO&%&fOmI-5aN+Pe1;w`qsHPeSO-% z!@^Z-TjW&>J*VZx=QhM)p`lYdKG_$io2LtZ-=lsIr|;gHM<$I+(B?9stEJ;UzY z^YXb9aoTa7#y>V*iPKlkuB?5C*2U@mz2iST-40IqtTo;8pXr}RslBrCk;i_n#c0Li z#z!~3^HhxbpPcsatQqHHwB^l5CPz<9jnhT1O&fmhXhWQ`Ctlh){ON}gy6jhU*MmFF zC}kU(-s{}wjnQ|$WXJA~w#VpaS438wS$|)QrVs9XDzx-yjJ|mEq2R<5e~!`aS*(MZ+ifrGt!V)Pf$z={tZ*b$|7A9=BQ(GfjLr#=7UwgX2FMQJv>cH#>Q{u!lh zRkddhH&n;y`a_5MzPx*Sj4n9#m#KeKC&lP{H$=W7n?8%u!_S_2^-b%wC2lPVfH+n) zeVzBgJ0kSy>x!k>I}SwXOV9NEb@r5>M8iQ|&DmoT*~}K5neAq_-Q*b@P@2kW=7RZ9 z`@l^D*NW+s>y-c(Ucx(tJJxZ$jtP&my$E}QVHIvGBdL@vhHk6RNiJ+Y?>HxcEy8bk ztAjw{5BV4yV7wk zxOOY%lbmMOZ)voBj%Z6;8lB?0P?PeKo!83T$6VnB8{%~~|NWy}mCllUO1~N_NCRtW QMJ$(;TBStsDITTxzv)gRk^lez literal 0 HcmV?d00001 diff --git a/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py new file mode 100644 index 000000000..58a1df8de --- /dev/null +++ b/tf_quant_finance/volatility/sabr_approx_hagan_tf_test.py @@ -0,0 +1,137 @@ +""" +Created on Fri Nov 22 15:22:13 2019 + +# Copyright 2020 Joerg Kienitz + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@author: Joerg Kienitz +""" + +import sabr_approx_tf as sabr +import bachelier_tf as vptf +import volbachelier_tf as bvtf + +import numpy as np +import matplotlib.pyplot as plt + +# SABR parameters +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.2632859 +rho_org = -0.32978014 +T = 5 + +displacement_org = 0. #0.005 +kmin = -displacement_org +kmax = 10 +kval = np.arange(kmin, kmax, 0.01) +kval[0] = (kval[0] + kval[1])/2 +vol = np.zeros(len(kval)) + +alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] +displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] + +print('alpha varies') +for alpha in alpha_vec: + print('alpha: ', alpha) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha, beta_org, rho_org,nu_org) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(alpha) + label2 = 'iv ' + str(alpha) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('alpha varies') +plt.legend() +plt.show() + + +print('beta varies') +for beta in beta_vec: + print('parameters: ', beta) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta, rho_org,nu_org) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(beta) + label2 = 'iv ' + str(beta) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('beta varies') +plt.legend() +plt.show() + +print('rho varies') +for rho in rho_vec: + print('parameters: ', rho) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho,nu_org) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(rho) + label2 = 'iv ' + str(rho) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('rho varies') +plt.legend() +plt.show() + +print('nu varies') +for nu in nu_vec: + print('parameters: ', nu) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(nu) + label2 = 'iv ' + str(nu) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('nu varies') +plt.legend() +plt.show() + +print('displacement varies') +for displacement in displacement_vec: + print('parameters: ', displacement) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) + label1 = 'approx ' + str(displacement) + plt.plot(kval,yval,label= label1) +plt.title('displacement varies') +plt.legend() +plt.show() + +# different approximation techniques for SABR and Mean Reverting SABR +kappa = 0.5 +cap = 3. + +yval1 = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) +yval2 = sabr.volsabr_mr_n_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, kappa) +yval3 = sabr.volsabr_h_n_cap_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, cap) + +label1 = 'Hagan approx ' +label2 = 'MR SABR approx ' +label3 = 'Capped SABR approx ' + +plt.plot(kval,yval1,label= label1) +plt.plot(kval,yval2,label= label2) +plt.plot(kval,yval3,label= label3) +plt.title('different SABR approximation') +plt.legend() +plt.show() + + + diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf.py b/tf_quant_finance/volatility/test_sabr_hagan_tf.py new file mode 100644 index 000000000..0e5d3e471 --- /dev/null +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +""" +"" + +'Copyright 2020 Joerg Kienitz + +'Redistribution and use in source and binary forms, with or without modification, +'are permitted provided that the following conditions are met: + +'1. Redistributions of source code must retain the above copyright notice, +'this list of conditions and the following disclaimer. + +'2. Redistributions in binary form must reproduce the above copyright notice, +'this list of conditions and the following disclaimer in the documentation +'and/or other materials provided with the distribution. + +'3. Neither the name of the copyright holder nor the names of its contributors +'may be used to endorse or promote products derived from this software without +'specific prior written permission. + +'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@author: Joerg Kienitz +""" +# f = 1.0 is sufficient due to scaling property + +import volsabr_h_n_tf as sabr + +import matplotlib.pyplot as plt +#import numpy as np +import autograd.numpy as np +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.0632859 +rho_org = -0.32978014 +T = 5 + +displacement = 0 #0.005 +kmin = -displacement +kmax = 10 +kval = np.arange(kmin, kmax, 0.01) + +alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] +displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] + +print('alpha varies') +for alpha in alpha_vec: + print('alpha:', alpha) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta_org, rho_org, nu_org) + plt.plot(kval,yval,label=alpha) +plt.title('alpha varies') +plt.legend() +plt.show() + + +print('beta varies') +for beta in beta_vec: + print('beta:', beta) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta, rho_org, nu_org) + plt.plot(kval,yval,label=beta) +plt.title('beta varies') +plt.legend() +plt.show() + +print('rho varies') +for rho in rho_vec: + print('rho:', rho) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho, nu_org) + plt.plot(kval,yval,label=rho) +plt.title('rho varies') +plt.legend() +plt.show() + +print('nu varies') +for nu in nu_vec: + print('nu:' nu) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta, rho_org,nu) + plt.plot(kval,yval,label=nu) +plt.title('nu varies') +plt.legend() +plt.show() + +print('displacement varies') +for displacement in displacement_vec: + print('displacement:', displacement) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho_org,nu_org) + plt.plot(kval,yval,label=displacement) +plt.title('displacement varies') +plt.legend() +plt.show() + diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py b/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py new file mode 100644 index 000000000..07df85a19 --- /dev/null +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py @@ -0,0 +1,90 @@ +# Lint as: python3 +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.hor: Joerg Kienitz + +# f = 1.0 is sufficient due to scaling property + +import sabr_approx_tf as sabr + +import matplotlib.pyplot as plt +#import numpy as np +import autograd.numpy as np +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.0632859 +rho_org = -0.32978014 +T = 5 + +displacement = 0 #0.005 +kmin = -displacement +kmax = 10 +kval = np.arange(kmin, kmax, 0.01) + +alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] +displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] + +print('alpha varies') +for alpha in alpha_vec: + print('alpha:', alpha) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta_org, rho_org, nu_org) + plt.plot(kval,yval,label=alpha) +plt.title('alpha varies') +plt.legend() +plt.show() + + +print('beta varies') +for beta in beta_vec: + print('beta:', beta) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta, rho_org, nu_org) + plt.plot(kval,yval,label=beta) +plt.title('beta varies') +plt.legend() +plt.show() + +print('rho varies') +for rho in rho_vec: + print('rho:', rho) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho, nu_org) + plt.plot(kval,yval,label=rho) +plt.title('rho varies') +plt.legend() +plt.show() + +print('nu varies') +for nu in nu_vec: + print('nu:', nu) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta, rho_org,nu) + plt.plot(kval,yval,label=nu) +plt.title('nu varies') +plt.legend() +plt.show() + +print('displacement varies') +for d in displacement_vec: + print('displacement:', d) + kmin = -d + kmax = 10 + kval = np.arange(kmin, kmax, 0.01) + yval = sabr.volsabr_h_n_tf(f, kval, T, d, alpha_org, beta_org, rho_org,nu_org) + plt.plot(kval,yval,label=d) +plt.title('displacement varies') +plt.legend() +plt.show() + diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf_2.py b/tf_quant_finance/volatility/test_sabr_hagan_tf_2.py new file mode 100644 index 000000000..343ba8ec5 --- /dev/null +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf_2.py @@ -0,0 +1,132 @@ +# Lint as: python3 +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sabr_approx_tf as sabr +import bachelier_tf as vptf +import volbachelier_tf as bvtf + +import numpy as np +import matplotlib.pyplot as plt + +# SABR parameters +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.2632859 +rho_org = -0.32978014 +T = 5 + +displacement_org = 0. #0.005 +kmin = -displacement_org +kmax = 10 +kval = np.arange(kmin, kmax, 0.01) +kval[0] = (kval[0] + kval[1])/2 +vol = np.zeros(len(kval)) + +alpha_vec = [0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75, 1., 1.5] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] +displacement_vec = [0.0, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.05] + +print('alpha varies') +for alpha in alpha_vec: + print('alpha: ', alpha) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha, beta_org, rho_org,nu_org) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(alpha) + label2 = 'iv ' + str(alpha) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('alpha varies') +plt.legend() +plt.show() + + +print('beta varies') +for beta in beta_vec: + print('parameters: ', beta) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta, rho_org,nu_org) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(beta) + label2 = 'iv ' + str(beta) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('beta varies') +plt.legend() +plt.show() + +print('rho varies') +for rho in rho_vec: + print('parameters: ', rho) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho,nu_org) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(rho) + label2 = 'iv ' + str(rho) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('rho varies') +plt.legend() +plt.show() + +print('nu varies') +for nu in nu_vec: + print('parameters: ', nu) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu) + cval = vptf.bachelier_option_price(f,kval,yval,T,0.) + yval1 = bvtf.volbachelier_tf(1, kval, f, T, cval) + label1 = 'approx ' + str(nu) + label2 = 'iv ' + str(nu) + plt.plot(kval,yval,label= label1) + plt.plot(kval, yval1, label=label2) +plt.title('nu varies') +plt.legend() +plt.show() + +print('displacement varies') +for displacement in displacement_vec: + print('parameters: ', displacement) + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) + label1 = 'approx ' + str(displacement) + plt.plot(kval,yval,label= label1) +plt.title('displacement varies') +plt.legend() +plt.show() + +# different approximation techniques for SABR and Mean Reverting SABR +kappa = 0.5 +cap = 3. + +yval1 = sabr.volsabr_h_n_tf(f, kval, T, displacement_org, alpha_org, beta_org, rho_org,nu_org) +yval2 = sabr.volsabr_mr_n_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, kappa) +yval3 = sabr.volsabr_h_n_cap_tf(f,kval,T,displacement_org, alpha_org, beta_org, rho_org, nu_org, cap) + +label1 = 'Hagan approx ' +label2 = 'MR SABR approx ' +label3 = 'Capped SABR approx ' + +plt.plot(kval,yval1,label= label1) +plt.plot(kval,yval2,label= label2) +plt.plot(kval,yval3,label= label3) +plt.title('different SABR approximation') +plt.legend() +plt.show() + + + diff --git a/tf_quant_finance/volatility/test_volbachelier_tf.py b/tf_quant_finance/volatility/test_volbachelier_tf.py new file mode 100644 index 000000000..06a16cd72 --- /dev/null +++ b/tf_quant_finance/volatility/test_volbachelier_tf.py @@ -0,0 +1,80 @@ +# Lint as: python3 +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.hor: Joerg Kienitz + +# f = 1.0 is sufficient due to scaling property + +import sabr_approx_tf as sabr + +import matplotlib.pyplot as plt +import vanilla_n_tf as vp +import volbachelier_tf as vb +import autograd.numpy as np + +# SABR parameters +f = 1.0 #0.00434015 +alpha_org = 0.16575423 +beta_org = .6#0.7#0.16415365 +nu_org = 0.0632859 +rho_org = -0.32978014 +T = 5 + +displacement = 0 #0.005 +kmin = .25 +kmax = 5 +kval = np.arange(kmin, kmax, 0.01) + +alpha_vec = [0.1, 0.15, 0.175, 0.2, 0.25, 0.3, 0.5, 0.75] +beta_vec = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] +rho_vec = [-0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] +nu_vec = [0.001, 0.01, 0.02, 0.05, 0.075, 0.1, 0.15, 0.2, 0.5, 0.75, 1.0, 1.5] + + +for alpha in alpha_vec: + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha, beta_org, rho_org, nu_org) + oval = vp.option_price(f, kval, yval, T, 0) + ival = vb.volbachelier_tf(1., kval, f, T, oval) + plt.plot(kval, yval - ival) +plt.title('Bachelier implied vol vs SABR 1') +plt.legend() +plt.show() + +for beta in beta_vec: + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta, rho_org, nu_org) + oval = vp.option_price(f, kval, yval, T, 0) + ival = vb.volbachelier_tf(1., kval, f, T, oval) + plt.plot(kval, yval - ival) +plt.title('Bachelier implied vol vs SABR 2') +plt.legend() +plt.show() + + +for rho in rho_vec: + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho, nu_org) + oval = vp.option_price(f, kval, yval, T, 0) + ival = vb.volbachelier_tf(1., kval, f, T, oval) + plt.plot(kval, yval - ival) +plt.title('Bachelier implied vol vs SABR 3') +plt.legend() +plt.show() + + +for nu in nu_vec: + yval = sabr.volsabr_h_n_tf(f, kval, T, displacement, alpha_org, beta_org, rho_org, nu) + oval = vp.option_price(f, kval, yval, T, 0) + ival = vb.volbachelier_tf(1., kval, f, T, oval) + plt.plot(kval, yval - ival) +plt.title('Bachelier implied vol vs SABR 4') +plt.legend() +plt.show() \ No newline at end of file From b5cb6c9421070ff2b85e9fe01e4f3d21aac18109 Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Thu, 17 Sep 2020 21:16:42 +0200 Subject: [PATCH 7/8] deltetions and headers --- .../__pycache__/bachelier_tf.cpython-36.pyc | Bin 7663 -> 0 bytes .../__pycache__/sabr_approx_tf.cpython-36.pyc | Bin 11306 -> 0 bytes .../__pycache__/sabr_approx_tf.cpython-37.pyc | Bin 10661 -> 0 bytes .../__pycache__/vanilla_n_tf.cpython-37.pyc | Bin 6784 -> 0 bytes .../volbachelier_tf.cpython-36.pyc | Bin 5840 -> 0 bytes .../volbachelier_tf.cpython-37.pyc | Bin 5092 -> 0 bytes .../volatility/test_sabr_hagan_tf.py | 46 ++++++------------ .../volatility/test_sabr_hagan_tf_1.py | 2 +- .../volatility/test_volbachelier_tf.py | 2 +- 9 files changed, 16 insertions(+), 34 deletions(-) delete mode 100644 tf_quant_finance/volatility/__pycache__/bachelier_tf.cpython-36.pyc delete mode 100644 tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-36.pyc delete mode 100644 tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-37.pyc delete mode 100644 tf_quant_finance/volatility/__pycache__/vanilla_n_tf.cpython-37.pyc delete mode 100644 tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-36.pyc delete mode 100644 tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-37.pyc diff --git a/tf_quant_finance/volatility/__pycache__/bachelier_tf.cpython-36.pyc b/tf_quant_finance/volatility/__pycache__/bachelier_tf.cpython-36.pyc deleted file mode 100644 index bfe2982afbcc5b17287bf2046fb52df7887c1a78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7663 zcmd5>TXWmS6$U_3qA2QOTZ!E|O?T`z788o1D8-JID2^=2t#XkaQHdKxE)5YN1qlS0 z1t?h_c-o0Gee*Oked|ByKgdHK`UCO{@YHD^TEAuT*oUUy*#&qJ=}c|6Go^+La4%=i zIeYf(_pRo~#xi4n|NPf>PEr1*bbV5Ie+OTWqcD_h#ZV2+R`<32#CB4=r?!WTgpvG0 z*&a4h#t@!qGr2#qpFufl45Q2%=||c_b$hH+Zw~E`ceP9yW5$S)`9j^EG{%ilBa63F zhE`T`6Z&s7MaisiQ}<1SxemL*Ew$8?;LWJe9nq`~JyjL}wKC>KFbsJ6F(w(Zwjx2vqOcMzyK*T4J z2zS@l(OXCV<}q_?-Tj#EXD*^IefE66=`GIA9vvMObfIm*<@H%x+TzW=zrM1zQC^#Y z#$wDzj%|7#;8-314AR%zI5v`a?;J{Ae2Fw6aOQZm$!o zp_zVrO|xp%tSans>Mgx)vbuX{atG$HrpX(YN2}>UJp)o~t6}-NFKYUXDr7S6=q-QG z<%=gG=P_bm*{G`Yz=xg*d{^-G&Y|#?ee8%p@e}8jhpM5TRSfOCg6K_b)X|L3x7VT< z<(*tI)cjhQZ0P=8m@s)Q9Ili<+}x^^a%!mF`;)?lG2owjD~mfHc?iaxD1JpS@2tAj zR>O3BZ|4?w>s)U%VCjxuoB6DzJN`_~awzUlQ4tlDxZ=>YVYhAh$2+?e@bD|I__adw zI80TXs!{t9CiSq@U>+YqIoR5l(Gpv0sArT>18YqDpXh9-K2B~1EK5S@@5?`vn|5l}5Ni3MMpQ7aTDDgnnsG=q%YUn)~XrgAw z7)Bp@PX-B5lNL3QY>XTv`0s+0eELI1=Artz8r6R->NWng7?~6!krW|o1n0o43 z2@+Fq;e(9xekA2PF*O+J38#*&?i?%qWiNs_dV_(NZ@Vt1DZJITco7mmn zA}T(eyAz*mdG>CBU08Q~GP}x#~;GPwR=q)Ck+z$`h`5ZrQ66GhbH@= z`hjI5ZL(<`p9?wGEX?5)CDRy=L+4*Pfq^Dyy}|HGLOHmtOTNma#OyP;{-3Dx#Kgp<--u#F|kQ< zH;QP-24HVN#1`NiozGa=tHp&Y@TIqhXjqyq<#T!LDVz*T(KLDHv>MIhrOtBB6^n0N zc^zZmK>)_93s>gu}!~S>c#tnKKAdQTPlLD&UNcd?HLD#3BtsnqhZ^GIzyvk=$5T1RSH>M2K$J zlu7_N(OP$}+u)hK|9sZAuw$C3+qO6Wo^cAH>WPqFWHR(?+--z*lvBgt)uLggPO5Jg*3~nKwrBOFEd3DQm{?OQcq+?(L;L( z>7Nikaga!(yY1yex2On?~}e z;f8K|W)8Ayf)sfz;u@xrmqTNH$>H+2jG|KP)kPL}k3t=M1KZyLf~UlQ2;)=bq=IN!IN3HV z@o%#1qVBBw{x7`zvsj z^nu2|lK5MUmmDQyj6O=VSxw4$CF=Q&kf`x*z*kbDKb0|GNkwd6Bw{He5jO$X0GG)G zU{&B6qvDy3+D3_s1X+Rj$G{HKf*lmW^}sH`5Cpq@%<|Ajoe zZtDkTo~`0_MYoVH^K7|59O4%RfjU;*Bc$*53IOhs@DMn6fYyP61UZ?B(!Y?-1XY2I zmCf}sTLoxsi8~h%4Zw6<+z4p<*WdmDcXGumg^$~H9{sJ}JVzQ1KKOefu+7OKlJ|4X<|GsF?YIC zwDJ*>r)i=k7%2QCyyyY*v06QNo+P$q#^@%7PyMK#I(IMiKrNmGR`33R25q5z2%n~m zwKP;6!h+t6TBc6JD4AIZkJ?63eOD4`N01K^f=vPbGpcm2!RBp zy{PuNVE_F#8jd!M7tx9c%71%}|D2{DllS)LNguk0=Rcu>F8=vXsbEwjs34%uFH%95 z@dA(YpW!VxDGV6|$;A|$AafV;&e6|lDqf}HH5A*Y0W_lfFWhZO2tL(Q7cI>8sh-+F zD18P3|A?=58HMszA4*S1lzst79r#?E)UpXe=2JlB^i1Q)Nk%TUL7(_>8vnSd7;d#v z*`AW529)NAZY06H3x_36E(Db*Np6%9*HNGp%`SHdKavZ>G$;~XBm2_J;-4iN?gg`G w6udyF&_zIosX_eDB>h&yHCnd$HjzY+p-5_3s7-(8)E{T?4=eGPX~u8=2A%g%?EnA( diff --git a/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-36.pyc b/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-36.pyc deleted file mode 100644 index 0617a5cbd85a35013d83de6fd64e253870657025..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11306 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 YZq?0e1T$U2yh$xHoc#kOnf>U$0iZ;Og#Z8m diff --git a/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-37.pyc b/tf_quant_finance/volatility/__pycache__/sabr_approx_tf.cpython-37.pyc deleted file mode 100644 index 3f3e61a4de5700fdc9075aa8b761d108a3ab7d15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10661 zcmeHNO>7%iexDf*DT);JNlUV1J8zxs)^cb`l(mjyB>qU^HrcG5)N(di##wp98B$}C zGu$^r$qGj30xeLWK#&}I=%EGdLk}$qw3l9+y|l-o*YdPT(Sr{~_fTLLduf0F|C`~5 zC9S`97h9mD_~y;~_W}q`VUOCToklKY=j@CvUY1&TN=I5z>RiblAnoB5eMh2H; zxPIDBaM$H00k#Y0%&tdgLM3L~Im;s+_CF?*i$A)ZRg;djt2+Q(rvmN?dFM7_;vkx_&U zL=AeTsXwGhgItfMNM`SAdohY_l8n0=VOXy~BS*3iTW5dzndZRw z6Xw8dG#*XE%13H7Jf;{=%o^@-q=x+-q+>L-q5Xk&OZ!-}Phh_}*$J|mmJ|4FgqCMp z(iZPnb;}bQ*WSD(tae-a_uZBiy1plBz7*lMBi^*C+fLJUuNw!~R+X5$rm z=?7a*Xo-I+_yK6U%i<&7w~2j8tgWuDEsJyF>mU8a4OG@$uP!!PZqpIB z+@SIGkNy&k-Db-VLvaJ6@|o*7;OewPr?mz1zh4b~JeLzam<LZtZvt>(CO8E z*Yz5g#C90AgG(zbySux~a-i9==Y%Wm&Q{Z{@?fv5o&WZQwYBy2@@690CQG(Sk|{&1 zeVV9GmQd4Xzz!m@11bkhahM%Wiw`|a2pM29F_+-<5pw%p6GmvdThfwy%eyeu-g4D% zt=PW1Vr>O0<<;dfjJkrF7INQSJFjFt|EYM-bv!rxtR%j(EKa}cg&5T!6t`d_2rb#82UM!c-zk2?{>gom6`IGhM5$tHmUR^3dG$Ec}vhu|>?#xNsl2*%ssp82` z8%4Z$0?gYuDz!M1N*|DLG&POauvF+;+Bd)hh< zHm~|pI<(*UUcV`}p@S{4EegLzyJNp03-f!}NO^zVbwm|Y%4+Ufdx7W#j;Os+=2eWH zx4Fl=ZBVr^HbIAI?zES8 zERR+SQ({7HtKIyb-@L}G%B59&Z@&B%rA*+;_hw73w(K(rYW850T#OmwyicD-r{bu((f*d+o+{+bRBhS z_I!YW!~Y0(foD3O{_3D&$-1*FN=$N-WZNdcW69`_*-p*sG{a4J3Qjiz8+DwZn@xm4 zi?ki?wVkfX4MyTkrkhPR6;K%1JGyCJ6J3+0NH>LP+cmsS{qz6)hX+6V=fA(aq{|Gz zRUJQketM<;%Ad^s+rRwmzpf-DUnM19#U+~d$UxKN?P{F4c=eIqFaFo0|4))k_GD_G{Yu(&uj`V}gCbr>js_ECeX7EE9F3rd^B$V*@G)V}v zTNpG{AoEl~a8nj28K-0fNjK%RgG$czZ09~kC2V!mWXx9As99a3VO5NJqmsJsHY(=d;Ogcq>nSV)xxfK zC#;?OVFyZ{tGS*9CkzFfT(FrGfLH8%-WizPn_+Faz1JN_Etg_rL(wtt4?aesUC!!; zZWt$0)B4cYoYaeXVT>DDJ)0`(IX$DV>nHS*K8f6zUeU*ldqxg#7g1hHjp_5qtJ(|t z1zr9QXjl1O0GTQL$fk_mA7Ih|D=73ndL()`zG(keqIWaOLi)5l#&|x9`-eiq1lo>( zKnV3RW(7{p5~8vv=1JGggOMnkXB7HSXB?WfCxN03N{hgg`#GTd5%mV-HO}aB0%#WX z)ZU%|^(?3}j9*|-mxai7Qm4#328?XDSC>6(inFeblUaSCGMS5J-=aP5_^4B`&Pi zT32u=h0>~qo38!F`SrDnuf4X;bo$9PS&zX5mnFx%Apb-<@ZkrY6wBLF{)zHPsvY>^ zUMPaLA1Y4^Q`V0KRlq{c!vu&NO7wBh2UwjQj6-~&m~=uecAMfU57zLFl^nL>o46#0 zYxC@kd-PtA^Pr#x8f}frtjKGmU>N%p``tcEX$q{%@AZDe@e+;NhE!W*iBOB|$vrNIHYu!5i^TV5*`$M^ROdhEfD{F3!&*k62$4 z4TY7Jt@A(<(2SylN=I;Je@jaQ$o|x}3#g|cIk1Nmr!?_-#IvTZ@>#;spniq0FTB(0yKLia~nn?`HMI(?~NQ;Z$>Jc$cQqGaZAI$@vc-!p*5Jam1jXR#9` z)&5Dg=}D~M9`)!XtyKDtf%x_SGOIG06^QAk_D^xId^CwUi2tb|p3x%4{S**)3K)E> zhmZvj@;9u1!db`1_^%{lDt6s)o5@vi_9xC*-zy?eAsxF@b=XUjZhbpMAGiUDAItGV zrohSbK<-`ybs*%5>v#^jp8d^+T@}PW1Y`?AFguR7{u%?0!}#`jf&P7#Q7HDX49AS%}K9{?PM zrvM!CI6BKkN){*~=+PZ%S@_?VPD`G^+tN!5y!-~W zI!%e7rWu|(t*(iPdy66}ZAw}dxx zJyZg{hgM~D8%KpNZRY^0nFg0$Pz0lgz{r1td(cLrm5u~9hN%}3`aodB$QnfiLTY$B zYrK=n>82r4-@;qYSkM@%{BUmCM`Rj`$Nslefqyq CeZLO? diff --git a/tf_quant_finance/volatility/__pycache__/vanilla_n_tf.cpython-37.pyc b/tf_quant_finance/volatility/__pycache__/vanilla_n_tf.cpython-37.pyc deleted file mode 100644 index e8f0e8abbef038832f67589550a93d26609b84df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6784 zcmb_hOLH5?5#C)q2!h~46eGDT$2GB%6rlnk5Tafz(~d>TDcUjPNK7h4QvsIP1+mg% zcRjNp4cD?NN#&}ts&dOoI{IJalz))Ro>Ixlmz2*r#QAz=7Y_=GBuhYHINLMR-P6}*lPXTQ1G_`{Di?O*heezNHN3_tM;G?r%RuGZD}be;MJ`o^9i`x*2zdl}i! zy4k%P#Et%M!V;=LQr;E1zLyC0)F%OZQ>{XrfXWL-Pi9M_cPIyrAJz%M@E#1 zvQh3ZZy66WkMytpqSKsgL~YK>SlNe}6GhP_B_}D=&qju%pp?)^XNJ>FcsGp6p zk}@qR=s(U!`V;-65Ki4M+@Ho+@lcDj`!iPYp<&HfrH94|QA>|!qwI_pWtKF|E=ozI z$8%BUiN2(r%z)2)l(l9b7_^5sv}oo6xL`NMB@Iuc3uaq$*1Y0nEkxO+gxeb$df5x$ zyQHDboD`zz#|u#ba!Tl(k-gccB$TjfCYoK+&W}nW>QEZ=BF(Kclck*}X>(D|T6|D= zr1MA7++8i2i%4U#=h&V}&Iz=~K698e|0Hu)`;~S_`>kdz!ZFU8H*myk)9(gw3Kn*3 zcFSyaY}c_lgEO>j*7i9w*?}3hI?Qjg+db|Fw&^iHAQutUBEtvG#f$8Y-L|>ywQR8t z!e^`Z*vF3TIpLQT_ED9+v+ac#79qQ1Le`eeog*`Jj%>khe-XH*=~zMk|!r1Pgu1gfaVzz~OymC+Ollz=kI>CF=|5qc}r`#jLO& z*vu5HDV1qTaS7j)7u2DZ$$3C7JFt}!mJ)j8yRftCgwC@hzl78Qvpz{0-J9&cl8A&| zvOjV>8_t;QOj)`IcM>p=-*YY6r|4lq*fB%aRJyQBY^dU;OZ6sm)ZsE_IbEC}oYu8P z;;Vx7f~t=ZXema&urI*Rn@2zpcIpiyUuCZ(n}+Opeb&kfm; z>Gte(w&Qy+XUBo(bj?7nkXj_Ols1lsT*jfxL7%C>|Iqc16IGVmu5X4{>SZOtL(r}> z#G~?2dX!sGVJTP(`6E=U!Vb)s-mlNs50jx{KqmKPlv|0CQbtpGQ9~XvJVI)B#}0ek z8%t=CJ~~&B-=$Wfd`6m%CV}yUGrSWdr-4VQ{f%D(bP?bxxc!CM4G?E?L9^Km`e7$I zNtISNm={z{&dvVvXSHhWN`;}V-z&=nX=)ptgwYBcP8kF_Wt{POwKbYpyP7Z?qAlo*eiZCTD?GR=!h`k+#J`Z%grN=r3JpQZTpLAu)p z!bAGhwKZh{vS47h$ZKG3#FyU-DO7P*sgB7-Lsu<~&fWzJ<*4fncU^t$26iUzsEy@% zrCd=_wvl*lg?YVh(BBxI!0NTy)!LPt(i*kv_1g6tH}9QVRDMs&!f`5Bi%X-{DI0Mq zanA<1XPlSuCgMVxv@jzlw;N~WgsJ45UZVTqIQ*qJ^p^KBJOO z*a-bbC~y0CDmj+8_@&K#(Qt8p$Co zI^N-a*k1X(XL{jE+wn}4b09P%p^*{>=hfdoGCeBN8eRhq81#7#;x6DPuA$L33c8^i zMp2*3Eb7VEC>nYFoUy1c7)yFduVS>QzopOVwMMkQK2zll%z@{Edi4}~F~ zMj$glASG*-5J-Y53KukBkLkyys0eg0gWjy{l~UA!>c0>H1E5x)MO{y_{|%Wy38?HP zGC{pR8_m6eTAq*)5KIowsOD)#QqQBZFVFS<4pVKa>mN58()umeY&~FiTOCvxLgkF- z*Yrtln^4tLvQf4DmU%3E59NBbLP8$c6}E-$rs?4Nsjv^KRP_J6D(l!S{}@HY$JMkV z5X|>*fm6V+o@d#7WgwB*yM4GJcx>L;zRR{8(dr2*1W>P|*k^Zv9I%yt{{GLbUaMWN z{$_i-qIxPV5r+@>p#&k+XS82gHBBtLpHa&vYmzLB`*)zB%u7i@Pu!C%Hj(-1i*>A~ zPt_VL>xtulXL>iQJS$6;Q^h?^9z-L|GEs}stNlea7%+XR&?k{;ZhjSUjQ;s@jA(OPEs$r(6dGcNNId{@wBl z-z|@n+qm(awyd|kp}UPLim;G%xGKvNKBNeOC=rK>L3v9O>nI_)ED3EZDOZUheI}H} zDD(-W2Ur0bQIfDc!!8oHN6Vvd7i%C1Njik1pTO@Sjk{xHT;V}pJ7nTKpwmi8w>HtC}?;C zO~65^KI3>OrM>_z8ca=IBaP#pF?^Ix9i;K+;-qv%n%V(=QoJ-_Xf=US=}?MF{y%a` zXAiIB6b21PlI!&8fzhozJ({Zh^vGm{MFL+IWvMl%k=E7v^_N3hwc3sAR{>IiJ8ShD z_1ev=&p=uvkI)wV-8(x9wi=eKzRCvAqcrAIXm&Wgtp|mQWeE~aVTu7LiWkzfo?d(j zw&L`T9~|g)KR-kLd487qOVs>;nsd~gr{-;H7&UKFLp48ti<%!&Bb9iEdKanr5t{OX z)bNy6yh`KvUr4fsupeKh=BL#Bgqkunm(c7jj$U-~@)3JWW3(iA_s)z_2@6Riq?#4* ziq8(Ai?SvV%pWlz*3b-*ODVIU%db(;v-p;b1)cCqN#d3zP~{g-{4&;+Gdnvwhhi0;0%2Fc0XZZC{y}V3p)QvI|0X iTyCZCZr8VZuKgaJoS-u*0a=wuw;4^>^rA(rrvDGN3ztj) diff --git a/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-36.pyc b/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-36.pyc deleted file mode 100644 index 303dcb7b02a1d0f67737f0e491d95d2e2cdbdb57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5840 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 QQ)>fSi&m#aw2)T&U(^Bx+W-In diff --git a/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-37.pyc b/tf_quant_finance/volatility/__pycache__/volbachelier_tf.cpython-37.pyc deleted file mode 100644 index add1ff992e717f21db75d3cea120dae32544e90c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5092 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 QMJ$(;TBStsDITTxzv)gRk^lez diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf.py b/tf_quant_finance/volatility/test_sabr_hagan_tf.py index 0e5d3e471..e8c297d74 100644 --- a/tf_quant_finance/volatility/test_sabr_hagan_tf.py +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf.py @@ -1,36 +1,18 @@ -# -*- coding: utf-8 -*- -""" -"" +# Lint as: python3 +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.hor: Joerg Kienitz -'Copyright 2020 Joerg Kienitz - -'Redistribution and use in source and binary forms, with or without modification, -'are permitted provided that the following conditions are met: - -'1. Redistributions of source code must retain the above copyright notice, -'this list of conditions and the following disclaimer. - -'2. Redistributions in binary form must reproduce the above copyright notice, -'this list of conditions and the following disclaimer in the documentation -'and/or other materials provided with the distribution. - -'3. Neither the name of the copyright holder nor the names of its contributors -'may be used to endorse or promote products derived from this software without -'specific prior written permission. - -'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -'OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -'THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -@author: Joerg Kienitz -""" # f = 1.0 is sufficient due to scaling property import volsabr_h_n_tf as sabr diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py b/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py index 07df85a19..84da792b1 100644 --- a/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf_1.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License.hor: Joerg Kienitz +# limitations under the License. # f = 1.0 is sufficient due to scaling property diff --git a/tf_quant_finance/volatility/test_volbachelier_tf.py b/tf_quant_finance/volatility/test_volbachelier_tf.py index 06a16cd72..be5359df2 100644 --- a/tf_quant_finance/volatility/test_volbachelier_tf.py +++ b/tf_quant_finance/volatility/test_volbachelier_tf.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License.hor: Joerg Kienitz +# limitations under the License. # f = 1.0 is sufficient due to scaling property From aee7d8411af876b793c787bd6c5e0b811b2ebc7d Mon Sep 17 00:00:00 2001 From: Lapsilago Date: Thu, 17 Sep 2020 21:31:49 +0200 Subject: [PATCH 8/8] another header --- tf_quant_finance/volatility/test_sabr_hagan_tf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tf_quant_finance/volatility/test_sabr_hagan_tf.py b/tf_quant_finance/volatility/test_sabr_hagan_tf.py index e8c297d74..2ce3d8737 100644 --- a/tf_quant_finance/volatility/test_sabr_hagan_tf.py +++ b/tf_quant_finance/volatility/test_sabr_hagan_tf.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License.hor: Joerg Kienitz +# limitations under the License. # f = 1.0 is sufficient due to scaling property