Login  Register

Volatility Surface Interpolation

Posted by Sebastián Miranda on Feb 04, 2008; 11:39am
URL: http://quantlib.414.s1.nabble.com/Volatility-Surface-Interpolation-tp5741.html

Hello,

I'm trying to interpolate time/strike dependent volatilities using the
BlackVarianceTermStructure.

I interpolate every term smile to get the volatility matrix and then
interpolate that matrix to get volatilities at given standard times.

But, when I call the constructor, I get the error:

                QL_REQUIRE(variances_[i][j]>=variances_[i][j-1],
                           "variance must be non-decreasing");

Any ideas about where's the error????

Tankx !!!!

    Sebastián

============================================================================
==
Example Volatility Matrix:

0,7335    0,4989    0,3775    0,3467    0,3305    0,3342    0,5698    0,5814
0,6635    0,4404    0,3730    0,3324    0,3271    0,3275    0,5407    0,5463
0,5853    0,3983    0,3685    0,3217    0,3237    0,3239    0,5098    0,5138
0,4948    0,3855    0,3613    0,3225    0,3203    0,3196    0,4770    0,4899
0,4187    0,3604    0,3448    0,3188    0,3172    0,3175    0,4466    0,4382
0,4298    0,3545    0,3428    0,3150    0,3140    0,3154    0,4140    0,3796
0,3915    0,3456    0,3225    0,3135    0,3109    0,3115    0,3785    0,3712
0,3571    0,3365    0,3143    0,3119    0,3077    0,3076    0,3394    0,3626
0,4132    0,3206    0,2915    0,3083    0,3059    0,3030    0,3148    0,3401
0,3823    0,3169    0,2873    0,3046    0,3040    0,2983    0,2882    0,3160
0,3749    0,3170    0,2870    0,3008    0,2994    0,2921    0,2588    0,2900
0,3245    0,3183    0,2866    0,2970    0,2948    0,2857    0,2256    0,2613
0,4503    0,3375    0,2860    0,2939    0,2862    0,2815    0,2063    0,2472
0,5691    0,3396    0,2853    0,2906    0,2774    0,2772    0,1849    0,2323


============================================================================
==
The code:

