Esempio n. 1
0
    Real LinearTsrPricer::strikeFromVegaRatio(Real ratio,
                                              Option::Type optionType,
                                              Real referenceStrike) const {

        Real a, b, min, max, k;
        if (optionType == Option::Call) {
            a = swapRateValue_;
            min = referenceStrike;
            b = max = k =
                std::min(smileSection_->maxStrike(), adjustedUpperBound_);
        } else {
            a = min = k =
                std::max(smileSection_->minStrike(), adjustedLowerBound_);
            b = swapRateValue_;
            max = referenceStrike;
        }

        VegaRatioHelper h(&*smileSection_,
                          smileSection_->vega(swapRateValue_) * ratio);
        Brent solver;

        try {
            k = solver.solve(h, 1.0E-5, (a + b) / 2.0, a, b);
        }
        catch (...) {
            // use default value set above
        }

        return std::min(std::max(k, min), max);
    }
Esempio n. 2
0
    Spread CallableBond::OAS(Real cleanPrice,
                             const Handle<YieldTermStructure>& engineTS,
                             const DayCounter& dayCounter,
                             Compounding compounding,
                             Frequency frequency,
                             Date settlement,
                             Real accuracy,
                             Size maxIterations,
                             Spread guess)
    {
        if (settlement == Date())
            settlement = settlementDate();

        Real dirtyPrice = cleanPrice + accruedAmount(settlement);

        boost::function<Real(Real)> f = NPVSpreadHelper(*this);
        OASHelper obj(f, dirtyPrice);

        Brent solver;
        solver.setMaxEvaluations(maxIterations);

        Real step = 0.001;
        Spread oas=solver.solve(obj, accuracy, guess, step);

        return continuousToConv(oas,
                                *this,
                                engineTS,
                                dayCounter,
                                compounding,
                                frequency);
    }
Esempio n. 3
0
    Real LinearTsrPricer::strikeFromPrice(Real price, Option::Type optionType,
                                          Real referenceStrike) const {

        Real a, b, min, max, k;
        if (optionType == Option::Call) {
            a = swapRateValue_;
            min = referenceStrike;
            b = max = k =
                std::min(smileSection_->maxStrike(), settings_.upperRateBound_);
        } else {
            a = min = k =
                std::max(smileSection_->minStrike(), settings_.lowerRateBound_);
            b = swapRateValue_;
            max = referenceStrike;
        }

        PriceHelper h(&*smileSection_, optionType, price);
        Brent solver;

        try {
            k = solver.solve(h, 1.0E-5, swapRateValue_, a, b);
        }
        catch (...) {
            // use default value set above
        }

        return std::min(std::max(k, min), max);
    }
    Volatility CalibrationHelper::impliedVolatility(Real targetValue,
                                                    Real accuracy,
                                                    Size maxEvaluations,
                                                    Volatility minVol,
                                                    Volatility maxVol) const {

        ImpliedVolatilityHelper f(*this,targetValue);
        Brent solver;
        solver.setMaxEvaluations(maxEvaluations);
        return solver.solve(f,accuracy,volatility_->value(),minVol,maxVol);
    }
	double Gamma2Distribution::cumulativeInv(const double p, const bool fast, const long bins) {
			if(fast) {
				if(!fastCalculated_ || bins!=fastBins_) {
					fastBins_=bins;
					preCalculateCumulativeInv();
				}
				return fastCumulativeInv(p);
			}
			G2InvHelper hlp(this,p);
			Brent b;
			return b.solve(hlp,INVG2ACC,1.0,0.1);
	}
std::vector<Volatility> OptionletStripper2::spreadsVolImplied() const {

    Brent solver;
    std::vector<Volatility> result(nOptionExpiries_);
    Volatility guess = 0.0001, minSpread = -0.1, maxSpread = 0.1;
    for (Size j=0; j<nOptionExpiries_; ++j) {
        ObjectiveFunction f(stripper1_, caps_[j], atmCapFloorPrices_[j]);
        solver.setMaxEvaluations(maxEvaluations_);
        Volatility root = solver.solve(f, accuracy_, guess,
                                       minSpread, maxSpread);
        result[j] = root;
    }
    return result;
}
Esempio n. 7
0
 Volatility CallableBond::impliedVolatility(
                           Real targetValue,
                           const Handle<YieldTermStructure>& discountCurve,
                           Real accuracy,
                           Size maxEvaluations,
                           Volatility minVol,
                           Volatility maxVol) const {
     calculate();
     QL_REQUIRE(!isExpired(), "instrument expired");
     Volatility guess = 0.5*(minVol + maxVol);
     blackDiscountCurve_.linkTo(*discountCurve, false);
     ImpliedVolHelper f(*this,targetValue);
     Brent solver;
     solver.setMaxEvaluations(maxEvaluations);
     return solver.solve(f, accuracy, guess, minVol, maxVol);
 }
