Real AnalyticDoubleBarrierEngine::putKO() const {
       Real mu1 = 2 * costOfCarry() / volatilitySquared() + 1;
       Real bsigma = (costOfCarry() + volatilitySquared() / 2.0) * residualTime() / stdDeviation();

       Real acc1 = 0;
       Real acc2 = 0;
       for (int n = -series_ ; n <= series_ ; ++n) {
          Real L2n = std::pow(barrierLo(), 2 * n);
          Real U2n = std::pow(barrierHi(), 2 * n);
          Real y1 = std::log( underlying()* U2n / (std::pow(barrierLo(), 2 * n + 1)) ) / stdDeviation() + bsigma;
          Real y2 = std::log( underlying()* U2n / (strike() * L2n) ) / stdDeviation() + bsigma;
          Real y3 = std::log( std::pow(barrierLo(), 2 * n + 2) / (barrierLo() * underlying() * U2n) ) / stdDeviation() + bsigma;
          Real y4 = std::log( std::pow(barrierLo(), 2 * n + 2) / (strike() * underlying() * U2n) ) / stdDeviation() + bsigma;

          acc1 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1-2) * 
                  (f_(y1 - stdDeviation()) - f_(y2 - stdDeviation())) -
                  std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1-2 ) * 
                  (f_(y3-stdDeviation()) - f_(y4-stdDeviation()));

          acc2 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1 ) * 
                  (f_(y1) - f_(y2)) -
                  std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1 ) * 
                  (f_(y3) - f_(y4));

       }

       Real rend = std::exp(-dividendYield() * residualTime());
       Real kov = strike() * riskFreeDiscount() * acc1 - underlying() * rend  * acc2;
       return std::max(0.0, kov);
    }
예제 #2
0
    void ForwardVanillaEngine<Engine>::setup() const {

        ext::shared_ptr<StrikedTypePayoff> argumentsPayoff =
            ext::dynamic_pointer_cast<StrikedTypePayoff>(
                this->arguments_.payoff);
        QL_REQUIRE(argumentsPayoff, "wrong payoff given");

        ext::shared_ptr<StrikedTypePayoff> payoff(
                   new PlainVanillaPayoff(argumentsPayoff->optionType(),
                                          this->arguments_.moneyness *
                                          process_->x0()));

        // maybe the forward value is "better", in some fashion
        // the right level is needed in order to interpolate
        // the vol
        Handle<Quote> spot = process_->stateVariable();
        QL_REQUIRE(spot->value() >= 0.0, "negative or null underlting given");
        Handle<YieldTermStructure> dividendYield(
            ext::shared_ptr<YieldTermStructure>(
               new ImpliedTermStructure(process_->dividendYield(),
                                        this->arguments_.resetDate)));
        Handle<YieldTermStructure> riskFreeRate(
            ext::shared_ptr<YieldTermStructure>(
               new ImpliedTermStructure(process_->riskFreeRate(),
                                        this->arguments_.resetDate)));
        // The following approach is ok if the vol is at most
        // time dependant. It is plain wrong if it is asset dependant.
        // In the latter case the right solution would be stochastic
        // volatility or at least local volatility (which unfortunately
        // implies an unrealistic time-decreasing smile)
        Handle<BlackVolTermStructure> blackVolatility(
            ext::shared_ptr<BlackVolTermStructure>(
                new ImpliedVolTermStructure(process_->blackVolatility(),
                                            this->arguments_.resetDate)));

        ext::shared_ptr<GeneralizedBlackScholesProcess> fwdProcess(
                       new GeneralizedBlackScholesProcess(spot, dividendYield,
                                                          riskFreeRate,
                                                          blackVolatility));

        originalEngine_ = ext::shared_ptr<Engine>(new Engine(fwdProcess));
        originalEngine_->reset();

        originalArguments_ =
            dynamic_cast<VanillaOption::arguments*>(
                                             originalEngine_->getArguments());
        QL_REQUIRE(originalArguments_, "wrong engine type");
        originalResults_ =
            dynamic_cast<const VanillaOption::results*>(
                                               originalEngine_->getResults());
        QL_REQUIRE(originalResults_, "wrong engine type");

        originalArguments_->payoff = payoff;
        originalArguments_->exercise = this->arguments_.exercise;

        originalArguments_->validate();
    }
    Real AnalyticComplexChooserEngine::ComplexChooser() const{
        Real S = process_->x0();
        Real b;
        Real v;
        Real r = riskFreeRate(choosingTime());
        Real Xc = arguments_.strikeCall;
        Real Xp = arguments_.strikePut;
        Time T = choosingTime();
        Time Tc = callMaturity()-choosingTime();
        Time Tp = putMaturity()-choosingTime();

        Real i = CriticalValueChooser();

        b = riskFreeRate(choosingTime()) - dividendYield(choosingTime());
        v = volatility(T);
        Real d1 = (log(S / i) + (b + pow(v, 2) / 2)*T) / (v*sqrt(T));
        Real d2 = d1 - v*sqrt(T);

        b = riskFreeRate(callMaturity()) - dividendYield(callMaturity());
        v = volatility(Tc);
        Real y1 = (log(S / Xc) + (b + pow(v, 2) / 2)*Tc) / (v*sqrt(Tc));

        b = riskFreeRate(putMaturity()) - dividendYield(putMaturity());
        v = volatility(Tp);
        Real y2 = (log(S / Xp) + (b + pow(v, 2) / 2)*Tp) / (v*sqrt(Tp));

        Real rho1 = sqrt(T / Tc);
        Real rho2 = sqrt(T / Tp);
        b = riskFreeRate(callMaturity()) - dividendYield(callMaturity());
        r = riskFreeRate(callMaturity());
        Real ComplexChooser = S * exp((b - r)*Tc) *  BivariateCumulativeNormalDistributionDr78(rho1)(d1, y1)
            - Xc * exp(-r*Tc)*BivariateCumulativeNormalDistributionDr78(rho1)(d2, y1 - v * sqrt(Tc)) ;
        b = riskFreeRate(putMaturity()) - dividendYield(putMaturity());
        r = riskFreeRate(putMaturity());
        ComplexChooser-= S * exp((b - r)*Tp) * BivariateCumulativeNormalDistributionDr78(rho2)(-d1, -y2);
        ComplexChooser+= Xp * exp(-r*Tp) * BivariateCumulativeNormalDistributionDr78(rho2)(-d2, -y2 + v * sqrt(Tp));
        return ComplexChooser;
    }
