Very nascent.
Interest rate swaps are a first step towards including rate-sensitive instruments in the modeling and valuation spectrum of DX Analytics. The model used in the following is the square-root diffusion process by Cox-Ingersoll-Ross (1985). Data used are UK/London OIS and Libor rates.
In [1]:
import dx
import time
import numpy as np
import pandas as pd
import datetime as dt
from pylab import plt
plt.style.use('seaborn')
%matplotlib inline
We start by importing OIS term structure data (source: http://www.bankofengland.co.uk) for risk-free discounting. We also adjust the data structure somewhat for our purposes.
In [2]:
# UK OIS Spot Rates Yield Curve
oiss = pd.read_excel('data/ukois09.xls', 'oiss')
# use years as index
oiss = oiss.set_index('years')
# del oiss['years']
In [3]:
# only date information for columns, no time
oiss.columns = [d.date() for d in oiss.columns]
In [4]:
oiss.tail()
Out[4]:
Next we replace the year fraction index by a DatetimeIndex.
In [5]:
# generate time index given input data
# starting date + 59 months
date = oiss.columns[-1]
index = pd.date_range(date, periods=60, freq='M') # , tz='GMT')
index = [d.replace(day=date.day) for d in index]
index = pd.DatetimeIndex(index)
oiss.index = index
Let us have a look at the most current data, i.e. the term structure, of the data set.
In [6]:
oiss.iloc[:, -1].plot(figsize=(10, 6))
Out[6]:
This data is used to instantiate a deterministic_short_rate model for risk-neutral discounting purposes.
In [7]:
# generate deterministic short rate model based on UK OIS curve
ois = dx.deterministic_short_rate('ois', list(zip(oiss.index, oiss.iloc[:, -1].values / 100)))
In [8]:
# example dates and corresponding discount factors
dr = pd.date_range('2015-1', periods=4, freq='6m').to_pydatetime()
ois.get_discount_factors(dr)[::-1]
Out[8]:
We want to model a 3 month Libor-based interest rate swap. To this end, we need Libor term structure data, i.e. forward rates in this case (source: http://www.bankofengland.co.uk), to calibrate the valuation to. The data importing and adjustments are the same as before.
In [9]:
# UK Libor foward rates
libf = pd.read_excel('data/ukblc05.xls', 'fwds')
# use years as index
libf = libf.set_index('years')
In [10]:
# only date information for columns, no time
libf.columns = [d.date() for d in libf.columns]
In [11]:
libf.tail()
Out[11]:
In [12]:
# generate time index given input data
# starting date + 59 months
date = libf.columns[-1]
index = pd.date_range(date, periods=60, freq='M') # , tz='GMT')
index = [d.replace(day=date.day) for d in index]
index = pd.DatetimeIndex(index)
libf.index = index
And the short end of the Libor term sturcture visualized.
In [13]:
libf.iloc[:, -1].plot(figsize=(10, 6))
Out[13]:
Next, equipped with the Libor data, we calibrate the square-root diffusion short rate model. A bit of data preparation:
In [14]:
t = libf.index.to_pydatetime()
f = libf.iloc[:, -1].values / 100
initial_value = 0.005
A mean-squared error (MSE) function to be minimized during calibration.
In [15]:
def srd_forward_error(p0):
global initial_value, f, t
if p0[0] < 0 or p0[1] < 0 or p0[2] < 0:
return 100
f_model = dx.srd_forwards(initial_value, p0, t)
MSE = np.sum((f - f_model) ** 2) / len(f)
return MSE
And the calibration itself.
In [16]:
from scipy.optimize import fmin
In [17]:
opt = fmin(srd_forward_error, (1.0, 0.7, 0.2),
maxiter=1000, maxfun=1000)
The optimal parameters (kappa, theta, sigma) are:
In [18]:
opt
Out[18]:
The model fit is not too bad in this case.
In [19]:
plt.figure(figsize=(10, 6))
plt.plot(t, f, label='market forward rates')
plt.plot(t, dx.srd_forwards(initial_value, opt, t), 'r.', label='model forward rates')
plt.gcf().autofmt_xdate(); plt.legend(loc=0)
Out[19]:
The optimal parameters from the calibration are used to model the floating rate (3m Libor rate).
In [20]:
# market environment
me_srd = dx.market_environment('me_srd', dt.datetime(2014, 10, 16))
In [21]:
# square-root diffusion
me_srd.add_constant('initial_value', 0.02)
me_srd.add_constant('kappa', opt[0])
me_srd.add_constant('theta', opt[1])
me_srd.add_constant('volatility', opt[2])
me_srd.add_curve('discount_curve', ois)
# OIS discounting object
me_srd.add_constant('currency', 'EUR')
me_srd.add_constant('paths', 10000)
me_srd.add_constant('frequency', 'w')
me_srd.add_constant('starting_date', me_srd.pricing_date)
me_srd.add_constant('final_date', dt.datetime(2020, 12, 31))
In [22]:
srd = dx.square_root_diffusion('srd', me_srd)
Let us have a look at some simulated rate paths.
In [23]:
paths = srd.get_instrument_values()
In [24]:
plt.figure(figsize=(10, 6))
plt.plot(srd.time_grid, paths[:, :6])
Out[24]:
Finally, we can model the interest rate swap itself.
First, the market environment with all the parameters needed.
In [25]:
# market environment for the IRS
me_irs = dx.market_environment('irs', me_srd.pricing_date)
me_irs.add_constant('fixed_rate', 0.01)
me_irs.add_constant('trade_date', me_srd.pricing_date)
me_irs.add_constant('effective_date', me_srd.pricing_date)
me_irs.add_constant('payment_date', dt.datetime(2014, 12, 27))
me_irs.add_constant('payment_day', 27)
me_irs.add_constant('termination_date', me_srd.get_constant('final_date'))
me_irs.add_constant('currency', 'EUR')
me_irs.add_constant('notional', 1000000)
me_irs.add_constant('tenor', '6m')
me_irs.add_constant('counting', 'ACT/360')
# discount curve from mar_env of floating rate
The instantiation of the valuation object.
In [26]:
irs = dx.interest_rate_swap('irs', srd, me_irs)
The present value of the interest rate swap given the assumption, in particular, of the fixed rate.
In [27]:
%time irs.present_value(fixed_seed=True)
Out[27]:
You can also generate a full output of all present values per simulation path.
In [28]:
irs.present_value(full=True).iloc[:, :6]
Out[28]:
Copyright, License & Disclaimer
© Dr. Yves J. Hilpisch | The Python Quants GmbH
DX Analytics (the "dx library" or "dx package") is licensed under the GNU Affero General Public License version 3 or later (see http://www.gnu.org/licenses/).
DX Analytics comes with no representations or warranties, to the extent permitted by applicable law.
http://tpq.io | dx@tpq.io | http://twitter.com/dyjh
Quant Platform | http://pqp.io
Python for Finance Training | http://training.tpq.io
Certificate in Computational Finance | http://compfinance.tpq.io
Derivatives Analytics with Python (Wiley Finance) | http://dawp.tpq.io
Python for Finance (2nd ed., O'Reilly) | http://py4fi.tpq.io