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;

	}
示例#3
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;
    }

}
示例#4
0
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;
    }
}
示例#5
0
	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;
    }

}