Esempio n. 8
0
    Volatility HestonBlackVolSurface::blackVolImpl(Time t, Real strike) const {
        const boost::shared_ptr<HestonProcess> process = hestonModel_->process();

        const DiscountFactor df = process->riskFreeRate()->discount(t, true);
        const DiscountFactor div = process->dividendYield()->discount(t, true);
        const Real spotPrice = process->s0()->value();

        const Real fwd = spotPrice
            * process->dividendYield()->discount(t, true)
            / process->riskFreeRate()->discount(t, true);


        const PlainVanillaPayoff payoff(
            fwd > strike ? Option::Put : Option::Call, strike);

        const Real kappa = hestonModel_->kappa();
        const Real theta = hestonModel_->theta();
        const Real rho   = hestonModel_->rho();
        const Real sigma = hestonModel_->sigma();
        const Real v0    = hestonModel_->v0();

        const AnalyticHestonEngine::ComplexLogFormula cpxLogFormula
            = AnalyticHestonEngine::Gatheral;

        const AnalyticHestonEngine* const hestonEnginePtr = 0;

        Real npv;
        Size evaluations;

        AnalyticHestonEngine::doCalculation(
            df, div, spotPrice, strike, t,
            kappa, theta, sigma, v0, rho,
            payoff, integration_, cpxLogFormula,
            hestonEnginePtr, npv, evaluations);

        if (npv <= 0.0) return std::sqrt(theta);

        Brent solver;
        solver.setMaxEvaluations(10000);
        const Volatility guess = std::sqrt(theta);
        const Real accuracy = std::numeric_limits<Real>::epsilon();

        const boost::function<Real(Real)> f = boost::bind(
            &blackValue, payoff.optionType(), strike, fwd, t, _1, df, npv);

        return solver.solve(f, accuracy, guess, 0.01);
    }
    Real InverseNonCentralChiSquareDistribution::operator()(Real x) const {

        // first find the right side of the interval
        Real upper = guess_;
        Size evaluations = maxEvaluations_;
        while (nonCentralDist_(upper) < x && evaluations > 0) {
            upper*=2.0;
            --evaluations;
        }

        // use a brent solver for the rest
        Brent solver;
        solver.setMaxEvaluations(evaluations);
        return solver.solve(compose(std::bind2nd(std::minus<Real>(),x), 
                                    nonCentralDist_),
                            accuracy_, 0.75*upper, 
                            (evaluations == maxEvaluations_)? 0.0: 0.5*upper,
                            upper);
    }
Esempio n. 10
0
    Volatility CdsOption::impliedVolatility(
                   Real targetValue,
                   const Handle<YieldTermStructure>& termStructure,
                   const Handle<DefaultProbabilityTermStructure>& probability,
                   Real recoveryRate,
                   Real accuracy,
                   Size maxEvaluations,
                   Volatility minVol,
                   Volatility maxVol) const {
        calculate();
        QL_REQUIRE(!isExpired(), "instrument expired");

        Volatility guess = 0.10;

        ImpliedVolHelper f(*this, probability, recoveryRate,
                           termStructure, targetValue);
        Brent solver;
        solver.setMaxEvaluations(maxEvaluations);
        return solver.solve(f, accuracy, guess, minVol, maxVol);
    }
Esempio n. 11
0
        Volatility ImpliedVolatilityHelper::calculate(
                                                 const Instrument& instrument,
                                                 const PricingEngine& engine,
                                                 SimpleQuote& volQuote,
                                                 Real targetValue,
                                                 Real accuracy,
                                                 Natural maxEvaluations,
                                                 Volatility minVol,
                                                 Volatility maxVol) {

            instrument.setupArguments(engine.getArguments());
            engine.getArguments()->validate();

            PriceError f(engine, volQuote, targetValue);
            Brent solver;
            solver.setMaxEvaluations(maxEvaluations);
            Volatility guess = (minVol+maxVol)/2.0;
            Volatility result = solver.solve(f, accuracy, guess,
                                             minVol, maxVol);
            return result;
        }
