3
$\begingroup$

I'm trying to understand how QuantLib creates (bootstraps) a yield curve from a vanilla swap at the source level. I have the following test code:

void testYieldFromIRSwap()
{
Settings::instance().evaluationDate() = Date(1, Jan, 2015);

auto dc = Actual360();

auto h1 = boost::shared_ptr<RateHelper>(new DepositRateHelper
                                               (0.03, Period(1, Years), 0.0, UnitedStates(), Following, false, Actual360()));
auto h2 = boost::shared_ptr<RateHelper>(new DepositRateHelper
                                               (0.04, Period(2, Years), 0.0, UnitedStates(), Following, false, Actual360()));

auto index = boost::shared_ptr<IborIndex>(new EURLibor1Y());
auto h3 = boost::shared_ptr<RateHelper>(
                new SwapRateHelper(0.05, Period(3, Years), UnitedStates(), Annual,
                                   Following, Actual360(), index));

std::vector<boost::shared_ptr<RateHelper>> helpers;
helpers.push_back(h1);
helpers.push_back(h2);
helpers.push_back(h3);

boost::shared_ptr<YieldTermStructure> yield(
                new PiecewiseYieldCurve<Discount,LogLinear>(
                    Settings::instance().evaluationDate(), helpers,
                        Actual360()));

const auto t1 = dc.yearFraction(Date(1, Jan, 2015), Date(1, Jan, 2016)); // 1.014
const auto t2 = dc.yearFraction(Date(1, Jan, 2015), Date(1, Jan, 2017)); // 2.031
const auto t3 = dc.yearFraction(Date(1, Jan, 2015), Date(1, Jan, 2018)); // 3.044

std::cout << yield->discount(0)  << std::endl; // Must be 1
std::cout << yield->discount(t1) << std::endl; // 1/((1+0.03) ^ 1.014) = 0.9704721
std::cout << yield->discount(t2) << std::endl; // 1/(1+0.04) ^ 2.031   = 0.9234328
std::cout << yield->discount(t3) << std::endl;
}

This is obviously a toy example. I have two deposits that gives the discount rates for the first two years. My swap is an annual 3y swap, I expect the swap gives me the discount rate for the the third year. I do get the value but I don't understand how it's computed.

The code for bootstrapping a discount factor from a swap is:

Real SwapRateHelper::impliedQuote() const {
    QL_REQUIRE(termStructure_ != 0, "term structure not set");
    // we didn't register as observers - force calculation
    swap_->recalculate();
    // weak implementation... to be improved
    static const Spread basisPoint = 1.0e-4;
    Real floatingLegNPV = swap_->floatingLegNPV();
    Spread spread = spread_.empty() ? 0.0 : spread_->value();
    Real spreadNPV = swap_->floatingLegBPS()/basisPoint*spread;
    Real totNPV = - (floatingLegNPV+spreadNPV);
    Real result = totNPV/(swap_->fixedLegBPS()/basisPoint);
    return result;
}

Everytime when QuantLib guesses a new discount factor (i.e. iteratively bootstrapping), this function computes a new NPV for the floating leg. I'd expect this NPV be set to equal to the NPV for the fixed leg, from which a new swap rate can be computed.

What I don't understand is this particular line:

Real result = totNPV/(swap_->fixedLegBPS()/basisPoint);

I think BPS is the sum of accurate interest and is computed by:

bps += cp->nominal() * cp->accrualPeriod() * df;

Question:

Why do we need to divide the new fixed-leg NPV by BPS and basisPoint? Why basisPoint is set to 1.0e-4 (1 basis point)? What's the point of doing it?

$\endgroup$
  • $\begingroup$ Since the question is going to remain available here for future reference, you might want to change the title. The formula doesn't calculate the NPV; it calculates the fixed rate from the NPV. $\endgroup$ – Luigi Ballabio Sep 4 '15 at 15:41
6
$\begingroup$

fixedLegBPS is the basis-point sensitivity of the fixed leg, that is, how much its NPV changes when the fixed rate changes by one basis point: it's calculated as the NPV corresponding to a fixed rate of 1 bps.

Since the NPV of the fixed leg is linearly proportional to the fixed rate, you can write the equation

targetNPV : fixedRate = BPS : 1 basis point

The line you highlight simply solves it for the fixed rate.

$\endgroup$
0
$\begingroup$

it seems the method fixedLegBPS() returns the sum of the discount factors associated to the fixed leg multiplied by 1 basisPoint. So what SwapRateHelper::impliedQuote() returns is actually the new fair rate of the swap to be used in the minimization algorithm.

I have tried to find the implementation of the calculate() method from class VanillaSwap::engine (VanillaSwap.recalculate() calls calculate() which calls its engine calculate() method ) but I haven't been successful. I think you can find confirmation of the behavior of the method fixedLegBPS() there since it calls calculate() and then returns legBPS_[0].

Hope it helps. (and let me know where this implementation is if you find it)

$\endgroup$
  • $\begingroup$ The implementation is in the derived class DiscountingSwapEngine. $\endgroup$ – Luigi Ballabio Sep 4 '15 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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