예제 #4
0
    Disposable<Array> HestonSLVProcess::drift(Time t, const Array& x) const {
        Array tmp(2);

        const Real s = std::exp(x[0]);
        const Volatility vol
            = std::sqrt(x[1])*leverageFct_->localVol(t, s, true);

        tmp[0] = riskFreeRate()->forwardRate(t, t, Continuous)
               - dividendYield()->forwardRate(t, t, Continuous)
               - 0.5*vol*vol;

        tmp[1] = kappa_*(theta_ - x[1]);

        return tmp;
    }
 Real AnalyticContinuousFloatingLookbackEngine::A(Real eta) const {
     Volatility vol = volatility();
     Real lambda = 2.0*(riskFreeRate() - dividendYield())/(vol*vol);
     Real s = underlying()/minmax();
     Real d1 = std::log(s)/stdDeviation() + 0.5*(lambda+1.0)*stdDeviation();
     Real n1 = f_(eta*d1);
     Real n2 = f_(eta*(d1-stdDeviation()));
     Real n3 = f_(eta*(-d1+lambda*stdDeviation()));
     Real n4 = f_(eta*-d1);
     Real pow_s = std::pow(s, -lambda);
     return eta*((underlying() * dividendDiscount() * n1 -
                 minmax() * riskFreeDiscount() * n2) +
                 (underlying() * riskFreeDiscount() *
                 (pow_s * n3 - dividendDiscount()* n4/riskFreeDiscount())/
         lambda));
 }
예제 #6
0
    Disposable<Array> HestonSLVProcess::evolve(
        Time t0, const Array& x0, Time dt, const Array& dw) const {
        Array retVal(2);

        const Real ex = std::exp(-kappa_*dt);

        const Real m  =  theta_+(x0[1]-theta_)*ex;
        const Real s2 =  x0[1]*sigma_*sigma_*ex/kappa_*(1-ex)
                       + theta_*sigma_*sigma_/(2*kappa_)*(1-ex)*(1-ex);
        const Real psi = s2/(m*m);

        if (psi < 1.5) {
            const Real b2 = 2/psi-1+std::sqrt(2/psi*(2/psi-1));
            const Real b  = std::sqrt(b2);
            const Real a  = m/(1+b2);

            retVal[1] = a*(b+dw[1])*(b+dw[1]);
        }
        else {
            const Real p = (psi-1)/(psi+1);
            const Real beta = (1-p)/m;
            const Real u = CumulativeNormalDistribution()(dw[1]);

            retVal[1] = ((u <= p) ? 0.0 : std::log((1-p)/(1-u))/beta);
        }

        const Real mu = riskFreeRate()->forwardRate(t0, t0+dt, Continuous)
             - dividendYield()->forwardRate(t0, t0+dt, Continuous);

        const Real rho1 = std::sqrt(1-rho_*rho_);

        const Volatility l_0 = leverageFct_->localVol(t0, x0[0], true);
        const Real v_0 = 0.5*(x0[1]+retVal[1])*l_0*l_0;

        retVal[0] = x0[0]*std::exp(mu*dt - 0.5*v_0*dt
            + rho_/sigma_*l_0 * (
                  retVal[1] - kappa_*theta_*dt
                  + 0.5*(x0[1]+retVal[1])*kappa_*dt - x0[1])
            + rho1*std::sqrt(v_0*dt)*dw[0]);

        return retVal;
    }
 Rate AnalyticBarrierEngine::mu() const {
     Volatility vol = volatility();
     return (riskFreeRate() - dividendYield())/(vol * vol) - 0.5;
 }