Esempio n. 12
0
	Real CmsSpreadOption::impliedCorrelation(boost::shared_ptr<CmsPricer> pricer,const Period& pillar, const double price,Size preCalculatedFixings,double preCalculatedPrice) {
		Brent b;
		double res=b.solve(CmsSpreadOptionImplCorrHelper(this,pricer,pillar,price,preCalculatedFixings,preCalculatedPrice),CORRACC,pricer->correlationTermStructure()->correlation(pillar,true),CORRSTEP);
		double res2=atan(res)*2.0/M_PI;
		pricer->correlationTermStructure()->setPillarCorrelation(pillar,res2);
		return res2;
		/*CmsSpreadOptionImplCorrHelper h(boost::shared_ptr<CmsSpreadOption>(this),pricer,pillar,price);
		double x1=-MAXCORR,x2=MAXCORR,x;
		double f1=h(x1);
		double f2=h(x2);
		double f;
		double step=MAXCORR+MAXCORR;
		if(f1*f2>=0.0) QL_FAIL("No sign change for correlations -1,1");
		do {
			x=(x1+x2)/2.0;
			f=h(x);
			if(f1*f<0.0) x2=x; else x1=x;
			step/=step;
			pricer->correlationTermStructure()->setPillarCorrelation(pillar,x);
		} while(step>CORRACC);
		pricer->correlationTermStructure()->setPillarCorrelation(pillar,x);
		return x;*/
	}
    void IterativeBootstrap<Curve>::calculate() const {

        Size n = 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<n; ++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<n; ++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<n; ++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_));
        }

        // calculate dates and times
        ts_->dates_ = std::vector<Date>(n+1);
        ts_->times_ = std::vector<Time>(n+1);
        ts_->dates_[0] = Traits::initialDate(ts_);
        ts_->times_[0] = ts_->timeFromReference(ts_->dates_[0]);
        for (Size i=0; i<n; ++i) {
            ts_->dates_[i+1] = ts_->instruments_[i]->latestDate();
            ts_->times_[i+1] = ts_->timeFromReference(ts_->dates_[i+1]);
        }

        // set initial guess only if the current curve cannot be used as guess
        if (validCurve_) {
            QL_ENSURE(ts_->data_.size() == n+1,
                      "dimension mismatch: expected " << n+1 <<
                      ", actual " << ts_->data_.size());
        } else {
            ts_->data_ = std::vector<Rate>(n+1);
            ts_->data_[0] = Traits::initialValue(ts_);
            for (Size i=0; i<n; ++i)
                ts_->data_[i+1] = Traits::initialGuess();
        }

        Brent solver;
        Size maxIterations = Traits::maxIterations();

        for (Size iteration=0; ; ++iteration) {
            std::vector<Rate> previousData = ts_->data_;
            // restart from the previous interpolation
            if (validCurve_) {
                ts_->interpolation_ = ts_->interpolator_.interpolate(
                                                      ts_->times_.begin(),
                                                      ts_->times_.end(),
                                                      ts_->data_.begin());
            }
            for (Size i=1; i<n+1; ++i) {

                // calculate guess before extending interpolation
                // to ensure that any extrapolation is performed
                // using the curve bootstrapped so far and no more
                boost::shared_ptr<typename Traits::helper> instrument =
                    ts_->instruments_[i-1];
                Rate guess = 0.0;
                if (validCurve_ || iteration>0) {
                    guess = ts_->data_[i];
                } else if (i==1) {
                    guess = Traits::initialGuess();
                } else {
                    // most traits extrapolate
                    guess = Traits::guess(ts_, ts_->dates_[i]);
                }

                // bracket
                Real min = Traits::minValueAfter(i, ts_->data_);
                Real max = Traits::maxValueAfter(i, ts_->data_);
                if (guess<=min || guess>=max)
                    guess = (min+max)/2.0;

                if (!validCurve_ && iteration == 0) {
                    // extend interpolation a point at a time
                    try {
                        ts_->interpolation_ = ts_->interpolator_.interpolate(
                                                      ts_->times_.begin(),
                                                      ts_->times_.begin()+i+1,
                                                      ts_->data_.begin());
                    } catch(...) {
                        if (!Interpolator::global)
                            throw; // no chance to fix it in a later iteration

                        // otherwise, if the target interpolation is
                        // not usable yet
                        ts_->interpolation_ = Linear().interpolate(
                                                      ts_->times_.begin(),
                                                      ts_->times_.begin()+i+1,
                                                      ts_->data_.begin());
                    }
                }
                // required because we just changed the data
                // is it really required?
                ts_->interpolation_.update();

                try {
                    BootstrapError<Curve> error(ts_, instrument, i);
                    Real r = solver.solve(error,ts_->accuracy_,guess,min,max);
                    // redundant assignment (as it has been already performed
                    // by BootstrapError in solve procedure), but safe
                    ts_->data_[i] = r;
                } catch (std::exception &e) {
                    validCurve_ = false;
                    QL_FAIL(io::ordinal(iteration+1) << " iteration: "
                            "failed at " << io::ordinal(i) << " instrument"
                            ", maturity " << ts_->dates_[i] <<
                            ", reference date " << ts_->dates_[0] <<
                            ": " << e.what());
                }
            }

            if (!Interpolator::global)
                break;      // no need for convergence loop
            else if (!validCurve_ && iteration == 0) {
                // ensure the target interpolation is used
                ts_->interpolation_ =
                    ts_->interpolator_.interpolate(ts_->times_.begin(),
                                                   ts_->times_.end(),
                                                   ts_->data_.begin());
                // at least one more iteration is needed to check convergence
                continue;
            }

            // exit conditions
            Real improvement = 0.0;
            for (Size i=1; i<n+1; ++i)
                improvement=std::max(improvement,
                                     std::fabs(ts_->data_[i]-previousData[i]));
            if (improvement<=ts_->accuracy_)  // convergence reached
                break;

            QL_REQUIRE(iteration+1 < maxIterations,
                       "convergence not reached after " <<
                       iteration+1 << " iterations; last improvement " <<
                       improvement << ", required accuracy " <<
                       ts_->accuracy_);
        }
        validCurve_ = true;
    }
    void InterpolatedYoYOptionletStripper<Interpolator1D>::
    initialize(const boost::shared_ptr<YoYCapFloorTermPriceSurface> &s,
               const boost::shared_ptr<YoYInflationCapFloorEngine> &p,
               const Real slope) const {
        YoYCapFloorTermPriceSurface_ = s;
        p_ = p;
        lag_ = YoYCapFloorTermPriceSurface_->observationLag();
        frequency_ = YoYCapFloorTermPriceSurface_->frequency();
        indexIsInterpolated_ = YoYCapFloorTermPriceSurface_->indexIsInterpolated();
        Natural fixingDays_ = YoYCapFloorTermPriceSurface_->fixingDays();
        Natural settlementDays = 0; // always
        Calendar cal = YoYCapFloorTermPriceSurface_->calendar();
        BusinessDayConvention bdc =
            YoYCapFloorTermPriceSurface_->businessDayConvention();
        DayCounter dc = YoYCapFloorTermPriceSurface_->dayCounter();

        // switch from caps to floors when out of floors
        Rate maxFloor = YoYCapFloorTermPriceSurface_->floorStrikes().back();
        YoYInflationCapFloor::Type useType = YoYInflationCapFloor::Floor;
        Period TPmin = YoYCapFloorTermPriceSurface_->maturities().front();
        // create a "fake index" based on Generic, this should work
        // provided that the lag and frequency are correct
        RelinkableHandle<YoYInflationTermStructure> hYoY(
                                       YoYCapFloorTermPriceSurface_->YoYTS());
        boost::shared_ptr<YoYInflationIndex> anIndex(
                                           new YYGenericCPI(frequency_, false,
                                                            false, lag_,
                                                            Currency(), hYoY));

        // strip each K separatly
        for (Size i=0; i<YoYCapFloorTermPriceSurface_->strikes().size(); i++) {
            Rate K = YoYCapFloorTermPriceSurface_->strikes()[i];
            if (K > maxFloor) useType = YoYInflationCapFloor::Cap;

            // solve for the initial point on the vol curve
            Brent solver;
            Real solverTolerance_ = 1e-7;
             // these are VOLATILITY guesses (always +)
            Real lo = 0.00001, hi = 0.08;
            Real guess = (hi+lo)/2.0;
            Real found;
            Real priceToMatch =
                (useType == YoYInflationCapFloor::Cap ?
                 YoYCapFloorTermPriceSurface_->capPrice(TPmin, K) :
                 YoYCapFloorTermPriceSurface_->floorPrice(TPmin, K));

            try{
                found = solver.solve(
                      ObjectiveFunction(useType, slope, K, lag_, fixingDays_,
                                        anIndex, YoYCapFloorTermPriceSurface_,
                                        p_, priceToMatch),
                      solverTolerance_, guess, lo, hi );
            } catch( std::exception &e) {
                QL_FAIL("failed to find solution here because: " << e.what());
            }

            // ***create helpers***
            Real notional = 10000; // work in bps
            std::vector<boost::shared_ptr<BootstrapHelper<YoYOptionletVolatilitySurface> > > helperInstruments;
            std::vector<boost::shared_ptr<YoYOptionletHelper> > helpers;
            for (Size j = 0; j < YoYCapFloorTermPriceSurface_->maturities().size(); j++){
                Period Tp = YoYCapFloorTermPriceSurface_->maturities()[j];

                Real nextPrice =
                    (useType == YoYInflationCapFloor::Cap ?
                     YoYCapFloorTermPriceSurface_->capPrice(Tp, K) :
                     YoYCapFloorTermPriceSurface_->floorPrice(Tp, K));

                Handle<Quote> quote1(boost::shared_ptr<Quote>(
                                               new SimpleQuote( nextPrice )));
                // helper should be an integer number of periods away,
                // this is enforced by rounding
                Size nT = (Size)floor(s->timeFromReference(s->yoyOptionDateFromTenor(Tp))+0.5);
                helpers.push_back(boost::shared_ptr<YoYOptionletHelper>(
                          new YoYOptionletHelper(quote1, notional, useType,
                                                 lag_,
                                                 dc, cal,
                                                 fixingDays_,
                                                 anIndex, K, nT, p_)));

                boost::shared_ptr<ConstantYoYOptionletVolatility> yoyVolBLACK(
                          new ConstantYoYOptionletVolatility(found, settlementDays,
                                                             cal, bdc, dc,
                                                             lag_, frequency_,
                                                             false,
                                                             // -100% to +300%
                                                             -1.0,3.0));

                helpers[j]->setTermStructure(
                       // gets underlying pointer & removes const
                       const_cast<ConstantYoYOptionletVolatility*>(
                                                          yoyVolBLACK.get()));
                helperInstruments.push_back(helpers[j]);
            }
            // ***bootstrap***
            // this is the artificial vol at zero so that first section works
            Real Tmin = s->timeFromReference(s->yoyOptionDateFromTenor(TPmin));
            Volatility baseYoYVolatility = found - slope * Tmin * found;
            Rate eps = std::max(K, 0.02) / 1000.0;
            Rate minStrike = K-eps;
            Rate maxStrike = K+eps;
            boost::shared_ptr<
                PiecewiseYoYOptionletVolatilityCurve<Interpolator1D> > testPW(
                new PiecewiseYoYOptionletVolatilityCurve<Interpolator1D>(
                                            settlementDays, cal, bdc, dc, lag_,
                                            frequency_, indexIsInterpolated_,
                                            minStrike, maxStrike,
                                            baseYoYVolatility,
                                            helperInstruments) );
            testPW->recalculate();
            volCurves_.push_back(testPW);
        }
    }