void cargarBBDD( vector< MaturitySmileData > ACUMULADOR ){
    // ==============================================================
    // FECHA INICIAL DEL CALCULO -> Atentos a los históricos
    Date fechaINICIAL    = ACUMULADOR[0].subyacente.settlementDate;
    // Date fechaINICIAL    =    Date::todaysDate();
    // ==============================================================
    typedef map<double, double> Smile;
    typedef map<double,double>::iterator Iterador;
    const unsigned  int numVenc    =    ACUMULADOR.size();
    std::vector<Date> maturities(numVenc);
    // Monto set ordenado con todos los strikes.
    std::set< double >        strikesSet;
    std::vector< Smile >    Smiles;
    for ( unsigned int i = 0; i < numVenc ; i++){
        Smile tmpSmile__;
        Iterador iterSmile;
        Iterador iter_;
        iter_    =    ACUMULADOR[i].callSmile.begin();
        while (iter_ != ACUMULADOR[i].callSmile.end() ){
            strikesSet.insert( iter_->first );
            tmpSmile__.insert( *iter_ );
            iter_++;
        }
        iter_    =    ACUMULADOR[i].putSmile.begin();
        while (iter_ != ACUMULADOR[i].putSmile.end() ){
            strikesSet.insert( iter_->first );
            iterSmile    = tmpSmile__.find( iter_->first );
            if (iterSmile == tmpSmile__.end() ){
                tmpSmile__.insert( *iter_ ) ;
            } else{ //! Si ya tenemos este strike para las Calls,
promediamos ambos.
                if( fabs(iter_->second - iterSmile->second)
> 0.02) {
                    string MegError = "Error promediando curva -> ";
                    MegError += "RIC: " +
ACUMULADOR[i].subyacente.RIC + "\t Vencimiento. "+ ACUMULADOR[i].vencimiento ;
                    MegError += "\n Vol. Call:\t"  +
boost::lexical_cast<std::string>( (*iterSmile).second );
                    MegError += "\n Vol. Put:\t"   +
boost::lexical_cast<std::string>( (*iter_).second );
                    MegError += "\n
--------------------------------";
                    MegError += "\n DIFERENCIA:\t" +
boost::lexical_cast<std::string>(fabs((*iter_).second - (*iterSmile).second) );
                    VOLCAR_LOG( MegError  );
                }
                iterSmile->second = ((*iter_).second +
(*iterSmile).second) / 2;
            }
            iter_++;
        }// end while
        Smiles.push_back(tmpSmile__);
    };   // end for numVenc
    const unsigned int numStrikes    =    strikesSet.size();
    vector< double> strikes( strikesSet.begin(), strikesSet.end());
    Matrix volatilidades( numStrikes, numVenc );
    for ( unsigned  int i = 0; i < numVenc ; i++){
        maturities[i]    = ACUMULADOR[i].maturity;
        Iterador iter_;
        // Si no tiene todos los strikes, interpolamos.
        if ( Smiles[i].size() < numStrikes ){

            const unsigned int s_    =    Smiles[i].size();
            Matrix vols_( s_ , 1);
            std::vector<Date> dates_(1);
            dates_[0]        = ACUMULADOR[i].maturity;
            // Cargo las volas
            iter_ = Smiles[i].begin();
            vector< double> strikesTMP;
            int j = 0;
            while ( iter_ != Smiles[i].end() ){
                strikesTMP.push_back( (*iter_).first ) ;
                vols_[j][0] = (*iter_).second ; j++;
                iter_++;
            };
            // Montamos el Smile con lo que tenemos y lo interpolamos.
            boost::shared_ptr<BlackVolTermStructure>
curvaVolas(new
                BlackVarianceSurface( fechaINICIAL, dates_,
strikesTMP, vols_, dayCounter ));
            for (unsigned int j = 0 ; j < numStrikes ; j++){
                volatilidades[j][i] =
curvaVolas->blackVol(fechaINICIAL, strikes[j] , true );
                std::cout << "Vol " << j << " " << i << "\t"
<< volatilidades[j][i] << "\n";
            };
            /*
            set< double >::iterator itrK_ ;
            itrK_        =    strikesSet.begin();
            int indx_    =    0;
            while ( itrK_ != strikesSet.end() ){
            volatilidades[indx_][i] =
curvaVolas->blackVol(fechaINICIAL, *itrK_ , true );
            indx_++;
            itrK_++;
            };*/

        } else{ // Si tiene todos los strikes, no necesitamos interpolar nada.
            iter_ = Smiles[i].begin();
            int j = 0;
            while ( iter_ != Smiles[i].end() ){
volatilidades[j][i] = (*iter_).second ;
            std::cout << "Vol " << j << " " << i << "\t" <<
volatilidades[j][i] << "\n";
            j++; iter_++; };
        };

    };

    // Volatility Surface
    // HERE IS THE PROBLEM
*********************************************************
    boost::shared_ptr<BlackVolTermStructure> SupVolatilidad(new
        BlackVarianceSurface( fechaINICIAL, maturities, strikes,
volatilidades, dayCounter ));
    // HERE IS THE PROBLEM
*********************************************************

    // Interpolamos
    const int    numStrikesSTD    =    13;
    const int    numTermsSTD        =     8;
    double    strikesSTD[]        =    { 0.8,

0.85,

0.9,

0.95,

0.975,

0.9875,

1.0,

1.0125,

1.025,

1.05,

1.1,

1.15,

1.2 };
    Date    termsSTD[]            =    {fechaINICIAL +
1*Months,

fechaINICIAL + 3*Months,

fechaINICIAL + 6*Months,

fechaINICIAL + 1*Years,

fechaINICIAL + 2*Years,

fechaINICIAL + 3*Years,

fechaINICIAL + 4*Years,

fechaINICIAL + 5*Years };
    // Superficie de Volatilidades interpolada.
    double    volasBBDD[numStrikesSTD][numTermsSTD];
    for (unsigned int i = 0 ; i < numStrikesSTD ; i++){
        double    strike__    =    strikesSTD[i] *
ACUMULADOR[0].subyacente.spot;
        for (unsigned int j = 0 ; j < numTermsSTD ; j++){
            volasBBDD[i][j] =
SupVolatilidad->blackVol(termsSTD[j], strike__ , true );
        };
    };
    string dia =
boost::lexical_cast<std::string>(fechaINICIAL.dayOfMonth());
    dia    = ( dia.length() == 1 )? "0" + dia : dia ;
    int mes__  = fechaINICIAL.month();
    string mes = boost::lexical_cast<std::string>(mes__);
    mes    = ( mes.length() == 1 )? "0" + mes : mes ;
    std::string query = "";
    query    += "INSERT INTO `advisory`.`tsupvolas` VALUES ";
    for (unsigned int i = 0 ; i < numStrikesSTD ; i++){
        query    +=    "( " + ACUMULADOR[0].subyacente.ID + ",'" +
boost::lexical_cast<std::string>(fechaINICIAL.year());
        query    +=    mes + dia + "'," +
boost::lexical_cast<std::string>(strikesSTD[i]) + "," ;
        query    +=
boost::lexical_cast<std::string>(ACUMULADOR[0].subyacente.spot);
        for (unsigned int j = 0 ; j < numTermsSTD ; j++){
            query    +=    "," +
boost::lexical_cast<std::string>(volasBBDD[i][j]);
        };
        query    +=    ") ";
        query    +=    (i + 1 == numStrikesSTD)? "" : ",";
    };
    query    +=    "; ";
    // INSERTAMOS EN LA BBDD
    res            =    consultaSQL(query);
    //int filas    =    mysql_affected_rows();
    //string staus=    ( filas == numStrikesSTD)?
ACUMULADOR[0].subyacente.RIC + " insertado OK." :
ACUMULADOR[0].subyacente.RIC + " Error Inserción.";
    mysql_free_result(res);
// boost::lexical_cast<std::string>
};

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users