<|start_filename|>ql/pricingengines/capfloor/analyticcapfloorengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2001, 2002, 2003 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/capfloor/analyticcapfloorengine.hpp>

namespace QuantLib {

    AnalyticCapFloorEngine::AnalyticCapFloorEngine(
                              const boost::shared_ptr<AffineModel>& model,
                              const Handle<YieldTermStructure>& termStructure)
    : GenericModelEngine<AffineModel,
                         CapFloor::arguments,
                         CapFloor::results >(model),
      termStructure_(termStructure) {
        registerWith(termStructure_);
    }


    void AnalyticCapFloorEngine::calculate() const {
        QL_REQUIRE(!model_.empty(), "null model");

        Date referenceDate;
        DayCounter dayCounter;

        boost::shared_ptr<TermStructureConsistentModel> tsmodel =
            boost::dynamic_pointer_cast<TermStructureConsistentModel>(*model_);
        if (tsmodel) {
            referenceDate = tsmodel->termStructure()->referenceDate();
            dayCounter = tsmodel->termStructure()->dayCounter();
        } else {
            referenceDate = termStructure_->referenceDate();
            dayCounter = termStructure_->dayCounter();
        }

        Real value = 0.0;
        CapFloor::Type type = arguments_.type;
        Size nPeriods = arguments_.endDates.size();

        bool includeRefDatePayments =
            Settings::instance().includeReferenceDateEvents();
        if (referenceDate == Settings::instance().evaluationDate()) {
            boost::optional<bool> includeTodaysPayments =
                Settings::instance().includeTodaysCashFlows();
            if (includeTodaysPayments)
                includeRefDatePayments = *includeTodaysPayments;
        }

        for (Size i=0; i<nPeriods; i++) {

            Time fixingTime =
                dayCounter.yearFraction(referenceDate,
                                        arguments_.fixingDates[i]);
            Time paymentTime =
                dayCounter.yearFraction(referenceDate,
                                        arguments_.endDates[i]);

            bool not_expired =
                includeRefDatePayments ? paymentTime >= 0.0 : paymentTime > 0.0;

            if (not_expired) {
                Time tenor = arguments_.accrualTimes[i];
                Rate fixing = arguments_.forwards[i];
                if (fixingTime <= 0.0) {
                    if (type == CapFloor::Cap || type == CapFloor::Collar) {
                        DiscountFactor discount = model_->discount(paymentTime);
                        Rate strike = arguments_.capRates[i];
                        value += discount * arguments_.nominals[i] * tenor
                               * arguments_.gearings[i]
                               * std::max(0.0, fixing - strike);
                    }
                    if (type == CapFloor::Floor || type == CapFloor::Collar) {
                        DiscountFactor discount = model_->discount(paymentTime);
                        Rate strike = arguments_.floorRates[i];
                        Real mult = (type == CapFloor::Floor) ? 1.0 : -1.0;
                        value += discount * arguments_.nominals[i] * tenor
                               * mult * arguments_.gearings[i]
                               * std::max(0.0, strike - fixing);
                    }
                } else {
                    Time maturity =
                        dayCounter.yearFraction(referenceDate,
                                                arguments_.startDates[i]);
                    if (type == CapFloor::Cap || type == CapFloor::Collar) {
                        Real temp = 1.0+arguments_.capRates[i]*tenor;
                        value += arguments_.nominals[i] *
                            arguments_.gearings[i] * temp *
                            model_->discountBondOption(Option::Put, 1.0/temp,
                                                       maturity, paymentTime);
                    }
                    if (type == CapFloor::Floor || type == CapFloor::Collar) {
                        Real temp = 1.0+arguments_.floorRates[i]*tenor;
                        Real mult = (type == CapFloor::Floor) ? 1.0 : -1.0;
                        value += arguments_.nominals[i] *
                            arguments_.gearings[i] * temp * mult *
                            model_->discountBondOption(Option::Call, 1.0/temp,
                                                       maturity, paymentTime);
                    }
                }
            }
        }

        results_.value = value;
    }

}


<|start_filename|>ql/models/shortrate/twofactormodels/g2.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2001, 2002, 2003 <NAME>
 Copyright (C) 2004 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/models/shortrate/twofactormodels/g2.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/math/integrals/segmentintegral.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/math/solvers1d/brent.hpp>

namespace QuantLib {

    G2::G2(const Handle<YieldTermStructure>& termStructure,
           Real a, Real sigma, Real b, Real eta, Real rho)
    : TwoFactorModel(5), TermStructureConsistentModel(termStructure),
      a_(arguments_[0]), sigma_(arguments_[1]), b_(arguments_[2]),
      eta_(arguments_[3]), rho_(arguments_[4]) {

        a_     = ConstantParameter(a,     PositiveConstraint());
        sigma_ = ConstantParameter(sigma, PositiveConstraint());
        b_     = ConstantParameter(b,     PositiveConstraint());
        eta_   = ConstantParameter(eta,   PositiveConstraint());
        rho_   = ConstantParameter(rho,   BoundaryConstraint(-1.0, 1.0));

        generateArguments();

        registerWith(termStructure);
    }

    boost::shared_ptr<TwoFactorModel::ShortRateDynamics> G2::dynamics() const {
        return boost::shared_ptr<ShortRateDynamics>(new
            Dynamics(phi_, a(), sigma(), b(), eta(), rho()));
    }

    void G2::generateArguments() {

        phi_ = FittingParameter(termStructure(),
            a(), sigma(), b(), eta(), rho());
    }

    Real G2::sigmaP(Time t, Time s) const {
        Real temp = 1.0 - std::exp(-(a()+b())*t);
        Real temp1 = 1.0 - std::exp(-a()*(s-t));
        Real temp2 = 1.0 - std::exp(-b()*(s-t));
        Real a3 = a()*a()*a();
        Real b3 = b()*b()*b();
        Real sigma2 = sigma()*sigma();
        Real eta2 = eta()*eta();
        Real value =
            0.5*sigma2*temp1*temp1*(1.0 - std::exp(-2.0*a()*t))/a3 +
            0.5*eta2*temp2*temp2*(1.0 - std::exp(-2.0*b()*t))/b3 +
            2.0*rho()*sigma()*eta()/(a()*b()*(a()+b()))*
            temp1*temp2*temp;
        return std::sqrt(value);
    }

    Real G2::discountBond(Time t, Time T, Real x, Real y) const {
        return A(t,T) * std::exp(-B(a(),(T-t))*x-B(b(),(T-t))*y);
    }

    Real G2::discountBondOption(Option::Type type, Real strike, Time maturity,
        Time bondMaturity) const {

        Real v = sigmaP(maturity, bondMaturity);
        Real f = termStructure()->discount(bondMaturity);
        Real k = termStructure()->discount(maturity)*strike;

        return blackFormula(type, k, f, v);
    }

    Real G2::V(Time t) const {
        Real expat = std::exp(-a()*t);
        Real expbt = std::exp(-b()*t);
        Real cx = sigma()/a();
        Real cy = eta()/b();
        Real valuex = cx*cx*(t + (2.0*expat-0.5*expat*expat-1.5)/a());
        Real valuey = cy*cy*(t + (2.0*expbt-0.5*expbt*expbt-1.5)/b());
        Real value = 2.0*rho()*cx*cy* (t + (expat - 1.0)/a()
                                         + (expbt - 1.0)/b()
                                         - (expat*expbt-1.0)/(a()+b()));
        return valuex + valuey + value;
    }

    Real G2::A(Time t, Time T) const {
        return termStructure()->discount(T)/termStructure()->discount(t)*
            std::exp(0.5*(V(T-t) - V(T) + V(t)));
    }

    Real G2::B(Real x, Time t) const {
        return (1.0 - std::exp(-x*t))/x;
    }

    class G2::SwaptionPricingFunction {
      public:
        SwaptionPricingFunction(Real a, Real sigma,
                                Real b, Real eta, Real rho,
                                Real w, Real start,
                                const std::vector<Time>& payTimes,
                                Rate fixedRate, const G2& model)
        : a_(a), sigma_(sigma), b_(b), eta_(eta), rho_(rho), w_(w),
          T_(start), t_(payTimes), rate_(fixedRate), size_(t_.size()),
          A_(size_), Ba_(size_), Bb_(size_) {


            sigmax_ = sigma_*std::sqrt(0.5*(1.0-std::exp(-2.0*a_*T_))/a_);
            sigmay_ =   eta_*std::sqrt(0.5*(1.0-std::exp(-2.0*b_*T_))/b_);
            rhoxy_ = rho_*eta_*sigma_*(1.0 - std::exp(-(a_+b_)*T_))/
                ((a_+b_)*sigmax_*sigmay_);

            Real temp = sigma_*sigma_/(a_*a_);
            mux_ = -((temp+rho_*sigma_*eta_/(a_*b_))*(1.0 - std::exp(-a*T_)) -
                     0.5*temp*(1.0 - std::exp(-2.0*a_*T_)) -
                     rho_*sigma_*eta_/(b_*(a_+b_))*
                     (1.0- std::exp(-(b_+a_)*T_)));

            temp = eta_*eta_/(b_*b_);
            muy_ = -((temp+rho_*sigma_*eta_/(a_*b_))*(1.0 - std::exp(-b*T_)) -
                     0.5*temp*(1.0 - std::exp(-2.0*b_*T_)) -
                     rho_*sigma_*eta_/(a_*(a_+b_))*
                     (1.0- std::exp(-(b_+a_)*T_)));

            for (Size i=0; i<size_; i++) {
                A_[i] = model.A(T_, t_[i]);
                Ba_[i] = model.B(a_, t_[i]-T_);
                Bb_[i] = model.B(b_, t_[i]-T_);
            }
        }

        Real mux() const { return mux_; }
        Real sigmax() const { return sigmax_; }
        Real operator()(Real x) const {
            CumulativeNormalDistribution phi;
            Real temp = (x - mux_)/sigmax_;
            Real txy = std::sqrt(1.0 - rhoxy_*rhoxy_);

            Array lambda(size_);
            Size i;
            for (i=0; i<size_; i++) {
                Real tau = (i==0 ? t_[0] - T_ : t_[i] - t_[i-1]);
                Real c = (i==size_-1 ? (1.0+rate_*tau) : rate_*tau);
                lambda[i] = c*A_[i]*std::exp(-Ba_[i]*x);
            }

            SolvingFunction function(lambda, Bb_) ;
            Brent s1d;
            s1d.setMaxEvaluations(1000);
            Real yb = s1d.solve(function, 1e-6, 0.00, -100.0, 100.0);

            Real h1 = (yb - muy_)/(sigmay_*txy) -
                rhoxy_*(x  - mux_)/(sigmax_*txy);
            Real value = phi(-w_*h1);


            for (i=0; i<size_; i++) {
                Real h2 = h1 +
                    Bb_[i]*sigmay_*std::sqrt(1.0-rhoxy_*rhoxy_);
                Real kappa = - Bb_[i] *
                    (muy_ - 0.5*txy*txy*sigmay_*sigmay_*Bb_[i] +
                     rhoxy_*sigmay_*(x-mux_)/sigmax_);
                value -= lambda[i] *std::exp(kappa)*phi(-w_*h2);
            }

            return std::exp(-0.5*temp*temp)*value/
                (sigmax_*std::sqrt(2.0*M_PI));
        }


      private:
        class SolvingFunction {
          public:
            SolvingFunction(const Array& lambda, const Array& Bb)
            : lambda_(lambda), Bb_(Bb) {}
            Real operator()(Real y) const {
                Real value = 1.0;
                for (Size i=0; i<lambda_.size(); i++) {
                    value -= lambda_[i]*std::exp(-Bb_[i]*y);
                }
                return value;
            }
          private:
            const Array& lambda_;
            const Array& Bb_;
        };

        Real a_, sigma_, b_, eta_, rho_, w_;
        Time T_;
        std::vector<Time> t_;
        Rate rate_;
        Size size_;
        Array A_, Ba_, Bb_;
        Real mux_, muy_, sigmax_, sigmay_, rhoxy_;
    };

    Real G2::swaption(const Swaption::arguments& arguments,
                      Rate fixedRate, Real range, Size intervals) const {

        Date settlement = termStructure()->referenceDate();
        DayCounter dayCounter = termStructure()->dayCounter();
        Time start = dayCounter.yearFraction(settlement,
                                             arguments.floatingResetDates[0]);
        Real w = (arguments.type==VanillaSwap::Payer ? 1 : -1 );

        std::vector<Time> fixedPayTimes(arguments.fixedPayDates.size());
        for (Size i=0; i<fixedPayTimes.size(); ++i)
            fixedPayTimes[i] =
                dayCounter.yearFraction(settlement,
                                        arguments.fixedPayDates[i]);

        SwaptionPricingFunction function(a(), sigma(), b(), eta(), rho(),
                                         w, start,
                                         fixedPayTimes,
                                         fixedRate, (*this));

        Real upper = function.mux() + range*function.sigmax();
        Real lower = function.mux() - range*function.sigmax();
        SegmentIntegral integrator(intervals);
        return arguments.nominal*w*termStructure()->discount(start)*
            integrator(function, lower, upper);
    }

}



<|start_filename|>ql/instruments/forward.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file forward.hpp
    \brief Base forward class
*/

#ifndef quantlib_forward_hpp
#define quantlib_forward_hpp

#include <ql/instrument.hpp>
#include <ql/position.hpp>
#include <ql/time/calendar.hpp>
#include <ql/time/daycounter.hpp>
#include <ql/interestrate.hpp>
#include <ql/types.hpp>
#include <ql/handle.hpp>
#include <ql/payoff.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>

namespace QuantLib {

    //! Abstract base forward class
    /*! Derived classes must implement the virtual functions
        spotValue() (NPV or spot price) and spotIncome() associated
        with the specific relevant underlying (e.g. bond, stock,
        commodity, loan/deposit). These functions must be used to set the
        protected member variables underlyingSpotValue_ and
        underlyingIncome_ within performCalculations() in the derived
        class before the base-class implementation is called.

        spotIncome() refers generically to the present value of
        coupons, dividends or storage costs.

        discountCurve_ is the curve used to discount forward contract
        cash flows back to the evaluation day, as well as to obtain
        forward values for spot values/prices.

        incomeDiscountCurve_, which for generality is not
        automatically set to the discountCurve_, is the curve used to
        discount future income/dividends/storage-costs etc back to the
        evaluation date.

        \todo Add preconditions and tests

        \warning This class still needs to be rigorously tested

        \ingroup instruments
    */
    class Forward : public Instrument {
      public:
        //! \name Inspectors
        //@{
        virtual Date settlementDate() const;
        const Calendar& calendar() const;
        BusinessDayConvention businessDayConvention() const;
        const DayCounter& dayCounter() const;
        //! term structure relevant to the contract (e.g. repo curve)
        Handle<YieldTermStructure> discountCurve() const;
        //! term structure that discounts the underlying's income cash flows
        Handle<YieldTermStructure> incomeDiscountCurve() const;
        //! returns whether the instrument is still tradable.
        bool isExpired() const;
        //@}

        //! returns spot value/price of an underlying financial instrument
        virtual Real spotValue() const = 0;
        //! NPV of income/dividends/storage-costs etc. of underlying instrument
        virtual Real spotIncome(const Handle<YieldTermStructure>&
                                               incomeDiscountCurve) const = 0;

        //! \name Calculations
        //@{
        //! forward value/price of underlying, discounting income/dividends
        /*! \note if this is a bond forward price, is must be a dirty
                  forward price.
        */
        virtual Real forwardValue() const;

        /*! Simple yield calculation based on underlying spot and
            forward values, taking into account underlying income.
            When \f$ t>0 \f$, call with:
            underlyingSpotValue=spotValue(t),
            forwardValue=strikePrice, to get current yield. For a
            repo, if \f$ t=0 \f$, impliedYield should reproduce the
            spot repo rate. For FRA's, this should reproduce the
            relevant zero rate at the FRA's maturityDate_;
        */
        InterestRate impliedYield(Real underlyingSpotValue,
                                  Real forwardValue,
                                  Date settlementDate,
                                  Compounding compoundingConvention,
                                  DayCounter dayCounter);
        //@}
      protected:
        Forward(const DayCounter& dayCounter,
                const Calendar& calendar,
                BusinessDayConvention businessDayConvention,
                Natural settlementDays,
                const boost::shared_ptr<Payoff>& payoff,
                const Date& valueDate,
                const Date& maturityDate,
                const Handle<YieldTermStructure>& discountCurve =
                                                Handle<YieldTermStructure>());

        void performCalculations() const;
        /*! derived classes must set this, typically via spotIncome() */
        mutable Real underlyingIncome_;
        /*! derived classes must set this, typically via spotValue() */
        mutable Real underlyingSpotValue_;

        DayCounter dayCounter_;
        Calendar calendar_;
        BusinessDayConvention businessDayConvention_;
        Natural settlementDays_;
        boost::shared_ptr<Payoff> payoff_;
        /*! valueDate = settlement date (date the fwd contract starts
            accruing)
        */
        Date valueDate_;
        //! maturityDate of the forward contract or delivery date of underlying
        Date maturityDate_;
        Handle<YieldTermStructure> discountCurve_;
        /*! must set this in derived classes, based on particular underlying */
        Handle<YieldTermStructure> incomeDiscountCurve_;
    };


    //! Class for forward type payoffs
    class ForwardTypePayoff : public Payoff {
      public:
        ForwardTypePayoff(Position::Type type, Real strike)
        : type_(type),strike_(strike) {
            QL_REQUIRE(strike >= 0.0,"negative strike given");
        }
        Position::Type forwardType() const { return type_; };
        Real strike() const { return strike_; };
        //! \name Payoff interface
        //@{
        std::string name() const { return "Forward";}
        std::string description() const;
        Real operator()(Real price) const;
        //@}
      protected:
        Position::Type type_;
        Real strike_;
    };



    // inline definitions

    inline const Calendar& Forward::calendar() const {
        return calendar_;
    }

    inline BusinessDayConvention Forward::businessDayConvention() const {
        return businessDayConvention_;
    }

    inline const DayCounter& Forward::dayCounter() const {
        return dayCounter_;
    }

    inline Handle<YieldTermStructure> Forward::discountCurve() const {
        return discountCurve_;
    }

    inline Handle<YieldTermStructure> Forward::incomeDiscountCurve() const {
        return incomeDiscountCurve_;
    }


    inline std::string ForwardTypePayoff::description() const {
        std::ostringstream result;
        result << name() << ", " << strike() << " strike";
        return result.str();
    }

    inline Real ForwardTypePayoff::operator()(Real price) const {
        switch (type_) {
          case Position::Long:
            return (price-strike_);
          case Position::Short:
            return (strike_-price);
          default:
            QL_FAIL("unknown/illegal position type");
        }
    }

}


#endif



<|start_filename|>ql/experimental/finitedifferences/squarerootprocessrndcalculator.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2015 <NAME>
 Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/


#include <ql/experimental/finitedifferences/squarerootprocessrndcalculator.hpp>

#include <boost/math/distributions/non_central_chi_squared.hpp>

namespace QuantLib {

    SquareRootProcessRNDCalculator::SquareRootProcessRNDCalculator(
        Real v0, Real kappa, Real theta, Real sigma)
    : v0_(v0), kappa_(kappa), theta_(theta),
      d_(4*kappa/(sigma*sigma)), df_(d_*theta) {    }


    Real SquareRootProcessRNDCalculator::pdf(Real v, Time t) const {
        const Real e   = std::exp(-kappa_*t);
        const Real k   = d_/(1-e);
        const Real ncp = k*v0_*e;

        const boost::math::non_central_chi_squared_distribution<Real>
            dist(df_, ncp);

        return boost::math::pdf(dist, v*k) * k;
    }

    Real SquareRootProcessRNDCalculator::cdf(Real v, Time t) const {
        const Real e   = std::exp(-kappa_*t);
        const Real k   = d_/(1-e);
        const Real ncp = k*v0_*e;

        const boost::math::non_central_chi_squared_distribution<Real>
            dist(df_, ncp);

        return boost::math::cdf(dist, v*k);
    }

    Real SquareRootProcessRNDCalculator::invcdf(Real q, Time t) const {
        const Real e   = std::exp(-kappa_*t);
        const Real k   = d_/(1-e);
        const Real ncp = k*v0_*e;

        const boost::math::non_central_chi_squared_distribution<Real>
            dist(df_, ncp);

        return boost::math::quantile(dist, q) / k;
    }

    Real SquareRootProcessRNDCalculator::stationary_pdf(Real v) const {
        const Real alpha = 0.5*df_;
        const Real beta = alpha/theta_;

        return std::pow(beta, alpha)*std::pow(v, alpha-1)
                *std::exp(-beta*v-boost::math::lgamma(alpha));
    }

    Real SquareRootProcessRNDCalculator::stationary_cdf(Real v) const {
        const Real alpha = 0.5*df_;
        const Real beta = alpha/theta_;

        return boost::math::gamma_p(alpha, beta*v);
    }

    Real SquareRootProcessRNDCalculator::stationary_invcdf(Real q) const {
        const Real alpha = 0.5*df_;
        const Real beta = alpha/theta_;

        return boost::math::gamma_p_inv(alpha, q)/beta;
    }
}


<|start_filename|>ql/indexes/ibor/cdor.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2005 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file cdor.hpp
    \brief %CDOR rate
*/

#ifndef quantlib_cdor_hpp
#define quantlib_cdor_hpp

#include <ql/indexes/iborindex.hpp>
#include <ql/time/calendars/canada.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/currencies/america.hpp>

namespace QuantLib {

    //! %CDOR rate
    /*! Canadian Dollar Offered Rate fixed by IDA.

        \warning This is the rate fixed in Canada by IDA. Use CADLibor
                 if you're interested in the London fixing by BBA.

        \todo check settlement days, end-of-month adjustment,
              and day-count convention.
    */
    class Cdor : public IborIndex {
      public:
        Cdor(const Period& tenor,
             const Handle<YieldTermStructure>& h =
                                    Handle<YieldTermStructure>())
        : IborIndex("CDOR", tenor, 2, CADCurrency(),
                    Canada(), ModifiedFollowing, false,
                    Actual360(), h) {}
    };

}


#endif


<|start_filename|>ql/instruments/vanillaswingoption.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010, 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file vanillaswingoption.cpp
    \brief vanilla swing option class
*/


#include <ql/event.hpp>
#include <ql/instruments/vanillaswingoption.hpp>

namespace QuantLib {

    namespace {
        const Size secPerDay = 24u*3600u;

        std::pair<std::vector<Date>, std::vector<Size> >
            createDateTimes(const Date& from, const Date& to, Size stepSize) {

            std::vector<Size> secs;
            std::vector<Date> dates;

            Date iterDate = from;
            Size iterStepSize = 0u;

            while (iterDate <= to) {
                dates.push_back(iterDate);
                secs.push_back(iterStepSize);

                iterStepSize+=stepSize;
                if (iterStepSize >= secPerDay) {
                    iterDate+=1L;
                    iterStepSize%=secPerDay;
                }
            }

            return std::pair<std::vector<Date>,std::vector<Size> >(dates, secs);
        }
    }

    SwingExercise::SwingExercise(const std::vector<Date>& dates,
                                 const std::vector<Size>& seconds)
    : BermudanExercise(dates),
      seconds_(seconds.empty() ? std::vector<Size>(dates.size(), 0u)
                               : seconds) {
        QL_REQUIRE(dates_.size() == seconds_.size(),
                   "dates and seconds must have the same size");
        for (Size i=0; i < dates_.size(); ++i) {
            QL_REQUIRE(seconds_[i] < secPerDay,
                       "a date can not have more than 24*3600 seconds");
            if (i > 0) {
                QL_REQUIRE(dates_[i-1] < dates_[i]
                           || (dates_[i-1] == dates_[i]
                               && seconds_[i-1] < seconds_[i]),
                           "date times must be sorted");
            }
        }
    }


    SwingExercise::SwingExercise(const Date& from,
                                 const Date& to, Size stepSizeSecs)
    : BermudanExercise(createDateTimes(from, to, stepSizeSecs).first),
      seconds_(createDateTimes(from, to, stepSizeSecs).second) {
    }

    const std::vector<Size>& SwingExercise::seconds() const { return seconds_; }

    std::vector<Time> SwingExercise::exerciseTimes(const DayCounter& dc,
                                                   const Date& refDate) const {
        std::vector<Time> exerciseTimes;
        exerciseTimes.reserve(dates().size());
        for (Size i=0; i<dates().size(); ++i) {
            Time t = dc.yearFraction(refDate, dates()[i]);

            const Time dt
                = dc.yearFraction(refDate, dates()[i]+Period(1u, Days)) - t;

            t += dt*seconds()[i]/(24*3600.);

            QL_REQUIRE(t >= 0, "exercise dates must not contain past date");
            exerciseTimes.push_back(t);
        }

        return exerciseTimes;
    }

    void VanillaSwingOption::arguments::validate() const {
        QL_REQUIRE(payoff, "no payoff given");
        QL_REQUIRE(exercise, "no exercise given");

        QL_REQUIRE(minExerciseRights <= maxExerciseRights,
                   "minExerciseRights <= maxExerciseRights")
        QL_REQUIRE(exercise->dates().size() >= maxExerciseRights,
                   "number of exercise rights exceeds "
                   "number of exercise dates");
    }

    void VanillaSwingOption::setupArguments(
                            PricingEngine::arguments* args) const {
        VanillaSwingOption::arguments* arguments =
            dynamic_cast<VanillaSwingOption::arguments*>(args);
        QL_REQUIRE(arguments != 0, "wrong argument type");

        arguments->payoff
            = boost::dynamic_pointer_cast<StrikedTypePayoff>(payoff_);
        arguments->exercise
            = boost::dynamic_pointer_cast<SwingExercise>(exercise_);
        arguments->minExerciseRights = minExerciseRights_;
        arguments->maxExerciseRights = maxExerciseRights_;
    }

    bool VanillaSwingOption::isExpired() const {
        return detail::simple_event(exercise_->lastDate()).hasOccurred();
    }
}


<|start_filename|>ql/methods/finitedifferences/solvers/fdmhestonsolver.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008, 2009 <NAME>
 Copyright (C) 2008, 2009, 2011, 2014, 2015 <NAME>
 Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/processes/hestonprocess.hpp>
#include <ql/methods/finitedifferences/operators/fdmhestonop.hpp>
#include <ql/methods/finitedifferences/solvers/fdm2dimsolver.hpp>
#include <ql/methods/finitedifferences/solvers/fdmhestonsolver.hpp>

namespace QuantLib {

    FdmHestonSolver::FdmHestonSolver(
        const Handle<HestonProcess>& process,
        const FdmSolverDesc& solverDesc,
        const FdmSchemeDesc& schemeDesc,
        const Handle<FdmQuantoHelper>& quantoHelper,
        const boost::shared_ptr<LocalVolTermStructure>& leverageFct)
    : process_(process),
      solverDesc_(solverDesc),
      schemeDesc_(schemeDesc),
      quantoHelper_(quantoHelper),
      leverageFct_(leverageFct){

        registerWith(process_);
        registerWith(quantoHelper_);
    }

    void FdmHestonSolver::performCalculations() const {
        boost::shared_ptr<FdmLinearOpComposite> op(
            new FdmHestonOp(
                solverDesc_.mesher, process_.currentLink(),
                (!quantoHelper_.empty()) ? quantoHelper_.currentLink()
                             : boost::shared_ptr<FdmQuantoHelper>(),
                leverageFct_));

        solver_ = boost::shared_ptr<Fdm2DimSolver>(
                               new Fdm2DimSolver(solverDesc_, schemeDesc_, op));
    }

    Real FdmHestonSolver::valueAt(Real s, Real v) const {
        calculate();
        return solver_->interpolateAt(std::log(s), v);
    }

    Real FdmHestonSolver::deltaAt(Real s, Real v) const {
        calculate();
        return solver_->derivativeX(std::log(s), v)/s;
    }

    Real FdmHestonSolver::gammaAt(Real s, Real v) const {
        calculate();
        const Real x = std::log(s);
        return (solver_->derivativeXX(x, v)-solver_->derivativeX(x, v))/(s*s);
    }

    Real FdmHestonSolver::meanVarianceDeltaAt(Real s, Real v) const {
        calculate();

        const Real alpha = process_->rho()*process_->sigma()/s;
        return deltaAt(s, v) + alpha*solver_->derivativeY(std::log(s), v);
    }

    Real FdmHestonSolver::meanVarianceGammaAt(Real s, Real v) const {
        calculate();

        const Real x = std::log(s);
        const Real alpha = process_->rho()*process_->sigma()/s;
        return gammaAt(s, v)
                +  solver_->derivativeYY(x, v)*alpha*alpha
                +2*solver_->derivativeXY(x, v)*alpha/s;
    }

    Real FdmHestonSolver::thetaAt(Real s, Real v) const {
        calculate();
        return solver_->thetaAt(std::log(s), v);
    }
}


<|start_filename|>ql/math/distributions/studenttdistribution.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file studenttdistribution.hpp
    \brief Student's t-distribution
*/

#ifndef quantlib_student_t_distribution_hpp
#define quantlib_student_t_distribution_hpp

#include <ql/errors.hpp>
#include <ql/types.hpp>
#include <functional>

namespace QuantLib {

    //! Student t-distribution
    /*! Probability density function for \f$ n \f$ degrees of freedom
        (see mathworld.wolfram.com or wikipedia.org):
        \f[
        f(x) = \frac {\Gamma\left(\frac{n+1}{2}\right)} {\sqrt{n\pi}
        \, \Gamma\left(\frac{n}{2}\right)}\:
        \frac {1} {\left(1+\frac{x^2}{n}\right)^{(n+1)/2}}
        \f]
    */
    class StudentDistribution : public std::unary_function<Real,Real> {
      public:
        StudentDistribution(Integer n) : n_(n) {
            QL_REQUIRE(n > 0, "invalid parameter for t-distribution");
        }
        Real operator()(Real x) const;
      private:
        Integer n_;
    };

    //! Cumulative Student t-distribution
    /*! Cumulative distribution function for \f$ n \f$ degrees of freedom
        (see mathworld.wolfram.com):
        \f[
        F(x) = \int_{-\infty}^x\,f(y)\,dy
        = \frac{1}{2}\,
        +\,\frac{1}{2}\,sgn(x)\,
        \left[ I\left(1,\frac{n}{2},\frac{1}{2}\right)
        - I\left(\frac{n}{n+y^2}, \frac{n}{2},\frac{1}{2}\right)\right]
        \f]
        where \f$ I(z; a, b) \f$ is the regularized incomplete beta function.
    */
    class CumulativeStudentDistribution
        : public std::unary_function<Real,Real> {
      public:
        CumulativeStudentDistribution(Integer n) : n_(n) {
            QL_REQUIRE(n > 0, "invalid parameter for t-distribution");
        }
        Real operator()(Real x) const;
      private:
        Integer n_;
    };

    //! Inverse cumulative Student t-distribution
    /*! \todo Find/implement an efficient algorithm for evaluating the
              cumulative Student t-distribution, replacing the Newton
              iteration
    */
    class InverseCumulativeStudent
        : public std::unary_function<Real,Real> {
      public:
        InverseCumulativeStudent(Integer n,
                                 Real accuracy = 1e-6,
                                 Size maxIterations = 50)
        : d_(n), f_(n), accuracy_(accuracy),
          maxIterations_(maxIterations) {}
        Real operator()(Real x) const;
      private:
        StudentDistribution d_;
        CumulativeStudentDistribution f_;
        Real accuracy_;
        Size maxIterations_;
    };

}

#endif


<|start_filename|>ql/experimental/coupons/digitalcmsspreadcoupon.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file digitalcmsspreadcoupon.hpp
    \brief Cms-spread-rate coupon with digital call/put option
*/

#ifndef quantlib_digital_cmsspread_coupon_hpp
#define quantlib_digital_cmsspread_coupon_hpp

#include <ql/cashflows/digitalcoupon.hpp>
#include <ql/experimental/coupons/cmsspreadcoupon.hpp>
#include <ql/time/schedule.hpp>

namespace QuantLib {

    //! Cms-spread-rate coupon with digital digital call/put option
    class DigitalCmsSpreadCoupon : public DigitalCoupon {
      public:
        DigitalCmsSpreadCoupon(
            const boost::shared_ptr<CmsSpreadCoupon> &underlying,
            Rate callStrike = Null<Rate>(),
            Position::Type callPosition = Position::Long,
            bool isCallATMIncluded = false,
            Rate callDigitalPayoff = Null<Rate>(),
            Rate putStrike = Null<Rate>(),
            Position::Type putPosition = Position::Long,
            bool isPutATMIncluded = false,
            Rate putDigitalPayoff = Null<Rate>(),
            const boost::shared_ptr<DigitalReplication> &replication =
                boost::shared_ptr<DigitalReplication>(new DigitalReplication));

        //! \name Visitability
        //@{
        virtual void accept(AcyclicVisitor&);
        //@}
    };


    //! helper class building a sequence of digital ibor-rate coupons
    class DigitalCmsSpreadLeg {
      public:
        DigitalCmsSpreadLeg(const Schedule& schedule,
                      const boost::shared_ptr<SwapSpreadIndex>& index);
        DigitalCmsSpreadLeg& withNotionals(Real notional);
        DigitalCmsSpreadLeg& withNotionals(const std::vector<Real>& notionals);
        DigitalCmsSpreadLeg& withPaymentDayCounter(const DayCounter&);
        DigitalCmsSpreadLeg& withPaymentAdjustment(BusinessDayConvention);
        DigitalCmsSpreadLeg& withFixingDays(Natural fixingDays);
        DigitalCmsSpreadLeg& withFixingDays(const std::vector<Natural>& fixingDays);
        DigitalCmsSpreadLeg& withGearings(Real gearing);
        DigitalCmsSpreadLeg& withGearings(const std::vector<Real>& gearings);
        DigitalCmsSpreadLeg& withSpreads(Spread spread);
        DigitalCmsSpreadLeg& withSpreads(const std::vector<Spread>& spreads);
        DigitalCmsSpreadLeg& inArrears(bool flag = true);
        DigitalCmsSpreadLeg& withCallStrikes(Rate strike);
        DigitalCmsSpreadLeg& withCallStrikes(const std::vector<Rate>& strikes);
        DigitalCmsSpreadLeg& withLongCallOption(Position::Type);
        DigitalCmsSpreadLeg& withCallATM(bool flag = true);
        DigitalCmsSpreadLeg& withCallPayoffs(Rate payoff);
        DigitalCmsSpreadLeg& withCallPayoffs(const std::vector<Rate>& payoffs);
        DigitalCmsSpreadLeg& withPutStrikes(Rate strike);
        DigitalCmsSpreadLeg& withPutStrikes(const std::vector<Rate>& strikes);
        DigitalCmsSpreadLeg& withLongPutOption(Position::Type);
        DigitalCmsSpreadLeg& withPutATM(bool flag = true);
        DigitalCmsSpreadLeg& withPutPayoffs(Rate payoff);
        DigitalCmsSpreadLeg& withPutPayoffs(const std::vector<Rate>& payoffs);
        DigitalCmsSpreadLeg& withReplication(
            const boost::shared_ptr<DigitalReplication> &replication =
                boost::shared_ptr<DigitalReplication>(new DigitalReplication));

        operator Leg() const;
      private:
        Schedule schedule_;
        boost::shared_ptr<SwapSpreadIndex> index_;
        std::vector<Real> notionals_;
        DayCounter paymentDayCounter_;
        BusinessDayConvention paymentAdjustment_;
        std::vector<Natural> fixingDays_;
        std::vector<Real> gearings_;
        std::vector<Spread> spreads_;
        bool inArrears_;
        std::vector<Rate> callStrikes_, callPayoffs_;
        Position::Type longCallOption_;
        bool callATM_;
        std::vector<Rate> putStrikes_, putPayoffs_;
        Position::Type longPutOption_;
        bool putATM_;
        boost::shared_ptr<DigitalReplication> replication_;
    };

}


#endif


<|start_filename|>ql/math/autocovariance.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010 <NAME>, Inc.

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file autocovariance.hpp
    \brief autocovariance and convolution calculation
*/

#ifndef quantlib_auto_covariance_hpp
#define quantlib_auto_covariance_hpp

#include <ql/math/fastfouriertransform.hpp>
#include <ql/math/array.hpp>
#include <complex>
#include <vector>
#include <algorithm>
#include <functional>

namespace QuantLib {

    namespace detail {

        // Outputs double FT for a given input:
        // input -> FFT -> norm -> FFT -> out
        template <typename ForwardIterator>
        std::vector<std::complex<Real> > double_ft(ForwardIterator begin,
                                                   ForwardIterator end) {
            std::size_t nData = std::distance(begin, end);
            std::size_t order = FastFourierTransform::min_order(nData) + 1;
            FastFourierTransform fft(order);
            std::vector<std::complex<Real> > ft(fft.output_size());
            fft.transform(begin, end, ft.begin());
            Array tmp(ft.size(), 0.0);
            std::complex<Real> z = std::complex<Real>();
            for (Size i=0; i<ft.size(); ++i) {
                tmp[i] = std::norm<Real>(ft[i]);
                ft[i] = z;
            }
            fft.transform(tmp.begin(), tmp.end(), ft.begin());
            return ft;
        }


        // Calculates and subtracts mean from the input data; returns mean
        template <typename InputIterator, typename OutputIterator>
        Real remove_mean(InputIterator begin, InputIterator end,
                         OutputIterator out) {
            Real mean(0.0);
            std::size_t n = 1;
            for (InputIterator it = begin; it != end; ++it, ++n)
                mean = (mean*Real(n-1) + *it)/n;
            std::transform(begin, end, out,
                           std::bind2nd(std::minus<Real>(), mean));
            return mean;
        }

    }


    //! Convolutions of the input sequence.
    /*! Calculates x[0]*x[n]+x[1]*x[n+1]+x[2]*x[n+2]+...
        for n = 0,1,...,maxLag via FFT.

        \pre The size of the output sequence must be maxLag + 1
    */
    template <typename ForwardIterator, typename OutputIterator>
    void convolutions(ForwardIterator begin, ForwardIterator end,
                      OutputIterator out, std::size_t maxLag) {
        using namespace detail;
        std::size_t nData = std::distance(begin, end);
        QL_REQUIRE(maxLag < nData, "maxLag must be less than data size");
        const std::vector<std::complex<Real> >& ft = double_ft(begin, end);
        Real w = 1.0 / (Real)ft.size();
        for (std::size_t k = 0; k <= maxLag; ++k)
            *out++ = ft[k].real() * w;
    }

    //! Unbiased auto-covariances
    /*! Results are calculated via FFT.

        \pre Input data are supposed to be centered (i.e., zero mean).
        \pre The size of the output sequence must be maxLag + 1
    */
    template <typename ForwardIterator, typename OutputIterator>
    void autocovariances(ForwardIterator begin, ForwardIterator end,
                         OutputIterator out, std::size_t maxLag) {
        using namespace detail;
        std::size_t nData = std::distance(begin, end);
        QL_REQUIRE(maxLag < nData,
                   "number of covariances must be less than data size");
        const std::vector<std::complex<Real> >& ft = double_ft(begin, end);
        Real w1 = 1.0 / (Real)ft.size(), w2 = (Real)nData;
        for (std::size_t k = 0; k <= maxLag; ++k, w2 -= 1.0) {
            *out++ = ft[k].real() * w1 / w2;
        }
    }

    //! Unbiased auto-covariances
    /*! Results are calculated via FFT.

        This overload accepts non-centered data, removes the mean and
        returns it as a result.  The centered sequence is written back
        into the input sequence if the reuse parameter is true.

        \pre The size of the output sequence must be maxLag + 1
    */
    template <typename ForwardIterator, typename OutputIterator>
    Real autocovariances(ForwardIterator begin, ForwardIterator end,
                         OutputIterator out,
                         std::size_t maxLag, bool reuse) {
        using namespace detail;
        Real mean = 0.0;
        if (reuse) {
            mean = remove_mean(begin, end, begin);
            autocovariances(begin, end, out, maxLag);
        } else {
            Array tmp(std::distance(begin, end));
            mean = remove_mean(begin, end, tmp.begin());
            autocovariances(tmp.begin(), tmp.end(), out, maxLag);
        }
        return mean;
    }


    //! Unbiased auto-correlations.
    /*! Results are calculated via FFT.
        The first element of the output is the unbiased sample variance.

        \pre Input data are supposed to be centered (i.e., zero mean).
        \pre The size of the output sequence must be maxLag + 1
    */
    template <typename ForwardIterator, typename OutputIterator>
    void autocorrelations(ForwardIterator begin, ForwardIterator end,
                          OutputIterator out, std::size_t maxLag) {
        using namespace detail;
        std::size_t nData = std::distance(begin, end);
        QL_REQUIRE(maxLag < nData,
                   "number of correlations must be less than data size");
        const std::vector<std::complex<Real> >& ft = double_ft(begin, end);
        Real w1 = 1.0 / (Real)ft.size(), w2 = (Real)nData;
        Real variance = ft[0].real() * w1 / w2;
        *out++ = variance * w2 / (w2-1.0);
        w2 -= 1.0;
        for (std::size_t k = 1; k <= maxLag; ++k, w2 -= 1.0)
            *out++ = ft[k].real() * w1 / (variance * w2);
    }

    //! Unbiased auto-correlations.
    /*! Results are calculated via FFT.
        The first element of the output is the unbiased sample variance.

        This overload accepts non-centered data, removes the mean and
        returns it as a result.  The centered sequence is written back
        into the input sequence if the reuse parameter is true.

        \pre The size of the output sequence must be maxLag + 1
    */
    template <typename ForwardIterator, typename OutputIterator>
    Real autocorrelations(ForwardIterator begin, ForwardIterator end,
                          OutputIterator out,
                          std::size_t maxLag, bool reuse) {
        using namespace detail;
        Real mean = 0.0;
        if (reuse) {
            mean = remove_mean(begin, end, begin);
            autocorrelations(begin, end, out, maxLag);
        } else {
            Array tmp(std::distance(begin, end));
            mean = remove_mean(begin, end, tmp.begin());
            autocorrelations(tmp.begin(), tmp.end(), out, maxLag);
        }
        return mean;
    }

}

#endif


<|start_filename|>ql/indexes/ibor/libor.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2007 <NAME>
 Copyright (C) 2007 <NAME>
 Copyright (C) 2005, 2006, 2008 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/indexes/ibor/libor.hpp>
#include <ql/time/calendars/jointcalendar.hpp>
#include <ql/time/calendars/unitedkingdom.hpp>
#include <ql/currencies/europe.hpp>

namespace QuantLib {

    namespace {

        BusinessDayConvention liborConvention(const Period& p) {
            switch (p.units()) {
              case Days:
              case Weeks:
                return Following;
              case Months:
              case Years:
                return ModifiedFollowing;
              default:
                QL_FAIL("invalid time units");
            }
        }

        bool liborEOM(const Period& p) {
            switch (p.units()) {
              case Days:
              case Weeks:
                return false;
              case Months:
              case Years:
                return true;
              default:
                QL_FAIL("invalid time units");
            }
        }

    }


    Libor::Libor(const std::string& familyName,
                 const Period& tenor,
                 Natural settlementDays,
                 const Currency& currency,
                 const Calendar& financialCenterCalendar,
                 const DayCounter& dayCounter,
                 const Handle<YieldTermStructure>& h)
    : IborIndex(familyName, tenor, settlementDays, currency,
                // http://www.bba.org.uk/bba/jsp/polopoly.jsp?d=225&a=1412 :
                // UnitedKingdom::Exchange is the fixing calendar for
                // a) all currencies but EUR
                // b) all indexes but o/n and s/n
                UnitedKingdom(UnitedKingdom::Exchange),
                liborConvention(tenor), liborEOM(tenor),
                dayCounter, h),
      financialCenterCalendar_(financialCenterCalendar),
      jointCalendar_(JointCalendar(UnitedKingdom(UnitedKingdom::Exchange),
                                   financialCenterCalendar,
                                   JoinHolidays)) {
        QL_REQUIRE(this->tenor().units()!=Days,
                   "for daily tenors (" << this->tenor() <<
                   ") dedicated DailyTenor constructor must be used");
        QL_REQUIRE(currency!=EURCurrency(),
                   "for EUR Libor dedicated EurLibor constructor must be used");
    }

    Date Libor::valueDate(const Date& fixingDate) const {

        QL_REQUIRE(isValidFixingDate(fixingDate),
                   "Fixing date " << fixingDate << " is not valid");

        // http://www.bba.org.uk/bba/jsp/polopoly.jsp?d=225&a=1412 :
        // For all currencies other than EUR and GBP the period between
        // Fixing Date and Value Date will be two London business days
        // after the Fixing Date, or if that day is not both a London
        // business day and a business day in the principal financial centre
        // of the currency concerned, the next following day which is a
        // business day in both centres shall be the Value Date.
        Date d = fixingCalendar().advance(fixingDate, fixingDays_, Days);
        return jointCalendar_.adjust(d);
    }

    Date Libor::maturityDate(const Date& valueDate) const {
        // Where a deposit is made on the final business day of a
        // particular calendar month, the maturity of the deposit shall
        // be on the final business day of the month in which it matures
        // (not the corresponding date in the month of maturity). Or in
        // other words, in line with market convention, BBA LIBOR rates
        // are dealt on an end-end basis. For instance a one month
        // deposit for value 28th February would mature on 31st March,
        // not the 28th of March.
        return jointCalendar_.advance(valueDate, tenor_, convention_,
                                                         endOfMonth());
    }

    Calendar Libor::jointCalendar() const {
        return jointCalendar_;
    }

    boost::shared_ptr<IborIndex> Libor::clone(
                                  const Handle<YieldTermStructure>& h) const {
        return boost::shared_ptr<IborIndex>(new Libor(familyName(),
                                                      tenor(),
                                                      fixingDays(),
                                                      currency(),
                                                      financialCenterCalendar_,
                                                      dayCounter(),
                                                      h));
    }


    DailyTenorLibor::DailyTenorLibor(
                 const std::string& familyName,
                 Natural settlementDays,
                 const Currency& currency,
                 const Calendar& financialCenterCalendar,
                 const DayCounter& dayCounter,
                 const Handle<YieldTermStructure>& h)
    : IborIndex(familyName, 1*Days, settlementDays, currency,
                // http://www.bba.org.uk/bba/jsp/polopoly.jsp?d=225&a=1412 :
                // no o/n or s/n fixings (as the case may be) will take place
                // when the principal centre of the currency concerned is
                // closed but London is open on the fixing day.
                JointCalendar(UnitedKingdom(UnitedKingdom::Exchange),
                              financialCenterCalendar,
                              JoinHolidays),
                liborConvention(1*Days), liborEOM(1*Days),
                dayCounter, h) {
        QL_REQUIRE(currency!=EURCurrency(),
                   "for EUR Libor dedicated EurLibor constructor must be used");
    }

}


<|start_filename|>ql/experimental/mcbasket/longstaffschwartzmultipathpricer.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/math/generallinearleastsquares.hpp>
#include <ql/experimental/mcbasket/longstaffschwartzmultipathpricer.hpp>
#include <ql/utilities/tracing.hpp>

namespace QuantLib {

    LongstaffSchwartzMultiPathPricer::PathInfo::PathInfo(Size numberOfTimes)
        : payments(numberOfTimes, 0.0),
          exercises(numberOfTimes, 0.0),
          states(numberOfTimes) {
    }

    Size LongstaffSchwartzMultiPathPricer::PathInfo::pathLength() const {
        return states.size();
    }


    LongstaffSchwartzMultiPathPricer::LongstaffSchwartzMultiPathPricer(
        const boost::shared_ptr<PathPayoff>& payoff,
        const std::vector<Size> & timePositions,
        const std::vector<Handle<YieldTermStructure> > & forwardTermStructures,
        const Array & discounts,
        Size polynomOrder,
        LsmBasisSystem::PolynomType polynomType)
    : calibrationPhase_(true),
      payoff_(payoff),
      coeff_     (new Array[timePositions.size() - 1]),
      lowerBounds_(new Real[timePositions.size()]),
      timePositions_(timePositions),
      forwardTermStructures_(forwardTermStructures),
      dF_        (discounts),
      v_         (LsmBasisSystem::multiPathBasisSystem(payoff->basisSystemDimension(),
                                                       polynomOrder,
                                                       polynomType)) {
        QL_REQUIRE(   polynomType == LsmBasisSystem::Monomial
                   || polynomType == LsmBasisSystem::Laguerre
                   || polynomType == LsmBasisSystem::Hermite
                   || polynomType == LsmBasisSystem::Hyperbolic
                   || polynomType == LsmBasisSystem::Chebyshev2nd,
                   "insufficient polynom type");
    }

    /*
      Extract the relevant information from the whole path
     */
    LongstaffSchwartzMultiPathPricer::PathInfo 
    LongstaffSchwartzMultiPathPricer::transformPath(const MultiPath& multiPath)
    const {
        const Size numberOfAssets = multiPath.assetNumber();
        const Size numberOfTimes = timePositions_.size();

        Matrix path(numberOfAssets, numberOfTimes, Null<Real>());

        for (Size i = 0; i < numberOfTimes; ++i) {
            const Size pos = timePositions_[i];
            for (Size j = 0; j < numberOfAssets; ++j)
                path[j][i] = multiPath[j][pos];
        }
        
        PathInfo info(numberOfTimes);

        payoff_->value(path, forwardTermStructures_, info.payments, info.exercises, info.states);

        return info;
    }

    Real LongstaffSchwartzMultiPathPricer::operator()(
                                            const MultiPath& multiPath) const {
        PathInfo path = transformPath(multiPath);

        if (calibrationPhase_) {
            // store paths for the calibration
            // only the relevant part
            paths_.push_back(path);
            // result doesn't matter
            return 0.0;
        }

        // exercise at time t, cancels all payment AFTER t

        const Size len = path.pathLength();
        Real price = 0.0;

        // this is the last event date
        {
            const Real payoff = path.payments[len - 1];
            const Real exercise = path.exercises[len - 1];
            const Array & states = path.states[len - 1];
            const bool canExercise = !states.empty();

            // at the end the continuation value is 0.0
            if (canExercise && exercise > 0.0)
                price += exercise;
            price += payoff;
        }

        for (Integer i = len - 2; i >= 0; --i) {
            price *= dF_[i + 1] / dF_[i];

            const Real exercise = path.exercises[i];

            /*
              coeff_[i].size()
              - 0 => never exercise
              - v_.size() => use estimated continuation value 
                (if > lowerBounds_[i])
              - v_.size() + 1 => always exercise

              In any case if states is empty, no exercise is allowed.
             */
            const Array & states = path.states[i];
            const bool canExercise = !states.empty();

            if (canExercise) {
                if (coeff_[i].size() == v_.size() + 1) {   
                    // special value always exercise
                    price = exercise;
                }
                else {
                    if (!coeff_[i].empty() && exercise > lowerBounds_[i]) {
                        
                        Real continuationValue = 0.0;
                        for (Size l = 0; l < v_.size(); ++l) {
                            continuationValue += coeff_[i][l] * v_[l](states);
                        }
                        
                        if (continuationValue < exercise) {
                            price = exercise;
                        }
                    }
                }
            }
            const Real payoff = path.payments[i];
            price += payoff;
        }

        return price * dF_[0];
    }

    void LongstaffSchwartzMultiPathPricer::calibrate() {
        const Size n = paths_.size(); // number of paths
        Array prices(n, 0.0), exercise(n, 0.0);

        const Size basisDimension = payoff_->basisSystemDimension();

        const Size len = paths_[0].pathLength();

        /*
          We try to estimate the lower bound of the continuation value,
          so that only itm paths contribute to the regression.
         */

        for (Size j = 0; j < n; ++j) {
            const Real payoff = paths_[j].payments[len - 1];
            const Real exercise = paths_[j].exercises[len - 1];
            const Array & states = paths_[j].states[len - 1];
            const bool canExercise = !states.empty();

            // at the end the continuation value is 0.0
            if (canExercise && exercise > 0.0)
                prices[j] += exercise;
            prices[j] += payoff;
        }

        lowerBounds_[len - 1] = *std::min_element(prices.begin(), prices.end());

        std::vector<bool> lsExercise(n);

        for (Integer i = len - 2; i >= 0; --i) {
            std::vector<Real>  y;
            std::vector<Array> x;

            // prices are discounted up to time i
            const Real discountRatio = dF_[i + 1] / dF_[i];
            prices *= discountRatio;
            lowerBounds_[i + 1] *= discountRatio;

            //roll back step
            for (Size j = 0; j < n; ++j) {
                exercise[j] = paths_[j].exercises[i];

                // If states is empty, no exercise in this path
                // and the path will not partecipate to the Lesat Square regression

                const Array & states = paths_[j].states[i];
                QL_REQUIRE(states.empty() || states.size() == basisDimension, 
                           "Invalid size of basis system");

                // only paths that could potentially create exercise opportunities
                // partecipate to the regression

                // if exercise is lower than minimum continuation value, no point in considering it
                if (!states.empty() && exercise[j] > lowerBounds_[i + 1]) {
                    x.push_back(states);
                    y.push_back(prices[j]);
                }
            }

            if (v_.size() <=  x.size()) {
                coeff_[i] = GeneralLinearLeastSquares(x, y, v_).coefficients();
            }
            else {
            // if number of itm paths is smaller then the number of
            // calibration functions -> never exercise
                QL_TRACE("Not enough itm paths: default decision is NEVER");
                coeff_[i] = Array(0);
            }

            /* attempt to avoid static arbitrage given by always or never exercising.

               always is absolute: regardless of the lowerBoundContinuationValue_ (this could be changed)
               but it still honours "canExercise"
             */
            Real sumOptimized = 0.0;
            Real sumNoExercise = 0.0;
            Real sumAlwaysExercise = 0.0; // always, if allowed

            for (Size j = 0, k = 0; j < n; ++j) {
                sumNoExercise += prices[j];
                lsExercise[j] = false;

                const bool canExercise = !paths_[j].states[i].empty();
                if (canExercise) {
                    sumAlwaysExercise += exercise[j];
                    if (!coeff_[i].empty() && exercise[j] > lowerBounds_[i + 1]) {
                        Real continuationValue = 0.0;
                        for (Size l = 0; l < v_.size(); ++l) {
                            continuationValue += coeff_[i][l] * v_[l](x[k]);
                        }
                        
                        if (continuationValue < exercise[j]) {
                            lsExercise[j] = true;
                        }
                        ++k;
                    }
                }
                else {
                    sumAlwaysExercise += prices[j];
                }

                sumOptimized += lsExercise[j] ? exercise[j] : prices[j];
            }

            sumOptimized /= n;
            sumNoExercise /= n;
            sumAlwaysExercise /= n;

            QL_TRACE(   "Time index: " << i 
                     << ", LowerBound: " << lowerBounds_[i + 1] 
                     << ", Optimum: " << sumOptimized 
                     << ", Continuation: " << sumNoExercise 
                     << ", Termination: " << sumAlwaysExercise);

            if (  sumOptimized >= sumNoExercise 
                && sumOptimized >= sumAlwaysExercise) {
                
                QL_TRACE("Accepted LS decision");
                for (Size j = 0; j < n; ++j) {
                    // lsExercise already contains "canExercise"
                    prices[j] = lsExercise[j] ? exercise[j] : prices[j];
                }
            }
            else if (sumAlwaysExercise > sumNoExercise) {
                QL_TRACE("Overridden bad LS decision: ALWAYS");
                for (Size j = 0; j < n; ++j) {
                    const bool canExercise = !paths_[j].states[i].empty();
                    prices[j] = canExercise ? exercise[j] : prices[j];
                }
                // special value to indicate always exercise
                coeff_[i] = Array(v_.size() + 1); 
            }
            else {
                QL_TRACE("Overridden bad LS decision: NEVER");
                // prices already contain the continuation value
                // special value to indicate never exercise
                coeff_[i] = Array(0); 
            }

            // then we add in any case the payment at time t
            // which is made even if cancellation happens at t
            for (Size j = 0; j < n; ++j) {
                const Real payoff = paths_[j].payments[i];
                prices[j] += payoff;
            }

            lowerBounds_[i] = *std::min_element(prices.begin(), prices.end());
        }

        // remove calibration paths
        paths_.clear();
        // entering the calculation phase
        calibrationPhase_ = false;
    }
}


<|start_filename|>ql/models/marketmodels/browniangenerators/sobolbrowniangenerator.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/models/marketmodels/browniangenerators/sobolbrowniangenerator.hpp>
#include <boost/iterator/permutation_iterator.hpp>

namespace QuantLib {

    namespace {

        void fillByFactor(std::vector<std::vector<Size> >& M,
                          Size factors, Size steps) {
            Size counter = 0;
            for (Size i=0; i<factors; ++i)
                for (Size j=0; j<steps; ++j)
                    M[i][j] = counter++;
        }

        void fillByStep(std::vector<std::vector<Size> >& M,
                        Size factors, Size steps) {
            Size counter = 0;
            for (Size j=0; j<steps; ++j)
                for (Size i=0; i<factors; ++i)
                    M[i][j] = counter++;
        }

        // variate 2 is used for the second factor's full path
        void fillByDiagonal(std::vector<std::vector<Size> >& M,
                            Size factors, Size steps) {
            // starting position of the current diagonal
            Size i0 = 0, j0 = 0;
            // current position
            Size i=0, j=0;
            Size counter = 0;
            while (counter < factors*steps) {
                M[i][j] = counter++;
                if (i == 0 || j == steps-1) {
                    // we completed a diagonal and have to start a new one
                    if (i0 < factors-1) {
                        // we start the path of the next factor
                        i0 = i0+1;
                        j0 = 0;
                    } else {
                        // we move along the path of the last factor
                        i0 = factors-1;
                        j0 = j0+1;
                    }
                    i = i0;
                    j = j0;
                } else {
                    // we move along the diagonal
                    i = i-1;
                    j = j+1;
                }
            }
        }

        /*
        // variate 2 is used for the first factor's half path
        void fillByDiagonal(std::vector<std::vector<Size> >& M,
                            Size factors, Size steps) {
            // starting position of the current diagonal
            Size i0 = 0, j0 = 0;
            // current position
            Size i=0, j=0;
            Size counter = 0;
            while (counter < factors*steps) {
                M[i][j] = counter++;
                if (j == 0 || i == factors-1) {
                    // we completed a diagonal and have to start a new one
                    if (j0 < steps-1) {
                        // we move along the path of the first factor
                        i0 = 0;
                        j0 = j0+1;
                    } else {
                        // we complete the next path
                        i0 = i0+1;
                        j0 = steps-1;
                    }
                    i = i0;
                    j = j0;
                } else {
                    // we move along the diagonal
                    i = i+1;
                    j = j-1;
                }
            }
        }
        */

    }


    SobolBrownianGenerator::SobolBrownianGenerator(
                                        Size factors,
                                        Size steps,
                                        Ordering ordering,
                                        unsigned long seed,
                                        SobolRsg::DirectionIntegers integers)
    : factors_(factors), steps_(steps), ordering_(ordering),
      generator_(SobolRsg(factors*steps, seed, integers),
                 InverseCumulativeNormal()),
      bridge_(steps), lastStep_(0),
      orderedIndices_(factors, std::vector<Size>(steps)),
      bridgedVariates_(factors, std::vector<Real>(steps)) {

        switch (ordering_) {
          case Factors:
            fillByFactor(orderedIndices_, factors_, steps_);
            break;
          case Steps:
            fillByStep(orderedIndices_, factors_, steps_);
            break;
          case Diagonal:
            fillByDiagonal(orderedIndices_, factors_, steps_);
            break;
          default:
            QL_FAIL("unknown ordering");
        }
    }


    Real SobolBrownianGenerator::nextPath() {
        typedef InverseCumulativeRsg<SobolRsg,
                                     InverseCumulativeNormal>::sample_type
            sample_type;

        const sample_type& sample = generator_.nextSequence();
        // Brownian-bridge the variates according to the ordered indices
        for (Size i=0; i<factors_; ++i) {
            bridge_.transform(boost::make_permutation_iterator(
                                                  sample.value.begin(),
                                                  orderedIndices_[i].begin()),
                              boost::make_permutation_iterator(
                                                  sample.value.begin(),
                                                  orderedIndices_[i].end()),
                              bridgedVariates_[i].begin());
        }
        lastStep_ = 0;
        return sample.weight;
    }
    
    
    const std::vector<std::vector<Size> >& 
    SobolBrownianGenerator::orderedIndices() const {
        return orderedIndices_;
    }

    std::vector<std::vector<Real> > SobolBrownianGenerator::transform(
                            const std::vector<std::vector<Real> >& variates) {
        
        QL_REQUIRE(   (variates.size() == factors_*steps_),
                   "inconsistent variate vector");

        const Size dim    = factors_*steps_;
        const Size nPaths = variates.front().size();
        
        std::vector<std::vector<Real> > 
                       retVal(factors_, std::vector<Real>(nPaths*steps_));
        
        for (Size j=0; j < nPaths; ++j) {
            std::vector<Real> sample(steps_*factors_);
            for (Size k=0; k < dim; ++k) {
                sample[k] = variates[k][j];
            }
            for (Size i=0; i<factors_; ++i) {
                bridge_.transform(boost::make_permutation_iterator(
                                                  sample.begin(),
                                                  orderedIndices_[i].begin()),
                          boost::make_permutation_iterator(
                                                  sample.begin(),
                                                  orderedIndices_[i].end()),
                          retVal[i].begin()+j*steps_);
            }
        }
        
        return retVal;
    }

    Real SobolBrownianGenerator::nextStep(std::vector<Real>& output) {
        #if defined(QL_EXTRA_SAFETY_CHECKS)
        QL_REQUIRE(output.size() == factors_, "size mismatch");
        QL_REQUIRE(lastStep_<steps_, "sequence exhausted");
        #endif
        for (Size i=0; i<factors_; ++i)
            output[i] = bridgedVariates_[i][lastStep_];
        ++lastStep_;
        return 1.0;
    }

    Size SobolBrownianGenerator::numberOfFactors() const { return factors_; }

    Size SobolBrownianGenerator::numberOfSteps() const { return steps_; }



    SobolBrownianGeneratorFactory::SobolBrownianGeneratorFactory(
                                    SobolBrownianGenerator::Ordering ordering,
                                    unsigned long seed,
                                    SobolRsg::DirectionIntegers integers)
    : ordering_(ordering), seed_(seed), integers_(integers) {}

    boost::shared_ptr<BrownianGenerator>
    SobolBrownianGeneratorFactory::create(Size factors, Size steps) const {
        return boost::shared_ptr<BrownianGenerator>(
                         new SobolBrownianGenerator(factors, steps, ordering_,
                                                    seed_, integers_));
    }

}



<|start_filename|>ql/experimental/volatility/volcube.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2007 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file volcube.hpp
    \brief Interest rate (optionlet/swaption) volatility cube
*/

#ifndef quantlib_volatility_cube_h
#define quantlib_volatility_cube_h

#include <ql/handle.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

namespace QuantLib {

    class Period;
    class AbcdAtmVolCurve;
    class InterestRateVolSurface;
    class InterestRateIndex;

    class VolatilityCube {
      public:
        VolatilityCube(const std::vector<Handle<InterestRateVolSurface> >&,
                       const std::vector<Handle<AbcdAtmVolCurve> >&);
        const Period& minIndexTenor() const;
        const Period& maxIndexTenor() const;
        const std::vector<Handle<InterestRateVolSurface> >& surfaces() const;
        const std::vector<Handle<AbcdAtmVolCurve> >& curves() const;
      protected:
        std::vector<Handle<InterestRateVolSurface> > surfaces_;
        std::vector<Handle<AbcdAtmVolCurve> > curves_;
    };

    // inline

    inline const std::vector<Handle<InterestRateVolSurface> >&
    VolatilityCube::surfaces() const {
        return surfaces_;
    }

    inline const std::vector<Handle<AbcdAtmVolCurve> >&
    VolatilityCube::curves() const {
        return curves_;
    }

}

#endif


<|start_filename|>ql/pricingengines/swaption/gaussian1dfloatfloatswaptionengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2013, 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/swaption/gaussian1dfloatfloatswaptionengine.hpp>
#include <ql/experimental/coupons/swapspreadindex.hpp> // internal
#include <ql/math/interpolations/cubicinterpolation.hpp>
#include <ql/payoff.hpp>

namespace QuantLib {

    void Gaussian1dFloatFloatSwaptionEngine::calculate() const {

        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;
        }

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

        std::pair<Real, Real> result =
            npvs(settlement, 0.0, includeTodaysExercise_, true);

        results_.value = result.first;
        results_.additionalResults["underlyingValue"] = result.second;
    }

    Real
    Gaussian1dFloatFloatSwaptionEngine::underlyingNpv(const Date &expiry,
                                                      const Real y) const {
        return npvs(expiry, y, true).second;
    }

    VanillaSwap::Type
    Gaussian1dFloatFloatSwaptionEngine::underlyingType() const {
        return arguments_.swap->type();
    }

    const Date Gaussian1dFloatFloatSwaptionEngine::underlyingLastDate() const {
        Date l1 = arguments_.leg1PayDates.back();
        Date l2 = arguments_.leg2PayDates.back();
        return l2 >= l1 ? l2 : l1;
    }

    const Disposable<Array>
    Gaussian1dFloatFloatSwaptionEngine::initialGuess(const Date &expiry) const {

        Size idx1 =
            std::upper_bound(arguments_.leg1ResetDates.begin(),
                             arguments_.leg1ResetDates.end(), expiry - 1) -
            arguments_.leg1ResetDates.begin();

        // very simple initial guess
        // check guess for nominal and weighted maturity !

        Array initial(3);
        Real nominalSum1 = 0.0;
        for (Size i = idx1; i < arguments_.leg1ResetDates.size(); i++) {
            nominalSum1 += arguments_.nominal1[i];
        }
        Real nominalAvg1 = nominalSum1 /=
            (arguments_.leg1ResetDates.size() - idx1);
        Real weightedMaturity1 = 0.0;
        for (Size i = idx1; i < arguments_.leg1ResetDates.size(); i++) {
            weightedMaturity1 +=
                arguments_.leg1AccrualTimes[i] * arguments_.nominal1[i];
        }
        weightedMaturity1 /= nominalAvg1;

        initial[0] = nominalAvg1;
        initial[1] = weightedMaturity1;
        initial[2] = 0.03; // ???

        return initial;
    }

    // calculate npv and underlying npv as of expiry date
    const std::pair<Real, Real> Gaussian1dFloatFloatSwaptionEngine::npvs(
        const Date &expiry, const Real y, const bool includeExerciseOnExpiry,
        const bool considerProbabilities) const {

        // pricing

        // event dates are coupon fixing dates and exercise dates
        // we explicitly estimate cms and also libor coupons (although
        // the latter could be calculated analytically) to make the code
        // simpler

        std::vector<Date> events;
        events.insert(events.end(), arguments_.exercise->dates().begin(),
                      arguments_.exercise->dates().end());
        events.insert(events.end(), arguments_.leg1FixingDates.begin(),
                      arguments_.leg1FixingDates.end());
        events.insert(events.end(), arguments_.leg2FixingDates.begin(),
                      arguments_.leg2FixingDates.end());
        std::sort(events.begin(), events.end());

        std::vector<Date>::iterator it =
            std::unique(events.begin(), events.end());
        events.resize(std::distance(events.begin(), it));

        // only events on or after expiry are of interest by definition of the
        // deal part that is exericsed into.

        std::vector<Date>::iterator filit =
            std::upper_bound(events.begin(), events.end(),
                             expiry - (includeExerciseOnExpiry ? 1 : 0));
        events.erase(events.begin(), filit);

        int idx = events.size() - 1;

        FloatFloatSwap swap = *arguments_.swap;
        Option::Type type =
            arguments_.type == VanillaSwap::Payer ? Option::Call : Option::Put;

        Array npv0(2 * integrationPoints_ + 1, 0.0),
            npv1(2 * integrationPoints_ + 1, 0.0); // arrays for npvs of the
                                                   // option
        Array npv0a(2 * integrationPoints_ + 1, 0.0),
            npv1a(2 * integrationPoints_ + 1, 0.0); // arrays for npvs of the
                                                    // underlying
        Array z = model_->yGrid(stddevs_, integrationPoints_);
        Array p(z.size(), 0.0), pa(z.size(), 0.0);

        // for probability computation
        std::vector<Array> npvp0, npvp1;
        // how many active exercise dates are there ?
        Size noEx =  arguments_.exercise->dates().size() -
            (std::upper_bound(arguments_.exercise->dates().begin(),
                         arguments_.exercise->dates().end(),
                         expiry - (includeExerciseOnExpiry ? 1 : 0)) -
             arguments_.exercise->dates().begin());
        Size exIdx = noEx; // current exercise index
        if (considerProbabilities && probabilities_ != None) {
            for (Size i = 0; i < noEx+1 ; ++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 event1 = Null<Date>(), event0;
        Time event1Time = Null<Real>(), event0Time;

        bool isExercise, isLeg1Fixing, isLeg2Fixing;

        boost::shared_ptr<IborIndex> ibor1 =
            boost::dynamic_pointer_cast<IborIndex>(arguments_.index1);
        boost::shared_ptr<SwapIndex> cms1 =
            boost::dynamic_pointer_cast<SwapIndex>(arguments_.index1);
        boost::shared_ptr<SwapSpreadIndex> cmsspread1 =
            boost::dynamic_pointer_cast<SwapSpreadIndex>(arguments_.index1);
        boost::shared_ptr<IborIndex> ibor2 =
            boost::dynamic_pointer_cast<IborIndex>(arguments_.index2);
        boost::shared_ptr<SwapIndex> cms2 =
            boost::dynamic_pointer_cast<SwapIndex>(arguments_.index2);
        boost::shared_ptr<SwapSpreadIndex> cmsspread2 =
            boost::dynamic_pointer_cast<SwapSpreadIndex>(arguments_.index2);

        QL_REQUIRE(ibor1 != NULL || cms1 != NULL || cmsspread1 != NULL,
                   "index1 must be ibor or swap or swap spread index");
        QL_REQUIRE(ibor2 != NULL || cms2 != NULL || cmsspread2 != NULL,
                   "index2 must be ibor or swap or swap spread index");

        do {

            // we are at event0 date, which can be a structured coupon fixing
            // date or an exercise date or both.

            bool isEventDate = true;
            if (idx == -1) {
                event0 = expiry;
                isEventDate = false;
            } else {
                event0 = events[idx];
                if (event0 == expiry)
                    idx = -1; // avoid double roll back if expiry equal to
                              // earliest event date
            }

            if (std::find(arguments_.exercise->dates().begin(),
                          arguments_.exercise->dates().end(),
                          event0) != arguments_.exercise->dates().end())
                isExercise = true;
            else
                isExercise = false;

            if (std::find(arguments_.leg1FixingDates.begin(),
                          arguments_.leg1FixingDates.end(),
                          event0) != arguments_.leg1FixingDates.end())
                isLeg1Fixing = true;
            else
                isLeg1Fixing = false;

            if (std::find(arguments_.leg2FixingDates.begin(),
                          arguments_.leg2FixingDates.end(),
                          event0) != arguments_.leg2FixingDates.end())
                isLeg2Fixing = true;
            else
                isLeg2Fixing = false;

            event0Time = std::max(
                model_->termStructure()->timeFromReference(event0), 0.0);

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

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

                // roll back

                Real price = 0.0, pricea = 0.0;
                if (event1Time != Null<Real>()) {
                    Real zSpreadDf = oas_.empty()
                                         ? 1.0
                                         : std::exp(-oas_->value() *
                                                    (event1Time - event0Time));
                    Array yg =
                        model_->yGrid(stddevs_, integrationPoints_, event1Time,
                                      event0Time, event0 > expiry ? z[k] : y);
                    CubicInterpolation payoff0(
                        z.begin(), z.end(), npv1.begin(),
                        CubicInterpolation::Spline, true,
                        CubicInterpolation::Lagrange, 0.0,
                        CubicInterpolation::Lagrange, 0.0);
                    CubicInterpolation payoff0a(
                        z.begin(), z.end(), npv1a.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);
                        pa[i] = payoff0a(yg[i], true);
                    }
                    CubicInterpolation payoff1(
                        z.begin(), z.end(), p.begin(),
                        CubicInterpolation::Spline, true,
                        CubicInterpolation::Lagrange, 0.0,
                        CubicInterpolation::Lagrange, 0.0);
                    CubicInterpolation payoff1a(
                        z.begin(), z.end(), pa.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;
                        pricea += model_->gaussianShiftedPolynomialIntegral(
                                      0.0, payoff1a.cCoefficients()[i],
                                      payoff1a.bCoefficients()[i],
                                      payoff1a.aCoefficients()[i], pa[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;
                            pricea +=
                                model_->gaussianShiftedPolynomialIntegral(
                                    0.0, 0.0, 0.0, 0.0, pa[z.size() - 2],
                                    z[z.size() - 2], z[z.size() - 1], 100.0) *
                                zSpreadDf;
                            pricea += model_->gaussianShiftedPolynomialIntegral(
                                          0.0, 0.0, 0.0, 0.0, pa[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;
                            if (type == Option::Call)
                                pricea +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0,
                                        payoff1a.cCoefficients()[z.size() - 2],
                                        payoff1a.bCoefficients()[z.size() - 2],
                                        payoff1a.aCoefficients()[z.size() - 2],
                                        pa[z.size() - 2], z[z.size() - 2],
                                        z[z.size() - 1], 100.0) *
                                    zSpreadDf;
                            if (type == Option::Put)
                                pricea +=
                                    model_->gaussianShiftedPolynomialIntegral(
                                        0.0, payoff1a.cCoefficients()[0],
                                        payoff1a.bCoefficients()[0],
                                        payoff1a.aCoefficients()[0], pa[0],
                                        z[0], -100.0, z[0]) *
                                    zSpreadDf;
                        }
                    }
                }

                npv0[k] = price;
                npv0a[k] = pricea;

                // for probability computation
                if (considerProbabilities && probabilities_ != None) {
                    for (Size m = 0; m < npvp0.size(); m++) {
                        Real price = 0.0;
                        if (event1Time != Null<Real>()) {
                            Real zSpreadDf =
                                oas_.empty()
                                    ? 1.0
                                    : std::exp(-oas_->value() *
                                               (event1Time - event0Time));
                            Array yg = model_->yGrid(
                                stddevs_, integrationPoints_, event1Time,
                                event0Time, event0 > expiry ? 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

                // event date calculations

                if (isEventDate) {

                    Real zk = event0 > expiry ? z[k] : y;

                    if (isLeg1Fixing) { // if event is a fixing date and
                                        // exercise date,
                        // the coupon is part of the exercise into right (by
                        // definition)
                        Size j = std::find(arguments_.leg1FixingDates.begin(),
                                           arguments_.leg1FixingDates.end(),
                                           event0) -
                                 arguments_.leg1FixingDates.begin();
                        Real zSpreadDf =
                            oas_.empty()
                                ? 1.0
                                : std::exp(
                                      -oas_->value() *
                                      (model_->termStructure()
                                           ->dayCounter()
                                           .yearFraction(
                                                event0,
                                                arguments_.leg1PayDates[j])));
                        bool done = false;
                        do {
                            Real amount;
                            if (arguments_.leg1IsRedemptionFlow[j]) {
                                amount = arguments_.leg1Coupons[j];
                            } else {
                                Real estFixing = 0.0;
                                if(ibor1 != NULL) {
                                    estFixing = model_->forwardRate(
                                        arguments_.leg1FixingDates[j], event0,
                                        zk, ibor1);
                                }
                                if(cms1 != NULL) {
                                    estFixing = model_->swapRate(
                                        arguments_.leg1FixingDates[j],
                                        cms1->tenor(), event0, zk, cms1);
                                }
                                if (cmsspread1 != NULL)
                                    estFixing =
                                        cmsspread1->gearing1() *
                                            model_->swapRate(
                                                arguments_.leg1FixingDates[j],
                                                cmsspread1->swapIndex1()
                                                    ->tenor(),
                                                event0, zk,
                                                cmsspread1->swapIndex1()) +
                                        cmsspread1->gearing2() *
                                            model_->swapRate(
                                                arguments_.leg1FixingDates[j],
                                                cmsspread1->swapIndex2()
                                                    ->tenor(),
                                                event0, zk,
                                                cmsspread1->swapIndex2());
                                Real rate =
                                    arguments_.leg1Spreads[j] +
                                    arguments_.leg1Gearings[j] * estFixing;
                                if (arguments_.leg1CappedRates[j] !=
                                    Null<Real>())
                                    rate = std::min(
                                        arguments_.leg1CappedRates[j], rate);
                                if (arguments_.leg1FlooredRates[j] !=
                                    Null<Real>())
                                    rate = std::max(
                                        arguments_.leg1FlooredRates[j], rate);
                                amount = rate * arguments_.nominal1[j] *
                                         arguments_.leg1AccrualTimes[j];
                            }

                            npv0a[k] -=
                                amount *
                                model_->zerobond(arguments_.leg1PayDates[j],
                                                 event0, zk, discountCurve_) /
                                model_->numeraire(event0Time, zk,
                                                  discountCurve_) *
                                zSpreadDf;

                            if (j < arguments_.leg1FixingDates.size() - 1) {
                                j++;
                                done =
                                    (event0 != arguments_.leg1FixingDates[j]);
                            } else
                                done = true;

                        } while (!done);
                    }

                    if (isLeg2Fixing) { // if event is a fixing date and
                                        // exercise date,
                        // the coupon is part of the exercise into right (by
                        // definition)
                        Size j = std::find(arguments_.leg2FixingDates.begin(),
                                           arguments_.leg2FixingDates.end(),
                                           event0) -
                                 arguments_.leg2FixingDates.begin();
                        Real zSpreadDf =
                            oas_.empty()
                                ? 1.0
                                : std::exp(
                                      -oas_->value() *
                                      (model_->termStructure()
                                           ->dayCounter()
                                           .yearFraction(
                                                event0,
                                                arguments_.leg2PayDates[j])));
                        bool done;
                        do {
                            Real amount;
                            if (arguments_.leg2IsRedemptionFlow[j]) {
                                amount = arguments_.leg2Coupons[j];
                            } else {
                                Real estFixing = 0.0;
                                if(ibor2 != NULL)
                                    estFixing = model_->forwardRate(arguments_.leg2FixingDates[j],event0,zk,ibor2);
                                if(cms2 != NULL)
                                    estFixing = model_->swapRate(arguments_.leg2FixingDates[j],cms2->tenor(),event0,zk,cms2);
                                if (cmsspread2 != NULL)
                                    estFixing =
                                        cmsspread2->gearing1() *
                                            model_->swapRate(
                                                arguments_.leg2FixingDates[j],
                                                cmsspread2->swapIndex1()
                                                    ->tenor(),
                                                event0, zk,
                                                cmsspread2->swapIndex1()) +
                                        cmsspread2->gearing2() *
                                            model_->swapRate(
                                                arguments_.leg2FixingDates[j],
                                                cmsspread2->swapIndex2()
                                                    ->tenor(),
                                                event0, zk,
                                                cmsspread2->swapIndex2());
                                Real rate =
                                    arguments_.leg2Spreads[j] +
                                    arguments_.leg2Gearings[j] * estFixing;
                                if (arguments_.leg2CappedRates[j] !=
                                    Null<Real>())
                                    rate = std::min(
                                        arguments_.leg2CappedRates[j], rate);
                                if (arguments_.leg2FlooredRates[j] !=
                                    Null<Real>())
                                    rate = std::max(
                                        arguments_.leg2FlooredRates[j], rate);
                                amount = rate * arguments_.nominal2[j] *
                                         arguments_.leg2AccrualTimes[j];
                            }

                            npv0a[k] +=
                                amount *
                                model_->zerobond(arguments_.leg2PayDates[j],
                                                 event0, zk, discountCurve_) /
                                model_->numeraire(event0Time, zk,
                                                  discountCurve_) *
                                zSpreadDf;
                            if (j < arguments_.leg2FixingDates.size() - 1) {
                                j++;
                                done =
                                    (event0 != arguments_.leg2FixingDates[j]);
                            } else
                                done = true;

                        } while (!done);
                    }

                    if (isExercise) {
                        Size j = std::find(arguments_.exercise->dates().begin(),
                                           arguments_.exercise->dates().end(),
                                           event0) -
                                 arguments_.exercise->dates().begin();
                        Real rebate = 0.0;
                        Real zSpreadDf = 1.0;
                        Date rebateDate = event0;
                        if (rebatedExercise_ != NULL) {
                            rebate = rebatedExercise_->rebate(j);
                            rebateDate = rebatedExercise_->rebatePaymentDate(j);
                            zSpreadDf =
                                oas_.empty()
                                    ? 1.0
                                    : std::exp(-oas_->value() *
                                               (model_->termStructure()
                                                    ->dayCounter()
                                                    .yearFraction(event0,
                                                                  rebateDate)));
                        }
                        Real exerciseValue =
                            (type == Option::Call ? 1.0 : -1.0) * npv0a[k] +
                            rebate * model_->zerobond(rebateDate, event0) *
                                zSpreadDf / model_->numeraire(event0Time, zk,
                                                              discountCurve_);

                        if (considerProbabilities && probabilities_ != None) {
                            if (exIdx == noEx) {
                                // 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(
                                                     event0Time, 0.0, 0.0,
                                                     discountCurve_) *
                                                 model_->numeraire(
                                                     event0, z[k],
                                                     discountCurve_));
                            }
                            if (exerciseValue >= npv0[k]) {
                                npvp0[exIdx-1][k] =
                                    probabilities_ == Naive
                                        ? 1.0
                                        : 1.0 / (model_->zerobond(
                                                     event0Time, 0.0, 0.0,
                                                     discountCurve_) *
                                                 model_->numeraire(
                                                     event0Time, z[k],
                                                     discountCurve_));
                                for (Size ii = exIdx; ii < noEx+1; ++ii)
                                    npvp0[ii][k] = 0.0;
                            }
                        }
                        // end probability computation

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

            if(isExercise)
                --exIdx;

            npv1.swap(npv0);
            npv1a.swap(npv0a);

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

            event1 = event0;
            event1Time = event0Time;

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

        std::pair<Real, Real> res(
            npv1[0] * model_->numeraire(event1Time, y, discountCurve_),
            npv1a[0] * model_->numeraire(event1Time, y, discountCurve_) *
                (type == Option::Call ? 1.0 : -1.0));

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

        return res;
    }
}


<|start_filename|>ql/time/daycounters/all.hpp<|end_filename|>
/* This file is automatically generated; do not edit.     */
/* Add the files to be included into Makefile.am instead. */

#include <ql/time/daycounters/actual360.hpp>
#include <ql/time/daycounters/actual365fixed.hpp>
#include <ql/time/daycounters/actual365nl.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/business252.hpp>
#include <ql/time/daycounters/one.hpp>
#include <ql/time/daycounters/simpledaycounter.hpp>
#include <ql/time/daycounters/thirty360.hpp>



<|start_filename|>ql/experimental/processes/klugeextouprocess.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file klugeextouprocess.hpp
    \brief joint Kluge process an d Ornstein Uhlenbeck process
*/

#ifndef quantlib_kluge_ext_ou_process_hpp
#define quantlib_kluge_ext_ou_process_hpp

#include <ql/stochasticprocess.hpp>

namespace QuantLib {

    class ExtOUWithJumpsProcess;
    class ExtendedOrnsteinUhlenbeckProcess;

    /*! This class describes a correlated Kluge - extended Ornstein-Uhlenbeck
        process governed by
        \f[
        \begin{array}{rcl}
            P_t &=& \exp(p_t + X_t + Y_t) \\
            dX_t &=& -\alpha X_tdt + \sigma_x dW_t^x \\
            dY_t &=& -\beta Y_{t-}dt + J_tdN_t \\
            \omega(J) &=& \eta e^{-\eta J} \\
            G_t &=& \exp(g_t + U_t) \\
            dU_t &=& -\kappa U_tdt + \sigma_udW_t^u \\
            \rho &=& \mathrm{corr} (dW_t^x, dW_t^u)
         \end{array}
         \f]
    */

    /*! References:
        <NAME>, <NAME>, <NAME>, Modelling spikes and pricing
        swing options in electricity markets,
        http://people.maths.ox.ac.uk/hambly/PDF/Papers/elec.pdf
    */


    class KlugeExtOUProcess : public StochasticProcess {
      public:
        KlugeExtOUProcess(
            Real rho,
            const boost::shared_ptr<ExtOUWithJumpsProcess>& kluge,
            const boost::shared_ptr<ExtendedOrnsteinUhlenbeckProcess>& extOU);

        Size size() const;
        Size factors() const;

        Disposable<Array> initialValues() const;
        Disposable<Array> drift(Time t, const Array& x) const;
        Disposable<Matrix> diffusion(Time t, const Array& x) const;
        Disposable<Array> evolve(Time t0, const Array& x0,
                                 Time dt, const Array& dw) const;

        boost::shared_ptr<ExtOUWithJumpsProcess> getKlugeProcess() const;
        boost::shared_ptr<ExtendedOrnsteinUhlenbeckProcess>
                                                 getExtOUProcess() const;

        Real rho() const;

      private:
        const Real rho_, sqrtMRho_;
        const boost::shared_ptr<ExtOUWithJumpsProcess> klugeProcess_;
        const boost::shared_ptr<ExtendedOrnsteinUhlenbeckProcess> ouProcess_;
    };
}
#endif


<|start_filename|>ql/instruments/vanillastorageoption.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file vanillastorageoption.hpp
    \brief vanilla storage option class
*/

#ifndef quantlib_vanilla_storage_option_hpp
#define quantlib_vanilla_storage_option_hpp

#include <ql/event.hpp>
#include <ql/exercise.hpp>
#include <ql/instruments/payoffs.hpp>
#include <ql/instruments/oneassetoption.hpp>

namespace QuantLib {

    //! base option class
    class VanillaStorageOption : public OneAssetOption {
      public:
          class arguments;
          VanillaStorageOption(const boost::shared_ptr<BermudanExercise>& ex,
                               Real capacity, Real load, Real changeRate)
        : OneAssetOption(boost::shared_ptr<Payoff>(new NullPayoff), ex),
          capacity_  (capacity),
          load_      (load),
          changeRate_(changeRate) {}

        bool isExpired() const;
        void setupArguments(PricingEngine::arguments*) const;

      private:
        const Real capacity_;
        const Real load_;
        const Real changeRate_;
    };

    class VanillaStorageOption::arguments
        : public virtual PricingEngine::arguments {
      public:
        arguments() {}
        void validate() const {
            QL_REQUIRE(payoff, "no payoff given");
            QL_REQUIRE(exercise, "no exercise given");

            QL_REQUIRE(capacity > 0.0 && changeRate > 0.0 && load >= 0.0,
                      "positive capacity, load and change rate required");
            QL_REQUIRE(load <= capacity && changeRate <= capacity,
                        "illegal values load of changeRate");
        }

        Real capacity;
        Real load;
        Real changeRate;
        boost::shared_ptr<NullPayoff> payoff;
        boost::shared_ptr<BermudanExercise> exercise;
    };

    inline void VanillaStorageOption::setupArguments(
                                PricingEngine::arguments* args) const {
        VanillaStorageOption::arguments* arguments =
            dynamic_cast<VanillaStorageOption::arguments*>(args);
        QL_REQUIRE(arguments != 0, "wrong argument type");

        arguments->payoff
            = boost::dynamic_pointer_cast<NullPayoff>(payoff_);
        arguments->exercise
            = boost::dynamic_pointer_cast<BermudanExercise>(exercise_);
        arguments->capacity   = capacity_;
        arguments->load       = load_;
        arguments->changeRate = changeRate_;
    }

    inline bool VanillaStorageOption::isExpired() const {
        return detail::simple_event(exercise_->lastDate()).hasOccurred();
    }
}

#endif


<|start_filename|>ql/cashflows/digitalcoupon.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2007 <NAME>
 Copyright (C) 2007 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/cashflows/capflooredcoupon.hpp>
#include <ql/cashflows/digitalcoupon.hpp>
#include <ql/indexes/indexmanager.hpp>
#include <ql/indexes/interestrateindex.hpp>

namespace QuantLib {

    DigitalCoupon::DigitalCoupon(const boost::shared_ptr<FloatingRateCoupon>& underlying,
                  Rate callStrike,
                  Position::Type callPosition,
                  bool isCallATMIncluded,
                  Rate callDigitalPayoff,
                  Rate putStrike,
                  Position::Type putPosition,
                  bool isPutATMIncluded,
                  Rate putDigitalPayoff,
                  const boost::shared_ptr<DigitalReplication>& replication)
    : FloatingRateCoupon(underlying->date(),
                         underlying->nominal(),
                         underlying->accrualStartDate(),
                         underlying->accrualEndDate(),
                         underlying->fixingDays(),
                         underlying->index(),
                         underlying->gearing(),
                         underlying->spread(),
                         underlying->referencePeriodStart(),
                         underlying->referencePeriodEnd(),
                         underlying->dayCounter(),
                         underlying->isInArrears()),
      underlying_(underlying), callCsi_(0.), putCsi_(0.),
      isCallATMIncluded_(isCallATMIncluded), isPutATMIncluded_(isPutATMIncluded),
      isCallCashOrNothing_(false), isPutCashOrNothing_(false),
      callLeftEps_(replication->gap()/2.), callRightEps_(replication->gap()/2.),
      putLeftEps_(replication->gap()/2.), putRightEps_(replication->gap()/2.),
      hasPutStrike_(false), hasCallStrike_(false),
      replicationType_(replication->replicationType()) {

        QL_REQUIRE(replication->gap()>0.0, "Non positive epsilon not allowed");

        if (putStrike == Null<Rate>()) {
            QL_REQUIRE(putDigitalPayoff == Null<Rate>(),
            "Put Cash rate non allowed if put strike is null");
        }
        if (callStrike == Null<Rate>()) {
            QL_REQUIRE(callDigitalPayoff == Null<Rate>(),
            "Call Cash rate non allowed if call strike is null");
        }
        if (callStrike != Null<Rate>()) {
            QL_REQUIRE(callStrike >= 0., "negative call strike not allowed");
            hasCallStrike_ = true;
            callStrike_ = callStrike;
            QL_REQUIRE(callStrike_>=replication->gap()/2., "call strike < eps/2");
            switch (callPosition) {
                case Position::Long :
                    callCsi_ = 1.0;
                    break;
                case Position::Short :
                    callCsi_ = -1.0;
                    break;
                default:
                    QL_FAIL("unsupported position type");
            }
            if (callDigitalPayoff != Null<Rate>()){
                callDigitalPayoff_ = callDigitalPayoff;
                isCallCashOrNothing_ = true;
            }
        }
        if (putStrike != Null<Rate>()){
            QL_REQUIRE(putStrike >= 0., "negative put strike not allowed");
            hasPutStrike_ = true;
            putStrike_ = putStrike;
            switch (putPosition) {
                case Position::Long :
                    putCsi_ = 1.0;
                    break;
                case Position::Short :
                    putCsi_ = -1.0;
                    break;
                default:
                    QL_FAIL("unsupported position type");
            }
            if (putDigitalPayoff != Null<Rate>()){
                putDigitalPayoff_ = putDigitalPayoff;
                isPutCashOrNothing_ = true;
            }
        }

        switch (replicationType_) {
          case Replication::Central :
            // do nothing
            break;
          case Replication::Sub :
            if (hasCallStrike_) {
                switch (callPosition) {
                    case Position::Long :
                        callLeftEps_ = 0.;
                        callRightEps_ = replication->gap();
                        break;
                    case Position::Short :
                        callLeftEps_ = replication->gap();
                        callRightEps_ = 0.;
                        break;
                    default:
                        QL_FAIL("unsupported position type");
                }
            }
            if (hasPutStrike_) {
                switch (putPosition) {
                    case Position::Long :
                        putLeftEps_ = replication->gap();
                        putRightEps_ = 0.;
                        break;
                    case Position::Short :
                        putLeftEps_ = 0.;
                        putRightEps_ = replication->gap();
                        break;
                    default:
                        QL_FAIL("unsupported position type");
                }
            }
            break;
          case Replication::Super :
            if (hasCallStrike_) {
                switch (callPosition) {
                    case Position::Long :
                        callLeftEps_ = replication->gap();
                        callRightEps_ = 0.;
                        break;
                    case Position::Short :
                        callLeftEps_ = 0.;
                        callRightEps_ = replication->gap();
                        break;
                    default:
                        QL_FAIL("unsupported position type");
                }
            }
            if (hasPutStrike_) {
                switch (putPosition) {
                    case Position::Long :
                        putLeftEps_ = 0.;
                        putRightEps_ = replication->gap();
                        break;
                    case Position::Short :
                        putLeftEps_ = replication->gap();
                        putRightEps_ = 0.;
                        break;
                    default:
                        QL_FAIL("unsupported position type");
                }
            }
            break;
          default:
            QL_FAIL("unsupported replication type");
        }

        registerWith(underlying);
    }


    Rate DigitalCoupon::callOptionRate() const {

        Rate callOptionRate = Rate(0.);
        if(hasCallStrike_) {
            // Step function
            callOptionRate = isCallCashOrNothing_ ? callDigitalPayoff_ : callStrike_;
            CappedFlooredCoupon next(underlying_, callStrike_ + callRightEps_);
            CappedFlooredCoupon previous(underlying_, callStrike_ - callLeftEps_);
            callOptionRate *= (next.rate() - previous.rate())
                            / (callLeftEps_ + callRightEps_);
            if (!isCallCashOrNothing_) {
                // Call
                CappedFlooredCoupon atStrike(underlying_, callStrike_);
                Rate call = underlying_->rate() - atStrike.rate();
                // Sum up
                callOptionRate += call;
            }
        }
        return callOptionRate;
    }

    Rate DigitalCoupon::putOptionRate() const {

        Rate putOptionRate = Rate(0.);
        if(hasPutStrike_) {
            // Step function
            putOptionRate = isPutCashOrNothing_ ? putDigitalPayoff_ : putStrike_;
            CappedFlooredCoupon next(underlying_, Null<Rate>(), putStrike_ + putRightEps_);
            CappedFlooredCoupon previous(underlying_, Null<Rate>(), putStrike_ - putLeftEps_);
            putOptionRate *= (next.rate() - previous.rate())
                           / (putLeftEps_ + putRightEps_);
            if (!isPutCashOrNothing_) {
                // Put
                CappedFlooredCoupon atStrike(underlying_, Null<Rate>(), putStrike_);
                Rate put = - underlying_->rate() + atStrike.rate();
                // Sum up
                putOptionRate -= put;
            }
        }
        return putOptionRate;
    }

    Rate DigitalCoupon::rate() const {

        QL_REQUIRE(underlying_->pricer(), "pricer not set");

        Date fixingDate = underlying_->fixingDate();
        Date today = Settings::instance().evaluationDate();
        bool enforceTodaysHistoricFixings =
            Settings::instance().enforcesTodaysHistoricFixings();
        Rate underlyingRate = underlying_->rate();
        if (fixingDate < today ||
            ((fixingDate == today) && enforceTodaysHistoricFixings)) {
            // must have been fixed
            return underlyingRate + callCsi_ * callPayoff() + putCsi_  * putPayoff();
        }
        if (fixingDate == today) {
            // might have been fixed
            Rate pastFixing =
                IndexManager::instance().getHistory((underlying_->index())->name())[fixingDate];
            if (pastFixing != Null<Real>()) {
                return underlyingRate + callCsi_ * callPayoff() + putCsi_  * putPayoff();
            } else
                return underlyingRate + callCsi_ * callOptionRate() + putCsi_ * putOptionRate();
        }
        return underlyingRate + callCsi_ * callOptionRate() + putCsi_ * putOptionRate();
    }

    Rate DigitalCoupon::convexityAdjustment() const {
        return underlying_->convexityAdjustment();
    }

    Rate DigitalCoupon::callStrike() const {
        if (hasCall())
            return callStrike_;
        else
            return Null<Rate>();
   }

    Rate DigitalCoupon::putStrike() const {
        if (hasPut())
            return putStrike_;
        else
            return Null<Rate>();
    }

    Rate DigitalCoupon::callDigitalPayoff() const {
        if (isCallCashOrNothing_)
            return callDigitalPayoff_;
        else
            return Null<Rate>();
    }

    Rate DigitalCoupon::putDigitalPayoff() const {
        if (isPutCashOrNothing_)
            return putDigitalPayoff_;
        else
            return Null<Rate>();
    }

    void DigitalCoupon::update() {
        notifyObservers();
    }

    void DigitalCoupon::accept(AcyclicVisitor& v) {
        typedef FloatingRateCoupon super;
        Visitor<DigitalCoupon>* v1 =
            dynamic_cast<Visitor<DigitalCoupon>*>(&v);
        if (v1 != 0)
            v1->visit(*this);
        else
            super::accept(v);
    }

    Rate DigitalCoupon::callPayoff() const {
        // to use only if index has fixed
        Rate payoff(0.);
        if(hasCallStrike_) {
            Rate underlyingRate = underlying_->rate();
            if ( (underlyingRate - callStrike_) > 1.e-16 ) {
                payoff = isCallCashOrNothing_ ? callDigitalPayoff_ : underlyingRate;
            } else {
                if (isCallATMIncluded_) {
                    if ( std::abs(callStrike_ - underlyingRate) <= 1.e-16 )
                        payoff = isCallCashOrNothing_ ? callDigitalPayoff_ : underlyingRate;
                }
            }
        }
        return payoff;
    }

    Rate DigitalCoupon::putPayoff() const {
        // to use only if index has fixed
        Rate payoff(0.);
        if(hasPutStrike_) {
            Rate underlyingRate = underlying_->rate();
            if ( (putStrike_ - underlyingRate) > 1.e-16 ) {
                payoff = isPutCashOrNothing_ ? putDigitalPayoff_ : underlyingRate;
            } else {
                // putStrike_ <= underlyingRate
                if (isPutATMIncluded_) {
                    if ( std::abs(putStrike_ - underlyingRate) <= 1.e-16 )
                        payoff = isPutCashOrNothing_ ? putDigitalPayoff_ : underlyingRate;
                }
            }
        }
        return payoff;
    }

}



<|start_filename|>ql/indexes/swap/eurliborswap.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006, 2007, 2008 <NAME>
 Copyright (C) 2006 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/indexes/swap/eurliborswap.hpp>
#include <ql/indexes/ibor/eurlibor.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/currencies/europe.hpp>

using boost::shared_ptr;

namespace QuantLib {

    EurLiborSwapIsdaFixA::EurLiborSwapIsdaFixA(
                                        const Period& tenor,
                                        const Handle<YieldTermStructure>& h)
    : SwapIndex("EurLiborSwapIsdaFixA", // familyName
                tenor,
                2, // settlementDays
                EURCurrency(),
                TARGET(),
                1*Years, // fixedLegTenor
                ModifiedFollowing, // fixedLegConvention
                Thirty360(Thirty360::BondBasis), // fixedLegDaycounter
                tenor > 1*Years ?
                    shared_ptr<IborIndex>(new EURLibor(6*Months, h)) :
                    shared_ptr<IborIndex>(new EURLibor(3*Months, h))) {}

    EurLiborSwapIsdaFixA::EurLiborSwapIsdaFixA(
                                const Period& tenor,
                                const Handle<YieldTermStructure>& forwarding,
                                const Handle<YieldTermStructure>& discounting)
    : SwapIndex("EurLiborSwapIsdaFixA", // familyName
                tenor,
                2, // settlementDays
                EURCurrency(),
                TARGET(),
                1*Years, // fixedLegTenor
                ModifiedFollowing, // fixedLegConvention
                Thirty360(Thirty360::BondBasis), // fixedLegDaycounter
                tenor > 1*Years ?
                    shared_ptr<IborIndex>(new EURLibor(6*Months, forwarding)) :
                    shared_ptr<IborIndex>(new EURLibor(3*Months, forwarding)),
                discounting) {}

    EurLiborSwapIsdaFixB::EurLiborSwapIsdaFixB(
                                        const Period& tenor,
                                        const Handle<YieldTermStructure>& h)
    : SwapIndex("EurLiborSwapIsdaFixB", // familyName
                tenor,
                2, // settlementDays
                EURCurrency(),
                TARGET(),
                1*Years, // fixedLegTenor
                ModifiedFollowing, // fixedLegConvention
                Thirty360(Thirty360::BondBasis), // fixedLegDaycounter
                tenor > 1*Years ?
                    shared_ptr<IborIndex>(new EURLibor(6*Months, h)) :
                    shared_ptr<IborIndex>(new EURLibor(3*Months, h))) {}

    EurLiborSwapIsdaFixB::EurLiborSwapIsdaFixB(
                                const Period& tenor,
                                const Handle<YieldTermStructure>& forwarding,
                                const Handle<YieldTermStructure>& discounting)
    : SwapIndex("EurLiborSwapIsdaFixB", // familyName
                tenor,
                2, // settlementDays
                EURCurrency(),
                TARGET(),
                1*Years, // fixedLegTenor
                ModifiedFollowing, // fixedLegConvention
                Thirty360(Thirty360::BondBasis), // fixedLegDaycounter
                tenor > 1*Years ?
                    shared_ptr<IborIndex>(new EURLibor(6*Months, forwarding)) :
                    shared_ptr<IborIndex>(new EURLibor(3*Months, forwarding)),
                discounting) {}

    EurLiborSwapIfrFix::EurLiborSwapIfrFix(
                                        const Period& tenor,
                                        const Handle<YieldTermStructure>& h)
    : SwapIndex("EurLiborSwapIfrFix", // familyName
                tenor,
                2, // settlementDays
                EURCurrency(),
                TARGET(),
                1*Years, // fixedLegTenor
                ModifiedFollowing, // fixedLegConvention
                Thirty360(Thirty360::BondBasis), // fixedLegDaycounter
                tenor > 1*Years ?
                    shared_ptr<IborIndex>(new EURLibor(6*Months, h)) :
                    shared_ptr<IborIndex>(new EURLibor(3*Months, h))) {}

    EurLiborSwapIfrFix::EurLiborSwapIfrFix(
                                const Period& tenor,
                                const Handle<YieldTermStructure>& forwarding,
                                const Handle<YieldTermStructure>& discounting)
    : SwapIndex("EurLiborSwapIfrFix", // familyName
                tenor,
                2, // settlementDays
                EURCurrency(),
                TARGET(),
                1*Years, // fixedLegTenor
                ModifiedFollowing, // fixedLegConvention
                Thirty360(Thirty360::BondBasis), // fixedLegDaycounter
                tenor > 1*Years ?
                    shared_ptr<IborIndex>(new EURLibor(6*Months, forwarding)) :
                    shared_ptr<IborIndex>(new EURLibor(3*Months, forwarding)),
                discounting) {}

}


<|start_filename|>ql/experimental/commodities/paymentterm.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file commoditypricinghelpers.hpp
    \brief Commodity pricing helpers
*/

#ifndef quantlib_payment_term_hpp
#define quantlib_payment_term_hpp

#include <ql/time/calendar.hpp>
#include <map>

namespace QuantLib {

    class PaymentTerm {
      public:
        enum EventType { TradeDate, PricingDate };

        PaymentTerm();
        PaymentTerm(const std::string& name,
                    EventType eventType,
                    Integer offsetDays,
                    const Calendar& calendar);
        //! \name Inspectors
        //@{
        //! name, e.g, "Pricing end + 5 days"
        const std::string& name() const;
        EventType eventType() const;
        Integer offsetDays() const;
        const Calendar& calendar() const;

        bool empty() const;
        //@}
        Date getPaymentDate(const Date& date) const;
      protected:
        struct Data;
        boost::shared_ptr<Data> data_;

        struct Data {
            std::string name;
            EventType eventType;
            Integer offsetDays;
            Calendar calendar;

            Data(const std::string& name, EventType eventType, Integer offsetDays,
                 const Calendar& calendar);
        };

        static std::map<std::string, boost::shared_ptr<Data> > paymentTerms_;
    };

    /*! \relates PaymentTerm */
    bool operator==(const PaymentTerm&,
                    const PaymentTerm&);

    /*! \relates PaymentTerm */
    bool operator!=(const PaymentTerm&,
                    const PaymentTerm&);

    /*! \relates PaymentTerm */
    std::ostream& operator<<(std::ostream&,
                             const PaymentTerm&);


    inline PaymentTerm::Data::Data(const std::string& name,
                                   PaymentTerm::EventType eventType,
                                   Integer offsetDays,
                                   const Calendar& calendar)
    : name(name), eventType(eventType),
      offsetDays(offsetDays), calendar(calendar) {}

    inline PaymentTerm::PaymentTerm() {}

    inline const std::string& PaymentTerm::name() const {
        return data_->name;
    }

    inline PaymentTerm::EventType PaymentTerm::eventType() const {
        return data_->eventType;
    }

    inline Integer PaymentTerm::offsetDays() const {
        return data_->offsetDays;
    }

    inline Date PaymentTerm::getPaymentDate(const Date& date) const {
        return data_->calendar.adjust(date + data_->offsetDays);
    }

    inline bool PaymentTerm::empty() const {
        return !data_;
    }

    inline bool operator==(const PaymentTerm& c1, const PaymentTerm& c2) {
        return c1.name() == c2.name();
    }

    inline bool operator!=(const PaymentTerm& c1, const PaymentTerm& c2) {
        return !(c1 == c2);
    }

}


#endif


<|start_filename|>ql/methods/finitedifferences/stepconditions/fdmsimpleswingcondition.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010, 2014 <NAME>
 
 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmsimpleswingcondition.hpp>

namespace QuantLib {

    FdmSimpleSwingCondition::FdmSimpleSwingCondition(
            const std::vector<Time> & exerciseTimes,
            const boost::shared_ptr<FdmMesher>& mesher,
            const boost::shared_ptr<FdmInnerValueCalculator>& calculator,
            Size swingDirection,
            Size minExercises)
    : exerciseTimes_ (exerciseTimes),
      mesher_        (mesher),
      calculator_    (calculator),
      minExercises_  (minExercises),
      swingDirection_(swingDirection) {
    }
    
    void FdmSimpleSwingCondition::applyTo(Array& a, Time t) const {
        const std::vector<Time>::const_iterator iter
            = std::find(exerciseTimes_.begin(), exerciseTimes_.end(), t);
        const Size maxExerciseValue=mesher_->layout()->dim()[swingDirection_]-1;

        if (iter != exerciseTimes_.end()) {
            Array retVal= a;

            const Size d = std::distance(iter, exerciseTimes_.end());

            const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout();
            const FdmLinearOpIterator endIter = layout->end();
            
            for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
                 ++iter) {
                
                const std::vector<Size>& coor = iter.coordinates();
                
                const Size exercisesUsed = coor[swingDirection_];
                
                if (exercisesUsed < maxExerciseValue) {
                    const Real cashflow = calculator_->innerValue(iter, t);
                    const Real currentValue = a[iter.index()];
                    const Real valuePlusOneExercise
                         = a[layout->neighbourhood(iter, swingDirection_, 1)];
                    
                    if (   currentValue < valuePlusOneExercise + cashflow
                        || exercisesUsed + d <=  minExercises_) {
                        retVal[iter.index()] = valuePlusOneExercise + cashflow;
                    }
                }
            }
            a = retVal;
        }
    }
}


<|start_filename|>ql/cashflows/cpicouponpricer.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009, 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
 */

/*! \file cpicouponpricer.hpp
    \brief zero inflation-coupon pricer
 */

#ifndef quantlib_cpicouponpricer_hpp
#define quantlib_cpicouponpricer_hpp

#include <ql/cashflow.hpp>
#include <ql/option.hpp>
#include <ql/cashflows/inflationcouponpricer.hpp>
#include <ql/cashflows/cpicoupon.hpp>
#include <ql/termstructures/volatility/inflation/cpivolatilitystructure.hpp>

namespace QuantLib {

    //! base pricer for capped/floored CPI coupons N.B. vol-dependent parts are a TODO
    /*! \note this pricer can already do swaplets but to get
              volatility-dependent coupons you need to implement the descendents.
    */
    class CPICouponPricer : public InflationCouponPricer {
    public:
        CPICouponPricer(const Handle<CPIVolatilitySurface>& capletVol
                                 = Handle<CPIVolatilitySurface>());

        virtual Handle<CPIVolatilitySurface> capletVolatility() const{
            return capletVol_;
        }

        virtual void setCapletVolatility(
            const Handle<CPIVolatilitySurface>& capletVol);


        //! \name InflationCouponPricer interface
        //@{
        virtual Real swapletPrice() const;
        virtual Rate swapletRate() const;
        virtual Real capletPrice(Rate effectiveCap) const;
        virtual Rate capletRate(Rate effectiveCap) const;
        virtual Real floorletPrice(Rate effectiveFloor) const;
        virtual Rate floorletRate(Rate effectiveFloor) const;
        virtual void initialize(const InflationCoupon&);
        //@}


    protected:
        //! can replace this if really required
        virtual Real optionletPrice(Option::Type optionType,
                                    Real effStrike) const;

        //! usually only need implement this (of course they may need
        //! to re-implement initialize too ...)
        virtual Real optionletPriceImp(Option::Type, Real strike,
                                       Real forward, Real stdDev) const;
        virtual Rate adjustedFixing(Rate fixing = Null<Rate>()) const;

        //! data
        Handle<CPIVolatilitySurface> capletVol_;
        const CPICoupon* coupon_;
        Real gearing_;
        Spread spread_;
        Real discount_;
        Real spreadLegValue_;
    };

}   // namespace QuantLib

#endif


<|start_filename|>ql/math/interpolations/interpolation2d.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2002, 2003, 2006 <NAME>
 Copyright (C) 2004, 2005, 2006, 2007 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file interpolation2d.hpp
    \brief abstract base classes for 2-D interpolations
*/

#ifndef quantlib_interpolation2D_hpp
#define quantlib_interpolation2D_hpp

#include <ql/math/interpolations/extrapolation.hpp>
#include <ql/math/comparison.hpp>
#include <ql/math/matrix.hpp>
#include <ql/errors.hpp>
#include <ql/types.hpp>
#include <vector>

namespace QuantLib {

    //! base class for 2-D interpolations.
    /*! Classes derived from this class will provide interpolated
        values from two sequences of length \f$ N \f$ and \f$ M \f$,
        representing the discretized values of the \f$ x \f$ and \f$ y
        \f$ variables, and a \f$ N \times M \f$ matrix representing
        the tabulated function values.
    */
    class Interpolation2D : public Extrapolator {
      protected:
        //! abstract base class for 2-D interpolation implementations
        class Impl {
          public:
            virtual ~Impl() {}
            virtual void calculate() = 0;
            virtual Real xMin() const = 0;
            virtual Real xMax() const = 0;
            virtual std::vector<Real> xValues() const = 0;
            virtual Size locateX(Real x) const = 0;
            virtual Real yMin() const = 0;
            virtual Real yMax() const = 0;
            virtual std::vector<Real> yValues() const = 0;
            virtual Size locateY(Real y) const = 0;
            virtual const Matrix& zData() const = 0;
            virtual bool isInRange(Real x, Real y) const = 0;
            virtual Real value(Real x, Real y) const = 0;
        };
        boost::shared_ptr<Impl> impl_;
      public:
        typedef Real first_argument_type;
        typedef Real second_argument_type;
        typedef Real result_type;
        //! basic template implementation
        template <class I1, class I2, class M>
        class templateImpl : public Impl {
          public:
            templateImpl(const I1& xBegin, const I1& xEnd,
                         const I2& yBegin, const I2& yEnd,
                         const M& zData)
            : xBegin_(xBegin), xEnd_(xEnd), yBegin_(yBegin), yEnd_(yEnd),
              zData_(zData) {
                QL_REQUIRE(xEnd_-xBegin_ >= 2,
                           "not enough x points to interpolate: at least 2 "
                           "required, " << xEnd_-xBegin_ << " provided");
                QL_REQUIRE(yEnd_-yBegin_ >= 2,
                           "not enough y points to interpolate: at least 2 "
                           "required, " << yEnd_-yBegin_ << " provided");
            }
            Real xMin() const {
                return *xBegin_;
            }
            Real xMax() const {
                return *(xEnd_-1);
            }
            std::vector<Real> xValues() const {
                return std::vector<Real>(xBegin_,xEnd_);
            }
            Real yMin() const {
                return *yBegin_;
            }
            Real yMax() const {
                return *(yEnd_-1);
            }
            std::vector<Real> yValues() const {
                return std::vector<Real>(yBegin_,yEnd_);
            }
            const Matrix& zData() const {
                return zData_;
            }
            bool isInRange(Real x, Real y) const {
                #if defined(QL_EXTRA_SAFETY_CHECKS)
                for (I1 i=xBegin_, j=xBegin_+1; j!=xEnd_; ++i, ++j)
                    QL_REQUIRE(*j > *i, "unsorted x values");
                #endif
                Real x1 = xMin(), x2 = xMax();
                bool xIsInrange = (x >= x1 && x <= x2) ||
                                  close(x,x1) ||
                                  close(x,x2);
                if (!xIsInrange) return false;

                #if defined(QL_EXTRA_SAFETY_CHECKS)
                for (I2 k=yBegin_, l=yBegin_+1; l!=yEnd_; ++k, ++l)
                    QL_REQUIRE(*l > *k, "unsorted y values");
                #endif
                Real y1 = yMin(), y2 = yMax();
                return (y >= y1 && y <= y2) || close(y,y1) || close(y,y2);
            }
          protected:
            Size locateX(Real x) const {
                #if defined(QL_EXTRA_SAFETY_CHECKS)
                for (I1 i=xBegin_, j=xBegin_+1; j!=xEnd_; ++i, ++j)
                    QL_REQUIRE(*j > *i, "unsorted x values");
                #endif
                if (x < *xBegin_)
                    return 0;
                else if (x > *(xEnd_-1))
                    return xEnd_-xBegin_-2;
                else
                    return std::upper_bound(xBegin_,xEnd_-1,x)-xBegin_-1;
            }
            Size locateY(Real y) const {
                #if defined(QL_EXTRA_SAFETY_CHECKS)
                for (I2 k=yBegin_, l=yBegin_+1; l!=yEnd_; ++k, ++l)
                    QL_REQUIRE(*l > *k, "unsorted y values");
                #endif
                if (y < *yBegin_)
                    return 0;
                else if (y > *(yEnd_-1))
                    return yEnd_-yBegin_-2;
                else
                    return std::upper_bound(yBegin_,yEnd_-1,y)-yBegin_-1;
            }
            I1 xBegin_, xEnd_;
            I2 yBegin_, yEnd_;
            const M& zData_;
        };
      public:
        Interpolation2D() {}
        Real operator()(Real x, Real y,
                        bool allowExtrapolation = false) const {
            checkRange(x,y,allowExtrapolation);
            return impl_->value(x,y);
        }
        Real xMin() const {
            return impl_->xMin();
        }
        Real xMax() const {
            return impl_->xMax();
        }
        std::vector<Real> xValues() const {
            return impl_->xValues();
        }
        Size locateX(Real x) const {
            return impl_->locateX(x);
        }
        Real yMin() const {
            return impl_->yMin();
        }
        Real yMax() const {
            return impl_->yMax();
        }
        std::vector<Real> yValues() const {
            return impl_->yValues();
        }
        Size locateY(Real y) const {
            return impl_->locateY(y);
        }
        const Matrix& zData() const {
            return impl_->zData();
        }
        bool isInRange(Real x, Real y) const {
            return impl_->isInRange(x,y);
        }
        void update() {
            impl_->calculate();
        }
      protected:
        void checkRange(Real x, Real y, bool extrapolate) const {
            QL_REQUIRE(extrapolate || allowsExtrapolation() ||
                       impl_->isInRange(x,y),
                       "interpolation range is ["
                       << impl_->xMin() << ", " << impl_->xMax()
                       << "] x ["
                       << impl_->yMin() << ", " << impl_->yMax()
                       << "]: extrapolation at ("
                       << x << ", " << y << ") not allowed");
        }
    };

}


#endif


<|start_filename|>ql/pricingengines/swaption/treeswaptionengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2001, 2002, 2003 <NAME>
 Copyright (C) 2005, 2007 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/swaption/treeswaptionengine.hpp>
#include <ql/pricingengines/swaption/discretizedswaption.hpp>

namespace QuantLib {

    TreeSwaptionEngine::TreeSwaptionEngine(
                               const boost::shared_ptr<ShortRateModel>& model,
                              Size timeSteps,
                              const Handle<YieldTermStructure>& termStructure)
    : LatticeShortRateModelEngine<Swaption::arguments,
                                  Swaption::results>(model, timeSteps),
      termStructure_(termStructure) {
        registerWith(termStructure_);
    }

    TreeSwaptionEngine::TreeSwaptionEngine(
                              const boost::shared_ptr<ShortRateModel>& model,
                              const TimeGrid& timeGrid,
                              const Handle<YieldTermStructure>& termStructure)
    : LatticeShortRateModelEngine<Swaption::arguments,
                                  Swaption::results>(model, timeGrid),
      termStructure_(termStructure) {
        registerWith(termStructure_);
    }

    TreeSwaptionEngine::TreeSwaptionEngine(
                              const Handle<ShortRateModel>& model,
                              Size timeSteps,
                              const Handle<YieldTermStructure>& termStructure)
    : LatticeShortRateModelEngine<Swaption::arguments,
                                  Swaption::results>(model, timeSteps),
      termStructure_(termStructure) {
        registerWith(termStructure_);
    }

    void TreeSwaptionEngine::calculate() const {

        QL_REQUIRE(arguments_.settlementType==Settlement::Physical,
                   "cash-settled swaptions not priced with tree engine");
        QL_REQUIRE(!model_.empty(), "no model specified");

        Date referenceDate;
        DayCounter dayCounter;

        boost::shared_ptr<TermStructureConsistentModel> tsmodel =
            boost::dynamic_pointer_cast<TermStructureConsistentModel>(*model_);
        if (tsmodel) {
            referenceDate = tsmodel->termStructure()->referenceDate();
            dayCounter = tsmodel->termStructure()->dayCounter();
        } else {
            referenceDate = termStructure_->referenceDate();
            dayCounter = termStructure_->dayCounter();
        }

        DiscretizedSwaption swaption(arguments_, referenceDate, dayCounter);
        boost::shared_ptr<Lattice> lattice;

        if (lattice_) {
            lattice = lattice_;
        } else {
            std::vector<Time> times = swaption.mandatoryTimes();
            TimeGrid timeGrid(times.begin(), times.end(), timeSteps_);
            lattice = model_->tree(timeGrid);
        }

        std::vector<Time> stoppingTimes(arguments_.exercise->dates().size());
        for (Size i=0; i<stoppingTimes.size(); ++i)
            stoppingTimes[i] =
                dayCounter.yearFraction(referenceDate,
                                        arguments_.exercise->date(i));

        swaption.initialize(lattice, stoppingTimes.back());

        Time nextExercise =
            *std::find_if(stoppingTimes.begin(),
                          stoppingTimes.end(),
                          std::bind2nd(std::greater_equal<Time>(), 0.0));
        swaption.rollback(nextExercise);

        results_.value = swaption.presentValue();
    }

}


<|start_filename|>test-suite/dividendoption.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004, 2005, 2007 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

// TODO: Figure out why tests for options with both continuous and discrete
// dividends fail.

// TODO: Make the known value test work.  It is slightly off from the
// answer in Hull probably due to date conventions.

#include "dividendoption.hpp"
#include "utilities.hpp"
#include <ql/time/daycounters/actual360.hpp>
#include <ql/instruments/dividendvanillaoption.hpp>
#include <ql/instruments/vanillaoption.hpp>
#include <ql/pricingengines/vanilla/fddividendeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/fddividendamericanengine.hpp>
#include <ql/pricingengines/vanilla/fddividendshoutengine.hpp>
#include <ql/pricingengines/vanilla/analyticdividendeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <map>
#include <iostream>

using namespace QuantLib;
using namespace boost::unit_test_framework;

#define REPORT_FAILURE(greekName, payoff, exercise, s, q, r, today, \
                       v, expected, calculated, error, tolerance) \
    BOOST_ERROR(exerciseTypeToString(exercise) << " " \
               << payoff->optionType() << " option with " \
               << payoffTypeToString(payoff) << " payoff:\n" \
               << "    spot value:       " << s << "\n" \
               << "    strike:           " << payoff->strike() << "\n" \
               << "    dividend yield:   " << io::rate(q) << "\n" \
               << "    risk-free rate:   " << io::rate(r) << "\n" \
               << "    reference date:   " << today << "\n" \
               << "    maturity:         " << exercise->lastDate() << "\n" \
               << "    volatility:       " << io::volatility(v) << "\n\n" \
               << "    expected   " << greekName << ": " << expected << "\n" \
               << "    calculated " << greekName << ": " << calculated << "\n"\
               << "    error:            " << error << "\n" \
               << "    tolerance:        " << tolerance);

// tests

void DividendOptionTest::testEuropeanValues() {

    BOOST_TEST_MESSAGE(
              "Testing dividend European option values with no dividends...");

    SavedSettings backup;

    Real tolerance = 1.0e-5;

    Option::Type types[] = { Option::Call, Option::Put };
    Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };
    Real underlyings[] = { 100.0 };
    Rate qRates[] = { 0.00, 0.10, 0.30 };
    Rate rRates[] = { 0.01, 0.05, 0.15 };
    Integer lengths[] = { 1, 2 };
    Volatility vols[] = { 0.05, 0.20, 0.70 };

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
    Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

    for (Size i=0; i<LENGTH(types); i++) {
      for (Size j=0; j<LENGTH(strikes); j++) {
        for (Size k=0; k<LENGTH(lengths); k++) {
          Date exDate = today + lengths[k]*Years;
          boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

          std::vector<Date> dividendDates;
          std::vector<Real> dividends;
          for (Date d = today + 3*Months;
                    d < exercise->lastDate();
                    d += 6*Months) {
              dividendDates.push_back(d);
              dividends.push_back(0.0);
          }

          boost::shared_ptr<StrikedTypePayoff> payoff(
                                new PlainVanillaPayoff(types[i], strikes[j]));

          boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

          boost::shared_ptr<PricingEngine> ref_engine(
                                    new AnalyticEuropeanEngine(stochProcess));

          boost::shared_ptr<PricingEngine> engine(
                            new AnalyticDividendEuropeanEngine(stochProcess));

          DividendVanillaOption option(payoff, exercise,
                                       dividendDates, dividends);
          option.setPricingEngine(engine);

          VanillaOption ref_option(payoff, exercise);
          ref_option.setPricingEngine(ref_engine);

          for (Size l=0; l<LENGTH(underlyings); l++) {
            for (Size m=0; m<LENGTH(qRates); m++) {
              for (Size n=0; n<LENGTH(rRates); n++) {
                for (Size p=0; p<LENGTH(vols); p++) {
                    Real u = underlyings[l];
                    Rate q = qRates[m],
                         r = rRates[n];
                    Volatility v = vols[p];
                    spot->setValue(u);
                    qRate->setValue(q);
                    rRate->setValue(r);
                    vol->setValue(v);

                    Real calculated = option.NPV();
                    Real expected = ref_option.NPV();
                    Real error = std::fabs(calculated-expected);
                    if (error > tolerance) {
                        REPORT_FAILURE("value start limit",
                                       payoff, exercise,
                                       u, q, r, today, v,
                                       expected, calculated,
                                       error, tolerance);
                    }
                }
              }
            }
          }
        }
      }
    }
}

// Reference pg. 253 - Hull - Options, Futures, and Other Derivatives 5th ed
// Exercise 12.8

void DividendOptionTest::testEuropeanKnownValue() {

    BOOST_TEST_MESSAGE(
              "Testing dividend European option values with known value...");

    SavedSettings backup;

    Real tolerance = 1.0e-2;
    Real expected = 3.67;

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
    Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

    Date exDate = today + 6*Months;
    boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

    std::vector<Date> dividendDates;
    std::vector<Real> dividends;
    dividendDates.push_back(today + 2*Months);
    dividends.push_back(0.50);
    dividendDates.push_back(today + 5*Months);
    dividends.push_back(0.50);

    boost::shared_ptr<StrikedTypePayoff> payoff(
            new PlainVanillaPayoff(Option::Call, 40.0));

    boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

    boost::shared_ptr<PricingEngine> engine(
                            new AnalyticDividendEuropeanEngine(stochProcess));

    DividendVanillaOption option(payoff, exercise,
                                 dividendDates, dividends);
    option.setPricingEngine(engine);

    Real u = 40.0;
    Rate q = 0.0, r = 0.09;
    Volatility v = 0.30;
    spot->setValue(u);
    qRate->setValue(q);
    rRate->setValue(r);
    vol->setValue(v);

    Real calculated = option.NPV();
    Real error = std::fabs(calculated-expected);
    if (error > tolerance) {
        REPORT_FAILURE("value start limit",
                       payoff, exercise,
                       u, q, r, today, v,
                       expected, calculated,
                       error, tolerance);
    }
}


void DividendOptionTest::testEuropeanStartLimit() {

    BOOST_TEST_MESSAGE(
       "Testing dividend European option with a dividend on today's date...");

    SavedSettings backup;

    Real tolerance = 1.0e-5;
    Real dividendValue = 10.0;

    Option::Type types[] = { Option::Call, Option::Put };
    Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };
    Real underlyings[] = { 100.0 };
    Rate qRates[] = { 0.00, 0.10, 0.30 };
    Rate rRates[] = { 0.01, 0.05, 0.15 };
    Integer lengths[] = { 1, 2 };
    Volatility vols[] = { 0.05, 0.20, 0.70 };

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
    Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

    for (Size i=0; i<LENGTH(types); i++) {
      for (Size j=0; j<LENGTH(strikes); j++) {
        for (Size k=0; k<LENGTH(lengths); k++) {
          Date exDate = today + lengths[k]*Years;
          boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

          std::vector<Date> dividendDates;
          std::vector<Real> dividends;
          dividendDates.push_back(today);
          dividends.push_back(dividendValue);

          boost::shared_ptr<StrikedTypePayoff> payoff(
                                new PlainVanillaPayoff(types[i], strikes[j]));

          boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

          boost::shared_ptr<PricingEngine> engine(
                            new AnalyticDividendEuropeanEngine(stochProcess));

          boost::shared_ptr<PricingEngine> ref_engine(
                                    new AnalyticEuropeanEngine(stochProcess));

          DividendVanillaOption option(payoff, exercise,
                                       dividendDates, dividends);
          option.setPricingEngine(engine);

          VanillaOption ref_option(payoff, exercise);
          ref_option.setPricingEngine(ref_engine);

          for (Size l=0; l<LENGTH(underlyings); l++) {
            for (Size m=0; m<LENGTH(qRates); m++) {
              for (Size n=0; n<LENGTH(rRates); n++) {
                for (Size p=0; p<LENGTH(vols); p++) {
                    Real u = underlyings[l];
                    Rate q = qRates[m],
                         r = rRates[n];
                    Volatility v = vols[p];
                    spot->setValue(u);
                    qRate->setValue(q);
                    rRate->setValue(r);
                    vol->setValue(v);

                    Real calculated = option.NPV();
                    spot->setValue(u-dividendValue);
                    Real expected = ref_option.NPV();
                    Real error = std::fabs(calculated-expected);
                    if (error > tolerance) {
                        REPORT_FAILURE("value", payoff, exercise,
                                       u, q, r, today, v,
                                       expected, calculated,
                                       error, tolerance);
                    }
                }
              }
            }
          }
        }
      }
    }
}

void DividendOptionTest::testEuropeanEndLimit() {

    BOOST_TEST_MESSAGE(
              "Testing dividend European option values with end limits...");

    SavedSettings backup;

    Real tolerance = 1.0e-5;
    Real dividendValue = 10.0;

    Option::Type types[] = { Option::Call, Option::Put };
    Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };
    Real underlyings[] = { 100.0 };
    Rate qRates[] = { 0.00, 0.10, 0.30 };
    Rate rRates[] = { 0.01, 0.05, 0.15 };
    Integer lengths[] = { 1, 2 };
    Volatility vols[] = { 0.05, 0.20, 0.70 };

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
    Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

    for (Size i=0; i<LENGTH(types); i++) {
      for (Size j=0; j<LENGTH(strikes); j++) {
        for (Size k=0; k<LENGTH(lengths); k++) {
          Date exDate = today + lengths[k]*Years;
          boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

          std::vector<Date> dividendDates;
          std::vector<Real> dividends;
          dividendDates.push_back(exercise->lastDate());
          dividends.push_back(dividendValue);

          boost::shared_ptr<StrikedTypePayoff> payoff(
                                new PlainVanillaPayoff(types[i], strikes[j]));


          boost::shared_ptr<StrikedTypePayoff> refPayoff(
                                new PlainVanillaPayoff(types[i],
                                                       strikes[j] +
                                                       dividendValue));

          boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

          boost::shared_ptr<PricingEngine> engine(
                            new AnalyticDividendEuropeanEngine(stochProcess));

          boost::shared_ptr<PricingEngine> ref_engine(
                                    new AnalyticEuropeanEngine(stochProcess));

          DividendVanillaOption option(payoff, exercise,
                                       dividendDates, dividends);
          option.setPricingEngine(engine);

          VanillaOption ref_option(refPayoff, exercise);
          ref_option.setPricingEngine(ref_engine);

          for (Size l=0; l<LENGTH(underlyings); l++) {
            for (Size m=0; m<LENGTH(qRates); m++) {
              for (Size n=0; n<LENGTH(rRates); n++) {
                for (Size p=0; p<LENGTH(vols); p++) {
                    Real u = underlyings[l];
                    Rate q = qRates[m],
                         r = rRates[n];
                    Volatility v = vols[p];
                    spot->setValue(u);
                    qRate->setValue(q);
                    rRate->setValue(r);
                    vol->setValue(v);

                    Real calculated = option.NPV();
                    Real expected = ref_option.NPV();
                    Real error = std::fabs(calculated-expected);
                    if (error > tolerance) {
                        REPORT_FAILURE("value", payoff, exercise,
                                       u, q, r, today, v,
                                       expected, calculated,
                                       error, tolerance);
                    }
                }
              }
            }
          }
        }
      }
    }
}


void DividendOptionTest::testEuropeanGreeks() {

    BOOST_TEST_MESSAGE("Testing dividend European option greeks...");

    SavedSettings backup;

    std::map<std::string,Real> calculated, expected, tolerance;
    tolerance["delta"] = 1.0e-5;
    tolerance["gamma"] = 1.0e-5;
    tolerance["theta"] = 1.0e-5;
    tolerance["rho"]   = 1.0e-5;
    tolerance["vega"]  = 1.0e-5;

    Option::Type types[] = { Option::Call, Option::Put };
    Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };
    Real underlyings[] = { 100.0 };
    Rate qRates[] = { 0.00, 0.10, 0.30 };
    Rate rRates[] = { 0.01, 0.05, 0.15 };
    Integer lengths[] = { 1, 2 };
    Volatility vols[] = { 0.05, 0.20, 0.40 };

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
    Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

    for (Size i=0; i<LENGTH(types); i++) {
      for (Size j=0; j<LENGTH(strikes); j++) {
        for (Size k=0; k<LENGTH(lengths); k++) {
          Date exDate = today + lengths[k]*Years;
          boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

          std::vector<Date> dividendDates;
          std::vector<Real> dividends;
          for (Date d = today + 3*Months;
                    d < exercise->lastDate();
                    d += 6*Months) {
              dividendDates.push_back(d);
              dividends.push_back(5.0);
          }

          boost::shared_ptr<StrikedTypePayoff> payoff(
                                new PlainVanillaPayoff(types[i], strikes[j]));

          boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

          boost::shared_ptr<PricingEngine> engine(
                            new AnalyticDividendEuropeanEngine(stochProcess));

          DividendVanillaOption option(payoff, exercise,
                                       dividendDates, dividends);
          option.setPricingEngine(engine);

          for (Size l=0; l<LENGTH(underlyings); l++) {
            for (Size m=0; m<LENGTH(qRates); m++) {
              for (Size n=0; n<LENGTH(rRates); n++) {
                for (Size p=0; p<LENGTH(vols); p++) {
                    Real u = underlyings[l];
                    Rate q = qRates[m],
                         r = rRates[n];
                    Volatility v = vols[p];
                    spot->setValue(u);
                    qRate->setValue(q);
                    rRate->setValue(r);
                    vol->setValue(v);

                    Real value = option.NPV();
                    calculated["delta"]  = option.delta();
                    calculated["gamma"]  = option.gamma();
                    calculated["theta"]  = option.theta();
                    calculated["rho"]    = option.rho();
                    calculated["vega"]   = option.vega();

                    if (value > spot->value()*1.0e-5) {
                        // perturb spot and get delta and gamma
                        Real du = u*1.0e-4;
                        spot->setValue(u+du);
                        Real value_p = option.NPV(),
                             delta_p = option.delta();
                        spot->setValue(u-du);
                        Real value_m = option.NPV(),
                             delta_m = option.delta();
                        spot->setValue(u);
                        expected["delta"] = (value_p - value_m)/(2*du);
                        expected["gamma"] = (delta_p - delta_m)/(2*du);

                        // perturb risk-free rate and get rho
                        Spread dr = r*1.0e-4;
                        rRate->setValue(r+dr);
                        value_p = option.NPV();
                        rRate->setValue(r-dr);
                        value_m = option.NPV();
                        rRate->setValue(r);
                        expected["rho"] = (value_p - value_m)/(2*dr);

                        // perturb volatility and get vega
                        Spread dv = v*1.0e-4;
                        vol->setValue(v+dv);
                        value_p = option.NPV();
                        vol->setValue(v-dv);
                        value_m = option.NPV();
                        vol->setValue(v);
                        expected["vega"] = (value_p - value_m)/(2*dv);

                        // perturb date and get theta
                        Time dT = dc.yearFraction(today-1, today+1);
                        Settings::instance().evaluationDate() = today-1;
                        value_m = option.NPV();
                        Settings::instance().evaluationDate() = today+1;
                        value_p = option.NPV();
                        Settings::instance().evaluationDate() = today;
                        expected["theta"] = (value_p - value_m)/dT;

                        // compare
                        std::map<std::string,Real>::iterator it;
                        for (it = calculated.begin();
                             it != calculated.end(); ++it) {
                            std::string greek = it->first;
                            Real expct = expected  [greek],
                                 calcl = calculated[greek],
                                 tol   = tolerance [greek];
                            Real error = relativeError(expct,calcl,u);
                            if (error>tol) {
                                REPORT_FAILURE(greek, payoff, exercise,
                                               u, q, r, today, v,
                                               expct, calcl, error, tol);
                            }
                        }
                    }
                }
              }
            }
          }
        }
      }
    }
}


void DividendOptionTest::testFdEuropeanValues() {

    BOOST_TEST_MESSAGE(
              "Testing finite-difference dividend European option values...");

    SavedSettings backup;

    Real tolerance = 1.0e-2;
    Size gridPoints = 300;
    Size timeSteps = 40;

    Option::Type types[] = { Option::Call, Option::Put };
    Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };
    Real underlyings[] = { 100.0 };
    // Rate qRates[] = { 0.00, 0.10, 0.30 };
    // Analytic dividend may not be handling q correctly
    Rate qRates[] = { 0.00 };
    Rate rRates[] = { 0.01, 0.05, 0.15 };
    Integer lengths[] = { 1, 2 };
    Volatility vols[] = { 0.05, 0.20, 0.40 };

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
    Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
    Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

    for (Size i=0; i<LENGTH(types); i++) {
      for (Size j=0; j<LENGTH(strikes); j++) {
        for (Size k=0; k<LENGTH(lengths); k++) {
          Date exDate = today + lengths[k]*Years;
          boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

          std::vector<Date> dividendDates;
          std::vector<Real> dividends;
          for (Date d = today + 3*Months;
                    d < exercise->lastDate();
                    d += 6*Months) {
              dividendDates.push_back(d);
              dividends.push_back(5.0);
          }

          boost::shared_ptr<StrikedTypePayoff> payoff(
                                new PlainVanillaPayoff(types[i], strikes[j]));

          boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

          boost::shared_ptr<PricingEngine> engine(
              new FDDividendEuropeanEngine<CrankNicolson>(stochProcess,
                                                          timeSteps,
                                                          gridPoints));

          boost::shared_ptr<PricingEngine> ref_engine(
                            new AnalyticDividendEuropeanEngine(stochProcess));

          DividendVanillaOption option(payoff, exercise,
                                       dividendDates, dividends);
          option.setPricingEngine(engine);

          DividendVanillaOption ref_option(payoff, exercise,
                                           dividendDates, dividends);
          ref_option.setPricingEngine(ref_engine);

          for (Size l=0; l<LENGTH(underlyings); l++) {
            for (Size m=0; m<LENGTH(qRates); m++) {
              for (Size n=0; n<LENGTH(rRates); n++) {
                for (Size p=0; p<LENGTH(vols); p++) {
                    Real u = underlyings[l];
                    Rate q = qRates[m],
                         r = rRates[n];
                    Volatility v = vols[p];
                    spot->setValue(u);
                    qRate->setValue(q);
                    rRate->setValue(r);
                    vol->setValue(v);
                    // FLOATING_POINT_EXCEPTION
                    Real calculated = option.NPV();
                    if (calculated > spot->value()*1.0e-5) {
                        Real expected = ref_option.NPV();
                        Real error = std::fabs(calculated-expected);
                        if (error > tolerance) {
                            REPORT_FAILURE("value", payoff, exercise,
                                           u, q, r, today, v,
                                           expected, calculated,
                                           error, tolerance);
                        }
                    }
                }
              }
            }
          }
        }
      }
    }
}


namespace {

    template <class Engine>
    void testFdGreeks(const Date& today,
                      const boost::shared_ptr<Exercise>& exercise) {

        std::map<std::string,Real> calculated, expected, tolerance;
        tolerance["delta"] = 5.0e-3;
        tolerance["gamma"] = 7.0e-3;
        // tolerance["theta"] = 1.0e-2;

        Option::Type types[] = { Option::Call, Option::Put };
        Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };
        Real underlyings[] = { 100.0 };
        Rate qRates[] = { 0.00, 0.10, 0.20 };
        Rate rRates[] = { 0.01, 0.05, 0.15 };
        Volatility vols[] = { 0.05, 0.20, 0.50 };

        DayCounter dc = Actual360();

        boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
        boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
        Handle<YieldTermStructure> qTS(flatRate(qRate, dc));
        boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
        Handle<YieldTermStructure> rTS(flatRate(rRate, dc));
        boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
        Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));

        for (Size i=0; i<LENGTH(types); i++) {
            for (Size j=0; j<LENGTH(strikes); j++) {

                std::vector<Date> dividendDates;
                std::vector<Real> dividends;
                for (Date d = today + 3*Months;
                     d < exercise->lastDate();
                     d += 6*Months) {
                    dividendDates.push_back(d);
                    dividends.push_back(5.0);
                }

                boost::shared_ptr<StrikedTypePayoff> payoff(
                                new PlainVanillaPayoff(types[i], strikes[j]));

                boost::shared_ptr<BlackScholesMertonProcess> stochProcess(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

                boost::shared_ptr<PricingEngine> engine(
                                                    new Engine(stochProcess));
                DividendVanillaOption option(payoff, exercise,
                                             dividendDates, dividends);
                option.setPricingEngine(engine);

                for (Size l=0; l<LENGTH(underlyings); l++) {
                  for (Size m=0; m<LENGTH(qRates); m++) {
                    for (Size n=0; n<LENGTH(rRates); n++) {
                      for (Size p=0; p<LENGTH(vols); p++) {
                        Real u = underlyings[l];
                        Rate q = qRates[m],
                             r = rRates[n];
                        Volatility v = vols[p];
                        spot->setValue(u);
                        qRate->setValue(q);
                        rRate->setValue(r);
                        vol->setValue(v);

                        // FLOATING_POINT_EXCEPTION
                        Real value = option.NPV();
                        calculated["delta"]  = option.delta();
                        calculated["gamma"]  = option.gamma();
                        // calculated["theta"]  = option.theta();

                        if (value > spot->value()*1.0e-5) {
                          // perturb spot and get delta and gamma
                          Real du = u*1.0e-4;
                          spot->setValue(u+du);
                          Real value_p = option.NPV(),
                               delta_p = option.delta();
                          spot->setValue(u-du);
                          Real value_m = option.NPV(),
                               delta_m = option.delta();
                          spot->setValue(u);
                          expected["delta"] = (value_p - value_m)/(2*du);
                          expected["gamma"] = (delta_p - delta_m)/(2*du);

                          // perturb date and get theta
                          /*
                            Time dT = dc.yearFraction(today-1, today+1);
                            Settings::instance().evaluationDate() = today-1;
                            value_m = option.NPV();
                            Settings::instance().evaluationDate() = today+1;
                            value_p = option.NPV();
                            Settings::instance().evaluationDate() = today;
                            expected["theta"] = (value_p - value_m)/dT;
                          */

                          // compare
                          std::map<std::string,Real>::iterator it;
                          for (it = calculated.begin();
                               it != calculated.end(); ++it) {
                            std::string greek = it->first;
                            Real expct = expected  [greek],
                                 calcl = calculated[greek],
                                 tol   = tolerance [greek];
                            Real error = relativeError(expct,calcl,u);
                            if (error>tol) {
                                REPORT_FAILURE(greek, payoff, exercise,
                                               u, q, r, today, v,
                                               expct, calcl, error, tol);
                            }
                          }
                        }
                      }
                    }
                  }
                }
            }
        }
    }

}


void DividendOptionTest::testFdEuropeanGreeks() {

    BOOST_TEST_MESSAGE(
             "Testing finite-differences dividend European option greeks...");

    SavedSettings backup;

    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;
    Integer lengths[] = { 1, 2 };

    for (Size i=0; i<LENGTH(lengths); i++) {
        Date exDate = today + lengths[i]*Years;
        boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
        testFdGreeks<FDDividendEuropeanEngine<CrankNicolson> >(today,exercise);
    }
}

void DividendOptionTest::testFdAmericanGreeks() {
    BOOST_TEST_MESSAGE(
             "Testing finite-differences dividend American option greeks...");

    SavedSettings backup;

    Date today = Date::todaysDate();
    Settings::instance().evaluationDate() = today;
    Integer lengths[] = { 1, 2 };

    for (Size i=0; i<LENGTH(lengths); i++) {
        Date exDate = today + lengths[i]*Years;
        boost::shared_ptr<Exercise> exercise(
                                          new AmericanExercise(today,exDate));
        testFdGreeks<FDDividendAmericanEngine<CrankNicolson> >(today,exercise);
    }
}


namespace {

    template <class Engine>
    void testFdDegenerate(const Date& today,
                          const boost::shared_ptr<Exercise>& exercise) {

        DayCounter dc = Actual360();
        boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(54.625));
        Handle<YieldTermStructure> rTS(flatRate(0.052706, dc));
        Handle<YieldTermStructure> qTS(flatRate(0.0, dc));
        Handle<BlackVolTermStructure> volTS(flatVol(0.282922, dc));

        boost::shared_ptr<BlackScholesMertonProcess> process(
                            new BlackScholesMertonProcess(Handle<Quote>(spot),
                                                          qTS, rTS, volTS));

        Size timeSteps = 300;
        Size gridPoints = 300;

        boost::shared_ptr<PricingEngine> engine(
                                    new Engine(process,timeSteps,gridPoints));

        boost::shared_ptr<StrikedTypePayoff> payoff(
                                  new PlainVanillaPayoff(Option::Call, 55.0));

        Real tolerance = 3.0e-3;

        std::vector<Rate> dividends;
        std::vector<Date> dividendDates;

        DividendVanillaOption option1(payoff, exercise,
                                      dividendDates, dividends);
        option1.setPricingEngine(engine);

        // FLOATING_POINT_EXCEPTION
        Real refValue = option1.NPV();

        for (Size i=0; i<=6; i++) {

            dividends.push_back(0.0);
            dividendDates.push_back(today+i);

            DividendVanillaOption option(payoff, exercise,
                                         dividendDates, dividends);
            option.setPricingEngine(engine);
            Real value = option.NPV();

            if (std::fabs(refValue-value) > tolerance)
                BOOST_FAIL("NPV changed by null dividend :\n"
                           << "    previous value: " << value << "\n"
                           << "    current value:  " << refValue << "\n"
                           << "    change:         " << value-refValue);
        }
    }

}


void DividendOptionTest::testFdEuropeanDegenerate() {

    BOOST_TEST_MESSAGE(
         "Testing degenerate finite-differences dividend European option...");

    SavedSettings backup;

    Date today = Date(27,February,2005);
    Settings::instance().evaluationDate() = today;
    Date exDate(13,April,2005);

    boost::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));

    testFdDegenerate<FDDividendEuropeanEngine<CrankNicolson> >(today,exercise);
}

void DividendOptionTest::testFdAmericanDegenerate() {

    BOOST_TEST_MESSAGE(
         "Testing degenerate finite-differences dividend American option...");

    SavedSettings backup;

    Date today = Date(27,February,2005);
    Settings::instance().evaluationDate() = today;
    Date exDate(13,April,2005);

    boost::shared_ptr<Exercise> exercise(new AmericanExercise(today,exDate));

    testFdDegenerate<FDDividendAmericanEngine<CrankNicolson> >(today,exercise);
}


test_suite* DividendOptionTest::suite() {
    test_suite* suite = BOOST_TEST_SUITE("Dividend European option tests");
    suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanValues));
    // Doesn't quite work.  Need to deal with date conventions
    //  suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanKnownValue));
    suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanStartLimit));
    // Doesn't quite work.  Need to use discounted values
    // suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanEndLimit));
    suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanGreeks));
    // FLOATING_POINT_EXCEPTION
    suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdEuropeanValues));
    // FLOATING_POINT_EXCEPTION
    suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdEuropeanGreeks));
    // FLOATING_POINT_EXCEPTION
    suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdAmericanGreeks));
    // FLOATING_POINT_EXCEPTION
    suite->add(QUANTLIB_TEST_CASE(
                              &DividendOptionTest::testFdEuropeanDegenerate));
    // FLOATING_POINT_EXCEPTION
    suite->add(QUANTLIB_TEST_CASE(
                              &DividendOptionTest::testFdAmericanDegenerate));
    return suite;
}



<|start_filename|>ql/pricingengines/vanilla/juquadraticengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004 <NAME>
 Copyright (C) 2007 StatPro Italia srl
 Copyright (C) 2013 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/vanilla/juquadraticengine.hpp>
#include <ql/pricingengines/vanilla/baroneadesiwhaleyengine.hpp>
#include <ql/pricingengines/blackcalculator.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/exercise.hpp>

namespace QuantLib {

    /*  An Approximate Formula for Pricing American Options
        Journal of Derivatives Winter 1999
        Ju, N.
    */


    JuQuadraticApproximationEngine::JuQuadraticApproximationEngine(
              const boost::shared_ptr<GeneralizedBlackScholesProcess>& process)
    : process_(process) {
        registerWith(process_);
    }

    void JuQuadraticApproximationEngine::calculate() const {

        QL_REQUIRE(arguments_.exercise->type() == Exercise::American,
                   "not an American Option");

        boost::shared_ptr<AmericanExercise> ex =
            boost::dynamic_pointer_cast<AmericanExercise>(arguments_.exercise);
        QL_REQUIRE(ex, "non-American exercise given");
        QL_REQUIRE(!ex->payoffAtExpiry(),
                   "payoff at expiry not handled");

        boost::shared_ptr<StrikedTypePayoff> payoff =
            boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
        QL_REQUIRE(payoff, "non-striked payoff given");

        Real variance = process_->blackVolatility()->blackVariance(
            ex->lastDate(), payoff->strike());
        DiscountFactor dividendDiscount = process_->dividendYield()->discount(
            ex->lastDate());
        DiscountFactor riskFreeDiscount = process_->riskFreeRate()->discount(
            ex->lastDate());
        Real spot = process_->stateVariable()->value();
        QL_REQUIRE(spot > 0.0, "negative or null underlying given");
        Real forwardPrice = spot * dividendDiscount / riskFreeDiscount;
        BlackCalculator black(payoff, forwardPrice,
                              std::sqrt(variance), riskFreeDiscount);

        if (dividendDiscount>=1.0 && payoff->optionType()==Option::Call) {
            // early exercise never optimal
            results_.value        = black.value();
            results_.delta        = black.delta(spot);
            results_.deltaForward = black.deltaForward();
            results_.elasticity   = black.elasticity(spot);
            results_.gamma        = black.gamma(spot);

            DayCounter rfdc  = process_->riskFreeRate()->dayCounter();
            DayCounter divdc = process_->dividendYield()->dayCounter();
            DayCounter voldc = process_->blackVolatility()->dayCounter();
            Time t =
                rfdc.yearFraction(process_->riskFreeRate()->referenceDate(),
                                  arguments_.exercise->lastDate());
            results_.rho = black.rho(t);

            t = divdc.yearFraction(process_->dividendYield()->referenceDate(),
                                   arguments_.exercise->lastDate());
            results_.dividendRho = black.dividendRho(t);

            t = voldc.yearFraction(process_->blackVolatility()->referenceDate(),
                                   arguments_.exercise->lastDate());
            results_.vega        = black.vega(t);
            results_.theta       = black.theta(spot, t);
            results_.thetaPerDay = black.thetaPerDay(spot, t);

            results_.strikeSensitivity  = black.strikeSensitivity();
            results_.itmCashProbability = black.itmCashProbability();
        } else {
            // early exercise can be optimal
            CumulativeNormalDistribution cumNormalDist;
            NormalDistribution normalDist;

            Real tolerance = 1e-6;
            Real Sk = BaroneAdesiWhaleyApproximationEngine::criticalPrice(
                payoff, riskFreeDiscount, dividendDiscount, variance,
                tolerance);

            Real forwardSk = Sk * dividendDiscount / riskFreeDiscount;

            Real alpha = -2.0*std::log(riskFreeDiscount)/(variance);
            Real beta = 2.0*std::log(dividendDiscount/riskFreeDiscount)/
                                                (variance);
            Real h = 1 - riskFreeDiscount;
            Real phi;
            switch (payoff->optionType()) {
                case Option::Call:
                    phi = 1;
                    break;
                case Option::Put:
                    phi = -1;
                    break;
                default:
                  QL_FAIL("unknown option type");
            }
            //it can throw: to be fixed
            // FLOATING_POINT_EXCEPTION
            Real temp_root = std::sqrt ((beta-1)*(beta-1) + (4*alpha)/h);
            Real lambda = (-(beta-1) + phi * temp_root) / 2;
            Real lambda_prime = - phi * alpha / (h*h * temp_root);

            Real black_Sk = blackFormula(payoff->optionType(), payoff->strike(),
                                         forwardSk, std::sqrt(variance)) * riskFreeDiscount;
            Real hA = phi * (Sk - payoff->strike()) - black_Sk;

            Real d1_Sk = (std::log(forwardSk/payoff->strike()) + 0.5*variance)
                /std::sqrt(variance);
            Real d2_Sk = d1_Sk - std::sqrt(variance);
            Real part1 = forwardSk * normalDist(d1_Sk) /
                                        (alpha * std::sqrt(variance));
            Real part2 = - phi * forwardSk * cumNormalDist(phi * d1_Sk) *
                      std::log(dividendDiscount) / std::log(riskFreeDiscount);
            Real part3 = + phi * payoff->strike() * cumNormalDist(phi * d2_Sk);
            Real V_E_h = part1 + part2 + part3;

            Real b = (1-h) * alpha * lambda_prime / (2*(2*lambda + beta - 1));
            Real c = - ((1 - h) * alpha / (2 * lambda + beta - 1)) *
                (V_E_h / (hA) + 1 / h + lambda_prime / (2*lambda + beta - 1));
            Real temp_spot_ratio = std::log(spot / Sk);
            Real chi = temp_spot_ratio * (b * temp_spot_ratio + c);

            if (phi*(Sk-spot) > 0) {
                results_.value = black.value() +
                    hA * std::pow((spot/Sk), lambda) / (1 - chi);
                Real temp_chi_prime = (2 * b / spot) * std::log(spot/Sk);
                Real chi_prime = temp_chi_prime + c / spot;
                Real chi_double_prime = 2*b/(spot*spot)
                    - temp_chi_prime / spot - c / (spot*spot);
                Real d1_S = (std::log(forwardPrice/payoff->strike()) + 0.5*variance)
                    / std::sqrt(variance);
                //There is a typo in the original paper from Ju-Zhong
                //the first term is the Black-Scholes delta/gamma.    
                results_.delta = phi * dividendDiscount * cumNormalDist (phi * d1_S)
                    + (lambda / (spot * (1 - chi)) + chi_prime / ((1 - chi)*(1 - chi))) *
                    (phi * (Sk - payoff->strike()) - black_Sk) * std::pow((spot/Sk), lambda);

                results_.gamma = dividendDiscount * normalDist (phi*d1_S) 
                    / (spot * std::sqrt(variance))
                    + (2 * lambda * chi_prime / (spot * (1 - chi) * (1 - chi))
                        + 2 * chi_prime * chi_prime / ((1 - chi) * (1 - chi) * (1 - chi))
                        + chi_double_prime / ((1 - chi) * (1 - chi))
                        + lambda * (lambda - 1) / (spot * spot * (1 - chi)))
                    * (phi * (Sk - payoff->strike()) - black_Sk)
                    * std::pow((spot/Sk), lambda);
            } else {
                results_.value = phi * (spot - payoff->strike());
                results_.delta = phi;
                results_.gamma = 0;
            }

        } // end of "early exercise can be optimal"
    }

}


<|start_filename|>ql/models/shortrate/calibrationhelpers/caphelper.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2001, 2002, 2003 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file caphelper.hpp
    \brief CapHelper calibration helper
*/

#ifndef quantlib_cap_calibration_helper_hpp
#define quantlib_cap_calibration_helper_hpp

#include <ql/models/calibrationhelper.hpp>
#include <ql/instruments/capfloor.hpp>

namespace QuantLib {

    //! calibration helper for ATM cap

    class CapHelper : public CalibrationHelper {
      public:
        CapHelper(const Period& length,
                  const Handle<Quote>& volatility,
                  const boost::shared_ptr<IborIndex>& index,
                  // data for ATM swap-rate calculation
                  Frequency fixedLegFrequency,
                  const DayCounter& fixedLegDayCounter,
                  bool includeFirstSwaplet,
                  const Handle<YieldTermStructure>& termStructure,
                  CalibrationHelper::CalibrationErrorType errorType
                                    = CalibrationHelper::RelativePriceError);
        virtual void addTimesTo(std::list<Time>& times) const;
        virtual Real modelValue() const;
        virtual Real blackPrice(Volatility volatility) const;
      private:
        void performCalculations() const;
        mutable boost::shared_ptr<Cap> cap_;
        const Period length_;
        const boost::shared_ptr<IborIndex> index_;
        const Frequency fixedLegFrequency_;
        const DayCounter fixedLegDayCounter_;
        const bool includeFirstSwaplet_;
    };

}

#endif


<|start_filename|>ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008, 2009 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file fdblackscholesvanillaengine.hpp
    \brief Finite-Differences Black Scholes vanilla option engine
*/

#ifndef quantlib_fd_black_scholes_vanilla_engine_hpp
#define quantlib_fd_black_scholes_vanilla_engine_hpp

#include <ql/pricingengine.hpp>
#include <ql/instruments/dividendvanillaoption.hpp>
#include <ql/methods/finitedifferences/solvers/fdmbackwardsolver.hpp>

namespace QuantLib {

    //! Finite-Differences Black Scholes vanilla option engine

    /*! \ingroup vanillaengines

        \test the correctness of the returned value is tested by
              reproducing results available in web/literature
              and comparison with Black pricing.
    */
    class GeneralizedBlackScholesProcess;

    class FdBlackScholesVanillaEngine : public DividendVanillaOption::engine {
      public:
        // Constructor
          FdBlackScholesVanillaEngine(
                const boost::shared_ptr<GeneralizedBlackScholesProcess>&,
                Size tGrid = 100, Size xGrid = 100, Size dampingSteps = 0,
                const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas(),
                bool localVol = false,
                Real illegalLocalVolOverwrite = -Null<Real>());

        void calculate() const;

      private:
        const boost::shared_ptr<GeneralizedBlackScholesProcess> process_;
        const Size tGrid_, xGrid_, dampingSteps_;
        const FdmSchemeDesc schemeDesc_;
        const bool localVol_;
        const Real illegalLocalVolOverwrite_;
    };
}

#endif


<|start_filename|>ql/math/randomnumbers/haltonrsg.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2003 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file haltonrsg.hpp
    \brief Halton low-discrepancy sequence generator
*/

#ifndef quantlib_halton_ld_rsg_h
#define quantlib_halton_ld_rsg_h

#include <ql/methods/montecarlo/sample.hpp>
#include <vector>

namespace QuantLib {

    //! Halton low-discrepancy sequence generator
    /*! Halton algorithm for low-discrepancy sequence.  For more
        details see chapter 8, paragraph 2 of "Monte Carlo Methods in
        Finance", by <NAME>

        \test
        - the correctness of the returned values is tested by
          reproducing known good values.
        - the correctness of the returned values is tested by checking
          their discrepancy against known good values.
    */
    class HaltonRsg {
      public:
        typedef Sample<std::vector<Real> > sample_type;
        HaltonRsg(Size dimensionality,
                  unsigned long seed = 0,
                  bool randomStart = true,
                  bool randomShift = false);
        const sample_type& nextSequence() const;
        const sample_type& lastSequence() const {
            return sequence_;
        }
        Size dimension() const {return dimensionality_;}
      private:
        Size dimensionality_;
        mutable unsigned long sequenceCounter_;
        mutable sample_type sequence_;
        std::vector<unsigned long> randomStart_;
        std::vector<Real>  randomShift_;
    };
}


#endif


<|start_filename|>ql/math/rounding.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004 Decillion Pty(Ltd)

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file rounding.hpp
    \brief Rounding implementation
*/

#ifndef quantlib_rounding_hpp
#define quantlib_rounding_hpp

#include <ql/types.hpp>

namespace QuantLib {

    //! basic rounding class
    /*! \test the correctness of the returned values is tested by
              checking them against known good results.
    */
    class Rounding {
      public:
        //! rounding methods
        /*! The rounding methods follow the OMG specification available
            at <http://www.omg.org/cgi-bin/doc?formal/00-06-29.pdf>.

            \warning the names of the Floor and Ceiling methods might
                     be misleading. Check the provided reference.
        */
        enum Type {
            None,    /*!< do not round: return the number unmodified */
            Up,      /*!< the first decimal place past the precision will be
                          rounded up. This differs from the OMG rule which
                          rounds up only if the decimal to be rounded is
                          greater than or equal to the rounding digit */
            Down,    /*!< all decimal places past the precision will be
                          truncated */
            Closest, /*!< the first decimal place past the precision
                          will be rounded up if greater than or equal
                          to the rounding digit; this corresponds to
                          the OMG round-up rule.  When the rounding
                          digit is 5, the result will be the one
                          closest to the original number, hence the
                          name. */
            Floor,   /*!< positive numbers will be rounded up and negative
                          numbers will be rounded down using the OMG round up
                          and round down rules */
            Ceiling  /*!< positive numbers will be rounded down and negative
                          numbers will be rounded up using the OMG round up
                          and round down rules */
        };
        //! default constructor
        /*! Instances built through this constructor don't perform
            any rounding.
        */
        Rounding()
        : type_(None) {}
        Rounding(Integer precision,
                 Type type = Closest,
                 Integer digit = 5)
        : precision_(precision), type_(type), digit_(digit) {}
        //! perform rounding
        Decimal operator()(Decimal value) const;
        //! \name Inspectors
        //@{
        Integer precision() const { return precision_; }
        Type type() const { return type_; }
        Integer roundingDigit() const { return digit_; }
      private:
        Integer precision_;
        Type type_;
        Integer digit_;
    };


    //! Up-rounding.
    class UpRounding : public Rounding {
      public:
        UpRounding(Integer precision,
                   Integer digit = 5)
        : Rounding(precision,Up,digit) {}
    };

    //! Down-rounding.
    class DownRounding : public Rounding {
      public:
        DownRounding(Integer precision,
                     Integer digit = 5)
        : Rounding(precision,Down,digit) {}
    };

    //! Closest rounding.
    class ClosestRounding : public Rounding {
      public:
        ClosestRounding(Integer precision,
                        Integer digit = 5)
        : Rounding(precision,Closest,digit) {}
    };

    //! Ceiling truncation.
    class CeilingTruncation : public Rounding {
      public:
        CeilingTruncation(Integer precision,
                          Integer digit = 5)
        : Rounding(precision,Ceiling,digit) {}
    };

    //! %Floor truncation.
    class FloorTruncation : public Rounding {
      public:
        FloorTruncation(Integer precision,
                        Integer digit = 5)
        : Rounding(precision,Floor,digit) {}
    };

}


#endif


<|start_filename|>ql/termstructures/volatility/gaussian1dsmilesection.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file gaussian1dsmilesection.hpp
    \brief smile section generated by a gaussian 1d model
*/

#ifndef quantlib_gaussian1dsmilesection_hpp
#define quantlib_gaussian1dsmilesection_hpp

#include <ql/termstructures/volatility/smilesection.hpp>
#include <ql/indexes/swapindex.hpp>
#include <ql/indexes/iborindex.hpp>
#include <ql/models/shortrate/onefactormodels/gaussian1dmodel.hpp>
#include <ql/pricingengines/swaption/gaussian1dswaptionengine.hpp>
#include <ql/pricingengines/capfloor/gaussian1dcapfloorengine.hpp>

namespace QuantLib {

/*! smile section based on a gaussian 1d model instance
    if curves are attached to the swap or ibor index, these are used to adjust
    the model's yield term structure, if not the model's yield term structure
    is used directly */

class Gaussian1dSmileSection : public SmileSection {
  public:
    Gaussian1dSmileSection(
        const Date &fixingDate, const boost::shared_ptr<SwapIndex> &swapIndex,
        const boost::shared_ptr<Gaussian1dModel> &model, const DayCounter &dc,
        const boost::shared_ptr<Gaussian1dSwaptionEngine> swaptionEngine =
            boost::shared_ptr<Gaussian1dSwaptionEngine>());
    Gaussian1dSmileSection(
        const Date &fixingDate, const boost::shared_ptr<IborIndex> &swapIndex,
        const boost::shared_ptr<Gaussian1dModel> &model, const DayCounter &dc,
        const boost::shared_ptr<Gaussian1dCapFloorEngine> capEngine =
            boost::shared_ptr<Gaussian1dCapFloorEngine>());

    // the minimum strike is zero only because we are
    // returning a lognormal section
    Real minStrike() const { return 0.0; }
    Real maxStrike() const { return QL_MAX_REAL; }

    Real atmLevel() const;
    Real optionPrice(Rate strike, Option::Type = Option::Call,
                     Real discount = 1.0) const;

  protected:
    Real volatilityImpl(Rate strike) const;

  private:
    Real atm_, annuity_;
    Date fixingDate_;
    boost::shared_ptr<SwapIndex> swapIndex_;
    boost::shared_ptr<IborIndex> iborIndex_;
    boost::shared_ptr<Gaussian1dModel> model_;
    boost::shared_ptr<PricingEngine> engine_;
};
}

#endif


<|start_filename|>ql/pricingengines/credit/integralcdsengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008, 2009 StatPro Italia srl
 Copyright (C) 2009 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/credit/integralcdsengine.hpp>
#include <ql/instruments/claim.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>
#include <ql/cashflows/fixedratecoupon.hpp>

namespace QuantLib {

    IntegralCdsEngine::IntegralCdsEngine(
                   const Period& step,
                   const Handle<DefaultProbabilityTermStructure>& probability,
                   Real recoveryRate,
                   const Handle<YieldTermStructure>& discountCurve,
                   boost::optional<bool> includeSettlementDateFlows)
    : integrationStep_(step), probability_(probability),
      recoveryRate_(recoveryRate), discountCurve_(discountCurve),
      includeSettlementDateFlows_(includeSettlementDateFlows) {
        registerWith(probability_);
        registerWith(discountCurve_);
    }

    void IntegralCdsEngine::calculate() const {
        QL_REQUIRE(integrationStep_ != Period(),
                   "null period set");
        QL_REQUIRE(!discountCurve_.empty(),
                   "no discount term structure set");
        QL_REQUIRE(!probability_.empty(),
                   "no probability term structure set");

        Date today = Settings::instance().evaluationDate();
        Date settlementDate = discountCurve_->referenceDate();

        // Upfront Flow NPV. Either we are on-the-run (no flow)
        // or we are forward start
        Real upfPVO1 = 0.0;
        if(!arguments_.upfrontPayment->hasOccurred(
                                               settlementDate,
                                               includeSettlementDateFlows_)) {
            // date determining the probability survival so we have to pay
            // the upfront (did not knock out)
            Date effectiveUpfrontDate =
                arguments_.protectionStart > probability_->referenceDate() ?
                    arguments_.protectionStart : probability_->referenceDate();
            upfPVO1 =
                probability_->survivalProbability(effectiveUpfrontDate) *
                discountCurve_->discount(arguments_.upfrontPayment->date());
        }
        results_.upfrontNPV = upfPVO1 * arguments_.upfrontPayment->amount();

        results_.couponLegNPV = 0.0;
        results_.defaultLegNPV = 0.0;
        for (Size i=0; i<arguments_.leg.size(); ++i) {
            if (arguments_.leg[i]->hasOccurred(settlementDate,
                                               includeSettlementDateFlows_))
                continue;

            boost::shared_ptr<FixedRateCoupon> coupon =
                boost::dynamic_pointer_cast<FixedRateCoupon>(arguments_.leg[i]);

            // In order to avoid a few switches, we calculate the NPV
            // of both legs as a positive quantity. We'll give them
            // the right sign at the end.

            Date paymentDate = coupon->date(),
                 startDate = (i == 0 ? arguments_.protectionStart :
                                       coupon->accrualStartDate()),
                 endDate = coupon->accrualEndDate();
            Date effectiveStartDate =
                (startDate <= today && today <= endDate) ? today : startDate;
            Real couponAmount = coupon->amount();

            Probability S = probability_->survivalProbability(paymentDate);

            // On one side, we add the fixed rate payments in case of
            // survival.
            results_.couponLegNPV +=
                S * couponAmount * discountCurve_->discount(paymentDate);

            // On the other side, we add the payment (and possibly the
            // accrual) in case of default.

            Period step = integrationStep_;
            Date d0 = effectiveStartDate;
            Date d1 = std::min(d0 + step, endDate);
            Probability P0 = probability_->defaultProbability(d0);
            DiscountFactor endDiscount = discountCurve_->discount(paymentDate);
            do {
                DiscountFactor B =
                    arguments_.paysAtDefaultTime ?
                    discountCurve_->discount(d1) :
                    endDiscount;

                Probability P1 = probability_->defaultProbability(d1);
                Probability dP = P1 - P0;

                // accrual...
                if (arguments_.settlesAccrual) {
                    if (arguments_.paysAtDefaultTime)
                        results_.couponLegNPV +=
                            coupon->accruedAmount(d1) * B * dP;
                    else
                        results_.couponLegNPV +=
                            couponAmount * B * dP;
                }

                // ...and claim.
                Real claim = arguments_.claim->amount(d1,
                                                      arguments_.notional,
                                                      recoveryRate_);
                results_.defaultLegNPV += claim * B * dP;

                // setup for next time around the loop
                P0 = P1;
                d0 = d1;
                d1 = std::min(d0 + step, endDate);
            } while (d0 < endDate);
        }

        Real upfrontSign = 1.0;
        switch (arguments_.side) {
          case Protection::Seller:
            results_.defaultLegNPV *= -1.0;
            break;
          case Protection::Buyer:
            results_.couponLegNPV *= -1.0;
            results_.upfrontNPV   *= -1.0;
            upfrontSign = -1.0;
            break;
          default:
            QL_FAIL("unknown protection side");
        }

        results_.value =
            results_.defaultLegNPV+results_.couponLegNPV+results_.upfrontNPV;
        results_.errorEstimate = Null<Real>();

        if (results_.couponLegNPV != 0.0) {
            results_.fairSpread =
                -results_.defaultLegNPV*arguments_.spread/results_.couponLegNPV;
        } else {
            results_.fairSpread = Null<Rate>();
        }

        Real upfrontSensitivity = upfPVO1 * arguments_.notional;
        if (upfrontSensitivity != 0.0) {
            results_.fairUpfront =
                -upfrontSign*(results_.defaultLegNPV + results_.couponLegNPV)
                / upfrontSensitivity;
        } else {
            results_.fairUpfront = Null<Rate>();
        }

        static const Rate basisPoint = 1.0e-4;

        if (arguments_.spread != 0.0) {
            results_.couponLegBPS =
                results_.couponLegNPV*basisPoint/arguments_.spread;
        } else {
            results_.couponLegBPS = Null<Rate>();
        }

        if (arguments_.upfront && *arguments_.upfront != 0.0) {
            results_.upfrontBPS =
                results_.upfrontNPV*basisPoint/(*arguments_.upfront);
        } else {
            results_.upfrontBPS = Null<Rate>();
        }
    }

}



<|start_filename|>ql/methods/finitedifferences/operators/firstderivativeop.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
#include <ql/methods/finitedifferences/operators/firstderivativeop.hpp>

namespace QuantLib {

    FirstDerivativeOp::FirstDerivativeOp(
                                Size direction,
                                const boost::shared_ptr<FdmMesher>& mesher)
    : TripleBandLinearOp(direction, mesher) {

        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();
        const FdmLinearOpIterator endIter = layout->end();

        for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) {
            const Size i = iter.index();
            const Real hm = mesher->dminus(iter, direction_);
            const Real hp = mesher->dplus(iter, direction_);

            const Real zetam1 = hm*(hm+hp);
            const Real zeta0  = hm*hp;
            const Real zetap1 = hp*(hm+hp);

            if (iter.coordinates()[direction_] == 0) {
                //upwinding scheme
                lower_[i] = 0.0;
                diag_[i]  = -(upper_[i] = 1/hp);
            }
            else if (   iter.coordinates()[direction_]
                     == layout->dim()[direction]-1) {
                 // downwinding scheme
                lower_[i] = -(diag_[i] = 1/hm);
                upper_[i] = 0.0;
            }
            else {
                lower_[i] = -hp/zetam1;
                diag_[i]  = (hp-hm)/zeta0;
                upper_[i] = hm/zetap1;
            }
        }
    }
}



<|start_filename|>ql/methods/finitedifferences/solvers/fdmbackwardsolver.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 <NAME>
 Copyright (C) 2009 <NAME>
 Copyright (C) 2009 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file fdmbackwardsolver.cpp
*/

#include <ql/methods/finitedifferences/finitedifferencemodel.hpp>
#include <ql/methods/finitedifferences/solvers/fdmbackwardsolver.hpp>
#include <ql/methods/finitedifferences/schemes/douglasscheme.hpp>
#include <ql/methods/finitedifferences/schemes/craigsneydscheme.hpp>
#include <ql/methods/finitedifferences/schemes/hundsdorferscheme.hpp>
#include <ql/methods/finitedifferences/schemes/impliciteulerscheme.hpp>
#include <ql/methods/finitedifferences/schemes/expliciteulerscheme.hpp>
#include <ql/methods/finitedifferences/schemes/modifiedcraigsneydscheme.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmstepconditioncomposite.hpp>

namespace QuantLib {
    
    FdmSchemeDesc::FdmSchemeDesc(FdmSchemeType aType, Real aTheta, Real aMu)
    : type(aType), theta(aTheta), mu(aMu) { }

    FdmSchemeDesc FdmSchemeDesc::Douglas() { 
        return FdmSchemeDesc(FdmSchemeDesc::DouglasType, 0.5, 0.0);
    }
    
    FdmSchemeDesc FdmSchemeDesc::CraigSneyd() {
        return FdmSchemeDesc(FdmSchemeDesc::CraigSneydType,0.5, 0.5);
    }
    
    FdmSchemeDesc FdmSchemeDesc::ModifiedCraigSneyd() { 
        return FdmSchemeDesc(FdmSchemeDesc::ModifiedCraigSneydType, 
                             1.0/3.0, 1.0/3.0);
    }
    
    FdmSchemeDesc FdmSchemeDesc::Hundsdorfer() {
        return FdmSchemeDesc(FdmSchemeDesc::HundsdorferType, 
                             0.5+std::sqrt(3.0)/6, 0.5);
    }
    
    FdmSchemeDesc FdmSchemeDesc::ModifiedHundsdorfer() {
        return FdmSchemeDesc(FdmSchemeDesc::HundsdorferType, 
                             1.0-std::sqrt(2.0)/2, 0.5);
    }
    
    FdmSchemeDesc FdmSchemeDesc::ExplicitEuler() {
        return FdmSchemeDesc(FdmSchemeDesc::ExplicitEulerType, 0.0, 0.0);
    }

    FdmSchemeDesc FdmSchemeDesc::ImplicitEuler() {
        return FdmSchemeDesc(FdmSchemeDesc::ImplicitEulerType, 0.0, 0.0);
    }

    FdmBackwardSolver::FdmBackwardSolver(
        const boost::shared_ptr<FdmLinearOpComposite>& map,
        const FdmBoundaryConditionSet& bcSet,
        const boost::shared_ptr<FdmStepConditionComposite> condition,
        const FdmSchemeDesc& schemeDesc)
    : map_(map), bcSet_(bcSet),
      condition_((condition) ? condition 
                             : boost::shared_ptr<FdmStepConditionComposite>(
                                 new FdmStepConditionComposite(
                                     std::list<std::vector<Time> >(),
                                     FdmStepConditionComposite::Conditions()))),
      schemeDesc_(schemeDesc) {
     }
        
    void FdmBackwardSolver::rollback(FdmBackwardSolver::array_type& rhs, 
                                     Time from, Time to,
                                     Size steps, Size dampingSteps) {

        const Time deltaT = from - to;
        const Size allSteps = steps + dampingSteps;
        const Time dampingTo = from - (deltaT*dampingSteps)/allSteps;
                    
        if (   dampingSteps 
            && schemeDesc_.type != FdmSchemeDesc::ImplicitEulerType) {
            ImplicitEulerScheme implicitEvolver(map_, bcSet_);    
            FiniteDifferenceModel<ImplicitEulerScheme> 
                    dampingModel(implicitEvolver, condition_->stoppingTimes());
            dampingModel.rollback(rhs, from, dampingTo, 
                                  dampingSteps, *condition_);
        }
        
        switch (schemeDesc_.type) {
          case FdmSchemeDesc::HundsdorferType:
            {
                HundsdorferScheme hsEvolver(schemeDesc_.theta, schemeDesc_.mu, 
                                            map_, bcSet_);
                FiniteDifferenceModel<HundsdorferScheme> 
                               hsModel(hsEvolver, condition_->stoppingTimes());
                hsModel.rollback(rhs, dampingTo, to, steps, *condition_);
            }
            break;
          case FdmSchemeDesc::DouglasType:
            {
                DouglasScheme dsEvolver(schemeDesc_.theta, map_, bcSet_);
                FiniteDifferenceModel<DouglasScheme> 
                               dsModel(dsEvolver, condition_->stoppingTimes());
                dsModel.rollback(rhs, dampingTo, to, steps, *condition_);
            }
            break;
          case FdmSchemeDesc::CraigSneydType:
            {
                CraigSneydScheme csEvolver(schemeDesc_.theta, schemeDesc_.mu, 
                                           map_, bcSet_);
                FiniteDifferenceModel<CraigSneydScheme> 
                               csModel(csEvolver, condition_->stoppingTimes());
                csModel.rollback(rhs, dampingTo, to, steps, *condition_);
            }
            break;
          case FdmSchemeDesc::ModifiedCraigSneydType:
            {
                ModifiedCraigSneydScheme csEvolver(schemeDesc_.theta, 
                                                   schemeDesc_.mu,
                                                   map_, bcSet_);
                FiniteDifferenceModel<ModifiedCraigSneydScheme> 
                              mcsModel(csEvolver, condition_->stoppingTimes());
                mcsModel.rollback(rhs, dampingTo, to, steps, *condition_);
            }
            break;
          case FdmSchemeDesc::ImplicitEulerType:
            {
                ImplicitEulerScheme implicitEvolver(map_, bcSet_);
                FiniteDifferenceModel<ImplicitEulerScheme> 
                   implicitModel(implicitEvolver, condition_->stoppingTimes());
                implicitModel.rollback(rhs, from, to, allSteps, *condition_);
            }
            break;
          case FdmSchemeDesc::ExplicitEulerType:
            {
                ExplicitEulerScheme explicitEvolver(map_, bcSet_);
                FiniteDifferenceModel<ExplicitEulerScheme> 
                   explicitModel(explicitEvolver, condition_->stoppingTimes());
                explicitModel.rollback(rhs, dampingTo, to, steps, *condition_);
            }
            break;
          default:
            QL_FAIL("Unknown scheme type");
        }
    }
}


<|start_filename|>ql/pricingengines/vanilla/fdmultiperiodengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2005 <NAME>
 Copyright (C) 2007, 2009 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file fdmultiperiodengine.hpp
    \brief base engine for options with events happening at specific times
*/

#ifndef quantlib_fd_multi_period_engine_hpp
#define quantlib_fd_multi_period_engine_hpp

#include <ql/pricingengines/vanilla/fdvanillaengine.hpp>
#include <ql/instruments/oneassetoption.hpp>
#include <ql/methods/finitedifferences/fdtypedefs.hpp>
#include <ql/event.hpp>
#include <ql/exercise.hpp>

namespace QuantLib {

    template <template <class> class Scheme = CrankNicolson>
    class FDMultiPeriodEngine : public FDVanillaEngine {
      protected:
        typedef FiniteDifferenceModel<Scheme<TridiagonalOperator> > model_type;

        FDMultiPeriodEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             Size timeSteps = 100, Size gridPoints = 100,
             bool timeDependent = false);
        mutable std::vector<boost::shared_ptr<Event> > events_;
        mutable std::vector<Time> stoppingTimes_;
        Size timeStepPerPeriod_;
        mutable SampledCurve prices_;

        virtual void setupArguments(
               const PricingEngine::arguments* args,
               const std::vector<boost::shared_ptr<Event> >& schedule) const {
            FDVanillaEngine::setupArguments(args);
            events_ = schedule;
            stoppingTimes_.clear();
            Size n = schedule.size();
            stoppingTimes_.reserve(n);
            for (Size i=0; i<n; ++i)
                stoppingTimes_.push_back(process_->time(events_[i]->date()));
        }

        virtual void setupArguments(const PricingEngine::arguments* a) const {
            FDVanillaEngine::setupArguments(a);
            const OneAssetOption::arguments *args =
                dynamic_cast<const OneAssetOption::arguments*>(a);
            QL_REQUIRE(args, "incorrect argument type");
            events_.clear();

            Size n = args->exercise->dates().size();
            stoppingTimes_.resize(n);
            for (Size i=0; i<n; ++i)
                stoppingTimes_[i] =
                      process_->time(args->exercise->date(i));
        }

        virtual void calculate(PricingEngine::results*) const;
        mutable boost::shared_ptr<StandardStepCondition > stepCondition_;
        mutable boost::shared_ptr<model_type> model_;
        virtual void executeIntermediateStep(Size step) const = 0;
        virtual void initializeStepCondition() const;
        virtual void initializeModel() const;
        Time getDividendTime(Size i) const {
            return stoppingTimes_[i];
        }
    };


    // template definitions

    template <template <class> class Scheme>
    FDMultiPeriodEngine<Scheme>::FDMultiPeriodEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             Size timeSteps, Size gridPoints, bool timeDependent)
    : FDVanillaEngine(process, timeSteps, gridPoints, timeDependent),
      timeStepPerPeriod_(timeSteps) {}

    template <template <class> class Scheme>
    void FDMultiPeriodEngine<Scheme>::calculate(
                                            PricingEngine::results* r) const {
        OneAssetOption::results *results =
            dynamic_cast<OneAssetOption::results *>(r);
        QL_REQUIRE(results, "incorrect argument type");
        Time beginDate, endDate;
        Size dateNumber = stoppingTimes_.size();
        bool lastDateIsResTime = false;
        Integer firstIndex = -1;
        Integer lastIndex = static_cast<Integer>(dateNumber) - 1;
        bool firstDateIsZero = false;
        Time firstNonZeroDate = getResidualTime();

        Real dateTolerance = 1e-6;

        if (dateNumber > 0) {
            QL_REQUIRE(getDividendTime(0) >= 0,
                       "first date (" << getDividendTime(0)
                       << ") cannot be negative");
            if(getDividendTime(0) < getResidualTime() * dateTolerance ){
                firstDateIsZero = true;
                firstIndex = 0;
                if(dateNumber >= 2)
                    firstNonZeroDate = getDividendTime(1);
            }

            if (std::fabs(getDividendTime(lastIndex) - getResidualTime())
                < dateTolerance) {
                lastDateIsResTime = true;
                lastIndex = Integer(dateNumber) - 2;
            }

            if (!firstDateIsZero)
                firstNonZeroDate = getDividendTime(0);

            if (dateNumber >= 2) {
                for (Size j = 1; j < dateNumber; j++)
                    QL_REQUIRE(getDividendTime(j-1) < getDividendTime(j),
                               "dates must be in increasing order: "
                               << getDividendTime(j-1)
                               << " is not strictly smaller than "
                               << getDividendTime(j));
            }
        }

        Time dt = getResidualTime()/(timeStepPerPeriod_*(dateNumber+1));

        // Ensure that dt is always smaller than the first non-zero date
        if (firstNonZeroDate <= dt)
            dt = firstNonZeroDate/2.0;

        setGridLimits();
        initializeInitialCondition();
        initializeOperator();
        initializeBoundaryConditions();
        initializeModel();
        initializeStepCondition();

        prices_ = intrinsicValues_;
        if(lastDateIsResTime)
            executeIntermediateStep(dateNumber - 1);

        Integer j = lastIndex;
        do {
            if (j == Integer(dateNumber) - 1)
                beginDate = getResidualTime();
            else
                beginDate = getDividendTime(j+1);

            if (j >= 0)
                endDate = getDividendTime(j);
            else
                endDate = dt;

            model_->rollback(prices_.values(),
                             beginDate, endDate,
                             timeStepPerPeriod_, *stepCondition_);
            if (j >= 0)
                executeIntermediateStep(j);
        } while (--j >= firstIndex);

        model_->rollback(prices_.values(), dt, 0, 1, *stepCondition_);

        if(firstDateIsZero)
            executeIntermediateStep(0);

        results->value = prices_.valueAtCenter();
        results->delta = prices_.firstDerivativeAtCenter();
        results->gamma = prices_.secondDerivativeAtCenter();
        results->additionalResults["priceCurve"] = prices_;
    }

    template <template <class> class Scheme>
    void FDMultiPeriodEngine<Scheme>::initializeStepCondition() const{
        stepCondition_ = boost::shared_ptr<StandardStepCondition>(
                                                  new NullCondition<Array>());
    }

    template <template <class> class Scheme>
    void FDMultiPeriodEngine<Scheme>::initializeModel() const{
        model_ = boost::shared_ptr<model_type>(
                              new model_type(finiteDifferenceOperator_,BCs_));
    }

}


#endif


<|start_filename|>ql/models/marketmodels/products/multistep/callspecifiedmultiproduct.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/


#ifndef quantlib_callspecified_multiproduct_hpp
#define quantlib_callspecified_multiproduct_hpp

#include <ql/models/marketmodels/evolutiondescription.hpp>
#include <ql/models/marketmodels/multiproduct.hpp>
#include <ql/methods/montecarlo/exercisestrategy.hpp>
#include <ql/utilities/clone.hpp>
#include <valarray>

namespace QuantLib {

    class CallSpecifiedMultiProduct : public MarketModelMultiProduct {
     public:
        CallSpecifiedMultiProduct(
                             const Clone<MarketModelMultiProduct>& underlying,
                             const Clone<ExerciseStrategy<CurveState> >&,
                             const Clone<MarketModelMultiProduct>& rebate
                                          = Clone<MarketModelMultiProduct>());
        //! \name MarketModelMultiProduct interface
        //@{
        std::vector<Size> suggestedNumeraires() const;
        const EvolutionDescription& evolution() const;
        std::vector<Time> possibleCashFlowTimes() const;
        Size numberOfProducts() const;
        Size maxNumberOfCashFlowsPerProductPerStep() const;
        void reset();
        bool nextTimeStep(
                    const CurveState& currentState,
                    std::vector<Size>& numberCashFlowsThisStep,
                    std::vector<std::vector<CashFlow> >& cashFlowsGenerated);
        std::auto_ptr<MarketModelMultiProduct> clone() const;
        //@}
        const MarketModelMultiProduct& underlying() const;
        const ExerciseStrategy<CurveState>& strategy() const;
        const MarketModelMultiProduct& rebate() const;
        void enableCallability();
        void disableCallability();
      private:
        Clone<MarketModelMultiProduct> underlying_;
        Clone<ExerciseStrategy<CurveState> > strategy_;
        Clone<MarketModelMultiProduct> rebate_;
        EvolutionDescription evolution_;
        std::vector<std::valarray<bool> > isPresent_;
        std::vector<Time> cashFlowTimes_;
        Size rebateOffset_;
        bool wasCalled_;
        std::vector<Size> dummyCashFlowsThisStep_;
        std::vector<std::vector<CashFlow> > dummyCashFlowsGenerated_;
        Size currentIndex_;
        bool callable_;
    };

}

#endif


<|start_filename|>ql/pricingengines/vanilla/mceuropeanengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
 Copyright (C) 2003 <NAME>
 Copyright (C) 2007, 2008 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file mceuropeanengine.hpp
    \brief Monte Carlo European option engine
*/

#ifndef quantlib_montecarlo_european_engine_hpp
#define quantlib_montecarlo_european_engine_hpp

#include <ql/pricingengines/vanilla/mcvanillaengine.hpp>
#include <ql/processes/blackscholesprocess.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/volatility/equityfx/blackvariancecurve.hpp>

namespace QuantLib {

    //! European option pricing engine using Monte Carlo simulation
    /*! \ingroup vanillaengines

        \test the correctness of the returned value is tested by
              checking it against analytic results.
    */
    template <class RNG = PseudoRandom, class S = Statistics>
    class MCEuropeanEngine : public MCVanillaEngine<SingleVariate,RNG,S> {
      public:
        typedef
        typename MCVanillaEngine<SingleVariate,RNG,S>::path_generator_type
            path_generator_type;
        typedef
        typename MCVanillaEngine<SingleVariate,RNG,S>::path_pricer_type
            path_pricer_type;
        typedef typename MCVanillaEngine<SingleVariate,RNG,S>::stats_type
            stats_type;
        // constructor
        MCEuropeanEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             Size timeSteps,
             Size timeStepsPerYear,
             bool brownianBridge,
             bool antitheticVariate,
             Size requiredSamples,
             Real requiredTolerance,
             Size maxSamples,
             BigNatural seed);
      protected:
        boost::shared_ptr<path_pricer_type> pathPricer() const;
    };

    //! Monte Carlo European engine factory
    template <class RNG = PseudoRandom, class S = Statistics>
    class MakeMCEuropeanEngine {
      public:
        MakeMCEuropeanEngine(
                    const boost::shared_ptr<GeneralizedBlackScholesProcess>&);
        // named parameters
        MakeMCEuropeanEngine& withSteps(Size steps);
        MakeMCEuropeanEngine& withStepsPerYear(Size steps);
        MakeMCEuropeanEngine& withBrownianBridge(bool b = true);
        MakeMCEuropeanEngine& withSamples(Size samples);
        MakeMCEuropeanEngine& withAbsoluteTolerance(Real tolerance);
        MakeMCEuropeanEngine& withMaxSamples(Size samples);
        MakeMCEuropeanEngine& withSeed(BigNatural seed);
        MakeMCEuropeanEngine& withAntitheticVariate(bool b = true);
        // conversion to pricing engine
        operator boost::shared_ptr<PricingEngine>() const;
      private:
        boost::shared_ptr<GeneralizedBlackScholesProcess> process_;
        bool antithetic_;
        Size steps_, stepsPerYear_, samples_, maxSamples_;
        Real tolerance_;
        bool brownianBridge_;
        BigNatural seed_;
    };

    class EuropeanPathPricer : public PathPricer<Path> {
      public:
        EuropeanPathPricer(Option::Type type,
                           Real strike,
                           DiscountFactor discount);
        Real operator()(const Path& path) const;
      private:
        PlainVanillaPayoff payoff_;
        DiscountFactor discount_;
    };


    // inline definitions

    template <class RNG, class S>
    inline
    MCEuropeanEngine<RNG,S>::MCEuropeanEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             Size timeSteps,
             Size timeStepsPerYear,
             bool brownianBridge,
             bool antitheticVariate,
             Size requiredSamples,
             Real requiredTolerance,
             Size maxSamples,
             BigNatural seed)
    : MCVanillaEngine<SingleVariate,RNG,S>(process,
                                           timeSteps,
                                           timeStepsPerYear,
                                           brownianBridge,
                                           antitheticVariate,
                                           false,
                                           requiredSamples,
                                           requiredTolerance,
                                           maxSamples,
                                           seed) {}


    template <class RNG, class S>
    inline
    boost::shared_ptr<typename MCEuropeanEngine<RNG,S>::path_pricer_type>
    MCEuropeanEngine<RNG,S>::pathPricer() const {

        boost::shared_ptr<PlainVanillaPayoff> payoff =
            boost::dynamic_pointer_cast<PlainVanillaPayoff>(
                this->arguments_.payoff);
        QL_REQUIRE(payoff, "non-plain payoff given");

        boost::shared_ptr<GeneralizedBlackScholesProcess> process =
            boost::dynamic_pointer_cast<GeneralizedBlackScholesProcess>(
                this->process_);
        QL_REQUIRE(process, "Black-Scholes process required");

        return boost::shared_ptr<
                       typename MCEuropeanEngine<RNG,S>::path_pricer_type>(
          new EuropeanPathPricer(
              payoff->optionType(),
              payoff->strike(),
              process->riskFreeRate()->discount(this->timeGrid().back())));
    }


    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>::MakeMCEuropeanEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process)
    : process_(process), antithetic_(false),
      steps_(Null<Size>()), stepsPerYear_(Null<Size>()),
      samples_(Null<Size>()), maxSamples_(Null<Size>()),
      tolerance_(Null<Real>()), brownianBridge_(false), seed_(0) {}

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withSteps(Size steps) {
        steps_ = steps;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withStepsPerYear(Size steps) {
        stepsPerYear_ = steps;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withSamples(Size samples) {
        QL_REQUIRE(tolerance_ == Null<Real>(),
                   "tolerance already set");
        samples_ = samples;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withAbsoluteTolerance(Real tolerance) {
        QL_REQUIRE(samples_ == Null<Size>(),
                   "number of samples already set");
        QL_REQUIRE(RNG::allowsErrorEstimate,
                   "chosen random generator policy "
                   "does not allow an error estimate");
        tolerance_ = tolerance;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withMaxSamples(Size samples) {
        maxSamples_ = samples;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withSeed(BigNatural seed) {
        seed_ = seed;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withBrownianBridge(bool brownianBridge) {
        brownianBridge_ = brownianBridge;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCEuropeanEngine<RNG,S>&
    MakeMCEuropeanEngine<RNG,S>::withAntitheticVariate(bool b) {
        antithetic_ = b;
        return *this;
    }

    template <class RNG, class S>
    inline
    MakeMCEuropeanEngine<RNG,S>::operator boost::shared_ptr<PricingEngine>()
                                                                      const {
        QL_REQUIRE(steps_ != Null<Size>() || stepsPerYear_ != Null<Size>(),
                   "number of steps not given");
        QL_REQUIRE(steps_ == Null<Size>() || stepsPerYear_ == Null<Size>(),
                   "number of steps overspecified");
        return boost::shared_ptr<PricingEngine>(new
            MCEuropeanEngine<RNG,S>(process_,
                                    steps_,
                                    stepsPerYear_,
                                    brownianBridge_,
                                    antithetic_,
                                    samples_, tolerance_,
                                    maxSamples_,
                                    seed_));
    }



    inline EuropeanPathPricer::EuropeanPathPricer(Option::Type type,
                                                  Real strike,
                                                  DiscountFactor discount)
    : payoff_(type, strike), discount_(discount) {
        QL_REQUIRE(strike>=0.0,
                   "strike less than zero not allowed");
    }

    inline Real EuropeanPathPricer::operator()(const Path& path) const {
        QL_REQUIRE(path.length() > 0, "the path cannot be empty");
        return payoff_(path.back()) * discount_;
    }

}


#endif


<|start_filename|>ql/models/volatility/garch.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 <NAME>
 Copyright (C) 2012 Liquidnet Holdings, Inc.

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file garch.hpp
    \brief GARCH volatility model
*/

#ifndef quantlib_garch_volatility_model_hpp
#define quantlib_garch_volatility_model_hpp

#include <ql/volatilitymodel.hpp>
#include <ql/math/optimization/problem.hpp>
#include <ql/math/optimization/constraint.hpp>
#include <vector>

namespace QuantLib {

    //! GARCH volatility model
    /*! Volatilities are assumed to be expressed on an annual basis.
    */
    class Garch11 : public VolatilityCompositor {
      public:
        typedef TimeSeries<Volatility> time_series;
        typedef time_series::const_iterator const_iterator;
        typedef time_series::const_value_iterator const_value_iterator;

        enum Mode {
            MomentMatchingGuess,   /*!< The initial guess is a moment
                                        matching estimates for
                                        mean(r2), acf(0), and acf(1). */
            GammaGuess,            /*!< The initial guess is an
                                        estimate of gamma based on the
                                        property:
                                        acf(i+1) = gamma*acf(i) for i > 1. */
            BestOfTwo,             /*!< The best of the two above modes */
            DoubleOptimization     /*!< Double optimization */
        };

        //! \name Constructors
        //@{
        Garch11(Real a, Real b, Real vl)
        : alpha_(a), beta_(b), gamma_(1 - a - b),
          vl_(vl), logLikelihood_(0), mode_(BestOfTwo) {}

        Garch11(const time_series& qs, Mode mode = BestOfTwo)
        : alpha_(0), beta_(0), vl_(0), logLikelihood_(0), mode_(mode) {
            calibrate(qs);
        };
        //@}

        //! \name Inspectors
        //@{
        Real alpha() const { return alpha_; }
        Real beta() const { return beta_; }
        Real omega() const { return vl_ * gamma_; }
        Real ltVol() const { return vl_; }
        Real logLikelihood() const { return logLikelihood_; }
        Mode mode() const { return mode_; }
        //@}

        //! \name VolatilityCompositor interface
        //@{
        time_series calculate(const time_series& quoteSeries) {
            return calculate(quoteSeries, alpha(), beta(), omega());
        }
        void calibrate(const time_series& quoteSeries) {
            calibrate(quoteSeries.cbegin_values(), quoteSeries.cend_values());
        }
        //@}

        //! \name Additional interface
        //@{
        static time_series calculate(const time_series& quoteSeries,
                                     Real alpha, Real beta, Real omega);

        void calibrate(const time_series& quoteSeries,
                       OptimizationMethod& method,
                       const EndCriteria& endCriteria) {
            calibrate(quoteSeries.cbegin_values(), quoteSeries.cend_values(),
                      method, endCriteria);
        }

        void calibrate(const time_series& quoteSeries,
                       OptimizationMethod& method,
                       const EndCriteria& endCriteria,
                       const Array& initialGuess) {
            calibrate(quoteSeries.cbegin_values(), quoteSeries.cend_values(),
                      method, endCriteria, initialGuess);
        }

        template <typename ForwardIterator>
        void calibrate(ForwardIterator begin, ForwardIterator end) {
            std::vector<Volatility> r2;
            Real mean_r2 = to_r2(begin, end, r2);
            boost::shared_ptr<Problem> p =
                calibrate_r2(mode_, r2, mean_r2, alpha_, beta_, vl_);
            gamma_ = 1 - alpha_ - beta_;
            vl_ /= gamma_;
            logLikelihood_ = p ? -p->functionValue() :
                                 -costFunction(begin, end);
        }

        template <typename ForwardIterator>
        void calibrate(ForwardIterator begin, ForwardIterator end,
                       OptimizationMethod& method,
                       EndCriteria endCriteria) {
            std::vector<Volatility> r2;
            Real mean_r2 = to_r2(begin, end, r2);
            boost::shared_ptr<Problem> p =
                calibrate_r2(mode_, r2, mean_r2, method,
                             endCriteria, alpha_, beta_, vl_);
            gamma_ = 1 - alpha_ - beta_;
            vl_ /= gamma_;
            logLikelihood_ = p ? -p->functionValue() :
                                 -costFunction(begin, end);
        }

        template <typename ForwardIterator>
        void calibrate(ForwardIterator begin, ForwardIterator end,
                       OptimizationMethod& method,
                       EndCriteria endCriteria,
                       const Array& initialGuess) {
            std::vector<Volatility> r2;
            to_r2(begin, end, r2);
            boost::shared_ptr<Problem> p =
                calibrate_r2(r2, method, endCriteria, initialGuess,
                             alpha_, beta_, vl_);
            gamma_ = 1 - alpha_ - beta_;
            vl_ /= gamma_;
            logLikelihood_ = p ? -p->functionValue() :
                                 -costFunction(begin, end);
        }

        Real forecast(Real r, Real sigma2) const {
            return gamma_* vl_ + alpha_ * r * r + beta_ * sigma2;
        }

        // a helper for calculation of r^2 and <r^2>
        template <typename InputIterator>
        static Real to_r2(InputIterator begin, InputIterator end,
                          std::vector<Volatility>& r2) {
            Real u2(0.0), mean_r2(0.0), w(1.0);
            for (; begin != end; ++begin) {
                u2 = *begin; u2 *= u2;
                mean_r2 = (1.0 - w) * mean_r2 + w * u2;
                r2.push_back(u2);
                w /= (w + 1.0);
            }
            return mean_r2;
        }

        /*! calibrates GARCH for r^2 */
        static boost::shared_ptr<Problem> calibrate_r2(
                                        Mode mode,
                                        const std::vector<Volatility>& r2,
                                        Real mean_r2,
                                        Real& alpha,
                                        Real& beta,
                                        Real& omega);

        /*! calibrates GARCH for r^2 with user-defined optimization
            method and end criteria */
        static boost::shared_ptr<Problem> calibrate_r2(
                                        Mode mode,
                                        const std::vector<Volatility>& r2,
                                        Real mean_r2,
                                        OptimizationMethod& method,
                                        const EndCriteria& endCriteria,
                                        Real& alpha,
                                        Real& beta,
                                        Real& omega);

        /*! calibrates GARCH for r^2 with user-defined optimization
            method, end criteria and initial guess */
        static boost::shared_ptr<Problem> calibrate_r2(
                                        const std::vector<Volatility>& r2,
                                        Real mean_r2,
                                        OptimizationMethod& method,
                                        const EndCriteria& endCriteria,
                                        const Array& initialGuess,
                                        Real& alpha,
                                        Real& beta,
                                        Real& omega);

        /*! calibrates GARCH for r^2 with user-defined optimization
            method, end criteria and initial guess */
        static boost::shared_ptr<Problem> calibrate_r2(
                                        const std::vector<Volatility> &r2,
                                        OptimizationMethod& method,
                                        const EndCriteria& endCriteria,
                                        const Array& initialGuess,
                                        Real& alpha,
                                        Real& beta,
                                        Real& omega);

        /*! calibrates GARCH for r^2 with user-defined optimization
            method, end criteria, constraints and initial guess */
        static boost::shared_ptr<Problem> calibrate_r2(
                                        const std::vector<Volatility>& r2,
                                        Real mean_r2,
                                        OptimizationMethod& method,
                                        Constraint& constraints,
                                        const EndCriteria& endCriteria,
                                        const Array& initialGuess,
                                        Real& alpha,
                                        Real& beta,
                                        Real& omega);

        static boost::shared_ptr<Problem> calibrate_r2(
                                        const std::vector<Volatility> &r2,
                                        OptimizationMethod& method,
                                        Constraint& constraints,
                                        const EndCriteria& endCriteria,
                                        const Array& initialGuess,
                                        Real& alpha,
                                        Real& beta,
                                        Real& omega);

        template<class InputIterator>
        static Real costFunction(InputIterator begin, InputIterator end,
                                 Real alpha, Real beta, Real omega) {
            Real retval(0.0);
            Real u2(0.0), sigma2(0.0);
            Size N = 0;
            for (; begin != end; ++begin, ++N) {
                sigma2 = omega + alpha * u2 + beta * sigma2;
                u2 = *begin; u2 *= u2;
                retval += std::log(sigma2) + u2 / sigma2;
            }
            return N > 0 ? retval / (2*N) : 0.0;
        }
        //@}
      private:
        Real alpha_, beta_, gamma_, vl_;
        Real logLikelihood_;
        Mode mode_;

        template<class InputIterator>
        Real costFunction(InputIterator begin, InputIterator end) const {
            return costFunction(begin, end, alpha(), beta(), omega());
        }
    };

}


#endif


<|start_filename|>ql/instruments/creditdefaultswap.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008, 2009 <NAME>
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/instruments/creditdefaultswap.hpp>
#include <ql/instruments/claim.hpp>
#include <ql/cashflows/fixedratecoupon.hpp>
#include <ql/cashflows/simplecashflow.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>
#include <ql/termstructures/credit/flathazardrate.hpp>
#include <ql/pricingengines/credit/midpointcdsengine.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/math/solvers1d/brent.hpp>
#include <ql/time/calendars/weekendsonly.hpp>

namespace QuantLib {

    CreditDefaultSwap::CreditDefaultSwap(Protection::Side side,
                                         Real notional,
                                         Rate spread,
                                         const Schedule& schedule,
                                         BusinessDayConvention convention,
                                         const DayCounter& dayCounter,
                                         bool settlesAccrual,
                                         bool paysAtDefaultTime,
                                         const Date& protectionStart,
                                         const boost::shared_ptr<Claim>& claim)
    : side_(side), notional_(notional), upfront_(boost::none),
      runningSpread_(spread), settlesAccrual_(settlesAccrual),
      paysAtDefaultTime_(paysAtDefaultTime), claim_(claim),
      protectionStart_(protectionStart == Null<Date>() ? schedule[0] :
                                                         protectionStart) {
        QL_REQUIRE(protectionStart_ <= schedule[0],
                   "protection can not start after accrual");
        leg_ = FixedRateLeg(schedule)
            .withNotionals(notional)
            .withCouponRates(spread, dayCounter)
            .withPaymentAdjustment(convention);
        upfrontPayment_.reset(new SimpleCashFlow(0.0, schedule[0]));

        if (!claim_)
            claim_ = boost::shared_ptr<Claim>(new FaceValueClaim);
        registerWith(claim_);
    }

    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)
    : side_(side), notional_(notional), upfront_(upfront),
      runningSpread_(runningSpread), settlesAccrual_(settlesAccrual),
      paysAtDefaultTime_(paysAtDefaultTime), claim_(claim),
      protectionStart_(protectionStart == Null<Date>() ? schedule[0] :
                                                         protectionStart) {
        QL_REQUIRE(protectionStart_ <= schedule[0],
                   "protection can not start after accrual");
        leg_ = FixedRateLeg(schedule)
            .withNotionals(notional)
            .withCouponRates(runningSpread, dayCounter)
            .withPaymentAdjustment(convention);
        Date d = upfrontDate == Null<Date>() ? schedule[0] : upfrontDate;
        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_);
    }

    Protection::Side CreditDefaultSwap::side() const {
        return side_;
    }

    Real CreditDefaultSwap::notional() const {
        return notional_;
    }

    Rate CreditDefaultSwap::runningSpread() const {
        return runningSpread_;
    }

    boost::optional<Rate> CreditDefaultSwap::upfront() const {
        return upfront_;
    }

    bool CreditDefaultSwap::settlesAccrual() const {
        return settlesAccrual_;
    }

    bool CreditDefaultSwap::paysAtDefaultTime() const {
        return paysAtDefaultTime_;
    }

    const Leg& CreditDefaultSwap::coupons() const {
        return leg_;
    }


    bool CreditDefaultSwap::isExpired() const {
        for (Leg::const_reverse_iterator i = leg_.rbegin();
                                         i != leg_.rend(); ++i) {
            if (!(*i)->hasOccurred())
                return false;
        }
        return true;
    }

    void CreditDefaultSwap::setupExpired() const {
        Instrument::setupExpired();
        fairSpread_ = fairUpfront_ = 0.0;
        couponLegBPS_ = upfrontBPS_ = 0.0;
        couponLegNPV_ = defaultLegNPV_ = upfrontNPV_ = 0.0;
    }

    void CreditDefaultSwap::setupArguments(
                                       PricingEngine::arguments* args) const {
        CreditDefaultSwap::arguments* arguments =
            dynamic_cast<CreditDefaultSwap::arguments*>(args);
        QL_REQUIRE(arguments != 0, "wrong argument type");

        arguments->side = side_;
        arguments->notional = notional_;
        arguments->leg = leg_;
        arguments->upfrontPayment = upfrontPayment_;
        arguments->settlesAccrual = settlesAccrual_;
        arguments->paysAtDefaultTime = paysAtDefaultTime_;
        arguments->claim = claim_;
        arguments->upfront = upfront_;
        arguments->spread = runningSpread_;
        arguments->protectionStart = protectionStart_;
    }


    void CreditDefaultSwap::fetchResults(
                                      const PricingEngine::results* r) const {
        Instrument::fetchResults(r);

        const CreditDefaultSwap::results* results =
            dynamic_cast<const CreditDefaultSwap::results*>(r);
        QL_REQUIRE(results != 0, "wrong result type");

        fairSpread_ = results->fairSpread;
        fairUpfront_ = results->fairUpfront;
        couponLegBPS_ = results->couponLegBPS;
        couponLegNPV_ = results->couponLegNPV;
        defaultLegNPV_ = results->defaultLegNPV;
        upfrontNPV_ = results->upfrontNPV;
        upfrontBPS_ = results->upfrontBPS;
    }

    Rate CreditDefaultSwap::fairUpfront() const {
        calculate();
        QL_REQUIRE(fairUpfront_ != Null<Rate>(),
                   "fair upfront not available");
        return fairUpfront_;
    }

    Rate CreditDefaultSwap::fairSpread() const {
        calculate();
        QL_REQUIRE(fairSpread_ != Null<Rate>(),
                   "fair spread not available");
        return fairSpread_;
    }

    Real CreditDefaultSwap::couponLegBPS() const {
        calculate();
        QL_REQUIRE(couponLegBPS_ != Null<Rate>(),
                   "coupon-leg BPS not available");
        return couponLegBPS_;
    }

    Real CreditDefaultSwap::couponLegNPV() const {
        calculate();
        QL_REQUIRE(couponLegNPV_ != Null<Rate>(),
                   "coupon-leg NPV not available");
        return couponLegNPV_;
    }

    Real CreditDefaultSwap::defaultLegNPV() const {
        calculate();
        QL_REQUIRE(defaultLegNPV_ != Null<Rate>(),
                   "default-leg NPV not available");
        return defaultLegNPV_;
    }

    Real CreditDefaultSwap::upfrontNPV() const {
        calculate();
        QL_REQUIRE(upfrontNPV_ != Null<Real>(),
                   "upfront NPV not available");
        return upfrontNPV_;
    }

    Real CreditDefaultSwap::upfrontBPS() const {
        calculate();
        QL_REQUIRE(upfrontBPS_ != Null<Real>(),
                   "upfront BPS not available");
        return upfrontBPS_;
    }


    namespace {

        class ObjectiveFunction {
          public:
            ObjectiveFunction(Real target,
                              SimpleQuote& quote,
                              PricingEngine& engine,
                              const CreditDefaultSwap::results* results)
            : target_(target), quote_(quote),
              engine_(engine), results_(results) {}

            Real operator()(Real guess) const {
                quote_.setValue(guess);
                engine_.calculate();
                return results_->value - target_;
            }
          private:
            Real target_;
            SimpleQuote& quote_;
            PricingEngine& engine_;
            const CreditDefaultSwap::results* results_;
        };

    }

    Rate CreditDefaultSwap::impliedHazardRate(
                               Real targetNPV,
                               const Handle<YieldTermStructure>& discountCurve,
                               const DayCounter& dayCounter,
                               Real recoveryRate,
                               Real accuracy) const {

        boost::shared_ptr<SimpleQuote> flatRate(new SimpleQuote(0.0));

        Handle<DefaultProbabilityTermStructure> probability(
            boost::shared_ptr<DefaultProbabilityTermStructure>(new
                FlatHazardRate(0, WeekendsOnly(),
                               Handle<Quote>(flatRate), dayCounter)));

        MidPointCdsEngine engine(probability, recoveryRate, discountCurve);
        setupArguments(engine.getArguments());
        const CreditDefaultSwap::results* results =
            dynamic_cast<const CreditDefaultSwap::results*>(
                                                       engine.getResults());

        ObjectiveFunction f(targetNPV, *flatRate, engine, results);
        Rate guess = 0.001;
        Rate step = guess*0.1;

        return Brent().solve(f, accuracy, guess, step);
    }


    Rate CreditDefaultSwap::conventionalSpread(
                              Real conventionalRecovery,
                              const Handle<YieldTermStructure>& discountCurve,
                              const DayCounter& dayCounter) const {
        Rate flatHazardRate = impliedHazardRate(0.0,
                                                discountCurve,
                                                dayCounter,
                                                conventionalRecovery);

        Handle<DefaultProbabilityTermStructure> probability(
            boost::shared_ptr<DefaultProbabilityTermStructure>(
                             new FlatHazardRate(0, WeekendsOnly(),
                                                flatHazardRate, dayCounter)));

        MidPointCdsEngine engine(probability, conventionalRecovery,
                                 discountCurve, true);
        setupArguments(engine.getArguments());
        engine.calculate();
        const CreditDefaultSwap::results* results =
            dynamic_cast<const CreditDefaultSwap::results*>(
                                                       engine.getResults());
        return results->fairSpread;
    }


    const Date& CreditDefaultSwap::protectionStartDate() const {
        return protectionStart_;
    }

    const Date& CreditDefaultSwap::protectionEndDate() const {
        return boost::dynamic_pointer_cast<Coupon>(leg_.back())
            ->accrualEndDate();
    }


    CreditDefaultSwap::arguments::arguments()
    : side(Protection::Side(-1)), notional(Null<Real>()),
      spread(Null<Rate>()) {}

    void CreditDefaultSwap::arguments::validate() const {
        QL_REQUIRE(side != Protection::Side(-1), "side not set");
        QL_REQUIRE(notional != Null<Real>(), "notional not set");
        QL_REQUIRE(notional != 0.0, "null notional set");
        QL_REQUIRE(spread != Null<Rate>(), "spread not set");
        QL_REQUIRE(!leg.empty(), "coupons not set");
        QL_REQUIRE(upfrontPayment, "upfront payment not set");
        QL_REQUIRE(claim, "claim not set");
        QL_REQUIRE(protectionStart != Null<Date>(),
                   "protection start date not set");
    }

    void CreditDefaultSwap::results::reset() {
        Instrument::results::reset();
        fairSpread = Null<Rate>();
        fairUpfront = Null<Rate>();
        couponLegBPS = Null<Real>();
        couponLegNPV = Null<Real>();
        defaultLegNPV = Null<Real>();
        upfrontBPS = Null<Real>();
        upfrontNPV = Null<Real>();
    }

}


<|start_filename|>ql/termstructures/bootstraperror.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2007 <NAME>
 Copyright (C) 2007 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file bootstraperror.hpp
    \brief boostrap error.
*/

#ifndef quantlib_bootstrap_error_hpp
#define quantlib_bootstrap_error_hpp

#include <ql/types.hpp>
#include <boost/shared_ptr.hpp>

namespace QuantLib {

    //! bootstrap error
    template <class Curve>
    class BootstrapError {
        typedef typename Curve::traits_type Traits;
      public:
        BootstrapError(
                 const Curve* curve,
                 const boost::shared_ptr<typename Traits::helper>& instrument,
                 Size segment);
        Real operator()(Rate guess) const;
        const boost::shared_ptr<typename Traits::helper>& helper() {
            return helper_;
        }
      private:
        const Curve* curve_;
        const boost::shared_ptr<typename Traits::helper> helper_;
        const Size segment_;
    };


    // template definitions

    template <class Curve>
    BootstrapError<Curve>::BootstrapError(
                     const Curve* curve,
                     const boost::shared_ptr<typename Traits::helper>& helper,
                     Size segment)
    : curve_(curve), helper_(helper), segment_(segment) {}

    #ifndef __DOXYGEN__
    template <class Curve>
    Real BootstrapError<Curve>::operator()(Real guess) const {
        Traits::updateGuess(curve_->data_, guess, segment_);
        curve_->interpolation_.update();
        return helper_->quoteError();
    }
    #endif

}

#endif


<|start_filename|>test-suite/rounding.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include "rounding.hpp"
#include "utilities.hpp"
#include <ql/math/rounding.hpp>
#include <ql/math/comparison.hpp>

using namespace QuantLib;
using namespace boost::unit_test_framework;

namespace {

    struct TestCase {
        Decimal x;
        Integer precision;
        Decimal closest;
        Decimal up;
        Decimal down;
        Decimal floor;
        Decimal ceiling;
    };

    TestCase testData[] = {
        {  0.86313513, 5,  0.86314,  0.86314,  0.86313,  0.86314,  0.86313 },
        {  0.86313,    5,  0.86313,  0.86313,  0.86313,  0.86313,  0.86313 },
        { -7.64555346, 1, -7.6,     -7.7,     -7.6,     -7.6,     -7.6     },
        {  0.13961605, 2,  0.14,     0.14,     0.13,     0.14,     0.13    },
        {  0.14344179, 4,  0.1434,   0.1435,   0.1434,   0.1434,   0.1434  },
        { -4.74315016, 2, -4.74,    -4.75,    -4.74,    -4.74,    -4.74    },
        { -7.82772074, 5, -7.82772, -7.82773, -7.82772, -7.82772, -7.82772 },
        {  2.74137947, 3,  2.741,    2.742,    2.741,    2.741,    2.741   },
        {  2.13056714, 1,  2.1,      2.2,      2.1,      2.1,      2.1     },
        { -1.06228670, 1, -1.1,     -1.1,     -1.0,     -1.0,     -1.1     },
        {  8.29234094, 4,  8.2923,   8.2924,   8.2923,   8.2923,   8.2923  },
        {  7.90185598, 2,  7.90,     7.91,     7.90,     7.90,     7.90    },
        { -0.26738058, 1, -0.3,     -0.3,     -0.2,     -0.2,     -0.3     },
        {  1.78128713, 1,  1.8,      1.8,      1.7,      1.8,      1.7     },
        {  4.23537260, 1,  4.2,      4.3,      4.2,      4.2,      4.2     },
        {  3.64369953, 4,  3.6437,   3.6437,   3.6436,   3.6437,   3.6436  },
        {  6.34542470, 2,  6.35,     6.35,     6.34,     6.35,     6.34    },
        { -0.84754962, 4, -0.8475,  -0.8476,  -0.8475,  -0.8475,  -0.8475  },
        {  4.60998652, 1,  4.6,      4.7,      4.6,      4.6,      4.6     },
        {  6.28794223, 3,  6.288,    6.288,    6.287,    6.288,    6.287   },
        {  7.89428221, 2,  7.89,     7.90,     7.89,     7.89,     7.89    }
    };

}


void RoundingTest::testClosest() {

    BOOST_TEST_MESSAGE("Testing closest decimal rounding...");

    for (Size i=0; i<LENGTH(testData); i++) {
        Integer digits = testData[i].precision;
        ClosestRounding closest(digits);
        Real calculated = closest(testData[i].x);
        Real expected = testData[i].closest;
        if (!close(calculated,expected,1))
            BOOST_ERROR(QL_FIXED << std::setprecision(8)
                        << "Original number: " << testData[i].x << "\n"
                        << std::setprecision(digits)
                        << "Expected:        " << expected << "\n"
                        << "Calculated:      " << calculated);
    }
}

void RoundingTest::testUp() {

    BOOST_TEST_MESSAGE("Testing upward decimal rounding...");

    for (Size i=0; i<LENGTH(testData); i++) {
        Integer digits = testData[i].precision;
        UpRounding up(digits);
        Real calculated = up(testData[i].x);
        Real expected = testData[i].up;
        if (!close(calculated,expected,1))
            BOOST_ERROR(QL_FIXED << std::setprecision(8)
                        << "Original number: " << testData[i].x << "\n"
                        << std::setprecision(digits)
                        << "Expected:        " << expected << "\n"
                        << "Calculated:      " << calculated);
    }
}

void RoundingTest::testDown() {

    BOOST_TEST_MESSAGE("Testing downward decimal rounding...");

    for (Size i=0; i<LENGTH(testData); i++) {
        Integer digits = testData[i].precision;
        DownRounding down(digits);
        Real calculated = down(testData[i].x);
        Real expected = testData[i].down;
        if (!close(calculated,expected,1))
            BOOST_ERROR(QL_FIXED << std::setprecision(8)
                        << "Original number: " << testData[i].x << "\n"
                        << std::setprecision(digits)
                        << "Expected:        " << expected << "\n"
                        << "Calculated:      " << calculated);
    }
}

void RoundingTest::testFloor() {

    BOOST_TEST_MESSAGE("Testing floor decimal rounding...");

    for (Size i=0; i<LENGTH(testData); i++) {
        Integer digits = testData[i].precision;
        FloorTruncation floor(digits);
        Real calculated = floor(testData[i].x);
        Real expected = testData[i].floor;
        if (!close(calculated,expected,1))
            BOOST_ERROR(QL_FIXED << std::setprecision(8)
                        << "Original number: " << testData[i].x << "\n"
                        << std::setprecision(digits)
                        << "Expected:        " << expected << "\n"
                        << "Calculated:      " << calculated);
    }
}

void RoundingTest::testCeiling() {

    BOOST_TEST_MESSAGE("Testing ceiling decimal rounding...");

    for (Size i=0; i<LENGTH(testData); i++) {
        Integer digits = testData[i].precision;
        CeilingTruncation ceiling(digits);
        Real calculated = ceiling(testData[i].x);
        Real expected = testData[i].ceiling;
        if (!close(calculated,expected,1))
            BOOST_ERROR(QL_FIXED << std::setprecision(8)
                        << "Original number: " << testData[i].x << "\n"
                        << std::setprecision(digits)
                        << "Expected:        " << expected << "\n"
                        << "Calculated:      " << calculated);
    }
}


test_suite* RoundingTest::suite() {
    test_suite* suite = BOOST_TEST_SUITE("Rounding tests");
    suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testClosest));
    suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testUp));
    suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testDown));
    suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testFloor));
    suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testCeiling));
    return suite;
}



<|start_filename|>ql/experimental/commodities/paymentterm.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/experimental/commodities/paymentterm.hpp>

namespace QuantLib {

    std::map<std::string, boost::shared_ptr<PaymentTerm::Data> >
    PaymentTerm::paymentTerms_;

    PaymentTerm::PaymentTerm(const std::string& name,
                             PaymentTerm::EventType eventType,
                             Integer offsetDays,
                             const Calendar& calendar) {
        std::map<std::string, boost::shared_ptr<PaymentTerm::Data> >::const_iterator i = paymentTerms_.find(name);
        if (i != paymentTerms_.end())
            data_ = i->second;
        else {
            data_ = boost::shared_ptr<PaymentTerm::Data>(
                                 new PaymentTerm::Data(name, eventType,
                                                       offsetDays, calendar));
            paymentTerms_[name] = data_;
        }
    }

    std::ostream& operator<<(std::ostream& out, const PaymentTerm& c) {
        if (!c.empty())
            return out << c.name();
        else
            return out << "null payment term type";
    }

}



<|start_filename|>ql/experimental/exoticoptions/analyticcompoundoptionengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/experimental/exoticoptions/analyticcompoundoptionengine.hpp>
#include <ql/math/solvers1d/brent.hpp>
#include <ql/pricingengines/blackformula.hpp>

namespace QuantLib {

    namespace {

        // Helper Class needed to solve an implicit problem of finding a
        // spot to a corresponding option price.
        class ImpliedSpotHelper {
          public:
            ImpliedSpotHelper(DiscountFactor dividendDiscount,
                              DiscountFactor riskFreeDiscount,
                              Real standardDeviation ,
                              boost::shared_ptr<PlainVanillaPayoff> payoff,
                              Real strike)
            : dividendDiscount_(dividendDiscount),
              riskFreeDiscount_(riskFreeDiscount),
              standardDeviation_(standardDeviation),
              strike_(strike),payoff_(payoff) {}
            Real operator()(Real spot) const {
                Real forwardPrice = spot*dividendDiscount_/riskFreeDiscount_;
                Real value = blackFormula(payoff_, forwardPrice,
                                          standardDeviation_,riskFreeDiscount_);
                return value - strike_;
            }
          private:
            DiscountFactor dividendDiscount_;
            DiscountFactor riskFreeDiscount_;
            Real standardDeviation_;
            Real strike_;
            boost::shared_ptr<PlainVanillaPayoff> payoff_;
        };

    }

    AnalyticCompoundOptionEngine::AnalyticCompoundOptionEngine(
            const boost::shared_ptr<GeneralizedBlackScholesProcess>& process)
    : process_(process){
        registerWith(process_);
    }

    void AnalyticCompoundOptionEngine::calculate() const {

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

        results_.value=tempRes;
        results_.delta=tempDelta;
        results_.gamma=tempGamma;
        results_.vega=tempVega;
        results_.theta=tempTheta;
    }

    Real AnalyticCompoundOptionEngine::typeDaughter() const {
        // returns -1 or 1 according to put or call
        return (Real) payoffDaughter()->optionType();
    }

    Real AnalyticCompoundOptionEngine::typeMother() const {
        return (Real) payoffMother()->optionType();
    }

    Date AnalyticCompoundOptionEngine::maturityDaughter() const {
        return arguments_.daughterExercise->lastDate();
    }

    Date AnalyticCompoundOptionEngine::maturityMother() const {
        return arguments_.exercise->lastDate();
    }

    Time AnalyticCompoundOptionEngine::residualTimeDaughter() const {
        return process_->time(maturityDaughter());
    }

    Time AnalyticCompoundOptionEngine::residualTimeMother() const {
        return process_->time(maturityMother());
    }

    Time AnalyticCompoundOptionEngine::residualTimeMotherDaughter() const {
        return residualTimeDaughter()-residualTimeMother();
    }


    Real AnalyticCompoundOptionEngine::volatilityDaughter() const {
        return process_->blackVolatility()->blackVol(maturityDaughter(),
                                                     strikeDaughter());
    }


    Real AnalyticCompoundOptionEngine::volatilityMother() const {
        return process_->blackVolatility()->blackVol(maturityMother(),
                                                     strikeMother());
    }

    Real AnalyticCompoundOptionEngine::stdDeviationDaughter() const {
        return volatilityDaughter()*std::sqrt(residualTimeDaughter());
    }

    Real AnalyticCompoundOptionEngine::stdDeviationMother() const {
        return volatilityMother()*std::sqrt(residualTimeMother());
    }


    boost::shared_ptr<PlainVanillaPayoff>
    AnalyticCompoundOptionEngine::payoffDaughter() const {
        boost::shared_ptr<PlainVanillaPayoff> dPayoff =
            boost::dynamic_pointer_cast<PlainVanillaPayoff>(
                                                   arguments_.daughterPayoff);
        QL_REQUIRE(dPayoff, "non-plain payoff given");
        return dPayoff;
    }

    boost::shared_ptr<PlainVanillaPayoff>
    AnalyticCompoundOptionEngine::payoffMother() const {
        boost::shared_ptr<PlainVanillaPayoff> mPayoff =
            boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
        QL_REQUIRE(mPayoff, "non-plain payoff given");
        return mPayoff;
    }

    Real AnalyticCompoundOptionEngine::strikeMother() const {
        return payoffMother()->strike();
    }

    Real AnalyticCompoundOptionEngine::strikeDaughter() const {
        return payoffDaughter()->strike();
    }

    DiscountFactor AnalyticCompoundOptionEngine::riskFreeDiscountDaughter() const {
        return process_->riskFreeRate()->discount(residualTimeDaughter());
    }

    DiscountFactor AnalyticCompoundOptionEngine::riskFreeDiscountMother() const {
        return process_->riskFreeRate()->discount(residualTimeMother());
    }

    DiscountFactor AnalyticCompoundOptionEngine::riskFreeDiscountMotherDaughter() const {
        return process_->riskFreeRate()->discount(residualTimeMotherDaughter());
    }

    DiscountFactor AnalyticCompoundOptionEngine::dividendDiscountDaughter() const {
        return process_->dividendYield()->discount(residualTimeDaughter());
    }

    DiscountFactor AnalyticCompoundOptionEngine::dividendDiscountMother() const {
        return process_->dividendYield()->discount(residualTimeMother());
    }

    DiscountFactor AnalyticCompoundOptionEngine::dividendDiscountMotherDaughter() const {
        return process_->dividendYield()->discount(residualTimeMotherDaughter());
    }

    Real AnalyticCompoundOptionEngine::dPlus() const {
        Real forward = spot() * dividendDiscountDaughter() / riskFreeDiscountDaughter();
        Real sd=stdDeviationDaughter();
        return std::log(forward/strikeDaughter())/sd+0.5*sd;
    }

    Real AnalyticCompoundOptionEngine::dMinus() const {
        return dPlus()-stdDeviationDaughter();
    }

    Real AnalyticCompoundOptionEngine::dPlusTau12(Real S) const {
        Real forward = S * dividendDiscountMotherDaughter() / riskFreeDiscountMotherDaughter();
        Real sd=volatilityDaughter()*std::sqrt(residualTimeMotherDaughter());
        return std::log(forward/strikeDaughter())/sd+0.5*sd;
    }

    Real AnalyticCompoundOptionEngine::spot() const {
        return process_->x0();
    }

    Real AnalyticCompoundOptionEngine::riskFreeRateDaughter() const {
        return process_->riskFreeRate()->zeroRate(residualTimeDaughter(),
                                                  Continuous,
                                                  NoFrequency);
    }

    Real AnalyticCompoundOptionEngine::dividendRateDaughter() const {
        return process_->dividendYield()->zeroRate(residualTimeDaughter(),
                                                   Continuous,
                                                   NoFrequency);
    }

    Real AnalyticCompoundOptionEngine::transformX(Real X) const {

        Real sd=stdDeviationMother();
        Real resX=riskFreeDiscountMother()*X/(spot()*dividendDiscountMother());
        resX=resX*std::exp(0.5*sd*sd);
        resX=std::log(resX);

        return resX/sd;
    }

    Real AnalyticCompoundOptionEngine::e(Real X) const {
        Real rtM=residualTimeMother();
        Real rtD=residualTimeDaughter();

        return (X*std::sqrt(rtD)+std::sqrt(rtM)*dMinus())/std::sqrt(rtD-rtM);
    }

}


<|start_filename|>ql/experimental/commodities/unitofmeasureconversionmanager.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2009 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/experimental/commodities/unitofmeasureconversionmanager.hpp>
#include <ql/experimental/commodities/petroleumunitsofmeasure.hpp>
#include <ql/errors.hpp>

using namespace std;

namespace QuantLib {

    namespace {

        bool matches(const UnitOfMeasureConversion& c1,
                     const UnitOfMeasureConversion& c2) {
            return c1.commodityType() == c2.commodityType() &&
                ((c1.source() == c2.source() && c1.target() == c2.target())
                 || (c1.source() == c2.target() && c1.target() == c2.source()));
        }

        bool matches(const UnitOfMeasureConversion& c,
                     const CommodityType& commodityType,
                     const UnitOfMeasure& source,
                     const UnitOfMeasure& target) {
            return c.commodityType() == commodityType &&
                ((c.source() == source && c.target() == target)
                 || (c.source() == target && c.target() == source));
        }

        bool matches(const UnitOfMeasureConversion& c,
                     const CommodityType& commodityType,
                     const UnitOfMeasure& source) {
            return c.commodityType() == commodityType &&
                (c.source() == source || c.target() == source);
        }

    }

    UnitOfMeasureConversionManager::UnitOfMeasureConversionManager()
    : Singleton<UnitOfMeasureConversionManager>() {
        addKnownConversionFactors();
    }

    void UnitOfMeasureConversionManager::add(const UnitOfMeasureConversion& c) {
        // not fast, but hopefully we won't have a lot of entries.
        for (list<UnitOfMeasureConversion>::iterator i = data_.begin();
             i != data_.end(); ++i) {
            if (matches(*i, c)) {
                data_.erase(i);
                break;
            }
        }

        data_.push_back(c);
    }

    UnitOfMeasureConversion UnitOfMeasureConversionManager::lookup(
                                   const CommodityType& commodityType,
                                   const UnitOfMeasure& source,
                                   const UnitOfMeasure& target,
                                   UnitOfMeasureConversion::Type type) const {
        if (type == UnitOfMeasureConversion::Direct) {
            return directLookup(commodityType,source,target);
        } else if (!source.triangulationUnitOfMeasure().empty()) {
            const UnitOfMeasure& link = source.triangulationUnitOfMeasure();
            if (link == target)
                return directLookup(commodityType,source,link);
            else
                return UnitOfMeasureConversion::chain(
                                      directLookup(commodityType,source,link),
                                      lookup(commodityType,link,target));
        } else if (!target.triangulationUnitOfMeasure().empty()) {
            const UnitOfMeasure& link = target.triangulationUnitOfMeasure();
            if (source == link)
                return directLookup(commodityType,link,target);
            else
                return UnitOfMeasureConversion::chain(
                                     lookup(commodityType,source,link),
                                     directLookup(commodityType,link,target));
        } else {
            return smartLookup(commodityType,source,target);
        }
    }

    void UnitOfMeasureConversionManager::clear() {
        data_.clear();
        addKnownConversionFactors();
    }

    void UnitOfMeasureConversionManager::addKnownConversionFactors() {
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    MBUnitOfMeasure(),
                                    BarrelUnitOfMeasure(),
                                    1000));
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    BarrelUnitOfMeasure(),
                                    GallonUnitOfMeasure(),
                                    42));
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    GallonUnitOfMeasure(),
                                    MBUnitOfMeasure(),
                                    1000 * 42));
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    LitreUnitOfMeasure(),
                                    GallonUnitOfMeasure(),
                                    3.78541));
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    BarrelUnitOfMeasure(),
                                    LitreUnitOfMeasure(),
                                    158.987));
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    KilolitreUnitOfMeasure(),
                                    BarrelUnitOfMeasure(),
                                    6.28981));
        add(UnitOfMeasureConversion(NullCommodityType(),
                                    TokyoKilolitreUnitOfMeasure(),
                                    BarrelUnitOfMeasure(),
                                    6.28981));
    }

    UnitOfMeasureConversion UnitOfMeasureConversionManager::directLookup(
                                           const CommodityType& commodityType,
                                           const UnitOfMeasure& source,
                                           const UnitOfMeasure& target) const {

        for (list<UnitOfMeasureConversion>::const_iterator i = data_.begin();
             i != data_.end(); ++i) {
            if (matches(*i, commodityType, source, target)) {
                return *i;
            }
        }

        // Here, the code used to look for conversions with null
        // commodity type as a fall-back.  However, this would only
        // affect direct lookups and not other matches being tried in
        // the smart-lookup loop.  To implement the complete fall-back
        // strategy, we should either duplicate the loop (as we would
        // duplicate it here---smelly) or change the 'matches'
        // functions so that a null commodity type matches. However,
        // in the second case we would also have to take care that
        // conversions with a null type be at the end of the list so
        // that they don't supersede specific types. We'll have to
        // think a bit about this, so no fall-back for the time being.

        QL_FAIL("no direct conversion available from "
                << commodityType.code() << " " << source.code()
                << " to " << target.code());
    }

    UnitOfMeasureConversion UnitOfMeasureConversionManager::smartLookup(
                              const CommodityType& commodityType,
                              const UnitOfMeasure& source,
                              const UnitOfMeasure& target,
                              list<string> forbidden) const {

        try {
            return directLookup(commodityType,source,target);
        } catch (Error&) {
            ; // no direct conversion available; turn to smart lookup.
        }

        // The source unit is forbidden to subsequent lookups in order
        // to avoid cycles.
        forbidden.push_back(source.code());

        for (list<UnitOfMeasureConversion>::const_iterator i = data_.begin();
             i != data_.end(); ++i) {
            // we look for conversion data which involve our source unit...
            if (matches(*i, commodityType, source)) {
                const UnitOfMeasure& other =
                    source == i->source() ? i->target() : i->source();
                if (find(forbidden.begin(),forbidden.end(),
                         other.code()) == forbidden.end()) {
                    // if we can get to the target from here...
                    try {
                        UnitOfMeasureConversion tail =
                            smartLookup(commodityType,other,target);
                        // ..we're done.
                        return UnitOfMeasureConversion::chain(*i,tail);
                    } catch (Error&) {
                        // otherwise, we just discard this conversion.
                        ;
                    }
                }
            }
        }

        // if the loop completed, we have no way to return the
        // requested conversion.
        QL_FAIL("no conversion available for "
                << commodityType.code() << " from "
                << source.code() << " to " << target.code());
    }

}



<|start_filename|>ql/pricingengines/asian/analytic_discr_geom_av_strike.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 Master IMAFA - Polytech'Nice Sophia - Université de Nice Sophia Antipolis

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/asian/analytic_discr_geom_av_strike.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/exercise.hpp>

namespace QuantLib {

    AnalyticDiscreteGeometricAverageStrikeAsianEngine::
    AnalyticDiscreteGeometricAverageStrikeAsianEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process)
    : process_(process) {
        registerWith(process_);
    }

    void AnalyticDiscreteGeometricAverageStrikeAsianEngine::calculate() const {

        QL_REQUIRE(arguments_.averageType == Average::Geometric,
                   "not a geometric average option");

        QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
                   "not an European option");

        QL_REQUIRE(arguments_.runningAccumulator > 0.0,
                   "positive running product required: "
                   << arguments_.runningAccumulator << "not allowed");
        Real runningLog = std::log(arguments_.runningAccumulator);
        Size pastFixings = arguments_.pastFixings;
        QL_REQUIRE(pastFixings == 0, "past fixings currently not managed");

        boost::shared_ptr<PlainVanillaPayoff> payoff =
            boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
        QL_REQUIRE(payoff, "non-plain payoff given");

        DayCounter rfdc  = process_->riskFreeRate()->dayCounter();
        DayCounter divdc = process_->dividendYield()->dayCounter();
        DayCounter voldc = process_->blackVolatility()->dayCounter();

        std::vector<Time> fixingTimes;
        for (Size i=0; i<arguments_.fixingDates.size(); i++) {
            if (arguments_.fixingDates[i]>=arguments_.fixingDates[0]) {
                Time t = voldc.yearFraction(arguments_.fixingDates[0],
                    arguments_.fixingDates[i]);
                fixingTimes.push_back(t);
            }
        }

        Size remainingFixings = fixingTimes.size();
        Size numberOfFixings = pastFixings + remainingFixings;
        Real N = static_cast<Real>(numberOfFixings);

        Real pastWeight   = pastFixings/N;
        Real futureWeight = 1.0-pastWeight;

        Time timeSum = std::accumulate(fixingTimes.begin(),
                                       fixingTimes.end(), Real(0.0));

        Time residualTime = rfdc.yearFraction(arguments_.fixingDates[pastFixings],
                                              arguments_.exercise->lastDate());


        Real underlying = process_->stateVariable()->value();
        QL_REQUIRE(underlying > 0.0, "positive underlying value required");

        Volatility volatility = process_->blackVolatility()->blackVol(
                                                arguments_.exercise->lastDate(),
                                                underlying);

        Date exDate = arguments_.exercise->lastDate();
        Rate dividendRate = process_->dividendYield()->
            zeroRate(exDate, divdc, Continuous, NoFrequency);

        Rate riskFreeRate = process_->riskFreeRate()->
            zeroRate(exDate, rfdc, Continuous, NoFrequency);

        Rate nu = riskFreeRate - dividendRate - 0.5*volatility*volatility;

        Real temp = 0.0;
        for (Size i=pastFixings+1; i<numberOfFixings; i++)
            temp += fixingTimes[i-pastFixings-1]*(N-i);
        Real variance = volatility*volatility /N/N * (timeSum + 2.0*temp);
        Real covarianceTerm = volatility*volatility/N * timeSum;
        Real sigmaSum_2 = variance + volatility*volatility*residualTime -
                                     2.0*covarianceTerm;

        Size M = (pastFixings == 0 ? 1 : pastFixings);
        Real runningLogAverage = runningLog/M;

        Real muG = pastWeight * runningLogAverage +
                   futureWeight * std::log(underlying) +
                   nu*timeSum/N;

        CumulativeNormalDistribution f;

        Real y1 = (std::log(underlying)+
                     (riskFreeRate-dividendRate)*residualTime-
                      muG - variance/2.0 + sigmaSum_2/2.0)
                      /std::sqrt(sigmaSum_2);
        Real y2 = y1-std::sqrt(sigmaSum_2);

        switch (payoff->optionType()) {
          case Option::Call:
            results_.value = underlying*std::exp(-dividendRate*residualTime)
                *f(y1)-
                std::exp(muG + variance/2.0 - riskFreeRate*residualTime)
                *f(y2);
            break;
          case Option::Put:
            results_.value = -underlying*std::exp(-dividendRate*residualTime)
                *f(-y1)+
                std::exp(muG + variance/2.0 - riskFreeRate*residualTime)
                *f(-y2);
            break;
          default:
            QL_FAIL("invalid option type");
        }
    }

}



<|start_filename|>ql/cashflows/conundrumpricer.cpp<|end_filename|>
/*
 Copyright (C) 2006 <NAME>
 Copyright (C) 2006 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.


 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
 */

/*! \file conundrumpricer.hpp
    \brief
*/

#include <ql/cashflows/conundrumpricer.hpp>
#include <ql/math/integrals/kronrodintegral.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/math/solvers1d/newton.hpp>
#include <ql/termstructures/volatility/smilesection.hpp>
#include <ql/cashflows/cmscoupon.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/indexes/swapindex.hpp>
#include <ql/indexes/interestrateindex.hpp>
#include <ql/time/schedule.hpp>
#include <ql/instruments/vanillaswap.hpp>

#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif

#include <boost/bind.hpp>

#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4))
#pragma GCC diagnostic pop
#endif

namespace QuantLib {

//===========================================================================//
//                          BlackVanillaOptionPricer                         //
//===========================================================================//

    BlackVanillaOptionPricer::BlackVanillaOptionPricer(
            Rate forwardValue,
            Date expiryDate,
            const Period& swapTenor,
            const boost::shared_ptr<SwaptionVolatilityStructure>& volatilityStructure) :
    forwardValue_(forwardValue), expiryDate_(expiryDate), swapTenor_(swapTenor),
        volatilityStructure_(volatilityStructure),
        smile_(volatilityStructure_->smileSection(expiryDate_, swapTenor_)) {
        }

    Real BlackVanillaOptionPricer::operator()(Real strike,
                                              Option::Type optionType,
                                              Real deflator) const {
        const Real variance = smile_->variance(strike);
        return deflator * blackFormula(optionType, strike,
            forwardValue_, std::sqrt(variance));
    }


//===========================================================================//
//                             HaganPricer                               //
//===========================================================================//
    HaganPricer::HaganPricer(
                const Handle<SwaptionVolatilityStructure>& swaptionVol,
                GFunctionFactory::YieldCurveModel modelOfYieldCurve,
                const Handle<Quote>& meanReversion)
    : CmsCouponPricer(swaptionVol),
      modelOfYieldCurve_(modelOfYieldCurve),
      cutoffForCaplet_(2), cutoffForFloorlet_(0),
      meanReversion_(meanReversion) {
          registerWith(meanReversion_);
    }

    void HaganPricer::initialize(const FloatingRateCoupon& coupon){
        coupon_ =  dynamic_cast<const CmsCoupon*>(&coupon);
        QL_REQUIRE(coupon_, "CMS coupon needed");
        gearing_ = coupon_->gearing();
        spread_ = coupon_->spread();
        Time accrualPeriod = coupon_->accrualPeriod();
        QL_REQUIRE(accrualPeriod != 0.0, "null accrual period");

        fixingDate_ = coupon_->fixingDate();
        paymentDate_ = coupon_->date();
        const boost::shared_ptr<SwapIndex>& swapIndex = coupon_->swapIndex();
        rateCurve_ = *(swapIndex->forwardingTermStructure());

        Date today = Settings::instance().evaluationDate();

        if(paymentDate_ > today)
            discount_ = rateCurve_->discount(paymentDate_);
        else discount_= 1.;

        spreadLegValue_ = spread_ * accrualPeriod * discount_;

        if (fixingDate_ > today){
            swapTenor_ = swapIndex->tenor();
            boost::shared_ptr<VanillaSwap> swap = swapIndex->underlyingSwap(fixingDate_);

            swapRateValue_ = swap->fairRate();

            static const Spread bp = 1.0e-4;
            annuity_ = std::fabs(swap->fixedLegBPS()/bp);

            Size q = swapIndex->fixedLegTenor().frequency();
            const Schedule& schedule = swap->fixedSchedule();
            const DayCounter& dc = swapIndex->dayCounter();
            //const DayCounter dc = coupon.dayCounter();
            Time startTime = dc.yearFraction(rateCurve_->referenceDate(),
                                             swap->startDate());
            Time swapFirstPaymentTime =
                dc.yearFraction(rateCurve_->referenceDate(), schedule.date(1));
            Time paymentTime = dc.yearFraction(rateCurve_->referenceDate(),
                                               paymentDate_);
            Real delta = (paymentTime-startTime) / (swapFirstPaymentTime-startTime);

            switch (modelOfYieldCurve_) {
                case GFunctionFactory::Standard:
                    gFunction_ = GFunctionFactory::newGFunctionStandard(q, delta, swapTenor_.length());
                    break;
                case GFunctionFactory::ExactYield:
                    gFunction_ = GFunctionFactory::newGFunctionExactYield(*coupon_);
                    break;
                case GFunctionFactory::ParallelShifts: {
                    Handle<Quote> nullMeanReversionQuote(boost::shared_ptr<Quote>(new SimpleQuote(0.0)));
                    gFunction_ = GFunctionFactory::newGFunctionWithShifts(*coupon_, nullMeanReversionQuote);
                    }
                    break;
                case GFunctionFactory::NonParallelShifts:
                    gFunction_ = GFunctionFactory::newGFunctionWithShifts(*coupon_, meanReversion_);
                    break;
                default:
                    QL_FAIL("unknown/illegal gFunction type");
            }
            vanillaOptionPricer_= boost::shared_ptr<VanillaOptionPricer>(new
                BlackVanillaOptionPricer(swapRateValue_, fixingDate_, swapTenor_,
                                        *swaptionVolatility()));
         }
    }

    Real HaganPricer::meanReversion() const { return meanReversion_->value();}

    Rate HaganPricer::swapletRate() const {
        return swapletPrice()/(coupon_->accrualPeriod()*discount_);
    }

    Real HaganPricer::capletPrice(Rate effectiveCap) const {
        // caplet is equivalent to call option on fixing
        Date today = Settings::instance().evaluationDate();
        if (fixingDate_ <= today) {
            // the fixing is determined
            const Rate Rs =
                std::max(coupon_->swapIndex()->fixing(fixingDate_)-effectiveCap, 0.);
            Rate price = (gearing_*Rs)*(coupon_->accrualPeriod()*discount_);
            return price;
        } else {
            Real cutoffNearZero = 1e-10;
            Real capletPrice = 0;
            if (effectiveCap < cutoffForCaplet_) {
                Rate effectiveStrikeForMax = std::max(effectiveCap,cutoffNearZero);
                capletPrice = optionletPrice(Option::Call, effectiveStrikeForMax);
            }
            return gearing_ * capletPrice;
        }
    }

    Rate HaganPricer::capletRate(Rate effectiveCap) const {
        return capletPrice(effectiveCap)/(coupon_->accrualPeriod()*discount_);
    }

    Real HaganPricer::floorletPrice(Rate effectiveFloor) const {
        // floorlet is equivalent to put option on fixing
        Date today = Settings::instance().evaluationDate();
        if (fixingDate_ <= today) {
            // the fixing is determined
            const Rate Rs =
                std::max(effectiveFloor-coupon_->swapIndex()->fixing(fixingDate_),0.);
            Rate price = (gearing_*Rs)*(coupon_->accrualPeriod()*discount_);
            return price;
        } else {
            Real cutoffNearZero = 1e-10;
            Real floorletPrice = 0;
            if (effectiveFloor > cutoffForFloorlet_){
                Rate effectiveStrikeForMin = std::max(effectiveFloor,cutoffNearZero);
                floorletPrice=optionletPrice(Option::Put, effectiveStrikeForMin);
            }
            return gearing_ * floorletPrice;
        }
    }

    Rate HaganPricer::floorletRate(Rate effectiveFloor) const {
        return floorletPrice(effectiveFloor)/(coupon_->accrualPeriod()*discount_);
    }

//===========================================================================//
//                  NumericHaganPricer                    //
//===========================================================================//

    namespace {

        class VariableChange {
          public:
            VariableChange(boost::function<Real (Real)>& f,
                           Real a, Real b, Size k)
            : a_(a), width_(b-a), f_(f), k_(k) {}
            Real value(Real x) const {
                Real newVar;
                Real temp = width_;
                for (Size i = 1; i < k_ ; ++i) {
                    temp *= x;
                }
                newVar = a_ + x* temp;
                return f_(newVar) * k_* temp;
            }
          private:
            Real a_, width_;
            boost::function<Real (Real)> f_;
            Size k_;
        };

        class Spy {
          public:
            Spy(boost::function<Real (Real)> f) : f_(f) {}
            Real value(Real x){
                abscissas.push_back(x);
                Real value = f_(x);
                functionValues.push_back(value);
                return value;
            }
          private:
            boost::function<Real (Real)> f_;
            std::vector<Real> abscissas;
            std::vector<Real> functionValues;
        };

    }

    NumericHaganPricer::NumericHaganPricer(
        const Handle<SwaptionVolatilityStructure>& swaptionVol,
        GFunctionFactory::YieldCurveModel modelOfYieldCurve,
        const Handle<Quote>& meanReversion,
        Real lowerLimit,
        Real upperLimit,
        Real precision,
        Real hardUpperLimit)
    : HaganPricer(swaptionVol, modelOfYieldCurve, meanReversion),
       upperLimit_(upperLimit),
       lowerLimit_(lowerLimit),
       requiredStdDeviations_(8),
       precision_(precision),
       refiningIntegrationTolerance_(.0001),
       hardUpperLimit_(hardUpperLimit) {

    }

    Real NumericHaganPricer::integrate(Real a,
        Real b, const ConundrumIntegrand& integrand) const {
            Real result =.0;
            //double abserr =.0;
            //double alpha = 1.0;


            //double epsabs = precision_;
            //double epsrel = 1.0; // we are interested only in absolute precision
            //size_t neval =0;

            // we use the non adaptive algorithm only for semi infinite interval
            if (a>0){

                // we estimate the actual boudary by testing integrand values
                Real upperBoundary = 2*a;
                while(integrand(upperBoundary)>precision_)
                    upperBoundary *=2.0;
                // sometimes b < a because of a wrong estimation of b based on stdev
                if (b > a)
                    upperBoundary = std::min(upperBoundary, b);

                boost::function<Real (Real)> f;
                GaussKronrodNonAdaptive
                    gaussKronrodNonAdaptive(precision_, 1000000, 1.0);
                // if the integration intervall is wide enough we use the
                // following change variable x -> a + (b-a)*(t/(a-b))^3
                upperBoundary = std::max(a,std::min(upperBoundary, hardUpperLimit_));
                if (upperBoundary > 2*a){
                    Size k = 3;
                    boost::function<Real (Real)> temp = boost::ref(integrand);
                    VariableChange variableChange(temp, a, upperBoundary, k);
                    f = boost::bind(&VariableChange::value, &variableChange, _1);
                    result = gaussKronrodNonAdaptive(f, .0, 1.0);
                } else {
                    f = boost::ref(integrand);
                    result = gaussKronrodNonAdaptive(f, a, upperBoundary);
                }

                // if the expected precision has not been reached we use the old algorithm
                if (!gaussKronrodNonAdaptive.integrationSuccess()){
                    const GaussKronrodAdaptive integrator(precision_, 100000);
                    b = std::max(a,std::min(b, hardUpperLimit_));
                    result = integrator(integrand,a , b);
                }

            } else {   // if a < b we use the old algorithm
                b = std::max(a,std::min(b,hardUpperLimit_));
                const GaussKronrodAdaptive integrator(precision_, 100000);
                result = integrator(integrand,a , b);
            }
            return result;
    }

    Real NumericHaganPricer::optionletPrice(
                                Option::Type optionType, Real strike) const {

        boost::shared_ptr<ConundrumIntegrand> integrand(new
            ConundrumIntegrand(vanillaOptionPricer_, rateCurve_, gFunction_,
                               fixingDate_, paymentDate_, annuity_,
                               swapRateValue_, strike, optionType));
        stdDeviationsForUpperLimit_= requiredStdDeviations_;
        Real a, b, integralValue;
        if (optionType==Option::Call) {
            upperLimit_ = resetUpperLimit(stdDeviationsForUpperLimit_);
        //    while(upperLimit_ <= strike){
        //        stdDeviationsForUpperLimit_ += 1.;
        //        upperLimit_ = resetUpperLimit(stdDeviationsForUpperLimit_);
        //    }
            integralValue = integrate(strike, upperLimit_, *integrand);
            //refineIntegration(integralValue, *integrand);
        } else {
            a = std::min(strike, lowerLimit_);
            b = strike;
            integralValue = integrate(a, b, *integrand);
        }

        Real dFdK = integrand->firstDerivativeOfF(strike);
        Real swaptionPrice =
            (*vanillaOptionPricer_)(strike, optionType, annuity_);

        // v. HAGAN, Conundrums..., formule 2.17a, 2.18a
        return coupon_->accrualPeriod() * (discount_/annuity_) *
            ((1 + dFdK) * swaptionPrice + optionType*integralValue);
    }

    Real NumericHaganPricer::swapletPrice() const {

        Date today = Settings::instance().evaluationDate();
        if (fixingDate_ <= today) {
            // the fixing is determined
            const Rate Rs = coupon_->swapIndex()->fixing(fixingDate_);
            Rate price = (gearing_*Rs + spread_)*(coupon_->accrualPeriod()*discount_);
            return price;
        } else {
            Real atmCapletPrice = optionletPrice(Option::Call, swapRateValue_);
            Real atmFloorletPrice = optionletPrice(Option::Put, swapRateValue_);
            return gearing_ *(coupon_->accrualPeriod()* discount_ * swapRateValue_
                             + atmCapletPrice - atmFloorletPrice)
                   + spreadLegValue_;
        }
    }

    Real NumericHaganPricer::refineIntegration(Real integralValue,
                                                const ConundrumIntegrand& integrand) const {
        Real percDiff = 1000.;
        while(std::fabs(percDiff) < refiningIntegrationTolerance_){
            stdDeviationsForUpperLimit_ += 1.;
            Real lowerLimit = upperLimit_;
            upperLimit_ = resetUpperLimit(stdDeviationsForUpperLimit_);
            Real diff = integrate(lowerLimit, upperLimit_,integrand);
            percDiff = diff/integralValue;
            integralValue += diff;
        }
        return integralValue;
    }

    Real NumericHaganPricer::resetUpperLimit(
                        Real stdDeviationsForUpperLimit) const {
        //return 1.0;
        Real variance =
            swaptionVolatility()->blackVariance(fixingDate_,swapTenor_,swapRateValue_);
        return swapRateValue_ *
            std::exp(stdDeviationsForUpperLimit*std::sqrt(variance));
    }


//===========================================================================//
//                              ConundrumIntegrand                           //
//===========================================================================//

    NumericHaganPricer::ConundrumIntegrand::ConundrumIntegrand(
        const boost::shared_ptr<VanillaOptionPricer>& o,
        const boost::shared_ptr<YieldTermStructure>&,
        const boost::shared_ptr<GFunction>& gFunction,
        Date fixingDate,
        Date paymentDate,
        Real annuity,
        Real forwardValue,
        Real strike,
        Option::Type optionType)
    : vanillaOptionPricer_(o), forwardValue_(forwardValue), annuity_(annuity),
      fixingDate_(fixingDate), paymentDate_(paymentDate), strike_(strike),
      optionType_(optionType),
      gFunction_(gFunction) {}

    void NumericHaganPricer::ConundrumIntegrand::setStrike(Real strike) {
        strike_ = strike;
    }

    Real NumericHaganPricer::ConundrumIntegrand::strike() const {
        return strike_;
    }

    Real NumericHaganPricer::ConundrumIntegrand::annuity() const {
        return annuity_;
    }

    Date NumericHaganPricer::ConundrumIntegrand::fixingDate() const {
        return fixingDate_;
    }

    Real NumericHaganPricer::ConundrumIntegrand::functionF (const Real x) const {
        const Real Gx = gFunction_->operator()(x);
        const Real GR = gFunction_->operator()(forwardValue_);
        return (x - strike_) * (Gx/GR - 1.0);
    }

    Real NumericHaganPricer::ConundrumIntegrand::firstDerivativeOfF (const Real x) const {
        const Real Gx = gFunction_->operator()(x);
        const Real GR = gFunction_->operator()(forwardValue_) ;
        const Real G1 = gFunction_->firstDerivative(x);
        return (Gx/GR - 1.0) + G1/GR * (x - strike_);
    }

    Real NumericHaganPricer::ConundrumIntegrand::secondDerivativeOfF (const Real x) const {
        const Real GR = gFunction_->operator()(forwardValue_) ;
        const Real G1 = gFunction_->firstDerivative(x);
        const Real G2 = gFunction_->secondDerivative(x);
        return 2.0 * G1/GR + (x - strike_) * G2/GR;
    }

    Real NumericHaganPricer::ConundrumIntegrand::operator()(Real x) const {
        const Real option = (*vanillaOptionPricer_)(x, optionType_, annuity_);
        return option * secondDerivativeOfF(x);
    }



//===========================================================================//
//                          AnalyticHaganPricer                           //
//===========================================================================//

    AnalyticHaganPricer::AnalyticHaganPricer(
        const Handle<SwaptionVolatilityStructure>& swaptionVol,
        GFunctionFactory::YieldCurveModel modelOfYieldCurve,
        const Handle<Quote>& meanReversion)
    : HaganPricer(swaptionVol, modelOfYieldCurve, meanReversion)
      { }

    //Hagan, 3.5b, 3.5c
    Real AnalyticHaganPricer::optionletPrice(Option::Type optionType,
                                                  Real strike) const {
        Real variance = swaptionVolatility()->blackVariance(fixingDate_,
                                                           swapTenor_,
                                                           swapRateValue_);
        Real firstDerivativeOfGAtForwardValue = gFunction_->firstDerivative(
                                                        swapRateValue_);
        Real price = 0;

        Real CK = (*vanillaOptionPricer_)(strike, optionType, annuity_);
        price += (discount_/annuity_)*CK;
        const Real sqrtSigma2T = std::sqrt(variance);
        const Real lnRoverK =  std::log(swapRateValue_/strike);
        const Real d32 = (lnRoverK+1.5*variance)/sqrtSigma2T;
        const Real d12 =  (lnRoverK+.5*variance)/sqrtSigma2T;
        const Real dminus12 =  (lnRoverK-.5*variance)/sqrtSigma2T;

        CumulativeNormalDistribution cumulativeOfNormal;
        const Real N32 = cumulativeOfNormal(optionType*d32);
        const Real N12 = cumulativeOfNormal(optionType*d12);
        const Real Nminus12 = cumulativeOfNormal(optionType*dminus12);

        price += optionType * firstDerivativeOfGAtForwardValue * annuity_ *
            swapRateValue_ * (swapRateValue_ * std::exp(variance) * N32-
            (swapRateValue_+strike) * N12 + strike * Nminus12);
        price *= coupon_->accrualPeriod();
        return price;
    }

    //Hagan 3.4c
    Real AnalyticHaganPricer::swapletPrice() const {

        Date today = Settings::instance().evaluationDate();
        if (fixingDate_ <= today) {
            // the fixing is determined
            const Rate Rs = coupon_->swapIndex()->fixing(fixingDate_);
            Rate price = (gearing_*Rs + spread_)*(coupon_->accrualPeriod()*discount_);
            return price;
        } else {
            Real variance(swaptionVolatility()->blackVariance(fixingDate_,
                                                               swapTenor_,
                                                               swapRateValue_));
            Real firstDerivativeOfGAtForwardValue(gFunction_->firstDerivative(
                                                            swapRateValue_));
            Real price = 0;
            price += discount_*swapRateValue_;
            price += firstDerivativeOfGAtForwardValue*annuity_*swapRateValue_*
                     swapRateValue_*(std::exp(variance)-1.);
            return gearing_ * price * coupon_->accrualPeriod() + spreadLegValue_;
        }
    }


//===========================================================================//
//                              GFunctionStandard                            //
//===========================================================================//

    Real GFunctionFactory::GFunctionStandard::operator()(Real x) {
        Real n = static_cast<Real>(swapLength_) * q_;
        return x / std::pow((1.0 + x/q_), delta_) * 1.0 /
            (1.0 - 1.0 / std::pow((1.0 + x/q_), n));
    }

    Real GFunctionFactory::GFunctionStandard::firstDerivative(Real x) {
        Real n = static_cast<Real>(swapLength_) * q_;
        Real a = 1.0 + x / q_;
        Real AA = a - delta_/q_ * x;
        Real B = std::pow(a,(n - delta_ - 1.0))/(std::pow(a,n) - 1.0);

        Real secNum = n * x * std::pow(a,(n-1.0));
        Real secDen = q_ * std::pow(a, delta_) * (std::pow(a, n) - 1.0) *
            (std::pow(a, n) - 1.0);
        Real sec = secNum / secDen;

        return AA * B - sec;
    }

    Real GFunctionFactory::GFunctionStandard::secondDerivative(Real x) {
        Real n = static_cast<Real>(swapLength_) * q_;
        Real a = 1.0 + x/q_;
        Real AA = a - delta_/q_ * x;
        Real A1 = (1.0 - delta_)/q_;
        Real B = std::pow(a,(n - delta_ - 1.0))/(std::pow(a,n) - 1.0);
        Real Num = (1.0 + delta_ - n) * std::pow(a, (n-delta_-2.0)) -
            (1.0 + delta_) * std::pow(a, (2.0*n-delta_-2.0));
        Real Den = (std::pow(a, n) - 1.0) * (std::pow(a, n) - 1.0);
        Real B1 = 1.0 / q_ * Num / Den;

        Real C =  x / std::pow(a, delta_);
        Real C1 = (std::pow(a, delta_)
            - delta_ /q_ * x * std::pow(a, (delta_ - 1.0))) / std::pow(a, 2 * delta_);

        Real D =  std::pow(a, (n-1.0))/ ((std::pow(a, n) - 1.0) * (std::pow(a, n) - 1.0));
        Real D1 = ((n - 1.0) * std::pow(a, (n-2.0)) * (std::pow(a, n) - 1.0)
            - 2 * n * std::pow(a, (2 * (n-1.0))))
            / (q_ * (std::pow(a, n) - 1.0)*(std::pow(a, n) - 1.0)*(std::pow(a, n) - 1.0));

        return A1 * B + AA * B1 - n/q_ * (C1 * D + C * D1);
    }

    boost::shared_ptr<GFunction> GFunctionFactory::newGFunctionStandard(Size q,
                                                            Real delta, Size swapLength) {
        return boost::shared_ptr<GFunction>(new GFunctionStandard(q, delta, swapLength));
    }

//===========================================================================//
//                              GFunctionExactYield                          //
//===========================================================================//

    GFunctionFactory::GFunctionExactYield::GFunctionExactYield(const CmsCoupon& coupon){

        const boost::shared_ptr<SwapIndex>& swapIndex = coupon.swapIndex();
        const boost::shared_ptr<VanillaSwap>& swap =
            swapIndex->underlyingSwap(coupon.fixingDate());

        const Schedule& schedule = swap->fixedSchedule();
        Handle<YieldTermStructure> rateCurve =
            swapIndex->forwardingTermStructure();

        const DayCounter& dc = swapIndex->dayCounter();

        Real swapStartTime = dc.yearFraction(rateCurve->referenceDate(),
                                             schedule.startDate());
        Real swapFirstPaymentTime = dc.yearFraction(rateCurve->referenceDate(),
                                                    schedule.date(1));

        Real paymentTime = dc.yearFraction(rateCurve->referenceDate(),
                                                 coupon.date());

        delta_ = (paymentTime-swapStartTime) / (swapFirstPaymentTime-swapStartTime);

        const Leg& fixedLeg(swap->fixedLeg());
        Size n = fixedLeg.size();
        accruals_.reserve(n);
        for (Size i=0; i<n; ++i) {
            boost::shared_ptr<Coupon> coupon =
                boost::dynamic_pointer_cast<Coupon>(fixedLeg[i]);
            accruals_.push_back(coupon->accrualPeriod());
        }
    }

    Real GFunctionFactory::GFunctionExactYield::operator()(Real x) {
        Real product = 1.;
        for(Size i=0; i<accruals_.size(); i++) {
            product *= 1./(1.+ accruals_[i]*x);
        }
        return x*std::pow(1.+ accruals_[0]*x,-delta_)*(1./(1.-product));
    }

    Real GFunctionFactory::GFunctionExactYield::firstDerivative(Real x) {
        Real c = -1.;
        Real derC = 0.;
        std::vector<Real> b;
        b.reserve(accruals_.size());
        for (Size i=0; i<accruals_.size(); i++) {
            Real temp = 1.0/(1.0+ accruals_[i]*x);
            b.push_back(temp);
            c *= temp;
            derC += accruals_[i]*temp;
        }
        c += 1.;
        c = 1./c;
        derC *= (c-c*c);

        return -delta_*accruals_[0]*std::pow(b[0],delta_+1.)*x*c+
                std::pow(b[0],delta_)*c+ std::pow(b[0],delta_)*x*derC;
        //Real dx = 1.0e-8;
        //return (operator()(x+dx)-operator()(x-dx))/(2.0*dx);
    }

    Real GFunctionFactory::GFunctionExactYield::secondDerivative(Real x) {
        Real c = -1.;
        Real sum = 0.;
        Real sumOfSquare = 0.;
        std::vector<Real> b;
        b.reserve(accruals_.size());
        for(Size i=0; i<accruals_.size(); i++) {
            Real temp = 1.0/(1.0+ accruals_[i]*x);
            b.push_back(temp);
            c *= temp;
            sum += accruals_[i]*temp;
            sumOfSquare += std::pow(accruals_[i]*temp, 2.0);
        }
        c += 1.;
        c = 1./c;
        Real derC =sum*(c-c*c);

        return (-delta_*accruals_[0]*std::pow(b[0],delta_+1.)*c+ std::pow(b[0],delta_)*derC)*
               (-delta_*accruals_[0]*b[0]*x + 1. + x*(1.-c)*sum)+
                std::pow(b[0],delta_)*c*(delta_*std::pow(accruals_[0]*b[0],2.)*x - delta_* accruals_[0]*b[0] -
                x*derC*sum + (1.-c)*sum - x*(1.-c)*sumOfSquare);
        //Real dx = 1.0e-8;
        //return (firstDerivative(x+dx)-firstDerivative(x-dx))/(2.0*dx);
    }

    boost::shared_ptr<GFunction> GFunctionFactory::newGFunctionExactYield(const CmsCoupon& coupon) {
        return boost::shared_ptr<GFunction>(new GFunctionExactYield(coupon));
    }



//===========================================================================//
//                            GFunctionWithShifts                            //
//===========================================================================//

    GFunctionFactory::GFunctionWithShifts::GFunctionWithShifts(
                    const CmsCoupon& coupon,
                    const Handle<Quote>& meanReversion)
    : meanReversion_(meanReversion), calibratedShift_(0.03),
      tmpRs_(10000000.0), accuracy_( 1.0e-14) {

        const boost::shared_ptr<SwapIndex>& swapIndex = coupon.swapIndex();
        const boost::shared_ptr<VanillaSwap>& swap = swapIndex->underlyingSwap(coupon.fixingDate());

        swapRateValue_ = swap->fairRate();

        objectiveFunction_ = boost::shared_ptr<ObjectiveFunction>(new ObjectiveFunction(*this, swapRateValue_));

        const Schedule& schedule = swap->fixedSchedule();
        Handle<YieldTermStructure> rateCurve =
            swapIndex->forwardingTermStructure();
        const DayCounter& dc = swapIndex->dayCounter();

        swapStartTime_ = dc.yearFraction(rateCurve->referenceDate(),
                                         schedule.startDate());
        discountAtStart_ = rateCurve->discount(schedule.startDate());

        Real paymentTime = dc.yearFraction(rateCurve->referenceDate(),
                                                 coupon.date());

        shapedPaymentTime_ = shapeOfShift(paymentTime);

        const Leg& fixedLeg(swap->fixedLeg());
        Size n = fixedLeg.size();
        accruals_.reserve(n);
        shapedSwapPaymentTimes_.reserve(n);
        swapPaymentDiscounts_.reserve(n);
        for(Size i=0; i<n; ++i) {
            boost::shared_ptr<Coupon> coupon =
                boost::dynamic_pointer_cast<Coupon>(fixedLeg[i]);
            accruals_.push_back(coupon->accrualPeriod());
            const Date paymentDate(coupon->date());
            const double swapPaymentTime(dc.yearFraction(rateCurve->referenceDate(), paymentDate));
            shapedSwapPaymentTimes_.push_back(shapeOfShift(swapPaymentTime));
            swapPaymentDiscounts_.push_back(rateCurve->discount(paymentDate));
        }
        discountRatio_ = swapPaymentDiscounts_.back()/discountAtStart_;
    }

    Real GFunctionFactory::GFunctionWithShifts::operator()(Real Rs) {
        const Real calibratedShift = calibrationOfShift(Rs);
        return Rs* functionZ(calibratedShift);
    }

    Real GFunctionFactory::GFunctionWithShifts::functionZ(Real x) {
        return std::exp(-shapedPaymentTime_*x)
            / (1.-discountRatio_*std::exp(-shapedSwapPaymentTimes_.back()*x));
    }

    Real GFunctionFactory::GFunctionWithShifts::derRs_derX(Real x) {
        Real sqrtDenominator = 0;
        Real derSqrtDenominator = 0;
        for(Size i=0; i<accruals_.size(); i++) {
            sqrtDenominator += accruals_[i]*swapPaymentDiscounts_[i]
                *std::exp(-shapedSwapPaymentTimes_[i]*x);
            derSqrtDenominator -= shapedSwapPaymentTimes_[i]* accruals_[i]*swapPaymentDiscounts_[i]
                *std::exp(-shapedSwapPaymentTimes_[i]*x);
        }
        const Real denominator = sqrtDenominator* sqrtDenominator;

        Real numerator = 0;
        numerator += shapedSwapPaymentTimes_.back()* swapPaymentDiscounts_.back()*
                     std::exp(-shapedSwapPaymentTimes_.back()*x)*sqrtDenominator;
        numerator -= (discountAtStart_ - swapPaymentDiscounts_.back()* std::exp(-shapedSwapPaymentTimes_.back()*x))*
                     derSqrtDenominator;
        QL_REQUIRE(denominator!=0, "GFunctionWithShifts::derRs_derX: denominator == 0");
        return numerator/denominator;
    }

    Real GFunctionFactory::GFunctionWithShifts::der2Rs_derX2(Real x) {
        Real denOfRfunztion = 0.;
        Real derDenOfRfunztion = 0.;
        Real der2DenOfRfunztion = 0.;
        for(Size i=0; i<accruals_.size(); i++) {
            denOfRfunztion += accruals_[i]*swapPaymentDiscounts_[i]
                *std::exp(-shapedSwapPaymentTimes_[i]*x);
            derDenOfRfunztion -= shapedSwapPaymentTimes_[i]* accruals_[i]*swapPaymentDiscounts_[i]
                *std::exp(-shapedSwapPaymentTimes_[i]*x);
            der2DenOfRfunztion+= shapedSwapPaymentTimes_[i]*shapedSwapPaymentTimes_[i]* accruals_[i]*
                swapPaymentDiscounts_[i]*std::exp(-shapedSwapPaymentTimes_[i]*x);
        }

        const Real denominator = std::pow(denOfRfunztion, 4);

        Real numOfDerR = 0;
        numOfDerR += shapedSwapPaymentTimes_.back()* swapPaymentDiscounts_.back()*
                     std::exp(-shapedSwapPaymentTimes_.back()*x)*denOfRfunztion;
        numOfDerR -= (discountAtStart_ - swapPaymentDiscounts_.back()* std::exp(-shapedSwapPaymentTimes_.back()*x))*
                     derDenOfRfunztion;

        const Real denOfDerR = std::pow(denOfRfunztion,2);

        Real derNumOfDerR = 0.;
        derNumOfDerR -= shapedSwapPaymentTimes_.back()*shapedSwapPaymentTimes_.back()* swapPaymentDiscounts_.back()*
                     std::exp(-shapedSwapPaymentTimes_.back()*x)*denOfRfunztion;
        derNumOfDerR += shapedSwapPaymentTimes_.back()* swapPaymentDiscounts_.back()*
                     std::exp(-shapedSwapPaymentTimes_.back()*x)*derDenOfRfunztion;

        derNumOfDerR -= (shapedSwapPaymentTimes_.back()*swapPaymentDiscounts_.back()*
                        std::exp(-shapedSwapPaymentTimes_.back()*x))* derDenOfRfunztion;
        derNumOfDerR -= (discountAtStart_ - swapPaymentDiscounts_.back()* std::exp(-shapedSwapPaymentTimes_.back()*x))*
                     der2DenOfRfunztion;

        const Real derDenOfDerR = 2*denOfRfunztion*derDenOfRfunztion;

        const Real numerator = derNumOfDerR*denOfDerR -numOfDerR*derDenOfDerR;
        QL_REQUIRE(denominator!=0, "GFunctionWithShifts::der2Rs_derX2: denominator == 0");
        return numerator/denominator;
    }

    Real GFunctionFactory::GFunctionWithShifts::derZ_derX(Real x) {
        const Real sqrtDenominator = (1.-discountRatio_*std::exp(-shapedSwapPaymentTimes_.back()*x));
        const Real denominator = sqrtDenominator* sqrtDenominator;
        QL_REQUIRE(denominator!=0, "GFunctionWithShifts::derZ_derX: denominator == 0");

        Real numerator = 0;
        numerator -= shapedPaymentTime_* std::exp(-shapedPaymentTime_*x)* sqrtDenominator;
        numerator -= shapedSwapPaymentTimes_.back()* std::exp(-shapedPaymentTime_*x)* (1.-sqrtDenominator);

        return numerator/denominator;
    }

    Real GFunctionFactory::GFunctionWithShifts::der2Z_derX2(Real x) {
        const Real denOfZfunction = (1.-discountRatio_*std::exp(-shapedSwapPaymentTimes_.back()*x));
        const Real derDenOfZfunction = shapedSwapPaymentTimes_.back()*discountRatio_*std::exp(-shapedSwapPaymentTimes_.back()*x);
        const Real denominator = std::pow(denOfZfunction, 4);
        QL_REQUIRE(denominator!=0, "GFunctionWithShifts::der2Z_derX2: denominator == 0");

        Real numOfDerZ = 0;
        numOfDerZ -= shapedPaymentTime_* std::exp(-shapedPaymentTime_*x)* denOfZfunction;
        numOfDerZ -= shapedSwapPaymentTimes_.back()* std::exp(-shapedPaymentTime_*x)* (1.-denOfZfunction);

        const Real denOfDerZ = std::pow(denOfZfunction,2);
        const Real derNumOfDerZ = (-shapedPaymentTime_* std::exp(-shapedPaymentTime_*x)*
                             (-shapedPaymentTime_+(shapedPaymentTime_*discountRatio_-
                               shapedSwapPaymentTimes_.back()*discountRatio_)* std::exp(-shapedSwapPaymentTimes_.back()*x))
                              -shapedSwapPaymentTimes_.back()*std::exp(-shapedPaymentTime_*x)*
                              (shapedPaymentTime_*discountRatio_- shapedSwapPaymentTimes_.back()*discountRatio_)*
                              std::exp(-shapedSwapPaymentTimes_.back()*x));

        const Real derDenOfDerZ = 2*denOfZfunction*derDenOfZfunction;
        const Real numerator = derNumOfDerZ*denOfDerZ -numOfDerZ*derDenOfDerZ;

        return numerator/denominator;
    }

    Real GFunctionFactory::GFunctionWithShifts::firstDerivative(Real Rs) {
        //Real dRs = 1.0e-8;
        //return (operator()(Rs+dRs)-operator()(Rs-dRs))/(2.0*dRs);
        const Real calibratedShift = calibrationOfShift(Rs);
        return functionZ(calibratedShift) + Rs * derZ_derX(calibratedShift)/derRs_derX(calibratedShift);
    }

    Real GFunctionFactory::GFunctionWithShifts::secondDerivative(Real Rs) {
        //Real dRs = 1.0e-8;
        //return (firstDerivative(Rs+dRs)-firstDerivative(Rs-dRs))/(2.0*dRs);
        const Real calibratedShift = calibrationOfShift(Rs);
        return 2.*derZ_derX(calibratedShift)/derRs_derX(calibratedShift) +
            Rs * der2Z_derX2(calibratedShift)/std::pow(derRs_derX(calibratedShift),2.)-
            Rs * derZ_derX(calibratedShift)*der2Rs_derX2(calibratedShift)/
            std::pow(derRs_derX(calibratedShift),3.);
    }

    Real GFunctionFactory::GFunctionWithShifts::ObjectiveFunction::operator ()(const Real& x) const {
        Real result = 0;
        derivative_ = 0;
        for(Size i=0; i<o_.accruals_.size(); i++) {
            Real temp = o_.accruals_[i]*o_.swapPaymentDiscounts_[i]
                *std::exp(-o_.shapedSwapPaymentTimes_[i]*x);
            result += temp;
            derivative_ -= o_.shapedSwapPaymentTimes_[i] * temp;
        }
        result *= Rs_;
        derivative_ *= Rs_;
        Real temp = o_.swapPaymentDiscounts_.back()
            * std::exp(-o_.shapedSwapPaymentTimes_.back()*x);

        result += temp-o_.discountAtStart_;
        derivative_ -= o_.shapedSwapPaymentTimes_.back()*temp;
        return result;
    }

    Real GFunctionFactory::GFunctionWithShifts::ObjectiveFunction::derivative(const Real&) const {
        return derivative_;
    }

    void GFunctionFactory::GFunctionWithShifts::ObjectiveFunction::setSwapRateValue(Real x) {
        Rs_ = x;
    }

    Real GFunctionFactory::GFunctionWithShifts::shapeOfShift(Real s) const {
        const Real x(s-swapStartTime_);
        Real meanReversion = meanReversion_->value();
        if(meanReversion>0) {
            return (1.-std::exp(-meanReversion*x))/meanReversion;
        }
        else {
            return x;
        }
    }

    Real GFunctionFactory::GFunctionWithShifts::calibrationOfShift(Real Rs){

        if(Rs!=tmpRs_){
            Real initialGuess, N=0, D=0;
            for(Size i=0; i<accruals_.size(); i++) {
                N+=accruals_[i]*swapPaymentDiscounts_[i];
                D+=accruals_[i]*swapPaymentDiscounts_[i]*shapedSwapPaymentTimes_[i];
            }
            N *= Rs;
            D *= Rs;
            N += accruals_.back() * swapPaymentDiscounts_.back()
                - objectiveFunction_->gFunctionWithShifts().discountAtStart_;
            D += accruals_.back() * swapPaymentDiscounts_.back()*
                            shapedSwapPaymentTimes_.back();
            initialGuess = N/D;

            objectiveFunction_->setSwapRateValue(Rs);
            Newton solver;
            solver.setMaxEvaluations(1000);

            // these boundaries migth not be big enough if the volatility
            // of big swap rate values is too high . In this case the G function
            // is not even integrable, so better to fix the vol than increasing
            // these values
            const Real lower = -20, upper = 20.;

            try {
                calibratedShift_ = solver.solve(*objectiveFunction_, accuracy_,
                    std::max( std::min(initialGuess, upper*.99), lower*.99),
                    lower, upper);
            } catch (std::exception& e) {
                QL_FAIL("meanReversion: " << meanReversion_->value() <<
                        ", swapRateValue: " << swapRateValue_ <<
                        ", swapStartTime: " << swapStartTime_ <<
                        ", shapedPaymentTime: " << shapedPaymentTime_ <<
                        "\n error message: " << e.what());
            }
            tmpRs_=Rs;
        }
        return calibratedShift_;
    }

    boost::shared_ptr<GFunction> GFunctionFactory::newGFunctionWithShifts(const CmsCoupon& coupon,
                                                                          const Handle<Quote>& meanReversion) {
        return boost::shared_ptr<GFunction>(new GFunctionWithShifts(coupon, meanReversion));
    }

}


<|start_filename|>test-suite/bonds.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004, 2005 StatPro Italia srl
 Copyright (C) 2007, 2012 <NAME>
 Copyright (C) 2007, 2009 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include "bonds.hpp"
#include "utilities.hpp"
#include <ql/instruments/bonds/fixedratebond.hpp>
#include <ql/instruments/bonds/floatingratebond.hpp>
#include <ql/instruments/bonds/zerocouponbond.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/calendars/unitedstates.hpp>
#include <ql/time/calendars/unitedkingdom.hpp>
#include <ql/time/calendars/australia.hpp>
#include <ql/time/calendars/brazil.hpp>
#include <ql/time/calendars/southafrica.hpp>
#include <ql/time/calendars/nullcalendar.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/business252.hpp>
#include <ql/indexes/ibor/usdlibor.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <ql/time/schedule.hpp>
#include <ql/cashflows/fixedratecoupon.hpp>
#include <ql/cashflows/simplecashflow.hpp>
#include <ql/cashflows/couponpricer.hpp>
#include <ql/cashflows/cashflows.hpp>
#include <ql/pricingengines/bond/discountingbondengine.hpp>
#include <ql/pricingengines/bond/bondfunctions.hpp>

using namespace QuantLib;
using namespace boost::unit_test_framework;
using boost::shared_ptr;

#define ASSERT_CLOSE(name, settlement, calculated, expected, tolerance)  \
    if (std::fabs(calculated-expected) > tolerance) { \
    BOOST_FAIL("Failed to reproduce " << name << " at " << settlement \
               << "\n    calculated: " << std::setprecision(8) << calculated \
               << "\n    expected:   " << std::setprecision(8) << expected); \
    }

namespace {

    struct CommonVars {
        // common data
        Calendar calendar;
        Date today;
        Real faceAmount;

        // cleanup
        SavedSettings backup;

        // setup
        CommonVars() {
            calendar = TARGET();
            today = calendar.adjust(Date::todaysDate());
            Settings::instance().evaluationDate() = today;
            faceAmount = 1000000.0;
        }
    };

}


void BondTest::testYield() {

    BOOST_TEST_MESSAGE("Testing consistency of bond price/yield calculation...");

    CommonVars vars;

    Real tolerance = 1.0e-7;
    Size maxEvaluations = 100;

    Integer issueMonths[] = { -24, -18, -12, -6, 0, 6, 12, 18, 24 };
    Integer lengths[] = { 3, 5, 10, 15, 20 };
    Natural settlementDays = 3;
    Real coupons[] = { 0.02, 0.05, 0.08 };
    Frequency frequencies[] = { Semiannual, Annual };
    DayCounter bondDayCount = Thirty360();
    BusinessDayConvention accrualConvention = Unadjusted;
    BusinessDayConvention paymentConvention = ModifiedFollowing;
    Real redemption = 100.0;

    Rate yields[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };
    Compounding compounding[] = { Compounded, Continuous };

    for (Size i=0; i<LENGTH(issueMonths); i++) {
      for (Size j=0; j<LENGTH(lengths); j++) {
        for (Size k=0; k<LENGTH(coupons); k++) {
          for (Size l=0; l<LENGTH(frequencies); l++) {
            for (Size n=0; n<LENGTH(compounding); n++) {

              Date dated = vars.calendar.advance(vars.today,
                                                 issueMonths[i], Months);
              Date issue = dated;
              Date maturity = vars.calendar.advance(issue,
                                                    lengths[j], Years);

              Schedule sch(dated, maturity,
                           Period(frequencies[l]), vars.calendar,
                           accrualConvention, accrualConvention,
                           DateGeneration::Backward, false);

              FixedRateBond bond(settlementDays, vars.faceAmount, sch,
                                 std::vector<Rate>(1, coupons[k]),
                                 bondDayCount, paymentConvention,
                                 redemption, issue);

              for (Size m=0; m<LENGTH(yields); m++) {

                Real price = BondFunctions::cleanPrice(bond, yields[m],
                                                 bondDayCount,
                                                 compounding[n],
                                                 frequencies[l]);
                Rate calculated = BondFunctions::yield(bond, price,
                                             bondDayCount, compounding[n],
                                             frequencies[l],
                                             Date(),
                                             tolerance, maxEvaluations);

                if (std::fabs(yields[m]-calculated) > tolerance) {
                  // the difference might not matter
                  Real price2 = BondFunctions::cleanPrice(bond, calculated,
                                                    bondDayCount,
                                                    compounding[n],
                                                    frequencies[l]);
                  if (std::fabs(price-price2)/price > tolerance) {
                      BOOST_FAIL("\nyield recalculation failed:"
                          "\n    issue:     " << issue <<
                          "\n    maturity:  " << maturity <<
                          "\n    coupon:    " << io::rate(coupons[k]) <<
                          "\n    frequency: " << frequencies[l] <<
                          "\n    yield:   " << io::rate(yields[m]) <<
                          (compounding[n] == Compounded ?
                                " compounded" : " continuous") <<
                          std::setprecision(7) <<
                          "\n    price:   " << price <<
                          "\n    yield': " << io::rate(calculated) <<
                          "\n    price': " << price2);
                  }
                }
              }
            }
          }
        }
      }
    }
}

void BondTest::testAtmRate() {

    BOOST_TEST_MESSAGE("Testing consistency of bond price/ATM rate calculation...");

    CommonVars vars;

    Real tolerance = 1.0e-7;

    Integer issueMonths[] = { -24, -18, -12, -6, 0, 6, 12, 18, 24 };
    Integer lengths[] = { 3, 5, 10, 15, 20 };
    Natural settlementDays = 3;
    Real coupons[] = { 0.02, 0.05, 0.08 };
    Frequency frequencies[] = { Semiannual, Annual };
    DayCounter bondDayCount = Thirty360();
    BusinessDayConvention accrualConvention = Unadjusted;
    BusinessDayConvention paymentConvention = ModifiedFollowing;
    Real redemption = 100.0;
    Handle<YieldTermStructure> disc(flatRate(vars.today,0.03,Actual360()));
    shared_ptr<PricingEngine> bondEngine(new DiscountingBondEngine(disc));

    for (Size i=0; i<LENGTH(issueMonths); i++) {
      for (Size j=0; j<LENGTH(lengths); j++) {
        for (Size k=0; k<LENGTH(coupons); k++) {
          for (Size l=0; l<LENGTH(frequencies); l++) {
            Date dated = vars.calendar.advance(vars.today,
                                               issueMonths[i], Months);
            Date issue = dated;
            Date maturity = vars.calendar.advance(issue,
                                                  lengths[j], Years);

            Schedule sch(dated, maturity,
                         Period(frequencies[l]), vars.calendar,
                         accrualConvention, accrualConvention,
                         DateGeneration::Backward, false);

            FixedRateBond bond(settlementDays, vars.faceAmount, sch,
                             std::vector<Rate>(1, coupons[k]),
                             bondDayCount, paymentConvention,
                             redemption, issue);

            bond.setPricingEngine(bondEngine);
            Real price = bond.cleanPrice();
            Rate calculated = BondFunctions::atmRate(bond,
                                                     **disc,
                                                     bond.settlementDate(),
                                                     price);

            if (std::fabs(coupons[k]-calculated) > tolerance) {
                  BOOST_FAIL("\natm rate recalculation failed:"
                      "\n today:           " << vars.today <<
                      "\n settlement date: " << bond.settlementDate() <<
                      "\n issue:           " << issue <<
                      "\n maturity:        " << maturity <<
                      "\n coupon:          " << io::rate(coupons[k]) <<
                      "\n frequency:       " << frequencies[l] <<
                      "\n clean price:     " << price <<
                      "\n dirty price:     " << price + bond.accruedAmount() <<
                      "\n atm rate:        " << io::rate(calculated));
            }
          }
        }
      }
    }
}

void BondTest::testZspread() {

    BOOST_TEST_MESSAGE("Testing consistency of bond price/z-spread calculation...");

    CommonVars vars;

    Real tolerance = 1.0e-7;
    Size maxEvaluations = 100;

    Handle<YieldTermStructure> discountCurve(
                                       flatRate(vars.today,0.03,Actual360()));

    Integer issueMonths[] = { -24, -18, -12, -6, 0, 6, 12, 18, 24 };
    Integer lengths[] = { 3, 5, 10, 15, 20 };
    Natural settlementDays = 3;
    Real coupons[] = { 0.02, 0.05, 0.08 };
    Frequency frequencies[] = { Semiannual, Annual };
    DayCounter bondDayCount = Thirty360();
    BusinessDayConvention accrualConvention = Unadjusted;
    BusinessDayConvention paymentConvention = ModifiedFollowing;
    Real redemption = 100.0;

    Spread spreads[] = { -0.01, -0.005, 0.0, 0.005, 0.01 };
    Compounding compounding[] = { Compounded, Continuous };

    for (Size i=0; i<LENGTH(issueMonths); i++) {
      for (Size j=0; j<LENGTH(lengths); j++) {
        for (Size k=0; k<LENGTH(coupons); k++) {
          for (Size l=0; l<LENGTH(frequencies); l++) {
            for (Size n=0; n<LENGTH(compounding); n++) {

              Date dated = vars.calendar.advance(vars.today,
                                                 issueMonths[i], Months);
              Date issue = dated;
              Date maturity = vars.calendar.advance(issue,
                                                    lengths[j], Years);

              Schedule sch(dated, maturity,
                           Period(frequencies[l]), vars.calendar,
                           accrualConvention, accrualConvention,
                           DateGeneration::Backward, false);

              FixedRateBond bond(settlementDays, vars.faceAmount, sch,
                                 std::vector<Rate>(1, coupons[k]),
                                 bondDayCount, paymentConvention,
                                 redemption, issue);

              for (Size m=0; m<LENGTH(spreads); m++) {

                Real price = BondFunctions::cleanPrice(bond, *discountCurve,
                                                   spreads[m],
                                                   bondDayCount,
                                                   compounding[n],
                                                   frequencies[l]);
                Spread calculated = BondFunctions::zSpread(bond, price,
                                                           *discountCurve,
                                                           bondDayCount,
                                                           compounding[n],
                                                           frequencies[l],
                                                           Date(),
                                                           tolerance,
                                                           maxEvaluations);

                if (std::fabs(spreads[m]-calculated) > tolerance) {
                  // the difference might not matter
                  Real price2 = BondFunctions::cleanPrice(bond, *discountCurve,
                                                      calculated,
                                                      bondDayCount,
                                                      compounding[n],
                                                      frequencies[l]);
                  if (std::fabs(price-price2)/price > tolerance) {
                      BOOST_FAIL("\nZ-spread recalculation failed:"
                          "\n    issue:     " << issue <<
                          "\n    maturity:  " << maturity <<
                          "\n    coupon:    " << io::rate(coupons[k]) <<
                          "\n    frequency: " << frequencies[l] <<
                          "\n    Z-spread:  " << io::rate(spreads[m]) <<
                          (compounding[n] == Compounded ?
                                " compounded" : " continuous") <<
                          std::setprecision(7) <<
                          "\n    price:     " << price <<
                          "\n    Z-spread': " << io::rate(calculated) <<
                          "\n    price':    " << price2);
                  }
                }
              }
            }
          }
        }
      }
    }
}



void BondTest::testTheoretical() {

    BOOST_TEST_MESSAGE("Testing theoretical bond price/yield calculation...");

    CommonVars vars;

    Real tolerance = 1.0e-7;
    Size maxEvaluations = 100;

    Size lengths[] = { 3, 5, 10, 15, 20 };
    Natural settlementDays = 3;
    Real coupons[] = { 0.02, 0.05, 0.08 };
    Frequency frequencies[] = { Semiannual, Annual };
    DayCounter bondDayCount = Actual360();
    BusinessDayConvention accrualConvention = Unadjusted;
    BusinessDayConvention paymentConvention = ModifiedFollowing;
    Real redemption = 100.0;

    Rate yields[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };

    for (Size j=0; j<LENGTH(lengths); j++) {
      for (Size k=0; k<LENGTH(coupons); k++) {
        for (Size l=0; l<LENGTH(frequencies); l++) {

            Date dated = vars.today;
            Date issue = dated;
            Date maturity = vars.calendar.advance(issue, lengths[j], Years);

            shared_ptr<SimpleQuote> rate(new SimpleQuote(0.0));
            Handle<YieldTermStructure> discountCurve(flatRate(vars.today,
                                                              rate,
                                                              bondDayCount));

            Schedule sch(dated, maturity,
                         Period(frequencies[l]), vars.calendar,
                         accrualConvention, accrualConvention,
                         DateGeneration::Backward, false);

            FixedRateBond bond(settlementDays, vars.faceAmount, sch,
                               std::vector<Rate>(1, coupons[k]),
                               bondDayCount, paymentConvention,
                               redemption, issue);

            shared_ptr<PricingEngine> bondEngine(
                                    new DiscountingBondEngine(discountCurve));
            bond.setPricingEngine(bondEngine);

            for (Size m=0; m<LENGTH(yields); m++) {

                rate->setValue(yields[m]);

                Real price = BondFunctions::cleanPrice(bond, yields[m],
                                                 bondDayCount, Continuous,
                                                 frequencies[l]);
                Real calculatedPrice = bond.cleanPrice();

                if (std::fabs(price-calculatedPrice) > tolerance) {
                    BOOST_FAIL("price calculation failed:" <<
                        "\n    issue:     " << issue <<
                        "\n    maturity:  " << maturity <<
                        "\n    coupon:    " << io::rate(coupons[k]) <<
                        "\n    frequency: " << frequencies[l] <<
                        "\n    yield:  " << io::rate(yields[m]) <<
                        std::setprecision(7) <<
                        "\n    expected:    " << price <<
                        "\n    calculated': " << calculatedPrice <<
                        "\n    error':      " << price-calculatedPrice);
                }

                Rate calculatedYield = BondFunctions::yield(bond, calculatedPrice,
                    bondDayCount, Continuous, frequencies[l],
                    bond.settlementDate(),
                    tolerance, maxEvaluations);
                if (std::fabs(yields[m]-calculatedYield) > tolerance) {
                    BOOST_FAIL("yield calculation failed:" <<
                        "\n    issue:     " << issue <<
                        "\n    maturity:  " << maturity <<
                        "\n    coupon:    " << io::rate(coupons[k]) <<
                        "\n    frequency: " << frequencies[l] <<
                        "\n    yield:  " << io::rate(yields[m]) <<
                        std::setprecision(7) <<
                        "\n    price:  " << price <<
                        "\n    yield': " << io::rate(calculatedYield));
                }
            }
        }
      }
    }
}


void BondTest::testCached() {

    BOOST_TEST_MESSAGE(
        "Testing bond price/yield calculation against cached values...");

    CommonVars vars;

    // with implicit settlement calculation:

    Date today(22, November, 2004);
    Settings::instance().evaluationDate() = today;

    Calendar bondCalendar = NullCalendar();
    DayCounter bondDayCount = ActualActual(ActualActual::ISMA);
    Natural settlementDays = 1;

    Handle<YieldTermStructure> discountCurve(flatRate(today,0.03,Actual360()));

    // actual market values from the evaluation date

    Frequency freq = Semiannual;
    Schedule sch1(Date(31, October, 2004),
                  Date(31, October, 2006), Period(freq), bondCalendar,
                  Unadjusted, Unadjusted, DateGeneration::Backward, false);

    FixedRateBond bond1(settlementDays, vars.faceAmount, sch1,
                        std::vector<Rate>(1, 0.025),
                        bondDayCount, ModifiedFollowing,
                        100.0, Date(1, November, 2004));

    shared_ptr<PricingEngine> bondEngine(
                                    new DiscountingBondEngine(discountCurve));
    bond1.setPricingEngine(bondEngine);

    Real marketPrice1 = 99.203125;
    Rate marketYield1 = 0.02925;

    Schedule sch2(Date(15, November, 2004),
                  Date(15, November, 2009), Period(freq), bondCalendar,
                  Unadjusted, Unadjusted, DateGeneration::Backward, false);

    FixedRateBond bond2(settlementDays, vars.faceAmount, sch2,
                        std::vector<Rate>(1, 0.035),
                        bondDayCount, ModifiedFollowing,
                        100.0, Date(15, November, 2004));

    bond2.setPricingEngine(bondEngine);

    Real marketPrice2 = 99.6875;
    Rate marketYield2 = 0.03569;

    // calculated values

    Real cachedPrice1a = 99.204505, cachedPrice2a = 99.687192;
    Real cachedPrice1b = 98.943393, cachedPrice2b = 101.986794;
    Rate cachedYield1a = 0.029257,  cachedYield2a = 0.035689;
    Rate cachedYield1b = 0.029045,  cachedYield2b = 0.035375;
    Rate cachedYield1c = 0.030423,  cachedYield2c = 0.030432;

    // check
    Real tolerance = 1.0e-6;
    Real price, yield;

    price = BondFunctions::cleanPrice(bond1, marketYield1,
                             bondDayCount, Compounded, freq);
    if (std::fabs(price-cachedPrice1a) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:"
                   << QL_FIXED
                   << "\n    calculated: " << price
                   << "\n    expected:   " << cachedPrice1a
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << price-cachedPrice1a);
    }

    price = bond1.cleanPrice();
    if (std::fabs(price-cachedPrice1b) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:"
                   << QL_FIXED
                   << "\n    calculated: " << price
                   << "\n    expected:   " << cachedPrice1b
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << price-cachedPrice1b);
    }

    yield = BondFunctions::yield(bond1, marketPrice1, bondDayCount, Compounded, freq);
    if (std::fabs(yield-cachedYield1a) > tolerance) {
        BOOST_FAIL("\nfailed to reproduce cached compounded yield:" <<
                   std::setprecision(4) <<
                   "\n    calculated: " << io::rate(yield) <<
                   "\n    expected:   " << io::rate(cachedYield1a) <<
                   "\n    tolerance:  " << io::rate(tolerance) <<
                   "\n    error:      " << io::rate(yield-cachedYield1a));
    }

    yield = BondFunctions::yield(bond1, marketPrice1, bondDayCount, Continuous, freq);
    if (std::fabs(yield-cachedYield1b) > tolerance) {
        BOOST_FAIL("failed to reproduce cached continuous yield:"
                   << std::setprecision(4)
                   << "\n    calculated: " << io::rate(yield)
                   << "\n    expected:   " << io::rate(cachedYield1b)
                   << "\n    tolerance:  " << io::rate(tolerance)
                   << "\n    error:      " << io::rate(yield-cachedYield1b));
    }

    yield = BondFunctions::yield(bond1, bond1.cleanPrice(), bondDayCount, Continuous, freq, bond1.settlementDate());
    if (std::fabs(yield-cachedYield1c) > tolerance) {
        BOOST_FAIL("failed to reproduce cached continuous yield:"
                   << std::setprecision(4)
                   << "\n    calculated: " << io::rate(yield)
                   << "\n    expected:   " << io::rate(cachedYield1c)
                   << "\n    tolerance:  " << io::rate(tolerance)
                   << "\n    error:      " << io::rate(yield-cachedYield1c));
    }


    price = BondFunctions::cleanPrice(bond2, marketYield2, bondDayCount, Compounded, freq);
    if (std::fabs(price-cachedPrice2a) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:"
                   << QL_FIXED
                   << "\n    calculated: " << price
                   << "\n    expected:   " << cachedPrice2a
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << price-cachedPrice2a);
    }

    price = bond2.cleanPrice();
    if (std::fabs(price-cachedPrice2b) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:"
                   << QL_FIXED
                   << "\n    calculated: " << price
                   << "\n    expected:   " << cachedPrice2b
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << price-cachedPrice2b);
    }

    yield = BondFunctions::yield(bond2, marketPrice2, bondDayCount, Compounded, freq);
    if (std::fabs(yield-cachedYield2a) > tolerance) {
        BOOST_FAIL("failed to reproduce cached compounded yield:"
                   << std::setprecision(4)
                   << "\n    calculated: " << io::rate(yield)
                   << "\n    expected:   " << io::rate(cachedYield2a)
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << io::rate(yield-cachedYield2a));
    }

    yield = BondFunctions::yield(bond2, marketPrice2, bondDayCount, Continuous, freq);
    if (std::fabs(yield-cachedYield2b) > tolerance) {
        BOOST_FAIL("failed to reproduce cached continuous yield:"
                   << std::setprecision(4)
                   << "\n    calculated: " << io::rate(yield)
                   << "\n    expected:   " << io::rate(cachedYield2b)
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << io::rate(yield-cachedYield2b));
    }

    yield = BondFunctions::yield(bond2, bond2.cleanPrice(), bondDayCount, Continuous, freq, bond2.settlementDate());
    if (std::fabs(yield-cachedYield2c) > tolerance) {
        BOOST_FAIL("failed to reproduce cached continuous yield:"
                   << std::setprecision(4)
                   << "\n    calculated: " << io::rate(yield)
                   << "\n    expected:   " << io::rate(cachedYield2c)
                   << "\n    tolerance:  " << tolerance
                   << "\n    error:      " << io::rate(yield-cachedYield2c));
    }

    // with explicit settlement date:

    Schedule sch3(Date(30,November,2004),
                  Date(30,November,2006), Period(freq),
                  UnitedStates(UnitedStates::GovernmentBond),
                  Unadjusted, Unadjusted, DateGeneration::Backward, false);

    FixedRateBond bond3(settlementDays, vars.faceAmount, sch3,
                        std::vector<Rate>(1, 0.02875),
                        ActualActual(ActualActual::ISMA),
                        ModifiedFollowing,
                        100.0, Date(30,November,2004));

    bond3.setPricingEngine(bondEngine);

    Rate marketYield3 = 0.02997;

    Date settlementDate = Date(30,November,2004);
    Real cachedPrice3 = 99.764759;

    price = BondFunctions::cleanPrice(bond3, marketYield3,
                             bondDayCount, Compounded, freq, settlementDate);
    if (std::fabs(price-cachedPrice3) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:"
                   << QL_FIXED
                   << "\n    calculated: " << price << ""
                   << "\n    expected:   " << cachedPrice3 << ""
                   << "\n    error:      " << price-cachedPrice3);
    }

    // this should give the same result since the issue date is the
    // earliest possible settlement date

    Settings::instance().evaluationDate() = Date(22,November,2004);

    price = BondFunctions::cleanPrice(bond3, marketYield3, bondDayCount, Compounded, freq);
    if (std::fabs(price-cachedPrice3) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:"
                   << QL_FIXED
                   << "\n    calculated: " << price << ""
                   << "\n    expected:   " << cachedPrice3 << ""
                   << "\n    error:      " << price-cachedPrice3);
    }
}



void BondTest::testCachedZero() {

    BOOST_TEST_MESSAGE("Testing zero-coupon bond prices against cached values...");

    CommonVars vars;

    Date today(22,November,2004);
    Settings::instance().evaluationDate() = today;

    Natural settlementDays = 1;

    Handle<YieldTermStructure> discountCurve(flatRate(today,0.03,Actual360()));

    Real tolerance = 1.0e-6;

    // plain

    ZeroCouponBond bond1(settlementDays,
                         UnitedStates(UnitedStates::GovernmentBond),
                         vars.faceAmount,
                         Date(30,November,2008),
                         ModifiedFollowing,
                         100.0, Date(30,November,2004));

    shared_ptr<PricingEngine> bondEngine(
                                    new DiscountingBondEngine(discountCurve));
    bond1.setPricingEngine(bondEngine);

    Real cachedPrice1 = 88.551726;

    Real price = bond1.cleanPrice();
    if (std::fabs(price-cachedPrice1) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice1 << "\n"
                   << "    error:      " << price-cachedPrice1);
    }

    ZeroCouponBond bond2(settlementDays,
                         UnitedStates(UnitedStates::GovernmentBond),
                         vars.faceAmount,
                         Date(30,November,2007),
                         ModifiedFollowing,
                         100.0, Date(30,November,2004));

    bond2.setPricingEngine(bondEngine);

    Real cachedPrice2 = 91.278949;

    price = bond2.cleanPrice();
    if (std::fabs(price-cachedPrice2) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice2 << "\n"
                   << "    error:      " << price-cachedPrice2);
    }

    ZeroCouponBond bond3(settlementDays,
                         UnitedStates(UnitedStates::GovernmentBond),
                         vars.faceAmount,
                         Date(30,November,2006),
                         ModifiedFollowing,
                         100.0, Date(30,November,2004));

    bond3.setPricingEngine(bondEngine);

    Real cachedPrice3 = 94.098006;

    price = bond3.cleanPrice();
    if (std::fabs(price-cachedPrice3) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice3 << "\n"
                   << "    error:      " << price-cachedPrice3);
    }
}


void BondTest::testCachedFixed() {

    BOOST_TEST_MESSAGE("Testing fixed-coupon bond prices against cached values...");

    CommonVars vars;

    Date today(22,November,2004);
    Settings::instance().evaluationDate() = today;

    Natural settlementDays = 1;

    Handle<YieldTermStructure> discountCurve(flatRate(today,0.03,Actual360()));

    Real tolerance = 1.0e-6;

    // plain

    Schedule sch(Date(30,November,2004),
                 Date(30,November,2008), Period(Semiannual),
                 UnitedStates(UnitedStates::GovernmentBond),
                 Unadjusted, Unadjusted, DateGeneration::Backward, false);

    FixedRateBond bond1(settlementDays, vars.faceAmount, sch,
                        std::vector<Rate>(1, 0.02875),
                        ActualActual(ActualActual::ISMA),
                        ModifiedFollowing,
                        100.0, Date(30,November,2004));

    shared_ptr<PricingEngine> bondEngine(
                                    new DiscountingBondEngine(discountCurve));
    bond1.setPricingEngine(bondEngine);

    Real cachedPrice1 = 99.298100;

    Real price = bond1.cleanPrice();
    if (std::fabs(price-cachedPrice1) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice1 << "\n"
                   << "    error:      " << price-cachedPrice1);
    }

    // varying coupons

    std::vector<Rate> couponRates(4);
    couponRates[0] = 0.02875;
    couponRates[1] = 0.03;
    couponRates[2] = 0.03125;
    couponRates[3] = 0.0325;

    FixedRateBond bond2(settlementDays, vars.faceAmount, sch,
                          couponRates,
                          ActualActual(ActualActual::ISMA),
                          ModifiedFollowing,
                          100.0, Date(30,November,2004));

    bond2.setPricingEngine(bondEngine);

    Real cachedPrice2 = 100.334149;

    price = bond2.cleanPrice();
    if (std::fabs(price-cachedPrice2) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice2 << "\n"
                   << "    error:      " << price-cachedPrice2);
    }

    // stub date

    Schedule sch3(Date(30,November,2004),
                  Date(30,March,2009), Period(Semiannual),
                  UnitedStates(UnitedStates::GovernmentBond),
                  Unadjusted, Unadjusted, DateGeneration::Backward, false,
                  Date(), Date(30,November,2008));

    FixedRateBond bond3(settlementDays, vars.faceAmount, sch3,
                          couponRates, ActualActual(ActualActual::ISMA),
                          ModifiedFollowing,
                          100.0, Date(30,November,2004));

    bond3.setPricingEngine(bondEngine);

    Real cachedPrice3 = 100.382794;

    price = bond3.cleanPrice();
    if (std::fabs(price-cachedPrice3) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice3 << "\n"
                   << "    error:      " << price-cachedPrice3);
    }
}


void BondTest::testCachedFloating() {

    BOOST_TEST_MESSAGE("Testing floating-rate bond prices against cached values...");

    CommonVars vars;

    Date today(22,November,2004);
    Settings::instance().evaluationDate() = today;

    Natural settlementDays = 1;

    Handle<YieldTermStructure> riskFreeRate(flatRate(today,0.025,Actual360()));
    Handle<YieldTermStructure> discountCurve(flatRate(today,0.03,Actual360()));

    shared_ptr<IborIndex> index(new USDLibor(6*Months, riskFreeRate));
    Natural fixingDays = 1;

    Real tolerance = 1.0e-6;

    shared_ptr<IborCouponPricer> pricer(new
        BlackIborCouponPricer(Handle<OptionletVolatilityStructure>()));

    // plain

    Schedule sch(Date(30,November,2004),
                 Date(30,November,2008),
                 Period(Semiannual),
                 UnitedStates(UnitedStates::GovernmentBond),
                 ModifiedFollowing, ModifiedFollowing,
                 DateGeneration::Backward, false);

    FloatingRateBond bond1(settlementDays, vars.faceAmount, sch,
                           index, ActualActual(ActualActual::ISMA),
                           ModifiedFollowing, fixingDays,
                           std::vector<Real>(), std::vector<Spread>(),
                           std::vector<Rate>(), std::vector<Rate>(),
                           false,
                           100.0, Date(30,November,2004));

    shared_ptr<PricingEngine> bondEngine(
                                     new DiscountingBondEngine(riskFreeRate));
    bond1.setPricingEngine(bondEngine);

    setCouponPricer(bond1.cashflows(),pricer);

    #if defined(QL_USE_INDEXED_COUPON)
    Real cachedPrice1 = 99.874645;
    #else
    Real cachedPrice1 = 99.874646;
    #endif


    Real price = bond1.cleanPrice();
    if (std::fabs(price-cachedPrice1) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice1 << "\n"
                   << "    error:      " << price-cachedPrice1);
    }

    // different risk-free and discount curve

    FloatingRateBond bond2(settlementDays, vars.faceAmount, sch,
                           index, ActualActual(ActualActual::ISMA),
                           ModifiedFollowing, fixingDays,
                           std::vector<Rate>(), std::vector<Spread>(),
                           std::vector<Rate>(), std::vector<Rate>(),
                           false,
                           100.0, Date(30,November,2004));

    shared_ptr<PricingEngine> bondEngine2(
                                    new DiscountingBondEngine(discountCurve));
    bond2.setPricingEngine(bondEngine2);

    setCouponPricer(bond2.cashflows(),pricer);

    #if defined(QL_USE_INDEXED_COUPON)
    Real cachedPrice2 = 97.955904;
    #else
    Real cachedPrice2 = 97.955904;
    #endif

    price = bond2.cleanPrice();
    if (std::fabs(price-cachedPrice2) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice2 << "\n"
                   << "    error:      " << price-cachedPrice2);
    }

    // varying spread

    std::vector<Rate> spreads(4);
    spreads[0] = 0.001;
    spreads[1] = 0.0012;
    spreads[2] = 0.0014;
    spreads[3] = 0.0016;

    FloatingRateBond bond3(settlementDays, vars.faceAmount, sch,
                           index, ActualActual(ActualActual::ISMA),
                           ModifiedFollowing, fixingDays,
                           std::vector<Real>(), spreads,
                           std::vector<Rate>(), std::vector<Rate>(),
                           false,
                           100.0, Date(30,November,2004));

    bond3.setPricingEngine(bondEngine2);

    setCouponPricer(bond3.cashflows(),pricer);

    #if defined(QL_USE_INDEXED_COUPON)
    Real cachedPrice3 = 98.495458;
    #else
    Real cachedPrice3 = 98.495459;
    #endif

    price = bond3.cleanPrice();
    if (std::fabs(price-cachedPrice3) > tolerance) {
        BOOST_FAIL("failed to reproduce cached price:\n"
                   << QL_FIXED
                   << "    calculated: " << price << "\n"
                   << "    expected:   " << cachedPrice3 << "\n"
                   << "    error:      " << price-cachedPrice3);
    }
}

void BondTest::testBrazilianCached() {

    BOOST_TEST_MESSAGE(
        "Testing Brazilian public bond prices against Andima cached values...");

    CommonVars vars;

    Natural settlementDays = 1;
    Real faceAmount = 1000.0;
    Real redemption = 100.0;
    Date today(6,June,2007);
    Date issueDate(1,January,2007);

    // The tolerance is high because Andima truncate yields
    Real tolerance = 1.0e-4;

    // Reset evaluation date
    Settings::instance().evaluationDate() = today;

    // NTN-F maturity dates
    std::vector<Date> maturityDates(6);
    maturityDates[0] = Date(1,January,2008);
    maturityDates[1] = Date(1,January,2010);
    maturityDates[2] = Date(1,July,2010);
    maturityDates[3] = Date(1,January,2012);
    maturityDates[4] = Date(1,January,2014);
    maturityDates[5] = Date(1,January,2017);

    // Andima NTN-F yields
    std::vector<Rate> yields(6);
    yields[0] = 0.114614;
    yields[1] = 0.105726;
    yields[2] = 0.105328;
    yields[3] = 0.104283;
    yields[4] = 0.103218;
    yields[5] = 0.102948;

    // Andima NTN-F prices
    std::vector<Rate> prices(6);
    prices[0] = 1034.63031372;
    prices[1] = 1030.09919487;
    prices[2] = 1029.98307160;
    prices[3] = 1028.13585068;
    prices[4] = 1028.33383817;
    prices[5] = 1026.19716497;

    std::vector<InterestRate> couponRates(1);
    couponRates[0] = InterestRate(0.1, Thirty360(), Compounded,Annual);

    for (Size bondIndex = 0; bondIndex < maturityDates.size(); bondIndex++) {

        InterestRate yield(yields[bondIndex],
                           Business252(Brazil()),
                           Compounded, Annual);

        Schedule schedule(Date(1,January,2007),
                          maturityDates[bondIndex], Period(Semiannual),
                          Brazil(Brazil::Settlement),
                          Unadjusted, Unadjusted,
                          DateGeneration::Backward, false);

        FixedRateBond bond(settlementDays,
            faceAmount,
            schedule,
            couponRates,
            Following,
            redemption,
            issueDate);

        Real cachedPrice = prices[bondIndex];
        Real price = faceAmount *
            (BondFunctions::cleanPrice(bond, yield.rate(), yield.dayCounter(),
                                 yield.compounding(), yield.frequency(),
                                 today) + bond.accruedAmount(today)) / 100.0;

        if (std::fabs(price-cachedPrice) > tolerance) {
            BOOST_ERROR("failed to reproduce Andima cached price:\n"
                        << QL_FIXED
                        << "    calculated: " << price << "\n"
                        << "    expected:   " << cachedPrice << "\n"
                        << "    error:      " << price-cachedPrice  << "\n"
                        );
        }
    }
}

void BondTest::testExCouponGilt() {
    BOOST_TEST_MESSAGE(
        "Testing ex-coupon UK Gilt price against market values...");
    /* UK Gilts have an exCouponDate 7 business days before the coupon
       is due (see <http://www.dmo.gov.uk/index.aspx?page=Gilts/Gilt_Faq>).
       On the exCouponDate the bond still trades cum-coupon so we use
       6 days below and UK calendar

       Output verified with Bloomberg:

       ISIN: GB0009997999
       Issue Date: February 29th, 1996
       Interest Accrue: February 29th, 1996
       First Coupon: June 7th, 1996
       Maturity: June 7th, 2021
       coupon: 8
       period: 6M

       Settlement date: May 29th, 2013
       Test Price : 103
       Accrued : 38021.97802
       NPV : 106.8021978
       Yield : 7.495180593
       Yield->NPV : 106.8021978
       Yield->NPV->Price : 103
       Mod duration : 5.676044458
       Convexity : 0.4215314859
       PV 0.01 : 0.0606214023

       Settlement date: May 30th, 2013
       Test Price : 103
       Accrued : -1758.241758
       NPV : 102.8241758
       Yield : 7.496183543
       Yield->NPV : 102.8241758
       Yield->NPV->Price : 103
       Mod duration : 5.892816328
       Convexity : 0.4375621862
       PV 0.01 : 0.06059239822

       Settlement date: May 31st, 2013
       Test Price : 103
       Accrued : -1538.461538
       NPV : 102.8461538
       Yield : 7.495987492
       Yield->NPV : 102.8461539
       Yield->NPV->Price : 103
       Mod duration : 5.890186028
       Convexity : 0.4372394381
       PV 0.01 : 0.06057829784
    */
    struct test_case {
        Date settlementDate;
        Real testPrice;
        Real accruedAmount;
        Real NPV;
        Rate yield;
        Real duration;
        Real convexity;
    };

    Calendar calendar = UnitedKingdom();

    Natural settlementDays = 3;

    Date issueDate(29, February, 1996);
    Date startDate(29, February, 1996);
    Date firstCouponDate(07, June, 1996);
    Date maturityDate(07, June, 2021);

    Rate coupon = 0.08;

    Period tenor = 6*Months;
    Period exCouponPeriod = 6*Days;

    Compounding comp = Compounded;
    Frequency freq   = Semiannual;
    DayCounter dc = ActualActual(ActualActual::ISMA);

    FixedRateBond bond(settlementDays, 100.0,
                       Schedule(startDate, maturityDate, tenor,
                                NullCalendar(), Unadjusted, Unadjusted,
                                DateGeneration::Forward, true, firstCouponDate),
                       std::vector<Rate>(1, coupon),
                       dc, Unadjusted, 100.0,
                       issueDate, calendar, exCouponPeriod, calendar);

    const Leg& leg = bond.cashflows();

    test_case cases[] = {
        { Date(29,May,2013), 103.0,
          3.8021978, 106.8021978, 0.0749518,
          5.6760445, 42.1531486 },
        { Date(30,May,2013), 103.0,
          -0.1758242, 102.8241758, 0.0749618,
          5.8928163, 43.7562186 },
        { Date(31,May,2013), 103.0,
          -0.1538462, 102.8461538, 0.0749599,
          5.8901860, 43.7239438 }
    };

    for (Size i=0; i<LENGTH(cases); ++i) {
        Real accrued = bond.accruedAmount(cases[i].settlementDate);
        ASSERT_CLOSE("accrued amount", cases[i].settlementDate,
                     accrued, cases[i].accruedAmount, 1e-6);
        
        Real npv = cases[i].testPrice + accrued;
        ASSERT_CLOSE("NPV", cases[i].settlementDate,
                     npv, cases[i].NPV, 1e-6);

        Rate yield = CashFlows::yield(leg, npv, dc, comp, freq,
                                      false, cases[i].settlementDate);
        ASSERT_CLOSE("yield", cases[i].settlementDate,
                     yield, cases[i].yield, 1e-6);

        Time duration = CashFlows::duration(leg, yield, dc, comp, freq,
                                            Duration::Modified, false,
                                            cases[i].settlementDate);
        ASSERT_CLOSE("duration", cases[i].settlementDate,
                     duration, cases[i].duration, 1e-6);

        Real convexity = CashFlows::convexity(leg, yield, dc, comp, freq,
                                              false, cases[i].settlementDate);
        ASSERT_CLOSE("convexity", cases[i].settlementDate,
                     convexity, cases[i].convexity, 1e-6);

        Real calcnpv = CashFlows::npv(leg, yield, dc, comp, freq,
                                      false, cases[i].settlementDate);
        ASSERT_CLOSE("NPV from yield", cases[i].settlementDate,
                     calcnpv, cases[i].NPV, 1e-6);
        
        Real calcprice = calcnpv - accrued;
        ASSERT_CLOSE("price from yield", cases[i].settlementDate,
                     calcprice, cases[i].testPrice, 1e-6);
    }
}


void BondTest::testExCouponAustralianBond() {
    BOOST_TEST_MESSAGE(
        "Testing ex-coupon Australian bond price against market values...");
    /* Australian Government Bonds have an exCouponDate 7 calendar
       days before the coupon is due.  On the exCouponDate the bond
       trades ex-coupon so we use 7 days below and NullCalendar.
       AGB accrued interest is rounded to 3dp.

       Output verified with Bloomberg:

       ISIN: AU300TB01208
       Issue Date: June 10th, 2004
       Interest Accrue: February 15th, 2004
       First Coupon: August 15th, 2004
       Maturity: February 15th, 2017
       coupon: 6
       period: 6M

       Settlement date: August 7th, 2014
       Test Price : 103
       Accrued : 28670
       NPV : 105.867
       Yield : 4.723814867
       Yield->NPV : 105.867
       Yield->NPV->Price : 103
       Mod duration : 2.262763296
       Convexity : 0.0654870275
       PV 0.01 : 0.02395519619

       Settlement date: August 8th, 2014
       Test Price : 103
       Accrued : -1160
       NPV : 102.884
       Yield : 4.72354833
       Yield->NPV : 102.884
       Yield->NPV->Price : 103
       Mod duration : 2.325360055
       Convexity : 0.06725307785
       PV 0.01 : 0.02392423439

       Settlement date: August 11th, 2014
       Test Price : 103
       Accrued : -660
       NPV : 102.934
       Yield : 4.719277687
       Yield->NPV : 102.934
       Yield->NPV->Price : 103
       Mod duration : 2.317320093
       Convexity : 0.06684074058
       PV 0.01 : 0.02385310264
    */
    struct test_case {
        Date settlementDate;
        Real testPrice;
        Real accruedAmount;
        Real NPV;
        Rate yield;
        Real duration;
        Real convexity;
    };

    Calendar calendar = Australia();

    Natural settlementDays = 3;

    Date issueDate(10, June, 2004);
    Date startDate(15, February, 2004);
    Date firstCouponDate(15, August, 2004);
    Date maturityDate(15, February, 2017);

    Rate coupon = 0.06;

    Period tenor = 6*Months;
    Period exCouponPeriod = 7*Days;

    Compounding comp = Compounded;
    Frequency freq   = Semiannual;
    DayCounter dc = ActualActual(ActualActual::ISMA);

    FixedRateBond bond(settlementDays, 100.0,
                       Schedule(startDate, maturityDate, tenor,
                                NullCalendar(), Unadjusted, Unadjusted,
                                DateGeneration::Forward, true, firstCouponDate),
                       std::vector<Rate>(1, coupon),
                       dc, Unadjusted, 100.0,
                       issueDate, calendar, exCouponPeriod, NullCalendar());

    const Leg& leg = bond.cashflows();

    test_case cases[] = {
        { Date(7,August,2014), 103.0,
          2.8670, 105.867, 0.04723,
          2.26276, 6.54870 },
        { Date(8,August,2014), 103.0,
          -0.1160, 102.884, 0.047235,
          2.32536, 6.72531 },
        { Date(11,August,2014), 103.0,
          -0.0660, 102.934, 0.04719,
          2.31732, 6.68407 }
    };

    for (Size i=0; i<LENGTH(cases); ++i) {
        Real accrued = bond.accruedAmount(cases[i].settlementDate);
        ASSERT_CLOSE("accrued amount", cases[i].settlementDate,
                     accrued, cases[i].accruedAmount, 1e-3);
        
        Real npv = cases[i].testPrice + accrued;
        ASSERT_CLOSE("NPV", cases[i].settlementDate,
                     npv, cases[i].NPV, 1e-3);

        Rate yield = CashFlows::yield(leg, npv, dc, comp, freq,
                                      false, cases[i].settlementDate);
        ASSERT_CLOSE("yield", cases[i].settlementDate,
                     yield, cases[i].yield, 1e-5);

        Time duration = CashFlows::duration(leg, yield, dc, comp, freq,
                                            Duration::Modified, false,
                                            cases[i].settlementDate);
        ASSERT_CLOSE("duration", cases[i].settlementDate,
                     duration, cases[i].duration, 1e-5);

        Real convexity = CashFlows::convexity(leg, yield, dc, comp, freq,
                                              false, cases[i].settlementDate);
        ASSERT_CLOSE("convexity", cases[i].settlementDate,
                     convexity, cases[i].convexity, 1e-4);

        Real calcnpv = CashFlows::npv(leg, yield, dc, comp, freq,
                                      false, cases[i].settlementDate);
        ASSERT_CLOSE("NPV from yield", cases[i].settlementDate,
                     calcnpv, cases[i].NPV, 1e-3);
        
        Real calcprice = calcnpv - accrued;
        ASSERT_CLOSE("price from yield", cases[i].settlementDate,
                     calcprice, cases[i].testPrice, 1e-3);
    }
}

/// <summary>
/// Test calculation of South African R2048 bond
/// This requires the use of the Schedule to be constructed
/// with a custom date vector
/// </summary>
void BondTest::testBondFromScheduleWithDateVector()
{
    BOOST_TEST_MESSAGE("Testing South African R2048 bond price using Schedule constructor with Date vector...");
    SavedSettings backup;

    //When pricing bond from Yield To Maturity, use NullCalendar()
    Calendar calendar = NullCalendar();

    Natural settlementDays = 3;

    Date issueDate(29, June, 2012);
    Date today(7, September, 2015);
    Date evaluationDate = calendar.adjust(today);
    Date settlementDate = calendar.advance(evaluationDate, settlementDays * Days);
    Settings::instance().evaluationDate() = evaluationDate;

    // For the schedule to generate correctly for Feb-28's, make maturity date on Feb 29
    Date maturityDate(29, February, 2048);

    Rate coupon = 0.0875;
    Compounding comp = Compounded;
    Frequency freq = Semiannual;
    DayCounter dc = ActualActual(ActualActual::Bond);

    // Yield as quoted in market
    InterestRate yield(0.09185, dc, comp, freq);
    
    Period tenor = 6 * Months;
    Period exCouponPeriod = 10 * Days;

    // Generate coupon dates for 31 Aug and end of Feb each year
    // For leap years, this will generate 29 Feb, but the bond
    // actually pays coupons on 28 Feb, regardsless of whether
    // it is a leap year or not. 
    Schedule schedule(issueDate, maturityDate, tenor,
        NullCalendar(), Unadjusted, Unadjusted,
        DateGeneration::Backward, true);

    // Adjust the 29 Feb's to 28 Feb
    std::vector<Date> dates;
    for (Size i = 0; i < schedule.size(); ++i) {
        Date d = schedule.date(i);
        if (d.month() == February && d.dayOfMonth() == 29)
            dates.push_back(Date(28, February, d.year()));
        else
            dates.push_back(d);
    }

    schedule = Schedule(dates, 
                        schedule.calendar(),
                        schedule.businessDayConvention(),
                        schedule.terminationDateBusinessDayConvention(),
                        schedule.tenor(),
                        schedule.rule(),
                        schedule.endOfMonth(),
                        schedule.isRegular());

    FixedRateBond bond(
        0, 
        100.0,
        schedule,
        std::vector<Rate>(1, coupon),
        dc, Following, 100.0,
        issueDate, calendar, 
        exCouponPeriod, calendar, Unadjusted, false);

    Real calculatedPrice = BondFunctions::dirtyPrice(bond, yield, settlementDate);
    Real expectedPrice = 95.75706;
    Real tolerance = 1e-5;
    if (std::fabs(calculatedPrice - expectedPrice) > tolerance) {
        BOOST_FAIL("failed to reproduce R2048 dirty price"
            << QL_FIXED << std::setprecision(5)
            << "\n  expected:   " << expectedPrice
            << "\n  calculated: " << calculatedPrice);
    }
}


test_suite* BondTest::suite() {
    test_suite* suite = BOOST_TEST_SUITE("Bond tests");

    suite->add(QUANTLIB_TEST_CASE(&BondTest::testYield));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testAtmRate));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testZspread));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testTheoretical));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testCached));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testCachedZero));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testCachedFixed));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testCachedFloating));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testBrazilianCached));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testExCouponGilt));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testExCouponAustralianBond));
    suite->add(QUANTLIB_TEST_CASE(&BondTest::testBondFromScheduleWithDateVector));
    return suite;
}



<|start_filename|>ql/methods/finitedifferences/stepconditions/fdmstepconditioncomposite.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/


#include <ql/exercise.hpp>
#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
#include <ql/methods/finitedifferences/utilities/fdmdividendhandler.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmsnapshotcondition.hpp>
#include <ql/methods/finitedifferences/utilities/fdminnervaluecalculator.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmstepconditioncomposite.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmamericanstepcondition.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmbermudanstepcondition.hpp>

#include <set>

namespace QuantLib {

    FdmStepConditionComposite::FdmStepConditionComposite(
        const std::list<std::vector<Time> > & stoppingTimes,
        const Conditions & conditions)
    : conditions_(conditions) {

        std::set<Real> allStoppingTimes;
        for (std::list<std::vector<Time> >::const_iterator
             iter = stoppingTimes.begin(); iter != stoppingTimes.end();
             ++iter) {
            allStoppingTimes.insert(iter->begin(), iter->end());
        }
        stoppingTimes_ = std::vector<Time>(allStoppingTimes.begin(),
                                           allStoppingTimes.end());
    }

    const FdmStepConditionComposite::Conditions&
    FdmStepConditionComposite::conditions() const {
        return conditions_;
    }

    const std::vector<Time>& FdmStepConditionComposite::stoppingTimes() const {
        return stoppingTimes_;
    }

    void FdmStepConditionComposite::applyTo(Array& a, Time t) const {
        for (Conditions::const_iterator iter = conditions_.begin();
             iter != conditions_.end(); ++iter) {
            (*iter)->applyTo(a, t);
        }
    }
    
    boost::shared_ptr<FdmStepConditionComposite> 
    FdmStepConditionComposite::joinConditions(
                const boost::shared_ptr<FdmSnapshotCondition>& c1,
                const boost::shared_ptr<FdmStepConditionComposite>& c2) {

        std::list<std::vector<Time> > stoppingTimes;
        stoppingTimes.push_back(c2->stoppingTimes());
        stoppingTimes.push_back(std::vector<Time>(1, c1->getTime()));

        FdmStepConditionComposite::Conditions conditions;
        conditions.push_back(c2);
        conditions.push_back(c1);

        return boost::shared_ptr<FdmStepConditionComposite>(
            new FdmStepConditionComposite(stoppingTimes, conditions));
    }

    boost::shared_ptr<FdmStepConditionComposite> 
    FdmStepConditionComposite::vanillaComposite(
                 const DividendSchedule& cashFlow,
                 const boost::shared_ptr<Exercise>& exercise,
                 const boost::shared_ptr<FdmMesher>& mesher,
                 const boost::shared_ptr<FdmInnerValueCalculator>& calculator,
                 const Date& refDate,
                 const DayCounter& dayCounter) {
        
        std::list<std::vector<Time> > stoppingTimes;
        std::list<boost::shared_ptr<StepCondition<Array> > > stepConditions;

        if(!cashFlow.empty()) {
            boost::shared_ptr<FdmDividendHandler> dividendCondition(
                new FdmDividendHandler(cashFlow, mesher,
                                       refDate, dayCounter, 0));
            stepConditions.push_back(dividendCondition);
            stoppingTimes.push_back(dividendCondition->dividendTimes());
        }

        QL_REQUIRE(   exercise->type() == Exercise::American
                   || exercise->type() == Exercise::European
                   || exercise->type() == Exercise::Bermudan,
                   "exercise type is not supported");
        if (exercise->type() == Exercise::American) {
            stepConditions.push_back(boost::shared_ptr<StepCondition<Array> >(
                          new FdmAmericanStepCondition(mesher,calculator)));
        }
        else if (exercise->type() == Exercise::Bermudan) {
            boost::shared_ptr<FdmBermudanStepCondition> bermudanCondition(
                new FdmBermudanStepCondition(exercise->dates(),
                                             refDate, dayCounter,
                                             mesher, calculator));
            stepConditions.push_back(bermudanCondition);
            stoppingTimes.push_back(bermudanCondition->exerciseTimes());
        }
        
        return boost::shared_ptr<FdmStepConditionComposite>(
            new FdmStepConditionComposite(stoppingTimes, stepConditions));

    }

}


<|start_filename|>ql/models/marketmodels/pathwiseaccountingengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*

 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/


#ifndef quantlib_pathwise_accounting_engine_hpp
#define quantlib_pathwise_accounting_engine_hpp

#include <ql/models/marketmodels/pathwisemultiproduct.hpp>
#include <ql/models/marketmodels/pathwisediscounter.hpp>
#include <ql/math/statistics/sequencestatistics.hpp>
#include <ql/models/marketmodels/pathwisegreeks/ratepseudorootjacobian.hpp>

#include <ql/utilities/clone.hpp>
#include <ql/types.hpp>
#include <vector>

namespace QuantLib {

    class LogNormalFwdRateEuler;
    class MarketModel;


    //! Engine collecting cash flows along a market-model simulation for doing pathwise computation of Deltas
    // using Giles--Glasserman smoking adjoints method
    // note only works with displaced LMM, and requires knowledge of pseudo-roots and displacements 
    // This is tested in MarketModelTest::testPathwiseGreeks
    class PathwiseAccountingEngine 
    {
      public:
        PathwiseAccountingEngine(const boost::shared_ptr<LogNormalFwdRateEuler>& evolver, // method relies heavily on LMM Euler
                         const Clone<MarketModelPathwiseMultiProduct>& product,
                         const boost::shared_ptr<MarketModel>& pseudoRootStructure, // we need pseudo-roots and displacements
                         Real initialNumeraireValue);

        void multiplePathValues(SequenceStatisticsInc& stats,
                                Size numberOfPaths);
      private:
          Real singlePathValues(std::vector<Real>& values);

        boost::shared_ptr<LogNormalFwdRateEuler> evolver_;
        Clone<MarketModelPathwiseMultiProduct> product_;
        boost::shared_ptr<MarketModel> pseudoRootStructure_;

        Real initialNumeraireValue_;
        Size numberProducts_;
        Size numberRates_;
        Size numberCashFlowTimes_;
        Size numberSteps_;

        std::vector<Real> currentForwards_, lastForwards_;

        bool doDeflation_;


        // workspace
        std::vector<Real> numerairesHeld_;
        std::vector<Size> numberCashFlowsThisStep_;
        std::vector<std::vector<MarketModelPathwiseMultiProduct::CashFlow> >
                                                         cashFlowsGenerated_;
        std::vector<MarketModelPathwiseDiscounter> discounters_;

        std::vector<Matrix> V_;  // one V for each product, with components for each time step and rate

   //     std::vector<std::vector<std::vector<Real> > > V_; // one V for each product, with components for each time step and rate

        Matrix LIBORRatios_; // dimensions are step and rate number
        Matrix Discounts_; // dimensions are step and rate number, goes from 0 to n. P(t_0, t_j)

        Matrix StepsDiscountsSquared_; // dimensions are step and rate number

        Matrix LIBORRates_; // dimensions are step and rate number
        Matrix partials_; // dimensions are factor and rate

        std::vector<Real> deflatorAndDerivatives_;
        
        std::vector<std::vector<Size> > numberCashFlowsThisIndex_;
        std::vector<Matrix> totalCashFlowsThisIndex_; // need product cross times cross which sensitivity

        std::vector<std::vector<Size> > cashFlowIndicesThisStep_;

    };


   //! Engine collecting cash flows along a market-model simulation for doing pathwise computation of Deltas and vegas
    // using Giles--Glasserman smoking adjoints method
    // note only works with displaced LMM, 
    // 
    // The method is intimately connected with log-normal Euler evolution 
    // 
    // We must work with discretely compounding MM account
    // To compute a vega means changing the pseudo-square root at each time step
    // So for each vega, we have a vector of matrices. So we need a vector of vectors of matrices to compute all the vegas.
    // We do the outermost vector by time step and inner one by which vega.
    // This is tested in MarketModelTest::testPathwiseVegas

    class PathwiseVegasAccountingEngine 
    {
      public:
        PathwiseVegasAccountingEngine(const boost::shared_ptr<LogNormalFwdRateEuler>& evolver, // method relies heavily on LMM Euler
                         const Clone<MarketModelPathwiseMultiProduct>& product,
                         const boost::shared_ptr<MarketModel>& pseudoRootStructure, // we need pseudo-roots and displacements
                         const std::vector<std::vector<Matrix> >& VegaBumps, 
                         Real initialNumeraireValue);

        void multiplePathValues(std::vector<Real>& means,
                                std::vector<Real>& errors,
                                Size numberOfPaths);
      private:
          Real singlePathValues(std::vector<Real>& values);

        boost::shared_ptr<LogNormalFwdRateEuler> evolver_;
        Clone<MarketModelPathwiseMultiProduct> product_;
        boost::shared_ptr<MarketModel> pseudoRootStructure_;
        std::vector<Size> numeraires_;

        Real initialNumeraireValue_;
        Size numberProducts_;
        Size numberRates_;
        Size numberCashFlowTimes_;
        Size numberSteps_;
        Size numberBumps_;

        std::vector<RatePseudoRootJacobian> jacobianComputers_;

        
        bool doDeflation_;


        // workspace
        std::vector<Real> currentForwards_, lastForwards_;
        std::vector<Real> numerairesHeld_;
        std::vector<Size> numberCashFlowsThisStep_;
        std::vector<std::vector<MarketModelPathwiseMultiProduct::CashFlow> >
                                                         cashFlowsGenerated_;
        std::vector<MarketModelPathwiseDiscounter> discounters_;

        std::vector<Matrix> V_;  // one V for each product, with components for each time step and rate

        Matrix LIBORRatios_; // dimensions are step and rate number
        Matrix Discounts_; // dimensions are step and rate number, goes from 0 to n. P(t_0, t_j)

        Matrix StepsDiscountsSquared_; // dimensions are step and rate number
        std::vector<Real> stepsDiscounts_;

        Matrix LIBORRates_; // dimensions are step and rate number
        Matrix partials_; // dimensions are factor and rate

        Matrix vegasThisPath_; // dimensions are product and which vega
        std::vector<Matrix> jacobiansThisPaths_; // dimensions are step, rate and factor

        std::vector<Real> deflatorAndDerivatives_;
        std::vector<Real> fullDerivatives_;
        
        std::vector<std::vector<Size> > numberCashFlowsThisIndex_;
        std::vector<Matrix> totalCashFlowsThisIndex_; // need product cross times cross which sensitivity

        std::vector<std::vector<Size> > cashFlowIndicesThisStep_;

    };

   //! Engine collecting cash flows along a market-model simulation for doing pathwise computation of Deltas and vegas
    // using Giles--Glasserman smoking adjoints method
    // note only works with displaced LMM, 
    // 
    // The method is intimately connected with log-normal Euler evolution 
    // 
    // We must work with discretely compounding MM account
    // To compute a vega means changing the pseudo-square root at each time step
    // So for each vega, we have a vector of matrices. So we need a vector of vectors of matrices to compute all the vegas.
    // We do the outermost vector by time step and inner one by which vega.
    // This implementation is different in that all the linear combinations by the bumps are done as late as possible,
    // whereas PathwiseVegasAccountingEngine does them as early as possible. 
    // This is tested in MarketModelTest::testPathwiseVegas

    class PathwiseVegasOuterAccountingEngine 
    {
      public:
        PathwiseVegasOuterAccountingEngine(const boost::shared_ptr<LogNormalFwdRateEuler>& evolver, // method relies heavily on LMM Euler
                         const Clone<MarketModelPathwiseMultiProduct>& product,
                         const boost::shared_ptr<MarketModel>& pseudoRootStructure, // we need pseudo-roots and displacements
                         const std::vector<std::vector<Matrix> >& VegaBumps, 
                         Real initialNumeraireValue);

        //! Use to get vegas with respect to VegaBumps
        void multiplePathValues(std::vector<Real>& means,
                                std::vector<Real>& errors,
                                Size numberOfPaths);

        //! Use to get vegas with respect to pseudo-root-elements
        void multiplePathValuesElementary(std::vector<Real>& means,
                                std::vector<Real>& errors,
                                Size numberOfPaths);

      private:
          Real singlePathValues(std::vector<Real>& values);

        boost::shared_ptr<LogNormalFwdRateEuler> evolver_;
        Clone<MarketModelPathwiseMultiProduct> product_;
        boost::shared_ptr<MarketModel> pseudoRootStructure_;
        std::vector<std::vector<Matrix> > vegaBumps_; 
        std::vector<Size> numeraires_;

        Real initialNumeraireValue_;
        Size numberProducts_;
        Size numberRates_;
        Size numberCashFlowTimes_;
        Size numberSteps_;
        Size factors_;
        Size numberBumps_;
        Size numberElementaryVegas_;

        std::vector<RatePseudoRootJacobianAllElements> jacobianComputers_;

        
        bool doDeflation_;


        // workspace
        std::vector<Real> currentForwards_, lastForwards_;
        std::vector<Real> numerairesHeld_;
        std::vector<Size> numberCashFlowsThisStep_;
        std::vector<std::vector<MarketModelPathwiseMultiProduct::CashFlow> >
                                                         cashFlowsGenerated_;
        std::vector<MarketModelPathwiseDiscounter> discounters_;

        std::vector<Matrix> V_;  // one V for each product, with components for each time step and rate

        Matrix LIBORRatios_; // dimensions are step and rate number
        Matrix Discounts_; // dimensions are step and rate number, goes from 0 to n. P(t_0, t_j)

        Matrix StepsDiscountsSquared_; // dimensions are step and rate number
        std::vector<Real> stepsDiscounts_;

        Matrix LIBORRates_; // dimensions are step and rate number
        Matrix partials_; // dimensions are factor and rate

        std::vector<std::vector<Matrix>   > elementary_vegas_ThisPath_;  // dimensions are product, step,  rate and factor
        std::vector<std::vector<Matrix> > jacobiansThisPaths_;                      // dimensions are step, rate, rate and factor

        std::vector<Real> deflatorAndDerivatives_;
        std::vector<Real> fullDerivatives_;
        
        std::vector<std::vector<Size> > numberCashFlowsThisIndex_;
        std::vector<Matrix> totalCashFlowsThisIndex_; // need product cross times cross which sensitivity

        std::vector<std::vector<Size> > cashFlowIndicesThisStep_;
/*
        // experimental

        std::vector<std::vector<Real> > gaussians_;
        int distinguishedFactor_;
        int distinguishedRate_;
        int  distinguishedStep_;

*/
    };

}

#endif


<|start_filename|>ql/experimental/barrieroption/binomialdoublebarrierengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file binomialdoublebarrierengine.hpp
    \brief Binomial Double Barrier option engine
*/

#ifndef quantlib_binomial_double_barrier_engine_hpp
#define quantlib_binomial_double_barrier_engine_hpp

#include <ql/methods/lattices/binomialtree.hpp>
#include <ql/methods/lattices/bsmlattice.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/experimental/barrieroption/discretizeddoublebarrieroption.hpp>
#include <ql/processes/blackscholesprocess.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>

namespace QuantLib {

    //! Pricing engine for double barrier options using binomial trees
    /*! \ingroup barrierengines

        \note This engine requires a the discretized option classes. 
        By default uses a standard binomial implementation, but it can
        also work with DiscretizedDermanKaniDoubleBarrierOption to
        implement a Derman-Kani optimization.

        \test the correctness of the returned values is tested by
              checking it against analytic results.
    */
    template <class T, class D = DiscretizedDoubleBarrierOption>
    class BinomialDoubleBarrierEngine : public DoubleBarrierOption::engine {
      public:
        BinomialDoubleBarrierEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             Size timeSteps)
        : process_(process), timeSteps_(timeSteps) {
            QL_REQUIRE(timeSteps>0,
                       "timeSteps must be positive, " << timeSteps <<
                       " not allowed");
            registerWith(process_);
        }
        void calculate() const;
      private:
        boost::shared_ptr<GeneralizedBlackScholesProcess> process_;
        Size timeSteps_;
    };


    // template definitions

    template <class T, class D>
    void BinomialDoubleBarrierEngine<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));

        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_));
        
        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();

        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];
    }

}


#endif


<|start_filename|>test-suite/doublebinaryoption.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include "doublebinaryoption.hpp"
#include "utilities.hpp"
#include <ql/time/calendars/nullcalendar.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/experimental/barrieroption/doublebarrieroption.hpp>
#include <ql/experimental/barrieroption/analyticdoublebarrierbinaryengine.hpp>
#include <ql/experimental/barrieroption/binomialdoublebarrierengine.hpp>
#include <ql/utilities/dataformatters.hpp>

using namespace QuantLib;
using namespace boost::unit_test_framework;

#define REPORT_FAILURE(greekName, payoff, exercise, barrierType, barrier_lo, \
                        barrier_hi, s, q, r, today, v, expected, calculated, \
                        error, tolerance) \
    BOOST_ERROR(payoff->optionType() << " option with " \
               << barrierType << " barrier type:\n" \
               << "    barrier_lo:       " << barrier_lo << "\n" \
               << "    barrier_hi:       " << barrier_hi << "\n" \
               << payoffTypeToString(payoff) << " payoff:\n" \
               << "    spot value:       " << s << "\n" \
               << "    strike:           " << payoff->strike() << "\n" \
               << "    dividend yield:   " << io::rate(q) << "\n" \
               << "    risk-free rate:   " << io::rate(r) << "\n" \
               << "    reference date:   " << today << "\n" \
               << "    maturity:         " << exercise->lastDate() << "\n" \
               << "    volatility:       " << io::volatility(v) << "\n\n" \
               << "    expected   " << greekName << ": " << expected << "\n" \
               << "    calculated " << greekName << ": " << calculated << "\n"\
               << "    error:            " << error << "\n" \
               << "    tolerance:        " << tolerance << "\n");

namespace {

    struct DoubleBinaryOptionData {
        DoubleBarrier::Type barrierType;
        Real barrier_lo;
        Real barrier_hi;
        Real cash;     // cash payoff for cash-or-nothing
        Real s;        // spot
        Rate q;        // dividend
        Rate r;        // risk-free rate
        Time t;        // time to maturity
        Volatility v;  // volatility
        Real result;   // expected result
        Real tol;      // tolerance
    };
}


void DoubleBinaryOptionTest::testHaugValues() {

    BOOST_TEST_MESSAGE("Testing cash-or-nothing double barrier options against Haug's values...");

    DoubleBinaryOptionData values[] = {
        /* The data below are from
          "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 181
          Note: book uses cost of carry b, instead of dividend rate q
        */
        //    barrierType,          bar_lo, bar_hi,  cash,   spot,    q,    r,    t,  vol,   value, tol
        { DoubleBarrier::KnockOut,   80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  9.8716, 1e-4 },
        { DoubleBarrier::KnockOut,   80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  8.9307, 1e-4 },
        { DoubleBarrier::KnockOut,   80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  6.3272, 1e-4 },
        { DoubleBarrier::KnockOut,   80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  1.9094, 1e-4 },

        { DoubleBarrier::KnockOut,   85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  9.7961, 1e-4 },
        { DoubleBarrier::KnockOut,   85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  7.2300, 1e-4 },
        { DoubleBarrier::KnockOut,   85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  3.7100, 1e-4 },
        { DoubleBarrier::KnockOut,   85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  0.4271, 1e-4 },

        { DoubleBarrier::KnockOut,   90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  8.9054, 1e-4 },
        { DoubleBarrier::KnockOut,   90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  3.6752, 1e-4 },
        { DoubleBarrier::KnockOut,   90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  0.7960, 1e-4 },
        { DoubleBarrier::KnockOut,   90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  0.0059, 1e-4 },

        { DoubleBarrier::KnockOut,   95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  3.6323, 1e-4 },
        { DoubleBarrier::KnockOut,   95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.0911, 1e-4 },
        { DoubleBarrier::KnockOut,   95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  0.0002, 1e-4 },
        { DoubleBarrier::KnockOut,   95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  0.0000, 1e-4 },

        { DoubleBarrier::KIKO,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4 },
        { DoubleBarrier::KIKO,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.2402, 1e-4 },
        { DoubleBarrier::KIKO,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  1.4076, 1e-4 },
        { DoubleBarrier::KIKO,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  3.8160, 1e-4 },

        { DoubleBarrier::KIKO,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0075, 1e-4 },
        { DoubleBarrier::KIKO,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.9910, 1e-4 },
        { DoubleBarrier::KIKO,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  2.8098, 1e-4 },
        { DoubleBarrier::KIKO,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.6612, 1e-4 },

        { DoubleBarrier::KIKO,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.2656, 1e-4 },
        { DoubleBarrier::KIKO,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  2.7954, 1e-4 },
        { DoubleBarrier::KIKO,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  4.4024, 1e-4 },
        { DoubleBarrier::KIKO,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.9266, 1e-4 },

        { DoubleBarrier::KIKO,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  2.6285, 1e-4 },
        { DoubleBarrier::KIKO,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  4.7523, 1e-4 },
        { DoubleBarrier::KIKO,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  4.9096, 1e-4 },
        { DoubleBarrier::KIKO,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.9675, 1e-4 },

        // following values calculated with haug's VBA code
        { DoubleBarrier::KnockIn,    80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0042, 1e-4 },
        { DoubleBarrier::KnockIn,    80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.9450, 1e-4 },
        { DoubleBarrier::KnockIn,    80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  3.5486, 1e-4 },
        { DoubleBarrier::KnockIn,    80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  7.9663, 1e-4 },

        { DoubleBarrier::KnockIn,    85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0797, 1e-4 },
        { DoubleBarrier::KnockIn,    85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  2.6458, 1e-4 },
        { DoubleBarrier::KnockIn,    85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  6.1658, 1e-4 },
        { DoubleBarrier::KnockIn,    85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  9.4486, 1e-4 },

        { DoubleBarrier::KnockIn,    90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.9704, 1e-4 },
        { DoubleBarrier::KnockIn,    90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  6.2006, 1e-4 },
        { DoubleBarrier::KnockIn,    90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  9.0798, 1e-4 },
        { DoubleBarrier::KnockIn,    90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  9.8699, 1e-4 },

        { DoubleBarrier::KnockIn,    95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  6.2434, 1e-4 },
        { DoubleBarrier::KnockIn,    95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  9.7847, 1e-4 },
        { DoubleBarrier::KnockIn,    95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  9.8756, 1e-4 },
        { DoubleBarrier::KnockIn,    95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  9.8758, 1e-4 },

        { DoubleBarrier::KOKI,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0041, 1e-4 },
        { DoubleBarrier::KOKI,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.7080, 1e-4 },
        { DoubleBarrier::KOKI,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  2.1581, 1e-4 },
        { DoubleBarrier::KOKI,       80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.2061, 1e-4 },

        { DoubleBarrier::KOKI,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0723, 1e-4 },
        { DoubleBarrier::KOKI,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  1.6663, 1e-4 },
        { DoubleBarrier::KOKI,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  3.3930, 1e-4 },
        { DoubleBarrier::KOKI,       85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.8679, 1e-4 },

        { DoubleBarrier::KOKI,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.7080, 1e-4 },
        { DoubleBarrier::KOKI,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  3.4424, 1e-4 },
        { DoubleBarrier::KOKI,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  4.7496, 1e-4 },
        { DoubleBarrier::KOKI,       90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  5.0475, 1e-4 },

        { DoubleBarrier::KOKI,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  3.6524, 1e-4 },
        { DoubleBarrier::KOKI,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  5.1256, 1e-4 },
        { DoubleBarrier::KOKI,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  5.0763, 1e-4 },
        { DoubleBarrier::KOKI,       95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  5.0275, 1e-4 },

        // degenerate cases
        { DoubleBarrier::KnockOut,   95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4 },
        { DoubleBarrier::KnockOut,   95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4 },
        { DoubleBarrier::KnockIn,    95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4 },
        { DoubleBarrier::KnockIn,    95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4 },
        { DoubleBarrier::KIKO,       95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4 },
        { DoubleBarrier::KIKO,       95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4 },
        { DoubleBarrier::KOKI,       95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4 },
        { DoubleBarrier::KOKI,       95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4 },
    };

    DayCounter dc = Actual360();
    Date today = Date::todaysDate();

    boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(100.0));
    boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.04));
    boost::shared_ptr<YieldTermStructure> qTS = flatRate(today, qRate, dc);
    boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.01));
    boost::shared_ptr<YieldTermStructure> rTS = flatRate(today, rRate, dc);
    boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.25));
    boost::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, vol, dc);

    for (Size i=0; i<LENGTH(values); i++) {

        boost::shared_ptr<StrikedTypePayoff> payoff(new CashOrNothingPayoff(
            Option::Call, 0, values[i].cash));

        Date exDate = today + Integer(values[i].t*360+0.5);
        boost::shared_ptr<Exercise> exercise;
        if (values[i].barrierType == DoubleBarrier::KIKO ||
            values[i].barrierType == DoubleBarrier::KOKI)
            exercise.reset(new AmericanExercise(today, exDate));
        else
            exercise.reset(new EuropeanExercise(exDate));

        spot ->setValue(values[i].s);
        qRate->setValue(values[i].q);
        rRate->setValue(values[i].r);
        vol  ->setValue(values[i].v);

        boost::shared_ptr<BlackScholesMertonProcess> stochProcess(new
            BlackScholesMertonProcess(Handle<Quote>(spot),
                                      Handle<YieldTermStructure>(qTS),
                                      Handle<YieldTermStructure>(rTS),
                                      Handle<BlackVolTermStructure>(volTS)));

        // checking with analytic engine
        boost::shared_ptr<PricingEngine> engine(
                             new AnalyticDoubleBarrierBinaryEngine(stochProcess));
        DoubleBarrierOption opt(values[i].barrierType, 
                          values[i].barrier_lo, 
                          values[i].barrier_hi, 
                          0,
                          payoff,
                          exercise);
        opt.setPricingEngine(engine);

        Real calculated = opt.NPV();
        Real expected = values[i].result;
        Real error = std::fabs(calculated-expected);
        if (error > values[i].tol) {
            REPORT_FAILURE("value", payoff, exercise, values[i].barrierType, 
                           values[i].barrier_lo, values[i].barrier_hi, values[i].s,
                           values[i].q, values[i].r, today, values[i].v,
                           values[i].result, calculated, error, values[i].tol);
        }

        Size steps = 500;
        // checking with binomial engine
        engine = boost::shared_ptr<PricingEngine>(
              new BinomialDoubleBarrierEngine<CoxRossRubinstein,
                              DiscretizedDoubleBarrierOption>(stochProcess, 
                                                                 steps));
        opt.setPricingEngine(engine);
        calculated = opt.NPV();
        expected = values[i].result;
        error = std::fabs(calculated-expected);
        double tol = 0.22;
        if (error>tol) {
            REPORT_FAILURE("Binomial value", payoff, exercise, values[i].barrierType, 
                           values[i].barrier_lo, values[i].barrier_hi, values[i].s,
                           values[i].q, values[i].r, today, values[i].v,
                           values[i].result, calculated, error, tol);
        }

    }
} 


test_suite* DoubleBinaryOptionTest::suite() {
    test_suite* suite = BOOST_TEST_SUITE("DoubleBinary");
    suite->add(QUANTLIB_TEST_CASE(&DoubleBinaryOptionTest::testHaugValues));
    return suite;
}


<|start_filename|>ql/models/marketmodels/products/singleproductcomposite.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/models/marketmodels/products/singleproductcomposite.hpp>

namespace QuantLib {

    Size SingleProductComposite::numberOfProducts() const {
        return 1;
    }


    Size SingleProductComposite::maxNumberOfCashFlowsPerProductPerStep() const {
        Size result = 0;
        for (const_iterator i=components_.begin(); i!=components_.end(); ++i)
            result += i->product->maxNumberOfCashFlowsPerProductPerStep();
        return result;
    }


    bool SingleProductComposite::nextTimeStep(
                     const CurveState& currentState,
                     std::vector<Size>& numberCashFlowsThisStep,
                     std::vector<std::vector<CashFlow> >& cashFlowsGenerated) {
        QL_REQUIRE(finalized_, "composite not finalized");
        bool done = true;
        Size n = 0, totalCashflows = 0;
        // for each sub-product...
        for (iterator i=components_.begin(); i!=components_.end(); ++i, ++n) {
            if (isInSubset_[n][currentIndex_] && !i->done) {
                // ...make it evolve...
                bool thisDone = i->product->nextTimeStep(currentState,
                                                         i->numberOfCashflows,
                                                         i->cashflows);
                // ...and copy the results. Time indices need to be remapped
                // so that they point into all cash-flow times. Amounts need
                // to be adjusted by the corresponding multiplier.
                for (Size j=0; j<i->product->numberOfProducts(); ++j) {
                    Size offset = totalCashflows;
                    totalCashflows += i->numberOfCashflows[j];
                    for (Size k=0; k<i->numberOfCashflows[j]; ++k) {
                        CashFlow& from = i->cashflows[j][k];
                        CashFlow& to = cashFlowsGenerated[0][k+offset];
                        to.timeIndex = i->timeIndices[from.timeIndex];
                        to.amount = from.amount * i->multiplier;
                    }
                    numberCashFlowsThisStep[0] = totalCashflows;
                }
                // finally, set done to false if this product isn't done
                done = done && thisDone;
            }
        }
        ++currentIndex_;
        return done;
    }

    std::auto_ptr<MarketModelMultiProduct>
    SingleProductComposite::clone() const {
        return std::auto_ptr<MarketModelMultiProduct>(
                                           new SingleProductComposite(*this));
    }

}



<|start_filename|>ql/instruments/bonds/btp.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010, 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file btp.hpp
    \brief Italian BTP (Buoni Poliennali del Tesoro) fixed rate bond
*/

#ifndef quantlib_btp_hpp
#define quantlib_btp_hpp

#include <ql/instruments/bonds/fixedratebond.hpp>
#include <ql/instruments/bonds/floatingratebond.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/instruments/vanillaswap.hpp>

#include <numeric>

namespace QuantLib {

    /*! Italian CCTEU (Certificato di credito del tesoro)
        Euribor6M indexed floating rate bond
    
        \ingroup instruments

    */
    class CCTEU : public FloatingRateBond {
      public:
        CCTEU(const Date& maturityDate,
              Spread spread,
              const Handle<YieldTermStructure>& fwdCurve =
                                    Handle<YieldTermStructure>(),
              const Date& startDate = Date(),
              const Date& issueDate = Date());
        //! \name Bond interface
        //@{
        //! accrued amount at a given date
        /*! The default bond settlement is used if no date is given. */
        Real accruedAmount(Date d = Date()) const;
        //@}
    };

    //! Italian BTP (Buono Poliennali del Tesoro) fixed rate bond
    /*! \ingroup instruments

    */
    class BTP : public FixedRateBond {
      public:
        BTP(const Date& maturityDate,
            Rate fixedRate,
            const Date& startDate = Date(),
            const Date& issueDate = Date());
        /*! constructor needed for legacy non-par redemption BTPs.
            As of today the only remaining one is IT123456789012
            that will redeem 99.999 on xx-may-2037 */
        BTP(const Date& maturityDate,
            Rate fixedRate,
            Real redemption,
            const Date& startDate = Date(),
            const Date& issueDate = Date());
        //! \name Bond interface
        //@{
        //! accrued amount at a given date
        /*! The default bond settlement is used if no date is given. */
        Real accruedAmount(Date d = Date()) const;
        //@}
        //! BTP yield given a (clean) price and settlement date
        /*! The default BTP conventions are used: Actual/Actual (ISMA),
            Compounded, Annual.
            The default bond settlement is used if no date is given. */
        Rate yield(Real cleanPrice,
                   Date settlementDate = Date(),
                   Real accuracy = 1.0e-8,
                   Size maxEvaluations = 100) const;
    };

    class RendistatoBasket : public Observer,
                             public Observable {
      public:
        RendistatoBasket(const std::vector<boost::shared_ptr<BTP> >& btps,
                         const std::vector<Real>& outstandings,
                         const std::vector<Handle<Quote> >& cleanPriceQuotes);
        //! \name Inspectors
        //@{
        Size size() const { return n_;}
        const std::vector<boost::shared_ptr<BTP> >& btps() const;
        const std::vector<Handle<Quote> >& cleanPriceQuotes() const;
        const std::vector<Real>& outstandings() const { return outstandings_;}
        const std::vector<Real>& weights() const { return weights_;}
        Real outstanding() const { return outstanding_;}
        //@}
        //! \name Observer interface
        //@{
        void update() { notifyObservers(); }
        //@}
      private:
        std::vector<boost::shared_ptr<BTP> > btps_;
        std::vector<Real> outstandings_;
        std::vector<Handle<Quote> > quotes_;
        Real outstanding_;
        Size n_;
        std::vector<Real> weights_;
    };

    class RendistatoCalculator : LazyObject {
      public:
        RendistatoCalculator(const boost::shared_ptr<RendistatoBasket>& basket,
                             const boost::shared_ptr<Euribor>& euriborIndex,
                             const Handle<YieldTermStructure>& discountCurve);
        //! \name Calculations
        //@{
        Rate yield() const;
        Time duration() const;
        // bonds
        const std::vector<Rate>& yields() const;
        const std::vector<Time>& durations() const;
        // swaps
        const std::vector<Time>& swapLengths() const;
        const std::vector<Rate>& swapRates() const;
        const std::vector<Rate>& swapYields() const;
        const std::vector<Time>& swapDurations() const;
        //@}
        //! \name Equivalent Swap proxy
        //@{
        boost::shared_ptr<VanillaSwap> equivalentSwap() const;
        Rate equivalentSwapRate() const;
        Rate equivalentSwapYield() const;
        Time equivalentSwapDuration() const;
        Time equivalentSwapLength() const;
        Spread equivalentSwapSpread() const;
        //@}
      protected:
        //! \name LazyObject interface
        //@{
        void performCalculations() const;
        //@}
      private:
        boost::shared_ptr<RendistatoBasket> basket_;
        boost::shared_ptr<Euribor> euriborIndex_;
        Handle<YieldTermStructure> discountCurve_;

        mutable std::vector<Rate> yields_;
        mutable std::vector<Time> durations_;
        mutable Time duration_;
        mutable Size equivalentSwapIndex_;

        Size nSwaps_;
        mutable std::vector<boost::shared_ptr<VanillaSwap> > swaps_;
        std::vector<Time> swapLenghts_;
        mutable std::vector<Time> swapBondDurations_;
        mutable std::vector<Rate> swapBondYields_, swapRates_;
    };

    //! RendistatoCalculator equivalent swap lenth Quote adapter
    class RendistatoEquivalentSwapLengthQuote : public Quote {
      public:
        RendistatoEquivalentSwapLengthQuote(
            const boost::shared_ptr<RendistatoCalculator>& r);
        Real value() const;
        bool isValid() const;
      private:
        boost::shared_ptr<RendistatoCalculator> r_;
    };

    //! RendistatoCalculator equivalent swap spread Quote adapter
    class RendistatoEquivalentSwapSpreadQuote : public Quote {
      public:
        RendistatoEquivalentSwapSpreadQuote(
            const boost::shared_ptr<RendistatoCalculator>& r);
        Real value() const;
        bool isValid() const;
      private:
        boost::shared_ptr<RendistatoCalculator> r_;
    };

    // inline

    inline Real CCTEU::accruedAmount(Date d) const {
        Real result = FloatingRateBond::accruedAmount(d);
        return ClosestRounding(5)(result);
    }

    inline Real BTP::accruedAmount(Date d) const {
        Real result = FixedRateBond::accruedAmount(d);
        return ClosestRounding(5)(result);
    }

    inline const std::vector<boost::shared_ptr<BTP> >&
    RendistatoBasket::btps() const {
        return btps_;
    }

    inline const std::vector<Handle<Quote> >&
    RendistatoBasket::cleanPriceQuotes() const {
        return quotes_;
    }

    inline Rate RendistatoCalculator::yield() const {
        return std::inner_product(basket_->weights().begin(),
                                  basket_->weights().end(),
                                  yields().begin(), 0.0);
    }

    inline Time RendistatoCalculator::duration() const {
        calculate();
        return duration_;
    }

    inline const std::vector<Rate>& RendistatoCalculator::yields() const {
        calculate();
        return yields_;
    }

    inline const std::vector<Time>& RendistatoCalculator::durations() const {
        calculate();
        return durations_;
    }

    inline const std::vector<Time>& RendistatoCalculator::swapLengths() const {
        return swapLenghts_;
    }

    inline const std::vector<Rate>& RendistatoCalculator::swapRates() const {
        calculate();
        return swapRates_;
    }

    inline const std::vector<Rate>& RendistatoCalculator::swapYields() const {
        calculate();
        return swapBondYields_;
    }

    inline const std::vector<Time>& RendistatoCalculator::swapDurations() const {
        calculate();
        return swapBondDurations_;
    }

    inline boost::shared_ptr<VanillaSwap>
    RendistatoCalculator::equivalentSwap() const {
        calculate();
        return swaps_[equivalentSwapIndex_];
    }

    inline Rate RendistatoCalculator::equivalentSwapRate() const {
        calculate();
        return swapRates_[equivalentSwapIndex_];
    }

    inline Rate RendistatoCalculator::equivalentSwapYield() const {
        calculate();
        return swapBondYields_[equivalentSwapIndex_];
    }

    inline Time RendistatoCalculator::equivalentSwapDuration() const {
        calculate();
        return swapBondDurations_[equivalentSwapIndex_];
    }

    inline Time RendistatoCalculator::equivalentSwapLength() const {
        calculate();
        return swapLenghts_[equivalentSwapIndex_];
    }

    inline Spread RendistatoCalculator::equivalentSwapSpread() const {
        return yield() - equivalentSwapRate();
    }

    inline Real RendistatoEquivalentSwapLengthQuote::value() const {
        return r_->equivalentSwapLength();
    }

    inline Real RendistatoEquivalentSwapSpreadQuote::value() const {
        return r_->equivalentSwapSpread();
    }

}

#endif


<|start_filename|>ql/models/marketmodels/browniangenerators/sobolbrowniangenerator.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/


#ifndef quantlib_sobol_brownian_generator_hpp
#define quantlib_sobol_brownian_generator_hpp

#include <ql/models/marketmodels/browniangenerator.hpp>
#include <ql/math/randomnumbers/inversecumulativersg.hpp>
#include <ql/math/randomnumbers/sobolrsg.hpp>
#include <ql/methods/montecarlo/brownianbridge.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <vector>

namespace QuantLib {

    //! Sobol Brownian generator for market-model simulations
    /*! Incremental Brownian generator using a Sobol generator,
        inverse-cumulative Gaussian method, and Brownian bridging.
    */
    class SobolBrownianGenerator : public BrownianGenerator {
      public:
        enum Ordering {
            Factors,  /*!< The variates with the best quality will be
                           used for the evolution of the first factor. */
            Steps,    /*!< The variates with the best quality will be
                           used for the largest steps of all factors. */
            Diagonal  /*!< A diagonal schema will be used to assign
                           the variates with the best quality to the
                           most important factors and the largest
                           steps. */
        };
        SobolBrownianGenerator(
                           Size factors,
                           Size steps,
                           Ordering ordering,
                           unsigned long seed = 0,
                           SobolRsg::DirectionIntegers directionIntegers
                                                        = SobolRsg::Jaeckel);

        Real nextPath();
        Real nextStep(std::vector<Real>&);

        Size numberOfFactors() const;
        Size numberOfSteps() const;
        
        // test interface
        const std::vector<std::vector<Size> >& orderedIndices() const;
        std::vector<std::vector<Real> > transform(
                              const std::vector<std::vector<Real> >& variates);

      private:
        Size factors_, steps_;
        Ordering ordering_;
        InverseCumulativeRsg<SobolRsg,InverseCumulativeNormal> generator_;
        BrownianBridge bridge_;
        // work variables
        Size lastStep_;
        std::vector<std::vector<Size> > orderedIndices_;
        std::vector<std::vector<Real> > bridgedVariates_;
    };

    class SobolBrownianGeneratorFactory : public BrownianGeneratorFactory {
      public:
        SobolBrownianGeneratorFactory(
                           SobolBrownianGenerator::Ordering ordering,
                           unsigned long seed = 0,
                           SobolRsg::DirectionIntegers directionIntegers
                                                         = SobolRsg::Jaeckel);
        boost::shared_ptr<BrownianGenerator> create(Size factors,
                                                    Size steps) const;
      private:
        SobolBrownianGenerator::Ordering ordering_;
        unsigned long seed_;
        SobolRsg::DirectionIntegers integers_;
    };

}


#endif


<|start_filename|>ql/exercise.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
 Copyright (C) 2001, 2002, 2003 <NAME>
 Copyright (C) 2003 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/exercise.hpp>
#include <ql/errors.hpp>

namespace QuantLib {

    AmericanExercise::AmericanExercise(const Date& earliest,
                                       const Date& latest,
                                       bool payoffAtExpiry)
    : EarlyExercise(American, payoffAtExpiry) {
        QL_REQUIRE(earliest<=latest,
                   "earliest > latest exercise date");
        dates_ = std::vector<Date>(2);
        dates_[0] = earliest;
        dates_[1] = latest;
    }

    AmericanExercise::AmericanExercise(const Date& latest,
                                       bool payoffAtExpiry)
    : EarlyExercise(American, payoffAtExpiry) {
        dates_ = std::vector<Date>(2);
        dates_[0] = Date::minDate();
        dates_[1] = latest;
    }

    BermudanExercise::BermudanExercise(const std::vector<Date>& dates,
                                       bool payoffAtExpiry)
    : EarlyExercise(Bermudan, payoffAtExpiry) {
        QL_REQUIRE(!dates.empty(), "no exercise date given");
        dates_ = dates;
        std::sort(dates_.begin(), dates_.end());
    }

    EuropeanExercise::EuropeanExercise(const Date& date)
    : Exercise(European) {
        dates_ = std::vector<Date>(1,date);
    }

}


<|start_filename|>ql/currencies/africa.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004, 2005 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*
    Data from http://fx.sauder.ubc.ca/currency_table.html
    and http://www.thefinancials.com/vortex/CurrencyFormats.html
*/

#include <ql/currencies/africa.hpp>

namespace QuantLib {

    // South-African rand
    /* The ISO three-letter code is ZAR; the numeric code is 710.
       It is divided into 100 cents.
    */
    ZARCurrency::ZARCurrency() {
        static boost::shared_ptr<Data> zarData(
                                new Data("South-African rand", "ZAR", 710,
                                         "R", "", 100,
                                         Rounding(),
                                         "%3% %1$.2f"));
        data_ = zarData;
    }

}


<|start_filename|>ql/methods/finitedifferences/operators/fdmhestonop.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008 <NAME>
 Copyright (C) 2008, 2014, 2015 <NAME>
 Copyright (C) 2015 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
#include <ql/methods/finitedifferences/operators/fdmhestonop.hpp>
#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
#include <ql/methods/finitedifferences/operators/secondderivativeop.hpp>
#include <ql/methods/finitedifferences/operators/secondordermixedderivativeop.hpp>

namespace QuantLib {

    FdmHestonEquityPart::FdmHestonEquityPart(
        const boost::shared_ptr<FdmMesher>& mesher,
        const boost::shared_ptr<YieldTermStructure>& rTS,
        const boost::shared_ptr<YieldTermStructure>& qTS,
        const boost::shared_ptr<FdmQuantoHelper>& quantoHelper,
        const boost::shared_ptr<LocalVolTermStructure>& leverageFct)
    : varianceValues_(0.5*mesher->locations(1)),
      dxMap_ (FirstDerivativeOp(0, mesher)),
      dxxMap_(SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))),
      mapT_  (0, mesher),
      mesher_(mesher),
      rTS_(rTS),
      qTS_(qTS),
      quantoHelper_(quantoHelper),
      leverageFct_(leverageFct) {

        // on the boundary s_min and s_max the second derivative
        // d^2V/dS^2 is zero and due to Ito's Lemma the variance term
        // in the drift should vanish.
        boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
        FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
            if (   iter.coordinates()[0] == 0
                || iter.coordinates()[0] == layout->dim()[0]-1) {
                varianceValues_[iter.index()] = 0.0;
            }
        }
        volatilityValues_ = Sqrt(2*varianceValues_);
    }

    void FdmHestonEquityPart::setTime(Time t1, Time t2) {
        const Rate r = rTS_->forwardRate(t1, t2, Continuous).rate();
        const Rate q = qTS_->forwardRate(t1, t2, Continuous).rate();

        if (quantoHelper_) {
            mapT_.axpyb(r - q - varianceValues_
                - quantoHelper_->quantoAdjustment(
                volatilityValues_, t1, t2),
                dxMap_, dxxMap_, Array(1, -0.5*r));
        }
        else {
            L_ = getLeverageFctSlice(t1, t2);
            const Array Lsquare = L_*L_;

            mapT_.axpyb(r - q - varianceValues_*Lsquare, dxMap_,
                        dxxMap_.mult(Lsquare), Array(1, -0.5*r));
        }
    }

    Disposable<Array> FdmHestonEquityPart::getLeverageFctSlice(Time t1, Time t2)
    const {
        const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout();
        Array v(layout->size(), 1.0);

        if (!leverageFct_) {
            return v;
        }
        const Real t = 0.5*(t1+t2);
        const Time time = std::min(leverageFct_->maxTime(), t);

        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin();
             iter!=endIter; ++iter) {
            const Size nx = iter.coordinates()[0];

            if (iter.coordinates()[1] == 0) {
                const Real x = std::exp(mesher_->location(iter, 0));
                const Real spot = std::min(leverageFct_->maxStrike(),
                                           std::max(leverageFct_->minStrike(), x));
                v[nx] = std::max(0.01, leverageFct_->localVol(time, spot, true));
            }
            else {
                v[iter.index()] = v[nx];
            }
        }
        return v;
    }


    const TripleBandLinearOp& FdmHestonEquityPart::getMap() const {
        return mapT_;
    }

    FdmHestonVariancePart::FdmHestonVariancePart(
        const boost::shared_ptr<FdmMesher>& mesher,
        const boost::shared_ptr<YieldTermStructure>& rTS,
        Real sigma, Real kappa, Real theta)
    : dyMap_(SecondDerivativeOp(1, mesher)
                .mult(0.5*sigma*sigma*mesher->locations(1))
             .add(FirstDerivativeOp(1, mesher)
                  .mult(kappa*(theta - mesher->locations(1))))),
      mapT_(1, mesher),
      rTS_(rTS) {
    }

    void FdmHestonVariancePart::setTime(Time t1, Time t2) {
        const Rate r = rTS_->forwardRate(t1, t2, Continuous).rate();
        mapT_.axpyb(Array(), dyMap_, dyMap_, Array(1,-0.5*r));
    }

    const TripleBandLinearOp& FdmHestonVariancePart::getMap() const {
        return mapT_;
    }

    FdmHestonOp::FdmHestonOp(
        const boost::shared_ptr<FdmMesher>& mesher,
        const boost::shared_ptr<HestonProcess> & hestonProcess,
        const boost::shared_ptr<FdmQuantoHelper>& quantoHelper,
        const boost::shared_ptr<LocalVolTermStructure>& leverageFct)
    : correlationMap_(SecondOrderMixedDerivativeOp(0, 1, mesher)
                        .mult(hestonProcess->rho()*hestonProcess->sigma()
                                *mesher->locations(1))),
      dyMap_(mesher, hestonProcess->riskFreeRate().currentLink(),
              hestonProcess->sigma(), 
              hestonProcess->kappa(), 
              hestonProcess->theta()),
      dxMap_(mesher,
             hestonProcess->riskFreeRate().currentLink(), 
             hestonProcess->dividendYield().currentLink(),
             quantoHelper, leverageFct),
      leverageFct_(leverageFct) {
    }


    void FdmHestonOp::setTime(Time t1, Time t2) {
        dxMap_.setTime(t1, t2);
        dyMap_.setTime(t1, t2);
    }

    Size FdmHestonOp::size() const {
        return 2;
    }

    Disposable<Array> FdmHestonOp::apply(const Array& u) const {
        return dyMap_.getMap().apply(u) + dxMap_.getMap().apply(u)
              + dxMap_.getL()*correlationMap_.apply(u);
    }

    Disposable<Array> FdmHestonOp::apply_direction(Size direction,
                                                   const Array& r) const {
        if (direction == 0)
            return dxMap_.getMap().apply(r);
        else if (direction == 1)
            return dyMap_.getMap().apply(r);
        else
            QL_FAIL("direction too large");
    }

    Disposable<Array> FdmHestonOp::apply_mixed(const Array& r) const {
        return dxMap_.getL()*correlationMap_.apply(r);
    }

    Disposable<Array>
        FdmHestonOp::solve_splitting(Size direction,
                                     const Array& r, Real a) const {

        if (direction == 0) {
            return dxMap_.getMap().solve_splitting(r, a, 1.0);
        }
        else if (direction == 1) {
            return dyMap_.getMap().solve_splitting(r, a, 1.0);
        }
        else
            QL_FAIL("direction too large");
    }

    Disposable<Array>
        FdmHestonOp::preconditioner(const Array& r, Real dt) const {

        return solve_splitting(0, r, dt);
    }

#if !defined(QL_NO_UBLAS_SUPPORT)
    Disposable<std::vector<SparseMatrix> >
    FdmHestonOp::toMatrixDecomp() const {
        std::vector<SparseMatrix> retVal(3);

        retVal[0] = dxMap_.getMap().toMatrix();
        retVal[1] = dyMap_.getMap().toMatrix();
        retVal[2] = correlationMap_.toMatrix();

        return retVal;
    }
#endif
}


<|start_filename|>ql/pricingengines/barrier/mcbarrierengine.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2003 <NAME>
 Copyright (C) 2003 <NAME>
 Copyright (C) 2003, 2004, 2005 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/barrier/mcbarrierengine.hpp>

namespace QuantLib {

    BarrierPathPricer::BarrierPathPricer(
                    Barrier::Type barrierType,
                    Real barrier,
                    Real rebate,
                    Option::Type type,
                    Real strike,
                    const std::vector<DiscountFactor>& discounts,
                    const boost::shared_ptr<StochasticProcess1D>& diffProcess,
                    const PseudoRandom::ursg_type& sequenceGen)
    : barrierType_(barrierType), barrier_(barrier),
      rebate_(rebate), diffProcess_(diffProcess),
      sequenceGen_(sequenceGen), payoff_(type, strike),
      discounts_(discounts) {
        QL_REQUIRE(strike>=0.0,
                   "strike less than zero not allowed");
        QL_REQUIRE(barrier>0.0,
                   "barrier less/equal zero not allowed");
    }


    Real BarrierPathPricer::operator()(const Path& path) const {
        static Size null = Null<Size>();
        Size n = path.length();
        QL_REQUIRE(n>1, "the path cannot be empty");

        bool isOptionActive = false;
        Size knockNode = null;
        Real asset_price = path.front();
        Real new_asset_price;
        Real x, y;
        Volatility vol;
        TimeGrid timeGrid = path.timeGrid();
        Time dt;
        std::vector<Real> u = sequenceGen_.nextSequence().value;
        Size i;

        switch (barrierType_) {
          case Barrier::DownIn:
            isOptionActive = false;
            for (i = 0; i < n-1; i++) {
                new_asset_price = path[i+1];
                // terminal or initial vol?
                vol = diffProcess_->diffusion(timeGrid[i],asset_price);
                dt = timeGrid.dt(i);

                x = std::log(new_asset_price / asset_price);
                y = 0.5*(x - std::sqrt (x*x - 2*vol*vol*dt*std::log(u[i])));
                y = asset_price * std::exp(y);
                if (y <= barrier_) {
                    isOptionActive = true;
                    if (knockNode == null)
                        knockNode = i+1;
                }
                asset_price = new_asset_price;
            }
            break;
          case Barrier::UpIn:
            isOptionActive = false;
            for (i = 0; i < n-1; i++) {
                new_asset_price = path[i+1];
                // terminal or initial vol?
                vol = diffProcess_->diffusion(timeGrid[i],asset_price);
                dt = timeGrid.dt(i);

                x = std::log(new_asset_price / asset_price);
                y = 0.5*(x + std::sqrt(x*x - 2*vol*vol*dt*std::log((1-u[i]))));
                y = asset_price * std::exp(y);
                if (y >= barrier_) {
                    isOptionActive = true;
                    if (knockNode == null)
                        knockNode = i+1;
                }
                asset_price = new_asset_price;
            }
            break;
          case Barrier::DownOut:
            isOptionActive = true;
            for (i = 0; i < n-1; i++) {
                new_asset_price = path[i+1];
                // terminal or initial vol?
                vol = diffProcess_->diffusion(timeGrid[i],asset_price);
                dt = timeGrid.dt(i);

                x = std::log(new_asset_price / asset_price);
                y = 0.5*(x - std::sqrt(x*x - 2*vol*vol*dt*std::log(u[i])));
                y = asset_price * std::exp(y);
                if (y <= barrier_) {
                    isOptionActive = false;
                    if (knockNode == null)
                        knockNode = i+1;
                }
                asset_price = new_asset_price;
            }
            break;
          case Barrier::UpOut:
            isOptionActive = true;
            for (i = 0; i < n-1; i++) {
                new_asset_price = path[i+1];
                // terminal or initial vol?
                vol = diffProcess_->diffusion(timeGrid[i],asset_price);
                dt = timeGrid.dt(i);

                x = std::log(new_asset_price / asset_price);
                y = 0.5*(x + std::sqrt(x*x - 2*vol*vol*dt*std::log((1-u[i]))));
                y = asset_price * std::exp(y);
                if (y >= barrier_) {
                    isOptionActive = false;
                    if (knockNode == null)
                        knockNode = i+1;
                }
                asset_price = new_asset_price;
            }
            break;
          default:
            QL_FAIL("unknown barrier type");
        }

        if (isOptionActive) {
            return payoff_(asset_price) * discounts_.back();
        } else {
            switch (barrierType_) {
              case Barrier::UpIn:
              case Barrier::DownIn:
                return rebate_*discounts_.back();
              case Barrier::UpOut:
              case Barrier::DownOut:
                return rebate_*discounts_[knockNode];
              default:
                QL_FAIL("unknown barrier type");
            }
        }
    }


    BiasedBarrierPathPricer::BiasedBarrierPathPricer(
                                 Barrier::Type barrierType,
                                 Real barrier,
                                 Real rebate,
                                 Option::Type type,
                                 Real strike,
                                 const std::vector<DiscountFactor>& discounts)
    : barrierType_(barrierType), barrier_(barrier),
      rebate_(rebate), payoff_(type, strike), discounts_(discounts) {
        QL_REQUIRE(strike>=0.0,
                   "strike less than zero not allowed");
        QL_REQUIRE(barrier>0.0,
                   "barrier less/equal zero not allowed");
    }


    Real BiasedBarrierPathPricer::operator()(const Path& path) const {
        static Size null = Null<Size>();
        Size n = path.length();
        QL_REQUIRE(n>1, "the path cannot be empty");

        bool isOptionActive = false;
        Size knockNode = null;
        Real asset_price = path.front();
        Size i;

        switch (barrierType_) {
          case Barrier::DownIn:
            isOptionActive = false;
            for (i = 1; i < n; i++) {
                asset_price = path[i];
                if (asset_price <= barrier_) {
                    isOptionActive = true;
                    if (knockNode == null)
                        knockNode = i;
                }
            }
            break;
          case Barrier::UpIn:
            isOptionActive = false;
            for (i = 1; i < n; i++) {
                asset_price = path[i];
                if (asset_price >= barrier_) {
                    isOptionActive = true;
                    if (knockNode == null)
                        knockNode = i;
                }
            }
            break;
          case Barrier::DownOut:
            isOptionActive = true;
            for (i = 1; i < n; i++) {
                asset_price = path[i];
                if (asset_price <= barrier_) {
                    isOptionActive = false;
                    if (knockNode == null)
                        knockNode = i;
                }
            }
            break;
          case Barrier::UpOut:
            isOptionActive = true;
            for (i = 1; i < n; i++) {
                asset_price = path[i];
                if (asset_price >= barrier_) {
                    isOptionActive = false;
                    if (knockNode == null)
                        knockNode = i;
                }
            }
            break;
          default:
            QL_FAIL("unknown barrier type");
        }

        if (isOptionActive) {
            return payoff_(asset_price) * discounts_.back();
        } else {
            switch (barrierType_) {
              case Barrier::UpIn:
              case Barrier::DownIn:
                return rebate_*discounts_.back();
              case Barrier::UpOut:
              case Barrier::DownOut:
                return rebate_*discounts_[knockNode];
              default:
                QL_FAIL("unknown barrier type");
            }
        }
    }

}


<|start_filename|>ql/instruments/impliedvolatility.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2007, 2009 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/instruments/impliedvolatility.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/math/solvers1d/brent.hpp>

namespace QuantLib {

    namespace {

        class PriceError {
          public:
            PriceError(const PricingEngine& engine,
                       SimpleQuote& vol,
                       Real targetValue);
            Real operator()(Volatility x) const;
          private:
            const PricingEngine& engine_;
            SimpleQuote& vol_;
            Real targetValue_;
            const Instrument::results* results_;
        };

        PriceError::PriceError(const PricingEngine& engine,
                               SimpleQuote& vol,
                               Real targetValue)
        : engine_(engine), vol_(vol), targetValue_(targetValue) {
            results_ =
                dynamic_cast<const Instrument::results*>(engine_.getResults());
            QL_REQUIRE(results_ != 0,
                       "pricing engine does not supply needed results");
        }

        Real PriceError::operator()(Volatility x) const {
            vol_.setValue(x);
            engine_.calculate();
            return results_->value-targetValue_;
        }

    }


    namespace detail {

        Volatility ImpliedVolatilityHelper::calculate(
                                                 const Instrument& instrument,
                                                 const PricingEngine& engine,
                                                 SimpleQuote& volQuote,
                                                 Real targetValue,
                                                 Real accuracy,
                                                 Natural maxEvaluations,
                                                 Volatility minVol,
                                                 Volatility maxVol) {

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

            PriceError f(engine, volQuote, targetValue);
            Brent solver;
            solver.setMaxEvaluations(maxEvaluations);
            Volatility guess = (minVol+maxVol)/2.0;
            Volatility result = solver.solve(f, accuracy, guess,
                                             minVol, maxVol);
            return result;
        }

        boost::shared_ptr<GeneralizedBlackScholesProcess>
        ImpliedVolatilityHelper::clone(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             const boost::shared_ptr<SimpleQuote>& volQuote) {

            Handle<Quote> stateVariable = process->stateVariable();
            Handle<YieldTermStructure> dividendYield = process->dividendYield();
            Handle<YieldTermStructure> riskFreeRate = process->riskFreeRate();

            Handle<BlackVolTermStructure> blackVol = process->blackVolatility();
            Handle<BlackVolTermStructure> volatility(
                boost::shared_ptr<BlackVolTermStructure>(
                               new BlackConstantVol(blackVol->referenceDate(),
                                                    blackVol->calendar(),
                                                    Handle<Quote>(volQuote),
                                                    blackVol->dayCounter())));

            return boost::shared_ptr<GeneralizedBlackScholesProcess>(
                new GeneralizedBlackScholesProcess(stateVariable, dividendYield,
                                                   riskFreeRate, volatility));
        }

    }

}


<|start_filename|>ql/pricingengines/asian/mc_discr_arith_av_price.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
 Copyright (C) 2003, 2004 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file mc_discr_arith_av_price.hpp
    \brief Monte Carlo engine for discrete arithmetic average price Asian
*/

#ifndef quantlib_mc_discrete_arithmetic_average_price_asian_engine_hpp
#define quantlib_mc_discrete_arithmetic_average_price_asian_engine_hpp

#include <ql/pricingengines/asian/mc_discr_geom_av_price.hpp>
#include <ql/pricingengines/asian/analytic_discr_geom_av_price.hpp>
#include <ql/exercise.hpp>

namespace QuantLib {

    //!  Monte Carlo pricing engine for discrete arithmetic average price Asian
    /*!  Monte Carlo pricing engine for discrete arithmetic average price
         Asian options. It can use MCDiscreteGeometricAPEngine (Monte Carlo
         discrete arithmetic average price engine) and
         AnalyticDiscreteGeometricAveragePriceAsianEngine (analytic discrete
         arithmetic average price engine) for control variation.

         \ingroup asianengines

         \test the correctness of the returned value is tested by
               reproducing results available in literature.
    */
    template <class RNG = PseudoRandom, class S = Statistics>
    class MCDiscreteArithmeticAPEngine
        : public MCDiscreteAveragingAsianEngine<RNG,S> {
      public:
        typedef
        typename MCDiscreteAveragingAsianEngine<RNG,S>::path_generator_type
            path_generator_type;
        typedef
        typename MCDiscreteAveragingAsianEngine<RNG,S>::path_pricer_type
            path_pricer_type;
        typedef typename MCDiscreteAveragingAsianEngine<RNG,S>::stats_type
            stats_type;
        // constructor
        MCDiscreteArithmeticAPEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             bool brownianBridge,
             bool antitheticVariate,
             bool controlVariate,
             Size requiredSamples,
             Real requiredTolerance,
             Size maxSamples,
             BigNatural seed);
      protected:
        boost::shared_ptr<path_pricer_type> pathPricer() const;
        boost::shared_ptr<path_pricer_type> controlPathPricer() const;
        boost::shared_ptr<PricingEngine> controlPricingEngine() const {
            return boost::shared_ptr<PricingEngine>(
                new AnalyticDiscreteGeometricAveragePriceAsianEngine(
                                                             this->process_));
        }
    };


    class ArithmeticAPOPathPricer : public PathPricer<Path> {
      public:
        ArithmeticAPOPathPricer(Option::Type type,
                                Real strike,
                                DiscountFactor discount,
                                Real runningSum = 0.0,
                                Size pastFixings = 0);
        Real operator()(const Path& path) const;
      private:
        PlainVanillaPayoff payoff_;
        DiscountFactor discount_;
        Real runningSum_;
        Size pastFixings_;
    };


    // inline definitions

    template <class RNG, class S>
    inline
    MCDiscreteArithmeticAPEngine<RNG,S>::MCDiscreteArithmeticAPEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
             bool brownianBridge,
             bool antitheticVariate,
             bool controlVariate,
             Size requiredSamples,
             Real requiredTolerance,
             Size maxSamples,
             BigNatural seed)
    : MCDiscreteAveragingAsianEngine<RNG,S>(process,
                                            brownianBridge,
                                            antitheticVariate,
                                            controlVariate,
                                            requiredSamples,
                                            requiredTolerance,
                                            maxSamples,
                                            seed) {}

    template <class RNG, class S>
    inline
    boost::shared_ptr<
            typename MCDiscreteArithmeticAPEngine<RNG,S>::path_pricer_type>
        MCDiscreteArithmeticAPEngine<RNG,S>::pathPricer() const {

        boost::shared_ptr<PlainVanillaPayoff> payoff =
            boost::dynamic_pointer_cast<PlainVanillaPayoff>(
                this->arguments_.payoff);
        QL_REQUIRE(payoff, "non-plain payoff given");

        boost::shared_ptr<EuropeanExercise> exercise =
            boost::dynamic_pointer_cast<EuropeanExercise>(
                this->arguments_.exercise);
        QL_REQUIRE(exercise, "wrong exercise given");

        return boost::shared_ptr<typename
            MCDiscreteArithmeticAPEngine<RNG,S>::path_pricer_type>(
                new ArithmeticAPOPathPricer(
                    payoff->optionType(),
                    payoff->strike(),
                    this->process_->riskFreeRate()->discount(
                                                     this->timeGrid().back()),
                    this->arguments_.runningAccumulator,
                    this->arguments_.pastFixings));
    }

    template <class RNG, class S>
    inline
    boost::shared_ptr<
            typename MCDiscreteArithmeticAPEngine<RNG,S>::path_pricer_type>
        MCDiscreteArithmeticAPEngine<RNG,S>::controlPathPricer() const {

        boost::shared_ptr<PlainVanillaPayoff> payoff =
            boost::dynamic_pointer_cast<PlainVanillaPayoff>(
                this->arguments_.payoff);
        QL_REQUIRE(payoff, "non-plain payoff given");

        boost::shared_ptr<EuropeanExercise> exercise =
            boost::dynamic_pointer_cast<EuropeanExercise>(
                this->arguments_.exercise);
        QL_REQUIRE(exercise, "wrong exercise given");

        // for seasoned option the geometric strike might be rescaled
        // to obtain an equivalent arithmetic strike.
        // Any change applied here MUST be applied to the analytic engine too
        return boost::shared_ptr<typename
            MCDiscreteArithmeticAPEngine<RNG,S>::path_pricer_type>(
            new GeometricAPOPathPricer(
              payoff->optionType(),
              payoff->strike(),
              this->process_->riskFreeRate()->discount(
                                                   this->timeGrid().back())));
    }

    template <class RNG = PseudoRandom, class S = Statistics>
    class MakeMCDiscreteArithmeticAPEngine {
      public:
        MakeMCDiscreteArithmeticAPEngine(
            const boost::shared_ptr<GeneralizedBlackScholesProcess>& process);
        // named parameters
        MakeMCDiscreteArithmeticAPEngine& withBrownianBridge(bool b = true);
        MakeMCDiscreteArithmeticAPEngine& withSamples(Size samples);
        MakeMCDiscreteArithmeticAPEngine& withAbsoluteTolerance(Real tolerance);
        MakeMCDiscreteArithmeticAPEngine& withMaxSamples(Size samples);
        MakeMCDiscreteArithmeticAPEngine& withSeed(BigNatural seed);
        MakeMCDiscreteArithmeticAPEngine& withAntitheticVariate(bool b = true);
        MakeMCDiscreteArithmeticAPEngine& withControlVariate(bool b = true);
        // conversion to pricing engine
        operator boost::shared_ptr<PricingEngine>() const;
      private:
        boost::shared_ptr<GeneralizedBlackScholesProcess> process_;
        bool antithetic_, controlVariate_;
        Size samples_, maxSamples_;
        Real tolerance_;
        bool brownianBridge_;
        BigNatural seed_;
    };

    template <class RNG, class S>
    inline
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::MakeMCDiscreteArithmeticAPEngine(
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process)
    : process_(process), antithetic_(false), controlVariate_(false),
      samples_(Null<Size>()), maxSamples_(Null<Size>()),
      tolerance_(Null<Real>()), brownianBridge_(true), seed_(0) {}

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withSamples(Size samples) {
        QL_REQUIRE(tolerance_ == Null<Real>(),
                   "tolerance already set");
        samples_ = samples;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withAbsoluteTolerance(
                                                             Real tolerance) {
        QL_REQUIRE(samples_ == Null<Size>(),
                   "number of samples already set");
        QL_REQUIRE(RNG::allowsErrorEstimate,
                   "chosen random generator policy "
                   "does not allow an error estimate");
        tolerance_ = tolerance;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withMaxSamples(Size samples) {
        maxSamples_ = samples;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withSeed(BigNatural seed) {
        seed_ = seed;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withBrownianBridge(bool b) {
        brownianBridge_ = b;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withAntitheticVariate(bool b) {
        antithetic_ = b;
        return *this;
    }

    template <class RNG, class S>
    inline MakeMCDiscreteArithmeticAPEngine<RNG,S>&
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::withControlVariate(bool b) {
        controlVariate_ = b;
        return *this;
    }

    template <class RNG, class S>
    inline
    MakeMCDiscreteArithmeticAPEngine<RNG,S>::operator boost::shared_ptr<PricingEngine>()
                                                                      const {
        return boost::shared_ptr<PricingEngine>(new
            MCDiscreteArithmeticAPEngine<RNG,S>(process_,
                                                brownianBridge_,
                                                antithetic_, controlVariate_,
                                                samples_, tolerance_,
                                                maxSamples_,
                                                seed_));
    }



}


#endif


<|start_filename|>ql/experimental/inflation/cpicapfloortermpricesurface.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010, 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file cpicapfloortermpricesurface.hpp
    \brief cpi inflation cap and floor term price structure.  N.B. 
           cpi cap/floors have a single (one) flow (unlike nominal
           caps) because they observe cumulative inflation up to
           their maturity.  Options are on CPI(T)/CPI(0) but strikes
           are quoted for yearly average inflation, so require transformation
           via (1+quote)^T to obtain actual strikes.  These are consistent
           with ZCIIS quoting conventions.
 
    The single-flow property of CPI cap/floors means that no stripping
    is required.  Additionally CPI swaps, i.e. ZCIIS zero coupon inflation
    indexed swaps are usually the most liquid of all the inflation products.
    These two facts mean that we can use a Zero Inflation term structure to
    give ATM.
 
*/

#ifndef quantlib_cpi_capfloor_term_price_surface_hpp
#define quantlib_cpi_capfloor_term_price_surface_hpp

#include <ql/termstructures/inflationtermstructure.hpp>
#include <ql/math/interpolation.hpp>
#include <ql/math/interpolations/interpolation2d.hpp>
#include <ql/experimental/inflation/polynomial2Dspline.hpp>
#include <ql/indexes/inflationindex.hpp>


namespace QuantLib {

    //! Provides cpi cap/floor prices by interpolation and put/call parity (not cap/floor/swap* parity).
    /*! 
        The inflation index MUST contain a ZeroInflationTermStructure as
        this is used to create ATM.  Unlike YoY price surfaces we
        assume that 1) an ATM ZeroInflationTermStructure is available
        and 2) that it is safe to use it.  This is supported by the 
        fact that no stripping is required for CPI cap/floors as they
        only give one flow.

        cpi cap/floors have a single (one) flow (unlike nominal
        caps) because they observe cumulative inflation up to
        their maturity.  Options are on CPI(T)/CPI(0) but strikes
        are quoted for yearly average inflation, so require transformation
        via (1+quote)^T to obtain actual strikes.  These are consistent
        with ZCIIS quoting conventions.
     
        The observationLag is that for the referenced instrument prices.
        Strikes are as-quoted not as-used. 
    */    
    class CPICapFloorTermPriceSurface : public InflationTermStructure {
      public:
        CPICapFloorTermPriceSurface(Real nominal, 
                                    Real baseRate,  // avoids an uncontrolled crash if index has no TS
                                    const Period &observationLag,   
                                    const Calendar &cal, // calendar in index may not be useful
                                    const BusinessDayConvention &bdc,
                                    const DayCounter &dc,
                                    const Handle<ZeroInflationIndex>& zii,
                                    const Handle<YieldTermStructure>& yts,
                                    const std::vector<Rate> &cStrikes,
                                    const std::vector<Rate> &fStrikes,
                                    const std::vector<Period> &cfMaturities,
                                    const Matrix &cPrice,
                                    const Matrix &fPrice);
 
        //! \name InflationTermStructure interface
        //@{
        Period observationLag() const;
        Date baseDate() const;
        //@}

        //! is based on
        Handle<ZeroInflationIndex> zeroInflationIndex() const { return zii_; }


        //! inspectors
        /*! \note you don't know if price() is a cap or a floor
                  without checking the ZeroInflation ATM level.
        */
        //@{
        virtual Real nominal() const;
        virtual BusinessDayConvention businessDayConvention() const;
        //@}

        //! \warning you MUST remind the compiler in any descendants with the using:: mechanism 
        //!          because you overload the names
        //! remember that the strikes use the quoting convention
        //@{
        virtual Real price(const Period &d, Rate k) const;
        virtual Real capPrice(const Period &d, Rate k) const;
        virtual Real floorPrice(const Period &d, Rate k) const;
        virtual Real price(const Date &d, Rate k) const = 0;
        virtual Real capPrice(const Date &d, Rate k) const = 0;
        virtual Real floorPrice(const Date &d, Rate k) const = 0;
        //@}
        
        virtual std::vector<Rate> strikes() const {return cfStrikes_;}
        virtual std::vector<Rate> capStrikes() const {return cStrikes_;}
        virtual std::vector<Rate> floorStrikes() const {return fStrikes_;}
        virtual std::vector<Period> maturities() const {return cfMaturities_;}
        
        virtual const Matrix &capPrices() const { return cPrice_; }
        virtual const Matrix &floorPrices() const { return fPrice_; }
        
        virtual Rate minStrike() const {return cfStrikes_.front();};
        virtual Rate maxStrike() const {return cfStrikes_.back();};
        virtual Date minDate() const {return referenceDate()+cfMaturities_.front();}// \TODO deal with index interpolation
        virtual Date maxDate() const {return referenceDate()+cfMaturities_.back();}
        //@}

        
        virtual Date cpiOptionDateFromTenor(const Period& p) const;

      protected:
        virtual bool checkStrike(Rate K) {
            return ( minStrike() <= K && K <= maxStrike() );
        }
        virtual bool checkMaturity(const Date& d) {
            return ( minDate() <= d && d <= maxDate() );
        }
        
        

        Handle<ZeroInflationIndex> zii_;
        // data
        std::vector<Rate> cStrikes_;
        std::vector<Rate> fStrikes_;
        std::vector<Period> cfMaturities_;
        mutable std::vector<Real> cfMaturityTimes_;
        Matrix cPrice_;
        Matrix fPrice_;
        // constructed
        mutable std::vector<Rate> cfStrikes_;
      private:
        Real nominal_;
        BusinessDayConvention bdc_;
    };

        

    template<class Interpolator2D>
    class InterpolatedCPICapFloorTermPriceSurface
        : public CPICapFloorTermPriceSurface {
            public:
            InterpolatedCPICapFloorTermPriceSurface(Real nominal, 
                                                Rate startRate,
                                                const Period &observationLag,
                                                const Calendar &cal,
                                                const BusinessDayConvention &bdc,
                                                const DayCounter &dc,
                                                const Handle<ZeroInflationIndex>& zii,
                                                const Handle<YieldTermStructure>& yts,
                                                const std::vector<Rate> &cStrikes,
                                                const std::vector<Rate> &fStrikes,
                                                const std::vector<Period> &cfMaturities,
                                                const Matrix &cPrice,
                                                const Matrix &fPrice,
                                                const Interpolator2D &interpolator2d = Interpolator2D());

            //! \name LazyObject interface
            //@{
            void update();
            void performCalculations() const;
            //@}
            
            //! required to allow for method hiding
            //@{
            using CPICapFloorTermPriceSurface::price;
            using CPICapFloorTermPriceSurface::capPrice;
            using CPICapFloorTermPriceSurface::floorPrice;
            //@}
            
            //! remember that the strikes use the quoting convention
            //@{
            virtual Real price(const Date &d, Rate k) const;
            virtual Real capPrice(const Date &d, Rate k) const;
            virtual Real floorPrice(const Date &d, Rate k) const;
            //@}
            
        protected:
        
            // data for surfaces and curve
            mutable std::vector<Rate> allStrikes_;
            mutable Matrix cPriceB_;
            mutable Matrix fPriceB_;
            mutable Interpolation2D capPrice_, floorPrice_;
            mutable Interpolator2D interpolator2d_;
    };



    // template definitions, for some reason DOXYGEN doesn't like the first one

    #ifndef __DOXYGEN__

    template<class Interpolator2D>
    InterpolatedCPICapFloorTermPriceSurface<Interpolator2D>::
    InterpolatedCPICapFloorTermPriceSurface(Real nominal, 
                                            Rate startRate,
                                            const Period &observationLag,   
                                            const Calendar &cal,
                                            const BusinessDayConvention &bdc,
                                            const DayCounter &dc,
                                            const Handle<ZeroInflationIndex>& zii,
                                            const Handle<YieldTermStructure>& yts,
                                            const std::vector<Rate> &cStrikes,
                                            const std::vector<Rate> &fStrikes,
                                            const std::vector<Period> &cfMaturities,
                                            const Matrix &cPrice,
                                            const Matrix &fPrice,
                                            const Interpolator2D &interpolator2d)
    : CPICapFloorTermPriceSurface(nominal, startRate, observationLag, cal, bdc, dc,
                                  zii, yts, cStrikes, fStrikes, cfMaturities, cPrice, fPrice),
      interpolator2d_(interpolator2d) {
        performCalculations();
    }

    #endif

    
    
    template<class I2D>
    void InterpolatedCPICapFloorTermPriceSurface<I2D>::
    update() {
        notifyObservers();
    }


    //! set up the interpolations for capPrice_ and floorPrice_
    //! since we know ATM, and we have single flows,
    //! we can use put/call parity to extend the surfaces
    //! across all strikes
    template<class I2D>
    void InterpolatedCPICapFloorTermPriceSurface<I2D>::
    performCalculations() const {
        
        
        Size nMat = cfMaturities_.size(), ncK = cStrikes_.size(), nfK = fStrikes_.size(),
            nK = ncK + nfK;
        Matrix cP(nK, nMat), fP(nK, nMat);
        Handle<ZeroInflationTermStructure> zts = zii_->zeroInflationTermStructure();
        Handle<YieldTermStructure> yts = this->nominalTermStructure();
        QL_REQUIRE(!zts.empty(),"Zts is empty!!!");
        QL_REQUIRE(!yts.empty(),"Yts is empty!!!");
        
        for (Size i =0; i<nfK; i++){
            allStrikes_.push_back(fStrikes_[i]);
            for (Size j=0; j<nMat; j++) {
                Period mat = cfMaturities_[j];
                Real df = yts->discount(cpiOptionDateFromTenor(mat));
                Real atm_quote = zts->zeroRate(cpiOptionDateFromTenor(mat));
                Real atm = std::pow(1.0+atm_quote, mat.length());
                Real S = atm * df;
                Real K_quote = fStrikes_[i]/100.0;
                Real K = std::pow(1.0+K_quote, mat.length());
                cP[i][j] = fPrice_[i][j] + S - K * df;
                fP[i][j] = fPrice_[i][j];
            }
        }
        for (Size i =0; i<ncK; i++){
            allStrikes_.push_back(cStrikes_[i]);
            for (Size j=0; j<nMat; j++) {
                Period mat = cfMaturities_[j];
                Real df = yts->discount(cpiOptionDateFromTenor(mat));
                Real atm_quote = zts->zeroRate(cpiOptionDateFromTenor(mat));
                Real atm = std::pow(1.0+atm_quote, mat.length());
                Real S = atm * df;
                Real K_quote = cStrikes_[i]/100.0;
                Real K = std::pow(1.0+K_quote, mat.length());
                cP[i+nfK][j] = cPrice_[i][j];
                fP[i+nfK][j] = cPrice_[i][j] + K * df - S;
            }
        }
        
        // copy to store        
        cPriceB_ = cP;
        fPriceB_ = fP;
        
        cfMaturityTimes_.clear();
        for (Size i=0; i<cfMaturities_.size();i++) {
            cfMaturityTimes_.push_back(timeFromReference(cpiOptionDateFromTenor(cfMaturities_[i])));
        }
        
        capPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
                                                allStrikes_.begin(), allStrikes_.end(),
                                                cPriceB_
                                                );
        capPrice_.enableExtrapolation();
        
        floorPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
                                                  allStrikes_.begin(), allStrikes_.end(),
                                                  fPriceB_
                                                  );
        floorPrice_.enableExtrapolation();
        
        /* test code - note order of indices
        for (Size i =0; i<nK; i++){
            std::cout << allStrikes_[i] << ":  ";
            Real qK = allStrikes_[i];
            for (Size j=0; j<nMat; j++) {
                Real t = cfMaturityTimes_[j];
                std::cout << fP[i][j] << "," << floorPrice_(t,qK) << " | " ;
            }
            std::cout << std::endl;
        }
        
        for (Size i =0; i<nK; i++){
            std::cout << allStrikes_[i] << ":  ";
            Real qK = allStrikes_[i];
            for (Size j=0; j<nMat; j++) {
                Real t = cfMaturityTimes_[j];
                std::cout << cP[i][j] << "," << capPrice_(t,qK) << " | " ;
            }
            std::cout << std::endl;
        }
        */
    }

    //! remember that the strike uses the quoting convention
    template<class I2D>
    Real InterpolatedCPICapFloorTermPriceSurface<I2D>::
    price(const Date &d, Rate k) const {
        
        Rate atm = zeroInflationIndex()->zeroInflationTermStructure()->zeroRate(d);
        return k > atm ? capPrice(d,k): floorPrice(d,k);
    }

    //! remember that the strike uses the quoting convention
    template<class I2D>
    Real InterpolatedCPICapFloorTermPriceSurface<I2D>::
    capPrice(const Date &d, Rate k) const {
        Time t = timeFromReference(d);
        return capPrice_(t,k);
    }

    //! remember that the strike uses the quoting convention
    template<class I2D>
    Real InterpolatedCPICapFloorTermPriceSurface<I2D>::
    floorPrice(const Date &d, Rate k) const {
        Time t = timeFromReference(d);
        return floorPrice_(t,k);
    }

    // inline

    inline Period CPICapFloorTermPriceSurface::observationLag() const {
        return zeroInflationIndex()->zeroInflationTermStructure()->observationLag();
    }

    inline Date CPICapFloorTermPriceSurface::baseDate() const {
        return zeroInflationIndex()->zeroInflationTermStructure()->baseDate();
    }

    inline Real CPICapFloorTermPriceSurface::nominal() const {
        return nominal_;
    }

    inline BusinessDayConvention
    CPICapFloorTermPriceSurface::businessDayConvention() const {
        return bdc_;
    }

}

#endif


<|start_filename|>ql/pricingengines/swaption/fdg2swaptionengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file fdg2swaptionengine.hpp
    \brief finite differences swaption engine
*/

#ifndef quantlib_fd_g2_swaption_engine_hpp
#define quantlib_fd_g2_swaption_engine_hpp

#include <ql/instruments/swaption.hpp>
#include <ql/pricingengines/genericmodelengine.hpp>
#include <ql/models/shortrate/twofactormodels/g2.hpp>
#include <ql/methods/finitedifferences/solvers/fdmbackwardsolver.hpp>

namespace QuantLib {

    class FdG2SwaptionEngine
        : public GenericModelEngine<G2,Swaption::arguments,Swaption::results> {
      public:
        FdG2SwaptionEngine(
            const boost::shared_ptr<G2>& model,
            Size tGrid = 100, Size xGrid = 50, Size yGrid = 50,
            Size dampingSteps = 0, Real invEps = 1e-5,
            const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer());

        void calculate() const;

      private:
        const Size tGrid_, xGrid_, yGrid_, dampingSteps_;
        const Real invEps_;
        const FdmSchemeDesc schemeDesc_;
    };
}
#endif


<|start_filename|>ql/math/statistics/generalstatistics.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2003 <NAME>
 Copyright (C) 2003 RiskMap srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/math/statistics/generalstatistics.hpp>
#include <ql/math/functional.hpp>

namespace QuantLib {

    Real GeneralStatistics::weightSum() const {
        Real result = 0.0;
        std::vector<std::pair<Real,Real> >::const_iterator it;
        for (it=samples_.begin(); it!=samples_.end(); ++it) {
            result += it->second;
        }
        return result;
    }

    Real GeneralStatistics::mean() const {
        Size N = samples();
        QL_REQUIRE(N != 0, "empty sample set");
        // eat our own dog food
        return expectationValue(identity<Real>(),
                                everywhere()).first;
    }

    Real GeneralStatistics::variance() const {
        Size N = samples();
        QL_REQUIRE(N > 1,
                   "sample number <=1, unsufficient");
        // Subtract the mean and square. Repeat on the whole range.
        // Hopefully, the whole thing will be inlined in a single loop.
        Real s2 = expectationValue(compose(square<Real>(),
                                           std::bind2nd(std::minus<Real>(),
                                                        mean())),
                                   everywhere()).first;
        return s2*N/(N-1.0);
    }

    Real GeneralStatistics::skewness() const {
        Size N = samples();
        QL_REQUIRE(N > 2,
                   "sample number <=2, unsufficient");

        Real x = expectationValue(compose(cube<Real>(),
                                          std::bind2nd(std::minus<Real>(),
                                                       mean())),
                                  everywhere()).first;
        Real sigma = standardDeviation();

        return (x/(sigma*sigma*sigma))*(N/(N-1.0))*(N/(N-2.0));
    }

    Real GeneralStatistics::kurtosis() const {
        Size N = samples();
        QL_REQUIRE(N > 3,
                   "sample number <=3, unsufficient");

        Real x = expectationValue(compose(fourth_power<Real>(),
                                          std::bind2nd(std::minus<Real>(),
                                                       mean())),
                                  everywhere()).first;
        Real sigma2 = variance();

        Real c1 = (N/(N-1.0)) * (N/(N-2.0)) * ((N+1.0)/(N-3.0));
        Real c2 = 3.0 * ((N-1.0)/(N-2.0)) * ((N-1.0)/(N-3.0));

        return c1*(x/(sigma2*sigma2))-c2;
    }

    Real GeneralStatistics::percentile(Real percent) const {

        QL_REQUIRE(percent > 0.0 && percent <= 1.0,
                   "percentile (" << percent << ") must be in (0.0, 1.0]");

        Real sampleWeight = weightSum();
        QL_REQUIRE(sampleWeight>0.0,
                   "empty sample set");

        sort();

        std::vector<std::pair<Real,Real> >::iterator k, l;
        k = samples_.begin();
        l = samples_.end()-1;
        /* the sum of weight is non null, therefore there's
           at least one sample */
        Real integral = k->second, target = percent*sampleWeight;
        while (integral < target && k != l) {
            ++k;
            integral += k->second;
        }
        return k->first;
    }

    Real GeneralStatistics::topPercentile(Real percent) const {

        QL_REQUIRE(percent > 0.0 && percent <= 1.0,
                   "percentile (" << percent << ") must be in (0.0, 1.0]");

        Real sampleWeight = weightSum();
        QL_REQUIRE(sampleWeight > 0.0,
                   "empty sample set");

        sort();

        std::vector<std::pair<Real,Real> >::reverse_iterator k, l;
        k = samples_.rbegin();
        l = samples_.rend()-1;
        /* the sum of weight is non null, therefore there's
           at least one sample */
        Real integral = k->second, target = percent*sampleWeight;
        while (integral < target && k != l) {
            ++k;
            integral += k->second;
        }
        return k->first;
    }

}


<|start_filename|>ql/instruments/claim.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/instruments/claim.hpp>

namespace QuantLib {

    Real FaceValueClaim::amount(const Date&,
                                Real notional,
                                Real recoveryRate) const {
        return notional * (1.0-recoveryRate);
    }



    FaceValueAccrualClaim::FaceValueAccrualClaim(
                          const boost::shared_ptr<Bond>& referenceSecurity)
    : referenceSecurity_(referenceSecurity) {
        registerWith(referenceSecurity);
    }

    Real FaceValueAccrualClaim::amount(const Date& d,
                                       Real notional,
                                       Real recoveryRate) const {
        Real accrual = referenceSecurity_->accruedAmount(d)
                     / referenceSecurity_->notional(d);
        return notional * (1.0-recoveryRate-accrual);
    }

}



<|start_filename|>ql/legacy/libormarketmodels/lfmcovarproxy.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2005, 2006 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/legacy/libormarketmodels/lfmcovarproxy.hpp>
#include <ql/math/integrals/kronrodintegral.hpp>

namespace QuantLib {
    LfmCovarianceProxy::LfmCovarianceProxy(
        const boost::shared_ptr<LmVolatilityModel>& volaModel,
        const boost::shared_ptr<LmCorrelationModel>& corrModel)

    : LfmCovarianceParameterization(corrModel->size(), corrModel->factors()),
      volaModel_(volaModel),
      corrModel_(corrModel) {

        QL_REQUIRE(volaModel_->size() == corrModel_->size(),
            "different size for the volatility (" << volaModel_->size() <<
            ") and correlation (" << corrModel_->size() <<
            ") models");
    }

    boost::shared_ptr<LmVolatilityModel>
    LfmCovarianceProxy::volatilityModel() const {
        return volaModel_;
    }

    boost::shared_ptr<LmCorrelationModel>
    LfmCovarianceProxy::correlationModel() const {
        return corrModel_;
    }

    Disposable<Matrix> LfmCovarianceProxy::diffusion(Time t,
                                                     const Array& x) const {

        Matrix pca = corrModel_->pseudoSqrt(t, x);
        Array  vol = volaModel_->volatility(t, x);
        for (Size i=0; i<size_; ++i) {
            std::transform(pca.row_begin(i), pca.row_end(i),
                           pca.row_begin(i),
                           std::bind2nd(std::multiplies<Real>(), vol[i]));
        }

        return pca;
    }

    Disposable<Matrix> LfmCovarianceProxy::covariance(Time t,
                                                      const Array& x) const {

        Array  volatility  = volaModel_->volatility(t, x);
        Matrix correlation = corrModel_->correlation(t, x);

        Matrix tmp(size_, size_);
        for (Size i=0; i<size_; ++i) {
            for (Size j=0; j<size_; ++j) {
                tmp[i][j] = volatility[i]*correlation[i][j]*volatility[j];
            }
        }

        return tmp;
    }

    class LfmCovarianceProxy::Var_Helper {
      public:
        Var_Helper(const LfmCovarianceProxy* proxy, Size i, Size j);

        Real operator()(Real t) const;
      private:
        const Size i_, j_;
        const LmVolatilityModel*  const volaModel_;
        const LmCorrelationModel* const corrModel_;
    };

    LfmCovarianceProxy::Var_Helper::Var_Helper(const LfmCovarianceProxy* proxy,
                                               Size i, Size j)
    : i_(i),
      j_(j),
      volaModel_(proxy->volaModel_.get()),
      corrModel_(proxy->corrModel_.get()) {
    }

    Real LfmCovarianceProxy::Var_Helper::operator()(Real t) const {
        Volatility v1, v2;

        if (i_ == j_) {
            v1 = v2 = volaModel_->volatility(i_, t);
        } else {
            v1 = volaModel_->volatility(i_, t);
            v2 = volaModel_->volatility(j_, t);
        }

        return  v1 * corrModel_->correlation(i_, j_, t) * v2;
    }

    Real LfmCovarianceProxy::integratedCovariance(
                               Size i, Size j, Time t, const Array& x) const {

        if (corrModel_->isTimeIndependent()) {
            try {
                // if all objects support these methods
                // thats by far the fastest way to get the
                // integrated covariance
                return corrModel_->correlation(i, j, 0.0, x)
                        * volaModel_->integratedVariance(j, i, t, x);
            }
            catch (Error&) {
                // okay proceed with the
                // slow numerical integration routine
            }
        }

        QL_REQUIRE(x.empty(), "can not handle given x here");

        Real tmp=0.0;
        Var_Helper helper(this, i, j);

        GaussKronrodAdaptive integrator(1e-10, 10000);
        for (Size k=0; k<64; ++k) {
            tmp+=integrator(helper, k*t/64., (k+1)*t/64.);
        }
        return tmp;
    }

}



<|start_filename|>ql/models/marketmodels/models/alphafinder.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2007 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/models/marketmodels/models/alphafinder.hpp>
#include <ql/math/quadratic.hpp>

namespace QuantLib {

namespace
{

    template<class T>
    Real Bisection(Real target,
                   Real low,
                   Real high,
                   Real tolerance,
                   T& theObject,
                   Real (T::*Value)(Real)) {

        Real x=0.5*(low+high);
        Real y=(theObject.*Value)(x);

        do {
            if (y < target) low = x;
            else if (y > target) high = x;

            x = 0.5*(low+high);
            y = (theObject.*Value)(x);
        } while ((std::fabs(high-low) > tolerance));

        return x;
    }

    template<class T>
    Real FindHighestOK(Real low,
                       Real high,
                       Real tolerance,
                       T& theObject,
                       bool (T::*Value)(Real)) {

        Real x=0.5*(low+high);
        bool ok=(theObject.*Value)(x);

        do {
            if (ok) low = x;
            else    high = x;

            x = 0.5*(low+high);
            ok = (theObject.*Value)(x);
        } while ((std::fabs(high-low) > tolerance));

        return x;
    }

    template<class T>
    Real FindLowestOK(Real low,
                      Real high,
                      Real tolerance,
                      T& theObject,
                      bool (T::*Value)(Real)) {

        Real x=0.5*(low+high);
        bool ok=(theObject.*Value)(x);

        do {
            if (ok) high = x;
            else    low = x;

            x = 0.5*(low+high);
            ok = (theObject.*Value)(x);
        } while ( (std::fabs(high-low) > tolerance) );

        return x;
    }


    template<class T>
    Real Minimize(Real low,
                  Real high,
                  Real tolerance,
                  T& theObject,
                  Real (T::*Value)(Real),
                  bool (T::*Condition)(Real),
                  bool& failed) {

        Real leftValue = (theObject.*Value)(low);
        Real rightValue = (theObject.*Value)(high);
        Real W = 0.5*(3.0-std::sqrt(5.0));
        Real x=W*low+(1-W)*high;
        Real midValue =  (theObject.*Value)(x);

        failed = true;

        while(high - low > tolerance) {

            if (x - low > high -x) // left interval is bigger
            {
                Real tentativeNewMid = W*low+(1-W)*x;
                Real tentativeNewMidValue =  (theObject.*Value)(tentativeNewMid);
                bool conditioner = (theObject.*Condition)(tentativeNewMidValue);
                if (!conditioner) {
                    if  ((theObject.*Condition)(x))
                        return x;
                    else
                        if (leftValue < rightValue)
                            return low;
                        else
                            return high;
                }

                if (tentativeNewMidValue < midValue) // go left
                {
                    high =x;
                    rightValue = midValue;
                    x = tentativeNewMid;
                    midValue = tentativeNewMidValue;
                }
                else // go right
                {
                    low = tentativeNewMid;
                    leftValue = tentativeNewMidValue;
                }
            }
            else
            {
                Real tentativeNewMid = W*x+(1-W)*high;
                Real tentativeNewMidValue =  (theObject.*Value)(tentativeNewMid);
                bool conditioner = (theObject.*Condition)(tentativeNewMidValue);
                if (!conditioner) {
                    if  ((theObject.*Condition)(x))
                        return x;
                    else
                        if (leftValue < rightValue)
                            return low;
                        else
                            return high;
                }

                if (tentativeNewMidValue < midValue) // go right
                {
                    low =x;
                    leftValue = midValue;
                    x = tentativeNewMid;
                    midValue = tentativeNewMidValue;
                }
                else // go left
                {
                    high = tentativeNewMid;
                    rightValue = tentativeNewMidValue;
                }
            }




            }
        failed = false;
        return x;
    }
}

    AlphaFinder::AlphaFinder(boost::shared_ptr<AlphaForm> parametricform)
    : parametricform_(parametricform) {}


    Real AlphaFinder::computeLinearPart(Real alpha) {
        Real cov =0.0;
        parametricform_->setAlpha(alpha);

        for (Integer i=0; i < stepindex_+1; ++i) {
            Real vol1 = ratetwohomogeneousvols_[i]*(*parametricform_)(i);
            cov += vol1*rateonevols_[i]*correlations_[i];
        }

        cov *= 2*w0_*w1_;
        return cov;
    }


    Real AlphaFinder::computeQuadraticPart(Real alpha) {
        Real var =0.0;
        parametricform_->setAlpha(alpha);

        for (Integer i=0; i < stepindex_+1; ++i) {
            Real vol = ratetwohomogeneousvols_[i]*(*parametricform_)(i);
            var+= vol*vol;
        }

        var *= w1_*w1_;
        return var;
    }

    Real AlphaFinder::homogeneityfailure(Real alpha) {
        Real dum1, dum2, dum3;
        finalPart(alpha,
                  stepindex_,
                  ratetwohomogeneousvols_,
                  computeQuadraticPart(alpha),
                  computeLinearPart(alpha),
                  constantPart_,
                  dum1,
                  dum2,
                  dum3,
                  putativevols_);

    Real result=0.0;
    for (Size i=0; i<=static_cast<Size>(stepindex_)+1; ++i) {
        Real val =  putativevols_[i]-ratetwohomogeneousvols_[i];
        result +=val*val;
    }

    return result;
}

    bool AlphaFinder::finalPart(Real alphaFound,
                                Integer stepindex,
                                const std::vector<Volatility>& ratetwohomogeneousvols,
                                Real quadraticPart,
                                Real linearPart,
                                Real constantPart,
                                Real& alpha,
                                Real& a,
                                Real& b,
                                std::vector<Volatility>& ratetwovols) {
            alpha = alphaFound;
            quadratic q2(quadraticPart, linearPart, constantPart-targetVariance_ );
            parametricform_->setAlpha(alpha);
            Real y; // dummy
            q2.roots(a,y);

            Real varSoFar=0.0;
            for (Integer i =0; i < stepindex+1; ++i) {
                ratetwovols[i] = ratetwohomogeneousvols[i] *
                                            (*parametricform_)(i) * a;
                varSoFar += ratetwovols[i]* ratetwovols[i];
            }

            Real VarToFind = totalVar_-varSoFar;
            if (VarToFind < 0)
                return false;
            Real requiredSd = std::sqrt(VarToFind);
            b = requiredSd / (ratetwohomogeneousvols[stepindex+1] *
                                            (*parametricform_)(stepindex));
            ratetwovols[stepindex+1] = requiredSd;
            return true;
    }

    Real AlphaFinder::valueAtTurningPoint(Real alpha) {

        linearPart_ = computeLinearPart(alpha);
        quadraticPart_ = computeQuadraticPart(alpha);

        quadratic q(quadraticPart_, linearPart_, constantPart_);
        Real valueAtTP =q.valueAtTurningPoint();
        return valueAtTP;
    }

    Real AlphaFinder::minusValueAtTurningPoint(Real alpha) {
        return -valueAtTurningPoint(alpha);
    }

    bool AlphaFinder::testIfSolutionExists(Real alpha) {
        bool aExists =  valueAtTurningPoint(alpha)<targetVariance_;
        if (!aExists)
            return false;

        Real dum1, dum2, dum3;
        return finalPart(alpha,
                         stepindex_,
                         ratetwohomogeneousvols_,
                         computeQuadraticPart(alpha),
                         computeLinearPart(alpha),
                         constantPart_,
                         dum1,
                         dum2,
                         dum3,
                         putativevols_);
    }

    bool AlphaFinder::solve(Real alpha0,
                            Integer stepindex, // caplet index
                            const std::vector<Volatility>& rateonevols,
                            const std::vector<Volatility>& ratetwohomogeneousvols,
                            const std::vector<Real>& correlations,
                            Real w0,
                            Real w1,
                            Real targetVariance,
                            Real tolerance,
                            Real alphaMax,
                            Real alphaMin,
                            Integer steps,
                            Real& alpha,
                            Real& a,
                            Real& b,
                            std::vector<Volatility>& ratetwovols) {
        stepindex_=stepindex;
        rateonevols_=rateonevols;
        ratetwohomogeneousvols_=ratetwohomogeneousvols;
        correlations_=correlations;
        w0_=w0;
        w1_=w1;
        totalVar_=0;
        for (Size i=0; i <=static_cast<Size>(stepindex)+1; ++i)
            totalVar_+=ratetwohomogeneousvols[i]*ratetwohomogeneousvols[i];
        targetVariance_ = targetVariance;

        // constant part will not depend on alpha

        constantPart_ =0.0;
        for (Integer i=0; i < stepindex+1; ++i)
                constantPart_+=rateonevols[i]*rateonevols[i];

        constantPart_ *= w0*w0;

        // compute linear part with initial alpha
        Real valueAtTP = valueAtTurningPoint(alpha0);

        if (valueAtTP <= targetVariance) {
            finalPart(alpha0,
                      stepindex,
                      ratetwohomogeneousvols,
                      quadraticPart_,
                      linearPart_,
                      constantPart_,
                      alpha,
                      a,
                      b,
                      ratetwovols);
            return true;
        }

        // we now have to solve
        Real bottomValue = valueAtTurningPoint(alphaMin);
        Real bottomAlpha = alphaMin;
        Real topValue = valueAtTurningPoint(alphaMax);
        Real topAlpha = alphaMax;
        Real bilimit = alpha0;

        if (bottomValue > targetVariance && topValue > targetVariance) {
            // see if if ok at some intermediate point by stepping through
            Integer i=1;
            while ( i < steps && topValue> targetVariance) {
                topAlpha = alpha0 + (alphaMax-alpha0)*(i+0.0)/(steps+0.0);
                topValue=valueAtTurningPoint(topAlpha);
                ++i;
            }

            if (topValue <= targetVariance)
                bilimit = alpha0 + (topAlpha-alpha0)*(i-2.0)/(steps+0.0);
        }

        if (bottomValue > targetVariance && topValue > targetVariance) {
            // see if if ok at some intermediate point by stepping through
            Integer i=1;
            while ( i < steps && topValue> targetVariance) {
                bottomAlpha = alpha0 + (alphaMin-alpha0)*(i+0.0)/(steps+0.0);
                bottomValue=valueAtTurningPoint(bottomAlpha);
                ++i;
            }

            if (bottomValue <= targetVariance)
                bilimit = alpha0 +(bottomAlpha-alpha0)*(i-2.0)/(steps+0.0);
        }

        if (bottomValue > targetVariance && topValue > targetVariance)
            return false;

        if (bottomValue <= targetVariance) {
            // then find root of increasing function
            // (or as if increasing function)
            alpha = Bisection<AlphaFinder>(
                                           targetVariance,
                                           bottomAlpha,
                                           bilimit,
                                           tolerance,
                                           *this,
                                           &AlphaFinder::valueAtTurningPoint);
        } else {
            // find root of decreasing function (or as if decreasing function)
            alpha=Bisection<AlphaFinder>(
                                         -targetVariance,
                                         bilimit,
                                         topAlpha,
                                         tolerance,
                                         *this,
                                         &AlphaFinder::minusValueAtTurningPoint);
        }
        finalPart(alpha,
                  stepindex,
                  ratetwohomogeneousvols,
                  quadraticPart_,
                  linearPart_,
                  constantPart_,
                  alpha,
                  a,
                  b,
                  ratetwovols);
        return true;
    }

    bool AlphaFinder::solveWithMaxHomogeneity(
                        Real alpha0,
                        Integer stepindex, // caplet index
                        const std::vector<Volatility>& rateonevols,
                        const std::vector<Volatility>& ratetwohomogeneousvols,
                        const std::vector<Real>& correlations,
                        Real w0,
                        Real w1,
                        Real targetVariance,
                        Real tolerance,
                        Real alphaMax,
                        Real alphaMin,
                        Integer steps,
                        Real& alpha,
                        Real& a,
                        Real& b,
                        std::vector<Volatility>& ratetwovols) {

        stepindex_=stepindex;
        rateonevols_=rateonevols;
        ratetwohomogeneousvols_=ratetwohomogeneousvols;
        putativevols_.resize(ratetwohomogeneousvols_.size());
        correlations_=correlations;
        w0_=w0;
        w1_=w1;
        totalVar_=0;
        for (Size i=0; i <=static_cast<Size>(stepindex)+1; ++i)
            totalVar_+=ratetwohomogeneousvols[i]*ratetwohomogeneousvols[i];
        targetVariance_=targetVariance;

        // constant part will not depend on alpha

        constantPart_ =0.0;
        for (Integer i=0; i < stepindex+1; ++i)
            constantPart_+=rateonevols[i]*rateonevols[i];

        constantPart_ *= w0*w0;

        Real alpha1 = alphaMin;
        Real alpha2 = alphaMax;

        // compute linear part with initial alpha
        bool alpha0OK = testIfSolutionExists(alpha0);
        bool alphaMaxOK = testIfSolutionExists(alphaMax);
        bool alphaMinOK = testIfSolutionExists(alphaMin);

        bool foundOKPoint = alpha0OK || alphaMaxOK || alphaMinOK;

        if (foundOKPoint) {
            if (!alphaMinOK) {
                // lower alpha is bad
                if (alpha0OK) {
                    // must die somewhere in between
                    alpha1 = FindLowestOK<AlphaFinder>(
                         alphaMin,
                         alpha0,
                         tolerance,
                        *this,
                         &AlphaFinder::testIfSolutionExists);
                } else {
                    // alphaMaxOK must be true to get here
                    alpha1 = FindLowestOK<AlphaFinder>(
                         alpha0,
                         alphaMax,
                         tolerance,
                        *this,
                         &AlphaFinder::testIfSolutionExists);
                }
            }


            if (!alphaMaxOK) {
                // higher alpha is bad
                alpha2 = FindHighestOK<AlphaFinder>(
                     alpha1,
                     alphaMax,
                     tolerance,
                     *this,
                     &AlphaFinder::testIfSolutionExists);
            } else
                alpha2= alphaMax;
            }
        else {
            // ok let's see if we can find a value of alpha that works
            bool foundUpOK = false;
            bool foundDownOK = false;
            Real alphaUp = alpha0, alphaDown = alpha0;
            Real stepSize = (alphaMax-alpha0)/steps;

            for (Size j=0;
                 j<static_cast<Size>(steps) && !foundUpOK && !foundDownOK;
                 ++j) {
                alphaUp = alpha0+j*stepSize;
                foundUpOK=testIfSolutionExists(alphaUp);
                alphaDown = alpha0-j*stepSize;
                foundDownOK=testIfSolutionExists(alphaDown);
            }
            foundOKPoint = foundUpOK || foundDownOK;
            if (!foundOKPoint)
                return false;

            if (foundUpOK) {
                alpha1 = alphaUp;
                alpha2 = FindHighestOK<AlphaFinder>(
                     alpha1,
                     alphaMax,
                     tolerance,
                     *this,
                     &AlphaFinder::testIfSolutionExists);
            } else {
                alpha2 = alphaDown;
                alpha1 = FindLowestOK<AlphaFinder>(
                     alphaMin,
                     alpha2,
                     tolerance,
                    *this,
                     &AlphaFinder::testIfSolutionExists);
            }
        }

        // we have now found alpha1, alpha2 such that solution exists
        // at endpoints. we now want to minimize within that interval
        bool failed;
        alpha =  Minimize<AlphaFinder>(
                                        alpha1,
                                        alpha2,
                                        tolerance,
                                        *this,
                                        &AlphaFinder::homogeneityfailure,
                                        &AlphaFinder::testIfSolutionExists,
                                        failed) ;

        finalPart(alpha,
                  stepindex,
                  ratetwohomogeneousvols,
                  computeQuadraticPart(alpha),
                  computeLinearPart(alpha),
                  constantPart_,
                  alpha,
                  a,
                  b,
                  ratetwovols);

        return true;;
    }
}


<|start_filename|>ql/pricingengines/blackscholescalculator.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2006 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/pricingengines/blackscholescalculator.hpp>

namespace QuantLib {

    BlackScholesCalculator::BlackScholesCalculator(
                        const boost::shared_ptr<StrikedTypePayoff>& payoff,
                        Real spot,
                        DiscountFactor growth,
                        Real stdDev,
                        DiscountFactor discount)
    : BlackCalculator(payoff, spot*growth/discount, stdDev, discount),
      spot_(spot), growth_(growth)
    {
        QL_REQUIRE(spot_>0.0,
                   "spot (" << spot_ << ") must be positive");
        QL_REQUIRE(growth_>0.0,
                   "growth (" << growth_ << ") must be positive");
    }

    BlackScholesCalculator::BlackScholesCalculator(Option::Type type,
                                                   Real strike,
                                                   Real spot,
                                                   DiscountFactor growth,
                                                   Real stdDev,
                                                   DiscountFactor discount)
    : BlackCalculator(type, strike, spot*growth/discount, stdDev, discount),
      spot_(spot), growth_(growth)
    {
        QL_REQUIRE(spot_>0.0,
                   "spot (" << spot_ << ") must be positive");
        QL_REQUIRE(growth_>0.0,
                   "growth (" << growth_ << ") must be positive");
    }

}


<|start_filename|>ql/experimental/mcbasket/pathmultiassetoption.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/experimental/mcbasket/pathmultiassetoption.hpp>
#include <ql/processes/stochasticprocessarray.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/math/solvers1d/brent.hpp>
#include <ql/event.hpp>

namespace QuantLib {

    PathMultiAssetOption::PathMultiAssetOption(
                            const boost::shared_ptr<PricingEngine>& engine) {
        if (engine)
            setPricingEngine(engine);
    }

    bool PathMultiAssetOption::isExpired() const {
        return detail::simple_event(fixingDates().back()).hasOccurred();
    }

    void PathMultiAssetOption::setupExpired() const {
        NPV_ = 0.0;
    }

    void PathMultiAssetOption::setupArguments(PricingEngine::arguments* args)
                                                                       const {
        PathMultiAssetOption::arguments* arguments =
            dynamic_cast<PathMultiAssetOption::arguments*>(args);

        QL_REQUIRE(arguments != 0, "wrong argument type");

        arguments->payoff            = pathPayoff();
        arguments->fixingDates       = fixingDates();
    }

    void PathMultiAssetOption::arguments::validate() const {
        QL_REQUIRE(payoff,                 "no payoff given");
        QL_REQUIRE(fixingDates.size() > 0, "no dates given");
    }
}



<|start_filename|>ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2011 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file fdhullwhiteswaptionengine.hpp
    \brief finite differences swaption engine
*/

#ifndef quantlib_fd_hull_white_swaption_engine_hpp
#define quantlib_fd_hull_white_swaption_engine_hpp

#include <ql/instruments/swaption.hpp>
#include <ql/pricingengines/genericmodelengine.hpp>
#include <ql/models/shortrate/onefactormodels/hullwhite.hpp>
#include <ql/methods/finitedifferences/solvers/fdmbackwardsolver.hpp>

namespace QuantLib {

    class FdHullWhiteSwaptionEngine
        : public GenericModelEngine<HullWhite, 
                                    Swaption::arguments, Swaption::results> {
      public:
        FdHullWhiteSwaptionEngine(
            const boost::shared_ptr<HullWhite>& model,
            Size tGrid = 100, Size xGrid = 100,
            Size dampingSteps = 0, Real invEps = 1e-5,
            const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas());

        void calculate() const;

      private:
        const Size tGrid_, xGrid_, dampingSteps_;
        const Real invEps_;
        const FdmSchemeDesc schemeDesc_;
    };
}

#endif



<|start_filename|>ql/experimental/commodities/commoditytype.hpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file commodity.hpp
    \brief commodity type
*/

#ifndef quantlib_commodity_type_hpp
#define quantlib_commodity_type_hpp

#include <ql/qldefines.hpp>
#include <boost/shared_ptr.hpp>
#include <map>
#include <iosfwd>
#include <string>

namespace QuantLib {

    //! commodity type
    class CommodityType {
      public:
        //! default constructor
        /*! Instances built via this constructor have undefined
          behavior. Such instances can only act as placeholders
          and must be reassigned to a valid currency before being
          used.
        */
        CommodityType() {}
        CommodityType(const std::string& code, const std::string& name);
        //! \name Inspectors
        //@{
        //! commodity code, e.g, "HO"
        const std::string& code() const;
        //! name, e.g, "Heating Oil"
        const std::string& name() const;
        // commodity code
        //@}
        //! \name Other information
        //@{
        //! is this a usable instance?
        bool empty() const;
        //@}

      protected:
        struct Data;
        boost::shared_ptr<Data> data_;

        struct Data {
            std::string name, code;

            Data(const std::string& name,
                 const std::string& code)
            : name(name), code(code) {}
        };

        static std::map<std::string, boost::shared_ptr<Data> > commodityTypes_;
    };

    /*! \relates CommodityType */
    bool operator==(const CommodityType&,
                    const CommodityType&);

    /*! \relates CommodityType */
    bool operator!=(const CommodityType&,
                    const CommodityType&);

    /*! \relates CommodityType */
    std::ostream& operator<<(std::ostream&,
                             const CommodityType&);


    class NullCommodityType : public CommodityType {
      public:
        NullCommodityType() :
        CommodityType("<NULL>", "<NULL>") {}
    };


    inline const std::string& CommodityType::code() const {
        return data_->code;
    }

    inline const std::string& CommodityType::name() const {
        return data_->name;
    }

    inline bool CommodityType::empty() const {
        return !data_;
    }

    inline bool operator==(const CommodityType& c1, const CommodityType& c2) {
        return c1.code() == c2.code();
    }

    inline bool operator!=(const CommodityType& c1, const CommodityType& c2) {
        return !(c1 == c2);
    }

}


#endif


<|start_filename|>ql/instruments/multiassetoption.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004 <NAME>
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
 Copyright (C) 2007 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/instruments/multiassetoption.hpp>
#include <ql/stochasticprocess.hpp>
#include <ql/exercise.hpp>
#include <ql/event.hpp>

namespace QuantLib {

    MultiAssetOption::MultiAssetOption(
        const boost::shared_ptr<Payoff>& payoff,
        const boost::shared_ptr<Exercise>& exercise)
    : Option(payoff, exercise) {}

    bool MultiAssetOption::isExpired() const {
        return detail::simple_event(exercise_->lastDate()).hasOccurred();
    }

    Real MultiAssetOption::delta() const {
        calculate();
        QL_REQUIRE(delta_ != Null<Real>(), "delta not provided");
        return delta_;
    }

    Real MultiAssetOption::gamma() const {
        calculate();
        QL_REQUIRE(gamma_ != Null<Real>(), "gamma not provided");
        return gamma_;
    }

    Real MultiAssetOption::theta() const {
        calculate();
        QL_REQUIRE(theta_ != Null<Real>(), "theta not provided");
        return theta_;
    }

    Real MultiAssetOption::vega() const {
        calculate();
        QL_REQUIRE(vega_ != Null<Real>(), "vega not provided");
        return vega_;
    }

    Real MultiAssetOption::rho() const {
        calculate();
        QL_REQUIRE(rho_ != Null<Real>(), "rho not provided");
        return rho_;
    }

    Real MultiAssetOption::dividendRho() const {
        calculate();
        QL_REQUIRE(dividendRho_ != Null<Real>(), "dividend rho not provided");
        return dividendRho_;
    }

    void MultiAssetOption::setupExpired() const {
        NPV_ = delta_ = gamma_ = theta_ =
            vega_ = rho_ = dividendRho_ =  0.0;
    }

    void MultiAssetOption::setupArguments(
                                       PricingEngine::arguments* args) const {
        MultiAssetOption::arguments* arguments =
            dynamic_cast<MultiAssetOption::arguments*>(args);
        QL_REQUIRE(arguments != 0, "wrong argument type");

        arguments->payoff = payoff_;
        arguments->exercise = exercise_;
    }

    void MultiAssetOption::fetchResults(const PricingEngine::results* r) const {
        Option::fetchResults(r);
        const Greeks* results = dynamic_cast<const Greeks*>(r);
        QL_ENSURE(results != 0,
                  "no greeks returned from pricing engine");
        delta_          = results->delta;
        gamma_          = results->gamma;
        theta_          = results->theta;
        vega_           = results->vega;
        rho_            = results->rho;
        dividendRho_    = results->dividendRho;
    }

}


<|start_filename|>ql/experimental/coupons/subperiodcoupons.cpp<|end_filename|>
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2008 <NAME>

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <<EMAIL>>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/experimental/coupons/subperiodcoupons.hpp>
#include <ql/cashflows/cashflowvectors.hpp>
#include <ql/time/schedule.hpp>
#include <ql/indexes/iborindex.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>
#include <cmath>

namespace QuantLib {

    SubPeriodsCoupon::SubPeriodsCoupon(
                                    const Date& paymentDate,
                                    Real nominal,
                                    const boost::shared_ptr<IborIndex>& index,
                                    const Date& startDate,
                                    const Date& endDate,
                                    Natural fixingDays,
                                    const DayCounter& dayCounter,
                                    Real gearing,
                                    Rate couponSpread,
                                    Rate rateSpread,
                                    const Date& refPeriodStart,
                                    const Date& refPeriodEnd)
    : FloatingRateCoupon(paymentDate, nominal, startDate, endDate,
                         fixingDays, index, gearing, couponSpread,
                         refPeriodStart, refPeriodEnd, dayCounter),
      rateSpread_(rateSpread) {
        const Handle<YieldTermStructure>& rateCurve =
            index->forwardingTermStructure();
        const Date& referenceDate = rateCurve->referenceDate();

        observationsSchedule_ = boost::shared_ptr<Schedule>(new
            Schedule(startDate, endDate,
                     index->tenor(),
                     NullCalendar(),
                     Unadjusted,
                     Unadjusted,
                     DateGeneration::Forward,
                     false));

        observationDates_ = observationsSchedule_->dates();
        observationDates_.pop_back();                       //remove end date
        observations_ = observationDates_.size();

        startTime_ = dayCounter.yearFraction(referenceDate, startDate);
        endTime_ = dayCounter.yearFraction(referenceDate, endDate);

        for (Size i=0; i<observations_; ++i) {
            observationTimes_.push_back(
                dayCounter.yearFraction(referenceDate, observationDates_[i]));
        }
     }

    void SubPeriodsCoupon::accept(AcyclicVisitor& v) {
        Visitor<SubPeriodsCoupon>* v1 =
            dynamic_cast<Visitor<SubPeriodsCoupon>*>(&v);
        if (v1 != 0)
            v1->visit(*this);
        else
            FloatingRateCoupon::accept(v);
    }


    void SubPeriodsPricer::initialize(const FloatingRateCoupon& coupon) {
        coupon_ =  dynamic_cast<const SubPeriodsCoupon*>(&coupon);
        QL_REQUIRE(coupon_, "sub-periods coupon required");
        gearing_ = coupon_->gearing();
        spread_ = coupon_->spread();

        Date paymentDate = coupon_->date();

        boost::shared_ptr<IborIndex> index =
            boost::dynamic_pointer_cast<IborIndex>(coupon_->index());
        const Handle<YieldTermStructure>& rateCurve =
            index->forwardingTermStructure();
        discount_ = rateCurve->discount(paymentDate);
        accrualFactor_ = coupon_->accrualPeriod();
        spreadLegValue_ = spread_ * accrualFactor_* discount_;

        startTime_ = coupon_->startTime();
        endTime_ = coupon_->endTime();
        observationTimes_ = coupon_->observationTimes();
        observations_ = coupon_->observations();

        const std::vector<Date>& observationDates =
            coupon_->observationsSchedule()->dates();

        QL_REQUIRE(observationDates.size()==observations_+2,
                   "incompatible size of initialValues vector");

        initialValues_ = std::vector<Real>(observationDates.size(),0.);

        observationCvg_ = std::vector<Real>(observationDates.size(),0.);

        observationIndexStartDates_ =
            std::vector<Date>(observationDates.size());
        observationIndexEndDates_ =
            std::vector<Date>(observationDates.size());

        Calendar calendar = index->fixingCalendar();

        for(Size i=0; i<observationDates.size(); i++) {
            Date fixingDate = calendar.advance(
                                 observationDates[i],
                                 -static_cast<Integer>(coupon_->fixingDays()),
                                 Days);

            initialValues_[i] =
                index->fixing(fixingDate) + coupon_->rateSpread();

            Date fixingValueDate = index->valueDate(fixingDate);
            Date endValueDate = index->maturityDate(fixingValueDate);

            observationIndexStartDates_[i] = fixingValueDate;
            observationIndexEndDates_[i] = endValueDate;

            observationCvg_[i] =
                index->dayCounter().yearFraction(fixingValueDate, endValueDate);
        }
    }

    Real SubPeriodsPricer::swapletRate() const {
        return swapletPrice()/(accrualFactor_*discount_);
    }

    Real SubPeriodsPricer::capletPrice(Rate) const {
        QL_FAIL("SubPeriodsPricer::capletPrice not implemented");
    }

    Rate SubPeriodsPricer::capletRate(Rate) const {
        QL_FAIL("SubPeriodsPricer::capletRate not implemented");
    }

    Real SubPeriodsPricer::floorletPrice(Rate) const {
        QL_FAIL("SubPeriodsPricer::floorletPrice not implemented");
    }

    Rate SubPeriodsPricer::floorletRate(Rate) const {
        QL_FAIL("SubPeriodsPricer::floorletRate not implemented");
    }

    Real AveragingRatePricer::swapletPrice() const {
        // past or future fixing is managed in InterestRateIndex::fixing()

        Size nCount = initialValues_.size();
        Real dAvgRate = 0.0, dTotalCvg = 0.0, dTotalPayment = 0.0;
        for (Size i=0; i<nCount; i++) {
            dTotalPayment += initialValues_[i] * observationCvg_[i];
            dTotalCvg += observationCvg_[i];
        }

        dAvgRate =  dTotalPayment/dTotalCvg;

        Real swapletPrice = dAvgRate*coupon_->accrualPeriod()*discount_;
        return gearing_ * swapletPrice + spreadLegValue_;
    }

    Real CompoundingRatePricer::swapletPrice() const {
        // past or future fixing is managed in InterestRateIndex::fixing()

        Real dNotional = 1.0;

        Size nCount = initialValues_.size();
        Real dCompRate = 0.0, dTotalCvg = 0.0, dTotalPayment = 0.0;
        for (Size i=0; i<nCount; i++) {
            dTotalPayment = initialValues_[i] * observationCvg_[i]*dNotional;
            dNotional += dTotalPayment;
            dTotalCvg += observationCvg_[i];
        }

        dCompRate = (dNotional - 1.0)/dTotalCvg;

        Real swapletPrice = dCompRate*coupon_->accrualPeriod()*discount_;
        return gearing_ * swapletPrice + spreadLegValue_;
    }

}

