利率

如何在 QuantLib 中求和利率曲線

  • November 9, 2013

C++ 程式碼取自Bonds.cpp並稍作修改:

#include <ql/quantlib.hpp>
#include <boost/timer.hpp>
#include <iostream>
#include <iomanip>

using namespace QuantLib;

int main(int, char* []) {

   try {

       // Just a couple of parameters

       Calendar calendar = TARGET();
       Date settlementDate(18, September, 2008);
       settlementDate = calendar.adjust(settlementDate);
       Integer fixingDays = 3;
       Natural settlementDays = 3;
       Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
       Settings::instance().evaluationDate() = todaysDate;

       /* Now let's introduce two curves: the first one is a swap curve built from 
       deposits and IRS, the second one is a credit spread curve which should be 
       added to the former one to get a proper yield curve */

       // Swap curve

       DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA);
       double tolerance = 1.0e-5;

       // Deposits

       Rate d1wQuote = 0.043375;
       Rate d1mQuote = 0.031875;
       Rate d3mQuote = 0.0320375;
       Rate d6mQuote = 0.03385;
       Rate d9mQuote = 0.0338125;
       Rate d1yQuote = 0.0335125;

       boost::shared_ptr<Quote> d1wRate(new SimpleQuote(d1wQuote));
       boost::shared_ptr<Quote> d1mRate(new SimpleQuote(d1mQuote));
       boost::shared_ptr<Quote> d3mRate(new SimpleQuote(d3mQuote));
       boost::shared_ptr<Quote> d6mRate(new SimpleQuote(d6mQuote));
       boost::shared_ptr<Quote> d9mRate(new SimpleQuote(d9mQuote));
       boost::shared_ptr<Quote> d1yRate(new SimpleQuote(d1yQuote));

       // IRS

       Rate s2yQuote = 0.0295;
       Rate s3yQuote = 0.0323;
       Rate s5yQuote = 0.0359;
       Rate s10yQuote = 0.0412;
       Rate s15yQuote = 0.0433;

       boost::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote));
       boost::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote));
       boost::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote));
       boost::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote));
       boost::shared_ptr<Quote> s15yRate(new SimpleQuote(s15yQuote));

       // Rate Helper

       // Deposits
       DayCounter depositDayCounter = Actual360();

       boost::shared_ptr<RateHelper> d1w(new DepositRateHelper(
               Handle<Quote>(d1wRate),
               1*Weeks, fixingDays,
               calendar, ModifiedFollowing,
               true, depositDayCounter));
       boost::shared_ptr<RateHelper> d1m(new DepositRateHelper(
               Handle<Quote>(d1mRate),
               1*Months, fixingDays,
               calendar, ModifiedFollowing,
               true, depositDayCounter));
       boost::shared_ptr<RateHelper> d3m(new DepositRateHelper(
               Handle<Quote>(d3mRate),
               3*Months, fixingDays,
               calendar, ModifiedFollowing,
               true, depositDayCounter));
       boost::shared_ptr<RateHelper> d6m(new DepositRateHelper(
               Handle<Quote>(d6mRate),
               6*Months, fixingDays,
               calendar, ModifiedFollowing,
               true, depositDayCounter));
       boost::shared_ptr<RateHelper> d9m(new DepositRateHelper(
               Handle<Quote>(d9mRate),
               9*Months, fixingDays,
               calendar, ModifiedFollowing,
               true, depositDayCounter));
       boost::shared_ptr<RateHelper> d1y(new DepositRateHelper(
               Handle<Quote>(d1yRate),
               1*Years, fixingDays,
               calendar, ModifiedFollowing,
               true, depositDayCounter));

       // Setup IRS
       Frequency swFixedLegFrequency = Annual;
       BusinessDayConvention swFixedLegConvention = Unadjusted;
       DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European);
       boost::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M);

       const Period forwardStart(1*Days);

       boost::shared_ptr<RateHelper> s2y(new SwapRateHelper(
               Handle<Quote>(s2yRate), 2*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> s3y(new SwapRateHelper(
               Handle<Quote>(s3yRate), 3*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> s5y(new SwapRateHelper(
               Handle<Quote>(s5yRate), 5*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> s10y(new SwapRateHelper(
               Handle<Quote>(s10yRate), 10*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> s15y(new SwapRateHelper(
               Handle<Quote>(s15yRate), 15*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));


       // A depo-swap curve
       std::vector<boost::shared_ptr<RateHelper> > depoSwapInstruments;
       depoSwapInstruments.push_back(d1w);
       depoSwapInstruments.push_back(d1m);
       depoSwapInstruments.push_back(d3m);
       depoSwapInstruments.push_back(d6m);
       depoSwapInstruments.push_back(d9m);
       depoSwapInstruments.push_back(d1y);
       depoSwapInstruments.push_back(s2y);
       depoSwapInstruments.push_back(s3y);
       depoSwapInstruments.push_back(s5y);
       depoSwapInstruments.push_back(s10y);
       depoSwapInstruments.push_back(s15y);
       boost::shared_ptr<YieldTermStructure> depoSwapTermStructure(
               new PiecewiseYieldCurve<Discount,LogLinear>(
                       settlementDate, depoSwapInstruments,
                       termStructureDayCounter,
                       tolerance));

       return 0;

   } catch (std::exception& e) {
       std::cerr << e.what() << std::endl;
       return 1;
   } catch (...) {
       std::cerr << "unknown error" << std::endl;
       return 1;
   }
}

如果我沒記錯的話,到目前為止,我們已經獲得了一種無風險貼現曲線。

現在讓我以對象的形式介紹一條額外的信用利差曲線,由RateHelper(在上面程式碼的 depo-swap 曲線之後插入的片段):

       ...
       Rate d1ySpread = 0.013;
       Rate d2ySpread = 0.011;
       Rate d3ySpread = 0.022;
       Rate d6ySpread = 0.0238;
       Rate d9ySpread = 0.0238;
       Rate d10ySpread = 0.0239;

       boost::shared_ptr<Quote> d1ySpreadRate(new SimpleQuote(d1ySpread));
       boost::shared_ptr<Quote> d2ySpreadRate(new SimpleQuote(d2ySpread));
       boost::shared_ptr<Quote> d3ySpreadRate(new SimpleQuote(d3ySpread));
       boost::shared_ptr<Quote> d6ySpreadRate(new SimpleQuote(d6ySpread));
       boost::shared_ptr<Quote> d9ySpreadRate(new SimpleQuote(d9ySpread));
       boost::shared_ptr<Quote> d10ySpreadRate(new SimpleQuote(d10ySpread));

       boost::shared_ptr<RateHelper> credit1y(new SwapRateHelper(
               Handle<Quote>(d1ySpreadRate), 1*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> credit2y(new SwapRateHelper(
               Handle<Quote>(d2ySpreadRate), 2*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> credit3y(new SwapRateHelper(
               Handle<Quote>(d3ySpreadRate), 3*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> credit6y(new SwapRateHelper(
               Handle<Quote>(d6ySpreadRate), 6*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> credit9y(new SwapRateHelper(
               Handle<Quote>(d9ySpreadRate), 9*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));
       boost::shared_ptr<RateHelper> credit10y(new SwapRateHelper(
               Handle<Quote>(d10ySpreadRate), 10*Years,
               calendar, swFixedLegFrequency,
               swFixedLegConvention, swFixedLegDayCounter,
               swFloatingLegIndex, Handle<Quote>(),forwardStart));

       std::vector<boost::shared_ptr<RateHelper> > creditInstruments;
       creditInstruments.push_back(credit1y);
       creditInstruments.push_back(credit2y);
       creditInstruments.push_back(credit3y);
       creditInstruments.push_back(credit6y);
       creditInstruments.push_back(credit9y);
       creditInstruments.push_back(credit10y);
       boost::shared_ptr<YieldTermStructure> creditTermStructure(
               new PiecewiseYieldCurve<Discount,LogLinear>(
                       settlementDate, creditInstruments,
                       termStructureDayCounter,
                       tolerance));
       ...

例如,該對象creditTermStructure可以表示 CDS 價差曲線或此類期限結構。

depoSwapTermStructure由上面的程式碼建構和creditTermStructure建構,我想YieldTermStructure通過求和depoSwapTermStructure並考慮creditTermStructure未對齊的時間節點來生成一個新的類對象,也就是說,程式碼必須按適當的期限對費率求和(1Y depo-swap + 1Y 信用利差,2Y depo-swap + 2Y 信用利差……等等。由於缺乏信用利差到期,比如18Y,應該是插值已知節點)。

使用QuantLib怎麼可能做這樣的事情?

目前沒有課程可以根據需要添加兩條曲線,但編寫它並不難。

您將在庫中最接近的是ZeroSpreadedTermStructure類,它顯示了一般思想:它繼承自YieldTermStructure(通過ZeroYieldStructure)接受 aYieldTermStructure和傳播(在本例中為常量)並覆蓋其自己的方法,以便它們返回總和兩者之一:例如,

Rate ZeroSpreadedTermStructure::forwardImpl(Time t) const {
   return originalCurve_->forwardRate(t, t, comp_, freq_, true)
       + spread_->value();
}

在您的情況下,您必須編寫一個類似的類,它需要兩個Handles 來YieldTermStructure代替。有點令人驚訝的是,這將使您的工作更輕鬆。您仍然可以將ZeroSpreadedTermStructure其作為其他任務的模型,例如向所需的觀察者註冊,但在這種情況下您所要做的就是YieldTermStructure直接繼承並覆蓋單個discountImpl方法:

DiscountFactor YourClass::discountImpl(Time t) const {
   return baseCurve_->discount(t, true)
        * spreadCurve_->discount(t, true);
}    

因為利率之和意味著相應折扣因子的乘積。

如果您需要更多資訊,可在http://implementingquantlib.blogspot.com/2013/09/chapter-3-part-2YieldTermStructure獲得層次結構及其實現方法的描述(此處包含的內容有點長)-of-n-yield-term.html和以後的文章。

當然,一旦您的曲線工作正常,歡迎您將其貢獻給 QuantLib。更簡單的方法是獲取一個 GitHub 帳戶並按照https://github.com/lballabio/quantlib上的自述文件中的說明進行操作。

引用自:https://quant.stackexchange.com/questions/9397