Getting Started¶
Let’s look at a few examples!
First, start off by importing QuantLib.jl
using QuantLib
Price a fixed rate bond¶
First, set up the global environment.
settlement_date = Date(2008, 9, 18) # construct settlement date
# settings is a global singleton that contains global settings
set_eval_date!(settings, settlement_date - Dates.Day(3))
Then, construct settings we will need to construct the yield curve
freq = QuantLib.Time.Semiannual()
tenor = QuantLib.Time.TenorPeriod(freq)
conv = QuantLib.Time.Unadjusted()
conv_depo = QuantLib.Time.ModifiedFollowing()
rule = QuantLib.Time.DateGenerationBackwards()
calendar = QuantLib.Time.USGovernmentBondCalendar()
dc_depo = QuantLib.Time.Actual365()
dc = QuantLib.Time.ISDAActualActual()
dc_bond = QuantLib.Time.ISMAActualActual()
fixing_days = 3
Build the Deposit and Bond helpers we will use to bootstrap the curve.
First we will set up vectors of the deposit rates and tenors, and bond issue dates and maturity dates (these could come from some other market data source)
# build depos
depo_rates = [0.0096, 0.0145, 0.0194]
depo_tens = [Base.Dates.Month(3), Base.Dates.Month(6), Base.Dates.Month(12)]
# build bonds
issue_dates = [Date(2005, 3, 15), Date(2005, 6, 15), Date(2006, 6, 30), Date(2002, 11, 15), Date(1987, 5, 15)]
mat_dates = [Date(2010, 8, 31), Date(2011, 8, 31), Date(2013, 8, 31), Date(2018, 8, 15), Date(2038, 5, 15)]
Now, we’ll use some static coupon rates and market quotes for the bond helpers
coupon_rates = [0.02375, 0.04625, 0.03125, 0.04000, 0.04500]
market_quotes = [100.390625, 106.21875, 100.59375, 101.6875, 102.140625]
With this data, we can now construct our helpers
# construct the deposit and fixed rate bond helpers
insts = Vector{BootstrapHelper}(length(depo_rates) + length(issue_dates))
for i = eachindex(depo_rates)
depo_quote = Quote(depo_rates[i])
depo_tenor = QuantLib.Time.TenorPeriod(depo_tens[i])
depo = DepositRateHelper(depo_quote, depo_tenor, fixing_days, calendar, conv_depo, true, dc_depo)
insts[i] = depo
end
for i = eachindex(coupon_rates)
term_date = mat_dates[i]
rate = coupon_rates[i]
issue_date = issue_dates[i]
market_quote = market_quotes[i]
sched = QuantLib.Time.Schedule(issue_date, term_date, tenor, conv, conv, rule, true)
bond = FixedRateBondHelper(Quote(market_quote), FixedRateBond(3, 100.0, sched, rate, dc_bond, conv,
100.0, issue_date, calendar, DiscountingBondEngine()))
insts[i + length(depo_rates)] = bond
end
With our helpers created, we can start to construct the yield curve which we will bootstrap
interp = QuantLib.Math.LogLinear()
trait = Discount()
bootstrap = IterativeBootstrap()
yts = PiecewiseYieldCurve(settlement_date, insts, dc, interp, trait, 0.00000000001, bootstrap)
Now, we can trigger the bootstrapping calculation (this can be triggered by a number of events, but for now we will just directly trigger calculation)
calculate!(yts)
Let’s now create our fixed rate bond, by generating a coupon schedule and giving it a pricing engine
settlement_days = 3
face_amount = 100.0
fixed_schedule = QuantLib.Time.Schedule(Date(2007, 5, 15), Date(2017, 5, 15),
QuantLib.Time.TenorPeriod(QuantLib.Time.Semiannual()), QuantLib.Time.Unadjusted(),
QuantLib.Time.Unadjusted(), QuantLib.Time.DateGenerationBackwards(), false,
QuantLib.Time.USGovernmentBondCalendar())
pe = DiscountingBondEngine(yts)
fixedrate_bond = FixedRateBond(settlement_days, face_amount, fixed_schedule, 0.045,
QuantLib.Time.ISMAActualActual(), QuantLib.Time.ModifiedFollowing(), 100.0,
Date(2007, 5, 15), fixed_schedule.cal, pe)
Finally, we can request for the bond’s NPV!
npv(fixedrate_bond) # 107.66828913260542
Calculate the Survival Probability of a Credit Default Swap¶
First, let’s set up the environment
cal = QuantLib.Time.TargetCalendar()
todays_date = Date(2007, 5, 15)
settlementDate = todays_date
set_eval_date!(settings, todays_date)
Now, let’s generate a flat-forward term structure for use with our CDS Helpers (which are used to generate the Hazard Rate Curve)
flatRate = Quote(0.01)
tsCurve = FlatForwardTermStructure(settlementDate, cal, flatRate, QuantLib.Time.Actual365())
To bootstrap the hazard rate curve that we will use for survival probability (and inversely, default probability), we need to build CDS helpers. To begin, we’ll set a recovery rate, and quote spreads, tenors, and maturity dates for 4 CDS helpers
recoveryRate = 0.5
quoteSpreads = [0.0150, 0.0150, 0.0150, 0.0150]
tenors = [Dates.Month(3), Dates.Month(6), Dates.Year(1), Dates.Year(2)]
maturities = [QuantLib.Time.adjust(cal, QuantLib.Following(), todays_date + ten) for ten in tenors]
Let’s build our CDS helpers
insts = SpreadCDSHelper[SpreadCDSHelper(Quote(quoteSpreads[i]), tenors[i], 0, cal, QuantLib.Time.Quarterly(),
QuantLib.Time.Following(), QuantLib.Time.DateGenerationTwentieth(), QuantLib.Time.Actual365(),
recoveryRate, tsCurve) for i in eachindex(tenors)]
With our helpers constructed, now we can build the hazard rate curve.
hazardRateStructure = PiecewiseDefaultCurve(todays_date, insts, QuantLib.Time.Actual365(),
QuantLib.Math.BackwardFlatInterpolation(), HazardRate(), 1.0e-12)
By requested for the curve nodes, we will trigger the bootstrap calculation
hr_curve_data = nodes(hazardRateStructure)
Now we can output the 1Y and 2Y survival probabilities
println(@sprintf("1Y Survival Probability: %.6f %%", survival_probability(hazardRateStructure,
todays_date + Dates.Year(1)) * 100.0))
println(@sprintf("2Y Survival Probability: %.6f %%", survival_probability(hazardRateStructure,
todays_date + Dates.Year(2)) * 100.0))
Price a Swaption Using a G2 Calibrated Model¶
Set up our environment
cal = QuantLib.Time.TargetCalendar()
settlementDate = Date(2002, 2, 19)
todays_date = Date(2002, 2, 15)
set_eval_date!(settings, todays_date)
Gather appropriate market data
swaptionMats = [Dates.Year(1), Dates.Year(2), Dates.Year(3), Dates.Year(4), Dates.Year(5)]
swaptionVols = [0.1490, 0.1340, 0.1228, 0.1189, 0.1148, 0.1290, 0.1201, 0.1146, 0.1108,
0.1040, 0.1149, 0.1112, 0.1070, 0.1010, 0.0957, 0.1047, 0.1021, 0.0980, 0.0951,
0.1270, 0.1000, 0.0950, 0.0900, 0.1230, 0.1160]
swaptionLengths = [Dates.Year(1), Dates.Year(2), Dates.Year(3), Dates.Year(4), Dates.Year(5)]
Generate a flat-forward term structure implying a 1x5 swap at 5%
flat_rate = Quote(0.04875825)
rhTermStructure = FlatForwardTermStructure(settlementDate, cal, flat_rate, QuantLib.Time.Actual365())
Build an ATM swap
fixedLegFrequency = QuantLib.Time.Annual()
fixedLegConvention = QuantLib.Time.Unadjusted()
floatingLegConvention = QuantLib.Time.ModifiedFollowing()
fixedLegDayCounter = QuantLib.Time.EuroThirty360()
floatingLegFrequency = QuantLib.Time.Semiannual()
swapType = Payer()
dummyFixedRate = 0.03
indexSixMonths = euribor_index(QuantLib.Time.TenorPeriod(Dates.Month(6)), rhTermStructure)
startDate = QuantLib.Time.advance(Dates.Year(1), cal, settlementDate, floatingLegConvention)
maturity = QuantLib.Time.advance(Dates.Year(5), cal, startDate, floatingLegConvention)
fixedSchedule = QuantLib.Time.Schedule(startDate, maturity, QuantLib.Time.TenorPeriod(fixedLegFrequency),
fixedLegConvention, fixedLegConvention, QuantLib.Time.DateGenerationForwards(), false, cal)
floatSchedule = QuantLib.Time.Schedule(startDate, maturity, QuantLib.Time.TenorPeriod(floatingLegFrequency),
floatingLegConvention, floatingLegConvention, QuantLib.Time.DateGenerationForwards(), false, cal)
swap = VanillaSwap(swapType, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter,
indexSixMonths, 0.0, floatSchedule, indexSixMonths.dc, DiscountingSwapEngine(rhTermStructure))
fixedATMRate = fair_rate(swap)
atmSwap = VanillaSwap(swapType, 1000.0, fixedSchedule, fixedATMRate, fixedLegDayCounter, indexSixMonths,
0.0, floatSchedule, indexSixMonths.dc, DiscountingSwapEngine(rhTermStructure))
Construct our model
modelG2 = G2(rhTermStructure)
Build our calibration helpers
numRows = 5
numCols = 5
times = zeros(0)
swaptions = Vector{SwaptionHelper}(numRows)
for i = 1:numRows
j = numCols - (i - 1)
k = (i - 1) * numCols + j
sh = SwaptionHelper(swaptionMats[i], swaptionLengths[j], Quote(swaptionVols[k]), indexSixMonths,
indexSixMonths.tenor, indexSixMonths.dc, indexSixMonths.dc, rhTermStructure,
G2SwaptionEngine(modelG2, 6.0, 16))
times = add_times_to!(sh, times)
swaptions[i] = sh
end
tg = QuantLib.Time.TimeGrid(times, 30)
Calibrate our model
om = QuantLib.Math.LevenbergMarquardt()
calibrate!(modelG2, swaptions, om, QuantLib.Math.EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8))
for i=1:numRows
j = numCols - (i - 1)
k = (i - 1) * numCols + j
npv = model_value!(swaptions[i])
implied = implied_volatility!(swaptions[i], npv, 1e-4, 1000, 0.05, 0.50)
diff = implied - swaptionVols[k]
println(@sprintf("%i x %i: model %.5f%%, market: %.5f%% (%.5f%%)", i, Int(swaptionLengths[j]), implied * 100,
swaptionVols[k] * 100, diff * 100))
end
println("calibrated to: ")
println(@sprintf("a = %.6f, sigma = %.6f", get_params(modelG2)[1], get_params(modelG2)[2]))
println(@sprintf("b = %.6f, eta = %.6f", get_params(modelG2)[3], get_params(modelG2)[4]))
println(@sprintf("rho = %.6f", get_params(modelG2)[5]))
Build a Bermudan swaption for pricing
swapLeg = swap.legs[1] # Fixed Leg
bermudanDates = Vector{Date}(length(swapLeg.coupons))
for i=1:length(swapLeg.coupons)
bermudanDates[i] = accrual_start_date(swapLeg.coupons[i])
end
bermudanExercise = BermudanExercise(bermudanDates)
bermudanSwaption = Swaption(atmSwap, bermudanExercise)
Use a tree swaption engine to price the swaption with our G2 model
bermudanSwaption = update_pricing_engine(bermudanSwaption, TreeSwaptionEngine(modelG2, 50))
println(@sprintf("G2 (tree): %.6f", npv(bermudanSwaption)))
Use a finite-differences swaption engine to price the swaption with our G2 model
bermudanSwaption = update_pricing_engine(bermudanSwaption, FdG2SwaptionEngine(modelG2))
println(@sprintf("G2 (fdm): %.6f", npv(bermudanSwaption)))