void SimpleRangeAccrualRateETI::initializeImpl(const TimeGrid& timeGrid, const boost::shared_ptr<YieldTermStructure>& discountCurve, const boost::shared_ptr<PathGeneratorFactory>& pathGenFactory) { referenceCalculation_->initialize(timeGrid,discountCurve,pathGenFactory); this->payoffDateInfo_->initialize(timeGrid,discountCurve,pathGenFactory); this->rangeNum_ = simpleRangeRateList_.size(); this->assetNum_ = pathGenFactory->numAssets(); Date today = Settings::instance().evaluationDate(); DayCounter dayCounter = Actual365Fixed(); double fixingStartTime = dayCounter.yearFraction( today , calculationStartDate_ ); Size fixingStartPosition = timeGrid.closestIndex(fixingStartTime); double fixingEndTime = dayCounter.yearFraction( today , calculationEndDate_ ); Size fixingEndPosition = timeGrid.closestIndex(fixingEndTime); Size fixingSize = fixingEndPosition - fixingStartPosition; this->fixingDatePositions_ = std::valarray<Size>(fixingSize); for ( Size position = 0 ; fixingSize ; position++ ) { fixingDatePositions_[position] = fixingStartPosition + position; } for ( Size rng = 0 ; this->rangeNum_ ; rng++ ) { simpleRangeRateList_[rng]->initialize(timeGrid,discountCurve,pathGenFactory); } }
boost::shared_ptr<path_generator_type> pathGenerator() const { Size numAssets = processes_->size(); TimeGrid grid = timeGrid(); Calendar calendar = this->arguments_.sp_payoff->calendar(); typename RNG::rsg_type gen = RNG::make_sequence_generator(numAssets*(grid.size()-1),seed_); boost::shared_ptr<path_generator_type> pgPtr = boost::shared_ptr<path_generator_type>( new path_generator_type(processes_, grid, gen)); PathInformation::instance().initialize(pgPtr->multiPath(),calendar); //history setting here.. //index의 Calendar와 product의 Calendar(calculation Date Calendar)는 따로 가야함 //과거 index fixing은 각각 클래스에서 fixing하는데 그 방법은 pathmanager가 indexHistory를 가지고 있어서 거기에 문의해서, //따로 클래스 내에 가져와서 fixing 시켜놈. 결과만 저장해서 나중에 함침. //그러므로 path에 따로 무언가를 붙일 필요는 없음. //MultiPath Grid는 product calendar로 grid숫자 계산함. return pgPtr; }
//! Return shared pointer to path generator who generates sample pathes in simulation virtual boost::shared_ptr<path_generator_type> pathGenerator() const { Size factors = this->process()->factors(); TimeGrid grid = timeGrid(); Size steps = grid.size() - 1; typename RNG::rsg_type gen = RNG::make_sequence_generator(factors * steps, seed_); return boost::make_shared<path_generator_type>(this->process(), grid, gen, false); }
inline ext::shared_ptr<typename MCDigitalEngine<RNG,S>::path_pricer_type> MCDigitalEngine<RNG,S>::pathPricer() const { ext::shared_ptr<CashOrNothingPayoff> payoff = ext::dynamic_pointer_cast<CashOrNothingPayoff>( this->arguments_.payoff); QL_REQUIRE(payoff, "wrong payoff given"); ext::shared_ptr<AmericanExercise> exercise = ext::dynamic_pointer_cast<AmericanExercise>( this->arguments_.exercise); QL_REQUIRE(exercise, "wrong exercise given"); ext::shared_ptr<GeneralizedBlackScholesProcess> process = ext::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( this->process_); QL_REQUIRE(process, "Black-Scholes process required"); TimeGrid grid = this->timeGrid(); PseudoRandom::ursg_type sequenceGen(grid.size()-1, PseudoRandom::urng_type(76)); return ext::shared_ptr< typename MCDigitalEngine<RNG,S>::path_pricer_type>( new DigitalPathPricer(payoff, exercise, process->riskFreeRate(), process, sequenceGen)); }
inline void MultiPathGeneratorFixedPath<GSG>::next() const { typedef typename GSG::sample_type sequence_type; const sequence_type& sequence_ = generator_.nextSequence(); Size m = process_->size(); Size n = process_->factors(); MultiPath& path = *nextPtr_; Array asset = process_->initialValues(); for (Size j=0; j<m; j++) path[j].front() = asset[j]; Array temp(n); TimeGrid timeGrid = path[0].timeGrid(); Time t, dt; for (Size i = 1; i < path.pathSize(); i++) { Size offset = (i-1)*n; t = timeGrid[i-1]; dt = timeGrid.dt(i-1); std::copy(sequence_.value.begin()+offset, sequence_.value.begin()+offset+n, temp.begin()); asset = process_->evolve(t, asset, dt, temp,i-1); for (Size j=0; j<m; j++) path[j][i] = asset[j]; } }
boost::shared_ptr<path_generator_type> pathGenerator() const { TimeGrid grid = this->timeGrid(); typename RNG::rsg_type gen = RNG::make_sequence_generator(grid.size()-1,seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(process_, grid, gen, brownianBridge_)); }
boost::shared_ptr<path_generator_type> pathGenerator() const { Size dimensions = process_->factors(); TimeGrid grid = this->timeGrid(); typename RNG::rsg_type generator = RNG::make_sequence_generator(dimensions*(grid.size()-1),seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(process_, grid, generator, brownianBridge_)); }
PathGeneratorFactory::PathGeneratorFactory(const boost::shared_ptr<StochasticProcessArray>& processes, const TimeGrid& timeGrid) : processes_(processes), grid_(timeGrid) { unsigned long myseed = static_cast<unsigned long>(1); rand_ = std::tr1::mt19937(myseed); this->numAssets_ = processes->size(); this->pathSize_ = timeGrid.size(); PseudoRandom::rsg_type gen = PseudoRandom::make_sequence_generator(numAssets_*(timeGrid.size()-1),1); gen_ = boost::shared_ptr<MultiVariate<PseudoRandom>::path_generator_type>(new MultiVariate<PseudoRandom>::path_generator_type(processes, timeGrid, gen, false)); this->next_ = MultiPath(numAssets_,this->grid_); S0_ = std::valarray<double>(numAssets_); randArrs_ = std::valarray<double>(numAssets_); //this->testRandom_ = Array(numAssets_ * pathSize_); previousRand_ = Matrix(numAssets_, pathSize_); Matrix corr = processes->correlation(); chol_=CholeskyDecomposition(corr); random_ = MultiPath(numAssets_,timeGrid); // num - 1 this->muGrid_ = Matrix(numAssets_, timeGrid.size() - 1); this->volGrid_ = Matrix(numAssets_,timeGrid.size() - 1); antitheticFlag_ = false; for (Size asset = 0 ; asset<numAssets_ ;++asset) { //초기화 수익률 or 절대값 S0_[asset] = processes->process(asset)->x0() / processes->process(asset)->basePrice(); for (Size t = 0 ; t < pathSize_ - 1 ;++t) { double mu_t = processes->process(asset)->drift(timeGrid[t],1.0); double sigma_t = processes->process(asset)->diffusion(timeGrid[t],1.0); double dt_t = timeGrid.dt(t); // exp( ( mu[t] - 0.5 * vol[t] * vol[t] ) * dt[t] ) muGrid_[asset][t] = std::exp( ( mu_t - 0.5 * sigma_t * sigma_t ) * dt_t ); // vol[t] * sqrt(dt[t]) volGrid_[asset][t] = sigma_t * std::sqrt(dt_t); } } }
ext::shared_ptr<path_generator_type> pathGenerator() const { Size numAssets = processes_->size(); TimeGrid grid = timeGrid(); typename RNG::rsg_type gen = RNG::make_sequence_generator(numAssets*(grid.size()-1),seed_); return ext::shared_ptr<path_generator_type>( new path_generator_type(processes_, grid, gen, brownianBridge_)); }
inline boost::shared_ptr<typename MCLongstaffSchwartzEngine<GenericEngine,MC,RNG,S>::path_generator_type> MCLongstaffSchwartzEngine<GenericEngine,MC,RNG,S>::pathGenerator() const { Size dimensions = process_->factors(); TimeGrid grid = this->timeGrid(); typename RNG::rsg_type generator = RNG::make_sequence_generator(dimensions*(grid.size()-1),seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(process_, grid, generator, brownianBridge_)); }
DiscretizedVanillaOption::DiscretizedVanillaOption( const VanillaOption::arguments& args, const StochasticProcess& process, const TimeGrid& grid) : arguments_(args) { stoppingTimes_.resize(args.exercise->dates().size()); for (Size i=0; i<stoppingTimes_.size(); ++i) { stoppingTimes_[i] = process.time(args.exercise->date(i)); if (!grid.empty()) { // adjust to the given grid stoppingTimes_[i] = grid.closestTime(stoppingTimes_[i]); } } }
boost::shared_ptr<Lattice> BlackKarasinski::tree(const TimeGrid& grid) const { TermStructureFittingParameter phi(termStructure()); boost::shared_ptr<ShortRateDynamics> numericDynamics( new Dynamics(phi, a(), sigma())); boost::shared_ptr<TrinomialTree> trinomial( new TrinomialTree(numericDynamics->process(), grid)); boost::shared_ptr<ShortRateTree> numericTree( new ShortRateTree(trinomial, numericDynamics, grid)); typedef TermStructureFittingParameter::NumericalImpl NumericalImpl; boost::shared_ptr<NumericalImpl> impl = boost::dynamic_pointer_cast<NumericalImpl>(phi.implementation()); impl->reset(); Real value = 1.0; Real vMin = -50.0; Real vMax = 50.0; for (Size i=0; i<(grid.size() - 1); i++) { Real discountBond = termStructure()->discount(grid[i+1]); Real xMin = trinomial->underlying(i, 0); Real dx = trinomial->dx(i); Helper finder(i, xMin, dx, discountBond, numericTree); Brent s1d; s1d.setMaxEvaluations(1000); value = s1d.solve(finder, 1e-7, value, vMin, vMax); impl->set(grid[i], value); // vMin = value - 10.0; // vMax = value + 10.0; } return numericTree; }
boost::shared_ptr<Lattice> HullWhite::tree(const TimeGrid& grid) const { TermStructureFittingParameter phi(termStructure()); boost::shared_ptr<ShortRateDynamics> numericDynamics( new Dynamics(phi, a(), sigma())); boost::shared_ptr<TrinomialTree> trinomial( new TrinomialTree(numericDynamics->process(), grid)); boost::shared_ptr<ShortRateTree> numericTree( new ShortRateTree(trinomial, numericDynamics, grid)); typedef TermStructureFittingParameter::NumericalImpl NumericalImpl; boost::shared_ptr<NumericalImpl> impl = boost::dynamic_pointer_cast<NumericalImpl>(phi.implementation()); impl->reset(); for (Size i=0; i<(grid.size() - 1); i++) { Real discountBond = termStructure()->discount(grid[i+1]); const Array& statePrices = numericTree->statePrices(i); Size size = numericTree->size(i); Time dt = numericTree->timeGrid().dt(i); Real dx = trinomial->dx(i); Real x = trinomial->underlying(i,0); Real value = 0.0; for (Size j=0; j<size; j++) { value += statePrices[j]*std::exp(-x*dt); x += dx; } value = std::log(value/discountBond)/dt; impl->set(grid[i], value); } return numericTree; }
inline boost::shared_ptr<LongstaffSchwartzMultiPathPricer> MCAmericanPathEngine<RNG>::lsmPathPricer() const { boost::shared_ptr<StochasticProcessArray> processArray = boost::dynamic_pointer_cast<StochasticProcessArray>(this->process_); QL_REQUIRE(processArray && processArray->size()>0, "Stochastic process array required"); boost::shared_ptr<GeneralizedBlackScholesProcess> process = boost::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( processArray->process(0)); QL_REQUIRE(process, "generalized Black-Scholes process required"); const TimeGrid theTimeGrid = this->timeGrid(); const std::vector<Time> & times = theTimeGrid.mandatoryTimes(); const Size numberOfTimes = times.size(); const std::vector<Date> & fixings = this->arguments_.fixingDates; QL_REQUIRE(fixings.size() == numberOfTimes, "Invalid dates/times"); std::vector<Size> timePositions(numberOfTimes); Array discountFactors(numberOfTimes); std::vector<Handle<YieldTermStructure> > forwardTermStructures(numberOfTimes); const Handle<YieldTermStructure> & riskFreeRate = process->riskFreeRate(); for (Size i = 0; i < numberOfTimes; ++i) { timePositions[i] = theTimeGrid.index(times[i]); discountFactors[i] = riskFreeRate->discount(times[i]); forwardTermStructures[i] = Handle<YieldTermStructure>( boost::make_shared<ImpliedTermStructure>(riskFreeRate, fixings[i])); } const Size polynomialOrder = 2; const LsmBasisSystem::PolynomType polynomType = LsmBasisSystem::Monomial; return boost::shared_ptr<LongstaffSchwartzMultiPathPricer> ( new LongstaffSchwartzMultiPathPricer(this->arguments_.payoff, timePositions, forwardTermStructures, discountFactors, polynomialOrder, polynomType)); }
template <class PathType> inline LongstaffSchwartzPathPricer<PathType>::LongstaffSchwartzPathPricer( const TimeGrid& times, const boost::shared_ptr<EarlyExercisePathPricer<PathType> >& pathPricer, const boost::shared_ptr<YieldTermStructure>& termStructure) : calibrationPhase_(true), pathPricer_(pathPricer), coeff_ (new Array[times.size()-1]), dF_ (new DiscountFactor[times.size()-1]), v_ (pathPricer_->basisSystem()) { for (Size i=0; i<times.size()-1; ++i) { dF_[i] = termStructure->discount(times[i+1]) / termStructure->discount(times[i]); } }
DiscretizedBarrierOption::DiscretizedBarrierOption( const BarrierOption::arguments& args, const StochasticProcess& process, const TimeGrid& grid) : arguments_(args), vanilla_(arguments_, process, grid) { QL_REQUIRE(args.exercise->dates().size(), "specify at least one stopping date"); stoppingTimes_.resize(args.exercise->dates().size()); for (Size i=0; i<stoppingTimes_.size(); ++i) { stoppingTimes_[i] = process.time(args.exercise->date(i)); if (!grid.empty()) { // adjust to the given grid stoppingTimes_[i] = grid.closestTime(stoppingTimes_[i]); } } }
boost::shared_ptr<path_generator_type> pathGenerator() const { boost::shared_ptr<BasketPayoff> payoff = boost::dynamic_pointer_cast<BasketPayoff>( arguments_.payoff); QL_REQUIRE(payoff, "non-basket payoff given"); Size numAssets = processes_->size(); TimeGrid grid = timeGrid(); typename RNG::rsg_type gen = RNG::make_sequence_generator(numAssets*(grid.size()-1),seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(processes_, grid, gen, brownianBridge_)); }
inline boost::shared_ptr<typename MCPathBasketEngine<RNG,S>::path_generator_type> MCPathBasketEngine<RNG,S>::pathGenerator() const { boost::shared_ptr<PathPayoff> payoff = arguments_.payoff; QL_REQUIRE(payoff, "non-basket payoff given"); Size numAssets = process_->size(); TimeGrid grid = timeGrid(); typename RNG::rsg_type gen = RNG::make_sequence_generator(numAssets * (grid.size() - 1), seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(process_, grid, gen, brownianBridge_)); }
void HifivePricer::initializeImpl(const TimeGrid& timeGrid, const boost::shared_ptr<YieldTermStructure>& discountCurve, const boost::shared_ptr<PathGeneratorFactory>& pathGenFactory) { //this->discount_ = Array(eventTriggerList_.size(),1.0); //for ( Size i = 0 ; i < eventTriggerList_.size() ; i++ ) //{ // eventTriggerList_[i]->initialize(timeGrid,discountCurve); // if ( eventTriggerList_[i]->isExpired() ) // { // remainEventPosition_ = i + 1; // this->discount_[i] = 1.0; // }else // { // this->discount_[i] = discountCurve_->discount(eventTriggerList_[i]->payoffDate()); // } //} Date today = Settings::instance().evaluationDate(); remainEventPosition_ = 0; autoCallEventPosition_ = timeGrid.size() - 1; this->cf_results_ = std::vector<boost::shared_ptr<CashFlowResult>>( this->eventTriggerList_.size() ); this->calcValue_results_ = std::vector<boost::shared_ptr<CalcValueResult>>(1); this->calcValue_results_[0] = boost::shared_ptr<CalcValueResult>( new CalcValueResult("NET","KRW")); for ( Size i = 0 ; i < eventTriggerList_.size() ; i++ ) { this->eventTriggerList_[i]->initialize(timeGrid,discountCurve,pathGenFactory); this->cf_results_[i] = boost::shared_ptr<CashFlowResult>( new CashFlowResult(i+1, this->eventTriggerList_[i]->getEventDate(), this->eventTriggerList_[i]->getPayoffDate(), "NET", this->currency_, this->payoffDateInfo_->discount()) ); bool kk = eventTriggerList_[i]->isExpired(); if ( eventTriggerList_[i]->isExpired() ) { remainEventPosition_ = i + 1; } } this->kiBarrierEventTrigger_->initialize(timeGrid,discountCurve,pathGenFactory); //this->nonOccBarrierEventTrigger_->initialize(timeGrid,discountCurve,pathGenFactory); //pastkiBarrierEventOcc_ = kiBarrierEventTrigger_->pastEventOcc(); }
MultiPathGeneratorFixedPath<GSG>::MultiPathGeneratorFixedPath( const boost::shared_ptr<StochasticProcess>& process, const TimeGrid& times, GSG generator, bool brownianBridge) : brownianBridge_(brownianBridge), process_(process), generator_(generator), next_(boost::shared_ptr<MultiPath>(new MultiPath(process->size(), times))) { nextPtr_ = next_.get(); QL_REQUIRE(generator_.dimension() == process->factors()*(times.size()-1), "dimension (" << generator_.dimension() << ") is not equal to (" << process->factors() << " * " << times.size()-1 << ") the number of factors " << "times the number of time steps"); QL_REQUIRE(times.size() > 1, "no times given"); }
inline boost::shared_ptr<typename MCPathBasketEngine<RNG,S>::path_pricer_type> MCPathBasketEngine<RNG,S>::pathPricer() const { boost::shared_ptr<PathPayoff> payoff = arguments_.payoff; QL_REQUIRE(payoff, "non-basket payoff given"); boost::shared_ptr<GeneralizedBlackScholesProcess> process = boost::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( process_->process(0)); QL_REQUIRE(process, "Black-Scholes process required"); const TimeGrid theTimeGrid = timeGrid(); const std::vector<Time> & times = theTimeGrid.mandatoryTimes(); const Size numberOfTimes = times.size(); const std::vector<Date> & fixings = this->arguments_.fixingDates; QL_REQUIRE(fixings.size() == numberOfTimes, "Invalid dates/times"); std::vector<Size> timePositions(numberOfTimes); Array discountFactors(numberOfTimes); std::vector<Handle<YieldTermStructure> > forwardTermStructures(numberOfTimes); const Handle<YieldTermStructure> & riskFreeRate = process->riskFreeRate(); for (Size i = 0; i < numberOfTimes; ++i) { timePositions[i] = theTimeGrid.index(times[i]); discountFactors[i] = riskFreeRate->discount(times[i]); forwardTermStructures[i] = Handle<YieldTermStructure>( new ImpliedTermStructure(riskFreeRate, fixings[i])); } return boost::shared_ptr< typename MCPathBasketEngine<RNG,S>::path_pricer_type>( new EuropeanPathMultiPathPricer(payoff, timePositions, forwardTermStructures, discountFactors)); }
boost::shared_ptr<path_generator_type> pathGenerator() const { Handle<YieldTermStructure> curve = model_->termStructure(); Date referenceDate = curve->referenceDate(); DayCounter dayCounter = curve->dayCounter(); Time forwardMeasureTime = dayCounter.yearFraction(referenceDate, arguments_.endDates.back()); Array parameters = model_->params(); Real a = parameters[0], sigma = parameters[1]; boost::shared_ptr<HullWhiteForwardProcess> process( new HullWhiteForwardProcess(curve, a, sigma)); process->setForwardMeasureTime(forwardMeasureTime); TimeGrid grid = this->timeGrid(); typename RNG::rsg_type generator = RNG::make_sequence_generator(grid.size()-1,seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(process, grid, generator, brownianBridge_)); }
void simulateMP(const boost::shared_ptr<StochasticProcess>& process, int nbPaths, TimeGrid& grid, BigNatural seed, bool antithetic_variates, double *res) { typedef PseudoRandom::rsg_type rsg_type; typedef MultiPathGenerator<rsg_type>::sample_type sample_type; Size assets = process->factors(); rsg_type rsg = PseudoRandom::make_sequence_generator( (grid.size() - 1) * assets, seed); MultiPathGenerator<rsg_type> generator(process, grid, rsg, false); // fill simulated paths for (int i=0; i<nbPaths; ++i) { const bool antithetic = (i%2)==0 ? false : true; sample_type sample = antithetic_variates ? (antithetic ? generator.antithetic(): generator.next()) : generator.next(); Path p1 = sample.value[0]; std::copy(p1.begin(), p1.end(), res + i * grid.size()); } }
boost::shared_ptr<path_generator_type> pathGenerator() const { if(ifConst) { Date exercisedate = GenericEngine<OneAssetOption::arguments,OneAssetOption::results>::arguments_.exercise->lastDate(); boost::shared_ptr<BlackScholesConstProcess> constProcess_( new BlackScholesConstProcess( exercisedate, realProcess->stateVariable(), realProcess->dividendYield(), realProcess->riskFreeRate(), realProcess->blackVolatility() )); Size dimensions = constProcess_->factors(); TimeGrid grid = this->timeGrid(); typename RNG::rsg_type generator = RNG::make_sequence_generator(dimensions*(grid.size()-1),seed_); return boost::shared_ptr<path_generator_type>( new path_generator_type(constProcess_, grid, generator, brownianBridge_)); } else { return MCEuropeanEngine<RNG,S>::pathGenerator(); } };
MultiPathGenerator<GSG>::MultiPathGenerator( const boost::shared_ptr<StochasticProcess>& process, const TimeGrid& times, GSG generator, bool brownianBridge) : brownianBridge_(brownianBridge), process_(process), generator_(generator), next_(MultiPath(process->size(), times), 1.0) { //std::cout << "dimension (" << generator_.dimension() // << ") is not equal to (" // << process->factors() << " * " << times.size() - 1 // << ") the number of factors " // << "times the number of time steps"; QL_REQUIRE(generator_.dimension() == process->factors()*(times.size()-1), "dimension (" << generator_.dimension() << ") is not equal to (" << process->factors() << " * " << times.size()-1 << ") the number of factors " << "times the number of time steps"); QL_REQUIRE(times.size() > 1, "no times given"); }
void VPPTest::testVPPPricing() { BOOST_TEST_MESSAGE("Testing VPP pricing using perfect foresight or FDM..."); SavedSettings backup; const Date today = Date(18, December, 2011); const DayCounter dc = ActualActual(); Settings::instance().evaluationDate() = today; // vpp paramter const Real heatRate = 2.5; const Real pMin = 8; const Real pMax = 40; const Size tMinUp = 6; const Size tMinDown = 2; const Real startUpFuel = 20; const Real startUpFixCost = 100; const boost::shared_ptr<SwingExercise> exercise( new SwingExercise(today, today+6, 3600u)); VanillaVPPOption vppOption(heatRate, pMin, pMax, tMinUp, tMinDown, startUpFuel, startUpFixCost, exercise); const boost::shared_ptr<KlugeExtOUProcess> klugeOUProcess = createKlugeExtOUProcess(); const boost::shared_ptr<ExtOUWithJumpsProcess> lnPowerProcess = klugeOUProcess->getKlugeProcess(); const boost::shared_ptr<ExtendedOrnsteinUhlenbeckProcess> ouProcess = lnPowerProcess->getExtendedOrnsteinUhlenbeckProcess(); const boost::shared_ptr<ExtendedOrnsteinUhlenbeckProcess> lnGasProcess = klugeOUProcess->getExtOUProcess(); const Real beta = lnPowerProcess->beta(); const Real eta = lnPowerProcess->eta(); const Real lambda = lnPowerProcess->jumpIntensity(); const Real alpha = ouProcess->speed(); const Real volatility_x = ouProcess->volatility(); const Real kappa = lnGasProcess->speed(); const Real volatility_u = lnGasProcess->volatility(); const Rate irRate = 0.00; const Real fuelCostAddon = 3.0; const boost::shared_ptr<YieldTermStructure> rTS = flatRate(today, irRate, dc); const Size nHours = LENGTH(powerPrices); typedef FdSimpleKlugeExtOUVPPEngine::Shape Shape; boost::shared_ptr<Shape> fuelShape(new Shape(nHours)); boost::shared_ptr<Shape> powerShape(new Shape(nHours)); for (Size i=0; i < nHours; ++i) { const Time t = (i+1)/(365*24.); const Real fuelPrice = fuelPrices[i]; const Real gs = std::log(fuelPrice)-square<Real>()(volatility_u) /(4*kappa)*(1-std::exp(-2*kappa*t)); (*fuelShape)[i] = Shape::value_type(t, gs); const Real powerPrice = powerPrices[i]; const Real ps = std::log(powerPrice)-square<Real>()(volatility_x) /(4*alpha)*(1-std::exp(-2*alpha*t)) -lambda/beta*std::log((eta-std::exp(-beta*t))/(eta-1.0)); (*powerShape)[i] = Shape::value_type(t, ps); } // Test: intrinsic value vppOption.setPricingEngine(boost::shared_ptr<PricingEngine>( new DynProgVPPIntrinsicValueEngine( std::vector<Real>(fuelPrices, fuelPrices+nHours), std::vector<Real>(powerPrices, powerPrices+nHours), fuelCostAddon, flatRate(0.0, dc)))); const Real intrinsic = vppOption.NPV(); const Real expectedIntrinsic = 2056.04; if (std::fabs(intrinsic - expectedIntrinsic) > 0.1) { BOOST_ERROR("Failed to reproduce intrinsic value" << "\n calculated: " << intrinsic << "\n expected : " << expectedIntrinsic); } // Test: finite difference price const boost::shared_ptr<PricingEngine> engine( new FdSimpleKlugeExtOUVPPEngine(klugeOUProcess, rTS, fuelShape, powerShape, fuelCostAddon, 1, 25, 11, 10)); vppOption.setPricingEngine(engine); const Real fdmPrice = vppOption.NPV(); const Real expectedFdmPrice = 5217.68; if (std::fabs(fdmPrice - expectedFdmPrice) > 0.1) { BOOST_ERROR("Failed to reproduce finite difference price" << "\n calculated: " << fdmPrice << "\n expected : " << expectedFdmPrice); } // Test: Monte-Carlo perfect foresight price VanillaVPPOption::arguments args; vppOption.setupArguments(&args); const FdmVPPStepConditionFactory stepConditionFactory(args); const boost::shared_ptr<FdmMesher> oneDimMesher(new FdmMesherComposite( stepConditionFactory.stateMesher())); const Size nStates = oneDimMesher->layout()->dim()[0]; const FdmVPPStepConditionMesher vppMesh = { 0u, oneDimMesher }; const TimeGrid grid(dc.yearFraction(today, exercise->lastDate()+1), exercise->dates().size()); typedef PseudoRandom::rsg_type rsg_type; typedef MultiPathGenerator<rsg_type>::sample_type sample_type; rsg_type rsg = PseudoRandom::make_sequence_generator( klugeOUProcess->factors()*(grid.size()-1), 1234ul); MultiPathGenerator<rsg_type> generator(klugeOUProcess, grid, rsg, false); GeneralStatistics npv; const Size nTrails = 2500; for (Size i=0; i < nTrails; ++i) { const sample_type& path = generator.next(); const boost::shared_ptr<FdmVPPStepCondition> stepCondition( stepConditionFactory.build( vppMesh, fuelCostAddon, boost::shared_ptr<FdmInnerValueCalculator>( new PathFuelPrice(path.value, fuelShape)), boost::shared_ptr<FdmInnerValueCalculator>( new PathSparkSpreadPrice(heatRate, path.value, fuelShape, powerShape)))); Array state(nStates, 0.0); for (Size j=exercise->dates().size(); j > 0; --j) { stepCondition->applyTo(state, grid.at(j)); state*=rTS->discount(grid.at(j))/rTS->discount(grid.at(j-1)); } npv.add(state.back()); } Real npvMC = npv.mean(); Real errorMC = npv.errorEstimate(); const Real expectedMC = 5250.0; if (std::fabs(npvMC-expectedMC) > 3*errorMC) { BOOST_ERROR("Failed to reproduce Monte-Carlo price" << "\n calculated: " << npvMC << "\n error ; " << errorMC << "\n expected : " << expectedMC); } npv.reset(); // Test: Longstaff Schwartz least square Monte-Carlo const Size nCalibrationTrails = 1000u; std::vector<sample_type> calibrationPaths; std::vector<boost::shared_ptr<FdmVPPStepCondition> > stepConditions; std::vector<boost::shared_ptr<FdmInnerValueCalculator> > sparkSpreads; sparkSpreads.reserve(nCalibrationTrails); stepConditions.reserve(nCalibrationTrails); calibrationPaths.reserve(nCalibrationTrails); for (Size i=0; i < nCalibrationTrails; ++i) { calibrationPaths.push_back(generator.next()); sparkSpreads.push_back(boost::shared_ptr<FdmInnerValueCalculator>( new PathSparkSpreadPrice(heatRate, calibrationPaths.back().value, fuelShape, powerShape))); stepConditions.push_back(stepConditionFactory.build( vppMesh, fuelCostAddon, boost::shared_ptr<FdmInnerValueCalculator>( new PathFuelPrice(calibrationPaths.back().value, fuelShape)), sparkSpreads.back())); } const FdmLinearOpIterator iter = oneDimMesher->layout()->begin(); // prices of all calibration paths for all states std::vector<Array> prices(nCalibrationTrails, Array(nStates, 0.0)); // regression coefficients for all states and all exercise dates std::vector<std::vector<Array> > coeff( nStates, std::vector<Array>(exercise->dates().size(), Array())); // regression functions const Size dim = 1u; std::vector<boost::function1<Real, Array> > v( LsmBasisSystem::multiPathBasisSystem(dim,5u, LsmBasisSystem::Monomial)); for (Size i=exercise->dates().size(); i > 0u; --i) { const Time t = grid.at(i); std::vector<Array> x(nCalibrationTrails, Array(dim)); for (Size j=0; j < nCalibrationTrails; ++j) { x[j][0] = sparkSpreads[j]->innerValue(iter, t); } for (Size k=0; k < nStates; ++k) { std::vector<Real> y(nCalibrationTrails); for (Size j=0; j < nCalibrationTrails; ++j) { y[j] = prices[j][k]; } coeff[k][i-1] = GeneralLinearLeastSquares(x, y, v).coefficients(); for (Size j=0; j < nCalibrationTrails; ++j) { prices[j][k] = 0.0; for (Size l=0; l < v.size(); ++l) { prices[j][k] += coeff[k][i-1][l]*v[l](x[j]); } } } for (Size j=0; j < nCalibrationTrails; ++j) { stepConditions[j]->applyTo(prices[j], grid.at(i)); } } Real tmpValue = 0.0; for (Size i=0; i < nTrails; ++i) { Array x(dim), state(nStates, 0.0), contState(nStates, 0.0); const sample_type& path = (i % 2) ? generator.antithetic() : generator.next(); const boost::shared_ptr<FdmInnerValueCalculator> fuelPrices( new PathFuelPrice(path.value, fuelShape)); const boost::shared_ptr<FdmInnerValueCalculator> sparkSpreads( new PathSparkSpreadPrice(heatRate, path.value, fuelShape, powerShape)); for (Size j=exercise->dates().size(); j > 0u; --j) { const Time t = grid.at(j); const Real fuelPrice = fuelPrices->innerValue(iter, t); const Real sparkSpread = sparkSpreads->innerValue(iter, t); const Real startUpCost = startUpFixCost + (fuelPrice + fuelCostAddon)*startUpFuel; x[0] = sparkSpread; for (Size k=0; k < nStates; ++k) { contState[k] = 0.0; for (Size l=0; l < v.size(); ++l) { contState[k] += coeff[k][j-1][l]*v[l](x); } } const Real pMinFlow = pMin*(sparkSpread - heatRate*fuelCostAddon); const Real pMaxFlow = pMax*(sparkSpread - heatRate*fuelCostAddon); // rollback continuation states and the path states for (Size i=0; i < 2*tMinUp; ++i) { if (i < tMinUp) { state[i] += pMinFlow; contState[i]+= pMinFlow; } else { state[i] += pMaxFlow; contState[i]+= pMaxFlow; } } // dynamic programming using the continuation values Array retVal(nStates); for (Size i=0; i < tMinUp-1; ++i) { retVal[i] = retVal[tMinUp + i] = (contState[i+1] > contState[tMinUp + i+1])? state[i+1] : state[tMinUp + i+1]; } if (contState[2*tMinUp] >= std::max(contState[tMinUp-1], contState[2*tMinUp-1])) { retVal[tMinUp-1] = retVal[2*tMinUp-1] = state[2*tMinUp]; } else if (contState[tMinUp-1] >= contState[2*tMinUp-1]) { retVal[tMinUp-1] = retVal[2*tMinUp-1] = state[tMinUp-1]; } else { retVal[tMinUp-1] = retVal[2*tMinUp-1] = state[2*tMinUp-1]; } for (Size i=0; i < tMinDown-1; ++i) { retVal[2*tMinUp + i] = state[2*tMinUp + i+1]; } if (contState.back() >= std::max(contState.front(), contState[tMinUp]) - startUpCost) { retVal.back() = state.back(); } else if (contState.front() > contState[tMinUp]) { retVal.back() = state.front()-startUpCost; } else { retVal.back() = state[tMinUp]-startUpCost; } state = retVal; } tmpValue+=0.5*state.back(); if ((i%2)) { npv.add(tmpValue, 1.0); tmpValue = 0.0; } } npvMC = npv.mean(); errorMC = npv.errorEstimate(); if (std::fabs(npvMC-fdmPrice) > 3*errorMC) { BOOST_ERROR("Failed to reproduce Least Square Monte-Carlo price" << "\n calculated : " << npvMC << "\n error : " << errorMC << "\n expected FDM : " << fdmPrice); } }
boost::shared_ptr<ELSNotionalProtectedPricer> MCELSNotionalProtectedEngine::pathPricer() const{ /*boost::shared_ptr<GeneralizedBlackScholesProcess> process = boost::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( process_->process(0)); QL_REQUIRE(process, "Black-Scholes process required");*/ TimeGrid theTimeGrid = timeGrid(); const std::vector<Time> & times = theTimeGrid.mandatoryTimes(); Size numberOfTimes = times.size(); Size numAssets = process_->size(); Size pastFixingNum=this->arguments_.pastFixingDateNum; const std::vector<Date> & fixings = this->arguments_.fixingDates; const std::vector<boost::shared_ptr<StockIndex>>& refIndex=arguments_.refIndex; DayCounter dayCounter = this->arguments_.dayCounter; std::vector<Real> initialValues = this->arguments_.initialValues; std::vector<Real> dividends = this->arguments_.dividends; // 후에 TS로 수정 Real redemCoupon= this->arguments_.redemCoupon; std::vector<Date> remainfixings; //오늘일자를 TS에서 가져옴. Date today = Settings::instance().evaluationDate(); Size numberOfFixings = fixings.size(); for(Size i=0;i<numberOfFixings;++i){ if(fixings[i]>today){ remainfixings.push_back(fixings[i]); } } Size numberOfRemainFixings = remainfixings.size(); additionalStats_.resize(numberOfTimes+pastFixingNum); underlyingValue_.resize(numAssets); QL_REQUIRE(numberOfRemainFixings == numberOfTimes, "Invalid dates/times"); std::vector<Size> timePositions(numberOfTimes); Array discountFactors(numberOfTimes); for (Size i = 0; i < numberOfTimes; ++i) { //timePositions[i] = theTimeGrid.index(times[i]); discountFactors[i] = discountTS_->discount(times[i]); } Matrix earlyExValues_Chg(numAssets,numberOfTimes,Null<Real>()); Array x0(numAssets); Array drift(numAssets); Array sigma(numAssets); const std::vector<Real>& earlyExValues = this->arguments_.earlyExTriggers; for(Size i=0;i<numAssets;++i){ if(process_->process(i)->x0()<0.00001){ x0[i]=std::log((refIndex[i]->fixing(Settings::instance().evaluationDate()))/initialValues[i]); underlyingValue_[i]=refIndex[i]->fixing(Settings::instance().evaluationDate()); }else{ x0[i]=std::log((process_->process(i)->x0())/initialValues[i]); underlyingValue_[i]=process_->process(i)->x0(); } sigma[i]=process_->process(i)->diffusion(times[0],1.0) ; // 변동성 조정 필요 if(process_->process(i)->drift(times[0],1.0)<0.00001){ drift[i]= discountTS_->zeroRate(times.back(),Compounded,Annual,false) - dividends[i]; //discountTS_->zeroRate(times.back(),Compounded,Annual,false); }else{ drift[i]= process_->process(i)->drift(times[0],1.0) - dividends[i]; //discountTS_->zeroRate(times.back(),Compounded,Annual,false); } //drift 이거 dividend 추가해야함. for(Size j=0;j<numberOfTimes;++j){ earlyExValues_Chg[i][j]=(std::log(earlyExValues[j])-(drift[i]-0.5*sigma[i]*sigma[i])*times[j]); } } return boost::shared_ptr<ELSNotionalProtectedPricer>( new ELSNotionalProtectedPricer(times,process_,x0,discountFactors,earlyExValues_Chg, redemCoupon,pastFixingNum,additionalStats_)); }
Real DigitalPathPricer::operator()(const Path& path) const { Size n = path.length(); QL_REQUIRE(n>1, "the path cannot be empty"); Real log_asset_price = std::log(path.front()); Real x, y; Volatility vol; TimeGrid timeGrid = path.timeGrid(); Time dt; std::vector<Real> u = sequenceGen_.nextSequence().value; Real log_strike = std::log(payoff_->strike()); Size i; switch (payoff_->optionType()) { case Option::Call: for (i=0; i<n-1; i++) { x = std::log(path[i+1]/path[i]); // terminal or initial vol? vol = diffProcess_->diffusion(timeGrid[i+1], std::exp(log_asset_price)); // vol = diffProcess_->diffusion(timeGrid[i+2], // std::exp(log_asset_price+x)); dt = timeGrid.dt(i); y = log_asset_price + 0.5*(x + std::sqrt(x*x-2*vol*vol*dt*std::log((1-u[i])))); // cross the strike if (y >= log_strike) { if (exercise_->payoffAtExpiry()) { return payoff_->cashPayoff() * discountTS_->discount(path.timeGrid().back()); } else { // the discount should be calculated at the exercise // time between path.timeGrid()[i+1] and // path.timeGrid()[i+2] return payoff_->cashPayoff() * discountTS_->discount(path.timeGrid()[i+1]); } } log_asset_price += x; } break; case Option::Put: for (i=0; i<n-1; i++) { x = std::log(path[i+1]/path[i]); // terminal or initial vol? // initial (timeGrid[i+1]) for the time being vol = diffProcess_->diffusion(timeGrid[i+1], std::exp(log_asset_price)); // vol = diffProcess_->diffusion(timeGrid[i+2], // std::exp(log_asset_price+x)); dt = timeGrid.dt(i); y = log_asset_price + 0.5*(x - std::sqrt(x*x - 2*vol*vol*dt*std::log(u[i]))); if (y <= log_strike) { if (exercise_->payoffAtExpiry()) { return payoff_->cashPayoff() * discountTS_->discount(path.timeGrid().back()); } else { // the discount should be calculated at the exercise // time between path.timeGrid()[i+1] and // path.timeGrid()[i+2] return payoff_->cashPayoff() * discountTS_->discount(path.timeGrid()[i+1]); } } log_asset_price += x; } break; default: QL_FAIL("unknown option type"); } return 0.0; }
//! \brief Calculate the NPV of the remaining cash flow at default time \f$ \tau \f$. //! //! The calculation method used here is based on CIR model. virtual Real defaultNPV(const MultiPath& path, Time defaultTime) const { //find short rate at default time TimeGrid timeGrid = path[0].timeGrid(); auto defaultPos = timeGrid.index(defaultTime); Real shortRate = path[0][defaultPos]; //calculate discount factor from reference time to the default time Time previousTime = timeGrid[0]; Real discountFactor = 1.0; for (auto i = 0; i <= defaultPos; ++i){ discountFactor *= std::exp(-path[0].value(i) * (timeGrid[i] - previousTime)); previousTime = timeGrid[i]; } boost::shared_ptr<const MCVanillaSwapUCVAEngine> engine = engine_.lock(); VanillaSwap::arguments* arguments = dynamic_cast<VanillaSwap::arguments*>(engine->getArguments()); Handle<YieldTermStructure> discountCurve = engine->discountCurve(); Date referenceDate = discountCurve->referenceDate(); std::vector<Date> fixedDates = arguments->fixedPayDates; std::vector<Date> floatingDates = arguments->floatingPayDates; // transfer payment Dates to Times std::vector<Real> fixedTimes; std::vector<Real> floatingTimes; for (int i = 0; i != fixedDates.size(); ++i){ fixedTimes.push_back(engine->instrument()->fixedDayCount().yearFraction(referenceDate, fixedDates[i])); } for (int i = 0; i != floatingDates.size(); ++i){ floatingTimes.push_back(engine->instrument()->floatingDayCount().yearFraction(referenceDate, floatingDates[i])); } // calculate the corresponding discount factors of each leg to default time std::vector<Real> fixedDiscountFactor; std::vector<Real> floatingDiscountFactor; int fixedIndex = 0; int floatingIndex = 0; for (int i = 0; i != fixedTimes.size(); ++i){ if (fixedTimes[i] >= defaultTime){ fixedDiscountFactor.push_back(engine->Model()->discountBond(0.0, fixedTimes[i] - defaultTime, shortRate)); } else{ ++fixedIndex; } } for (int i = 0; i != floatingTimes.size(); ++i){ if (floatingTimes[i] >= defaultTime){ floatingDiscountFactor.push_back(engine->Model()->discountBond(0.0, floatingTimes[i] - defaultTime, shortRate)); } else{ ++floatingIndex; } } //calculate the NPV(tau) Real NPVtau = 0.0; NPVtau += arguments->nominal * (1. - floatingDiscountFactor.back()); for (int m = 0; m != floatingDiscountFactor.size(); ++m){ NPVtau += arguments->nominal * arguments->floatingSpreads[m + floatingIndex] * floatingDiscountFactor[m]; } for (int m = 0; m != fixedDiscountFactor.size(); ++m){ NPVtau -= arguments->fixedCoupons[m + fixedIndex] * fixedDiscountFactor[m]; } if (arguments->type == QuantLib::VanillaSwap::Payer){ NPVtau = NPVtau; } else{ NPVtau = -NPVtau; } return NPVtau * discountFactor; }
LongstaffSchwartzProxyPathPricer::LongstaffSchwartzProxyPathPricer( const TimeGrid ×, const boost::shared_ptr<EarlyExercisePathPricer<PathType> > &pricer, const boost::shared_ptr<YieldTermStructure> &termStructure) : LongstaffSchwartzPathPricer<PathType>(times, pricer, termStructure), coeffItm_(times.size() - 1), coeffOtm_(times.size() - 1) {}