An Interest Rate Swap is a financial derivative instrument in which two parties agree to exchange interest rate cash flows based on a notional amount from a fixed rate to a floating rate or from one floating rate to another floating rate.
Here we will consider an example of a plain vanilla USD swap with 10 million notional and 10 year maturity. Let the fixed leg pay 2.5% coupon semiannually, and the floating leg pay Libor 3m quarterly.
In [1]:
# <!-- collapse=True -->
import QuantLib as ql
calculation_date = ql.Date(20, 10, 2015)
ql.Settings.instance().evaluationDate = calculation_date
Here we construct the yield curve objects. For simplicity, we will use flat curves for discounting and Libor 3M. This will help us focus on the Swap construction part. Please refer to curve construction example for some details. Once we construct the
In [2]:
# construct discount curve and libor curve
risk_free_rate = 0.01
libor_rate = 0.02
day_count = ql.Actual365Fixed()
discount_curve = ql.YieldTermStructureHandle(
ql.FlatForward(calculation_date, risk_free_rate, day_count)
)
libor_curve = ql.YieldTermStructureHandle(
ql.FlatForward(calculation_date, libor_rate, day_count)
)
#libor3M_index = ql.Euribor3M(libor_curve)
libor3M_index = ql.USDLibor(ql.Period(3, ql.Months), libor_curve)
To construct the Swap instrument, we have to specify the fixed rate leg and floating rate leg. We construct the fixed rate and floating rate leg schedules below.
In [3]:
calendar = ql.UnitedStates()
settle_date = calendar.advance(calculation_date, 5, ql.Days)
maturity_date = calendar.advance(settle_date, 10, ql.Years)
fixed_leg_tenor = ql.Period(6, ql.Months)
fixed_schedule = ql.Schedule(settle_date, maturity_date,
fixed_leg_tenor, calendar,
ql.ModifiedFollowing, ql.ModifiedFollowing,
ql.DateGeneration.Forward, False)
float_leg_tenor = ql.Period(3, ql.Months)
float_schedule = ql.Schedule (settle_date, maturity_date,
float_leg_tenor, calendar,
ql.ModifiedFollowing, ql.ModifiedFollowing,
ql.DateGeneration.Forward, False)
Below, we construct a VanillaSwap
object by including the fixed and float leg schedules created above.
In [4]:
notional = 10000000
fixed_rate = 0.025
fixed_leg_daycount = ql.Actual360()
float_spread = 0.004
float_leg_daycount = ql.Actual360()
ir_swap = ql.VanillaSwap(ql.VanillaSwap.Payer, notional, fixed_schedule,
fixed_rate, fixed_leg_daycount, float_schedule,
libor3M_index, float_spread, float_leg_daycount )
We evaluate the swap using a discounting engine.
In [5]:
swap_engine = ql.DiscountingSwapEngine(discount_curve)
ir_swap.setPricingEngine(swap_engine)
The cashflows for the fixed and floating leg can be extracted from the ir_swap
object. The fixed leg cashflows are shown below:
In [6]:
# <!-- collapse=True -->
for i, cf in enumerate(ir_swap.leg(0)):
print "%2d %-18s %10.2f"%(i+1, cf.date(), cf.amount())
The floating leg cashflows are shown below:
In [7]:
# <!-- collapse=True -->
for i, cf in enumerate(ir_swap.leg(1)):
print "%2d %-18s %10.2f"%(i+1, cf.date(), cf.amount())
Some other analytics such as the fair value, fair spread etc can be extracted as shown below.
In [8]:
# <!-- collapse=True -->
print "%-20s: %20.3f" % ("Net Present Value", ir_swap.NPV())
print "%-20s: %20.3f" % ("Fair Spread", ir_swap.fairSpread())
print "%-20s: %20.3f" % ("Fair Rate", ir_swap.fairRate())
print "%-20s: %20.3f" % ("Fixed Leg BPS", ir_swap.fixedLegBPS())
print "%-20s: %20.3f" % ("Floating Leg BPS", ir_swap.floatingLegBPS())