1 votos

Valoración de una opción de doble barrera mediante Monte Carlo (código C++ y Python incluido)

Estoy tratando de fijar el precio de una opción con barreras superiores e inferiores utilizando MC donde el pago es $B_u$ cuando $S_t > B_u$ , $B_l$ cuando $S_t < B_l$ y $S_t$ cuando $B_l < S_t < B_u$ .

He escrito código tanto en Python como en C++, cada uno da el mismo resultado pero no parece intuitivamente correcto. Para los parámetros de abajo, precio = 109,991. Si alguien tiene alguna indicación de dónde puede estar el error/una solución analítica, se lo agradecería mucho.

C++:

#include <iostream>
#include <random>
#include <math.h>

// Initialize variables
double s0 = 100;          // Price
double vol = 0.4;         // Volatility
double r = 0.01;          // Interest Rate
double t_ = 255;          // Year
int days = 2;             // Days
int N = pow(10,6);        // Simulations
double b_u = 110;         // Upper Barrier (Rebate)
double b_l = 90;          // Lower Barrier (Rebate)

using namespace std;

std::default_random_engine generator;

double asset_price(double p,double vol,int periods)
{
    double mean = 0.0;
    double stdv = 1.0;

    std::normal_distribution<double> distribution(mean,stdv);

    for(int i=0; i < periods; i++)
    {
        double w = distribution(generator);
        p += s0 * exp((r - 0.5 * pow(vol,2)) * days + vol * sqrt(days) * w);
    }
    return p;
}

int main()
{
    // Monte Carlo Payoffs
    double avg = 0.0;

    for(int j=0; j < N; j++)
    {
        double temp = asset_price(s0,vol,days);
        if(temp > b_u)
        {
            double payoff = b_u;
            payoff = payoff * exp(-r/t_ * days);
            avg += payoff;
        }
        else if(temp < b_l)
        {
            double payoff = b_l;
            payoff = payoff * exp(-r/t_ * days);
            avg += payoff;
        }
        else
        {
            double payoff = temp;
            payoff = payoff * exp(-r/t_ * days);
            avg += payoff;
        }
    }

    // Average Payoff Vector
    double price = avg/(double)N;

    // Results
    cout << "MONTE CARLO BARRIER OPTION PRICING" << endl;
    cout << "----------------------------------" << endl;
    cout << "Option price: " << price << endl;
    cout << "Price at t=0: " << s0 << endl;
    cout << "Volatility: " << vol*100 << "%" << endl;
    cout << "Number of simulations: " << N << endl;

    return 0;
}

Python:

import numpy as np
from math import *

def asset_price(p, v, periods):
    w = np.random.normal(0, 1, size=periods)
    for i in range(periods):
        p += s0 * exp((r - 0.5 * v**2) * days + v * sqrt(days) * w[i])
    return p

# Parameters
s0 = 100  # Price
v = 0.4  # Vol
t_ = 255  # Year
r = 0.01  # Interest Rate
days = 2  # Days until option expiration
N = 100000  # Simulations
avg = 0

# Simulation loop
for i in range(N):
    B_U = 110  # Upper barrier
    B_L = 90  # Lower barrier
    temp = asset_price(s0, v, days)
    if temp > B_U:
        payoff = B_U
        payoff = payoff * np.exp(-r / t_ * days)
        avg += payoff
    elif temp < B_L:
        payoff = B_L
        payoff = payoff * np.exp(-r / t_ * days)
        avg += payoff
    else:
        payoff = temp
        payoff = payoff * np.exp(-r / t_ * days)
        avg += payoff

# Average payoffs vector
price = avg / float(N)

# Results
print "MONTE CARLO BARRIER OPTION PRICING"
print "----------------------------------"
print "Option price: ", price
print "Price at t=0: ", s0
print "Volatility: ", v * 100, "%"

0 votos

Dado que el límite sólo está activo en el momento del vencimiento, debería tener una solución analítica bastante sencilla.

1 votos

Si puede ser de ayuda, escribí mi disertación sobre la fijación de precios de las opciones de barrera hace un par de años. La disertación y el código (matlab) que la acompaña están disponibles públicamente aquí: github.com/torbonde/dissertation . Obsérvese, por ejemplo, que en el apartado 1.2.1 doy expresiones analíticas para las opciones barrera en el caso unidimensional de Black-Scholes. También considero diferentes formas de fijar el precio de las opciones barrera, y de ellas recomendaría utilizar el enfoque de Monte Carlo secuencial.

6voto

Dan R Puntos 1852

Aquí hay al menos tres errores en su código:

  1. p += s0 * exp(...) debe ser p *= exp(...) .

  2. Su volatilidad y sus tarifas son por año Así que divide los días por 365 (o 255) en tu función asset_price .

  3. En asset_price se multiplica por days dentro del bucle. Sin embargo, el bucle ya está iterando sobre los días - por lo que no se toman dos pasos de un día sino dos pasos de dos días en su ejemplo.

Algunas sugerencias/observaciones más:

  1. Cuando se implementa un pricer, siempre es útil comprobar los casos de borde/comportamiento límite. En su caso, por ejemplo, podría dejar que B_L = 0 , B_H = 1000 (alto) y el precio de su contrato debería ser sólo el spot. Esto ya falla en su código original.

  2. Uso de la variable global days o r en su función asset_price es un mal estilo. Los argumentos de la función deben representar su interfaz. Sin embargo, mezclas pasando s0 en el argumento p pero sólo accede a la variable global r desde la función.

  3. Tenga en cuenta que está fijando el precio de una opción de barrera europea en la que la barrera sólo se activa al vencimiento. No estoy seguro de si esa era su intención.

  4. Se simula el precio del activo en cada día desde ahora hasta el vencimiento. Como sólo le interesa el precio al vencimiento (véase el punto anterior), podría limitarse a simular el valor en un paso mayor. Es decir, el bucle en asset_price es redundante.


Así es como se ha corregido asset_price podría parecer:

def asset_price(spot, vola, rate, period_count, delta_t):
    w = np.random.normal(0, 1, size=period_count)
    for i in range(period_count):
        spot *= exp((rate - 0.5 * vola**2) * delta_t + vola * sqrt(delta_t) * w[i])
    return spot

Pasarías 1.0 / 255.0 como delta_t de tal manera que este es el paso del tiempo en años. De nuevo, el bucle de esta función es en realidad completamente redundante (véase la observación 4).

0 votos

¿Por qué la volatilidad tiene que ser escalada por los días y no por root cuadrada de los días?

1 votos

Eso no es lo que estoy diciendo. Escalar por root cuadrada de tiempo es generalmente correcto. Como tu bucle ya ha superado los días, necesitas v * sqrt(1 / 255) * w[i] . No debería haber days en esta línea.

0 votos

Genial, muchas gracias por tus sugerencias @LocalVolatility.

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