Real blackFormulaImpliedStdDev(Option::Type optionType, Real strike, Real forward, Real blackPrice, Real discount, Real displacement, Real guess, Real accuracy, Natural maxIterations) { checkParameters(strike, forward, displacement); QL_REQUIRE(discount>0.0, "discount (" << discount << ") must be positive"); QL_REQUIRE(blackPrice>=0.0, "option price (" << blackPrice << ") must be non-negative"); // check the price of the "other" option implied by put-call paity Real otherOptionPrice = blackPrice - optionType*(forward-strike)*discount; QL_REQUIRE(otherOptionPrice>=0.0, "negative " << Option::Type(-1*optionType) << " price (" << otherOptionPrice << ") implied by put-call parity. No solution exists for " << optionType << " strike " << strike << ", forward " << forward << ", price " << blackPrice << ", deflator " << discount); // solve for the out-of-the-money option which has // greater vega/price ratio, i.e. // it is numerically more robust for implied vol calculations if (optionType==Option::Put && strike>forward) { optionType = Option::Call; blackPrice = otherOptionPrice; } if (optionType==Option::Call && strike<forward) { optionType = Option::Put; blackPrice = otherOptionPrice; } strike = strike + displacement; forward = forward + displacement; if (guess==Null<Real>()) guess = blackFormulaImpliedStdDevApproximation( optionType, strike, forward, blackPrice, discount, displacement); else QL_REQUIRE(guess>=0.0, "stdDev guess (" << guess << ") must be non-negative"); BlackImpliedStdDevHelper f(optionType, strike, forward, blackPrice/discount); NewtonSafe solver; solver.setMaxEvaluations(maxIterations); Real minSdtDev = 0.0, maxStdDev = 24.0; // 24 = 300% * sqrt(60) Real stdDev = solver.solve(f, accuracy, guess, minSdtDev, maxStdDev); QL_ENSURE(stdDev>=0.0, "stdDev (" << stdDev << ") must be non-negative"); return stdDev; }
boost::shared_ptr<SmileSection> Gaussian1dSwaptionVolatility::smileSectionImpl(Time optionTime, Time swapLength) const { DateHelper hlp(*this, optionTime); NewtonSafe newton; Date d(static_cast<BigInteger>(newton.solve( hlp, 0.1, 365.25 * optionTime + static_cast<Real>(referenceDate().serialNumber()), 1.0))); Period tenor( static_cast<Integer>(Rounding(0).operator()(swapLength * 12.0)), Months); d = indexBase_->fixingCalendar().adjust(d); return smileSectionImpl(d, tenor); }
Volatility CapFloor::impliedVolatility(Real targetValue, const Handle<YieldTermStructure>& d, Volatility guess, Real accuracy, Natural maxEvaluations, Volatility minVol, Volatility maxVol) const { //calculate(); QL_REQUIRE(!isExpired(), "instrument expired"); ImpliedVolHelper f(*this, d, targetValue); //Brent solver; NewtonSafe solver; solver.setMaxEvaluations(maxEvaluations); return solver.solve(f, accuracy, guess, minVol, maxVol); }
Real solveImpl(const F& f, Real xAccuracy) const { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ Real froot, dfroot, dx; froot = f(root_); dfroot = f.derivative(root_); QL_REQUIRE(dfroot != Null<Real>(), "Newton requires function's derivative"); ++evaluationNumber_; while (evaluationNumber_<=maxEvaluations_) { dx = froot/dfroot; root_ -= dx; // jumped out of brackets, switch to NewtonSafe if ((xMin_-root_)*(root_-xMax_) < 0.0) { NewtonSafe s; s.setMaxEvaluations(maxEvaluations_-evaluationNumber_); return s.solve(f, xAccuracy, root_+dx, xMin_, xMax_); } if (std::fabs(dx) < xAccuracy) { f(root_); ++evaluationNumber_; return root_; } froot = f(root_); dfroot = f.derivative(root_); ++evaluationNumber_; } QL_FAIL("maximum number of function evaluations (" << maxEvaluations_ << ") exceeded"); }
boost::shared_ptr<SmileSection> SingleSabrSwaptionVolatility::smileSectionImpl(Time optionTime, Time swapLength) const { std::vector<Real> params(4); params[0] = alpha_; params[1] = beta_; params[2] = nu_; params[3] = rho_; DateHelper hlp(*this,optionTime); NewtonSafe newton; Date d(static_cast<BigInteger>(newton.solve( hlp, 0.1, 365.25 * optionTime + static_cast<Real>(referenceDate().serialNumber()), 1.0))); Period tenor(static_cast<Integer>(Rounding(0).operator()(swapLength*12.0)), Months); d = indexBase_->fixingCalendar().adjust(d); Real forward = indexBase_->clone(tenor)->fixing(d); boost::shared_ptr<SmileSection> raw(new SabrSmileSection(optionTime,forward,params,shift_)); // make it arbitrage free //boost::shared_ptr<SmileSection> af(new KahaleSmileSection(raw)); //return af; return raw; }