OvernightIndexedCoupon::OvernightIndexedCoupon(
                    const Date& paymentDate,
                    Real nominal,
                    const Date& startDate,
                    const Date& endDate,
                    const shared_ptr<OvernightIndex>& overnightIndex,
                    Real gearing,
                    Spread spread,
                    const Date& refPeriodStart,
                    const Date& refPeriodEnd,
                    const DayCounter& dayCounter)
    : FloatingRateCoupon(paymentDate, nominal, startDate, endDate,
                         overnightIndex->fixingDays(), overnightIndex,
                         gearing, spread,
                         refPeriodStart, refPeriodEnd,
                         dayCounter, false) {

        // value dates
        Schedule sch = MakeSchedule()
                    .from(startDate)
                    .to(endDate)
                    .withTenor(1*Days)
                    .withCalendar(overnightIndex->fixingCalendar())
                    .withConvention(overnightIndex->businessDayConvention())
                    .backwards();
        valueDates_ = sch.dates();
        QL_ENSURE(valueDates_.size()>=2, "degenerate schedule");

        // fixing dates
        n_ = valueDates_.size()-1;
        if (overnightIndex->fixingDays()==0) {
            fixingDates_ = vector<Date>(valueDates_.begin(),
                                             valueDates_.end()-1);
        } else {
            fixingDates_.resize(n_);
            for (Size i=0; i<n_; ++i)
                fixingDates_[i] = overnightIndex->fixingDate(valueDates_[i]);
        }

        // accrual (compounding) periods
        dt_.resize(n_);
        const DayCounter& dc = overnightIndex->dayCounter();
        for (Size i=0; i<n_; ++i)
            dt_[i] = dc.yearFraction(valueDates_[i], valueDates_[i+1]);

        setPricer(shared_ptr<FloatingRateCouponPricer>(new
                                            OvernightIndexedCouponPricer));
    }
示例#2
0
    SyntheticCDO::SyntheticCDO (const boost::shared_ptr<Basket> basket,
                                Protection::Side side,
                                const Schedule& schedule,
                                Rate upfrontRate,
                                Rate runningRate,
                                const DayCounter& dayCounter,
                                BusinessDayConvention paymentConvention,
                                const Handle<YieldTermStructure>& yieldTS)
        : basket_(basket),
          side_(side),
          schedule_(schedule),
          upfrontRate_(upfrontRate),
          runningRate_(runningRate),
          dayCounter_(dayCounter),
          paymentConvention_(paymentConvention),
          yieldTS_(yieldTS) {
        QL_REQUIRE (basket->names().size() > 0, "basket is empty");

        registerWith (yieldTS_);
        const boost::shared_ptr<Pool> pool = basket->pool();

        Date today = Settings::instance().evaluationDate();
        // register with probabilities if the corresponding issuer is
        // alive under this name contractual conditions
        for (Size i = 0; i < basket->names().size(); i++) {
            if(!pool->get(basket->names()[i]).
                defaultedBetween(schedule.dates()[0],
                                 today,
                                 basket->defaultKeys()[i]))
            registerWith(pool->get(basket->names()[i]).
                defaultProbability(basket->defaultKeys()[i]));
            // To do: the basket could do this last line on its own without so much
            //    travelling, update its interface? some RR models depend on the
            //    probabilities and they will be registered with them. Strictly
            //    speaking the basket does not need directly to be registered
            //    with the probs.
            /*
                we used to be registering with Issuers which are not observables. However
                this might be what we want: Issuer registration might give us registration
                with probabilities and with creditEvents at the same time.
            */
        }
        // register with recoveries:
        registerWith(basket_);
    }
