// The constructor does the work to generate the results.
AccumulatorCalculator::AccumulatorCalculator(
	         AccumulatorContract* pAccumContract, MarketCaches* pMarketCaches,
		     ResultSet* pResultSet) // constructor will set the resultSet
				  : CalculatorBase(pAccumContract, pMarketCaches, pResultSet)
{
	boost::shared_ptr<AccumulatorMCEngine> accumMCEngine = (boost::shared_ptr<AccumulatorMCEngine>)
		 new AccumulatorMCEngine(pAccumContract, pMarketCaches);

	boost::shared_ptr<StockData> stockData = pMarketCaches->getStockDataCache()->
		                 get(pAccumContract->m_underlyingID, pAccumContract->m_underlyingIDType);

	std::string stockCurrency = stockData->getCurrency();

	boost::shared_ptr<Prices> prices = pMarketCaches->getStockPricesCache()->
		                 get(pAccumContract->m_underlyingID, pAccumContract->m_underlyingIDType);

    Handle<Quote> underlyingH(boost::shared_ptr<Quote>(new SimpleQuote(prices->getCurrentPrice())));

	Handle<YieldTermStructure> yieldTS (pMarketCaches->getYieldTSCache()->get( CONST_STR_risk_free_rate, stockCurrency));

    Handle<YieldTermStructure> dividendYieldTS(boost::shared_ptr<YieldTermStructure>(
         new FlatForward(pMarketCaches->getEvalDate(), stockData->getDividendYield(), Actual365Fixed())));

	Date finalAccumDate = pAccumContract->m_periodEndDates[pAccumContract->m_numPeriods-1];

	Handle<BlackVolTermStructure> flatVolTS(boost::shared_ptr<BlackVolTermStructure>(
            new BlackConstantVol(finalAccumDate, *(accumMCEngine->getUndlHolCal()) , stockData->getFlatVol(), Actual365Fixed())));

	//////////////////////////////////////////////////////////////////////
    boost::shared_ptr<StochasticProcess1D> stochasticPro(new BlackScholesMertonProcess
		(underlyingH, dividendYieldTS, yieldTS, flatVolTS));

    Size nTimeSteps = accumMCEngine->getNumMCTimeSteps();
	PseudoRandom::rsg_type rsg = PseudoRandom::make_sequence_generator(
		                           nTimeSteps, 
				                   getConfig()->getRandomGeneratorSeed());

    bool brownianBridge = false;
    Time years = (finalAccumDate - pMarketCaches->getEvalDate())/ 365.0;
    typedef SingleVariate<PseudoRandom>::path_generator_type generator_type;

	boost::shared_ptr<generator_type> myPathGenerator(new
        generator_type(stochasticPro, years, nTimeSteps, rsg, brownianBridge));

    // a statistics accumulator for the path-dependant Profit&Loss values
    Statistics statisticsAccumulator;
    bool antithetic = true;
    // The Monte Carlo model generates paths using myPathGenerator
    // each path is priced using myPathPricer
    // prices will be accumulated into statisticsAccumulator
    MonteCarloModel<SingleVariate,PseudoRandom> MCSimulation(myPathGenerator, accumMCEngine,
                                                             statisticsAccumulator, antithetic );
    
    MCSimulation.addSamples(atoi(getConfig()->get("accumulator_num_mc_samples").c_str()));
    
    Real cashValue     = MCSimulation.sampleAccumulator().mean();
	Real errorEstimate = MCSimulation.sampleAccumulator().errorEstimate() / accumMCEngine->getRemainingNotional(); 
	writeDiagnostics("Error estimate is " + toString(errorEstimate), mid, "Accum");
    
	/////////////////////////////////////////////////////////////////////////////
	// populate results
	boost::shared_ptr<Result> perUnitValRes = (boost::shared_ptr<Result>) new Result();
	Real pricePerUnitRemainingNotional = cashValue / accumMCEngine->getRemainingNotional();
	perUnitValRes->setValueAndCategory(price_per_unit_notional, pricePerUnitRemainingNotional);
	perUnitValRes->setAttribute(contract_category, "accumulator",                  true);
	perUnitValRes->setAttribute(contract_id,       pAccumContract->getID(),        true);
	perUnitValRes->setAttribute(underlying_id,     pAccumContract->m_underlyingID, true);
	pResultSet->addNewResult(perUnitValRes);

	// we don't have to reset the attributes because we are using the copy constructor
	boost::shared_ptr<Result> cashValRes = (boost::shared_ptr<Result>) new Result(*perUnitValRes);
	cashValRes->setAttribute(currency, accumMCEngine->getCurrency(), true);
	cashValRes->setValueAndCategory(cash_price, cashValue);
    pResultSet->addNewResult(cashValRes);
}
예제 #2
0
int TestFromQuantLib() {

	try {

		boost::timer timer;
		std::cout << std::endl;

		// set up dates
		Calendar calendar = TARGET();
		Date todaysDate(15, May, 1998);
		Date settlementDate(17, May, 1998);
		Settings::instance().evaluationDate() = todaysDate;

		// our options
		Option::Type type(Option::Put);
		Real underlying = 36;
		Real strike = 40;
		Spread dividendYield = 0.00;
		Rate riskFreeRate = 0.06;
		Volatility volatility = 0.20;
		Date maturity(17, May, 1999);
		DayCounter dayCounter = Actual365Fixed();

		std::cout << "Option type = " << type << std::endl;
		std::cout << "Maturity = " << maturity << std::endl;
		std::cout << "Underlying price = " << underlying << std::endl;
		std::cout << "Strike = " << strike << 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, 14 };
		std::cout << std::setw(widths[0]) << std::left << "Method"
			<< std::setw(widths[1]) << std::left << "European"
			<< std::setw(widths[2]) << std::left << "Bermudan"
			<< std::setw(widths[3]) << std::left << "American"
			<< std::endl;

		std::vector<Date> exerciseDates;
		for (Integer i = 1; i <= 4; i++)
			exerciseDates.push_back(settlementDate + 3 * i*Months);

		boost::shared_ptr<Exercise> europeanExercise(
			new EuropeanExercise(maturity));

		boost::shared_ptr<Exercise> bermudanExercise(
			new BermudanExercise(exerciseDates));

		boost::shared_ptr<Exercise> americanExercise(
			new AmericanExercise(settlementDate,
				maturity));

		Handle<Quote> underlyingH(
			boost::shared_ptr<Quote>(new SimpleQuote(underlying)));

		// bootstrap the yield/dividend/vol curves
		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<StrikedTypePayoff> payoff(
			new PlainVanillaPayoff(type, strike));
		boost::shared_ptr<BlackScholesMertonProcess> bsmProcess(
			new BlackScholesMertonProcess(underlyingH, flatDividendTS,
				flatTermStructure, flatVolTS));

		// options
		VanillaOption europeanOption(payoff, europeanExercise);
		VanillaOption bermudanOption(payoff, bermudanExercise);
		VanillaOption americanOption(payoff, americanExercise);

		// Analytic formulas:

		// Black-Scholes for European
		method = "Black-Scholes";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new AnalyticEuropeanEngine(bsmProcess)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << "N/A"
			<< std::endl;

		// semi-analytic Heston for European
		method = "Heston semi-analytic";
		boost::shared_ptr<HestonProcess> hestonProcess(
			new HestonProcess(flatTermStructure, flatDividendTS,
				underlyingH, volatility*volatility,
				1.0, volatility*volatility, 0.001, 0.0));
		boost::shared_ptr<HestonModel> hestonModel(
			new HestonModel(hestonProcess));
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new AnalyticHestonEngine(hestonModel)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << "N/A"
			<< std::endl;

		// semi-analytic Bates for European
		method = "Bates semi-analytic";
		boost::shared_ptr<BatesProcess> batesProcess(
			new BatesProcess(flatTermStructure, flatDividendTS,
				underlyingH, volatility*volatility,
				1.0, volatility*volatility, 0.001, 0.0,
				1e-14, 1e-14, 1e-14));
		boost::shared_ptr<BatesModel> batesModel(new BatesModel(batesProcess));
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BatesEngine(batesModel)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << "N/A"
			<< std::endl;

		// Barone-Adesi and Whaley approximation for American
		method = "Barone-Adesi/Whaley";
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BaroneAdesiWhaleyApproximationEngine(bsmProcess)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << "N/A"
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Bjerksund and Stensland approximation for American
		method = "Bjerksund/Stensland";
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BjerksundStenslandApproximationEngine(bsmProcess)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << "N/A"
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Integral
		method = "Integral";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new IntegralEngine(bsmProcess)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << "N/A"
			<< std::endl;

		// Finite differences
		Size timeSteps = 801;
		method = "Finite differences";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new FDEuropeanEngine<CrankNicolson>(bsmProcess,
				timeSteps, timeSteps - 1)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new FDBermudanEngine<CrankNicolson>(bsmProcess,
				timeSteps, timeSteps - 1)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new FDAmericanEngine<CrankNicolson>(bsmProcess,
				timeSteps, timeSteps - 1)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Binomial method: Jarrow-Rudd
		method = "Binomial Jarrow-Rudd";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<JarrowRudd>(bsmProcess, timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<JarrowRudd>(bsmProcess, timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<JarrowRudd>(bsmProcess, timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;
		method = "Binomial Cox-Ross-Rubinstein";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
				timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
				timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
				timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Binomial method: Additive equiprobabilities
		method = "Additive equiprobabilities";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
				timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
				timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
				timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Binomial method: Binomial Trigeorgis
		method = "Binomial Trigeorgis";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Trigeorgis>(bsmProcess, timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Trigeorgis>(bsmProcess, timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Trigeorgis>(bsmProcess, timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Binomial method: Binomial Tian
		method = "Binomial Tian";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Tian>(bsmProcess, timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Tian>(bsmProcess, timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Tian>(bsmProcess, timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Binomial method: Binomial Leisen-Reimer
		method = "Binomial Leisen-Reimer";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<LeisenReimer>(bsmProcess, timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<LeisenReimer>(bsmProcess, timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<LeisenReimer>(bsmProcess, timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Binomial method: Binomial Joshi
		method = "Binomial Joshi";
		europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Joshi4>(bsmProcess, timeSteps)));
		bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Joshi4>(bsmProcess, timeSteps)));
		americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
			new BinomialVanillaEngine<Joshi4>(bsmProcess, timeSteps)));
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// Monte Carlo Method: MC (crude)
		timeSteps = 1;
		method = "MC (crude)";
		Size mcSeed = 42;
		boost::shared_ptr<PricingEngine> mcengine1;
		mcengine1 = MakeMCEuropeanEngine<PseudoRandom>(bsmProcess)
			.withSteps(timeSteps)
			.withAbsoluteTolerance(0.02)
			.withSeed(mcSeed);
		europeanOption.setPricingEngine(mcengine1);
		// Real errorEstimate = europeanOption.errorEstimate();
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << "N/A"
			<< std::endl;

		// Monte Carlo Method: QMC (Sobol)
		method = "QMC (Sobol)";
		Size nSamples = 32768;  // 2^15

		boost::shared_ptr<PricingEngine> mcengine2;
		mcengine2 = MakeMCEuropeanEngine<LowDiscrepancy>(bsmProcess)
			.withSteps(timeSteps)
			.withSamples(nSamples);
		europeanOption.setPricingEngine(mcengine2);
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << europeanOption.NPV()
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << "N/A"
			<< std::endl;

		// Monte Carlo Method: MC (Longstaff Schwartz)
		method = "MC (Longstaff Schwartz)";
		boost::shared_ptr<PricingEngine> mcengine3;
		mcengine3 = MakeMCAmericanEngine<PseudoRandom>(bsmProcess)
			.withSteps(100)
			.withAntitheticVariate()
			.withCalibrationSamples(4096)
			.withAbsoluteTolerance(0.02)
			.withSeed(mcSeed);
		americanOption.setPricingEngine(mcengine3);
		std::cout << std::setw(widths[0]) << std::left << method
			<< std::fixed
			<< std::setw(widths[1]) << std::left << "N/A"
			<< std::setw(widths[2]) << std::left << "N/A"
			<< std::setw(widths[3]) << std::left << americanOption.NPV()
			<< std::endl;

		// End test
		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;
	}
}