// MJZeroCouponBond.h #pragma once #include <ql/quantlib.hpp> using namespace QuantLib; // // implementation for zero-coupon bond instrument class MJZeroCouponBond : public Instrument { public: // forward class declarations class arguments; class engine; // // ctor and implementations for required base class methods MJZeroCouponBond(Real faceAmount, Date maturityDate); bool isExpired() const; private: void setupArguments(PricingEngine::arguments* args) const; // term sheet related information Real faceAmount_; Date maturityDate_; }; // inner arguments class class MJZeroCouponBond::arguments : public PricingEngine::arguments { public: void validate() const; Real faceAmount; Date maturityDate; }; // inner engine class class MJZeroCouponBond::engine : public GenericEngine<MJZeroCouponBond::arguments, MJZeroCouponBond::results> { // base class for all further engine implementations }; // // implementation for base class engine class MJZeroCouponBondEngine : public MJZeroCouponBond::engine { public: MJZeroCouponBondEngine(const Handle<YieldTermStructure>& curve); void calculate() const; private: Handle<YieldTermStructure> curve_; }; // // // // // // MJZeroCouponBond.cpp #include "MJZeroCouponBond.h" using namespace QuantLib; // // implementations for MJZeroCouponBond instrument MJZeroCouponBond::MJZeroCouponBond(Real faceAmount, Date maturityDate) : faceAmount_(faceAmount), maturityDate_(maturityDate) { // ctor } bool MJZeroCouponBond::isExpired() const { return Settings::instance().evaluationDate() >= maturityDate_; } void MJZeroCouponBond::setupArguments(PricingEngine::arguments* args) const { MJZeroCouponBond::arguments* args_ = dynamic_cast<MJZeroCouponBond::arguments*>(args); QL_REQUIRE(args_ != nullptr, "arguments casting error"); args_->faceAmount = faceAmount_; args_->maturityDate = maturityDate_; } void MJZeroCouponBond::arguments::validate() const { QL_REQUIRE(faceAmount > 0.0, "transaction face amount cannot be zero"); } // // implementations for MJZeroCouponBondEngine MJZeroCouponBondEngine::MJZeroCouponBondEngine(const Handle<YieldTermStructure>& curve) : curve_(curve) { // register observer (MJZeroCouponBondEngine) with observable (curve) registerWith(curve_); } void MJZeroCouponBondEngine::calculate() const { // extract required parameters from arguments or curve object // implement the actual pricing algorithm and store result Date maturityDate = arguments_.maturityDate; Real P = arguments_.faceAmount; DiscountFactor df = curve_->discount(maturityDate); Real PV = P * df; results_.value = PV; } // // // // // // Tester.cpp #pragma once #include "MJZeroCouponBond.h" using namespace QuantLib; // int main() { // try { // common data : calendar, daycounter, dates Calendar calendar = TARGET(); DayCounter dayCounter = Actual360(); Date transactionDate(18, December, 2017); Date maturityDate(18, December, 2030); Natural settlementDays = 2; Date settlementDate = calendar.advance(transactionDate, Period(settlementDays, Days)); Settings::instance().evaluationDate() = settlementDate; // // create flat discount curve auto riskFreeRate = boost::make_shared<SimpleQuote>(0.01); Handle<Quote> riskFreeRateHandle(riskFreeRate); auto riskFreeRateTermStructure = boost::make_shared<FlatForward>(settlementDate, riskFreeRateHandle, dayCounter); Handle<YieldTermStructure> riskFreeRateTermStructureHandle(riskFreeRateTermStructure); // // create zero coupon bonds (QL in-built and custom implementation) Real faceAmount = 250000.0; auto QLZero = boost::make_shared<ZeroCouponBond>(settlementDays, calendar, faceAmount, maturityDate); auto MJZero = boost::make_shared<MJZeroCouponBond>(faceAmount, maturityDate); // // create pricing engines (QL in-built and custom implementation) auto QLEngine = boost::make_shared<DiscountingBondEngine>(riskFreeRateTermStructureHandle); auto MJEngine = boost::make_shared<MJZeroCouponBondEngine>(riskFreeRateTermStructureHandle); // // set engines to instruments and price the both transaction QLZero->setPricingEngine(QLEngine); MJZero->setPricingEngine(MJEngine); // std::cout << "pre-shift QL zero " << QLZero->NPV() << std::endl; std::cout << "pre-shift MJ zero " << MJZero->NPV() << std::endl; // // shift valuation curve and re-price the both transactions riskFreeRate->setValue(0.0101); std::cout << "post-shift QL zero " << QLZero->NPV() << std::endl; std::cout << "post-shift MJ zero " << MJZero->NPV() << std::endl; } catch (std::exception& e) { std::cout << e.what() << std::endl; } return 0; }
In order to get more familiar with QuantLib Monte Carlo framework, one may take a look at Implementing QuantLib blog or get the actual book on QuantLib implementation from Leanpub. Also, MoneyScience is organizing Introduction to QuantLib Development course regularly. The most essential parts of the library are thoroughly covered during this 3-day training course, hosted by QuantLib lead developer Luigi Ballabio. Thanks for reading this blog. Merry Christmas and Happy New Year for everybody.
-Mike
No comments:
Post a Comment