6 votos

¿Cuál es un método eficaz para hallar la volatilidad implícita?

Tengo un código que encuentra la volatilidad implícita utilizando el método Newton-Raphson.

He puesto el número de pruebas en 1000 pero a veces no converge y no encuentra el resultado.

¿Hay algún método mejor para encontrar el resultado? ¿Existen condiciones técnicas en las que se espera que este método numérico no converja a la solución?

Aquí está el código C#:

    public double findIV(double S, double K, double r, double time, string type, double optionPrice)
    {
        int trial= 1000;
        double ACCURACY = 1.0e-5;
        double t_sqrt = Math.Sqrt(time);

        double sigma = (optionPrice / S) / (0.398 * t_sqrt);    // find initial value  
        for (int i = 0; i < trial; i++)
        {
            Option myCurrentOpt = new Option(type, S, K, time, r, 0, sigma); // create an Option object
            double price = myCurrentOpt.BlackScholes();
            double diff = optionPrice - price;
            if (Math.Abs(diff) < ACCURACY)
                return sigma;
            double d1 = (Math.Log(S / K) + r * time) / (sigma * t_sqrt) + 0.5 * sigma * t_sqrt;
            double vega = S * t_sqrt * ND(d1);
            sigma = sigma + diff / vega;
        }         
        throw new Exception("Failed to converge."); 
    }

    public double ND(double X)
    {
        return (1.0 / Math.Sqrt(2.0 * Math.PI)) * Math.Exp(-0.5 * X * X);
    }

3voto

Steven Dick Puntos 151

Peter Jaeckel escribió un artículo sobre cómo resolver este problema:

Por implicación (julio de 2006; Wilmott, páginas 60-66, noviembre de 2006). Probablemente la cuestión trivial más complicada de las matemáticas financieras: cómo calcular la volatilidad implícita de Black de forma robusta, sencilla, eficiente y rápida

descargable en jaeckel.org

Según mi experiencia, lo más importante es asegurarse de que se trabaja con una opción fuera del dinero. Si la opción está dentro del dinero utilice la paridad put-call para transformar al otro caso.

2voto

Femi Puntos 299

Se sabe que los métodos de horquillado, como Bisection y Regula Falsi, siempre convergen, pero son muy lentos.

Los métodos Newton Raphson y secante son rápidos (convergencia cuadrática) pero tienen problemas de convergencia. Busca en Google los problemas de convergencia de Newton Raphson. Los clásicos como "Atrapado en mínimos locales", "Diverge en lugar de converger", etc.

Algoritmos como el de Dekker y el de Brent combinan las características del bracketing y de la convergencia cuadrática, por lo que su convergencia es segura y relativamente rápida.

2voto

Femi Puntos 299

A continuación está el código del algoritmo de búsqueda de raíces que escribí en la universidad. Está escrito en octava. Es sencillo de entender y reescribir en C++.

Desarrollar algos de métodos numéricos como un módulo separado e integrarlos con su código de precios y otros.

Quiero ADVERTIRTE de que vuelvas a revisar los errores. Siempre converge para mis funciones objetivo

La primera función es el método Dekker, similar al de Brent. Brent es mejor. La segunda función es el método de bracketing. Cualquiera de los dos puede ser utilizado para la búsqueda de root

##
## Dekker root search.
##
## Eg call: dekker(@expMinusOne, -2, 3) 
##
function c = dekker(f, lowerBound, upperBound)

    MAX_ITER = 50;
    iterations = 0;

    a = lowerBound;
    b = upperBound;

    assert(validateBracket(f, a, b), "Given bounds doesn't bracket the root");
    assert(!hasMultipleRoots(f, a, b), "Given bounds has mutiple roots");

    fa = f(a);
    fb = f(b);

    #printf("fa = %f, fb = %f\n", fa, fb);

    if(abs(fa) < abs(fb))
        c = a;
        d = b;
    else
        c = b;
        d = a;
    endif

    linOps = 0;

    do
        s = linearInterpolation(f, c, d);
        m = bisectionPoint(c, d);

        a = c;
        b = d;

        # LI/LE and BI points are on same side of root
        if(f(s) * f(m) >= 0)
            # New root and lower bound are on same side of the root
            # We can adjust one side of the bracket
            if(f(c) * f(s) > 0)
                if(abs(c - m) < abs(c - s) && linOps < 4)
                    c = s;
                    linOps++;
                else
                    c = m;
                    linOps = 0;
                endif
            # New root and lower bound are on different sides of the root
            # We can adjust both sides of the bracket
            else
                # Reduce the bracket.
                if(abs(c - s) < abs(c - m))
                    c = s;
                else
                    c = m;
                endif
                d = a;
            endif
        # LI/LE and BI points are on different sides of root. 
        # We can adjust both sides of the bracket
        else
            if(f(c) * f(s) > 0)
                c = s;
                d = m;
                linOps++;
            else
                c = m;
                d = s;
                linOps = 0;
            endif
        endif

        #printf("c = %f, d = %f\n", c, d);

        # Check for Convergence
        if(c == d)
            #printf("DEKKER ROOT = %f in %d iterations.\n", c, iterations);
            break;
        endif

        iterations++;
    until (iterations == MAX_ITER)

    if(iterations == MAX_ITER)
        #printf("DEKKER ROOT = %f for maximum iterations %d.\n", c, MAX_ITER);
    endif

endfunction

function s = linearInterpolation(f, a, b)
    s = a - (b - a) * f(a)/(f(b) - f(a));
endfunction

function m = bisectionPoint(a, b)
    m = (a + b)/2;
endfunction

function r = hasMultipleRoots(f, a, b)
    if(f(a) == f(b))
        r = true;
    else
        r = false;
    endif
endfunction

function r = validateBracket(f, a, b)
    if(f(a) * f(b) < 0)
        r = true;
    else
        r = false;
    endif
endfunction

##
##  regulaFalsi( f, a, b, yAcc )
##
## rootsearching by regulaFalsi method 
##
## f is a real numeric function s.t. f( a ) * f( b ) < 0.0
## xAcc convergence threshold 
## nIter max number of iterations
function [c, x] = regulaFalsi( f, a, b, yAcc )

    fb = f( b );  
    fa = f( a );

    if ( fa * fb >= 0.0 ), 
        error(" f( a ) * f( b ) >= 0.0 " ); 
    endif

    # init loop variables
    c = a;  
    iter = 1;  
    x = [];  

    do
        cOld = c;     # save previous value of c. Guard for infinite loop
        c  = a - fa * ( b  - a ) / ( fb - fa );  # new point
        fc = f( c );

        if ( fc * fb < 0.0 )  # update interval
           a  = c;
           fa = fc;
        else 
           b  = c;
           fb = fc; 
        endif

        x(iter,:)=[iter, c]; iter++;  # unnecessary, just for display

    until ( abs(fc) < yAcc || cOld == c ) # Exit criteria is on yAcc.
endfunction

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X