2
$\begingroup$

I am trying to understand the rate helper more in detail. In principal I want to build a 3M forward curve based on 6M quotes and 6Mvs3M quotes.

The 6M works and prices to 0. I am not sure whether for the 3M I am doing the proper thing feeding the market quote and the basisswap-spread into the vanilla swap pricer becasue at larger maturities I am getting deviations?

import QuantLib as ql

date = ql.Date(9, ql.February, 2015)
ql.Settings.instance().evaluationDate = date

#Definition of OIS and Libor Index
TONAR_JPY = ql.OvernightIndex("Tonar", 2, ql.JPYCurrency(), ql.Japan(), ql.Actual365Fixed())
Libor_JPY_3M = ql.JPYLibor(ql.Period(3, ql.Months))
Libor_JPY_6M = ql.JPYLibor(ql.Period(6, ql.Months))

#--------------------------------------------------------------------
# Discounting curve
#--------------------------------------------------------------------

#2015-02-09

# setup DepositRateHelper for 0-2 days
helpers_disc = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)),
                                     ql.Period(2,ql.Days), fixingDays,
                                     ql.Japan(), ql.ModifiedFollowing, False, ql.Actual365Fixed())
            for rate, fixingDays in [(0.081, 0)]]

# OIS quotes up to 30 years
# setup OISRateHelper from 15 months to 30 years
helpers_disc += [ql.OISRateHelper(2, ql.Period(*tenor),
                                 ql.QuoteHandle(ql.SimpleQuote(rate/100)), TONAR_JPY)
            for rate, tenor in [(0.0713, (1,ql.Weeks)), (0.0688, (2,ql.Weeks)), (0.0663, (3,ql.Weeks)), (0.0656, (1,ql.Months)), 
                                (0.0563, (4,ql.Months)), (0.055, (5,ql.Months)), (0.0538, (6,ql.Months)), (0.05, (11,ql.Months)),
                                (0.0494, (12,ql.Months)), (0.0481, (15,ql.Months)), (0.0506, (18,ql.Months)), (0.0538, (2,ql.Years)),
                                (0.0769, (3,ql.Years)), (0.1119, (4,ql.Years)), (0.2925, (8,ql.Years)), (0.3356, (9,ql.Years)),
                                (0.6888, (15,ql.Years)), (0.965, (20,ql.Years)), (1.1081, (25,ql.Years)), (1.1831, (30,ql.Years))]]

tonar_curve = ql.PiecewiseCubicZero(date, helpers_disc, ql.Actual365Fixed())
tonar_curve.enableExtrapolation()

discount_curve = ql.RelinkableYieldTermStructureHandle()
discount_curve.linkTo(tonar_curve)

#--------------------------------------------------------------------
#6-months JPY Libor
#--------------------------------------------------------------------

#Fixings
helpers_fwd_6M = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)),
                                     ql.Period(6,ql.Months), fixingDays,
                                     ql.Japan(), ql.ModifiedFollowing, False, ql.Actual365Fixed())
            for rate, fixingDays in [(0.14214, 0)]]

#FRA Helper
helpers_fwd_6M += [ql.FraRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)), start, Libor_JPY_6M)
            for rate, start in [(0.1444, 1), (0.1456, 2), (0.1463, 3),
                                (0.1475, 4), (0.1488, 5)]]
#Swap Helper
helpers_fwd_6M += [ql.SwapRateHelper(ql.QuoteHandle(ql.SimpleQuote((rate)/100)),
                                  ql.Period(tenor, ql.Years), ql.Japan(),
                                  ql.Semiannual, ql.Unadjusted, ql.Actual365Fixed(),
                                  Libor_JPY_6M, ql.QuoteHandle(), 
                                  ql.Period(0, ql.Days),
                                  discount_curve)
                for rate, tenor in [(0.1475, 1), (0.155, 2), (0.18, 3), (0.21875, 4), (0.2675, 5), (0.32, 6),
                                    (0.375, 7), (0.4325, 8), (0.49, 9), (0.55, 10), (0.67875, 12), (0.8825, 15),
                                    (1.16125, 20), (1.3075, 25), (1.385, 30)]]

jpy_libor_curve_6M = ql.PiecewiseCubicZero(date, helpers_fwd_6M, ql.Actual365Fixed())
jpy_libor_curve_6M.enableExtrapolation()

forward_curve_6M = ql.RelinkableYieldTermStructureHandle()
forward_curve_6M.linkTo(jpy_libor_curve_6M)

#--------------------------------------------------------------------
#3-months JPY Libor
#--------------------------------------------------------------------

#Fixings
helpers_fwd_3M = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)),
                                     ql.Period(3,ql.Months), fixingDays,
                                     ql.Japan(), ql.ModifiedFollowing, False, ql.Actual365Fixed())
            for rate, fixingDays in [(0.10429, 0)]]

