2 votos

Interpretación de los resultados del modelo de calibración SABR

¿Calibrar un modelo SABR?

Siguiendo con esta pregunta, he utilizado los mismos datos de mercado que adjuntaron pero no estoy seguro de interpretar el resultado.

Cuando trazo las probabilidades SABR contra el strike para los datos de abajo, no se muestra ninguna sonrisa, sólo una pendiente sesgada/baja ya que todas las volatilidades de salida son decrecientes.

¿Cómo puedo utilizar estos datos para producir los gráficos de volatilidad smile? o ¿estos datos simplemente no muestran smile?

La primera línea de datos de mercado que utiliza Travaglini es;

y la primera línea de las volatilidades SABR de salida es;

datos de mercado y código de https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2725485

0 votos

¿Puedes reproducir el código aquí por si se rompe el enlace?

0 votos

Ahora he actualizado la pregunta, con ejemplos de los datos, ¡gracias StackG!

2voto

Marc Puntos 892

El papel toma cada sonrisa observada, golpea todos los golpes por un shift término para hacerlos positivos, y el encaja una sonrisa SABR a ellos.

Cuando hago lo mismo con el conjunto de datos que has adjuntado arriba (quito el punto -150 porque su vol de 0,0 rompe las cosas) obtengo el siguiente ajuste "sonriente", que se parece a los resultados presentados arriba:

SABR fit

Esto se generó así:

import numpy as np
import pandas as pd
import QuantLib as ql
from matplotlib import pyplot as plt
from scipy import optimize

# Parameters from the post
strikes = [-100, -50, -25, 0, 25, 50, 100, 150]
vols = [1.047, 0.4812, 0.4327, 0.4268, 0.4148, 0.4253, 0.4322, 0.4495]

fwd = 0.01076
expiry = 0.25
shift = 0.0110 # Shift chosen to make first strike positive

# params are sigma_0, beta, vol_vol, rho
params = [0.4, 0.6, 0.1, -0.4]

# Optimise SABR least squares using python's minimize function
def f(params):
    alpha, beta, nu, rho = params[0], params[1], params[2], params[3]

    alpha = max(alpha, 1e-8) # Avoid alpha going negative
    beta = max(beta, 1e-8) # Avoid beta going negative
    nu = max(nu, 1e-8) # Avoid nu going negative
    rho = max(rho, -0.999) # Avoid rhp going < -1.0
    rho = min(rho, 0.999) # Avoid rho going > 1.0

    calc_vols = np.array([
        ql.sabrVolatility(strike*1e-4 + shift, fwd + shift, expiry, alpha, beta, nu, rho)
        for strike in strikes
    ])

    error = ((calc_vols - np.array(vols))**2 ).mean() **.5
    return error

cons = (
    {'type': 'ineq', 'fun': lambda x: x[0]},
    {'type': 'ineq', 'fun': lambda x: 0.99 - x[1]},
    {'type': 'ineq', 'fun': lambda x: x[1]},
    {'type': 'ineq', 'fun': lambda x: x[2]},
    {'type': 'ineq', 'fun': lambda x: 1. - x[3]**2}
)

result = optimize.minimize(f, params, constraints=cons, options={'eps': 1e-5})
alpha, beta, nu, rho = result['x'][0], result['x'][1], result['x'][2], result['x'][3]

calc_vols = np.array([
    ql.sabrVolatility(strike*1e-4 + shift, fwd + shift, expiry, alpha, beta, nu, rho)
    for strike in strikes
])

results = pd.DataFrame([vols, calc_vols], columns=strikes, index=['market', 'SABR'])

0 votos

Así es, SABR intenta ajustarse al mercado lo más posible, por lo que si el mercado no tiene "sonrisa", probablemente SABR tampoco la tenga. La sonrisa está controlada por el parámetro SABR vol-of-vol (que es pequeño en el ajuste anterior) y la pendiente está determinada por una combinación de rho y beta - un rho pequeño y una beta cercana a 0 conducen a la pendiente descendente que vemos aquí

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