Search code examples
pythonbootstrappingquantlib

Calculating the Potential Future Exposure for IR swaps in python using EONIA curve for discounting and 6M EURIBOR forward curve for pricing


I want to calculate the Potential Future Exposure (PFE) of a portfolio of two swaps using 2 curves - EURIBOR 6M to price the floating leg, and EONIA curve to discount the fixed leg of the swaps. I built the two curves with Quantlib Python Cookbook, and for the swap pricing and PFE calculator I would like to use this example: (https://ipythonquant.wordpress.com/2015/04/08/expected-exposure-and-pfe-simulation-with-quantlib-and-python/). My problem is that in this example they use one single curve for discounting and forwarding, calculated from one rate (which is not really realistic). I can construct the yield curves but i can't put together the two examples into one code to work properly. (Please help me, my thesis work's deadline is coming!) I am interested in any other codes or solutions that can work for this problem. Here are my codes:

! pip install QuantLib-Python

# import the used libraries
%%capture
%pylab inline --no-import-all
import math
import utils
import datetime as dt
import pandas  as pd
#utils.set_default_plot_size()
import QuantLib as ql

from QuantLib import *

today = Date(8, September, 2020)
Settings.instance().evaluationDate = today

eonia = Eonia()
helpers = [ OISRateHelper(2, Period(*tenor),
QuoteHandle(SimpleQuote(rate/100)), eonia)
for rate, tenor in [(-0.468, (1,Days)), (-0.470000013709068, (1,Weeks)),(-0.473499998450279, (2,Weeks)), (-0.476999998092651, (1,Months)), (-0.478000000119209, (2,Months)),(-0.480000004172325, (3,Months)), (-0.483400002121925, (4,Months)),(-0.486249998211861, (5,Months)), (-0.488499999046326, (6,Months)),(-0.493000000715256, (7,Months)), (-0.497000008821487, (8,Months)),(-0.500199988484383, (9,Months)), (-0.504599988460541, (10,Months)),(-0.50874999165535, (11,Months)), (-0.512099981307983, (12,Months)),(-0.531000018119812, (18,Months)), (-0.541999995708465, (2,Years)),(-0.546999990940093, (30,Months)), (-0.550999999046326, (3,Years)),(-0.544999986886978, (4,Years)), (-0.527999997138977, (5,Years)),(-0.49499998986721, (6,Years)), (-0.459999993443489, (7,Years)),(-0.417999997735023, (8,Years)), (-0.373999997973442, (9,Years)),(-0.326999992132187, (10,Years)), (-0.277999997138977, (11,Years)),(-0.236000001430512, (12,Years)), (-0.123999997973442, (15,Years)),(-0.0370000004768372, (20,Years)), (-0.0330000007525086, (25,Years)),(-0.0490000005811453, (30,Years)), (-0.0710000023245811,(35,Years)),(-0.0889999493956566, (40,Years)), (-0.128000002354383, (50,Years))] ]

eonia_curve_c = PiecewiseLogCubicDiscount(0, TARGET(),
helpers, Actual360())
eonia_curve_c.enableExtrapolation()

helpers = [ DepositRateHelper(QuoteHandle(SimpleQuote(-0.459/100)),Period(6,Months), 3,TARGET(), Following, False, Actual360()) ]
euribor6m = Euribor6M()

Besides, what is the problem here??:

helpers += [ FraRateHelper(QuoteHandle(SimpleQuote(rate/100)),
start, euribor6m)
for rate, start in [(-0.43818798661232, 7), (-0.442768007516861, 8), (-0.440380990505219, 9),
   (-0.437555998563766, 10), (-0.445408999919891, 11), (-0.452802002429962, 12),
   (-0.453942000865936, 13), (-0.450417011976242, 14), (-0.466143995523453, 15),
  (-0.450170010328293, 16), (-0.,452068001031876, 17), (-0.468688994646072, 18)] ]

(it says too many values to unpack)

discount_curve = RelinkableYieldTermStructureHandle()
discount_curve.linkTo(eonia_curve)

helpers += [ SwapRateHelper(QuoteHandle(SimpleQuote(rate/100)),Period(tenor, Years), TARGET(),Annual, Unadjusted,Thirty360(Thirty360.BondBasis),euribor6m, QuoteHandle(), Period(0, Days),discount_curve)for rate, tenor in [(-0.471998006105423, 2), (-0.4668410122394563, 3), (-0.448518991470337, 4),(-0.419505000114441, 5),(-0.386981993913651, 6), (-0.345064997673035, 7), (-0.301272988319397, 8),(-0.259175002574921, 9), (-0.206983998417854, 10), (-0.164517998695374, 11),(-0.123749002814293, 12),(-0.0165138002485037, 15), (0.0642198026180267, 20),(0.0658923983573914, 25), (0.0394961982965469, 30),(-0.0109016001224518, 40),(-0.0604206994175911, 50)] ]

euribor6m_curve = PiecewiseLogCubicDiscount(2, TARGET(), helpers,Actual365Fixed())
euribor6m_curve.enableExtrapolation()

Then, I want to add this curves to this code: https://ipythonquant.wordpress.com/2015/04/08/expected-exposure-and-pfe-simulation-with-quantlib-and-python/ To replace this:

# Setup Marketdata
rate = ql.SimpleQuote(0.0536)
rate_handle = ql.QuoteHandle(rate)
dc = ql.Actual365Fixed()
yts = ql.FlatForward(today, rate_handle, dc)
yts.enableExtrapolation()
hyts = ql.RelinkableYieldTermStructureHandle(yts)
t0_curve = ql.YieldTermStructureHandle(yts)
euribor6m = ql.Euribor6M(hyts)

And then price the swaps with these curves. Please if you know a solution to this problem, share it with me! Or any advice, how I can price the swaps with two bootstrapped curves. Thx


Solution

  • You actually have two questions here:

    1. PFE Example

    First, the reason you cannot extract the data for the FraRateHelper is that there is an extra comma in one of the elements. Notice the type here that makes that particular tuple have 3 elements and not 2:

    (-0.,452068001031876, 17)
    

    After that, replace this bit of code (where you are creating a flat curve):

    rate = ql.SimpleQuote(0.0536)
    rate_handle = ql.QuoteHandle(rate)
    dc = ql.Actual365Fixed()
    yts = ql.FlatForward(today, rate_handle, dc)
    yts.enableExtrapolation()
    

    with...

    yts = euribor6m_curve
    

    and you should be good to use the example you mentioned.

    2. Pricing Swaps

    Now for pricing swaps with the two curves, the idea is to use the the forwards curve for the index:

    euribor6m = ql.Euribor6M(hyts)
    

    and then the discount curve for the engine:

    engine = ql.DiscountingSwapEngine(discount_curve)
    swap.setPricingEngine(engine)
    print( swap.NPV() )
    print( swap.fairRate() )