Ejemplo n.º 1
0
    void KahaleSmileSection::compute() {

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

        if(deleteArbitragePoints_) {
            while(leftIndex_>1 || rightIndex_<k_.size()-1) {
                
                ssutils_ = boost::shared_ptr<SmileSectionUtils>(new SmileSectionUtils(*source_,moneynessGrid_,f_));
                std::pair<Size,Size> afIdx = ssutils_->arbitragefreeIndices();

                leftIndex_ = afIdx.first;
                rightIndex_ = afIdx.second;

                QL_REQUIRE(rightIndex_>leftIndex_,
                           "arbitrage free region must at least contain two points (only index is " << leftIndex_ << ")");
            
                if(leftIndex_>1) {
                    moneynessGrid_.erase(moneynessGrid_.begin()+leftIndex_-1);
                    k_.erase(k_.begin()+leftIndex_-1);
                    c_.erase(c_.begin()+leftIndex_-1);
                    leftIndex_--;
                    rightIndex_--; 
                }

                if(rightIndex_<k_.size()-1) {
                    moneynessGrid_.erase(moneynessGrid_.begin()+rightIndex_+1);
                    k_.erase(k_.begin()+rightIndex_+1);
                    c_.erase(c_.begin()+rightIndex_+1);
                    rightIndex_--;
                }
            }
        }

        cFunctions_ = std::vector<boost::shared_ptr<cFunction> >(rightIndex_-leftIndex_+2);

        // extrapolation in the leftmost interval

        Brent brent;
        bool success;
        Real secl = 0.0;

        do {
            success=true;
            try {
                Real k1 = k_[leftIndex_];
                Real c1 = c_[leftIndex_];
                Real c0 = c_[0];
                secl = (c_[leftIndex_]-c_[0]) / (k_[leftIndex_]-k_[0]);
                Real sec = (c_[leftIndex_+1]-c_[leftIndex_]) / (k_[leftIndex_+1]-k_[leftIndex_]);
                Real c1p;
                if(interpolate_) c1p=(secl+sec)/2;
                else {
                    c1p=(blackFormula(Option::Call, k1+gap_, f_, sqrt(source_->variance(k1+gap_)))-
                         blackFormula(Option::Call, k1, f_, sqrt(source_->variance(k1))))/gap_;
                    QL_REQUIRE(secl < c1p && c1p <= 0.0,"dummy"); 
                    // can not extrapolate so throw exception which is caught below
                }
                sHelper1 sh1(k1,c0,c1,c1p);
                Real s = brent.solve(sh1,QL_KAHALE_ACC,0.20,0.00,QL_KAHALE_SMAX); // numerical parameters hardcoded here
                sh1(s);
                boost::shared_ptr<cFunction> cFct1(new cFunction(sh1.f_,s,0.0,sh1.b_));
                cFunctions_[0]=cFct1;
            } catch(...) {
                leftIndex_++;
                success=false;
            }
        } while(!success && leftIndex_ < rightIndex_);

        QL_REQUIRE(leftIndex_ < rightIndex_, "can not extrapolate to left, right index of af region reached (" 
                   << rightIndex_ << ")");

        // interpolation

        Real cp0 = 0.0, cp1 = 0.0;

        if(interpolate_) {

            for(Size i = leftIndex_; i<rightIndex_; i++) {
                Real k0 = k_[i];
                Real k1 = k_[i+1];
                Real c0 = c_[i];
                Real c1 = c_[i+1];
                Real sec = (c_[i+1]-c_[i]) / (k_[i+1]-k_[i]);
                if(i==leftIndex_) cp0 = leftIndex_ > 0 ? (secl + sec) / 2.0 : sec;
                Real secr;
                if(i==rightIndex_-1) secr=0.0;
                else secr = (c_[i+2]-c_[i+1]) / (k_[i+2]-k_[i+1]);
                cp1 = (sec+secr) / 2.0;
                aHelper ah(k0,k1,c0,c1,cp0,cp1);
                Real a;
                try {
                    a = brent.solve(ah,QL_KAHALE_ACC,0.5*(cp1+(1.0+cp0)),cp1+QL_KAHALE_EPS,1.0+cp0-QL_KAHALE_EPS);
                    // numerical parameters hardcoded here
                } catch(...) {
                    // from theory there must exist a zero. if the solver does not find it, it most
                    // probably lies close one of the interval bounds. Just choose the better bound
                    // and relax the accuracy. This does not matter in practice usually.
                    Real la = std::fabs(ah(cp1+QL_KAHALE_EPS));
                    Real ra = std::fabs(ah(1.0+cp0-QL_KAHALE_EPS));
                    if( la < QL_KAHALE_ACC_RELAX || ra < QL_KAHALE_ACC_RELAX) { // tolerance hardcoded here
                        a = la < ra ? cp1+QL_KAHALE_EPS : 1.0+cp0-QL_KAHALE_EPS;
                    }
                    else
                        QL_FAIL("can not interpolate at index " << i);

                }
                ah(a);
                boost::shared_ptr<cFunction> cFct(new cFunction(ah.f_,ah.s_,a,ah.b_));
                cFunctions_[leftIndex_ > 0 ? i-leftIndex_+1 : 0]=cFct;
                cp0=cp1;
            }

        }

        // extrapolation of right wing

        do {
            success=true;
            try {
                Real k0 = k_[rightIndex_];
                Real c0 = c_[rightIndex_];
                Real cp0;
                if(interpolate_) cp0 = 0.5*(c_[rightIndex_]-c_[rightIndex_-1])/(k_[rightIndex_]-k_[rightIndex_-1]);
                else {
                    cp0=(blackFormula(Option::Call, k0, f_, sqrt(source_->variance(k0)))-
                         blackFormula(Option::Call, k0-gap_, f_, sqrt(source_->variance(k0-gap_))))/gap_;

                }
                boost::shared_ptr<cFunction> cFct;
                if(exponentialExtrapolation_) {
                    cFct = boost::shared_ptr<cFunction>(new cFunction(-cp0/c0 ,std::log(c0)-cp0/c0*k0));
                }
                else {
                    sHelper sh(k0,c0,cp0);
                    Real s;
                    s = brent.solve(sh,QL_KAHALE_ACC,0.20,0.0,QL_KAHALE_SMAX);  // numerical parameters hardcoded here
                    sh(s);
                    cFct = boost::shared_ptr<cFunction>(new cFunction(sh.f_,s,0.0,0.0));
                }
                cFunctions_[rightIndex_-leftIndex_+1]=cFct;
            } catch (...) {
                rightIndex_--;
                success=false;
            }
        } while(!success && rightIndex_ > leftIndex_);

        QL_REQUIRE(leftIndex_ < rightIndex_, "can not extrapolate to right, left index of af region reached (" << 
                   leftIndex_ << ")");


    }