예제 #8
0
    void FFTEngine::precalculate(const std::vector<boost::shared_ptr<Instrument> >& optionList) {
        // Group payoffs by expiry date
        // as with FFT we can compute a bunch of these at once
        resultMap_.clear();

        typedef std::vector<boost::shared_ptr<StrikedTypePayoff> > PayoffList;
        typedef std::map<Date, PayoffList> PayoffMap;
        PayoffMap payoffMap;
        
        for (std::vector<boost::shared_ptr<Instrument> >::const_iterator optIt = optionList.begin();
            optIt != optionList.end(); optIt++)
        {
            boost::shared_ptr<VanillaOption> option = boost::dynamic_pointer_cast<VanillaOption>(*optIt);
            QL_REQUIRE(option, "instrument must be option");
            QL_REQUIRE(option->exercise()->type() == Exercise::European,
                "not an European Option");

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

            payoffMap[option->exercise()->lastDate()].push_back(payoff);
        }

        std::complex<Real> i1(0, 1);
        Real alpha = 1.25;

        for (PayoffMap::const_iterator payIt = payoffMap.begin(); payIt != payoffMap.end(); payIt++)
        {
            Date expiryDate = payIt->first;

            // Calculate n large enough for maximum strike, and round up to a power of 2
            Real maxStrike = 0.0;
            for (PayoffList::const_iterator it = payIt->second.begin();
                it != payIt->second.end(); it++)
            {
                boost::shared_ptr<StrikedTypePayoff> payoff = *it;

                if (payoff->strike() > maxStrike)
                    maxStrike = payoff->strike();
            }
            Real nR = 2.0 * (std::log(maxStrike) + lambda_) / lambda_;
      Size log2_n = (static_cast<Size>((std::log(nR) / std::log(2.0))) + 1);
            Size n = 1 << log2_n;

            // Strike range (equation 19,20)
            Real b = n * lambda_ / 2.0;

            // Grid spacing (equation 23)
            Real eta = 2.0 * M_PI / (lambda_ * n);

            // Discount factor
            Real df = discountFactor(expiryDate);
            Real div = dividendYield(expiryDate);

            // Input to fourier transform
            std::vector<std::complex<Real> > fti;
            fti.resize(n);

            // Precalculate any discount factors etc.
            precalculateExpiry(expiryDate);

            for (Size i=0; i<n; i++)
            {
                Real k_u = -b + lambda_ * i;
                Real v_j = eta * i;
                Real sw = eta * (3.0 + ((i % 2) == 0 ? -1.0 : 1.0) - ((i == 0) ? 1.0 : 0.0)) / 3.0; 

                std::complex<Real> psi = df * complexFourierTransform(v_j - (alpha + 1)* i1);
                psi = psi / (alpha*alpha + alpha - v_j*v_j + i1 * (2 * alpha + 1.0) * v_j);

                fti[i] = std::exp(i1 * b * v_j)  * sw * psi;
            }

            // Perform fft
            std::vector<std::complex<Real> > results(n);
            FastFourierTransform fft(log2_n);
            fft.transform(fti.begin(), fti.end(), results.begin());

            // Call prices
            std::vector<Real> prices, strikes;
            prices.resize(n);
            strikes.resize(n);
            for (Size i=0; i<n; i++)
            {
                Real k_u = -b + lambda_ * i;
                prices[i] = (std::exp(-alpha * k_u) / M_PI) * results[i].real();
                strikes[i] = std::exp(k_u);
            }

            for (PayoffList::const_iterator it = payIt->second.begin();
                it != payIt->second.end(); it++)
            {
                boost::shared_ptr<StrikedTypePayoff> payoff = *it;

                Real callPrice = LinearInterpolation(strikes.begin(), strikes.end(), prices.begin())(payoff->strike());
                switch (payoff->optionType())
                {
                case Option::Call:
                    resultMap_[expiryDate][payoff] = callPrice;
                    break;
                case Option::Put:
                    resultMap_[expiryDate][payoff] = callPrice - process_->x0() * div + payoff->strike() * df;
                    break;
                default:
                    QL_FAIL("Invalid option type");
                }
            }
        }
    }
 Rate AnalyticDoubleBarrierEngine::costOfCarry() const {
     return riskFreeRate() - dividendYield();
 }