固定收益

在 Quantlib 中為 FixedRateBond 定價:收益率與 TermStructure

  • September 19, 2019

我正在嘗試使用兩種方法在 QuantLib 中為一個簡單的美國國庫定價。第一個方法呼叫 FixedRatebond.dirtyPrice(…),傳入 YTM 和其他參數。

第二種方法涉及使用與方法 #1 相同的 YTM 和參數建構 FlatForward YieldTermStructure。

這兩種方法給我的髒價格略有不同,我希望它們是相同的。誰能解釋我做錯了什麼,或者解釋為什麼使用這兩種方法的骯髒價格應該不同?

這是一些範常式式碼(完全披露:此程式碼是從這裡抄襲的):

try {
   // date set up
   Calendar calendar = TARGET();

   Date settlementDate(28, January, 2011);
   // the settlement date must be a business day
   settlementDate = calendar.adjust(settlementDate);

   // Evaluation date
   Integer fixingDays = 1;
   Natural settlementDays = 1;
   Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
   Settings::instance().evaluationDate() = todaysDate;

   // bond set up  
   Real faceAmount = 100.0;
   Real redemption = 100.0;
   Date issueDate(27, January, 2011);
   Date maturity(31, August, 2020);
   Real couponRate = 0.03625;
   Real yield = 0.034921;

   RelinkableHandle<YieldTermStructure> discountingTermStructure;
   boost::shared_ptr<YieldTermStructure> flatTermStructure(
   new FlatForward(
       settlementDate,
       yield,
       ActualActual(ActualActual::Bond),
       Compounding::Compounded,
       Semiannual));
   discountingTermStructure.linkTo(flatTermStructure);

   // Pricing engine
   boost::shared_ptr<PricingEngine> bondEngine(
       new DiscountingBondEngine(discountingTermStructure));

    // Rate
   Schedule fixedBondSchedule(
       issueDate,
       maturity,
       Period(Semiannual),
       UnitedStates(UnitedStates::GovernmentBond),
       BusinessDayConvention::Unadjusted,
       BusinessDayConvention::Unadjusted,
       DateGeneration::Rule::Backward,
       false);

   FixedRateBond fixedRateBond(
       settlementDays,
       faceAmount,
       fixedBondSchedule,
       std::vector<Rate>(1, couponRate),
       ActualActual(ActualActual::Bond),
       BusinessDayConvention::Unadjusted,
       redemption,
       issueDate);

   //Calculate pricing without term structure
   Real cp = fixedRateBond.cleanPrice(yield, fixedRateBond.dayCounter(), Compounding::Compounded, Semiannual);
   Real dp = fixedRateBond.dirtyPrice(yield, fixedRateBond.dayCounter(), Compounding::Compounded, Semiannual);
   Rate ytm = fixedRateBond.yield(cp, fixedRateBond.dayCounter(), Compounding::Compounded, Semiannual);
   Real accrued = fixedRateBond.accruedAmount();

   fixedRateBond.setPricingEngine(bondEngine);


   // write column headings
   Size widths[] = { 18, 15, 15};

   std::cout << std::setw(widths[0]) <<  "                 "
       << std::setw(widths[1]) << "Without TS"
       << std::setw(widths[2]) << "With TS"
       << std::endl;

   Size width = widths[0]
                   + widths[1]
                           + widths[2];
   std::string rule(width, '-'), dblrule(width, '=');

   std::cout << rule << std::endl;

   std::cout << std::setw(widths[0]) << "Clean Price"
       << std::setw(widths[1]) << std::setprecision (8) << cp
       << std::setw(widths[2]) << std::setprecision (8) << fixedRateBond.cleanPrice()
       << std::endl;

   std::cout << std::setw(widths[0]) << "Dirty Price"
       << std::setw(widths[1]) << std::setprecision (8) << dp
       << std::setw(widths[2]) << std::setprecision (8) << fixedRateBond.dirtyPrice()
       << std::endl;

   std::cout << std::setw(widths[0]) << "Accrued"
       << std::setw(widths[1]) << std::setprecision (8) << accrued
       << std::setw(widths[2]) << std::setprecision (8) << fixedRateBond.accruedAmount()
       << std::endl;

   return 0;

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

}

計日慣例。你不能和他們一起生活,你不能沒有他們。

價格不同的原因是定價引擎無法正確計算第一張優惠券的折扣時間,因此適用於優惠券金額的折扣因子略有不同。請坐,這需要一些解釋。

最終,這兩種方法都通過將優惠券金額相加來計算臟價,每個優惠券金額都根據其支付日期進行折扣。它們的不同之處在於折扣因子的計算。

正如可以預期的那樣,採用收益率和相應約定的方法通過組合收益率來計算折扣。折扣 $ D_1 $ 第一張票券是通過在票券的剩餘期限內累積收益而獲得的;折扣 $ D_2 $ 對於第二個息票,通過在其生命週期內累積並將其與之前的結果相乘;以此類推,直到最後一張優惠券。問題是,為了根據通過的 act/act(b) 天數約定正確計算累積時間,您還需要一個由優惠券頻率給出的參考期,在本例中為 6 個月。因此,例如,第一張優惠券的累積時間(從 2011 年 1 月 28 日到 2011 年 2 月 28 日)必須計算為:

dayCounter.yearFraction(Date(28,January,2011), Date(28,February,2011),
                       Date(28,August,2010),  Date(28,February,2011));

返回0.08423913043478261(第三個和第四個日期是 6 個月參考期的開始和結束日期)。如果優惠券是年度的,結果會略有不同:上面的參考開始日期是 2010 年 2 月 28 日,返回0.08493150684931507. 取收益方法的重載dirtyPrice使用票券資訊選擇正確的參考期,並根據上面的第一個值計算第一個折扣因子。結果是0.997087920498809

相反,依賴定價引擎的方法使用收益率期限結構t,並且只要求t.discount(coupon.date())提供每張優惠券:該discount方法的介面不允許傳遞有關參考期的任何額外資訊。在內部,期限結構能做的最好的事情就是計算

dayCounter.yearFraction(Date(28,January,2011), Date(28,February,2011));

預設情況下,將通過的相同兩個日期作為參考期的開始和結束,使上述等價於

dayCounter.yearFraction(Date(28,January,2011), Date(28,February,2011),
                       Date(28,January,2011), Date(28,February,2011));

這個返回0.08333333333333333,第一張優惠券對應的折扣係數是0.9971191880350325

這種差異解釋了價格的變化(其他息票無效:它們都是正常的 6 個月息票,並且對它們而言,參考期等於息票的壽命,使得 T0.5在兩種情況下都等於)。返回的價格dirtyPrice()101.08980828425344; 返回的dirtyPrice(yield, ...)101.08663832294855; 如果我們校正上述不同的折扣因子,我們得到:

101.08980828425344 * 0.997087920498809 / 0.9971191880350325 = 101.08663832294862

調和價格。

最後一點:這只發生在那些需要參考期的天數約定中。如果您嘗試使用不支持的程式碼(例如 act/360),這兩種方法將為您提供相同的價格。

更新(2019 年 9 月):

現在可以創建ActualActual使用正確參考期間進行計算的日計數器實例。將其實例化為:

DayCounter dayCounter = ActualActual(ActualActual::Bond, fixedBondSchedule);

並將其用於貼現曲線和債券。當詢問年份分數時,它將從時間表中檢索正確的參考期並使用它們。這將給出正確的結果。

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