void FdSimpleKlugeExtOUVPPEngine::calculate() const { boost::shared_ptr<SwingExercise> swingExercise( boost::dynamic_pointer_cast<SwingExercise>(arguments_.exercise)); QL_REQUIRE(swingExercise, "Swing exercise supported only"); const Size nStates = (arguments_.nStarts == Null<Size>()) ? 2*arguments_.tMinUp + arguments_.tMinDown : (arguments_.nStarts+1)*(2*arguments_.tMinUp+arguments_.tMinDown); // 1. Layout std::vector<Size> dim; dim.push_back(xGrid_); dim.push_back(yGrid_); dim.push_back(gGrid_); dim.push_back(nStates); const boost::shared_ptr<FdmLinearOpLayout> layout( new FdmLinearOpLayout(dim)); const std::vector<Time> exerciseTimes = swingExercise->exerciseTimes(rTS_->dayCounter(), rTS_->referenceDate()); // 2. mesher set-up const Time maturity = exerciseTimes.back(); const boost::shared_ptr<ExtOUWithJumpsProcess> klugeProcess = process_->getKlugeProcess(); const boost::shared_ptr<StochasticProcess1D> klugeOUProcess = klugeProcess->getExtendedOrnsteinUhlenbeckProcess(); const boost::shared_ptr<Fdm1dMesher> xMesher( new FdmSimpleProcess1dMesher(xGrid_, klugeOUProcess, maturity)); const boost::shared_ptr<Fdm1dMesher> yMesher( new ExponentialJump1dMesher(yGrid_, klugeProcess->beta(), klugeProcess->jumpIntensity(), klugeProcess->eta(), 1e-3)); const boost::shared_ptr<Fdm1dMesher> gMesher( new FdmSimpleProcess1dMesher(gGrid_, process_->getExtOUProcess(),maturity)); const boost::shared_ptr<Fdm1dMesher> exerciseMesher( new Uniform1dMesher(0.0, nStates-1.0, nStates)); std::vector<boost::shared_ptr<Fdm1dMesher> > meshers; meshers.push_back(xMesher); meshers.push_back(yMesher); meshers.push_back(gMesher); meshers.push_back(exerciseMesher); const boost::shared_ptr<FdmMesher> mesher ( new FdmMesherComposite(layout, meshers)); // 3. Calculator const boost::shared_ptr<FdmInnerValueCalculator> zeroInnerValue( new FdmZeroInnerValue()); const boost::shared_ptr<Payoff> zeroStrikeCall( new PlainVanillaPayoff(Option::Call, 0.0)); const boost::shared_ptr<FdmInnerValueCalculator> gasPrice( new FdmExpExtOUInnerValueCalculator(zeroStrikeCall, mesher, gasShape_, 2)); const boost::shared_ptr<FdmInnerValueCalculator> powerPrice( new FdmExtOUJumpModelInnerValue(zeroStrikeCall,mesher,powerShape_)); const boost::shared_ptr<FdmInnerValueCalculator> sparkSpread( new FdmSparkSpreadInnerValue( boost::dynamic_pointer_cast<BasketPayoff>(arguments_.payoff), gasPrice, powerPrice)); // 4. Step conditions std::list<std::vector<Time> > stoppingTimes; std::list<boost::shared_ptr<StepCondition<Array> > > stepConditions; // 4.1 Bermudan step conditions stoppingTimes.push_back(exerciseTimes); stepConditions.push_back(boost::shared_ptr<StepCondition<Array> >( new FdmVPPStepCondition(arguments_.heatRate, arguments_.pMin, arguments_.pMax, arguments_.tMinUp, arguments_.tMinDown, arguments_.nStarts, arguments_.startUpFuel, arguments_.startUpFixCost, carbonPrice_, 3, mesher, gasPrice, sparkSpread))); boost::shared_ptr<FdmStepConditionComposite> conditions( new FdmStepConditionComposite(stoppingTimes, stepConditions)); // 5. Boundary conditions const std::vector<boost::shared_ptr<FdmDirichletBoundary> > boundaries; // 6. set-up solver FdmSolverDesc solverDesc = { mesher, boundaries, conditions, zeroInnerValue, maturity, tGrid_, 0 }; const boost::shared_ptr<FdmKlugeExtOUSolver<4> > solver( new FdmKlugeExtOUSolver<4>(Handle<KlugeExtOUProcess>(process_), rTS_, solverDesc, schemeDesc_)); std::vector<Real> x(4); x[0] = process_->initialValues()[0]; x[1] = process_->initialValues()[1]; x[2] = process_->initialValues()[2]; const Real tol = 1e-8; Array results(2*arguments_.tMinUp + arguments_.tMinDown); for (Size i=0; i < results.size(); ++i) { x[3] = std::max(tol, std::min( (Real) (nStates-results.size()+i), nStates-1-tol)); results[i] = solver->valueAt(x); } results_.value = *std::max_element(results.begin(), results.end()); }
void FdSimpleExtOUJumpSwingEngine::calculate() const { boost::shared_ptr<SwingExercise> swingExercise( boost::dynamic_pointer_cast<SwingExercise>(arguments_.exercise)); QL_REQUIRE(swingExercise, "Swing exercise supported only"); // 1. Layout std::vector<Size> dim; dim.push_back(xGrid_); dim.push_back(yGrid_); dim.push_back(arguments_.maxExerciseRights+1); const boost::shared_ptr<FdmLinearOpLayout> layout( new FdmLinearOpLayout(dim)); // 2. Mesher const std::vector<Time> exerciseTimes = swingExercise->exerciseTimes(rTS_->dayCounter(), rTS_->referenceDate()); const Time maturity = exerciseTimes.back(); const boost::shared_ptr<StochasticProcess1D> ouProcess( process_->getExtendedOrnsteinUhlenbeckProcess()); const boost::shared_ptr<Fdm1dMesher> xMesher( new FdmSimpleProcess1dMesher(xGrid_, ouProcess,maturity)); const boost::shared_ptr<Fdm1dMesher> yMesher( new ExponentialJump1dMesher(yGrid_, process_->beta(), process_->jumpIntensity(), process_->eta())); const boost::shared_ptr<Fdm1dMesher> exerciseMesher( new Uniform1dMesher(0, arguments_.maxExerciseRights, arguments_.maxExerciseRights+1)); std::vector<boost::shared_ptr<Fdm1dMesher> > meshers; meshers.push_back(xMesher); meshers.push_back(yMesher); meshers.push_back(exerciseMesher); const boost::shared_ptr<FdmMesher> mesher ( new FdmMesherComposite(layout, meshers)); // 3. Calculator boost::shared_ptr<FdmInnerValueCalculator> calculator( new FdmZeroInnerValue()); // 4. Step conditions std::list<boost::shared_ptr<StepCondition<Array> > > stepConditions; std::list<std::vector<Time> > stoppingTimes; // 4.1 Bermudan step conditions stoppingTimes.push_back(exerciseTimes); const boost::shared_ptr<StrikedTypePayoff> payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); boost::shared_ptr<FdmInnerValueCalculator> exerciseCalculator( new FdmExtOUJumpModelInnerValue(payoff, mesher, shape_)); stepConditions.push_back(boost::shared_ptr<StepCondition<Array> >( new FdmSimpleSwingCondition(exerciseTimes, mesher, exerciseCalculator, 2))); boost::shared_ptr<FdmStepConditionComposite> conditions( new FdmStepConditionComposite(stoppingTimes, stepConditions)); // 5. Boundary conditions const std::vector<boost::shared_ptr<FdmDirichletBoundary> > boundaries; // 6. set-up solver FdmSolverDesc solverDesc = { mesher, boundaries, conditions, calculator, maturity, tGrid_, 0 }; const boost::shared_ptr<FdmSimple3dExtOUJumpSolver> solver( new FdmSimple3dExtOUJumpSolver( Handle<ExtOUWithJumpsProcess>(process_), rTS_, solverDesc, schemeDesc_)); const Real x = process_->initialValues()[0]; const Real y = process_->initialValues()[1]; std::vector< std::pair<Real, Real> > exerciseValues; for (Size i=arguments_.minExerciseRights; i <= arguments_.maxExerciseRights; ++i) { const Real z = Real(i); exerciseValues.push_back(std::pair<Real, Real>( solver->valueAt(x, y, z), z)); } const Real z = std::max_element(exerciseValues.begin(), exerciseValues.end())->second; results_.value = solver->valueAt(x, y, z); }
void FdSimpleKlugeExtOUVPPEngine::calculate() const { ext::shared_ptr<SwingExercise> swingExercise( ext::dynamic_pointer_cast<SwingExercise>(arguments_.exercise)); QL_REQUIRE(swingExercise, "Swing exercise supported only"); const FdmVPPStepConditionFactory stepConditionFactory(arguments_); // 1. Exercise definition const std::vector<Time> exerciseTimes = swingExercise->exerciseTimes(rTS_->dayCounter(), rTS_->referenceDate()); // 2. mesher set-up const Time maturity = exerciseTimes.back(); const ext::shared_ptr<ExtOUWithJumpsProcess> klugeProcess = process_->getKlugeProcess(); const ext::shared_ptr<StochasticProcess1D> klugeOUProcess = klugeProcess->getExtendedOrnsteinUhlenbeckProcess(); const ext::shared_ptr<Fdm1dMesher> xMesher( new FdmSimpleProcess1dMesher(xGrid_, klugeOUProcess, maturity)); const ext::shared_ptr<Fdm1dMesher> yMesher( new ExponentialJump1dMesher(yGrid_, klugeProcess->beta(), klugeProcess->jumpIntensity(), klugeProcess->eta(), 1e-3)); const ext::shared_ptr<Fdm1dMesher> gMesher( new FdmSimpleProcess1dMesher(gGrid_, process_->getExtOUProcess(),maturity)); const ext::shared_ptr<Fdm1dMesher> exerciseMesher( stepConditionFactory.stateMesher()); const ext::shared_ptr<FdmMesher> mesher ( new FdmMesherComposite(xMesher, yMesher, gMesher, exerciseMesher)); // 3. Calculator const ext::shared_ptr<FdmInnerValueCalculator> zeroInnerValue( new FdmZeroInnerValue()); const ext::shared_ptr<Payoff> zeroStrikeCall( new PlainVanillaPayoff(Option::Call, 0.0)); const ext::shared_ptr<FdmInnerValueCalculator> fuelPrice( new FdmExpExtOUInnerValueCalculator(zeroStrikeCall, mesher, fuelShape_, 2)); const ext::shared_ptr<FdmInnerValueCalculator> powerPrice( new FdmExtOUJumpModelInnerValue(zeroStrikeCall,mesher,powerShape_)); const ext::shared_ptr<FdmInnerValueCalculator> sparkSpread( new FdmSparkSpreadInnerValue( ext::dynamic_pointer_cast<BasketPayoff>(arguments_.payoff), fuelPrice, powerPrice)); // 4. Step conditions std::list<std::vector<Time> > stoppingTimes; std::list<ext::shared_ptr<StepCondition<Array> > > stepConditions; // 4.1 Bermudan step conditions stoppingTimes.push_back(exerciseTimes); const FdmVPPStepConditionMesher mesh = { 3u, mesher }; const ext::shared_ptr<FdmVPPStepCondition> stepCondition( stepConditionFactory.build(mesh, fuelCostAddon_, fuelPrice, sparkSpread)); stepConditions.push_back(stepCondition); const ext::shared_ptr<FdmStepConditionComposite> conditions( new FdmStepConditionComposite(stoppingTimes, stepConditions)); // 5. Boundary conditions const FdmBoundaryConditionSet boundaries; // 6. set-up solver FdmSolverDesc solverDesc = { mesher, boundaries, conditions, zeroInnerValue, maturity, tGrid_, 0 }; const ext::shared_ptr<FdmKlugeExtOUSolver<4> > solver( new FdmKlugeExtOUSolver<4>(Handle<KlugeExtOUProcess>(process_), rTS_, solverDesc, schemeDesc_)); std::vector<Real> x(4); x[0] = process_->initialValues()[0]; x[1] = process_->initialValues()[1]; x[2] = process_->initialValues()[2]; const Real tol = 1e-8; const Real maxExerciseValue = exerciseMesher->locations().back(); const Real minExerciseValue = exerciseMesher->locations().front(); Array results(exerciseMesher->size()); for (Size i=0; i < results.size(); ++i) { x[3] = std::max(minExerciseValue + tol, std::min(exerciseMesher->location(i), maxExerciseValue - tol)); results[i] = solver->valueAt(x); } results_.value = stepCondition->maxValue(results); }