Home Swap Curve
Post
Cancel

Swap Curve

This post is about swap curve. You might heard about swap and curve independtly. But swap curve is required to price interest rate swap(IRS) and cross currency swap(CCS).

What is Swap Curve

Swap rate is interest rate which is reflect credibility among banks. Since banks are major players of Over-The-Counter(OTC) market, special interest rate is needed.

Each player in finance industry has different credibility. Credibility of US government, Korea government, JP Morgan bank , Korea industrial bank and me have different credibility. When these banks are trading derivative product in OTC market, special interest rate called swap rate curve which is different from treasury yield, corporate bond rate is needed.

We need Libor rate, Euro dollar futures and swap rate to calculate swap curve. In here, we use QuantLib package to construct term structure.

Construct curve with QuantLib

TermStructure() = DepositRateHelper() + FuturesRateHelper() + SwapRateHelper()

DepositRateHelper = helper for short term LIBOR rate
FuturesRateHelper = helper to extract interest rate implied in Euro Dollar futures contract
SwapRateHelper = helper for swap rate longer than 2 years

Test Data

I downloaded from Bloomberg Terminal in excel form. If you want to apply below code in real world, you need to make excel type file. which contains futures, and swap rate info.
Data

Result

Result of swap curve calculation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
       discount_factor  zero_rate  forward_rate
Tenor                                          
3MO           0.999424   0.225410      0.225410
6MO           0.999006   0.225213      0.223262
9MO           0.998446   0.224097      0.221029
12MO          0.997891   0.222980      0.218796
15MO          0.997343   0.221863      0.216563
18MO          0.996800   0.220747      0.214329
21MO          0.996263   0.219630      0.212096
2Y            0.995599   0.218231      0.209299
3Y            0.993033   0.229976      0.265555
4Y            0.989204   0.267638      0.419189
5Y            0.983540   0.327478      0.628952
6Y            0.976198   0.396210      0.809997
7Y            0.967113   0.471725      1.003116
8Y            0.956853   0.544133      1.121227
9Y            0.945523   0.614450      1.248637
10Y           0.933515   0.679342      1.328857
11Y           0.921174   0.737188      1.373633
12Y           0.908723   0.787884      1.396338
15Y           0.871961   0.902431      1.475245
20Y           0.812882   1.023566      1.507719
25Y           0.765340   1.057177      1.223894
30Y           0.722038   1.073100      1.168532
40Y           0.659502   1.028424      0.849571
50Y           0.625947   0.925671      0.412459

Let’s code this idea

Full code can be found at below link.
CODE

Full Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import os
import datetime
import numpy as np
import pandas as pd

import QuantLib as ql


def get_quote(today):
    quote = pd.read_excel(os.path.join(os.getcwd(), "market_data/swap_data.xlsx"),index_col='Tenor')
    # pre-processing dataframe
    quote['DaysToMaturity'] = np.nan
    quote['Maturity'] = pd.to_datetime(quote['Maturity']).dt.date

    for tenor in quote.index:
        quote.loc[tenor, 'DaysToMaturity'] = (quote.loc[tenor, 'Maturity'] - today).days
    return quote

# construct IRS curve
def swap_curve(today, quote):

    # divide dataframe into 3 parts
    depo = quote[quote['InstType'] == 'CASH']
    futures = quote[quote['InstType'] == 'FUTURES']
    swap = quote[quote['InstType'] == 'SWAP']

    # Set evaluation date
    todays_date = ql.Date(today.day, today.month, today.year)
    ql.Settings.instance().evaluationDate = todays_date

    #Market Conventions
    calendar = ql.UnitedStates()
    dayCounter = ql.Actual360()
    convention = ql.ModifiedFollowing
    settlementDays = 2
    frequency = ql.Semiannual

    ### Build Rate Helper ###

    # 1_Deposit rate helper
    depositHelpers = [
        ql.DepositRateHelper(
            ql.QuoteHandle(ql.SimpleQuote(rate/100)),
            ql.Period(int(day), ql.Days),
            settlementDays,
            calendar,
            convention,
            False,
            dayCounter
        )
        for day, rate in zip(depo['DaysToMaturity'], depo['Market.Mid'])
    ]

    # 2_ Futures rate helper
    futuresHelpers = []
    for i, price in enumerate(futures['Market.Mid']):
        iborStartDate = ql.Date(
            futures['Maturity'][i].day,
            futures['Maturity'][i].month,
            futures['Maturity'][i].year
        )
        
        futuresHelpers = ql.FuturesRateHelper(
            ql.QuoteHandle(ql.SimpleQuote(price)),
            iborStartDate,
            3,
            calendar,
            convention,
            False,
            dayCounter
        )
        futuresHelpers.append(futuresHelpers)

    # 3_ Swap rate helper
    swapHelpers = [ql.SwapRateHelper(
        ql.QuoteHandle(ql.SimpleQuote(rate/100)),
        ql.Period(int(day), ql.Days),
        calendar,
        frequency,
        convention,
        dayCounter,
        ql.Euribor3M()
        )
        for day, rate in zip(swap['DaysToMaturity'], swap['Market.Mid'])
    ]

    # Combine 1_2_3 with Piece wise linear zero method
    # Curve construction
    helpers = depositHelpers + futuresHelpers + swapHelpers
    depoFuturesSwapCurve = ql.PiecewiseLinearZero(todays_date, helpers, dayCounter)

    return depoFuturesSwapCurve

# use curve to compute discount factor and zero rate
# the curve is calcualted with module used while pricing treasury
def discount_factor(date, curve):
    date = ql.Date(date.day, date.month, date.year)
    return curve.discount(date)

def zero_rate(date, curve):
    date = ql.Date(date.day, date.month, date.year)
    day_counter = ql.Actual360()
    compounding = ql.Compounded
    freq = ql.Continuous
    zero_rate = curve.zeroRate(
        date,
        day_counter,
        compounding,
        freq
    ).rate()

    return zero_rate

# cacualte forward rate
def forward_rate(date, curve):
    date = ql.Date(date.day, date.month, date.year)
    day_counter = ql.Actual360()
    compounding = ql.Compounded
    freq = ql.Continuous
    forward_rate = curve.forwardRate(
        date,
        date,
        day_counter,
        compounding,
        freq,
        True
    ).rate()
    
    return forward_rate

##############################################
## Let's calculate swap curve


today = datetime.date(2020,10,9)
quote = get_quote(today=today)
curve = swap_curve(today=today, quote=quote)

# calculate discount factor/ zero rate/ forward rate
quote['discount_factor'], quote['zero_rate'], quote['forward_rate'] = np.nan, np.nan, np.nan

for tenor, date in zip(quote.index, quote['Maturity']):
    quote.loc[tenor, 'discount_factor'] = discount_factor(date, curve)
    quote.loc[tenor, 'zero_rate'] = zero_rate(date, curve) * 100
    quote.loc[tenor, 'forward_rate'] = forward_rate(date, curve) * 100

# print result
print(quote[['discount_factor', 'zero_rate', 'forward_rate']])
This post is licensed under CC BY 4.0 by the author.