int main() { try { boost::timer timer; Date today = Date::todaysDate(); Schedule schedule(today, today+10*Years, Period(Quarterly), NullCalendar(), Unadjusted, Unadjusted, DateGeneration::Forward, false); //Schedule schedule2(today, today+3*Years, Period(Quarterly), NullCalendar(), Unadjusted, Unadjusted, DateGeneration::Forward, false); Rate cpnRate = 0.06; CallabilitySchedule callSchedule; for (Size i=1; i<schedule.size()-1; ++i) { boost::shared_ptr<Callability> callability(new Callability(Callability::Price(10000, Callability::Price::Dirty), Callability::Call, schedule[i])); callSchedule.push_back(callability); } //CallableFixedRateBond bond(0, 10000, schedule, std::vector<Real>(1, cpnRate), SimpleDayCounter(), Unadjusted, 100.0, Date(), callSchedule); //FixedRateBond fbond(0, 10000, schedule2, std::vector<Real>(1,cpnRate), SimpleDayCounter(), Unadjusted); FixedRateCpnBond bond(0, 10000, schedule, std::vector<Rate>(1, cpnRate), SimpleDayCounter(), Unadjusted, 100.0, Date(), callSchedule); Rate yield = 0.05; boost::shared_ptr<YieldTermStructure> ts(new FlatForward(0, NullCalendar(), yield, SimpleDayCounter())); boost::shared_ptr<ShortRateModel> model(new HullWhite(Handle<YieldTermStructure>(ts), 0.1, 0.01)); boost::shared_ptr<PricingEngine> engine(new HwTreeCallableBondEngine(model, 500, Handle<YieldTermStructure>(ts))); bond.setPricingEngine(engine); Real price = bond.NPV(); std::cout<<"Price = "<<price<<std::endl; std::cout<<"Time = "<<timer.elapsed()<<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; } }
std::vector<Real> power_spread_note(Date evaluationDate, Real notional, Schedule schedule, DayCounter dayCounter, BusinessDayConvention bdc, std::vector<Real> gearing, std::vector<Real> spread, std::vector<Real> caps, std::vector<Real> floors, bool isAvg, Date firstCallDate, Real pastFixing, boost::shared_ptr<StochasticProcess1D> obs1Process, boost::shared_ptr<StochasticProcess1D> obs2Process, boost::shared_ptr<HullWhiteProcess> discProcess, Real rho12, Real rho1disc, Real rho2disc, Size numSimulation, Size numCalibration) { Date todaysDate = evaluationDate; Settings::instance().evaluationDate() = todaysDate; boost::shared_ptr<IborIndex> index1(new Euribor3M(Handle<YieldTermStructure>( discProcess->yieldTermStructure() ))); boost::shared_ptr<SpreadIndex> index(new SpreadIndex(index1, index1)); boost::shared_ptr<Callability> callability(new Callability(Callability::Price(notional, Callability::Price::Clean), Callability::Call, firstCallDate)); CallabilitySchedule callSchedule; callSchedule.push_back(callability); /***********************************************************************************/ PowerSpreadNote testProduct(0, notional, schedule, index, dayCounter, bdc, Null<Natural>(), gearing, spread, caps, floors, isAvg, 100.0, Date(), callSchedule, Exercise::Bermudan); /*****Pricing Engine*****/ std::vector<boost::shared_ptr<StochasticProcess1D> > pros; pros.push_back(discProcess); pros.push_back(obs1Process); pros.push_back(obs2Process); Matrix corr(3,3,1.0); corr[0][1] = corr[1][0] = rho1disc; corr[0][2] = corr[2][0] = rho2disc; corr[1][2] = corr[2][1] = rho12; boost::shared_ptr<StochasticProcessArray> processes(new StochasticProcessArray(pros, corr)); boost::shared_ptr<PricingEngine> engine_lsmc(new MC_PowerSpread_Engine_LSMC<>(processes, 0.0, //pastAccrual 256, //seed numSimulation, //required samples numCalibration, //calibration samples true, //antithetic false, //control variate false //brownian bridge )); testProduct.setPricingEngine(engine_lsmc); std::vector<Real> rst; rst.push_back(testProduct.NPV()); rst.push_back(testProduct.errorEstimate()); return rst; }
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; 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; } }
std::vector<Real> power_spread_swap(Date evaluationDate, Real notional, PowerSpreadSwap::Side side, Rate alpha, Schedule floatingSchedule, Schedule fixedSchedule, DayCounter dayCounter, BusinessDayConvention bdc, std::vector<Real> gearing, std::vector<Real> spread, std::vector<Real> caps, std::vector<Real> floors, bool isAvg, Date firstCallDate, Real pastFixing, Rate floatingFixingRate, Real floatingGearing, DayCounter floatingDayCounter, boost::shared_ptr<StochasticProcess1D> obs1Process, boost::shared_ptr<StochasticProcess1D> obs2Process, YieldCurveParams disc, Real rho12, Real rho1disc, Real rho2disc, Size numSimulation, Size numCalibration) { Date todaysDate = evaluationDate; Settings::instance().evaluationDate() = todaysDate; boost::shared_ptr<IborIndex> index1(new Euribor3M(Handle<YieldTermStructure>( disc.yts ))); boost::shared_ptr<SpreadIndex> index(new SpreadIndex(index1, index1)); boost::shared_ptr<Callability> callability(new Callability(Callability::Price(notional, Callability::Price::Clean), Callability::Call, firstCallDate)); CallabilitySchedule callSchedule; callSchedule.push_back(callability); boost::shared_ptr<StochasticProcess1D> discProcess(new HullWhiteProcess(Handle<YieldTermStructure>(disc.yts), disc.hwParams.a, disc.hwParams.sigma)); /***********************************************************************************/ Leg floatingcashflows = IborLeg(floatingSchedule, index1) .withNotionals(notional) .withPaymentDayCounter(floatingDayCounter) .withPaymentAdjustment(bdc) .withSpreads(alpha) .withGearings(floatingGearing) .withPaymentAdjustment(bdc); PowerSpreadSwap testProduct(0, notional, side, floatingSchedule, floatingcashflows, alpha, fixedSchedule, index, dayCounter, bdc, Null<Natural>(), gearing, spread, caps, floors, isAvg, 100.0, Date(), callSchedule, Exercise::Bermudan); /*****Pricing Engine*****/ std::vector<boost::shared_ptr<StochasticProcess1D> > pros; pros.push_back(discProcess); pros.push_back(obs1Process); pros.push_back(obs2Process); Matrix corr(3,3,1.0); corr[0][1] = corr[1][0] = rho1disc; corr[0][2] = corr[2][0] = rho2disc; corr[1][2] = corr[2][1] = rho12; boost::shared_ptr<StochasticProcessArray> processes(new StochasticProcessArray(pros, corr)); boost::shared_ptr<PricingEngine> engine_lsmc(new MC_PowerSpread_Swap_Engine_LSMC<>(processes, 0.03, //pastFixing 0.03, 256, //seed numSimulation, //required samples numCalibration, //calibration samples true, //antithetic false, //control variate false //brownian bridge )); testProduct.setPricingEngine(engine_lsmc); std::vector<Real> rst; rst.push_back(testProduct.NPV()); rst.push_back(testProduct.errorEstimate()); return rst; }
int main(int argc, const char * argv[]) { try { boost::timer timer; Date today = Date(16,October,2007); Settings::instance().evaluationDate() = today; cout << endl; cout << "This example prices a callable fixed rate bond using" << endl; cout << "Hull White model w/ reversion parameter = 0.03" << endl; cout << "vs Vasicek model w/ long term mean & r0 = 0.055" <<endl; cout << "& same reversion parameter" <<endl; cout << endl; cout << "The bond:" <<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; // Comment: a vector of Callability* -neil 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 ))); // cout<<callSchedule[i]->date()<<endl; // by neil 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); // Comment: Payment schedule -neil Size maxIterations = 1000; Real accuracy = 1e-8; Integer gridIntervals = 40; // timeSteps -neil Real reversionParameter = .03; // output price/yield results for varying volatility parameter // Real sigma=QL_EPSILON; // core dumps if sigma=zero on Cygwin // // HullWhite Engine // boost::shared_ptr<ShortRateModel> hw0(new HullWhite(termStructure,reversionParameter,sigma)); // cout<<boost::static_pointer_cast<HullWhite>(hw0)->a()<<endl; // neil testing // cout<<boost::static_pointer_cast<HullWhite>(hw0)->b()<<endl; // cout<<boost::static_pointer_cast<HullWhite>(hw0)->sigma()<<endl; // cout<<boost::static_pointer_cast<HullWhite>(hw0)->lambda()<<endl; // // boost::shared_ptr<PricingEngine> engine0(new TreeCallableFixedRateBondEngine(hw0,gridIntervals)); // commented out by neil. moved to print loop. /******** bond object ********/ CallableFixedRateBond callableBond(settlementDays, faceAmount, sch, vector<Rate>(1, coupon), bondDayCounter, paymentConvention, redemption, issue, callSchedule); // callableBond.setPricingEngine(engine0); // moved to print loop -neil /******** setting engines and print price ********/ for (auto sigma: vector<Real>({QL_EPSILON, .01, .03, .06, .12})) { // core dumps if sigma=zero on Cygwin // Comment: Defines the machine precision for operations over doubles // HullWhite Engine boost::shared_ptr<ShortRateModel> hw(new HullWhite(termStructure,reversionParameter,sigma)); boost::shared_ptr<PricingEngine> engine_hw(new TreeCallableFixedRateBondEngine(hw,gridIntervals)); // Vasicek Engine -by neil boost::shared_ptr<ShortRateModel> vsc(new Vasicek(bbCurveRate, reversionParameter, bbCurveRate, sigma) ); boost::shared_ptr<PricingEngine> engine_vsc(new TreeCallableFixedRateBondEngine(vsc, gridIntervals, termStructure) ); // Vasicek Model doesn't provide termStructure, need to specify it for PricingEngine object. -by neil // print -by neil cout << setprecision(2) << showpoint << fixed << "sigma/vol (%) = " << 100.*sigma << endl; callableBond.setPricingEngine(engine_vsc); cout << "QL Vasicek price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100. * callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; callableBond.setPricingEngine(engine_hw); cout << "QL HullWhite price/yld (%) "; cout << callableBond.cleanPrice() << " / " << 100. * callableBond.yield(bondDayCounter, Compounded, frequency, accuracy, maxIterations) << endl; cout << "Bloomberg price/yld (%) "; if (fabs(sigma - QL_EPSILON) < QL_EPSILON) cout << "96.50 / 5.47"; else if (fabs(sigma - .01) < QL_EPSILON) cout << "95.68 / 5.66"; else if (fabs(sigma - .03) < QL_EPSILON) cout << "92.34 / 6.49"; else if (fabs(sigma - .06) < QL_EPSILON) cout << "87.16 / 7.83"; else if (fabs(sigma - .12) < QL_EPSILON) cout << "77.31 / 10.65"; cout << 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(1) << 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; } }