#FRA Helper
helpers_fwd_3M += [ql.FraRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)), start, Libor_JPY_3M)
            for rate, start in [(0.1113, 1), (0.1138, 2), (0.115, 3), (0.1175, 4), (0.1188, 5), (0.1188, 6),
                                (0.1188, 7), (0.1188, 8)]]


helpers_fwd_3M += [ql.SwapRateHelper(ql.QuoteHandle(ql.SimpleQuote((rate)/100)),
                                  ql.Period(tenor, ql.Years), ql.Japan(),
                                  ql.Quarterly, ql.Unadjusted, ql.Actual365Fixed(),
                                  Libor_JPY_3M, ql.QuoteHandle(ql.SimpleQuote((basis/100/100))), 
                                  ql.Period(0, ql.Days),
                                  discount_curve)
            for rate, basis, tenor in [(0.1475, 3.25, 1), (0.155, 3.25, 2), (0.18, 3.25, 3), (0.21875, 3.375, 4), 
                                       (0.2675, 3.5, 5), (0.32, 3.625, 6), (0.375, 3.875, 7), (0.4325, 4.125, 8), 
                                       (0.49, 4.625, 9), (0.55, 5.125, 10), (0.67875, 6, 12), (0.8825, 6.5, 15),
                                       (1.16125, 6.5, 20), (1.3075, 6.5, 25), (1.385, 6.5, 30)]]

jpy_libor_curve_3M = ql.PiecewiseCubicZero(date, helpers_fwd_3M, ql.Actual365Fixed())
jpy_libor_curve_3M.enableExtrapolation()

forward_curve_3M = ql.RelinkableYieldTermStructureHandle()
forward_curve_3M.linkTo(jpy_libor_curve_3M)

#Swap Pricing 

settle_date = ql.Japan().advance(date, 2, ql.Days)
maturity_date = ql.Japan().advance(settle_date, 1, ql.Years)   
fixed_leg_tenor_6M = ql.Period(6, ql.Months)
float_leg_tenor_6M = ql.Period(6, ql.Months)
float_leg_tenor_3M = ql.Period(3, ql.Months)
fixed_leg_tenor_3M = ql.Period(3, ql.Months)

notional = 1000000

#6M Swap
#1Y market qoute
Market_Swap_Quote_6M = (0.1475/100)

#Fixed Rate
fixed_schedule_6M = ql.Schedule(settle_date, maturity_date, fixed_leg_tenor_6M, ql.Japan(), ql.ModifiedFollowing, ql.ModifiedFollowing,
                             ql.DateGeneration.Backward, True)

#Floating Rate
floating_schedule_6M = ql.Schedule(settle_date, maturity_date, float_leg_tenor_6M, ql.Japan(), ql.ModifiedFollowing, ql.ModifiedFollowing,
                                ql.DateGeneration.Backward, True)

index_complete_6M = ql.JPYLibor(ql.Period(6, ql.Months), forward_curve_6M)

swap_6M = ql.VanillaSwap(ql.VanillaSwap.Payer, notional,
                      fixed_schedule_6M, Market_Swap_Quote_6M, ql.Actual365Fixed(),
                      floating_schedule_6M, index_complete_6M, 0, ql.Actual360())   

swap_6M.setPricingEngine(ql.DiscountingSwapEngine(discount_curve))

#NPV
print('6M Swap NPV =', swap_6M.NPV())
print('6M Swap Fair Rate =', swap_6M.fairRate())

#3M Swap
#1Y market qoute
Market_Swap_Quote_3M = (0.1475/100)
Market_Quote_Spread_6M3M = (3.25/100/100)

#Fixed Rate
fixed_schedule_3M = ql.Schedule(settle_date, maturity_date, fixed_leg_tenor_3M, ql.Japan(), ql.ModifiedFollowing, ql.ModifiedFollowing,
                             ql.DateGeneration.Backward, True)

#Floating Rate
floating_schedule_3M = ql.Schedule(settle_date, maturity_date, float_leg_tenor_3M, ql.Japan(), ql.ModifiedFollowing, ql.ModifiedFollowing,
                                ql.DateGeneration.Backward, True)

index_complete_3M = ql.JPYLibor(ql.Period(3, ql.Months), forward_curve_3M)

swap_3M = ql.VanillaSwap(ql.VanillaSwap.Payer, notional,
                      fixed_schedule_3M, Market_Swap_Quote_3M, ql.Actual365Fixed(),
                      floating_schedule_3M, index_complete_3M, Market_Quote_Spread_6M3M, ql.Actual360())   

swap_3M.setPricingEngine(ql.DiscountingSwapEngine(discount_curve))

#NPV
print('3M Swap NPV =', swap_3M.NPV())
print('3M Swap Fair Rate =', swap_3M.fairRate())
$\endgroup$

1 Answer 1

1
$\begingroup$

The NPV fucntion gives you with the market quote the off-market swap. To calculate the par swap fixed rate you have to use the the function

swap_3M.fairRate()

which results in a NPV euqual to zero (PV Fixed Leg = PV Floating Leg).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.