示例#3
0
    CallableBond::CallableBond(Natural settlementDays,
                               const Schedule& schedule,
                               const DayCounter& paymentDayCounter,
                               const Date& issueDate,
                               const CallabilitySchedule& putCallSchedule)
    : Bond(settlementDays, schedule.calendar(), issueDate),
      paymentDayCounter_(paymentDayCounter), putCallSchedule_(putCallSchedule) {

        maturityDate_ = schedule.dates().back();

        if (!putCallSchedule_.empty()) {
            Date finalOptionDate = Date::minDate();
            for (Size i=0; i<putCallSchedule_.size();++i) {
                finalOptionDate=std::max(finalOptionDate,
                                         putCallSchedule_[i]->date());
            }
            QL_REQUIRE(finalOptionDate <= maturityDate_ ,
                       "Bond cannot mature before last call/put date");
        }

        // derived classes must set cashflows_ and frequency_
    }
void LgmSwaptionEngineAD::calculate() const {

    // collect data needed for core computation routine

    QL_REQUIRE(arguments_.settlementType == Settlement::Physical,
               "cash-settled swaptions not yet implemented ...");

    Date settlement = model_->termStructure()->referenceDate();

    if (arguments_.exercise->dates().back() <=
        settlement) { // swaption is expired, possibly generated swap is not
                      // valued
        results_.value = 0.0;
        return;
    }

    int idxMax = static_cast<int>(arguments_.exercise->dates().size()) - 1;
    int minIdxAlive = static_cast<int>(
        std::upper_bound(arguments_.exercise->dates().begin(),
                         arguments_.exercise->dates().end(), settlement) -
        arguments_.exercise->dates().begin());

    VanillaSwap swap = *arguments_.swap;

    int callput = arguments_.type == VanillaSwap::Payer ? 1 : -1;

    Schedule fixedSchedule = swap.fixedSchedule();
    Schedule floatSchedule = swap.floatingSchedule();

    Date expiry0;

    std::vector<int> fix_startidxes, float_startidxes;
    std::vector<Date> expiryDates;

    for (int idx = minIdxAlive; idx <= idxMax; ++idx) {
        expiry0 = arguments_.exercise->dates()[idx];
        expiryDates.push_back(expiry0);

        Size j1 = std::upper_bound(fixedSchedule.dates().begin(),
                                   fixedSchedule.dates().end(), expiry0 - 1) -
                  fixedSchedule.dates().begin();
        Size k1 = std::upper_bound(floatSchedule.dates().begin(),
                                   floatSchedule.dates().end(), expiry0 - 1) -
                  floatSchedule.dates().begin();

        fix_startidxes.push_back(j1);
        float_startidxes.push_back(k1);
    }

    std::vector<double> float_mults, index_acctimes, float_spreads, fix_cpn;
    std::vector<Date> floatt1Dates, floatt2Dates, floattpDates;
    std::vector<Date> fixtpDates;

    for (Size i = 0; i < arguments_.floatingFixingDates.size(); ++i) {
        float_mults.push_back(arguments_.nominal *
                              arguments_.floatingAccrualTimes[i]);
        float_spreads.push_back(arguments_.floatingSpreads[i]);
        boost::shared_ptr<IborIndex> index = arguments_.swap->iborIndex();
        Date d1 = index->valueDate(arguments_.floatingFixingDates[i]);
        Date d2 = index->maturityDate(d1);
        double acctime = index->dayCounter().yearFraction(d1, d2, d1, d2);
        floatt1Dates.push_back(d1);
        floatt2Dates.push_back(d2);
        floattpDates.push_back(arguments_.floatingPayDates[i]);
        index_acctimes.push_back(acctime);
    }

    for (Size i = 0; i < arguments_.fixedCoupons.size(); ++i) {
        fix_cpn.push_back(arguments_.fixedCoupons[i]);
        fixtpDates.push_back(arguments_.fixedPayDates[i]);
    }

    // join all dates and fill index vectors

    std::vector<Date> allDates;
    std::vector<double> allTimes; // with settlement as first entry !
    std::vector<int> expiries, floatt1s, floatt2s, floattps, fixtps;
    std::vector<double> modpar;

    allDates.reserve(expiryDates.size() + floatt1Dates.size() +
                     floatt2Dates.size() + floattpDates.size() +
                     fixtpDates.size());

    allTimes.reserve(allDates.size());
    modpar.reserve(3 * allDates.size());

    allDates.push_back(settlement);
    allDates.insert(allDates.end(), expiryDates.begin(), expiryDates.end());
    allDates.insert(allDates.end(), floatt1Dates.begin(), floatt1Dates.end());
    allDates.insert(allDates.end(), floatt2Dates.begin(), floatt2Dates.end());
    allDates.insert(allDates.end(), floattpDates.begin(), floattpDates.end());
    allDates.insert(allDates.end(), fixtpDates.begin(), fixtpDates.end());

    std::sort(allDates.begin(), allDates.end());
    allDates.erase(unique(allDates.begin(), allDates.end()), allDates.end());

    for (Size i = 0; i < allDates.size(); ++i) {
        allTimes.push_back(
            model_->termStructure()->timeFromReference(allDates[i]));
    }

    for (Size i = 0; i < allDates.size(); ++i) {
        modpar.push_back(model_->parametrization()->H(allTimes[i]));
    }
    for (Size i = 0; i < allDates.size(); ++i) {
        modpar.push_back(model_->parametrization()->zeta(allTimes[i]));
    }
    for (Size i = 0; i < allDates.size(); ++i) {
        modpar.push_back(model_->termStructure()->discount(allTimes[i]));
    }

    for (Size i = 0; i < expiryDates.size(); ++i) {
        expiries.push_back(
            std::find(allDates.begin(), allDates.end(), expiryDates[i]) -
            allDates.begin());
    }
    for (Size i = 0; i < floatt1Dates.size(); ++i) {
        floatt1s.push_back(
            std::find(allDates.begin(), allDates.end(), floatt1Dates[i]) -
            allDates.begin());
    }
    for (Size i = 0; i < floatt2Dates.size(); ++i) {
        floatt2s.push_back(
            std::find(allDates.begin(), allDates.end(), floatt2Dates[i]) -
            allDates.begin());
    }
    for (Size i = 0; i < floattpDates.size(); ++i) {
        floattps.push_back(
            std::find(allDates.begin(), allDates.end(), floattpDates[i]) -
            allDates.begin());
    }
    for (Size i = 0; i < fixtpDates.size(); ++i) {
        fixtps.push_back(
            std::find(allDates.begin(), allDates.end(), fixtpDates[i]) -
            allDates.begin());
    }

    // call core computation routine and set results

    int ntimes = allTimes.size();
    int nexpiries = expiries.size();
    int nfloats = floatt1s.size();
    int nfixs = fix_cpn.size();

    double res = 0.0;
    std::vector<Real> dres(3*ntimes);
    int integration_pts = integrationPoints_;
    double std_devs = stddevs_;
    lgm_swaption_engine_ad_(&ntimes, &allTimes[0], &modpar[0], &nexpiries,
                         &expiries[0], &callput, &nfloats, &float_startidxes[0],
                         &float_mults[0], &index_acctimes[0], &float_spreads[0],
                         &floatt1s[0], &floatt2s[0], &floattps[0],
                         &fix_startidxes[0], &nfixs, &fix_cpn[0], &fixtps[0],
                         &integration_pts, &std_devs, &res, &dres[0]);

    results_.value = res;

    std::vector<Real> H_sensitivity(dres.begin(),dres.begin()+ntimes);
    std::vector<Real> zeta_sensitivity(dres.begin()+ntimes,dres.begin()+2*ntimes);
    std::vector<Real> discount_sensitivity(dres.begin()+2*ntimes,dres.begin()+3*ntimes);

    results_.additionalResults["sensitivityTimes"] = allTimes;
    results_.additionalResults["sensitivityH"] = H_sensitivity;
    results_.additionalResults["sensitivityZeta"] = zeta_sensitivity;
    results_.additionalResults["sensitivityDiscount"] = discount_sensitivity;

}
    void Gaussian1dNonstandardSwaptionEngine::calculate() const {

        QL_REQUIRE(arguments_.settlementType == Settlement::Physical,
                   "cash-settled swaptions not yet implemented ...");

        Date settlement = model_->termStructure()->referenceDate();

        if (arguments_.exercise->dates().back() <=
            settlement) { // swaption is expired, possibly generated swap is not
                          // valued
            results_.value = 0.0;
            return;
        }

        boost::shared_ptr<RebatedExercise> rebatedExercise =
            boost::dynamic_pointer_cast<RebatedExercise>(arguments_.exercise);

        int idx = arguments_.exercise->dates().size() - 1;
        int minIdxAlive = static_cast<int>(
            std::upper_bound(arguments_.exercise->dates().begin(),
                             arguments_.exercise->dates().end(), settlement) -
            arguments_.exercise->dates().begin());

        NonstandardSwap swap = *arguments_.swap;
        Option::Type type =
            arguments_.type == VanillaSwap::Payer ? Option::Call : Option::Put;
        Schedule schedule = swap.fixedSchedule();
        Schedule floatSchedule = swap.floatingSchedule();

        Array npv0(2 * integrationPoints_ + 1, 0.0),
            npv1(2 * integrationPoints_ + 1, 0.0);
        Array z = model_->yGrid(stddevs_, integrationPoints_);
        Array p(z.size(), 0.0);

        // for probability computation
        std::vector<Array> npvp0, npvp1;
        if (probabilities_ != None) {
            for (Size i = 0; i < static_cast<Size>(idx - minIdxAlive + 2); ++i) {
                Array npvTmp0(2 * integrationPoints_ + 1, 0.0);
                Array npvTmp1(2 * integrationPoints_ + 1, 0.0);
                npvp0.push_back(npvTmp0);
                npvp1.push_back(npvTmp1);
            }
        }
        // end probabkility computation

        Date expiry1 = Null<Date>(), expiry0;
        Time expiry1Time = Null<Real>(), expiry0Time;

        do {

            if (idx == minIdxAlive - 1)
                expiry0 = settlement;
            else
                expiry0 = arguments_.exercise->dates()[idx];

            expiry0Time = std::max(
                model_->termStructure()->timeFromReference(expiry0), 0.0);

            Size j1 = std::upper_bound(schedule.dates().begin(),
                                       schedule.dates().end(), expiry0 - 1) -
                      schedule.dates().begin();
            Size k1 =
                std::upper_bound(floatSchedule.dates().begin(),
                                 floatSchedule.dates().end(), expiry0 - 1) -
                floatSchedule.dates().begin();

            // todo add openmp support later on (as in gaussian1dswaptionengine)

            for (Size k = 0; k < (expiry0 > settlement ? npv0.size() : 1);
                 k++) {

                Real price = 0.0;
                if (expiry1Time != Null<Real>()) {
                    Real zSpreadDf =
                        oas_.empty() ? 1.0
                                     : std::exp(-oas_->value() *
                                                (expiry1Time - expiry0Time));
                    Array yg = model_->yGrid(stddevs_, integrationPoints_,
                                             expiry1Time, expiry0Time,
                                             expiry0 > settlement ? z[k] : 0.0);
                    CubicInterpolation payoff0(
                        z.begin(), z.end(), npv1.begin(),
                        CubicInterpolation::Spline, true,
                        CubicInterpolation::Lagrange, 0.0,
                        CubicInterpolation::Lagrange, 0.0);
                    for (Size i = 0; i < yg.size(); i++) {
                        p[i] = payoff0(yg[i], true);
                    }
                    CubicInterpolation payoff1(
                        z.begin(), z.end(), p.begin(),
                        CubicInterpolation::Spline, true,
                        CubicInterpolation::Lagrange, 0.0,
                        CubicInterpolation::Lagrange, 0.0);
                    for (Size i = 0; i < z.size() - 1; i++) {
                        price += model_->gaussianShiftedPolynomialIntegral(
                                     0.0, payoff1.cCoefficients()[i],
                                     payoff1.bCoefficients()[i],
                                     payoff1.aCoefficients()[i], p[i], z[i],
                                     z[i], z[i + 1]) *
                                 zSpreadDf;
                    }
                    if (extrapolatePayoff_) {
                        if (flatPayoffExtrapolation_) {
                            price +=
                                model_->gaussianShiftedPolynomialIntegral(
                                    0.0, 0.0, 0.0, 0.0, p[z.size() - 2],
                                    z[z.size() - 2], z[z.size() - 1], 100.0) *
                                zSpreadDf;
                            price += model_->gaussianShiftedPolynomialIntegral(
                                         0.0, 0.0, 0.0, 0.0, p[0], z[0], -100.0,
                                         z[0]) *
                                     zSpreadDf;
                        } else {
                            if (type == Option::Call)
                                price +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0,
                                        payoff1.cCoefficients()[z.size() - 2],
                                        payoff1.bCoefficients()[z.size() - 2],
                                        payoff1.aCoefficients()[z.size() - 2],
                                        p[z.size() - 2], z[z.size() - 2],
                                        z[z.size() - 1], 100.0) *
                                    zSpreadDf;
                            if (type == Option::Put)
                                price +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0, payoff1.cCoefficients()[0],
                                        payoff1.bCoefficients()[0],
                                        payoff1.aCoefficients()[0], p[0], z[0],
                                        -100.0, z[0]) *
                                    zSpreadDf;
                        }
                    }
                }

                npv0[k] = price;

                // for probability computation
                if (probabilities_ != None) {
                    for (Size m = 0; m < npvp0.size(); m++) {
                        Real price = 0.0;
                        if (expiry1Time != Null<Real>()) {
                            Real zSpreadDf =
                                oas_.empty()
                                    ? 1.0
                                    : std::exp(-oas_->value() *
                                               (expiry1Time - expiry0Time));
                            Array yg = model_->yGrid(
                                stddevs_, integrationPoints_, expiry1Time,
                                expiry0Time, expiry0 > settlement ? z[k] : 0.0);
                            CubicInterpolation payoff0(
                                z.begin(), z.end(), npvp1[m].begin(),
                                CubicInterpolation::Spline, true,
                                CubicInterpolation::Lagrange, 0.0,
                                CubicInterpolation::Lagrange, 0.0);
                            for (Size i = 0; i < yg.size(); i++) {
                                p[i] = payoff0(yg[i], true);
                            }
                            CubicInterpolation payoff1(
                                z.begin(), z.end(), p.begin(),
                                CubicInterpolation::Spline, true,
                                CubicInterpolation::Lagrange, 0.0,
                                CubicInterpolation::Lagrange, 0.0);
                            for (Size i = 0; i < z.size() - 1; i++) {
                                price +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0, payoff1.cCoefficients()[i],
                                        payoff1.bCoefficients()[i],
                                        payoff1.aCoefficients()[i], p[i], z[i],
                                        z[i], z[i + 1]) *
                                    zSpreadDf;
                            }
                            if (extrapolatePayoff_) {
                                if (flatPayoffExtrapolation_) {
                                    price +=
                                        model_
                                            ->gaussianShiftedPolynomialIntegral(
                                                  0.0, 0.0, 0.0, 0.0,
                                                  p[z.size() - 2],
                                                  z[z.size() - 2],
                                                  z[z.size() - 1], 100.0) *
                                        zSpreadDf;
                                    price +=
                                        model_
                                            ->gaussianShiftedPolynomialIntegral(
                                                  0.0, 0.0, 0.0, 0.0, p[0],
                                                  z[0], -100.0, z[0]) *
                                        zSpreadDf;
                                } else {
                                    if (type == Option::Call)
                                        price +=
                                            model_
                                                ->gaussianShiftedPolynomialIntegral(
                                                      0.0,
                                                      payoff1.cCoefficients()
                                                          [z.size() - 2],
                                                      payoff1.bCoefficients()
                                                          [z.size() - 2],
                                                      payoff1.aCoefficients()
                                                          [z.size() - 2],
                                                      p[z.size() - 2],
                                                      z[z.size() - 2],
                                                      z[z.size() - 1], 100.0) *
                                            zSpreadDf;
                                    if (type == Option::Put)
                                        price +=
                                            model_
                                                ->gaussianShiftedPolynomialIntegral(
                                                      0.0,
                                                      payoff1
                                                          .cCoefficients()[0],
                                                      payoff1
                                                          .bCoefficients()[0],
                                                      payoff1
                                                          .aCoefficients()[0],
                                                      p[0], z[0], -100.0,
                                                      z[0]) *
                                            zSpreadDf;
                                }
                            }
                        }

                        npvp0[m][k] = price;
                    }
                }
                // end probability computation

                if (expiry0 > settlement) {
                    Real floatingLegNpv = 0.0;
                    for (Size l = k1; l < arguments_.floatingCoupons.size();
                         l++) {
                        Real zSpreadDf =
                            oas_.empty()
                                ? 1.0
                                : std::exp(
                                      -oas_->value() *
                                      (model_->termStructure()
                                           ->dayCounter()
                                           .yearFraction(
                                                expiry0,
                                                arguments_
                                                    .floatingPayDates[l])));
                        Real amount;
                        if (arguments_.floatingIsRedemptionFlow[l])
                            amount = arguments_.floatingCoupons[l];
                        else
                            amount = arguments_.floatingNominal[l] *
                                     arguments_.floatingAccrualTimes[l] *
                                     (arguments_.floatingGearings[l] *
                                          model_->forwardRate(
                                              arguments_.floatingFixingDates[l],
                                              expiry0, z[k],
                                              arguments_.swap->iborIndex()) +
                                      arguments_.floatingSpreads[l]);
                        floatingLegNpv +=
                            amount *
                            model_->zerobond(arguments_.floatingPayDates[l],
                                             expiry0, z[k], discountCurve_) *
                            zSpreadDf;
                    }
                    Real fixedLegNpv = 0.0;
                    for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) {
                        Real zSpreadDf =
                            oas_.empty()
                                ? 1.0
                                : std::exp(
                                      -oas_->value() *
                                      (model_->termStructure()
                                           ->dayCounter()
                                           .yearFraction(
                                                expiry0,
                                                arguments_.fixedPayDates[l])));
                        fixedLegNpv +=
                            arguments_.fixedCoupons[l] *
                            model_->zerobond(arguments_.fixedPayDates[l],
                                             expiry0, z[k], discountCurve_) *
                            zSpreadDf;
                    }
                    Real rebate = 0.0;
                    Real zSpreadDf = 1.0;
                    Date rebateDate = expiry0;
                    if (rebatedExercise != NULL) {
                        rebate = rebatedExercise->rebate(idx);
                        rebateDate = rebatedExercise->rebatePaymentDate(idx);
                        zSpreadDf =
                            oas_.empty()
                                ? 1.0
                                : std::exp(
                                      -oas_->value() *
                                      (model_->termStructure()
                                           ->dayCounter()
                                           .yearFraction(expiry0, rebateDate)));
                    }
                    Real exerciseValue =
                        ((type == Option::Call ? 1.0 : -1.0) *
                             (floatingLegNpv - fixedLegNpv) +
                         rebate * model_->zerobond(rebateDate, expiry0, z[k],
                                                   discountCurve_) *
                             zSpreadDf) /
                        model_->numeraire(expiry0Time, z[k], discountCurve_);

                    // for probability computation
                    if (probabilities_ != None) {
                        if (idx == static_cast<int>(
                                       arguments_.exercise->dates().size()) -
                                       1) // if true we are at the latest date,
                                          // so we init
                                          // the no call probability
                            npvp0.back()[k] =
                                probabilities_ == Naive
                                    ? 1.0
                                    : 1.0 / (model_->zerobond(expiry0Time, 0.0,
                                                              0.0,
                                                              discountCurve_) *
                                             model_->numeraire(expiry0, z[k],
                                                               discountCurve_));
                        if (exerciseValue >= npv0[k]) {
                            npvp0[idx - minIdxAlive][k] =
                                probabilities_ == Naive
                                    ? 1.0
                                    : 1.0 /
                                          (model_->zerobond(expiry0Time, 0.0,
                                                            0.0,
                                                            discountCurve_) *
                                           model_->numeraire(expiry0Time, z[k],
                                                             discountCurve_));
                            for (Size ii = idx - minIdxAlive + 1;
                                 ii < npvp0.size(); ii++)
                                npvp0[ii][k] = 0.0;
                        }
                    }
                    // end probability computation

                    npv0[k] = std::max(npv0[k], exerciseValue);
                }
            }

            npv1.swap(npv0);

            // for probability computation
            if (probabilities_ != None) {
                for (Size i = 0; i < npvp0.size(); i++)
                    npvp1[i].swap(npvp0[i]);
            }
            // end probability computation

            expiry1 = expiry0;
            expiry1Time = expiry0Time;

        } while (--idx >= minIdxAlive - 1);

        results_.value = npv1[0] * model_->numeraire(0.0, 0.0, discountCurve_);

        // for probability computation
        if (probabilities_ != None) {
            std::vector<Real> prob(npvp0.size());
            for (Size i = 0; i < npvp0.size(); i++) {
                prob[i] = npvp1[i][0] *
                          (probabilities_ == Naive
                               ? 1.0
                               : model_->numeraire(0.0, 0.0, discountCurve_));
            }
            results_.additionalResults["probabilities"] = prob;
        }
        // end probability computation
    }
    void Gaussian1dSwaptionEngine::calculate() const {

        QL_REQUIRE(arguments_.settlementType == Settlement::Physical,
                   "cash-settled swaptions not yet implemented ...");

        Date settlement = model_->termStructure()->referenceDate();

        if (arguments_.exercise->dates().back() <=
            settlement) { // swaption is expired, possibly generated swap is not
                          // valued
            results_.value = 0.0;
            return;
        }

        int idx = static_cast<int>(arguments_.exercise->dates().size()) - 1;
        int minIdxAlive = static_cast<int>(
            std::upper_bound(arguments_.exercise->dates().begin(),
                             arguments_.exercise->dates().end(), settlement) -
            arguments_.exercise->dates().begin());

        VanillaSwap swap = *arguments_.swap;
        Option::Type type =
            arguments_.type == VanillaSwap::Payer ? Option::Call : Option::Put;
        Schedule fixedSchedule = swap.fixedSchedule();
        Schedule floatSchedule = swap.floatingSchedule();

        Array npv0(2 * integrationPoints_ + 1, 0.0),
            npv1(2 * integrationPoints_ + 1, 0.0);
        Array z = model_->yGrid(stddevs_, integrationPoints_);
        Array p(z.size(), 0.0);

        Date expiry1 = Null<Date>(), expiry0;
        Time expiry1Time = Null<Real>(), expiry0Time;

        do {

            if (idx == minIdxAlive - 1)
                expiry0 = settlement;
            else
                expiry0 = arguments_.exercise->dates()[idx];

            expiry0Time = std::max(
                model_->termStructure()->timeFromReference(expiry0), 0.0);

            Size j1 =
                std::upper_bound(fixedSchedule.dates().begin(),
                                 fixedSchedule.dates().end(), expiry0 - 1) -
                fixedSchedule.dates().begin();
            Size k1 =
                std::upper_bound(floatSchedule.dates().begin(),
                                 floatSchedule.dates().end(), expiry0 - 1) -
                floatSchedule.dates().begin();

            // a lazy object is not thread safe, neither is the caching
            // in gsrprocess. therefore we trigger computations here such
            // that neither lazy object recalculation nor write access
            // during caching occurs in the parallized loop below.
            // this is known to work for the gsr and markov functional
            // model implementations of Gaussian1dModel
#ifdef _OPENMP
            if (expiry0 > settlement) {
                for (Size l = k1; l < arguments_.floatingCoupons.size(); l++) {
                    model_->forwardRate(arguments_.floatingFixingDates[l],
                                        expiry0, 0.0,
                                        arguments_.swap->iborIndex());
                    model_->zerobond(arguments_.floatingPayDates[l], expiry0,
                                     0.0, discountCurve_);
                }
                for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) {
                    model_->zerobond(arguments_.fixedPayDates[l], expiry0, 0.0,
                                     discountCurve_);
                }
                model_->numeraire(expiry0Time, 0.0, discountCurve_);
            }
#endif

#pragma omp parallel for default(shared) firstprivate(p) if(expiry0>settlement)
            for (Size k = 0; k < (expiry0 > settlement ? npv0.size() : 1);
                 k++) {

                Real price = 0.0;
                if (expiry1Time != Null<Real>()) {
                    Array yg = model_->yGrid(stddevs_, integrationPoints_,
                                             expiry1Time, expiry0Time,
                                             expiry0 > settlement ? z[k] : 0.0);
                    CubicInterpolation payoff0(
                        z.begin(), z.end(), npv1.begin(),
                        CubicInterpolation::Spline, true,
                        CubicInterpolation::Lagrange, 0.0,
                        CubicInterpolation::Lagrange, 0.0);
                    for (Size i = 0; i < yg.size(); i++) {
                        p[i] = payoff0(yg[i], true);
                    }
                    CubicInterpolation payoff1(
                        z.begin(), z.end(), p.begin(),
                        CubicInterpolation::Spline, true,
                        CubicInterpolation::Lagrange, 0.0,
                        CubicInterpolation::Lagrange, 0.0);
                    for (Size i = 0; i < z.size() - 1; i++) {
                        price += model_->gaussianShiftedPolynomialIntegral(
                            0.0, payoff1.cCoefficients()[i],
                            payoff1.bCoefficients()[i],
                            payoff1.aCoefficients()[i], p[i], z[i], z[i],
                            z[i + 1]);
                    }
                    if (extrapolatePayoff_) {
                        if (flatPayoffExtrapolation_) {
                            price += model_->gaussianShiftedPolynomialIntegral(
                                0.0, 0.0, 0.0, 0.0, p[z.size() - 2],
                                z[z.size() - 2], z[z.size() - 1], 100.0);
                            price += model_->gaussianShiftedPolynomialIntegral(
                                0.0, 0.0, 0.0, 0.0, p[0], z[0], -100.0, z[0]);
                        } else {
                            if (type == Option::Call)
                                price +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0,
                                        payoff1.cCoefficients()[z.size() - 2],
                                        payoff1.bCoefficients()[z.size() - 2],
                                        payoff1.aCoefficients()[z.size() - 2],
                                        p[z.size() - 2], z[z.size() - 2],
                                        z[z.size() - 1], 100.0);
                            if (type == Option::Put)
                                price +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0, payoff1.cCoefficients()[0],
                                        payoff1.bCoefficients()[0],
                                        payoff1.aCoefficients()[0], p[0], z[0],
                                        -100.0, z[0]);
                        }
                    }
                }

                npv0[k] = price;

                if (expiry0 > settlement) {
                    Real floatingLegNpv = 0.0;
                    for (Size l = k1; l < arguments_.floatingCoupons.size();
                         l++) {
                        floatingLegNpv +=
                            arguments_.nominal *
                            arguments_.floatingAccrualTimes[l] *
                            (arguments_.floatingSpreads[l] +
                             model_->forwardRate(
                                 arguments_.floatingFixingDates[l], expiry0,
                                 z[k], arguments_.swap->iborIndex())) *
                            model_->zerobond(arguments_.floatingPayDates[l],
                                             expiry0, z[k], discountCurve_);
                    }
                    Real fixedLegNpv = 0.0;
                    for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) {
                        fixedLegNpv +=
                            arguments_.fixedCoupons[l] *
                            model_->zerobond(arguments_.fixedPayDates[l],
                                             expiry0, z[k], discountCurve_);
                    }
                    npv0[k] = std::max(npv0[k],
                                       (type == Option::Call ? 1.0 : -1.0) *
                                           (floatingLegNpv - fixedLegNpv) /
                                           model_->numeraire(expiry0Time, z[k],
                                                             discountCurve_));
                }
            }

            npv1.swap(npv0);
            expiry1 = expiry0;
            expiry1Time = expiry0Time;

        } while (--idx >= minIdxAlive - 1);

        results_.value = npv1[0] * model_->numeraire(0.0, 0.0, discountCurve_);
    }