void SwaptionHelper::performCalculations() const { Calendar calendar = index_->fixingCalendar(); Natural fixingDays = index_->fixingDays(); Date exerciseDate = exerciseDate_; if (exerciseDate == Null<Date>()) exerciseDate = calendar.advance(termStructure_->referenceDate(), maturity_, index_->businessDayConvention()); Date startDate = calendar.advance(exerciseDate, fixingDays, Days, index_->businessDayConvention()); Date endDate = endDate_; if (endDate == Null<Date>()) endDate = calendar.advance(startDate, length_, index_->businessDayConvention()); Schedule fixedSchedule(startDate, endDate, fixedLegTenor_, calendar, index_->businessDayConvention(), index_->businessDayConvention(), DateGeneration::Forward, false); Schedule floatSchedule(startDate, endDate, index_->tenor(), calendar, index_->businessDayConvention(), index_->businessDayConvention(), DateGeneration::Forward, false); boost::shared_ptr<PricingEngine> swapEngine( new DiscountingSwapEngine(termStructure_, false)); VanillaSwap::Type type = VanillaSwap::Receiver; VanillaSwap temp(VanillaSwap::Receiver, nominal_, fixedSchedule, 0.0, fixedLegDayCounter_, floatSchedule, index_, 0.0, floatingLegDayCounter_); temp.setPricingEngine(swapEngine); Real forward = temp.fairRate(); if(strike_ == Null<Real>()) { exerciseRate_ = forward; } else { exerciseRate_ = strike_; type = strike_ <= forward ? VanillaSwap::Receiver : VanillaSwap::Payer; // ensure that calibration instrument is out of the money } swap_ = boost::shared_ptr<VanillaSwap>( new VanillaSwap(type, nominal_, fixedSchedule, exerciseRate_, fixedLegDayCounter_, floatSchedule, index_, 0.0, floatingLegDayCounter_)); swap_->setPricingEngine(swapEngine); boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exerciseDate)); swaption_ = boost::shared_ptr<Swaption>(new Swaption(swap_, exercise)); CalibrationHelper::performCalculations(); }
set<Date> AsianContract::getAllBusinessDaysBetween(Date startDate, Date endDate, Calendar calendar) { Date averagingStart; if (calendar.isBusinessDay(startDate)) { averagingStart = startDate; } else { averagingStart = calendar.advance(startDate, 1, Days); } Date lastDateInAveragingMonth; if (calendar.isBusinessDay(endDate)) { lastDateInAveragingMonth = endDate; } else { lastDateInAveragingMonth = calendar.advance(endDate, -1, Days); } set<Date> averagingDates; Date tmp = averagingStart; while (tmp <= endDate) { averagingDates.insert(tmp); tmp = calendar.advance(tmp, 1, Days); } return averagingDates; }
void historicalRatesAnalysis( SequenceStatistics& statistics, std::vector<Date>& skippedDates, std::vector<std::string>& skippedDatesErrorMessage, const Date& startDate, const Date& endDate, const Period& step, const std::vector<boost::shared_ptr<InterestRateIndex> >& indexes) { skippedDates.clear(); skippedDatesErrorMessage.clear(); Size nRates = indexes.size(); statistics.reset(nRates); std::vector<Rate> sample(nRates); std::vector<Rate> prevSample(nRates); std::vector<Rate> sampleDiff(nRates); Calendar cal = indexes[0]->fixingCalendar(); // start with a valid business date Date currentDate = cal.advance(startDate, 1*Days, Following); bool isFirst = true; // Loop over the historical dataset for (; currentDate<=endDate; currentDate = cal.advance(currentDate, step, Following)) { try { for (Size i=0; i<nRates; ++i) { Rate fixing = indexes[i]->fixing(currentDate, false); sample[i] = fixing; } } catch (std::exception& e) { skippedDates.push_back(currentDate); skippedDatesErrorMessage.push_back(e.what()); continue; } // From 2nd step onwards, calculate forward rate // relative differences if (!isFirst){ for (Size i=0; i<nRates; ++i) sampleDiff[i] = sample[i]/prevSample[i] -1.0; // add observation statistics.add(sampleDiff.begin(), sampleDiff.end()); } else isFirst = false; // Store last calculated forward rates std::swap(prevSample, sample); } }
static bool test_bond_schedule_today_cython() { Date today; Calendar calendar; FixedRateBond* bond; Date s_date; Date b_date; today = Date::todaysDate(); calendar = TARGET(); bond = get_bond_for_evaluation_date(today); s_date = calendar.advance(today, 3, Days, Following, 0); b_date = bond->settlementDate(); if (s_date != b_date) { std::cout << "Dates are not equivalent " << s_date << " vs " << b_date << std::endl; return false; } return true; }
void DefaultProbabilityCurveTest::testFlatHazardRate() { BOOST_TEST_MESSAGE("Testing flat hazard rate..."); Real hazardRate = 0.0100; Handle<Quote> hazardRateQuote = Handle<Quote>( boost::shared_ptr<Quote>(new SimpleQuote(hazardRate))); DayCounter dayCounter = Actual360(); Calendar calendar = TARGET(); Size n = 20; double tolerance = 1.0e-10; Date today = Settings::instance().evaluationDate(); Date startDate = today; Date endDate = startDate; FlatHazardRate flatHazardRate(today, hazardRateQuote, dayCounter); for(Size i=0; i<n; i++){ endDate = calendar.advance(endDate, 1, Years); Time t = dayCounter.yearFraction(startDate, endDate); Probability probability = 1.0 - std::exp(-hazardRate * t); Probability computedProbability = flatHazardRate.defaultProbability(t); if (std::fabs(probability - computedProbability) > tolerance) BOOST_ERROR( "Failed to reproduce probability for flat hazard rate\n" << std::setprecision(10) << " calculated probability: " << computedProbability << "\n" << " expected probability: " << probability); } }
CmsSpreadOption::CmsSpreadOption(boost::shared_ptr<Schedule> calculationSchedule, int fixingDays, boost::shared_ptr<SwapIndex> index1, boost::shared_ptr<SwapIndex> index2, DayCounter couponDayCounter, double strike, int flavour) : index1_(index1), index2_(index2), couponDayCounter_(couponDayCounter), strike_(strike), flavour_(flavour) { calc_ = calculationSchedule->dates(); Calendar cal = calculationSchedule->calendar(); BusinessDayConvention bdc = calculationSchedule->businessDayConvention(); for(int i=1;i<calc_.size();i++) { payments_.push_back(calc_[i]); Date fix = calc_[i-1]; fix = cal.advance(fix,-fixingDays,Days,bdc); fixings_.push_back(fix); } rates1_=vector<double>(fixings_.size()); rates2_=vector<double>(fixings_.size()); adjustedRates1_=vector<double>(fixings_.size()); adjustedRates2_=vector<double>(fixings_.size()); spreads_=vector<double>(fixings_.size()); areRatesComputed_=vector<bool>(fixings_.size(),false); QL_REQUIRE(fixings_.size() == payments_.size() && fixings_.size() == calc_.size()-1, "Number of fixings (" << fixings_.size() << "), payments (" << payments_.size() << ") and calculation schedules (" << calc_.size() << ") do not match."); }
FuturesRateHelper::FuturesRateHelper(Real price, const Date& iborStartDate, Natural lengthInMonths, const Calendar& calendar, BusinessDayConvention convention, bool endOfMonth, const DayCounter& dayCounter, Rate convAdj, Futures::Type type) : RateHelper(price), convAdj_(Handle<Quote>(shared_ptr<Quote>(new SimpleQuote(convAdj)))) { switch (type) { case Futures::IMM: QL_REQUIRE(IMM::isIMMdate(iborStartDate, false), iborStartDate << " is not a valid IMM date"); break; case Futures::ASX: QL_REQUIRE(ASX::isASXdate(iborStartDate, false), iborStartDate << " is not a valid ASX date"); break; default: QL_FAIL("unknown futures type (" << Integer(type) << ")"); } earliestDate_ = iborStartDate; latestDate_ = calendar.advance(iborStartDate, lengthInMonths*Months, convention, endOfMonth); yearFraction_ = dayCounter.yearFraction(earliestDate_, latestDate_); }
void SubPeriodsPricer::initialize(const FloatingRateCoupon& coupon) { coupon_ = dynamic_cast<const SubPeriodsCoupon*>(&coupon); QL_REQUIRE(coupon_, "sub-periods coupon required"); gearing_ = coupon_->gearing(); spread_ = coupon_->spread(); Date paymentDate = coupon_->date(); boost::shared_ptr<IborIndex> index = boost::dynamic_pointer_cast<IborIndex>(coupon_->index()); const Handle<YieldTermStructure>& rateCurve = index->forwardingTermStructure(); discount_ = rateCurve->discount(paymentDate); accrualFactor_ = coupon_->accrualPeriod(); spreadLegValue_ = spread_ * accrualFactor_* discount_; startTime_ = coupon_->startTime(); endTime_ = coupon_->endTime(); observationTimes_ = coupon_->observationTimes(); observations_ = coupon_->observations(); const std::vector<Date>& observationDates = coupon_->observationsSchedule()->dates(); QL_REQUIRE(observationDates.size()==observations_+2, "incompatible size of initialValues vector"); initialValues_ = std::vector<Real>(observationDates.size(),0.); observationCvg_ = std::vector<Real>(observationDates.size(),0.); observationIndexStartDates_ = std::vector<Date>(observationDates.size()); observationIndexEndDates_ = std::vector<Date>(observationDates.size()); Calendar calendar = index->fixingCalendar(); for(Size i=0; i<observationDates.size(); i++) { Date fixingDate = calendar.advance( observationDates[i], -static_cast<Integer>(coupon_->fixingDays()), Days); initialValues_[i] = index->fixing(fixingDate) + coupon_->rateSpread(); Date fixingValueDate = index->valueDate(fixingDate); Date endValueDate = index->maturityDate(fixingValueDate); observationIndexStartDates_[i] = fixingValueDate; observationIndexEndDates_[i] = endValueDate; observationCvg_[i] = index->dayCounter().yearFraction(fixingValueDate, endValueDate); } }
static FixedRateBond* get_bond_for_evaluation_date( Date &in_date ) { Date evaluation_date; Calendar calendar; Date effective_date; Date termination_date; Natural settlement_days; Real face_amount; Real coupon_rate; Real redemption; Schedule fixed_bond_schedule; Date issue_date; std::vector<Rate>* coupons; FixedRateBond* bond; QL::set_evaluation_date(in_date); evaluation_date = QL::get_evaluation_date(); std::cout << "Current evaluation date:" << evaluation_date << std::endl; calendar = QuantLib::TARGET(); effective_date = Date(10, QuantLib::Jul, 2006); termination_date = calendar.advance( effective_date, 10, Years, Unadjusted, 0 ); settlement_days = 3; face_amount = 100.0; coupon_rate = 0.05; redemption = 100.0; fixed_bond_schedule = Schedule( effective_date, termination_date, Period(Annual), calendar, ModifiedFollowing, ModifiedFollowing, DateGeneration::Backward, 0 ); issue_date = Date(10, Jul, 2006); coupons = new std::vector<Rate>(); coupons->push_back(coupon_rate); bond = new FixedRateBond( settlement_days, face_amount, fixed_bond_schedule, *coupons, ActualActual(ActualActual::ISMA), Following, redemption, issue_date ); return bond; }
FuturesRateHelper::FuturesRateHelper(Real price, const Date& immDate, Natural lengthInMonths, const Calendar& calendar, BusinessDayConvention convention, bool endOfMonth, const DayCounter& dayCounter, Rate convAdj) : RateHelper(price), convAdj_(Handle<Quote>(shared_ptr<Quote>(new SimpleQuote(convAdj)))) { QL_REQUIRE(IMM::isIMMdate(immDate, false), immDate << "is not a valid IMM date"); earliestDate_ = immDate; latestDate_ = calendar.advance(immDate, lengthInMonths*Months, convention, endOfMonth); yearFraction_ = dayCounter.yearFraction(earliestDate_, latestDate_); }
FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price, const Date& immDate, Natural lengthInMonths, const Calendar& calendar, BusinessDayConvention convention, bool endOfMonth, const DayCounter& dayCounter, const Handle<Quote>& convAdj) : RateHelper(price), convAdj_(convAdj) { QL_REQUIRE(IMM::isIMMdate(immDate, false), immDate << " is not a valid IMM date"); earliestDate_ = immDate; latestDate_ = calendar.advance(immDate, lengthInMonths*Months, convention, endOfMonth); yearFraction_ = dayCounter.yearFraction(earliestDate_, latestDate_); registerWith(convAdj_); }
static bool test_bond_schedule_anotherday_cython() { Date last_month; Date today; FixedRateBond* bond; Calendar calendar; Date s_date; Date b_date; Date e_date; last_month = Date(30, August, 2011); today = Date::endOfMonth(last_month); bond = get_bond_for_evaluation_date(today); calendar = TARGET(); s_date = calendar.advance(today, 3, Days, Following, 0); b_date = bond->settlementDate(); e_date = QL::get_evaluation_date(); if (s_date != b_date) { std::cout << "Dates are not equivalent " << s_date << " vs " << b_date << std::endl; return false; } if (today != e_date) { std::cout << "Evaluation dates are not equivalent " << today << " vs " << e_date << std::endl; return false; } return true; }
boost::shared_ptr<VanillaSwap> InstrumentFactory::make_vanillaSwap(Real notional, const Date& ref_date, const std::string& swap_index_cd, Rate fixedRate, VanillaSwap::Type fixedPayRecType, Spread floatingLegSpread, const Handle<YieldTermStructure>& evalYieldCurve, const boost::shared_ptr<PricingEngine>& engine ) { // 로드해 boost::shared_ptr<SwapIndex> swapIndex = IndexFactory::swapIndex(swap_index_cd, evalYieldCurve.currentLink()); Calendar calendar = SouthKorea(); Period maturityTenor = swapIndex->tenor(); Period couponTenor = swapIndex->fixedLegTenor(); DayCounter dayCounter = swapIndex->dayCounter(); BusinessDayConvention businessDayConvention = BusinessDayConvention::ModifiedFollowing; Schedule schedule = Schedule(ref_date, calendar.advance(ref_date, maturityTenor, businessDayConvention), couponTenor, calendar, businessDayConvention, businessDayConvention, DateGeneration::Rule::Forward, false); boost::shared_ptr<VanillaSwap> vanilla_swap = boost::shared_ptr<VanillaSwap>(new VanillaSwap(fixedPayRecType, notional, schedule, fixedRate, dayCounter, schedule, swapIndex->iborIndex()->clone(evalYieldCurve), floatingLegSpread, dayCounter)); vanilla_swap->setPricingEngine(engine); return vanilla_swap; }
AverageBMACoupon::AverageBMACoupon(const Date& paymentDate, Real nominal, const Date& startDate, const Date& endDate, const boost::shared_ptr<BMAIndex>& index, Real gearing, Spread spread, const Date& refPeriodStart, const Date& refPeriodEnd, const DayCounter& dayCounter) : FloatingRateCoupon(paymentDate, nominal, startDate, endDate, index->fixingDays(), index, gearing, spread, refPeriodStart, refPeriodEnd, dayCounter, false) { Calendar cal = index->fixingCalendar(); Integer fixingDays = Integer(index->fixingDays()); fixingDays += bmaCutoffDays; Date fixingStart = cal.advance(startDate, -fixingDays*Days, Preceding); fixingSchedule_ = index->fixingSchedule(fixingStart, endDate); setPricer(boost::shared_ptr<FloatingRateCouponPricer>( new AverageBMACouponPricer)); }
Date BMAIndex::maturityDate(const Date& valueDate) const { Calendar cal = fixingCalendar(); Date fixingDate = cal.advance(valueDate, -1, Days); Date nextWednesday = previousWednesday(fixingDate+7); return cal.advance(nextWednesday, 1, Days); }
void qlVariableValueFactory::setSerialClass(const boost::shared_ptr<FpmlSerialized::VariableValue>& serial_vv) { const std::string& choiceStr_paraType = serial_vv->getChoiceStr_paraType(); boost::shared_ptr<QuantLib::VariableValue> ql_vv; if( choiceStr_paraType == "indexRef") { const boost::shared_ptr<FpmlSerialized::IndexRef>& serial_indexRef = serial_vv->getIndexRef(); const Date& refDate = serial_indexRef->getEventDateRef()->getDateSingle()->dateValue(); const std::string& fixingTypeChoiceStr = serial_indexRef->getFixingDays()->getChoiceStr_fixingType(); Integer fixingDays = 0; if(fixingTypeChoiceStr == "days"){ fixingDays = serial_indexRef->getFixingDays()->getDays()->IValue(); }else { QL_FAIL("not implementation"); } Calendar calendar = PathInformation::instance().getCalendar(); const QuantLib::Period& dayUnit = QuantLib::Period(fixingDays,QuantLib::Days); const Date& adjustedRefDate = calendar.advance(refDate,dayUnit); const boost::shared_ptr<FpmlSerialized::UnderlyingIndex>& serial_under = serial_vv->getIndexRef()->getUnderlyingIndexRef(); qlUnderlyingFactory ql_uf = qlUnderlyingFactory(); ql_uf.setSerialClass(serial_under); boost::shared_ptr<QuantLib::Index> index = ql_uf.getIndex(); ql_vv = boost::shared_ptr<QuantLib::SimpleVariableValue>( new QuantLib::SimpleVariableValue(index,adjustedRefDate)); } else if(choiceStr_paraType == "indexTimeRef"){ const boost::shared_ptr<FpmlSerialized::IndexTimeRef>& serial_indexItmeRef = serial_vv->getIndexTimeRef(); const std::string& fixingTypeChoiceStr = serial_indexItmeRef->getFixingDays()->getChoiceStr_fixingType(); Integer fixingDays = 0; if(fixingTypeChoiceStr == "days"){ fixingDays = serial_indexItmeRef->getFixingDays()->getDays()->IValue(); }else { QL_FAIL("not implementation"); } Calendar calendar = PathInformation::instance().getCalendar(); const boost::shared_ptr<FpmlSerialized::UnderlyingIndex>& serial_under = serial_indexItmeRef->getUnderlyingIndexRef(); qlUnderlyingFactory ql_uf = qlUnderlyingFactory(); ql_uf.setSerialClass(serial_under); boost::shared_ptr<QuantLib::Index> index = ql_uf.getIndex(); ql_vv = boost::shared_ptr<QuantLib::SimpleTimeVariableValue>( new QuantLib::SimpleTimeVariableValue(index,fixingDays)); } else if(choiceStr_paraType == "symbolName"){ const std::string& symbolName = serial_vv->getSymbolName()->SValue(); ql_vv = boost::shared_ptr<QuantLib::ComplexVariableValue>( new QuantLib::ComplexVariableValue(symbolName)); } else if(choiceStr_paraType == "constValue"){ Real value = serial_vv->getConstValue()->DValue(); ql_vv = boost::shared_ptr<QuantLib::ConstVariableValue>(new QuantLib::ConstVariableValue(value)); } else { QL_FAIL("unknown type paraType"); } ql_vv->registManager(); this->variableValue_ = ql_vv; }
int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; Date todaysDate(15, February, 2002); Calendar calendar = TARGET(); Date settlementDate(19, February, 2002); Settings::instance().evaluationDate() = todaysDate; // flat yield term structure impling 1x5 swap at 5% boost::shared_ptr<Quote> flatRate(new SimpleQuote(0.04875825)); Handle<YieldTermStructure> rhTermStructure( boost::shared_ptr<FlatForward>( new FlatForward(settlementDate, Handle<Quote>(flatRate), Actual365Fixed()))); // Define the ATM/OTM/ITM swaps Frequency fixedLegFrequency = Annual; BusinessDayConvention fixedLegConvention = Unadjusted; BusinessDayConvention floatingLegConvention = ModifiedFollowing; DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); Frequency floatingLegFrequency = Semiannual; VanillaSwap::Type type = VanillaSwap::Payer; Rate dummyFixedRate = 0.03; boost::shared_ptr<IborIndex> indexSixMonths(new Euribor6M(rhTermStructure)); Date startDate = calendar.advance(settlementDate,1,Years, floatingLegConvention); Date maturity = calendar.advance(startDate,5,Years, floatingLegConvention); Schedule fixedSchedule(startDate,maturity,Period(fixedLegFrequency), calendar,fixedLegConvention,fixedLegConvention, DateGeneration::Forward,false); Schedule floatSchedule(startDate,maturity,Period(floatingLegFrequency), calendar,floatingLegConvention,floatingLegConvention, DateGeneration::Forward,false); boost::shared_ptr<VanillaSwap> swap(new VanillaSwap( type, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths->dayCounter())); swap->setPricingEngine(boost::shared_ptr<PricingEngine>( new DiscountingSwapEngine(rhTermStructure))); Rate fixedATMRate = swap->fairRate(); Rate fixedOTMRate = fixedATMRate * 1.2; Rate fixedITMRate = fixedATMRate * 0.8; boost::shared_ptr<VanillaSwap> atmSwap(new VanillaSwap( type, 1000.0, fixedSchedule, fixedATMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths->dayCounter())); boost::shared_ptr<VanillaSwap> otmSwap(new VanillaSwap( type, 1000.0, fixedSchedule, fixedOTMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths->dayCounter())); boost::shared_ptr<VanillaSwap> itmSwap(new VanillaSwap( type, 1000.0, fixedSchedule, fixedITMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths->dayCounter())); // defining the swaptions to be used in model calibration std::vector<Period> swaptionMaturities; swaptionMaturities.push_back(Period(1, Years)); swaptionMaturities.push_back(Period(2, Years)); swaptionMaturities.push_back(Period(3, Years)); swaptionMaturities.push_back(Period(4, Years)); swaptionMaturities.push_back(Period(5, Years)); std::vector<boost::shared_ptr<CalibrationHelper> > swaptions; // List of times that have to be included in the timegrid std::list<Time> times; Size i; for (i=0; i<numRows; i++) { Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1 Size k = i*numCols + j; boost::shared_ptr<Quote> vol(new SimpleQuote(swaptionVols[k])); swaptions.push_back(boost::shared_ptr<CalibrationHelper>(new SwaptionHelper(swaptionMaturities[i], Period(swapLenghts[j], Years), Handle<Quote>(vol), indexSixMonths, indexSixMonths->tenor(), indexSixMonths->dayCounter(), indexSixMonths->dayCounter(), rhTermStructure))); swaptions.back()->addTimesTo(times); } // Building time-grid TimeGrid grid(times.begin(), times.end(), 30); // defining the models boost::shared_ptr<G2> modelG2(new G2(rhTermStructure)); boost::shared_ptr<HullWhite> modelHW(new HullWhite(rhTermStructure)); boost::shared_ptr<HullWhite> modelHW2(new HullWhite(rhTermStructure)); boost::shared_ptr<BlackKarasinski> modelBK( new BlackKarasinski(rhTermStructure)); // model calibrations std::cout << "G2 (analytic formulae) calibration" << std::endl; for (i=0; i<swaptions.size(); i++) swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( new G2SwaptionEngine(modelG2, 6.0, 16))); calibrateModel(modelG2, swaptions); std::cout << "calibrated to:\n" << "a = " << modelG2->params()[0] << ", " << "sigma = " << modelG2->params()[1] << "\n" << "b = " << modelG2->params()[2] << ", " << "eta = " << modelG2->params()[3] << "\n" << "rho = " << modelG2->params()[4] << std::endl << std::endl; std::cout << "Hull-White (analytic formulae) calibration" << std::endl; for (i=0; i<swaptions.size(); i++) swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( new JamshidianSwaptionEngine(modelHW))); calibrateModel(modelHW, swaptions); std::cout << "calibrated to:\n" << "a = " << modelHW->params()[0] << ", " << "sigma = " << modelHW->params()[1] << std::endl << std::endl; std::cout << "Hull-White (numerical) calibration" << std::endl; for (i=0; i<swaptions.size(); i++) swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW2, grid))); calibrateModel(modelHW2, swaptions); std::cout << "calibrated to:\n" << "a = " << modelHW2->params()[0] << ", " << "sigma = " << modelHW2->params()[1] << std::endl << std::endl; std::cout << "Black-Karasinski (numerical) calibration" << std::endl; for (i=0; i<swaptions.size(); i++) swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelBK, grid))); calibrateModel(modelBK, swaptions); std::cout << "calibrated to:\n" << "a = " << modelBK->params()[0] << ", " << "sigma = " << modelBK->params()[1] << std::endl << std::endl; // ATM Bermudan swaption pricing std::cout << "Payer bermudan swaption " << "struck at " << io::rate(fixedATMRate) << " (ATM)" << std::endl; std::vector<Date> bermudanDates; const std::vector<boost::shared_ptr<CashFlow> >& leg = swap->fixedLeg(); for (i=0; i<leg.size(); i++) { boost::shared_ptr<Coupon> coupon = boost::dynamic_pointer_cast<Coupon>(leg[i]); bermudanDates.push_back(coupon->accrualStartDate()); } boost::shared_ptr<Exercise> bermudanExercise( new BermudanExercise(bermudanDates)); Swaption bermudanSwaption(atmSwap, bermudanExercise); // Do the pricing for each model // G2 price the European swaption here, it should switch to bermudan bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelG2, 50))); std::cout << "G2 (tree): " << bermudanSwaption.NPV() << std::endl; bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdG2SwaptionEngine(modelG2))); std::cout << "G2 (fdm) : " << bermudanSwaption.NPV() << std::endl; bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW, 50))); std::cout << "HW (tree): " << bermudanSwaption.NPV() << std::endl; bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdHullWhiteSwaptionEngine(modelHW))); std::cout << "HW (fdm) : " << bermudanSwaption.NPV() << std::endl; bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW2, 50))); std::cout << "HW (num, tree): " << bermudanSwaption.NPV() << std::endl; bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdHullWhiteSwaptionEngine(modelHW2))); std::cout << "HW (num, fdm) : " << bermudanSwaption.NPV() << std::endl; bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelBK, 50))); std::cout << "BK: " << bermudanSwaption.NPV() << std::endl; // OTM Bermudan swaption pricing std::cout << "Payer bermudan swaption " << "struck at " << io::rate(fixedOTMRate) << " (OTM)" << std::endl; Swaption otmBermudanSwaption(otmSwap,bermudanExercise); // Do the pricing for each model otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelG2, 300))); std::cout << "G2 (tree): " << otmBermudanSwaption.NPV() << std::endl; otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdG2SwaptionEngine(modelG2))); std::cout << "G2 (fdm) : " << otmBermudanSwaption.NPV() << std::endl; otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW, 50))); std::cout << "HW (tree): " << otmBermudanSwaption.NPV() << std::endl; otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdHullWhiteSwaptionEngine(modelHW))); std::cout << "HW (fdm) : " << otmBermudanSwaption.NPV() << std::endl; otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW2, 50))); std::cout << "HW (num, tree): " << otmBermudanSwaption.NPV() << std::endl; otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdHullWhiteSwaptionEngine(modelHW2))); std::cout << "HW (num, fdm): " << otmBermudanSwaption.NPV() << std::endl; otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelBK, 50))); std::cout << "BK: " << otmBermudanSwaption.NPV() << std::endl; // ITM Bermudan swaption pricing std::cout << "Payer bermudan swaption " << "struck at " << io::rate(fixedITMRate) << " (ITM)" << std::endl; Swaption itmBermudanSwaption(itmSwap,bermudanExercise); // Do the pricing for each model itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelG2, 50))); std::cout << "G2 (tree): " << itmBermudanSwaption.NPV() << std::endl; itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdG2SwaptionEngine(modelG2))); std::cout << "G2 (fdm) : " << itmBermudanSwaption.NPV() << std::endl; itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW, 50))); std::cout << "HW (tree): " << itmBermudanSwaption.NPV() << std::endl; itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdHullWhiteSwaptionEngine(modelHW))); std::cout << "HW (fdm) : " << itmBermudanSwaption.NPV() << std::endl; itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelHW2, 50))); std::cout << "HW (num, tree): " << itmBermudanSwaption.NPV() << std::endl; itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new FdHullWhiteSwaptionEngine(modelHW2))); std::cout << "HW (num, fdm) : " << itmBermudanSwaption.NPV() << std::endl; itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( new TreeSwaptionEngine(modelBK, 50))); std::cout << "BK: " << itmBermudanSwaption.NPV() << std::endl; double seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; std::cout << " \nRun completed in "; if (hours > 0) std::cout << hours << " h "; if (hours > 0 || minutes > 0) std::cout << minutes << " m "; std::cout << std::fixed << std::setprecision(0) << seconds << " s\n" << 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; } }
/* TODO: Instrument interface - swaps: euro swaps, usd - bonds: UST, corp, tax-exempt munis */ int main () { cout << "QuantLib Version #: " << QL_VERSION << endl ; Calendar calendar = TARGET(); // Date todaysDate = TARGET().adjust( Date(20, September, 2004) ); Date todaysDate = TARGET().adjust( Date(28, May, 2012) ); Settings::instance().evaluationDate() = todaysDate; cout << "settings: " << &Settings::instance() << endl; cout << "\n\nToday: " << todaysDate << endl; string futtenors[] = {"ED1", "ED2", "ED3", "ED4", "ED5", "ED6", "ED7", "ED8"}; double futspots[] = {96.2875, 96.7875, 96.9875, 96.6875, 96.4875, 96.3875, 96.2875, 96.0875}; string depotenors[] = {"1W", "1M", "3M", "6M", "9M", "1y"}; double depospots[] = {.0382, 0.0372, 0.0363, 0.0353, 0.0348, 0.0345}; string swaptenors[] = {"2y", "3y", "5y", "10Y", "15Y"}; double swapspots[] = {0.037125, 0.0398, 0.0443, 0.05165, 0.055175}; cout << "test sc1" << endl; RateHelperCurve acurve = RateHelperCurve(EURiborCurve("6M")); acurve.update(depotenors, depospots, 6, swaptenors, swapspots, 5, todaysDate); cout << "quote: " << acurve.tenorquote("10Y") << endl; cout << "test tenors\n" << Period(6, Months) << " | " << Tenor("6M") << endl; cout << "fixing calendar: " << acurve.calendar() << endl; /********************* * SWAPS TO BE PRICED * **********************/ RelinkableHandle<YieldTermStructure>forecastingTermStructure = acurve.forecastingTermStructure(); // constant nominal 1,000,000 Euro Real nominal = 1000000.0; // fixed leg Frequency fixedLegFrequency = Annual; BusinessDayConvention fixedLegConvention = Unadjusted; BusinessDayConvention floatingLegConvention = ModifiedFollowing; DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); Rate fixedRate = 0.04; DayCounter floatingLegDayCounter = Actual360(); // floating leg Frequency floatingLegFrequency = Semiannual; boost::shared_ptr<IborIndex> euriborIndex(new Euribor6M(forecastingTermStructure)); Spread spread = 0.0; Integer lenghtInYears = 5; VanillaSwap::Type swapType = VanillaSwap::Payer; Date settlementDate = acurve.referenceDate(); Date maturity = acurve.referenceDate() + lenghtInYears*Years; Schedule fixedSchedule(settlementDate, maturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule floatSchedule(settlementDate, maturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap spot5YearSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, Years); Date fwdMaturity = fwdStart + lenghtInYears*Years; Schedule fwdFixedSchedule(fwdStart, fwdMaturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule fwdFloatSchedule(fwdStart, fwdMaturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap oneYearForward5YearSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); cout << "swap." << endl; boost::shared_ptr<PricingEngine> swapEngine = createPriceEngine<DiscountingSwapEngine>( acurve.discountingTermStructure() ); spot5YearSwap.setPricingEngine(swapEngine); oneYearForward5YearSwap.setPricingEngine(swapEngine); Real NPV; Rate fairRate; Spread fairSpread; cout << "spot " << endl; NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); cout << std::setprecision(2) << std::setw(12) << std::fixed << "NPV : " << NPV << " | Fair Spread: " << io::rate(fairSpread) << " | Fair Rate: " << io::rate(fairRate) << endl; cout << std::setprecision(2) << std::setw(12) << std::fixed << "fx NPV : " << spot5YearSwap.fixedLegNPV() << " | fx NPV : " << spot5YearSwap.floatingLegNPV() << endl; cout << "forward " << endl; NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); cout << std::setprecision(2) << std::setw(12) << std::fixed << "NPV : " << NPV << " | Fair Spread: " << io::rate(fairSpread) << " | Fair Rate: " << io::rate(fairRate) << endl; cout << std::setprecision(2) << std::setw(12) << std::fixed << "fx NPV : " << oneYearForward5YearSwap.fixedLegNPV() << " | fx NPV : " << oneYearForward5YearSwap.floatingLegNPV() << endl; cout << "test libor clone" << endl; RelinkableHandle<YieldTermStructure> indexTermStructure; boost::shared_ptr<IborIndex> libor3m(new USDLibor(Period(3, Months), indexTermStructure)); Handle<YieldTermStructure>testTS = acurve.forecastingTermStructure(); boost::shared_ptr<IborIndex> newlib = libor3m->clone(testTS); // If one wanted a USD Libor index.... USDLiborBase testIndex; cout << "\n\nSwap to compare to first swap " << endl; cout << "Qswap" << endl; cout << "mty: " << maturity << " | cpn: " << io::rate(fixedRate) << endl; EuriborBase euribor(6, Months); FixedFloatSwap qswp(settlementDate, maturity, fixedRate, euribor(acurve.yieldTermStructurePtr()), FixedPayer, 0.0, 1000000.0, Annual, Thirty360(Thirty360::European), Unadjusted, Semiannual, Actual360(), ModifiedFollowing, TARGET() ); qswp.setPricingEngine(swapEngine); cout << std::setprecision(2) << std::setw(12) << std::fixed << "NPV : " << qswp.NPV() << " | Fair Spread: " << io::rate(qswp.fairSpread()) << " | Fair Rate: " << io::rate(qswp.fairRate()) << endl; cout << std::setprecision(2) << std::setw(12) << std::fixed << "fx NPV : " << qswp.fixedLegNPV() << " | fl NPV : " << qswp.floatingLegNPV() << endl; cout << "Inspect Legs" << endl << endl; Leg fixedLeg = qswp.fixedLeg(); Leg floatingLeg = qswp.floatingLeg(); cout << "Fixed: " << endl; Leg::iterator fxIt; int cfCount =0; Date cfDate; double cfAmt; double cfDF; double cfNPV = 0.0; for (fxIt=fixedLeg.begin(); fxIt < fixedLeg.end(); fxIt++) { cfDate = (*fxIt)->date(); cfAmt = (*fxIt)->amount(); cfDF = acurve.discount((*fxIt)->date()); cfNPV += cfAmt*cfDF; cout << cfCount++ << ") " << std::setw(24) << cfDate << " | " << std::setw(12) << cfAmt << " | " << std::setprecision(6) << cfDF << " | " << std::setprecision(2) << cfNPV << endl; } cout << "Floating: " << endl; Leg::iterator flIt; cfCount =0; cfNPV = 0.0; for (flIt=floatingLeg.begin(); flIt < floatingLeg.end(); flIt++) { cfDate = (*flIt)->date(); cfAmt = (*flIt)->amount(); cfDF = acurve.discount((*flIt)->date()); cfNPV += cfAmt*cfDF; cout << cfCount++ << ") " << std::setw(24) << cfDate << " | " << std::setw(12) << cfAmt << " | " << std::setprecision(6) << cfDF << " | " << std::setprecision(2) << cfNPV << endl; } cout << "swp2 " << endl; SwapType<Euribor> euriborswaps(Annual, Thirty360(Thirty360::European), Unadjusted, Semiannual, Actual360(), ModifiedFollowing, TARGET() ); cout << "create" << endl; boost::shared_ptr<FixedFloatSwap> qswp2 = euriborswaps.create(settlementDate, maturity, fixedRate); cout << "pricing" << endl; qswp2->setEngine(acurve); cout << "link" << endl; euriborswaps.linkIndex(acurve); cout << std::setprecision(2) << std::setw(12) << std::fixed << "NPV : " << qswp2->NPV() << " | Fair Spread: " << io::rate(qswp2->fairSpread()) << " | Fair Rate: " << io::rate(qswp2->fairRate()) << endl; cout << std::setprecision(2) << std::setw(12) << std::fixed << "fx NPV : " << qswp2->fixedLegNPV() << " | fx NPV : " << qswp2->floatingLegNPV() << endl; cout << "\nSwap 3: forward" << endl; boost::shared_ptr<FixedFloatSwap> qswp3 = euriborswaps.create(fwdStart, fwdMaturity, fixedRate); cout << "fixed rate: " << qswp3->fixedRate() << endl; qswp3->setPricingEngine(swapEngine); euriborswaps.linkIndexTo(acurve.yieldTermStructurePtr()); cout << std::setprecision(2) << std::setw(12) << std::fixed << "NPV : " << qswp3->NPV() << " | Fair Spread: " << io::rate(qswp3->fairSpread()) << " | Fair Rate: " << io::rate(qswp3->fairRate()) << endl; cout << std::setprecision(2) << std::setw(12) << std::fixed << "fx NPV : " << qswp3->fixedLegNPV() << " | fx NPV : " << qswp3->floatingLegNPV() << endl; cout << "\n\nBonds" << endl; boost::shared_ptr<BulletBond> bond1(new BulletBond(.045, Date(15, May, 2017), Date(15, May, 2003)) ); cout << "mty: " << bond1->maturityDate() << endl; cout << "stl: " << bond1->settlementDate() << endl; cout << "test" << endl; bond1->setEngine(acurve); cout << "bondprice: " ; double prc = bond1->cleanPrice(); cout << std::setprecision(3) << prc << endl; cout << "Yield: " ; double yld = bond1->yield(prc, bond1->dayCounter(), Compounded, bond1->frequency()); cout << io::rate(yld) << endl; cout << "\n\nIMM Stuff\n"; cout << "settle: " << settlementDate << endl; Date imm = IMM::nextDate(settlementDate); string immcode = IMM::code(imm); Date imm2 = imm_nextDate(imm); string immcode2 = imm_nextCode(immcode); cout << "date: " << imm << " | code: " << immcode << endl; cout << "date: " << imm2 << " | code: " << immcode2 << endl; cout << "ED3: " << FuturesTenor("ED3") << endl; CurveMap depocurve; CurveMap futscurve; CurveMap swapcurve; RateHelperCurve rhcurve( EURiborCurve("6M", Annual) ); if (futscurve.empty()) { cout << "futscurve empty " << endl; } else { cout << "futscurve not empty: " << endl; } for (int i=0; i<2; i++) depocurve[depotenors[i]] = depospots[i]; for (int i=0; i<6; i++) futscurve[futtenors[i]] = futspots[i]; for (int i=0; i<5; i++) swapcurve[swaptenors[i]] = swapspots[i]; rhcurve.update(depocurve, futscurve, swapcurve); cout << "\n10Y: " << io::rate(rhcurve.tenorquote("10Y")) << endl; cout << "discount: " << rhcurve.discount(10.0) << endl; return 0; }
int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; Option::Type type(Option::Put); Real underlying = 36.0; Real spreadRate = 0.005; Spread dividendYield = 0.02; Rate riskFreeRate = 0.06; Volatility volatility = 0.20; Integer settlementDays = 3; Integer length = 5; Real redemption = 100.0; Real conversionRatio = redemption/underlying; // at the money // set up dates/schedules Calendar calendar = TARGET(); Date today = calendar.adjust(Date::todaysDate()); Settings::instance().evaluationDate() = today; Date settlementDate = calendar.advance(today, settlementDays, Days); Date exerciseDate = calendar.advance(settlementDate, length, Years); Date issueDate = calendar.advance(exerciseDate, -length, Years); BusinessDayConvention convention = ModifiedFollowing; Frequency frequency = Annual; Schedule schedule(issueDate, exerciseDate, Period(frequency), calendar, convention, convention, DateGeneration::Backward, false); DividendSchedule dividends; CallabilitySchedule callability; std::vector<Real> coupons(1, 0.05); DayCounter bondDayCount = Thirty360(); Integer callLength[] = { 2, 4 }; // Call dates, years 2, 4. Integer putLength[] = { 3 }; // Put dates year 3 Real callPrices[] = { 101.5, 100.85 }; Real putPrices[]= { 105.0 }; // Load call schedules for (Size i=0; i<LENGTH(callLength); i++) { callability.push_back( boost::shared_ptr<Callability>( new SoftCallability(Callability::Price( callPrices[i], Callability::Price::Clean), schedule.date(callLength[i]), 1.20))); } for (Size j=0; j<LENGTH(putLength); j++) { callability.push_back( boost::shared_ptr<Callability>( new Callability(Callability::Price( putPrices[j], Callability::Price::Clean), Callability::Put, schedule.date(putLength[j])))); } // Assume dividends are paid every 6 months. for (Date d = today + 6*Months; d < exerciseDate; d += 6*Months) { dividends.push_back( boost::shared_ptr<Dividend>(new FixedDividend(1.0, d))); } DayCounter dayCounter = Actual365Fixed(); Time maturity = dayCounter.yearFraction(settlementDate, exerciseDate); std::cout << "option type = " << type << std::endl; std::cout << "Time to maturity = " << maturity << std::endl; std::cout << "Underlying price = " << underlying << std::endl; std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate) << std::endl; std::cout << "Dividend yield = " << io::rate(dividendYield) << std::endl; std::cout << "Volatility = " << io::volatility(volatility) << std::endl; std::cout << std::endl; std::string method; std::cout << std::endl ; // write column headings Size widths[] = { 35, 14, 14 }; Size totalWidth = widths[0] + widths[1] + widths[2]; std::string rule(totalWidth, '-'), dblrule(totalWidth, '='); std::cout << dblrule << std::endl; std::cout << "Tsiveriotis-Fernandes method" << std::endl; std::cout << dblrule << std::endl; std::cout << std::setw(widths[0]) << std::left << "Tree type" << std::setw(widths[1]) << std::left << "European" << std::setw(widths[1]) << std::left << "American" << std::endl; std::cout << rule << std::endl; boost::shared_ptr<Exercise> exercise( new EuropeanExercise(exerciseDate)); boost::shared_ptr<Exercise> amExercise( new AmericanExercise(settlementDate, exerciseDate)); Handle<Quote> underlyingH( boost::shared_ptr<Quote>(new SimpleQuote(underlying))); Handle<YieldTermStructure> flatTermStructure( boost::shared_ptr<YieldTermStructure>( new FlatForward(settlementDate, riskFreeRate, dayCounter))); Handle<YieldTermStructure> flatDividendTS( boost::shared_ptr<YieldTermStructure>( new FlatForward(settlementDate, dividendYield, dayCounter))); Handle<BlackVolTermStructure> flatVolTS( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(settlementDate, calendar, volatility, dayCounter))); boost::shared_ptr<BlackScholesMertonProcess> stochasticProcess( new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS)); Size timeSteps = 801; Handle<Quote> creditSpread( boost::shared_ptr<Quote>(new SimpleQuote(spreadRate))); boost::shared_ptr<Quote> rate(new SimpleQuote(riskFreeRate)); Handle<YieldTermStructure> discountCurve( boost::shared_ptr<YieldTermStructure>( new FlatForward(today, Handle<Quote>(rate), dayCounter))); boost::shared_ptr<PricingEngine> engine( new BinomialConvertibleEngine<JarrowRudd>(stochasticProcess, timeSteps)); ConvertibleFixedCouponBond europeanBond( exercise, conversionRatio, dividends, callability, creditSpread, issueDate, settlementDays, coupons, bondDayCount, schedule, redemption); europeanBond.setPricingEngine(engine); ConvertibleFixedCouponBond americanBond( amExercise, conversionRatio, dividends, callability, creditSpread, issueDate, settlementDays, coupons, bondDayCount, schedule, redemption); americanBond.setPricingEngine(engine); method = "Jarrow-Rudd"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<JarrowRudd>(stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<JarrowRudd>(stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; method = "Cox-Ross-Rubinstein"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<CoxRossRubinstein>(stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<CoxRossRubinstein>(stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; method = "Additive equiprobabilities"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<AdditiveEQPBinomialTree>( stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<AdditiveEQPBinomialTree>( stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; method = "Trigeorgis"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<Trigeorgis>(stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<Trigeorgis>(stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; method = "Tian"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<Tian>(stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<Tian>(stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; method = "Leisen-Reimer"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<LeisenReimer>(stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<LeisenReimer>(stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; method = "Joshi"; europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<Joshi4>(stochasticProcess, timeSteps))); americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialConvertibleEngine<Joshi4>(stochasticProcess, timeSteps))); std::cout << std::setw(widths[0]) << std::left << method << std::fixed << std::setw(widths[1]) << std::left << europeanBond.NPV() << std::setw(widths[2]) << std::left << americanBond.NPV() << std::endl; std::cout << dblrule << std::endl; Real seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; std::cout << " \nRun completed in "; if (hours > 0) std::cout << hours << " h "; if (hours > 0 || minutes > 0) std::cout << minutes << " m "; std::cout << std::fixed << std::setprecision(0) << seconds << " s\n" << 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; } }
int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; /********************* *** MARKET DATA *** *********************/ RelinkableHandle<YieldTermStructure> euriborTermStructure; boost::shared_ptr<IborIndex> euribor3m( new Euribor3M(euriborTermStructure)); Date todaysDate = Date(23, May, 2006); Settings::instance().evaluationDate() = todaysDate; Calendar calendar = euribor3m->fixingCalendar(); Integer fixingDays = euribor3m->fixingDays(); Date settlementDate = calendar.advance(todaysDate, fixingDays, Days); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // 3 month term FRA quotes (index refers to monthsToStart) Rate threeMonthFraQuote[10]; threeMonthFraQuote[1]=0.030; threeMonthFraQuote[2]=0.031; threeMonthFraQuote[3]=0.032; threeMonthFraQuote[6]=0.033; threeMonthFraQuote[9]=0.034; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // FRAs boost::shared_ptr<SimpleQuote> fra1x4Rate( new SimpleQuote(threeMonthFraQuote[1])); boost::shared_ptr<SimpleQuote> fra2x5Rate( new SimpleQuote(threeMonthFraQuote[2])); boost::shared_ptr<SimpleQuote> fra3x6Rate( new SimpleQuote(threeMonthFraQuote[3])); boost::shared_ptr<SimpleQuote> fra6x9Rate( new SimpleQuote(threeMonthFraQuote[6])); boost::shared_ptr<SimpleQuote> fra9x12Rate( new SimpleQuote(threeMonthFraQuote[9])); RelinkableHandle<Quote> h1x4; h1x4.linkTo(fra1x4Rate); RelinkableHandle<Quote> h2x5; h2x5.linkTo(fra2x5Rate); RelinkableHandle<Quote> h3x6; h3x6.linkTo(fra3x6Rate); RelinkableHandle<Quote> h6x9; h6x9.linkTo(fra6x9Rate); RelinkableHandle<Quote> h9x12; h9x12.linkTo(fra9x12Rate); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. DayCounter fraDayCounter = euribor3m->dayCounter(); BusinessDayConvention convention = euribor3m->businessDayConvention(); bool endOfMonth = euribor3m->endOfMonth(); boost::shared_ptr<RateHelper> fra1x4( new FraRateHelper(h1x4, 1, 4, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra2x5( new FraRateHelper(h2x5, 2, 5, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra3x6( new FraRateHelper(h3x6, 3, 6, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra6x9( new FraRateHelper(h6x9, 6, 9, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra9x12( new FraRateHelper(h9x12, 9, 12, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A FRA curve std::vector<boost::shared_ptr<RateHelper> > fraInstruments; fraInstruments.push_back(fra1x4); fraInstruments.push_back(fra2x5); fraInstruments.push_back(fra3x6); fraInstruments.push_back(fra6x9); fraInstruments.push_back(fra9x12); boost::shared_ptr<YieldTermStructure> fraTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, fraInstruments, termStructureDayCounter, tolerance)); // Term structures used for pricing/discounting RelinkableHandle<YieldTermStructure> discountingTermStructure; discountingTermStructure.linkTo(fraTermStructure); /*********************** *** construct FRA's *** ***********************/ Calendar fraCalendar = euribor3m->fixingCalendar(); BusinessDayConvention fraBusinessDayConvention = euribor3m->businessDayConvention(); Position::Type fraFwdType = Position::Long; Real fraNotional = 100.0; const Integer FraTermMonths = 3; Integer monthsToStart[] = { 1, 2, 3, 6, 9 }; euriborTermStructure.linkTo(fraTermStructure); cout << endl; cout << "Test FRA construction, NPV calculation, and FRA purchase" << endl << endl; Size i; for (i=0; i<LENGTH(monthsToStart); i++) { Date fraValueDate = fraCalendar.advance( settlementDate,monthsToStart[i],Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,FraTermMonths,Months, fraBusinessDayConvention); Rate fraStrikeRate = threeMonthFraQuote[monthsToStart[i]]; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType,fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << "3m Term FRA, Months to Start: " << monthsToStart[i] << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(threeMonthFraQuote[monthsToStart[i]]) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be zero]: " << myFRA.NPV() << endl << endl; } cout << endl << endl; cout << "Now take a 100 basis-point upward shift in FRA quotes " << "and examine NPV" << endl << endl; const Real BpsShift = 0.01; threeMonthFraQuote[1]=0.030+BpsShift; threeMonthFraQuote[2]=0.031+BpsShift; threeMonthFraQuote[3]=0.032+BpsShift; threeMonthFraQuote[6]=0.033+BpsShift; threeMonthFraQuote[9]=0.034+BpsShift; fra1x4Rate->setValue(threeMonthFraQuote[1]); fra2x5Rate->setValue(threeMonthFraQuote[2]); fra3x6Rate->setValue(threeMonthFraQuote[3]); fra6x9Rate->setValue(threeMonthFraQuote[6]); fra9x12Rate->setValue(threeMonthFraQuote[9]); for (i=0; i<LENGTH(monthsToStart); i++) { Date fraValueDate = fraCalendar.advance( settlementDate,monthsToStart[i],Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,FraTermMonths,Months, fraBusinessDayConvention); Rate fraStrikeRate = threeMonthFraQuote[monthsToStart[i]] - BpsShift; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << "3m Term FRA, 100 notional, Months to Start = " << monthsToStart[i] << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(threeMonthFraQuote[monthsToStart[i]]) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be positive]: " << myFRA.NPV() << endl << endl; } double seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; cout << " \nRun completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s\n" << endl; return 0; } catch (exception& e) { cerr << e.what() << endl; return 1; } catch (...) { cerr << "unknown error" << endl; return 1; } }
/*Market Data -> FRA Quote -> FRA rate helper -> Curve Building -> Construct FRA*/ int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; std::ifstream file("data.csv"); CSVRow data_row; file >> data_row; const size_t num_data = data_row.size()/2; /********************* *** MARKET DATA *** *********************/ RelinkableHandle<YieldTermStructure> euriborTermStructure; boost::shared_ptr<IborIndex> euribor3m( new Euribor3M(euriborTermStructure)); Date todaysDate = Date(23, May, 2006); Settings::instance().evaluationDate() = todaysDate; Calendar calendar = euribor3m->fixingCalendar(); Integer fixingDays = euribor3m->fixingDays(); Date settlementDate = calendar.advance(todaysDate, fixingDays, Days); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // 3 month term FRA quotes (index refers to monthsToStart) vector <stFRAMarketData> vecMarketData; for(size_t i = 0 ; i < num_data; i++) { stFRAMarketData element_data; convertFromString(element_data.iMonthToStart, data_row[i]); element_data.iTermDuration = 3; //3 month term convertFromString(element_data.rateFraQuote, data_row[i + num_data]); vecMarketData.push_back(element_data); } /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // FRAs std::vector <boost::shared_ptr<SimpleQuote> > vecFRAQuote; for(size_t i = 0 ; i < num_data; i++) { boost::shared_ptr<SimpleQuote> fraRate(new SimpleQuote(vecMarketData[i].rateFraQuote)); vecFRAQuote.push_back(fraRate); } std::vector <RelinkableHandle<Quote> > vecQuoteHandle; for(size_t i = 0 ; i < num_data; i++) { RelinkableHandle<Quote> hQuote; hQuote.linkTo(vecFRAQuote[i]); vecQuoteHandle.push_back(hQuote); } /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. DayCounter fraDayCounter = euribor3m->dayCounter(); BusinessDayConvention convention = euribor3m->businessDayConvention(); bool endOfMonth = euribor3m->endOfMonth(); std::vector < boost::shared_ptr<RateHelper> > vecRateHelper; for(size_t i = 0 ; i < num_data; i++) { boost::shared_ptr<RateHelper> fra_helper( new FraRateHelper(vecQuoteHandle[i],vecMarketData[i].iMonthToStart, vecMarketData[i].iMonthToStart + vecMarketData[i].iTermDuration, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); vecRateHelper.push_back(fra_helper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A FRA curve boost::shared_ptr<YieldTermStructure> fraTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, vecRateHelper, termStructureDayCounter, tolerance)); // Term structures used for pricing/discounting RelinkableHandle<YieldTermStructure> discountingTermStructure; discountingTermStructure.linkTo(fraTermStructure); /*********************** *** construct FRA's *** ***********************/ Calendar fraCalendar = euribor3m->fixingCalendar(); BusinessDayConvention fraBusinessDayConvention = euribor3m->businessDayConvention(); Position::Type fraFwdType = Position::Long; Real fraNotional = 100.0; //const Integer FraTermMonths = 3; //Integer monthsToStart[] = { 1, 2, 3, 6, 9 }; euriborTermStructure.linkTo(fraTermStructure); cout << endl; cout << "Test FRA construction, NPV calculation, and FRA purchase" << endl << endl; Size i; for (i=0; i < num_data; i++) { Date fraValueDate = fraCalendar.advance( settlementDate,vecMarketData[i].iMonthToStart, Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,vecMarketData[i].iTermDuration,Months, fraBusinessDayConvention); Rate fraStrikeRate = vecMarketData[i].rateFraQuote; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType,fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << vecMarketData[i].iTermDuration<<"m Term FRA, Months to Start: " << vecMarketData[i].iMonthToStart << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(vecMarketData[i].rateFraQuote) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be zero]: " << myFRA.NPV() << endl << endl; } cout << endl << endl; cout << "Now take a 100 basis-point upward shift in FRA quotes " << "and examine NPV" << endl << endl; const Real BpsShift = 0.01; for(size_t i = 0; i< num_data; i++ ) { vecMarketData[i].rateFraQuote += BpsShift; vecFRAQuote[i]->setValue(vecMarketData[i].rateFraQuote); } for (i=0; i<num_data; i++) { Date fraValueDate = fraCalendar.advance( settlementDate,vecMarketData[i].iMonthToStart,Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,vecMarketData[i].iTermDuration,Months, fraBusinessDayConvention); Rate fraStrikeRate = vecMarketData[i].rateFraQuote - BpsShift; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << vecMarketData[i].iTermDuration <<"m Term FRA, 100 notional, Months to Start = " << vecMarketData[i].iMonthToStart << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(vecMarketData[i].rateFraQuote) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be positive]: " << myFRA.NPV() << endl << endl; } Real seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; cout << " \nRun completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s\n" << endl; return 0; } catch (exception& e) { cerr << e.what() << endl; return 1; } catch (...) { cerr << "unknown error" << endl; return 1; } }
Schedule::Schedule(Date effectiveDate, const Date& terminationDate, const Period& tenor, const Calendar& cal, BusinessDayConvention convention, BusinessDayConvention terminationDateConvention, DateGeneration::Rule rule, bool endOfMonth, const Date& first, const Date& nextToLast) : tenor_(tenor), calendar_(cal), convention_(convention), terminationDateConvention_(terminationDateConvention), rule_(rule), endOfMonth_(allowsEndOfMonth(tenor) ? endOfMonth : false), firstDate_(first==effectiveDate ? Date() : first), nextToLastDate_(nextToLast==terminationDate ? Date() : nextToLast) { // sanity checks QL_REQUIRE(terminationDate != Date(), "null termination date"); // in many cases (e.g. non-expired bonds) the effective date is not // really necessary. In these cases a decent placeholder is enough if (effectiveDate==Date() && first==Date() && rule==DateGeneration::Backward) { Date evalDate = Settings::instance().evaluationDate(); QL_REQUIRE(evalDate < terminationDate, "null effective date"); Natural y; if (nextToLast != Date()) { y = (nextToLast - evalDate)/366 + 1; effectiveDate = nextToLast - y*Years; } else { y = (terminationDate - evalDate)/366 + 1; effectiveDate = terminationDate - y*Years; } } else QL_REQUIRE(effectiveDate != Date(), "null effective date"); QL_REQUIRE(effectiveDate < terminationDate, "effective date (" << effectiveDate << ") later than or equal to termination date (" << terminationDate << ")"); if (tenor.length()==0) rule_ = DateGeneration::Zero; else QL_REQUIRE(tenor.length()>0, "non positive tenor (" << tenor << ") not allowed"); if (firstDate_ != Date()) { switch (*rule_) { case DateGeneration::Backward: case DateGeneration::Forward: QL_REQUIRE(firstDate_ > effectiveDate && firstDate_ < terminationDate, "first date (" << firstDate_ << ") out of effective-termination date range [" << effectiveDate << ", " << terminationDate << ")"); // we should ensure that the above condition is still // verified after adjustment break; case DateGeneration::ThirdWednesday: QL_REQUIRE(IMM::isIMMdate(firstDate_, false), "first date (" << firstDate_ << ") is not an IMM date"); break; case DateGeneration::Zero: case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: case DateGeneration::OldCDS: case DateGeneration::CDS: QL_FAIL("first date incompatible with " << *rule_ << " date generation rule"); default: QL_FAIL("unknown rule (" << Integer(*rule_) << ")"); } } if (nextToLastDate_ != Date()) { switch (*rule_) { case DateGeneration::Backward: case DateGeneration::Forward: QL_REQUIRE(nextToLastDate_ > effectiveDate && nextToLastDate_ < terminationDate, "next to last date (" << nextToLastDate_ << ") out of effective-termination date range (" << effectiveDate << ", " << terminationDate << "]"); // we should ensure that the above condition is still // verified after adjustment break; case DateGeneration::ThirdWednesday: QL_REQUIRE(IMM::isIMMdate(nextToLastDate_, false), "next-to-last date (" << nextToLastDate_ << ") is not an IMM date"); break; case DateGeneration::Zero: case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: case DateGeneration::OldCDS: case DateGeneration::CDS: QL_FAIL("next to last date incompatible with " << *rule_ << " date generation rule"); default: QL_FAIL("unknown rule (" << Integer(*rule_) << ")"); } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = NullCalendar(); Integer periods = 1; Date seed, exitDate; switch (*rule_) { case DateGeneration::Zero: tenor_ = 0*Years; dates_.push_back(effectiveDate); dates_.push_back(terminationDate); isRegular_.push_back(true); break; case DateGeneration::Backward: dates_.push_back(terminationDate); seed = terminationDate; if (nextToLastDate_ != Date()) { dates_.insert(dates_.begin(), nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods*(*tenor_), convention, *endOfMonth_); if (temp!=nextToLastDate_) isRegular_.insert(isRegular_.begin(), false); else isRegular_.insert(isRegular_.begin(), true); seed = nextToLastDate_; } exitDate = effectiveDate; if (firstDate_ != Date()) exitDate = firstDate_; for (;;) { Date temp = nullCalendar.advance(seed, -periods*(*tenor_), convention, *endOfMonth_); if (temp < exitDate) { if (firstDate_ != Date() && (calendar_.adjust(dates_.front(),convention)!= calendar_.adjust(firstDate_,convention))) { dates_.insert(dates_.begin(), firstDate_); isRegular_.insert(isRegular_.begin(), false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.front(),convention)!= calendar_.adjust(temp,convention)) { dates_.insert(dates_.begin(), temp); isRegular_.insert(isRegular_.begin(), true); } ++periods; } } if (calendar_.adjust(dates_.front(),convention)!= calendar_.adjust(effectiveDate,convention)) { dates_.insert(dates_.begin(), effectiveDate); isRegular_.insert(isRegular_.begin(), false); } break; case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: case DateGeneration::ThirdWednesday: case DateGeneration::OldCDS: case DateGeneration::CDS: QL_REQUIRE(!*endOfMonth_, "endOfMonth convention incompatible with " << *rule_ << " date generation rule"); // fall through case DateGeneration::Forward: if (*rule_ == DateGeneration::CDS) { dates_.push_back(previousTwentieth(effectiveDate, DateGeneration::CDS)); } else { dates_.push_back(effectiveDate); } seed = dates_.back(); if (firstDate_!=Date()) { dates_.push_back(firstDate_); Date temp = nullCalendar.advance(seed, periods*(*tenor_), convention, *endOfMonth_); if (temp!=firstDate_) isRegular_.push_back(false); else isRegular_.push_back(true); seed = firstDate_; } else if (*rule_ == DateGeneration::Twentieth || *rule_ == DateGeneration::TwentiethIMM || *rule_ == DateGeneration::OldCDS || *rule_ == DateGeneration::CDS) { Date next20th = nextTwentieth(effectiveDate, *rule_); if (*rule_ == DateGeneration::OldCDS) { // distance rule inforced in natural days static const BigInteger stubDays = 30; if (next20th - effectiveDate < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, *rule_); } } if (next20th != effectiveDate) { dates_.push_back(next20th); isRegular_.push_back(false); seed = next20th; } } exitDate = terminationDate; if (nextToLastDate_ != Date()) exitDate = nextToLastDate_; for (;;) { Date temp = nullCalendar.advance(seed, periods*(*tenor_), convention, *endOfMonth_); if (temp > exitDate) { if (nextToLastDate_ != Date() && (calendar_.adjust(dates_.back(),convention)!= calendar_.adjust(nextToLastDate_,convention))) { dates_.push_back(nextToLastDate_); isRegular_.push_back(false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.back(),convention)!= calendar_.adjust(temp,convention)) { dates_.push_back(temp); isRegular_.push_back(true); } ++periods; } } if (calendar_.adjust(dates_.back(),terminationDateConvention)!= calendar_.adjust(terminationDate,terminationDateConvention)) { if (*rule_ == DateGeneration::Twentieth || *rule_ == DateGeneration::TwentiethIMM || *rule_ == DateGeneration::OldCDS || *rule_ == DateGeneration::CDS) { dates_.push_back(nextTwentieth(terminationDate, *rule_)); isRegular_.push_back(true); } else { dates_.push_back(terminationDate); isRegular_.push_back(false); } } break; default: QL_FAIL("unknown rule (" << Integer(*rule_) << ")"); } // adjustments if (*rule_==DateGeneration::ThirdWednesday) for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = Date::nthWeekday(3, Wednesday, dates_[i].month(), dates_[i].year()); if (*endOfMonth_ && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention == Unadjusted) { for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = Date::endOfMonth(dates_[i]); } else { for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = calendar_.endOfMonth(dates_[i]); } if (terminationDateConvention != Unadjusted) { dates_.front() = calendar_.endOfMonth(dates_.front()); dates_.back() = calendar_.endOfMonth(dates_.back()); } else { // the termination date is the first if going backwards, // the last otherwise. if (*rule_ == DateGeneration::Backward) dates_.back() = Date::endOfMonth(dates_.back()); else dates_.front() = Date::endOfMonth(dates_.front()); } } else { // first date not adjusted for CDS schedules if (*rule_ != DateGeneration::OldCDS) dates_[0] = calendar_.adjust(dates_[0], convention); for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = calendar_.adjust(dates_[i], convention); // termination date is NOT adjusted as per ISDA // specifications, unless otherwise specified in the // confirmation of the deal or unless we're creating a CDS // schedule if (terminationDateConvention != Unadjusted || *rule_ == DateGeneration::Twentieth || *rule_ == DateGeneration::TwentiethIMM || *rule_ == DateGeneration::OldCDS || *rule_ == DateGeneration::CDS) { dates_.back() = calendar_.adjust(dates_.back(), terminationDateConvention); } } // Final safety checks to remove extra next-to-last date, if // necessary. It can happen to be equal or later than the end // date due to EOM adjustments (see the Schedule test suite // for an example). if (dates_.size() >= 2 && dates_[dates_.size()-2] >= dates_.back()) { isRegular_[dates_.size()-2] = (dates_[dates_.size()-2] == dates_.back()); dates_[dates_.size()-2] = dates_.back(); dates_.pop_back(); isRegular_.pop_back(); } if (dates_.size() >= 2 && dates_[1] <= dates_.front()) { isRegular_[1] = (dates_[1] == dates_.front()); dates_[1] = dates_.front(); dates_.erase(dates_.begin()); isRegular_.erase(isRegular_.begin()); } QL_ENSURE(dates_.size()>1, "degenerate single date (" << dates_[0] << ") schedule" << "\n seed date: " << seed << "\n exit date: " << exitDate << "\n effective date: " << effectiveDate << "\n first date: " << first << "\n next to last date: " << nextToLast << "\n termination date: " << terminationDate << "\n generation rule: " << *rule_ << "\n end of month: " << *endOfMonth_); }
void QtSwap::qtswap() { try { boost::timer timer; std::cout << std::endl; /********************* *** MARKET DATA *** *********************/ Calendar calendar = TARGET(); Date settlementDate(22, September, 2004); // must be a business day settlementDate = calendar.adjust(settlementDate); Integer fixingDays = 2; Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days); // nothing to do with Date::todaysDate Settings::instance().evaluationDate() = todaysDate; todaysDate = Settings::instance().evaluationDate(); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // deposits Rate d1wQuote=0.0382; Rate d1mQuote=0.0372; Rate d3mQuote=0.0363; Rate d6mQuote=0.0353; Rate d9mQuote=0.0348; Rate d1yQuote=0.0345; // FRAs Rate fra3x6Quote=0.037125; Rate fra6x9Quote=0.037125; Rate fra6x12Quote=0.037125; // futures Real fut1Quote=96.2875; Real fut2Quote=96.7875; Real fut3Quote=96.9875; Real fut4Quote=96.6875; Real fut5Quote=96.4875; Real fut6Quote=96.3875; Real fut7Quote=96.2875; Real fut8Quote=96.0875; // swaps Rate s2yQuote=0.037125; Rate s3yQuote=0.0398; Rate s5yQuote=0.0443; Rate s10yQuote=0.05165; Rate s15yQuote=0.055175; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits 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)); // FRAs boost::shared_ptr<Quote> fra3x6Rate(new SimpleQuote(fra3x6Quote)); boost::shared_ptr<Quote> fra6x9Rate(new SimpleQuote(fra6x9Quote)); boost::shared_ptr<Quote> fra6x12Rate(new SimpleQuote(fra6x12Quote)); // futures boost::shared_ptr<Quote> fut1Price(new SimpleQuote(fut1Quote)); boost::shared_ptr<Quote> fut2Price(new SimpleQuote(fut2Quote)); boost::shared_ptr<Quote> fut3Price(new SimpleQuote(fut3Quote)); boost::shared_ptr<Quote> fut4Price(new SimpleQuote(fut4Quote)); boost::shared_ptr<Quote> fut5Price(new SimpleQuote(fut5Quote)); boost::shared_ptr<Quote> fut6Price(new SimpleQuote(fut6Quote)); boost::shared_ptr<Quote> fut7Price(new SimpleQuote(fut7Quote)); boost::shared_ptr<Quote> fut8Price(new SimpleQuote(fut8Quote)); // swaps 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 HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // 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 FRAs boost::shared_ptr<RateHelper> fra3x6(new FraRateHelper( Handle<Quote>(fra3x6Rate), 3, 6, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> fra6x9(new FraRateHelper( Handle<Quote>(fra6x9Rate), 6, 9, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> fra6x12(new FraRateHelper( Handle<Quote>(fra6x12Rate), 6, 12, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); // setup futures // Rate convexityAdjustment = 0.0; Integer futMonths = 3; Date imm = IMM::nextDate(settlementDate); boost::shared_ptr<RateHelper> fut1(new FuturesRateHelper( Handle<Quote>(fut1Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut2(new FuturesRateHelper( Handle<Quote>(fut2Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut3(new FuturesRateHelper( Handle<Quote>(fut3Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut4(new FuturesRateHelper( Handle<Quote>(fut4Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut5(new FuturesRateHelper( Handle<Quote>(fut5Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut6(new FuturesRateHelper( Handle<Quote>(fut6Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut7(new FuturesRateHelper( Handle<Quote>(fut7Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut8(new FuturesRateHelper( Handle<Quote>(fut8Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); // setup swaps Frequency swFixedLegFrequency = Annual; BusinessDayConvention swFixedLegConvention = Unadjusted; DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European); boost::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M); boost::shared_ptr<RateHelper> s2y(new SwapRateHelper( Handle<Quote>(s2yRate), 2*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s3y(new SwapRateHelper( Handle<Quote>(s3yRate), 3*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s5y(new SwapRateHelper( Handle<Quote>(s5yRate), 5*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s10y(new SwapRateHelper( Handle<Quote>(s10yRate), 10*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s15y(new SwapRateHelper( Handle<Quote>(s15yRate), 15*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // 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)); // A depo-futures-swap curve std::vector<boost::shared_ptr<RateHelper> > depoFutSwapInstruments; depoFutSwapInstruments.push_back(d1w); depoFutSwapInstruments.push_back(d1m); depoFutSwapInstruments.push_back(fut1); depoFutSwapInstruments.push_back(fut2); depoFutSwapInstruments.push_back(fut3); depoFutSwapInstruments.push_back(fut4); depoFutSwapInstruments.push_back(fut5); depoFutSwapInstruments.push_back(fut6); depoFutSwapInstruments.push_back(fut7); depoFutSwapInstruments.push_back(fut8); depoFutSwapInstruments.push_back(s3y); depoFutSwapInstruments.push_back(s5y); depoFutSwapInstruments.push_back(s10y); depoFutSwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoFutSwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFutSwapInstruments, termStructureDayCounter, tolerance)); // A depo-FRA-swap curve std::vector<boost::shared_ptr<RateHelper> > depoFRASwapInstruments; depoFRASwapInstruments.push_back(d1w); depoFRASwapInstruments.push_back(d1m); depoFRASwapInstruments.push_back(d3m); depoFRASwapInstruments.push_back(fra3x6); depoFRASwapInstruments.push_back(fra6x9); depoFRASwapInstruments.push_back(fra6x12); depoFRASwapInstruments.push_back(s2y); depoFRASwapInstruments.push_back(s3y); depoFRASwapInstruments.push_back(s5y); depoFRASwapInstruments.push_back(s10y); depoFRASwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoFRASwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFRASwapInstruments, termStructureDayCounter, tolerance)); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure; // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure; /********************* * SWAPS TO BE PRICED * **********************/ // constant nominal 1,000,000 Euro Real nominal = 1000000.0; // fixed leg Frequency fixedLegFrequency = Annual; BusinessDayConvention fixedLegConvention = Unadjusted; BusinessDayConvention floatingLegConvention = ModifiedFollowing; DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); Rate fixedRate = 0.04; DayCounter floatingLegDayCounter = Actual360(); // floating leg Frequency floatingLegFrequency = Semiannual; boost::shared_ptr<IborIndex> euriborIndex( new Euribor6M(forecastingTermStructure)); Spread spread = 0.0; Integer lenghtInYears = 5; VanillaSwap::Type swapType = VanillaSwap::Payer; Date maturity = settlementDate + lenghtInYears*Years; Schedule fixedSchedule(settlementDate, maturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule floatSchedule(settlementDate, maturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap spot5YearSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, Years); Date fwdMaturity = fwdStart + lenghtInYears*Years; Schedule fwdFixedSchedule(fwdStart, fwdMaturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule fwdFloatSchedule(fwdStart, fwdMaturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap oneYearForward5YearSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); /*************** * SWAP PRICING * ****************/ // utilities for reporting std::vector<std::string> headers(4); headers[0] = "term structure"; headers[1] = "net present value"; headers[2] = "fair spread"; headers[3] = "fair fixed rate"; std::string separator = " | "; Size width = headers[0].size() + separator.size() + headers[1].size() + separator.size() + headers[2].size() + separator.size() + headers[3].size() + separator.size() - 1; std::string rule(width, '-'), dblrule(width, '='); std::string tab(8, ' '); // calculations std::cout << dblrule << std::endl; std::cout << "5-year market swap-rate = " << std::setprecision(2) << io::rate(s5yRate->value()) << std::endl; std::cout << dblrule << std::endl; std::cout << tab << "5-years swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; Real NPV; Rate fairRate; Spread fairSpread; boost::shared_ptr<PricingEngine> swapEngine( new DiscountingSwapEngine(discountingTermStructure)); spot5YearSwap.setPricingEngine(swapEngine); oneYearForward5YearSwap.setPricingEngine(swapEngine); // Of course, you're not forced to really use different curves forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; // let's check that the 5 years swap has been correctly re-priced QL_REQUIRE(std::fabs(fairRate-s5yQuote)<1e-8, "5-years swap mispriced by " << io::rate(std::fabs(fairRate-s5yQuote))); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yQuote)<1e-8, "5-years swap mispriced!"); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yQuote)<1e-8, "5-years swap mispriced!"); std::cout << rule << std::endl; // now let's price the 1Y forward 5Y swap std::cout << tab << "5-years, 1-year forward swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; // now let's say that the 5-years swap rate goes up to 4.60%. // A smarter market element--say, connected to a data source-- would // notice the change itself. Since we're using SimpleQuotes, // we'll have to change the value manually--which forces us to // downcast the handle and use the SimpleQuote // interface. In any case, the point here is that a change in the // value contained in the Quote triggers a new bootstrapping // of the curve and a repricing of the swap. boost::shared_ptr<SimpleQuote> fiveYearsRate = boost::dynamic_pointer_cast<SimpleQuote>(s5yRate); fiveYearsRate->setValue(0.0460); std::cout << dblrule << std::endl; std::cout << "5-year market swap-rate = " << io::rate(s5yRate->value()) << std::endl; std::cout << dblrule << std::endl; std::cout << tab << "5-years swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; // now get the updated results forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8, "5-years swap mispriced!"); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8, "5-years swap mispriced!"); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8, "5-years swap mispriced!"); std::cout << rule << std::endl; // the 1Y forward 5Y swap changes as well std::cout << tab << "5-years, 1-year forward swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; Real seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; std::cout << " \nRun completed in "; if (hours > 0) std::cout << hours << " h "; if (hours > 0 || minutes > 0) std::cout << minutes << " m "; std::cout << std::fixed << std::setprecision(0) << seconds << " s\n" << std::endl; } catch (std::exception& e) { std::cerr << e.what() << std::endl; } catch (...) { std::cerr << "unknown error" << std::endl; } }
void DefaultProbabilityCurveTest::testDefaultProbability() { BOOST_TEST_MESSAGE("Testing default-probability structure..."); Real hazardRate = 0.0100; Handle<Quote> hazardRateQuote = Handle<Quote>( boost::shared_ptr<Quote>(new SimpleQuote(hazardRate))); DayCounter dayCounter = Actual360(); Calendar calendar = TARGET(); Size n = 20; double tolerance = 1.0e-10; Date today = Settings::instance().evaluationDate(); Date startDate = today; Date endDate = startDate; FlatHazardRate flatHazardRate(startDate, hazardRateQuote, dayCounter); for(Size i=0; i<n; i++){ startDate = endDate; endDate = calendar.advance(endDate, 1, Years); Probability pStart = flatHazardRate.defaultProbability(startDate); Probability pEnd = flatHazardRate.defaultProbability(endDate); Probability pBetweenComputed = flatHazardRate.defaultProbability(startDate, endDate); Probability pBetween = pEnd - pStart; if (std::fabs(pBetween - pBetweenComputed) > tolerance) BOOST_ERROR( "Failed to reproduce probability(d1, d2) " << "for default probability structure\n" << std::setprecision(12) << " calculated probability: " << pBetweenComputed << "\n" << " expected probability: " << pBetween); Time t2 = dayCounter.yearFraction(today, endDate); Probability timeProbability = flatHazardRate.defaultProbability(t2); Probability dateProbability = flatHazardRate.defaultProbability(endDate); if (std::fabs(timeProbability - dateProbability) > tolerance) BOOST_ERROR( "single-time probability and single-date probability do not match\n" << std::setprecision(10) << " time probability: " << timeProbability << "\n" << " date probability: " << dateProbability); Time t1 = dayCounter.yearFraction(today, startDate); timeProbability = flatHazardRate.defaultProbability(t1, t2); dateProbability = flatHazardRate.defaultProbability(startDate, endDate); if (std::fabs(timeProbability - dateProbability) > tolerance) BOOST_ERROR( "double-time probability and double-date probability do not match\n" << std::setprecision(10) << " time probability: " << timeProbability << "\n" << " date probability: " << dateProbability); } }
void QuoteTest::testForwardValueQuoteAndImpliedStdevQuote() { BOOST_MESSAGE( "Testing forward-value and implied-standard-deviation quotes..."); Real forwardRate = .05; DayCounter dc = ActualActual(); Calendar calendar = TARGET(); boost::shared_ptr<SimpleQuote> forwardQuote(new SimpleQuote(forwardRate)); Handle<Quote> forwardHandle(forwardQuote); Date evaluationDate = Settings::instance().evaluationDate(); boost::shared_ptr<YieldTermStructure>yc (new FlatForward( evaluationDate, forwardHandle, dc)); Handle<YieldTermStructure> ycHandle(yc); Period euriborTenor(1,Years); boost::shared_ptr<Index> euribor(new Euribor(euriborTenor, ycHandle)); Date fixingDate = calendar.advance(evaluationDate, euriborTenor); boost::shared_ptr<ForwardValueQuote> forwardValueQuote( new ForwardValueQuote(euribor, fixingDate)); Rate forwardValue = forwardValueQuote->value(); Rate expectedForwardValue = euribor->fixing(fixingDate, true); // we test if the forward value given by the quote is consistent // with the one directly given by the index if (std::fabs(forwardValue-expectedForwardValue) > 1.0e-15) BOOST_FAIL("Foward Value Quote quote yields " << forwardValue << "\n" << "expected result is " << expectedForwardValue); // then we test the observer/observable chain Flag f; f.registerWith(forwardValueQuote); forwardQuote->setValue(0.04); if (!f.isUp()) BOOST_FAIL("Observer was not notified of quote change"); // and we retest if the values are still matching forwardValue = forwardValueQuote->value(); expectedForwardValue = euribor->fixing(fixingDate, true); if (std::fabs(forwardValue-expectedForwardValue) > 1.0e-15) BOOST_FAIL("Foward Value Quote quote yields " << forwardValue << "\n" << "expected result is " << expectedForwardValue); // we test the ImpliedStdevQuote class f.unregisterWith(forwardValueQuote); f.lower(); Real price = 0.02; Rate strike = 0.04; Volatility guess = .15; Real accuracy = 1.0e-6; Option::Type optionType = Option::Call; boost::shared_ptr<SimpleQuote> priceQuote(new SimpleQuote(price)); Handle<Quote> priceHandle(priceQuote); boost::shared_ptr<ImpliedStdDevQuote> impliedStdevQuote(new ImpliedStdDevQuote(optionType, forwardHandle, priceHandle, strike, guess, accuracy)); Real impliedStdev = impliedStdevQuote->value(); Real expectedImpliedStdev = blackFormulaImpliedStdDev(optionType, strike, forwardQuote->value(), price, 1.0, 0.0, guess, 1.0e-6); if (std::fabs(impliedStdev-expectedImpliedStdev) > 1.0e-15) BOOST_FAIL("\nimpliedStdevQuote yields :" << impliedStdev << "\nexpected result is :" << expectedImpliedStdev); // then we test the observer/observable chain boost::shared_ptr<Quote> quote = impliedStdevQuote; f.registerWith(quote); forwardQuote->setValue(0.05); if (!f.isUp()) BOOST_FAIL("Observer was not notified of quote change"); quote->value(); f.lower(); quote->value(); priceQuote->setValue(0.11); if (!f.isUp()) BOOST_FAIL("Observer was not notified of quote change"); }
// evaluate fitting error on benchmark with parameter set Real HestonPriceBenchmark(Handle<Quote> &s0, std::vector<CALIB> &c, std::vector<RD> &rd, std::vector<double> p, double sdCutOff) { Date settlementDate(24, January, 2011); SavedSettings backup; Settings::instance().evaluationDate() = settlementDate; Real theta = p[0]; Real kappa = p[1]; Real sigma = p[2]; Real rho = p[3]; Real v0 = p[4]; std::cout << "Theta: " << theta << "\nKappa: " << kappa << "\nsigma: " << sigma << "\nrho: " << rho << "\nv0: " << v0 << std::endl; DayCounter dayCounter = Actual365Fixed(); Calendar calendar = TARGET(); std::vector<Date> dates; std::vector<Rate> rates; std::vector<Rate> div; // this is indispensable: expiry in Heston helper is computed from YC settlement date dates.push_back(settlementDate); rates.push_back(rd[0].R); div.push_back(rd[0].D); for (Size i = 0; i < rd.size(); ++i) { Integer days = 365*rd[i].T; dates.push_back(settlementDate + days); rates.push_back(rd[i].R); div.push_back(rd[i].D); } Date dtLast = settlementDate + ((int) 365*rd[rd.size()-1].T); std::cout << "Last curve date: " << dtLast << std::endl; Integer days = (rd[rd.size()-1].T+1)*365; dates.push_back(settlementDate + days); rates.push_back(rd[rd.size()-1].R); div.push_back(rd[rd.size()-1].D); std::cout << "Heston model Benchmark Pricing: TS..." << std::endl; Handle<YieldTermStructure> riskFreeTS( boost::shared_ptr<YieldTermStructure>( new ZeroCurve(dates, rates, dayCounter))); Handle<YieldTermStructure> dividendTS( boost::shared_ptr<YieldTermStructure>( new ZeroCurve(dates, div, dayCounter))); Volatility vol = 2.0; Handle<BlackVolTermStructure> volTS( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(settlementDate, calendar, vol, dayCounter))); boost::shared_ptr<BlackScholesMertonProcess> BSprocess( new BlackScholesMertonProcess(s0, dividendTS, riskFreeTS, volTS)); // boost::shared_ptr<PricingEngine> BSengine( // new AnalyticEuropeanEngine(BSprocess)); boost::shared_ptr<HestonProcess> process(new HestonProcess( riskFreeTS, dividendTS, s0, v0, kappa, theta, sigma, rho)); boost::shared_ptr<PricingEngine> engine(new AnalyticHestonEngine( boost::shared_ptr<HestonModel>(new HestonModel(process)), 64)); std::cout << "Heston model Benchmark Pricing: engine set ..." << std::endl; IncrementalStatistics errorStat; vector<Real> error; ofstream myfile; Volatility ivol; Real errorBid; Real errorAsk; // myfile.open ("dump.csv", ios::out|ios::trunc); // this is the default // myfile << "T, dm, y, CP, PB, Calc, PA, Vega, iVol, ErrorBid, ErrorAsk" << std::endl; for (Size i = 0; i < c.size(); ++i) { Integer days = 365*c[i].T; //std::cout << "Expiry dates: " << dtExpiry << std::endl; Period maturity((int)((days+3)/7.), Weeks); // round to weeks Date dtExpiry = calendar.advance(riskFreeTS->referenceDate(), maturity); if (i==0) std::cout << dtExpiry << std::endl; // Time tau = riskFreeTS->dayCounter().yearFraction( // riskFreeTS->referenceDate(), dtExpiry); boost::shared_ptr<StrikedTypePayoff> payoff( new PlainVanillaPayoff(Option::Call, c[i].K)); boost::shared_ptr<Exercise> exercise(new EuropeanExercise(dtExpiry)); VanillaOption option(payoff, exercise); option.setPricingEngine(engine); Real calculated = option.NPV(); // option.setPricingEngine(BSengine); if (calculated >0) { try { ivol = option.impliedVolatility(calculated, BSprocess, 1.e-6, 1000, .1, 10); errorBid = std::max((c[i].VB-ivol), 0.0)*100; errorAsk = std::max((ivol-c[i].VA), 0.0)*100; } catch (...) { errorBid = 0.0; errorAsk = 0.0; }; } else { vol = 0.0; errorAsk = 0.0; errorBid = 0.0; }; error.push_back(errorBid+errorAsk); // myfile << c[i].T << "," << dtExpiry << "," << c[i].CP << "," << c[i].PB << "," << calculated << "," << c[i].PA << "," << c[i].Vega << "," << ivol << "," << errorBid << "," << errorAsk << std::endl; } // remove outliers and calculate sse errorStat.addSequence(error.begin(), error.end()); Real sse = errorStat.standardDeviation(); for (Size i=0; i<error.size(); ++i) if (abs(error[i]) > sdCutOff*sse) error[i] = 0.0; errorStat.reset(); errorStat.addSequence(error.begin(), error.end()); sse = errorStat.standardDeviation(); return sse; }
void ShortRateModelTest::testSwaps() { BOOST_TEST_MESSAGE("Testing Hull-White swap pricing against known values..."); SavedSettings backup; IndexHistoryCleaner cleaner; Date today = Settings::instance().evaluationDate(); Calendar calendar = TARGET(); today = calendar.adjust(today); Settings::instance().evaluationDate() = today; Date settlement = calendar.advance(today,2,Days); Date dates[] = { settlement, calendar.advance(settlement,1,Weeks), calendar.advance(settlement,1,Months), calendar.advance(settlement,3,Months), calendar.advance(settlement,6,Months), calendar.advance(settlement,9,Months), calendar.advance(settlement,1,Years), calendar.advance(settlement,2,Years), calendar.advance(settlement,3,Years), calendar.advance(settlement,5,Years), calendar.advance(settlement,10,Years), calendar.advance(settlement,15,Years) }; DiscountFactor discounts[] = { 1.0, 0.999258, 0.996704, 0.990809, 0.981798, 0.972570, 0.963430, 0.929532, 0.889267, 0.803693, 0.596903, 0.433022 }; Handle<YieldTermStructure> termStructure( boost::shared_ptr<YieldTermStructure>( new DiscountCurve( std::vector<Date>(dates,dates+LENGTH(dates)), std::vector<DiscountFactor>(discounts, discounts+LENGTH(discounts)), Actual365Fixed()))); boost::shared_ptr<HullWhite> model(new HullWhite(termStructure)); Integer start[] = { -3, 0, 3 }; Integer length[] = { 2, 5, 10 }; Rate rates[] = { 0.02, 0.04, 0.06 }; boost::shared_ptr<IborIndex> euribor(new Euribor6M(termStructure)); boost::shared_ptr<PricingEngine> engine( new TreeVanillaSwapEngine(model,120)); #if defined(QL_USE_INDEXED_COUPON) Real tolerance = 4.0e-3; #else Real tolerance = 1.0e-8; #endif for (Size i=0; i<LENGTH(start); i++) { Date startDate = calendar.advance(settlement,start[i],Months); if (startDate < today) { Date fixingDate = calendar.advance(startDate,-2,Days); TimeSeries<Real> pastFixings; pastFixings[fixingDate] = 0.03; IndexManager::instance().setHistory(euribor->name(), pastFixings); } for (Size j=0; j<LENGTH(length); j++) { Date maturity = calendar.advance(startDate,length[i],Years); Schedule fixedSchedule(startDate, maturity, Period(Annual), calendar, Unadjusted, Unadjusted, DateGeneration::Forward, false); Schedule floatSchedule(startDate, maturity, Period(Semiannual), calendar, Following, Following, DateGeneration::Forward, false); for (Size k=0; k<LENGTH(rates); k++) { VanillaSwap swap(VanillaSwap::Payer, 1000000.0, fixedSchedule, rates[k], Thirty360(), floatSchedule, euribor, 0.0, Actual360()); swap.setPricingEngine(boost::shared_ptr<PricingEngine>( new DiscountingSwapEngine(termStructure))); Real expected = swap.NPV(); swap.setPricingEngine(engine); Real calculated = swap.NPV(); Real error = std::fabs((expected-calculated)/expected); if (error > tolerance) { BOOST_ERROR("Failed to reproduce swap NPV:" << QL_FIXED << std::setprecision(9) << "\n calculated: " << calculated << "\n expected: " << expected << QL_SCIENTIFIC << "\n rel. error: " << error); } } } } }
int main(int, char* []) { try { boost::timer timer; Date today = Date(16,October,2007); Settings::instance().evaluationDate() = today; cout << endl; cout << "Pricing a callable fixed rate bond using" << endl; cout << "Hull White model w/ reversion parameter = 0.03" << endl; cout << "BAC4.65 09/15/12 ISIN: US06060WBJ36" << endl; cout << "roughly five year tenor, "; cout << "quarterly coupon and call dates" << endl; cout << "reference date is : " << today << endl << endl; /* Bloomberg OAS1: "N" model (Hull White) varying volatility parameter The curve entered into Bloomberg OAS1 is a flat curve, at constant yield = 5.5%, semiannual compounding. Assume here OAS1 curve uses an ACT/ACT day counter, as documented in PFC1 as a "default" in the latter case. */ // set up a flat curve corresponding to Bloomberg flat curve Rate bbCurveRate = 0.055; DayCounter bbDayCounter = ActualActual(ActualActual::Bond); InterestRate bbIR(bbCurveRate,bbDayCounter,Compounded,Semiannual); Handle<YieldTermStructure> termStructure(flatRate(today, bbIR.rate(), bbIR.dayCounter(), bbIR.compounding(), bbIR.frequency())); // set up the call schedule CallabilitySchedule callSchedule; Real callPrice = 100.; Size numberOfCallDates = 24; Date callDate = Date(15,September,2006); for (Size i=0; i< numberOfCallDates; i++) { Calendar nullCalendar = NullCalendar(); Callability::Price myPrice(callPrice, Callability::Price::Clean); callSchedule.push_back( boost::shared_ptr<Callability>( new Callability(myPrice, Callability::Call, callDate ))); callDate = nullCalendar.advance(callDate, 3, Months); } // set up the callable bond Date dated = Date(16,September,2004); Date issue = dated; Date maturity = Date(15,September,2012); Natural settlementDays = 3; // Bloomberg OAS1 settle is Oct 19, 2007 Calendar bondCalendar = UnitedStates(UnitedStates::GovernmentBond); Real coupon = .0465; Frequency frequency = Quarterly; Real redemption = 100.0; Real faceAmount = 100.0; /* The 30/360 day counter Bloomberg uses for this bond cannot reproduce the US Bond/ISMA (constant) cashflows used in PFC1. Therefore use ActAct(Bond) */ DayCounter bondDayCounter = ActualActual(ActualActual::Bond); // PFC1 shows no indication dates are being adjusted // for weekends/holidays for vanilla bonds BusinessDayConvention accrualConvention = Unadjusted; BusinessDayConvention paymentConvention = Unadjusted; Schedule sch(dated, maturity, Period(frequency), bondCalendar, accrualConvention, accrualConvention, DateGeneration::Backward, false); Size maxIterations = 1000; Real accuracy = 1e-8; Integer gridIntervals = 40; Real reversionParameter = .03; // output price/yield results for varying volatility parameter Real sigma = QL_EPSILON; // core dumps if zero on Cygwin boost::shared_ptr<ShortRateModel> hw0( new HullWhite(termStructure,reversionParameter,sigma)); boost::shared_ptr<PricingEngine> engine0( new TreeCallableFixedRateBondEngine(hw0,gridIntervals)); CallableFixedRateBond callableBond(settlementDays, faceAmount, sch, vector<Rate>(1, coupon), bondDayCounter, paymentConvention, redemption, issue, callSchedule); callableBond.setPricingEngine(engine0); cout << setprecision(2) << showpoint << fixed << "sigma/vol (%) = " << 100.*sigma << endl; cout << "QuantLib price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100. * callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; cout << "Bloomberg price/yld (%) "; cout << "96.50 / 5.47" << endl << endl; sigma = .01; cout << "sigma/vol (%) = " << 100.*sigma << endl; boost::shared_ptr<ShortRateModel> hw1( new HullWhite(termStructure,reversionParameter,sigma)); boost::shared_ptr<PricingEngine> engine1( new TreeCallableFixedRateBondEngine(hw1,gridIntervals)); callableBond.setPricingEngine(engine1); cout << "QuantLib price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100.* callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; cout << "Bloomberg price/yld (%) "; cout << "95.68 / 5.66" << endl << endl; //////////////////// sigma = .03; boost::shared_ptr<ShortRateModel> hw2( new HullWhite(termStructure, reversionParameter, sigma)); boost::shared_ptr<PricingEngine> engine2( new TreeCallableFixedRateBondEngine(hw2,gridIntervals)); callableBond.setPricingEngine(engine2); cout << "sigma/vol (%) = " << 100.*sigma << endl; cout << "QuantLib price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100. * callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; cout << "Bloomberg price/yld (%) "; cout << "92.34 / 6.49" << endl << endl; //////////////////////////// sigma = .06; boost::shared_ptr<ShortRateModel> hw3( new HullWhite(termStructure, reversionParameter, sigma)); boost::shared_ptr<PricingEngine> engine3( new TreeCallableFixedRateBondEngine(hw3,gridIntervals)); callableBond.setPricingEngine(engine3); cout << "sigma/vol (%) = " << 100.*sigma << endl; cout << "QuantLib price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100. * callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; cout << "Bloomberg price/yld (%) "; cout << "87.16 / 7.83" << endl << endl; ///////////////////////// sigma = .12; boost::shared_ptr<ShortRateModel> hw4( new HullWhite(termStructure, reversionParameter, sigma)); boost::shared_ptr<PricingEngine> engine4( new TreeCallableFixedRateBondEngine(hw4,gridIntervals)); callableBond.setPricingEngine(engine4); cout << "sigma/vol (%) = " << 100.*sigma << endl; cout << "QuantLib price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100.* callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; cout << "Bloomberg price/yld (%) "; cout << "77.31 / 10.65" << endl << endl; double seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; cout << " \nRun completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s\n" << endl; return 0; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return 1; } catch (...) { std::cerr << "unknown error" << std::endl; return 1; } }
boost::shared_ptr<IborIndex> curveCreation( // creates the libor index (the "curve") utilities::csvBuilder & file) { const Real convexity_ = 0.009; // convexity adjustment for future prices const Real meanReverting_ = 0.09 ; // mean reversion for future prices const Calendar calendar // pricing calendar = JointCalendar( UnitedStates(UnitedStates::Settlement), UnitedKingdom(UnitedKingdom::Settlement)); const Date pricingDate // set global evaluation date = Settings::instance().evaluationDate(); boost::shared_ptr<RelinkableHandle<YieldTermStructure> > ts( new RelinkableHandle<YieldTermStructure>()); // create the yield term structure boost::shared_ptr<IborIndex> libor( // libor index associated new USDLibor( Period(3, Months), *ts)); libor->addFixing(Date(16, April, 2014), .0022785); // add a few fixings libor->addFixing(Date(15, April, 2014), .0022635); libor->addFixing(Date(14, April, 2014), .0022865); libor->addFixing(Date(11, April, 2014), .0022645); // the rate helpers std::vector<boost::shared_ptr<RateHelper> > rateHelpers; std::vector<depositData> depositRates // deposit data = std::vector<depositData> { { .0009070, 0, Period(1, Days ) }, { .0014250, 1, Period(2, Days ) }, { .0012150, 2, Period(1, Weeks ) }, { .0015200, 2, Period(1, Months) }, { .0019300, 2, Period(2, Months) } }; std::vector<futureData> futureRates // future data = std::vector<futureData> { { 99.7700, "EDM4" }, { 99.7600, "EDU4" }, { 99.7250, "EDZ4" }, { 99.6300, "EDH5" }, { 99.4550, "EDM5" }, { 99.2250, "EDU5" }, { 98.9450, "EDZ5" }, { 98.6450, "EDH6" }, { 98.3400, "EDM6" }, { 98.0500, "EDU6" }, { 97.7850, "EDZ6" } }; std::vector<swapData> swapRates // future data = std::vector<swapData> { { .0139980, Period(4 , Years) }, { .0176100, Period(5 , Years) }, { .0205300, Period(6 , Years) }, { .0228500, Period(7 , Years) }, { .0247290, Period(8 , Years) }, { .0262750, Period(9 , Years) }, { .0275070, Period(10, Years) }, { .0286800, Period(11, Years) }, { .0296100, Period(12, Years) } }; for (std::vector<depositData>::const_iterator It = depositRates.cbegin(); It != depositRates.cend(); It++) { // settlement and maturity dates Date settlement = calendar.advance( pricingDate, Period(It->settlementDays_, Days)); Date maturity = calendar.advance( settlement, It->maturity_); // creating the deposit boost::shared_ptr<QuantLib::deposit> myDepositPtr( new deposit( pricingDate, maturity, calendar, It->settlementDays_)); Handle<Quote> quoteHandler( // quote handle boost::shared_ptr<Quote>( new SimpleQuote( myDepositPtr->cleanPrice( It->quote_, Actual360(), Simple, Once, Unadjusted, settlement)))); rateHelpers.push_back( // insert RateHelper boost::shared_ptr<RateHelper>( new depositBootstrapHelper( quoteHandler, myDepositPtr))); } for (std::vector<futureData>::const_iterator It = futureRates.cbegin(); It != futureRates.cend(); It++) { Handle<Quote> convexityHandle( // convexity adjustment boost::shared_ptr<Quote>( new SimpleQuote(convexity_))); Handle<Quote> meanRevertingHandle( // mean reverting boost::shared_ptr<Quote>( new SimpleQuote(meanReverting_))); Handle<Quote> futurePriceHandle( // price boost::shared_ptr<Quote>( new SimpleQuote(It->price_))); Date futureDate = IMM::date( // IMM date It->futureCode_.substr(2, 2), pricingDate); Handle<Quote> convexityAdjustedQuoteHendle( // convexity adjustement boost::shared_ptr<Quote>( new futuresConvexityAdjustmentQuote2( libor, futureDate, futurePriceHandle, convexityHandle, meanRevertingHandle, pricingDate))); rateHelpers.push_back( // helper boost::shared_ptr<FuturesRateHelper>( new FuturesRateHelper( futurePriceHandle, futureDate, libor, convexityAdjustedQuoteHendle))); } for (std::vector<swapData>::const_iterator It = swapRates.cbegin(); It != swapRates.cend(); It++) { QuantLib::Handle<QuantLib::Quote> myHandle( // creates the rate handle boost::shared_ptr<QuantLib::Quote>( new QuantLib::SimpleQuote(It->fairRate_))); rateHelpers.push_back( boost::shared_ptr<QuantLib::RateHelper>(new QuantLib::SwapRateHelper( myHandle, It->maturity_, calendar, Semiannual, ModifiedFollowing, ActualActual(), libor))); } boost::shared_ptr<swapCurve> curve( // building the curve object new swapCurve(rateHelpers, calendar, 10e-12)); ts->linkTo(curve); // finally relink the index Size size_ = 20; Array times(size_, 0.0); // saves yield curve data Array rates(size_, 0.0); Array fwd (size_, 0.0); for (Size i = 0; i < size_; i++) { times[i] = .5 * i; // the fixing times from model rates[i] = libor->forwardingTermStructure()->zeroRate( times[i], Continuous); fwd[i] = libor->forwardingTermStructure()->forwardRate( times[i], times[i] + .02, Continuous); } file.add("times" , 1, 1); // adds the yield curve data file.add(times , 2, 1); file.add("rates" , 1, 2); file.add(rates , 2, 2); file.add("forward", 1, 3); file.add(fwd , 2, 3); return libor; }
void historicalForwardRatesAnalysis( SequenceStatistics& statistics, std::vector<Date>& skippedDates, std::vector<std::string>& skippedDatesErrorMessage, std::vector<Date>& failedDates, std::vector<std::string>& failedDatesErrorMessage, std::vector<Period>& fixingPeriods, const Date& startDate, const Date& endDate, const Period& step, const boost::shared_ptr<InterestRateIndex>& fwdIndex, const Period& initialGap, const Period& horizon, const std::vector<boost::shared_ptr<IborIndex> >& iborIndexes, const std::vector<boost::shared_ptr<SwapIndex> >& swapIndexes, const DayCounter& yieldCurveDayCounter, Real yieldCurveAccuracy = 1.0e-12, const Interpolator& i = Interpolator()) { statistics.reset(); skippedDates.clear(); skippedDatesErrorMessage.clear(); failedDates.clear(); failedDatesErrorMessage.clear(); fixingPeriods.clear(); SavedSettings backup; Settings::instance().enforcesTodaysHistoricFixings() = true; std::vector<boost::shared_ptr<RateHelper> > rateHelpers; // Create DepositRateHelper std::vector<boost::shared_ptr<SimpleQuote> > iborQuotes; std::vector<boost::shared_ptr<IborIndex> >::const_iterator ibor; for (ibor=iborIndexes.begin(); ibor!=iborIndexes.end(); ++ibor) { boost::shared_ptr<SimpleQuote> quote(new SimpleQuote); iborQuotes.push_back(quote); Handle<Quote> quoteHandle(quote); rateHelpers.push_back(boost::shared_ptr<RateHelper> (new DepositRateHelper(quoteHandle, (*ibor)->tenor(), (*ibor)->fixingDays(), (*ibor)->fixingCalendar(), (*ibor)->businessDayConvention(), (*ibor)->endOfMonth(), (*ibor)->dayCounter()))); } // Create SwapRateHelper std::vector<boost::shared_ptr<SimpleQuote> > swapQuotes; std::vector<boost::shared_ptr<SwapIndex> >::const_iterator swap; for (swap=swapIndexes.begin(); swap!=swapIndexes.end(); ++swap) { boost::shared_ptr<SimpleQuote> quote(new SimpleQuote); swapQuotes.push_back(quote); Handle<Quote> quoteHandle(quote); rateHelpers.push_back(boost::shared_ptr<RateHelper> (new SwapRateHelper(quoteHandle, (*swap)->tenor(), (*swap)->fixingCalendar(), (*swap)->fixedLegTenor().frequency(), (*swap)->fixedLegConvention(), (*swap)->dayCounter(), (*swap)->iborIndex()))); } // Set up the forward rates time grid Period indexTenor = fwdIndex->tenor(); Period fixingPeriod = initialGap; while (fixingPeriod<=horizon) { fixingPeriods.push_back(fixingPeriod); fixingPeriod += indexTenor; } Size nRates = fixingPeriods.size(); statistics.reset(nRates); std::vector<Rate> fwdRates(nRates); std::vector<Rate> prevFwdRates(nRates); std::vector<Rate> fwdRatesDiff(nRates); DayCounter indexDayCounter = fwdIndex->dayCounter(); Calendar cal = fwdIndex->fixingCalendar(); // Bootstrap the yield curve at the currentDate Natural settlementDays = 0; PiecewiseYieldCurve<Traits, Interpolator> yc(settlementDays, cal, rateHelpers, yieldCurveDayCounter, std::vector<Handle<Quote> >(), std::vector<Date>(), yieldCurveAccuracy, i); // start with a valid business date Date currentDate = cal.advance(startDate, 1*Days, Following); bool isFirst = true; // Loop over the historical dataset for (; currentDate<=endDate; currentDate = cal.advance(currentDate, step, Following)) { // move the evaluationDate to currentDate // and update ratehelpers dates... Settings::instance().evaluationDate() = currentDate; try { // update the quotes... for (Size i=0; i<iborIndexes.size(); ++i) { Rate fixing = iborIndexes[i]->fixing(currentDate, false); iborQuotes[i]->setValue(fixing); } for (Size i=0; i<swapIndexes.size(); ++i) { Rate fixing = swapIndexes[i]->fixing(currentDate, false); swapQuotes[i]->setValue(fixing); } } catch (std::exception& e) { skippedDates.push_back(currentDate); skippedDatesErrorMessage.push_back(e.what()); continue; } try { for (Size i=0; i<nRates; ++i) { // Time-to-go forwards Date d = currentDate + fixingPeriods[i]; fwdRates[i] = yc.forwardRate(d, indexTenor, indexDayCounter, Simple); } } catch (std::exception& e) { failedDates.push_back(currentDate); failedDatesErrorMessage.push_back(e.what()); continue; } // From 2nd step onwards, calculate forward rate // relative differences if (!isFirst){ for (Size i=0; i<nRates; ++i) fwdRatesDiff[i] = fwdRates[i]/prevFwdRates[i] -1.0; // add observation statistics.add(fwdRatesDiff.begin(), fwdRatesDiff.end()); } else isFirst = false; // Store last calculated forward rates std::swap(prevFwdRates, fwdRates); } }