Esempio n. 15
0
NoArbSabrModel::NoArbSabrModel(const Real expiryTime, const Real forward,
                               const Real alpha, const Real beta, const Real nu,
                               const Real rho)
    : expiryTime_(expiryTime), externalForward_(forward), alpha_(alpha),
      beta_(beta), nu_(nu), rho_(rho), forward_(forward),
      numericalForward_(forward) {

    using namespace ext::placeholders;

    QL_REQUIRE(expiryTime > 0.0 && expiryTime <= detail::NoArbSabrModel::expiryTime_max,
               "expiryTime (" << expiryTime << ") out of bounds");
    QL_REQUIRE(forward > 0.0, "forward (" << forward << ") must be positive");
    QL_REQUIRE(beta >= detail::NoArbSabrModel::beta_min && beta <= detail::NoArbSabrModel::beta_max,
               "beta (" << beta << ") out of bounds");
    Real sigmaI = alpha * std::pow(forward, beta - 1.0);
    QL_REQUIRE(sigmaI >= detail::NoArbSabrModel::sigmaI_min &&
                   sigmaI <= detail::NoArbSabrModel::sigmaI_max,
               "sigmaI = alpha*forward^(beta-1.0) ("
                   << sigmaI << ") out of bounds, alpha=" << alpha
                   << " beta=" << beta << " forward=" << forward);
    QL_REQUIRE(nu >= detail::NoArbSabrModel::nu_min && nu <= detail::NoArbSabrModel::nu_max,
               "nu (" << nu << ") out of bounds");
    QL_REQUIRE(rho >= detail::NoArbSabrModel::rho_min && rho <= detail::NoArbSabrModel::rho_max,
               "rho (" << rho << ") out of bounds");

    // determine a region sufficient for integration in the normal case

    fmin_ = fmax_ = forward_;
    for (Real tmp = p(fmax_);
         tmp > std::max(detail::NoArbSabrModel::i_accuracy / std::max(1.0, fmax_ - fmin_),
                        detail::NoArbSabrModel::density_threshold);
         tmp = p(fmax_)) {
        fmax_ *= 2.0;
    }
    for (Real tmp = p(fmin_);
         tmp > std::max(detail::NoArbSabrModel::i_accuracy / std::max(1.0, fmax_ - fmin_),
                        detail::NoArbSabrModel::density_threshold);
         tmp = p(fmin_)) {
        fmin_ *= 0.5;
    }
    fmin_ = std::max(detail::NoArbSabrModel::strike_min, fmin_);

    QL_REQUIRE(fmax_ > fmin_, "could not find a reasonable integration domain");

    integrator_ =
        ext::make_shared<GaussLobattoIntegral>(
            detail::NoArbSabrModel::i_max_iterations, detail::NoArbSabrModel::i_accuracy);

    detail::D0Interpolator d0(forward_, expiryTime_, alpha_, beta_, nu_, rho_);
    absProb_ = d0();

    try {
        Brent b;
        Real start = std::sqrt(externalForward_ - detail::NoArbSabrModel::strike_min);
        Real tmp =
            b.solve(ext::bind(&NoArbSabrModel::forwardError, this, _1),
                    detail::NoArbSabrModel::forward_accuracy, start,
                    std::min(detail::NoArbSabrModel::forward_search_step, start / 2.0));
        forward_ = tmp * tmp + detail::NoArbSabrModel::strike_min;
    } catch (Error&) {
        // fall back to unadjusted forward
        forward_ = externalForward_;
    }

    Real d = forwardError(std::sqrt(forward_ - detail::NoArbSabrModel::strike_min));
    numericalForward_ = d + externalForward_;
}
Esempio n. 16
0
    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_ << ")");


    }
    CapPseudoDerivative::CapPseudoDerivative(boost::shared_ptr<MarketModel> inputModel,
        Real strike,
        Size startIndex,
        Size endIndex, Real firstDF) : firstDF_(firstDF)
    {
        QL_REQUIRE(startIndex < endIndex, "for a cap pseudo derivative the start of the cap must be before the end");
        QL_REQUIRE( endIndex <= inputModel->numberOfRates(), "for a cap pseudo derivative the end of the cap must before the end of the rates");

        Size numberCaplets = endIndex-startIndex;
        Size numberRates = inputModel->numberOfRates();
        Size factors = inputModel->numberOfFactors();
        LMMCurveState curve(inputModel->evolution().rateTimes());
        curve.setOnForwardRates(inputModel->initialRates());

        const Matrix& totalCovariance(inputModel->totalCovariance(inputModel->numberOfSteps()-1));

        std::vector<Real> displacedImpliedVols(numberCaplets);
        std::vector<Real> annuities(numberCaplets);
        std::vector<Real> initialRates(numberCaplets);
        std::vector<Real> expiries(numberCaplets);

        Real capPrice =0.0;

        Real guess=0.0;
        Real minVol = 1e10;
        Real maxVol =0.0;

        for (Size j = startIndex; j < endIndex; ++j)
        {
            Size capletIndex = j - startIndex;
            Time resetTime = inputModel->evolution().rateTimes()[j];
            expiries[capletIndex] =  resetTime;

            Real sd = std::sqrt(totalCovariance[j][j]);
            displacedImpliedVols[capletIndex] = std::sqrt(totalCovariance[j][j]/resetTime);

            Real forward = inputModel->initialRates()[j];
            initialRates[capletIndex] = forward;

            Real annuity = curve.discountRatio(j+1,0)* inputModel->evolution().rateTaus()[j]*firstDF_;
            annuities[capletIndex] = annuity;

            Real displacement =  inputModel->displacements()[j];

            guess+=  displacedImpliedVols[capletIndex]*(forward+displacement)/forward;
            minVol =std::min(minVol, displacedImpliedVols[capletIndex]);
            maxVol =std::max(maxVol, displacedImpliedVols[capletIndex]*(forward+displacement)/forward);


            Real capletPrice = blackFormula(Option::Call,
                strike,
                forward,
                sd,
                annuity,
                displacement
                );

            capPrice += capletPrice;

        }

        guess/=numberCaplets;


        for (Size step =0; step < inputModel->evolution().numberOfSteps(); ++step)
        {
            Matrix thisDerivative(numberRates,factors,0.0);

            for (Size rate =std::max(inputModel->evolution().firstAliveRate()[step],startIndex); 
                rate < endIndex; ++rate)
            {
                for (Size f=0; f < factors; ++f)
                {
                    Real expiry = inputModel->evolution().rateTimes()[rate];
                    Real volDerivative = inputModel->pseudoRoot(step)[rate][f]
                    /(displacedImpliedVols[rate-startIndex]*expiry);
                    Real capletVega = blackFormulaVolDerivative(strike,inputModel->initialRates()[rate],
                        displacedImpliedVols[rate-startIndex]*std::sqrt(expiry),
                        expiry,
                        annuities[rate-startIndex],
                        inputModel->displacements()[rate]);

                    // note that the cap derivative  is equal to one of the caplet ones so we lose a loop
                    thisDerivative[rate][f] = volDerivative*capletVega;
                }
            }

            priceDerivatives_.push_back(thisDerivative);

        }

        QuickCap capPricer(strike, annuities, initialRates, expiries,capPrice);

        Size maxEvaluations = 1000;
        Real accuracy = 1E-6;

        Brent solver;
        solver.setMaxEvaluations(maxEvaluations);
        impliedVolatility_ =   solver.solve(capPricer,accuracy,guess,minVol*0.99,maxVol*1.01);
      
            

        vega_ = capPricer.vega(impliedVolatility_);



        for (Size step =0; step < inputModel->evolution().numberOfSteps(); ++step)
        {
            Matrix thisDerivative(numberRates,factors,0.0);

            for (Size rate =std::max(inputModel->evolution().firstAliveRate()[step],startIndex); 
                rate < endIndex; ++rate)
            {
                for (Size f=0; f < factors; ++f)
                {
                   
                    thisDerivative[rate][f] = priceDerivatives_[step][rate][f]/vega_;
                }
            }

            volatilityDerivatives_.push_back(thisDerivative);

        }



    }
    void AnalyticCompoundOptionEngine::calculate() const {

        QL_REQUIRE(strikeDaughter()>0.0,
                   "Daughter strike must be positive");

        QL_REQUIRE(strikeMother()>0.0,
                   "Mother strike must be positive");

        QL_REQUIRE(spot() >= 0.0, "negative or null underlying given");

        /* Solver Setup ***************************************************/
        Date helpDate(process_->riskFreeRate()->referenceDate());
        Date helpMaturity=helpDate+(maturityDaughter()-maturityMother())*Days;
        Real vol =process_->blackVolatility()->blackVol(helpMaturity,
                                                        strikeDaughter());

        Time helpTimeToMat=process_->time(helpMaturity);
        vol=vol*std::sqrt(helpTimeToMat);

        DiscountFactor dividendDiscount =
            process_->dividendYield()->discount(helpMaturity);

        DiscountFactor riskFreeDiscount =
            process_->riskFreeRate()->discount(helpMaturity);


        boost::shared_ptr<ImpliedSpotHelper> f(
                new ImpliedSpotHelper(dividendDiscount, riskFreeDiscount,
                                      vol, payoffDaughter(), strikeMother()));

        Brent solver;
        solver.setMaxEvaluations(1000);
        Real accuracy = 1.0e-6;

        Real X=0.0;
        Real sSolved=0.0;
        sSolved=solver.solve(*f, accuracy, strikeDaughter(), 1.0e-6, strikeDaughter()*1000.0);
        X=transformX(sSolved); // transform stock to return as in Wystup's book
        /* Solver Setup Finished*****************************************/

        Real phi=typeDaughter(); // -1 or 1
        Real w=typeMother(); // -1 or 1

        Real rho=std::sqrt(residualTimeMother()/residualTimeDaughter());
        BivariateCumulativeNormalDistributionDr78 N2(w*rho) ;

        DiscountFactor ddD=dividendDiscountDaughter();
        DiscountFactor rdD=riskFreeDiscountDaughter();
        //DiscountFactor ddM=dividendDiscountMother();
        DiscountFactor rdM=riskFreeDiscountMother();

        Real XmSM=X-stdDeviationMother();
        Real S=spot();
        Real dP=dPlus();
        Real dPT12=dPlusTau12(sSolved);
        Real vD=volatilityDaughter();

        Real dM=dMinus();
        Real strD=strikeDaughter();
        Real strM=strikeMother();
        Real rTM=residualTimeMother();
        Real rTD=residualTimeDaughter();

        Real rD=riskFreeRateDaughter();
        Real dD=dividendRateDaughter();

        Real tempRes=0.0;
        Real tempDelta=0.0;
        Real tempGamma=0.0;
        Real tempVega=0.0;
        Real tempTheta=0.0;
        Real N2XmSM=N2(-phi*w*XmSM,phi*dP);
        Real N2X=N2(-phi*w*X,phi*dM);
        Real NeX=N_(-phi*w*e(X));
        Real NX=N_(-phi*w*X);
        Real NT12=N_(phi*dPT12);
        Real ndP=n_(dP);
        Real nXm=n_(XmSM);
        Real invMTime=1/std::sqrt(rTM);
        Real invDTime=1/std::sqrt(rTD);

        tempRes=phi*w*S*ddD*N2XmSM-phi*w*strD*rdD*N2X-w*strM*rdM*NX;
        tempDelta=phi*w*ddD*N2XmSM;
        tempGamma=(ddD/(vD*S))*(invMTime*nXm*NT12+w*invDTime*ndP*NeX);
        tempVega=ddD*S*((1/invMTime)*nXm*NT12+w*(1/invDTime)*ndP*NeX);

        tempTheta+=phi*w*dD*S*ddD*N2XmSM-phi*w*rD*strD*rdD*N2X-w*rD*strM*rdM*NX;
        tempTheta-=0.5*vD*S*ddD*(invMTime*nXm*NT12+w*invDTime*ndP*NeX);

        results_.value=tempRes;
        results_.delta=tempDelta;
        results_.gamma=tempGamma;
        results_.vega=tempVega;
        results_.theta=tempTheta;
    }
Esempio n. 19
0
    void KahaleSmileSection::compute() {

        std::pair<Size, Size> afIdx = ssutils_->arbitragefreeIndices();
        leftIndex_ = afIdx.first;
        rightIndex_ = afIdx.second;

        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;
                // sanity check - in rare cases we can get digitials
                // which are not monotonic or greater than 1.0
                // due to numerical effects. Move to the next index in
                // these cases.
                Real dig = digitalOptionPrice(k1 / 2.0);
                QL_REQUIRE(dig >= -c1p && dig <= 1.0, "dummy");
            }
            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;
                bool valid = false;
                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
                    valid = true;
                }
                catch (...) {
                    // delete the right point of the interval where we try to
                    // interpolate
                    moneynessGrid_.erase(moneynessGrid_.begin() + (i + 1));
                    k_.erase(k_.begin() + (i + 1));
                    c_.erase(c_.begin() + (i + 1));
                    cFunctions_.erase(cFunctions_.begin() + (i + 1));
                    rightIndex_--;
                    i--;
                }
                if (valid) {
                    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_) {
                    QL_REQUIRE(-cp0 / c0 > 0.0, "dummy"); // this is caught
                                                          // below
                    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_ << ")");
    }