Exemplo n.º 1
0
 void CatBond::arguments::validate() const {
     Bond::arguments::validate();
     QL_REQUIRE(notionalRisk, "null notionalRisk");
 }
Exemplo n.º 2
0
    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;
        }
    }
Exemplo n.º 5
0
    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);
        }
    }
Exemplo n.º 6
0
    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);
    }
Exemplo n.º 8
0
 /*! \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;
 }
Exemplo n.º 9
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_ << ")");


    }
Exemplo n.º 10
0
    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_);
    }
Exemplo n.º 11
0
    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;
    }
Exemplo n.º 12
0
 Real CreditDefaultSwap::couponLegNPV() const {
     calculate();
     QL_REQUIRE(couponLegNPV_ != Null<Rate>(),
                "coupon-leg NPV not available");
     return couponLegNPV_;
 }
Exemplo n.º 13
0
	Real CreditDefaultSwap::accrualRebateNPV() const {
		calculate();
		QL_REQUIRE(accrualRebateNPV_ != Null<Real>(),
			       "accrual Rebate NPV not available");
		return accrualRebateNPV_;
	}
Exemplo n.º 14
0
    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);
    }
Exemplo n.º 16
0
    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");
        }
    }
Exemplo n.º 17
0
  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];

  }
Exemplo n.º 18
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);
 }
Exemplo n.º 19
0
 inline BigInteger DayCounter::dayCount(const Date& d1,
                                        const Date& d2) const {
     QL_REQUIRE(impl_, "no implementation provided");
     return impl_->dayCount(d1,d2);
 }
Exemplo n.º 20
0
 inline std::string DayCounter::name() const {
     QL_REQUIRE(impl_, "no implementation provided");
     return impl_->name();
 }
Exemplo n.º 21
0
 Rate CreditDefaultSwap::fairUpfront() const {
     calculate();
     QL_REQUIRE(fairUpfront_ != Null<Rate>(),
                "fair upfront not available");
     return fairUpfront_;
 }
Exemplo n.º 22
0
    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;
    }
Exemplo n.º 23
0
 Rate CreditDefaultSwap::fairSpread() const {
     calculate();
     QL_REQUIRE(fairSpread_ != Null<Rate>(),
                "fair spread not available");
     return fairSpread_;
 }
Exemplo n.º 24
0
    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;
    }
Exemplo n.º 25
0
 Real CreditDefaultSwap::defaultLegNPV() const {
     calculate();
     QL_REQUIRE(defaultLegNPV_ != Null<Rate>(),
                "default-leg NPV not available");
     return defaultLegNPV_;
 }
Exemplo n.º 26
0
    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");

    }
Exemplo n.º 27
0
	Real CreditDefaultSwap::upfrontPV01() const {
		calculate();
		QL_REQUIRE(upfrontPV01_ != Null<Real>(),
			       "upfront PV01 not available");
		return upfrontPV01_;
	}
Exemplo n.º 28
0
 inline Real GeneralStatistics::max() const {
     QL_REQUIRE(samples() > 0, "empty sample set");
     return std::max_element(samples_.begin(),
                             samples_.end())->first;
 }
Exemplo n.º 29
0
 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];
 }
Exemplo n.º 30
-1
    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];
    }