void CatBond::arguments::validate() const { Bond::arguments::validate(); QL_REQUIRE(notionalRisk, "null notionalRisk"); }
void LinearTsrPricer::initialize(const FloatingRateCoupon &coupon) { coupon_ = dynamic_cast<const CmsCoupon *>(&coupon); QL_REQUIRE(coupon_, "CMS coupon needed"); gearing_ = coupon_->gearing(); spread_ = coupon_->spread(); fixingDate_ = coupon_->fixingDate(); paymentDate_ = coupon_->date(); swapIndex_ = coupon_->swapIndex(); forwardCurve_ = swapIndex_->forwardingTermStructure(); if (swapIndex_->exogenousDiscount()) discountCurve_ = swapIndex_->discountingTermStructure(); else discountCurve_ = forwardCurve_; // if no coupon discount curve is given just use the discounting curve // from the swap index. for rate calculation this curve cancels out in // the computation, so e.g. the discounting swap engine will produce // correct results, even if the couponDiscountCurve is not set here. // only the price member function in this class will be dependent on the // coupon discount curve. today_ = QuantLib::Settings::instance().evaluationDate(); if (paymentDate_ > today_ && !couponDiscountCurve_.empty()) couponDiscountRatio_ = couponDiscountCurve_->discount(paymentDate_) / discountCurve_->discount(paymentDate_); else couponDiscountRatio_ = 1.; spreadLegValue_ = spread_ * coupon_->accrualPeriod() * discountCurve_->discount(paymentDate_) * couponDiscountRatio_; if (fixingDate_ > today_) { swapTenor_ = swapIndex_->tenor(); swap_ = swapIndex_->underlyingSwap(fixingDate_); swapRateValue_ = swap_->fairRate(); annuity_ = 1.0E4 * std::fabs(swap_->fixedLegBPS()); ext::shared_ptr<SmileSection> sectionTmp = swaptionVolatility()->smileSection(fixingDate_, swapTenor_); adjustedLowerBound_ = settings_.lowerRateBound_; adjustedUpperBound_ = settings_.upperRateBound_; if(sectionTmp->volatilityType() == Normal) { // adjust lower bound if it was not set explicitly if(settings_.defaultBounds_) adjustedLowerBound_ = std::min(adjustedLowerBound_, -adjustedUpperBound_); } else { // adjust bounds by section's shift adjustedLowerBound_ -= sectionTmp->shift(); adjustedUpperBound_ -= sectionTmp->shift(); } // if the section does not provide an atm level, we enhance it to // have one, no need to exit with an exception ... if (sectionTmp->atmLevel() == Null<Real>()) smileSection_ = ext::make_shared<AtmSmileSection>( sectionTmp, swapRateValue_); else smileSection_ = sectionTmp; // compute linear model's parameters Real gx = 0.0, gy = 0.0; for (Size i = 0; i < swap_->fixedLeg().size(); i++) { ext::shared_ptr<Coupon> c = ext::dynamic_pointer_cast<Coupon>(swap_->fixedLeg()[i]); Real yf = c->accrualPeriod(); Date d = c->date(); Real pv = yf * discountCurve_->discount(d); gx += pv * GsrG(d); gy += pv; } Real gamma = gx / gy; Date lastd = swap_->fixedLeg().back()->date(); a_ = discountCurve_->discount(paymentDate_) * (gamma - GsrG(paymentDate_)) / (discountCurve_->discount(lastd) * GsrG(lastd) + swapRateValue_ * gy * gamma); b_ = discountCurve_->discount(paymentDate_) / gy - a_ * swapRateValue_; } }
void FDStepConditionEngine<Scheme>::calculate( PricingEngine::results* r) const { OneAssetOption::results * results = dynamic_cast<OneAssetOption::results *>(r); setGridLimits(); initializeInitialCondition(); initializeOperator(); initializeBoundaryConditions(); initializeStepCondition(); typedef FiniteDifferenceModel<ParallelEvolver< Scheme<TridiagonalOperator> > > model_type; typename model_type::operator_type operatorSet; typename model_type::array_type arraySet; typename model_type::bc_set bcSet; typename model_type::condition_type conditionSet; prices_ = intrinsicValues_; controlPrices_ = intrinsicValues_; controlOperator_ = finiteDifferenceOperator_; controlBCs_[0] = BCs_[0]; controlBCs_[1] = BCs_[1]; operatorSet.push_back(finiteDifferenceOperator_); operatorSet.push_back(controlOperator_); arraySet.push_back(prices_.values()); arraySet.push_back(controlPrices_.values()); bcSet.push_back(BCs_); bcSet.push_back(controlBCs_); conditionSet.push_back(stepCondition_); conditionSet.push_back(boost::shared_ptr<StandardStepCondition>( new NullCondition<Array>)); model_type model(operatorSet, bcSet); model.rollback(arraySet, getResidualTime(), 0.0, timeSteps_, conditionSet); prices_.values() = arraySet[0]; controlPrices_.values() = arraySet[1]; boost::shared_ptr<StrikedTypePayoff> striked_payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(payoff_); QL_REQUIRE(striked_payoff, "non-striked payoff given"); Real variance = process_->blackVolatility()->blackVariance( exerciseDate_, striked_payoff->strike()); DiscountFactor dividendDiscount = process_->dividendYield()->discount(exerciseDate_); DiscountFactor riskFreeDiscount = process_->riskFreeRate()->discount(exerciseDate_); Real spot = process_->stateVariable()->value(); Real forwardPrice = spot * dividendDiscount / riskFreeDiscount; BlackCalculator black(striked_payoff, forwardPrice, std::sqrt(variance), riskFreeDiscount); results->value = prices_.valueAtCenter() - controlPrices_.valueAtCenter() + black.value(); results->delta = prices_.firstDerivativeAtCenter() - controlPrices_.firstDerivativeAtCenter() + black.delta(spot); results->gamma = prices_.secondDerivativeAtCenter() - controlPrices_.secondDerivativeAtCenter() + black.gamma(spot); results->additionalResults["priceCurve"] = prices_; }
void AnalyticDoubleBarrierBinaryEngine::calculate() const { if (arguments_.barrierType == DoubleBarrier::KIKO || arguments_.barrierType == DoubleBarrier::KOKI) { boost::shared_ptr<AmericanExercise> ex = boost::dynamic_pointer_cast<AmericanExercise>( arguments_.exercise); QL_REQUIRE(ex, "KIKO/KOKI options must have American exercise"); QL_REQUIRE(ex->dates()[0] <= process_->blackVolatility()->referenceDate(), "American option with window exercise not handled yet"); } else { boost::shared_ptr<EuropeanExercise> ex = boost::dynamic_pointer_cast<EuropeanExercise>( arguments_.exercise); QL_REQUIRE(ex, "non-European exercise given"); } boost::shared_ptr<CashOrNothingPayoff> payoff = boost::dynamic_pointer_cast<CashOrNothingPayoff>(arguments_.payoff); QL_REQUIRE(payoff, "a cash-or-nothing payoff must be given"); Real spot = process_->stateVariable()->value(); QL_REQUIRE(spot > 0.0, "negative or null underlying given"); Real variance = process_->blackVolatility()->blackVariance( arguments_.exercise->lastDate(), payoff->strike()); Real barrier_lo = arguments_.barrier_lo; Real barrier_hi = arguments_.barrier_hi; DoubleBarrier::Type barrierType = arguments_.barrierType; QL_REQUIRE(barrier_lo>0.0, "positive low barrier value required"); QL_REQUIRE(barrier_hi>0.0, "positive high barrier value required"); QL_REQUIRE(barrier_lo < barrier_hi, "barrier_lo must be < barrier_hi"); QL_REQUIRE(barrierType == DoubleBarrier::KnockIn || barrierType == DoubleBarrier::KnockOut || barrierType == DoubleBarrier::KIKO || barrierType == DoubleBarrier::KOKI, "Unsupported barrier type"); // degenerate cases switch (barrierType) { case DoubleBarrier::KnockOut: if (spot <= barrier_lo || spot >= barrier_hi) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; case DoubleBarrier::KnockIn: if (spot <= barrier_lo || spot >= barrier_hi) { // knocked in - pays results_.value = payoff->cashPayoff(); results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; case DoubleBarrier::KIKO: if (spot >= barrier_hi) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } else if (spot <= barrier_lo) { // knocked in, pays results_.value = payoff->cashPayoff(); results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; case DoubleBarrier::KOKI: if (spot <= barrier_lo) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } else if (spot >= barrier_hi) { // knocked in, pays results_.value = payoff->cashPayoff(); results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; } AnalyticDoubleBarrierBinaryEngine_helper helper(process_, payoff, arguments_); switch (barrierType) { case DoubleBarrier::KnockOut: case DoubleBarrier::KnockIn: results_.value = helper.payoffAtExpiry(spot, variance, barrierType); break; case DoubleBarrier::KIKO: case DoubleBarrier::KOKI: results_.value = helper.payoffKIKO(spot, variance, barrierType); break; } }
FdmBlackScholesMesher::FdmBlackScholesMesher( Size size, const ext::shared_ptr<GeneralizedBlackScholesProcess>& process, Time maturity, Real strike, Real xMinConstraint, Real xMaxConstraint, Real eps, Real scaleFactor, const std::pair<Real, Real>& cPoint, const DividendSchedule& dividendSchedule) : Fdm1dMesher(size) { const Real S = process->x0(); QL_REQUIRE(S > 0.0, "negative or null underlying given"); std::vector<std::pair<Time, Real> > intermediateSteps; for (Size i=0; i < dividendSchedule.size() && process->time(dividendSchedule[i]->date()) <= maturity; ++i) intermediateSteps.push_back( std::make_pair( process->time(dividendSchedule[i]->date()), dividendSchedule[i]->amount() ) ); const Size intermediateTimeSteps = std::max<Size>(2, Size(24.0*maturity)); for (Size i=0; i < intermediateTimeSteps; ++i) intermediateSteps.push_back( std::make_pair((i+1)*(maturity/intermediateTimeSteps), 0.0)); std::sort(intermediateSteps.begin(), intermediateSteps.end()); const Handle<YieldTermStructure> rTS = process->riskFreeRate(); const Handle<YieldTermStructure> qTS = process->dividendYield(); Time lastDivTime = 0.0; Real fwd = S, mi = S, ma = S; for (Size i=0; i < intermediateSteps.size(); ++i) { const Time divTime = intermediateSteps[i].first; const Real divAmount = intermediateSteps[i].second; fwd = fwd / rTS->discount(divTime) * rTS->discount(lastDivTime) * qTS->discount(divTime) / qTS->discount(lastDivTime); mi = std::min(mi, fwd); ma = std::max(ma, fwd); fwd-= divAmount; mi = std::min(mi, fwd); ma = std::max(ma, fwd); lastDivTime = divTime; } // Set the grid boundaries const Real normInvEps = InverseCumulativeNormal()(1-eps); const Real sigmaSqrtT = process->blackVolatility()->blackVol(maturity, strike) *std::sqrt(maturity); Real xMin = std::log(mi) - sigmaSqrtT*normInvEps*scaleFactor; Real xMax = std::log(ma) + sigmaSqrtT*normInvEps*scaleFactor; if (xMinConstraint != Null<Real>()) { xMin = xMinConstraint; } if (xMaxConstraint != Null<Real>()) { xMax = xMaxConstraint; } ext::shared_ptr<Fdm1dMesher> helper; if ( cPoint.first != Null<Real>() && std::log(cPoint.first) >=xMin && std::log(cPoint.first) <=xMax) { helper = ext::shared_ptr<Fdm1dMesher>( new Concentrating1dMesher(xMin, xMax, size, std::pair<Real,Real>(std::log(cPoint.first), cPoint.second))); } else { helper = ext::shared_ptr<Fdm1dMesher>( new Uniform1dMesher(xMin, xMax, size)); } locations_ = helper->locations(); for (Size i=0; i < locations_.size(); ++i) { dplus_[i] = helper->dplus(i); dminus_[i] = helper->dminus(i); } }
void EnergyBasisSwap::performCalculations() const { try { if (payIndex_->empty()) { if (payIndex_->forwardCurveEmpty()) { QL_FAIL("index [" + payIndex_->name() + "] does not have any quotes or forward prices"); } else { addPricingError(PricingError::Warning, "index [" + payIndex_->name() + "] does not have any quotes; " "using forward prices from [" + payIndex_->forwardCurve()->name() + "]"); } } if (receiveIndex_->empty()) { if (receiveIndex_->forwardCurveEmpty()) { QL_FAIL("index [" + receiveIndex_->name() + "] does not have any quotes or forward prices"); } else { addPricingError(PricingError::Warning, "index [" + receiveIndex_->name() + "] does not have any quotes; " "using forward prices from [" + receiveIndex_->forwardCurve()->name() + "]"); } } NPV_ = 0.0; additionalResults_.clear(); dailyPositions_.clear(); paymentCashFlows_.clear(); Date evaluationDate = Settings::instance().evaluationDate(); const Currency& baseCurrency = CommoditySettings::instance().currency(); const UnitOfMeasure baseUnitOfMeasure = CommoditySettings::instance().unitOfMeasure(); Real quantityUomConversionFactor = calculateUomConversionFactor( pricingPeriods_[0]->quantity().commodityType(), baseUnitOfMeasure, pricingPeriods_[0]->quantity().unitOfMeasure()); Real payIndexUomConversionFactor = calculateUomConversionFactor(payIndex_->commodityType(), payIndex_->unitOfMeasure(), baseUnitOfMeasure); Real receiveIndexUomConversionFactor = calculateUomConversionFactor(receiveIndex_->commodityType(), receiveIndex_->unitOfMeasure(), baseUnitOfMeasure); Real payIndexFxConversionFactor = calculateFxConversionFactor(payIndex_->currency(), baseCurrency, evaluationDate); Real receiveIndexFxConversionFactor = calculateFxConversionFactor(receiveIndex_->currency(), baseCurrency, evaluationDate); Real payLegFxConversionFactor = calculateFxConversionFactor(baseCurrency, payCurrency_, evaluationDate); Real receiveLegFxConversionFactor = calculateFxConversionFactor(baseCurrency, receiveCurrency_, evaluationDate); Real basisUomConversionFactor = calculateUomConversionFactor( pricingPeriods_[0]->quantity().commodityType(), basis_.unitOfMeasure(), baseUnitOfMeasure); Real basisFxConversionFactor = calculateFxConversionFactor(baseCurrency, basis_.amount().currency(), evaluationDate); Real basisValue = basis_.amount().value() * basisUomConversionFactor * basisFxConversionFactor; Date lastPayIndexQuoteDate = payIndex_->lastQuoteDate(); Date lastReceiveIndexQuoteDate = receiveIndex_->lastQuoteDate(); if (lastPayIndexQuoteDate < evaluationDate - 1) { std::ostringstream message; message << "index [" << payIndex_->name() << "] has last quote date of " << io::iso_date(lastPayIndexQuoteDate); addPricingError(PricingError::Warning, message.str()); } if (lastReceiveIndexQuoteDate < evaluationDate - 1) { std::ostringstream message; message << "index [" << receiveIndex_->name() << "] has last quote date of " << io::iso_date(lastReceiveIndexQuoteDate); addPricingError(PricingError::Warning, message.str()); } Date lastQuoteDate = std::min(lastPayIndexQuoteDate, lastReceiveIndexQuoteDate); Real totalQuantityAmount = 0; // price each period for (PricingPeriods::const_iterator pi = pricingPeriods_.begin(); pi != pricingPeriods_.end(); ++pi) { const boost::shared_ptr<PricingPeriod>& pricingPeriod = *pi; Integer periodDayCount = 0; // get the index quotes Date periodStartDate = calendar_.adjust(pricingPeriod->startDate()); for (Date stepDate = periodStartDate; stepDate <= pricingPeriod->endDate(); stepDate = calendar_.advance(stepDate, 1*Days)) { bool unrealized = stepDate > evaluationDate; Real payQuoteValue = 0; Real receiveQuoteValue = 0; if (stepDate <= lastQuoteDate) { payQuoteValue = payIndex_->price(stepDate); receiveQuoteValue = receiveIndex_->price(stepDate); } else { payQuoteValue = payIndex_->forwardPrice(stepDate); receiveQuoteValue = receiveIndex_->forwardPrice(stepDate); } if (payQuoteValue == 0) { std::ostringstream message; message << "pay quote value for curve [" << payIndex_->name() << "] is 0 for date " << io::iso_date(stepDate); addPricingError(PricingError::Warning, message.str()); } if (receiveQuoteValue == 0) { std::ostringstream message; message << "receive quote value for curve [" << receiveIndex_->name() << "] is 0 for date " << io::iso_date(stepDate); addPricingError(PricingError::Warning, message.str()); } QL_REQUIRE(payQuoteValue != Null<Real>(), "curve [" << payIndex_->name() << "] missing value for pricing date: " << stepDate); QL_REQUIRE(receiveQuoteValue != Null<Real>(), "curve [" << receiveIndex_->name() << "] missing value for pricing date: " << stepDate); Real payLegPriceValue = payQuoteValue * payIndexUomConversionFactor * payIndexFxConversionFactor; Real receiveLegPriceValue = receiveQuoteValue * receiveIndexUomConversionFactor * receiveIndexFxConversionFactor; if (spreadToPayLeg_) payLegPriceValue += basisValue; else receiveLegPriceValue += basisValue; dailyPositions_[stepDate] = EnergyDailyPosition(stepDate, payLegPriceValue, receiveLegPriceValue, unrealized); periodDayCount++; } Real periodQuantityAmount = pricingPeriod->quantity().amount() * quantityUomConversionFactor; totalQuantityAmount += periodQuantityAmount; Real avgDailyQuantityAmount = periodDayCount == 0 ? 0 : periodQuantityAmount / periodDayCount; Real payLegValue = 0; Real receiveLegValue = 0; for (std::map<Date, EnergyDailyPosition>::iterator dpi = dailyPositions_.find(periodStartDate); dpi != dailyPositions_.end() && dpi->first <= pricingPeriod->endDate(); ++dpi) { EnergyDailyPosition& dailyPosition = dpi->second; dailyPosition.quantityAmount = avgDailyQuantityAmount; dailyPosition.riskDelta = (-dailyPosition.payLegPrice + dailyPosition.receiveLegPrice) * avgDailyQuantityAmount; payLegValue += -dailyPosition.payLegPrice * avgDailyQuantityAmount; receiveLegValue += dailyPosition.receiveLegPrice * avgDailyQuantityAmount; } Real discountFactor = 1; Real payLegDiscountFactor = 1; Real receiveLegDiscountFactor = 1; if (pricingPeriod->paymentDate() >= evaluationDate + 2 /* settlement days*/) { discountFactor = discountTermStructure_->discount( pricingPeriod->paymentDate()); payLegDiscountFactor = payLegTermStructure_->discount( pricingPeriod->paymentDate()); receiveLegDiscountFactor = receiveLegTermStructure_->discount( pricingPeriod->paymentDate()); } Real uDelta = receiveLegValue + payLegValue; Real dDelta = (receiveLegValue * receiveLegDiscountFactor) + (payLegValue * payLegDiscountFactor); Real pmtFxConversionFactor = (dDelta > 0) ? payLegFxConversionFactor : receiveLegFxConversionFactor; Currency pmtCurrency = (dDelta > 0) ? receiveCurrency_ : payCurrency_; Real pmtDiscountFactor = (dDelta > 0) ? receiveLegDiscountFactor : payLegDiscountFactor; paymentCashFlows_[pricingPeriod->paymentDate()] = boost::shared_ptr<CommodityCashFlow> ( new CommodityCashFlow(pricingPeriod->paymentDate(), Money(baseCurrency, uDelta * discountFactor), Money(baseCurrency, uDelta), Money(pmtCurrency, dDelta * pmtFxConversionFactor), Money(pmtCurrency, uDelta * pmtFxConversionFactor), discountFactor, pmtDiscountFactor, pricingPeriod->paymentDate() <= evaluationDate)); calculateSecondaryCostAmounts( pricingPeriods_[0]->quantity().commodityType(), totalQuantityAmount, evaluationDate); NPV_ += dDelta; } QL_REQUIRE(paymentCashFlows_.size() > 0, "no cashflows"); for (SecondaryCostAmounts::const_iterator i = secondaryCostAmounts_.begin(); i != secondaryCostAmounts_.end(); ++i) { Real amount = i->second.value(); NPV_ -= amount; } additionalResults_["dailyPositions"] = dailyPositions_; } catch (const QuantLib::Error& e) { addPricingError(PricingError::Error, e.what()); throw; } catch (const std::exception& e) { addPricingError(PricingError::Error, e.what()); throw; } }
void FdBlackScholesVanillaEngine::calculate() const { // 1. Layout std::vector<Size> dim; dim.push_back(xGrid_); const boost::shared_ptr<FdmLinearOpLayout> layout( new FdmLinearOpLayout(dim)); const boost::shared_ptr<StrikedTypePayoff> payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); // 2. Mesher const Time maturity = process_->time(arguments_.exercise->lastDate()); const boost::shared_ptr<Fdm1dMesher> equityMesher( new FdmBlackScholesMesher( xGrid_, process_, maturity, payoff->strike(), Null<Real>(), Null<Real>(), 0.0001, 1.5, std::pair<Real, Real>(payoff->strike(), 0.1))); std::vector<boost::shared_ptr<Fdm1dMesher> > meshers; meshers.push_back(equityMesher); boost::shared_ptr<FdmMesher> mesher ( new FdmMesherComposite(layout, meshers)); // 3. Calculator boost::shared_ptr<FdmInnerValueCalculator> calculator( new FdmLogInnerValue(payoff, mesher, 0)); // 4. Step conditions std::list<boost::shared_ptr<StepCondition<Array> > > stepConditions; std::list<std::vector<Time> > stoppingTimes; // 4.1 Step condition if discrete dividends if(!arguments_.cashFlow.empty()) { boost::shared_ptr<FdmDividendHandler> dividendCondition( new FdmDividendHandler(arguments_.cashFlow, mesher, process_->riskFreeRate()->referenceDate(), process_->riskFreeRate()->dayCounter(), 0)); stepConditions.push_back(dividendCondition); stoppingTimes.push_back(dividendCondition->dividendTimes()); } // 4.2 Step condition if american or bermudan exercise QL_REQUIRE( arguments_.exercise->type() == Exercise::American || arguments_.exercise->type() == Exercise::European || arguments_.exercise->type() == Exercise::Bermudan, "exercise type is not supported"); if (arguments_.exercise->type() == Exercise::American) { stepConditions.push_back(boost::shared_ptr<StepCondition<Array> >( new FdmAmericanStepCondition(mesher,calculator))); } else if (arguments_.exercise->type() == Exercise::Bermudan) { boost::shared_ptr<FdmBermudanStepCondition> bermudanCondition( new FdmBermudanStepCondition( arguments_.exercise->dates(), process_->riskFreeRate()->referenceDate(), process_->riskFreeRate()->dayCounter(), mesher, calculator)); stepConditions.push_back(bermudanCondition); stoppingTimes.push_back(bermudanCondition->exerciseTimes()); } boost::shared_ptr<FdmStepConditionComposite> conditions( new FdmStepConditionComposite(stoppingTimes, stepConditions)); // 5. Boundary conditions std::vector<boost::shared_ptr<FdmDirichletBoundary> > boundaries; // 6. Solver boost::shared_ptr<FdmBlackScholesSolver> solver( new FdmBlackScholesSolver( Handle<GeneralizedBlackScholesProcess>(process_), mesher, boundaries, conditions, calculator, payoff->strike(), maturity, tGrid_, dampingSteps_, schemeDesc_, localVol_, illegalLocalVolOverwrite_)); const Real spot = process_->x0(); results_.value = solver->valueAt(spot); results_.delta = solver->deltaAt(spot); results_.gamma = solver->gammaAt(spot); results_.theta = solver->thetaAt(spot); }
/*! \pre weights must be positive or null */ inline void GeneralStatistics::add(Real value, Real weight) { QL_REQUIRE(weight>=0.0, "negative weight not allowed"); samples_.push_back(std::make_pair(value,weight)); sorted_ = false; }
void KahaleSmileSection::compute() { std::pair<Size,Size> afIdx = ssutils_->arbitragefreeIndices(); leftIndex_ = afIdx.first; rightIndex_ = afIdx.second; if(deleteArbitragePoints_) { while(leftIndex_>1 || rightIndex_<k_.size()-1) { ssutils_ = boost::shared_ptr<SmileSectionUtils>(new SmileSectionUtils(*source_,moneynessGrid_,f_)); std::pair<Size,Size> afIdx = ssutils_->arbitragefreeIndices(); leftIndex_ = afIdx.first; rightIndex_ = afIdx.second; QL_REQUIRE(rightIndex_>leftIndex_, "arbitrage free region must at least contain two points (only index is " << leftIndex_ << ")"); if(leftIndex_>1) { moneynessGrid_.erase(moneynessGrid_.begin()+leftIndex_-1); k_.erase(k_.begin()+leftIndex_-1); c_.erase(c_.begin()+leftIndex_-1); leftIndex_--; rightIndex_--; } if(rightIndex_<k_.size()-1) { moneynessGrid_.erase(moneynessGrid_.begin()+rightIndex_+1); k_.erase(k_.begin()+rightIndex_+1); c_.erase(c_.begin()+rightIndex_+1); rightIndex_--; } } } cFunctions_ = std::vector<boost::shared_ptr<cFunction> >(rightIndex_-leftIndex_+2); // extrapolation in the leftmost interval Brent brent; bool success; Real secl = 0.0; do { success=true; try { Real k1 = k_[leftIndex_]; Real c1 = c_[leftIndex_]; Real c0 = c_[0]; secl = (c_[leftIndex_]-c_[0]) / (k_[leftIndex_]-k_[0]); Real sec = (c_[leftIndex_+1]-c_[leftIndex_]) / (k_[leftIndex_+1]-k_[leftIndex_]); Real c1p; if(interpolate_) c1p=(secl+sec)/2; else { c1p=(blackFormula(Option::Call, k1+gap_, f_, sqrt(source_->variance(k1+gap_)))- blackFormula(Option::Call, k1, f_, sqrt(source_->variance(k1))))/gap_; QL_REQUIRE(secl < c1p && c1p <= 0.0,"dummy"); // can not extrapolate so throw exception which is caught below } sHelper1 sh1(k1,c0,c1,c1p); Real s = brent.solve(sh1,QL_KAHALE_ACC,0.20,0.00,QL_KAHALE_SMAX); // numerical parameters hardcoded here sh1(s); boost::shared_ptr<cFunction> cFct1(new cFunction(sh1.f_,s,0.0,sh1.b_)); cFunctions_[0]=cFct1; } catch(...) { leftIndex_++; success=false; } } while(!success && leftIndex_ < rightIndex_); QL_REQUIRE(leftIndex_ < rightIndex_, "can not extrapolate to left, right index of af region reached (" << rightIndex_ << ")"); // interpolation Real cp0 = 0.0, cp1 = 0.0; if(interpolate_) { for(Size i = leftIndex_; i<rightIndex_; i++) { Real k0 = k_[i]; Real k1 = k_[i+1]; Real c0 = c_[i]; Real c1 = c_[i+1]; Real sec = (c_[i+1]-c_[i]) / (k_[i+1]-k_[i]); if(i==leftIndex_) cp0 = leftIndex_ > 0 ? (secl + sec) / 2.0 : sec; Real secr; if(i==rightIndex_-1) secr=0.0; else secr = (c_[i+2]-c_[i+1]) / (k_[i+2]-k_[i+1]); cp1 = (sec+secr) / 2.0; aHelper ah(k0,k1,c0,c1,cp0,cp1); Real a; try { a = brent.solve(ah,QL_KAHALE_ACC,0.5*(cp1+(1.0+cp0)),cp1+QL_KAHALE_EPS,1.0+cp0-QL_KAHALE_EPS); // numerical parameters hardcoded here } catch(...) { // from theory there must exist a zero. if the solver does not find it, it most // probably lies close one of the interval bounds. Just choose the better bound // and relax the accuracy. This does not matter in practice usually. Real la = std::fabs(ah(cp1+QL_KAHALE_EPS)); Real ra = std::fabs(ah(1.0+cp0-QL_KAHALE_EPS)); if( la < QL_KAHALE_ACC_RELAX || ra < QL_KAHALE_ACC_RELAX) { // tolerance hardcoded here a = la < ra ? cp1+QL_KAHALE_EPS : 1.0+cp0-QL_KAHALE_EPS; } else QL_FAIL("can not interpolate at index " << i); } ah(a); boost::shared_ptr<cFunction> cFct(new cFunction(ah.f_,ah.s_,a,ah.b_)); cFunctions_[leftIndex_ > 0 ? i-leftIndex_+1 : 0]=cFct; cp0=cp1; } } // extrapolation of right wing do { success=true; try { Real k0 = k_[rightIndex_]; Real c0 = c_[rightIndex_]; Real cp0; if(interpolate_) cp0 = 0.5*(c_[rightIndex_]-c_[rightIndex_-1])/(k_[rightIndex_]-k_[rightIndex_-1]); else { cp0=(blackFormula(Option::Call, k0, f_, sqrt(source_->variance(k0)))- blackFormula(Option::Call, k0-gap_, f_, sqrt(source_->variance(k0-gap_))))/gap_; } boost::shared_ptr<cFunction> cFct; if(exponentialExtrapolation_) { cFct = boost::shared_ptr<cFunction>(new cFunction(-cp0/c0 ,std::log(c0)-cp0/c0*k0)); } else { sHelper sh(k0,c0,cp0); Real s; s = brent.solve(sh,QL_KAHALE_ACC,0.20,0.0,QL_KAHALE_SMAX); // numerical parameters hardcoded here sh(s); cFct = boost::shared_ptr<cFunction>(new cFunction(sh.f_,s,0.0,0.0)); } cFunctions_[rightIndex_-leftIndex_+1]=cFct; } catch (...) { rightIndex_--; success=false; } } while(!success && rightIndex_ > leftIndex_); QL_REQUIRE(leftIndex_ < rightIndex_, "can not extrapolate to right, left index of af region reached (" << leftIndex_ << ")"); }
CreditDefaultSwap::CreditDefaultSwap(Protection::Side side, Real notional, Rate upfront, Rate runningSpread, const Schedule& schedule, BusinessDayConvention convention, const DayCounter& dayCounter, bool settlesAccrual, bool paysAtDefaultTime, const Date& protectionStart, const Date& upfrontDate, const boost::shared_ptr<Claim>& claim, const DayCounter& lastPeriodDayCounter, const Natural standardCdsStartDelayDays, const Natural standardCdsUpfrontDelayDays) : side_(side), notional_(notional), upfront_(upfront), runningSpread_(runningSpread), settlesAccrual_(settlesAccrual), paysAtDefaultTime_(paysAtDefaultTime), claim_(claim), protectionStart_(protectionStart == Null<Date>() ? schedule[0] : protectionStart) { Date d = upfrontDate == Null<Date>() ? schedule[0] : upfrontDate; try { if (schedule.rule() == DateGeneration::CDS) { // a standard CDS is identified // by the schedule rule Date evalDate = Settings::instance().evaluationDate(); if (protectionStart == Null<Date>()) protectionStart_ = evalDate + standardCdsStartDelayDays; // if protection // start is given it // is not set here if (upfrontDate == Null<Date>()) d = schedule.calendar().advance( evalDate, standardCdsUpfrontDelayDays * Days, schedule.businessDayConvention(), schedule.endOfMonth()); // if upfront date is // given it is not set // here QL_REQUIRE(protectionStart_ >= schedule[0], "protection must start on or after accrual " "start for standard CDS"); } } catch (...) { QL_REQUIRE(protectionStart_ <= schedule[0], "protection can not start after accrual for non " "standard CDS"); } leg_ = FixedRateLeg(schedule) .withNotionals(notional) .withCouponRates(runningSpread, dayCounter) .withPaymentAdjustment(convention) .withLastPeriodDayCounter(lastPeriodDayCounter); upfrontPayment_.reset(new SimpleCashFlow(notional*upfront, d)); QL_REQUIRE(upfrontPayment_->date() >= protectionStart_, "upfront can not be due before contract start"); if (!claim_) claim_ = boost::shared_ptr<Claim>(new FaceValueClaim); registerWith(claim_); }
void LocalBootstrap<Curve>::calculate() const { validCurve_ = false; Size nInsts = ts_->instruments_.size(); // ensure rate helpers are sorted std::sort(ts_->instruments_.begin(), ts_->instruments_.end(), detail::BootstrapHelperSorter()); // check that there is no instruments with the same maturity for (Size i=1; i<nInsts; ++i) { Date m1 = ts_->instruments_[i-1]->latestDate(), m2 = ts_->instruments_[i]->latestDate(); QL_REQUIRE(m1 != m2, "two instruments have the same maturity ("<< m1 <<")"); } // check that there is no instruments with invalid quote for (Size i=0; i<nInsts; ++i) QL_REQUIRE(ts_->instruments_[i]->quote()->isValid(), io::ordinal(i+1) << " instrument (maturity: " << ts_->instruments_[i]->latestDate() << ") has an invalid quote"); // setup instruments for (Size i=0; i<nInsts; ++i) { // don't try this at home! // This call creates instruments, and removes "const". // There is a significant interaction with observability. ts_->instruments_[i]->setTermStructure(const_cast<Curve*>(ts_)); } // set initial guess only if the current curve cannot be used as guess if (validCurve_) QL_ENSURE(ts_->data_.size() == nInsts+1, "dimension mismatch: expected " << nInsts+1 << ", actual " << ts_->data_.size()); else { ts_->data_ = std::vector<Rate>(nInsts+1); ts_->data_[0] = Traits::initialValue(ts_); } // calculate dates and times ts_->dates_ = std::vector<Date>(nInsts+1); ts_->times_ = std::vector<Time>(nInsts+1); ts_->dates_[0] = Traits::initialDate(ts_); ts_->times_[0] = ts_->timeFromReference(ts_->dates_[0]); for (Size i=0; i<nInsts; ++i) { ts_->dates_[i+1] = ts_->instruments_[i]->latestDate(); ts_->times_[i+1] = ts_->timeFromReference(ts_->dates_[i+1]); if (!validCurve_) ts_->data_[i+1] = ts_->data_[i]; } LevenbergMarquardt solver(ts_->accuracy_, ts_->accuracy_, ts_->accuracy_); EndCriteria endCriteria(100, 10, 0.00, ts_->accuracy_, 0.00); PositiveConstraint posConstraint; NoConstraint noConstraint; Constraint& solverConstraint = forcePositive_ ? static_cast<Constraint&>(posConstraint) : static_cast<Constraint&>(noConstraint); // now start the bootstrapping. Size iInst = localisation_-1; Size dataAdjust = Curve::interpolator_type::dataSizeAdjustment; do { Size initialDataPt = iInst+1-localisation_+dataAdjust; Array startArray(localisation_+1-dataAdjust); for (Size j = 0; j < startArray.size()-1; ++j) startArray[j] = ts_->data_[initialDataPt+j]; // here we are extending the interpolation a point at a // time... but the local interpolator can make an // approximation for the final localisation period. // e.g. if the localisation is 2, then the first section // of the curve will be solved using the first 2 // instruments... with the local interpolator making // suitable boundary conditions. ts_->interpolation_ = ts_->interpolator_.localInterpolate( ts_->times_.begin(), ts_->times_.begin()+(iInst + 2), ts_->data_.begin(), localisation_, ts_->interpolation_, nInsts+1); if (iInst >= localisation_) { startArray[localisation_-dataAdjust] = Traits::guess(iInst, ts_, false, 0); // ? } else { startArray[localisation_-dataAdjust] = ts_->data_[0]; } PenaltyFunction<Curve> currentCost( ts_, initialDataPt, ts_->instruments_.begin() + (iInst - localisation_+1), ts_->instruments_.begin() + (iInst+1)); Problem toSolve(currentCost, solverConstraint, startArray); EndCriteria::Type endType = solver.minimize(toSolve, endCriteria); // check the end criteria QL_REQUIRE(endType == EndCriteria::StationaryFunctionAccuracy || endType == EndCriteria::StationaryFunctionValue, "Unable to strip yieldcurve to required accuracy " ); ++iInst; } while ( iInst < nInsts ); validCurve_ = true; }
Real CreditDefaultSwap::couponLegNPV() const { calculate(); QL_REQUIRE(couponLegNPV_ != Null<Rate>(), "coupon-leg NPV not available"); return couponLegNPV_; }
Real CreditDefaultSwap::accrualRebateNPV() const { calculate(); QL_REQUIRE(accrualRebateNPV_ != Null<Real>(), "accrual Rebate NPV not available"); return accrualRebateNPV_; }
void BinomialVanillaEngine<T>::calculate() const { DayCounter rfdc = process_->riskFreeRate()->dayCounter(); DayCounter divdc = process_->dividendYield()->dayCounter(); DayCounter voldc = process_->blackVolatility()->dayCounter(); Calendar volcal = process_->blackVolatility()->calendar(); Real s0 = process_->stateVariable()->value(); QL_REQUIRE(s0 > 0.0, "negative or null underlying given"); Volatility v = process_->blackVolatility()->blackVol( arguments_.exercise->lastDate(), s0); Date maturityDate = arguments_.exercise->lastDate(); Rate r = process_->riskFreeRate()->zeroRate(maturityDate, rfdc, Continuous, NoFrequency); Rate q = process_->dividendYield()->zeroRate(maturityDate, divdc, Continuous, NoFrequency); Date referenceDate = process_->riskFreeRate()->referenceDate(); // binomial trees with constant coefficient Handle<YieldTermStructure> flatRiskFree( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, r, rfdc))); Handle<YieldTermStructure> flatDividends( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, q, divdc))); Handle<BlackVolTermStructure> flatVol( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(referenceDate, volcal, v, voldc))); boost::shared_ptr<PlainVanillaPayoff> payoff = boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-plain payoff given"); Time maturity = rfdc.yearFraction(referenceDate, maturityDate); boost::shared_ptr<StochasticProcess1D> bs( new GeneralizedBlackScholesProcess( process_->stateVariable(), flatDividends, flatRiskFree, flatVol)); TimeGrid grid(maturity, timeSteps_); boost::shared_ptr<T> tree(new T(bs, maturity, timeSteps_, payoff->strike())); boost::shared_ptr<BlackScholesLattice<T> > lattice( new BlackScholesLattice<T>(tree, r, maturity, timeSteps_)); DiscretizedVanillaOption option(arguments_, *process_, grid); option.initialize(lattice, maturity); // Partial derivatives calculated from various points in the // binomial tree (Odegaard) // Rollback to third-last step, and get underlying price (s2) & // option values (p2) at this point option.rollback(grid[2]); Array va2(option.values()); QL_ENSURE(va2.size() == 3, "Expect 3 nodes in grid at second step"); Real p2h = va2[2]; // high-price Real s2 = lattice->underlying(2, 2); // high price // Rollback to second-last step, and get option value (p1) at // this point option.rollback(grid[1]); Array va(option.values()); QL_ENSURE(va.size() == 2, "Expect 2 nodes in grid at first step"); Real p1 = va[1]; // Finally, rollback to t=0 option.rollback(0.0); Real p0 = option.presentValue(); Real s1 = lattice->underlying(1, 1); // Calculate partial derivatives Real delta0 = (p1-p0)/(s1-s0); // dp/ds Real delta1 = (p2h-p1)/(s2-s1); // dp/ds // Store results results_.value = p0; results_.delta = delta0; results_.gamma = 2.0*(delta1-delta0)/(s2-s0); //d(delta)/ds results_.theta = blackScholesTheta(process_, results_.value, results_.delta, results_.gamma); }
void ContinuousArithmeticAsianLevyEngine::calculate() const { QL_REQUIRE(arguments_.averageType == Average::Arithmetic, "not an Arithmetic average option"); QL_REQUIRE(arguments_.exercise->type() == Exercise::European, "not an European Option"); DayCounter rfdc = process_->riskFreeRate()->dayCounter(); DayCounter divdc = process_->dividendYield()->dayCounter(); DayCounter voldc = process_->blackVolatility()->dayCounter(); Real spot = process_->stateVariable()->value(); // payoff boost::shared_ptr<StrikedTypePayoff> payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-plain payoff given"); // original time to maturity Date maturity = arguments_.exercise->lastDate(); Time T = rfdc.yearFraction(startDate_, arguments_.exercise->lastDate()); // remaining time to maturity Time T2 = rfdc.yearFraction(process_->riskFreeRate()->referenceDate(), arguments_.exercise->lastDate()); Real strike = payoff->strike(); Volatility volatility = process_->blackVolatility()->blackVol(maturity, strike); CumulativeNormalDistribution N; Rate riskFreeRate = process_->riskFreeRate()-> zeroRate(maturity, rfdc, Continuous, NoFrequency); Rate dividendYield = process_->dividendYield()-> zeroRate(maturity, divdc, Continuous, NoFrequency); Real b = riskFreeRate - dividendYield; QL_REQUIRE(b != 0.0, "null cost of carry not allowed by Levy engine"); Real Se = (spot/(T*b))*(exp((b-riskFreeRate)*T2)-exp(-riskFreeRate*T2)); Real X; if (T2 < T) { QL_REQUIRE(!currentAverage_.empty() && currentAverage_->isValid(), "current average required"); X = strike - ((T-T2)/T)*currentAverage_->value(); } else { X = strike; } Real M = (2*spot*spot/(b+volatility*volatility)) * (((exp((2*b+volatility*volatility)*T2)-1) / (2*b+volatility*volatility))-((exp(b*T2)-1)/b)); Real D = M/(T*T); Real V = log(D)-2*(riskFreeRate*T2+log(Se)); Real d1 = (1/sqrt(V))*((log(D)/2)-log(X)); Real d2 = d1-sqrt(V); if(payoff->optionType()==Option::Call) results_.value = Se*N(d1) - X*exp(-riskFreeRate*T2)*N(d2); else results_.value = Se*N(d1) - X*exp(-riskFreeRate*T2)*N(d2) - Se + X*exp(-riskFreeRate*T2); }
void AnalyticPTDHestonEngine::calculate() const { // this is an european option pricer QL_REQUIRE(arguments_.exercise->type() == Exercise::European, "not an European option"); // plain vanilla boost::shared_ptr<PlainVanillaPayoff> payoff = boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-striked payoff given"); const Real v0 = model_->v0(); const Real spotPrice = model_->s0(); QL_REQUIRE(spotPrice > 0.0, "negative or null underlying given"); const Real strike = payoff->strike(); const Real term = model_->riskFreeRate()->dayCounter().yearFraction( model_->riskFreeRate()->referenceDate(), arguments_.exercise->lastDate()); const Real riskFreeDiscount = model_->riskFreeRate()->discount( arguments_.exercise->lastDate()); const Real dividendDiscount = model_->dividendYield()->discount( arguments_.exercise->lastDate()); //average values const TimeGrid& timeGrid = model_->timeGrid(); const Size n = timeGrid.size()-1; Real kappaAvg = 0.0, thetaAvg = 0.0, sigmaAvg=0.0, rhoAvg = 0.0; for (Size i=1; i <= n; ++i) { const Time t = 0.5*(timeGrid[i-1] + timeGrid[i]); kappaAvg += model_->kappa(t); thetaAvg += model_->theta(t); sigmaAvg += model_->sigma(t); rhoAvg += model_->rho(t); } kappaAvg/=n; thetaAvg/=n; sigmaAvg/=n; rhoAvg/=n; const Real c_inf = std::min(10.0, std::max(0.0001, std::sqrt(1.0-square<Real>()(rhoAvg))/sigmaAvg)) *(v0 + kappaAvg*thetaAvg*term); const Real p1 = integration_->calculate(c_inf, Fj_Helper(model_, this, term, strike, 1))/M_PI; const Real p2 = integration_->calculate(c_inf, Fj_Helper(model_, this, term, strike, 2))/M_PI; switch (payoff->optionType()) { case Option::Call: results_.value = spotPrice*dividendDiscount*(p1+0.5) - strike*riskFreeDiscount*(p2+0.5); break; case Option::Put: results_.value = spotPrice*dividendDiscount*(p1-0.5) - strike*riskFreeDiscount*(p2-0.5); break; default: QL_FAIL("unknown option type"); } }
void CounterpartyAdjSwapEngine::calculate() const { /* both DTS, YTS ref dates and pricing date consistency checks? settlement... */ QL_REQUIRE(!discountCurve_.empty(), "no discount term structure set"); QL_REQUIRE(!defaultTS_.empty(), "no ctpty default term structure set"); QL_REQUIRE(!swaptionletEngine_.empty(), "no swap option engine set"); Date priceDate = defaultTS_->referenceDate(); Real cumOptVal = 0., cumPutVal = 0.; // Vanilla swap so 0 leg is floater std::vector<Date>::const_iterator nextFD = arguments_.fixedPayDates.begin(); Date swapletStart = priceDate; while(*nextFD < priceDate) nextFD++; // Compute fair spread for strike value: // copy args into the non risky engine Swap::arguments * noCVAArgs = dynamic_cast<Swap::arguments*>( baseSwapEngine_->getArguments()); noCVAArgs->legs = this->arguments_.legs; noCVAArgs->payer = this->arguments_.payer; baseSwapEngine_->calculate(); Rate baseSwapRate = boost::dynamic_pointer_cast<FixedRateCoupon>( arguments_.legs[0][0])->rate(); const Swap::results * vSResults = dynamic_cast<const Swap::results *>(baseSwapEngine_->getResults()); Rate baseSwapFairRate = -baseSwapRate * vSResults->legNPV[1] / vSResults->legNPV[0]; Real baseSwapNPV = vSResults->value; VanillaSwap::Type reversedType = arguments_.type == VanillaSwap::Payer ? VanillaSwap::Receiver : VanillaSwap::Payer; // Swaplet options summatory: while(nextFD != arguments_.fixedPayDates.end()) { // iFD coupon not fixed, create swaptionlet: boost::shared_ptr<IborIndex> swapIndex = boost::dynamic_pointer_cast<IborIndex>( boost::dynamic_pointer_cast<FloatingRateCoupon>( arguments_.legs[1][0])->index()); // Alternatively one could cap this period to, say, 1M // Period swapPeriod = boost::dynamic_pointer_cast<FloatingRateCoupon>( // arguments_.legs[1][0])->index()->tenor(); Period baseSwapsTenor(arguments_.fixedPayDates.back().serialNumber() - swapletStart.serialNumber(), Days); boost::shared_ptr<VanillaSwap> swaplet = MakeVanillaSwap( baseSwapsTenor, swapIndex, baseSwapFairRate // strike ) .withType(arguments_.type) .withNominal(arguments_.nominal) //////// .withSettlementDays(2) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.back()); boost::shared_ptr<VanillaSwap> revSwaplet = MakeVanillaSwap( baseSwapsTenor, swapIndex, baseSwapFairRate // strike ) .withType(reversedType) .withNominal(arguments_.nominal) ///////// .withSettlementDays(2) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.back()); Swaption swaptionlet(swaplet, boost::make_shared<EuropeanExercise>(swapletStart)); Swaption putSwaplet(revSwaplet, boost::make_shared<EuropeanExercise>(swapletStart)); swaptionlet.setPricingEngine(swaptionletEngine_.currentLink()); putSwaplet.setPricingEngine(swaptionletEngine_.currentLink()); // atm underlying swap means that the value of put = value // call so this double pricing is not needed cumOptVal += swaptionlet.NPV() * defaultTS_->defaultProbability( swapletStart, *nextFD); cumPutVal += putSwaplet.NPV() * invstDTS_->defaultProbability( swapletStart, *nextFD); swapletStart = *nextFD; nextFD++; } results_.value = baseSwapNPV - (1.-ctptyRecoveryRate_) * cumOptVal + (1.-invstRecoveryRate_) * cumPutVal; results_.fairRate = -baseSwapRate * (vSResults->legNPV[1] - (1.-ctptyRecoveryRate_) * cumOptVal + (1.-invstRecoveryRate_) * cumPutVal ) / vSResults->legNPV[0]; }
inline Time DayCounter::yearFraction(const Date& d1, const Date& d2, const Date& refPeriodStart, const Date& refPeriodEnd) const { QL_REQUIRE(impl_, "no implementation provided"); return impl_->yearFraction(d1,d2,refPeriodStart,refPeriodEnd); }
inline BigInteger DayCounter::dayCount(const Date& d1, const Date& d2) const { QL_REQUIRE(impl_, "no implementation provided"); return impl_->dayCount(d1,d2); }
inline std::string DayCounter::name() const { QL_REQUIRE(impl_, "no implementation provided"); return impl_->name(); }
Rate CreditDefaultSwap::fairUpfront() const { calculate(); QL_REQUIRE(fairUpfront_ != Null<Rate>(), "fair upfront not available"); return fairUpfront_; }
std::vector<string> qlRateHelperSelection( const std::vector<shared_ptr<QuantLibAddin::RateHelper> >& qlarhs, const std::vector<QuantLib::Natural>& priority, QuantLib::Natural nImmFutures, QuantLib::Natural nSerialFutures, QuantLib::Natural frontFuturesRollingDays, RateHelper::DepoInclusionCriteria depoInclusionCriteria, const std::vector<QuantLib::Natural>& minDist) { // Checks QL_REQUIRE(!qlarhs.empty(), "no instrument given"); QuantLib::Size nInstruments = qlarhs.size(); QL_REQUIRE(priority.size()==nInstruments, "priority (" << priority.size() << ") / instruments (" << nInstruments << ") size mismatch"); QL_REQUIRE(minDist.size()==nInstruments || minDist.size()==1, "minDist (" << minDist.size() << ") / instruments (" << nInstruments << ") mismatch"); // RateHelperItem shared_ptr<QuantLibAddin::RateHelper> qlarh; shared_ptr<QuantLib::RateHelper> qlrh; std::vector<RateHelperItem> rhsAll; rhsAll.reserve(nInstruments); for (QuantLib::Size i=0; i<nInstruments; ++i) { qlarh = qlarhs[i]; qlarh->getLibraryObject(qlrh); string qlarh_id = convert2<string>( qlarh->propertyValue("OBJECTID")); bool isFutures = dynamic_pointer_cast<FuturesRateHelper>(qlarh); bool isImmFutures = false, isSerialFutures = false; if (isFutures) { isImmFutures = QuantLib::IMM::isIMMdate(qlrh->earliestDate()); isSerialFutures = !isImmFutures; } bool isDepo = dynamic_pointer_cast<DepositRateHelper>(qlarh); rhsAll.push_back(RateHelperItem(isImmFutures, isSerialFutures, isDepo, qlarh_id, priority[i], qlrh->earliestDate(), qlrh->latestDate(), minDist.size()==1 ? minDist[0] : minDist[i])); } // Preliminary sort of RateHelperItems according to // their latest date and priority std::sort(rhsAll.begin(), rhsAll.end(), RateHelperPrioritySorter()); // Select input rate helpers according to: // expiration, maximum number of allowed Imm and Serial Futures, Depo/Futures priorities QuantLib::Natural immFuturesCounter = 0; QuantLib::Natural serialFuturesCounter = 0; QuantLib::Date evalDate = QuantLib::Settings::instance().evaluationDate(); std::vector<RateHelperItem> rhs, rhsDepo; // Look for the front Futures, if any bool thereAreFutures = false; QuantLib::Date frontFuturesEarliestDate, frontFuturesLatestDate; if (nImmFutures>0 || nSerialFutures>0) { QuantLib::Size j=0; while (j<nInstruments) { if (nImmFutures>0 && rhsAll[j].isImmFutures && (rhsAll[j].earliestDate-frontFuturesRollingDays >= evalDate)) { thereAreFutures = true; frontFuturesEarliestDate = rhsAll[j].earliestDate; frontFuturesLatestDate = rhsAll[j].latestDate; break; } if (nSerialFutures>0 && rhsAll[j].isSerialFutures && (rhsAll[j].earliestDate-frontFuturesRollingDays >= evalDate)) { thereAreFutures = true; frontFuturesEarliestDate = rhsAll[j].earliestDate; frontFuturesLatestDate = rhsAll[j].latestDate; break; } ++j; } } // If there are NOT Futures, include all Depos if (!thereAreFutures) depoInclusionCriteria = RateHelper::AllDepos; // Start selection bool depoAfterFrontFuturesAlreadyIncluded = false; for (QuantLib::Size i=0; i<nInstruments; ++i) { if (rhsAll[i].earliestDate >= evalDate) { if (rhsAll[i].isDepo) { // Check Depo conditions switch (depoInclusionCriteria) { case RateHelper::AllDepos: // Include all depos rhs.push_back(rhsAll[i]); break; case RateHelper::DeposBeforeFirstFuturesStartDate: // Include only depos with maturity date before // the front Futures start date if (rhsAll[i].latestDate < frontFuturesEarliestDate) rhs.push_back(rhsAll[i]); break; case RateHelper::DeposBeforeFirstFuturesStartDatePlusOne: // Include only depos with maturity date before // the front Futures start date + 1 more Futures if (rhsAll[i].latestDate < frontFuturesEarliestDate) { rhs.push_back(rhsAll[i]); } else { if (depoAfterFrontFuturesAlreadyIncluded == false) { rhs.push_back(rhsAll[i]); depoAfterFrontFuturesAlreadyIncluded = true; } } break; case RateHelper::DeposBeforeFirstFuturesExpiryDate: // Include only depos with maturity date before // the front Futures expiry date if (rhsAll[i].latestDate < frontFuturesLatestDate) rhs.push_back(rhsAll[i]); break; default: QL_FAIL("unknown/illegal DepoInclusionCriteria"); } } else if (rhsAll[i].isSerialFutures) { // Check Serial Futures conditions if (serialFuturesCounter<nSerialFutures && (rhsAll[i].earliestDate-frontFuturesRollingDays >= evalDate)) { ++serialFuturesCounter; rhs.push_back(rhsAll[i]); } } else if (rhsAll[i].isImmFutures) { // Check IMM Futures conditions if (immFuturesCounter<nImmFutures && (rhsAll[i].earliestDate-frontFuturesRollingDays >= evalDate)) { ++immFuturesCounter; rhs.push_back(rhsAll[i]); } } else { // No conditions for other instruments rhs.push_back(rhsAll[i]); } } } std::vector<RateHelperItem>::iterator k; if (rhs.size()>1) { // Sort rate helpers according to their latest date and priority std::sort(rhs.begin(), rhs.end(), RateHelperPrioritySorter()); // remove RateHelpers with near latestDate k = rhs.begin(); QuantLib::Natural distance, minDistance; while (k != rhs.end()-1) { distance = static_cast<QuantLib::Natural>((k+1)->latestDate - k->latestDate); minDistance = std::max(k->minDist, (k+1)->minDist); if ( distance < minDistance) { if (k->priority <= (k+1)->priority) k = rhs.erase(k); else rhs.erase(k+1); } else ++k; } } std::vector<string> result; for (k = rhs.begin(); k != rhs.end(); ++k) result.push_back(k->objectID); return result; }
Rate CreditDefaultSwap::fairSpread() const { calculate(); QL_REQUIRE(fairSpread_ != Null<Rate>(), "fair spread not available"); return fairSpread_; }
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; }
Real CreditDefaultSwap::defaultLegNPV() const { calculate(); QL_REQUIRE(defaultLegNPV_ != Null<Rate>(), "default-leg NPV not available"); return defaultLegNPV_; }
Rate YoYInflationIndex::fixing(const Date& fixingDate, bool /*forecastTodaysFixing*/) const { Date today = Settings::instance().evaluationDate(); Date todayMinusLag = today - availabilityLag_; std::pair<Date,Date> lim = inflationPeriod(todayMinusLag, frequency_); Date lastFix = lim.first-1; Date flatMustForecastOn = lastFix+1; Date interpMustForecastOn = lastFix+1 - Period(frequency_); if (interpolated() && fixingDate >= interpMustForecastOn) { return forecastFixing(fixingDate); } if (!interpolated() && fixingDate >= flatMustForecastOn) { return forecastFixing(fixingDate); } // four cases with ratio() and interpolated() if (ratio()) { if(interpolated()){ // IS ratio, IS interpolated std::pair<Date,Date> lim = inflationPeriod(fixingDate, frequency_); Date fixMinus1Y=NullCalendar().advance(fixingDate, -1*Years, ModifiedFollowing); std::pair<Date,Date> limBef = inflationPeriod(fixMinus1Y, frequency_); Real dp= lim.second + 1 - lim.first; Real dpBef=limBef.second + 1 - limBef.first; Real dl = fixingDate-lim.first; // potentially does not work on 29th Feb Real dlBef = fixMinus1Y - limBef.first; // get the four relevant fixings // recall that they are stored flat for every day Rate limFirstFix = IndexManager::instance().getHistory(name())[lim.first]; QL_REQUIRE(limFirstFix != Null<Rate>(), "Missing " << name() << " fixing for " << lim.first ); Rate limSecondFix = IndexManager::instance().getHistory(name())[lim.second+1]; QL_REQUIRE(limSecondFix != Null<Rate>(), "Missing " << name() << " fixing for " << lim.second+1 ); Rate limBefFirstFix = IndexManager::instance().getHistory(name())[limBef.first]; QL_REQUIRE(limBefFirstFix != Null<Rate>(), "Missing " << name() << " fixing for " << limBef.first ); Rate limBefSecondFix = IndexManager::instance().getHistory(name())[limBef.second+1]; QL_REQUIRE(limBefSecondFix != Null<Rate>(), "Missing " << name() << " fixing for " << limBef.second+1 ); Real linearNow = limFirstFix + (limSecondFix-limFirstFix)*dl/dp; Real linearBef = limBefFirstFix + (limBefSecondFix-limBefFirstFix)*dlBef/dpBef; Rate wasYES = linearNow / linearBef - 1.0; return wasYES; } else { // IS ratio, NOT interpolated Rate pastFixing = IndexManager::instance().getHistory(name())[fixingDate]; QL_REQUIRE(pastFixing != Null<Rate>(), "Missing " << name() << " fixing for " << fixingDate); Date previousDate = fixingDate - 1*Years; Rate previousFixing = IndexManager::instance().getHistory(name())[previousDate]; QL_REQUIRE(previousFixing != Null<Rate>(), "Missing " << name() << " fixing for " << previousDate ); return pastFixing/previousFixing - 1.0; } } else { // NOT ratio if (interpolated()) { // NOT ratio, IS interpolated std::pair<Date,Date> lim = inflationPeriod(fixingDate, frequency_); Real dp= lim.second + 1 - lim.first; Real dl = fixingDate-lim.first; Rate limFirstFix = IndexManager::instance().getHistory(name())[lim.first]; QL_REQUIRE(limFirstFix != Null<Rate>(), "Missing " << name() << " fixing for " << lim.first ); Rate limSecondFix = IndexManager::instance().getHistory(name())[lim.second+1]; QL_REQUIRE(limSecondFix != Null<Rate>(), "Missing " << name() << " fixing for " << lim.second+1 ); Real linearNow = limFirstFix + (limSecondFix-limFirstFix)*dl/dp; return linearNow; } else { // NOT ratio, NOT interpolated // so just flat Rate pastFixing = IndexManager::instance().getHistory(name())[fixingDate]; QL_REQUIRE(pastFixing != Null<Rate>(), "Missing " << name() << " fixing for " << fixingDate); return pastFixing; } } // QL_FAIL("YoYInflationIndex::fixing, should never get here"); }
Real CreditDefaultSwap::upfrontPV01() const { calculate(); QL_REQUIRE(upfrontPV01_ != Null<Real>(), "upfront PV01 not available"); return upfrontPV01_; }
inline Real GeneralStatistics::max() const { QL_REQUIRE(samples() > 0, "empty sample set"); return std::max_element(samples_.begin(), samples_.end())->first; }
bool Date::isLeap(Year y) { static const bool YearIsLeap[] = { // 1900 is leap in agreement with Excel's bug // 1900 is out of valid date range anyway // 1900-1909 true,false,false,false, true,false,false,false, true,false, // 1910-1919 false,false, true,false,false,false, true,false,false,false, // 1920-1929 true,false,false,false, true,false,false,false, true,false, // 1930-1939 false,false, true,false,false,false, true,false,false,false, // 1940-1949 true,false,false,false, true,false,false,false, true,false, // 1950-1959 false,false, true,false,false,false, true,false,false,false, // 1960-1969 true,false,false,false, true,false,false,false, true,false, // 1970-1979 false,false, true,false,false,false, true,false,false,false, // 1980-1989 true,false,false,false, true,false,false,false, true,false, // 1990-1999 false,false, true,false,false,false, true,false,false,false, // 2000-2009 true,false,false,false, true,false,false,false, true,false, // 2010-2019 false,false, true,false,false,false, true,false,false,false, // 2020-2029 true,false,false,false, true,false,false,false, true,false, // 2030-2039 false,false, true,false,false,false, true,false,false,false, // 2040-2049 true,false,false,false, true,false,false,false, true,false, // 2050-2059 false,false, true,false,false,false, true,false,false,false, // 2060-2069 true,false,false,false, true,false,false,false, true,false, // 2070-2079 false,false, true,false,false,false, true,false,false,false, // 2080-2089 true,false,false,false, true,false,false,false, true,false, // 2090-2099 false,false, true,false,false,false, true,false,false,false, // 2100-2109 false,false,false,false, true,false,false,false, true,false, // 2110-2119 false,false, true,false,false,false, true,false,false,false, // 2120-2129 true,false,false,false, true,false,false,false, true,false, // 2130-2139 false,false, true,false,false,false, true,false,false,false, // 2140-2149 true,false,false,false, true,false,false,false, true,false, // 2150-2159 false,false, true,false,false,false, true,false,false,false, // 2160-2169 true,false,false,false, true,false,false,false, true,false, // 2170-2179 false,false, true,false,false,false, true,false,false,false, // 2180-2189 true,false,false,false, true,false,false,false, true,false, // 2190-2199 false,false, true,false,false,false, true,false,false,false, // 2200 false }; QL_REQUIRE(y>=1900 && y<=2200, "year outside valid range"); return YearIsLeap[y-1900]; }
void BinomialBarrierEngine<T,D>::calculate() const { DayCounter rfdc = process_->riskFreeRate()->dayCounter(); DayCounter divdc = process_->dividendYield()->dayCounter(); DayCounter voldc = process_->blackVolatility()->dayCounter(); Calendar volcal = process_->blackVolatility()->calendar(); Real s0 = process_->stateVariable()->value(); QL_REQUIRE(s0 > 0.0, "negative or null underlying given"); Volatility v = process_->blackVolatility()->blackVol( arguments_.exercise->lastDate(), s0); Date maturityDate = arguments_.exercise->lastDate(); Rate r = process_->riskFreeRate()->zeroRate(maturityDate, rfdc, Continuous, NoFrequency); Rate q = process_->dividendYield()->zeroRate(maturityDate, divdc, Continuous, NoFrequency); Date referenceDate = process_->riskFreeRate()->referenceDate(); // binomial trees with constant coefficient Handle<YieldTermStructure> flatRiskFree( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, r, rfdc))); Handle<YieldTermStructure> flatDividends( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, q, divdc))); Handle<BlackVolTermStructure> flatVol( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(referenceDate, volcal, v, voldc))); boost::shared_ptr<StrikedTypePayoff> payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-striked payoff given"); Time maturity = rfdc.yearFraction(referenceDate, maturityDate); boost::shared_ptr<StochasticProcess1D> bs( new GeneralizedBlackScholesProcess( process_->stateVariable(), flatDividends, flatRiskFree, flatVol)); // correct timesteps to ensure a (local) minimum, using Boyle and Lau // approach. See Journal of Derivatives, 1/1994, // "Bumping up against the barrier with the binomial method" // Note: this approach works only for CoxRossRubinstein lattices, so // is disabled if T is not a CoxRossRubinstein or derived from it. Size optimum_steps = timeSteps_; if (boost::is_base_of<CoxRossRubinstein, T>::value && maxTimeSteps_ > timeSteps_ && s0 > 0 && arguments_.barrier > 0) { Real divisor; if (s0 > arguments_.barrier) divisor = std::pow(std::log(s0 / arguments_.barrier), 2); else divisor = std::pow(std::log(arguments_.barrier / s0), 2); if (!close(divisor,0)) { for (Size i=1; i < timeSteps_ ; ++i) { Size optimum = Size(( i*i * v*v * maturity) / divisor); if (timeSteps_ < optimum) { optimum_steps = optimum; break; // found first minimum with iterations>=timesteps } } } if (optimum_steps > maxTimeSteps_) optimum_steps = maxTimeSteps_; // too high, limit } TimeGrid grid(maturity, optimum_steps); boost::shared_ptr<T> tree(new T(bs, maturity, optimum_steps, payoff->strike())); boost::shared_ptr<BlackScholesLattice<T> > lattice( new BlackScholesLattice<T>(tree, r, maturity, optimum_steps)); D option(arguments_, *process_, grid); option.initialize(lattice, maturity); // Partial derivatives calculated from various points in the // binomial tree // (see J.C.Hull, "Options, Futures and other derivatives", 6th edition, pp 397/398) // Rollback to third-last step, and get underlying prices (s2) & // option values (p2) at this point option.rollback(grid[2]); Array va2(option.values()); QL_ENSURE(va2.size() == 3, "Expect 3 nodes in grid at second step"); Real p2u = va2[2]; // up Real p2m = va2[1]; // mid Real p2d = va2[0]; // down (low) Real s2u = lattice->underlying(2, 2); // up price Real s2m = lattice->underlying(2, 1); // middle price Real s2d = lattice->underlying(2, 0); // down (low) price // calculate gamma by taking the first derivate of the two deltas Real delta2u = (p2u - p2m)/(s2u-s2m); Real delta2d = (p2m-p2d)/(s2m-s2d); Real gamma = (delta2u - delta2d) / ((s2u-s2d)/2); // Rollback to second-last step, and get option values (p1) at // this point option.rollback(grid[1]); Array va(option.values()); QL_ENSURE(va.size() == 2, "Expect 2 nodes in grid at first step"); Real p1u = va[1]; Real p1d = va[0]; Real s1u = lattice->underlying(1, 1); // up (high) price Real s1d = lattice->underlying(1, 0); // down (low) price Real delta = (p1u - p1d) / (s1u - s1d); // Finally, rollback to t=0 option.rollback(0.0); Real p0 = option.presentValue(); // Store results results_.value = p0; results_.delta = delta; results_.gamma = gamma; // theta can be approximated by calculating the numerical derivative // between mid value at third-last step and at t0. The underlying price // is the same, only time varies. results_.theta = (p2m - p0) / grid[2]; }