Ejemplo n.º 2
0
    void KahaleSmileSection::compute() {

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

        cFunctions_ = std::vector<boost::shared_ptr<cFunction> >(
            rightIndex_ - leftIndex_ + 2);

        // extrapolation in the leftmost interval

        Brent brent;
        bool success;
        Real secl = 0.0;

        do {
            success = true;
            try {
                Real k1 = k_[leftIndex_];
                Real c1 = c_[leftIndex_];
                Real c0 = c_[0];
                secl = (c_[leftIndex_] - c_[0]) / (k_[leftIndex_] - k_[0]);
                Real sec = (c_[leftIndex_ + 1] - c_[leftIndex_]) /
                           (k_[leftIndex_ + 1] - k_[leftIndex_]);
                Real c1p;
                if (interpolate_)
                    c1p = (secl + sec) / 2;
                else {
                    c1p = (blackFormula(Option::Call, k1 + gap_, f_,
                                        sqrt(source_->variance(k1 + gap_))) -
                           blackFormula(Option::Call, k1, f_,
                                        sqrt(source_->variance(k1)))) /
                          gap_;
                    QL_REQUIRE(secl < c1p && c1p <= 0.0, "dummy");
                    // can not extrapolate so throw exception which is caught
                    // below
                }
                sHelper1 sh1(k1, c0, c1, c1p);
                Real s = brent.solve(sh1, QL_KAHALE_ACC, 0.20, 0.00,
                                     QL_KAHALE_SMAX); // numerical parameters
                                                      // hardcoded here
                sh1(s);
                boost::shared_ptr<cFunction> cFct1(
                    new cFunction(sh1.f_, s, 0.0, sh1.b_));
                cFunctions_[0] = cFct1;
                // sanity check - in rare cases we can get digitials
                // which are not monotonic or greater than 1.0
                // due to numerical effects. Move to the next index in
                // these cases.
                Real dig = digitalOptionPrice(k1 / 2.0);
                QL_REQUIRE(dig >= -c1p && dig <= 1.0, "dummy");
            }
            catch (...) {
                leftIndex_++;
                success = false;
            }
        } while (!success && leftIndex_ < rightIndex_);

        QL_REQUIRE(
            leftIndex_ < rightIndex_,
            "can not extrapolate to left, right index of af region reached ("
                << rightIndex_ << ")");

        // interpolation

        Real cp0 = 0.0, cp1 = 0.0;

        if (interpolate_) {

            for (Size i = leftIndex_; i < rightIndex_; i++) {
                Real k0 = k_[i];
                Real k1 = k_[i + 1];
                Real c0 = c_[i];
                Real c1 = c_[i + 1];
                Real sec = (c_[i + 1] - c_[i]) / (k_[i + 1] - k_[i]);
                if (i == leftIndex_)
                    cp0 = leftIndex_ > 0 ? (secl + sec) / 2.0 : sec;
                Real secr;
                if (i == rightIndex_ - 1)
                    secr = 0.0;
                else
                    secr = (c_[i + 2] - c_[i + 1]) / (k_[i + 2] - k_[i + 1]);
                cp1 = (sec + secr) / 2.0;
                aHelper ah(k0, k1, c0, c1, cp0, cp1);
                Real a;
                bool valid = false;
                try {
                    a = brent.solve(
                        ah, QL_KAHALE_ACC, 0.5 * (cp1 + (1.0 + cp0)),
                        cp1 + QL_KAHALE_EPS, 1.0 + cp0 - QL_KAHALE_EPS);
                    // numerical parameters hardcoded here
                    valid = true;
                }
                catch (...) {
                    // delete the right point of the interval where we try to
                    // interpolate
                    moneynessGrid_.erase(moneynessGrid_.begin() + (i + 1));
                    k_.erase(k_.begin() + (i + 1));
                    c_.erase(c_.begin() + (i + 1));
                    cFunctions_.erase(cFunctions_.begin() + (i + 1));
                    rightIndex_--;
                    i--;
                }
                if (valid) {
                    ah(a);
                    boost::shared_ptr<cFunction> cFct(
                        new cFunction(ah.f_, ah.s_, a, ah.b_));
                    cFunctions_[leftIndex_ > 0 ? i - leftIndex_ + 1 : 0] = cFct;
                    cp0 = cp1;
                }
            }
        }

        // extrapolation of right wing

        do {
            success = true;
            try {
                Real k0 = k_[rightIndex_];
                Real c0 = c_[rightIndex_];
                Real cp0;
                if (interpolate_)
                    cp0 = 0.5 * (c_[rightIndex_] - c_[rightIndex_ - 1]) /
                          (k_[rightIndex_] - k_[rightIndex_ - 1]);
                else {
                    cp0 = (blackFormula(Option::Call, k0, f_,
                                        sqrt(source_->variance(k0))) -
                           blackFormula(Option::Call, k0 - gap_, f_,
                                        sqrt(source_->variance(k0 - gap_)))) /
                          gap_;
                }
                boost::shared_ptr<cFunction> cFct;
                if (exponentialExtrapolation_) {
                    QL_REQUIRE(-cp0 / c0 > 0.0, "dummy"); // this is caught
                                                          // below
                    cFct = boost::shared_ptr<cFunction>(
                        new cFunction(-cp0 / c0, std::log(c0) - cp0 / c0 * k0));
                } else {
                    sHelper sh(k0, c0, cp0);
                    Real s;
                    s = brent.solve(sh, QL_KAHALE_ACC, 0.20, 0.0,
                                    QL_KAHALE_SMAX); // numerical parameters
                                                     // hardcoded here
                    sh(s);
                    cFct = boost::shared_ptr<cFunction>(
                        new cFunction(sh.f_, s, 0.0, 0.0));
                }
                cFunctions_[rightIndex_ - leftIndex_ + 1] = cFct;
            }
            catch (...) {
                rightIndex_--;
                success = false;
            }
        } while (!success && rightIndex_ > leftIndex_);

        QL_REQUIRE(
            leftIndex_ < rightIndex_,
            "can not extrapolate to right, left index of af region reached ("
                << leftIndex_ << ")");
    }