4 votos

Quantlib: Griegas de la opción FX en Python

Estoy utilizando Quantlib en Python para fijar el precio de una opción FX. Estoy comparando el resultado con Bloomberg, para asegurarme de que el código está funcionando correctamente.

También quiero calcular todas las griegas, y eventualmente utilizarlas en una expansión de Taylor de las pérdidas y ganancias (como por ejemplo: P&L de la opción de compra con cobertura delta )

La opción que estoy tratando de valorar, tiene el siguiente precio en Bloomberg: enter image description here

Es un ejemplo estilizado.

El código que utilizo es el siguiente:

import QuantLib as ql

Spot = 1.1
Strike = 1.101
Sigma = 10/100
Ccy1Rate = 5/100
Ccy2Rate = 10/100
OptionType = ql.Option.Call

#Option dates in quantlib objects
EvaluationDate = ql.Date(3, 1,2022)
SettlementDate = ql.Date(5, 1, 2022) #Evaluation +2
ExpiryDate = ql.Date(10, 1, 2022) #Evaluation + term which is 1 week
DeliveryDate = ql.Date(12, 1, 2022) #Expiry +2
NumberOfDaysBetween = ExpiryDate - EvaluationDate
#print(NumberOfDaysBetween)

#Generate continuous interest rates
EurRate = Ccy1Rate
UsdRate = Ccy2Rate

#Create QuoteHandle objects. Easily to adapt later on.
#You can only access SimpleQuote objects. When you use setvalue, you can change it.
#These global variables will then be used in pricing the option.
#Everything will be adaptable except for the strike.
SpotGlobal = ql.SimpleQuote(Spot)
SpotHandle = ql.QuoteHandle(SpotGlobal)
VolGlobal = ql.SimpleQuote(Sigma)
VolHandle = ql.QuoteHandle(VolGlobal)
UsdRateGlobal = ql.SimpleQuote(UsdRate)
UsdRateHandle = ql.QuoteHandle(UsdRateGlobal)
EurRateGlobal = ql.SimpleQuote(EurRate)
EurRateHandle = ql.QuoteHandle(EurRateGlobal)

#Settings such as calendar, evaluationdate; daycount
Calendar = ql.UnitedStates()
ql.Settings.instance().evaluationDate = EvaluationDate
DayCountRate = ql.Actual360()
DayCountVolatility = ql.ActualActual()

#Create rate curves, vol surface and GK process
RiskFreeRateEUR = ql.YieldTermStructureHandle(ql.FlatForward(0, Calendar, EurRateHandle, DayCountRate))
RiskFreeRateUSD = ql.YieldTermStructureHandle(ql.FlatForward(0, Calendar, UsdRate, DayCountRate))
Volatility = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(0, Calendar, VolHandle, DayCountVolatility))
GKProcess = ql.GarmanKohlagenProcess(SpotHandle, RiskFreeRateEUR, RiskFreeRateUSD, Volatility)

#Generate option
Payoff = ql.PlainVanillaPayoff(OptionType, Strike)
Exercise = ql.EuropeanExercise(ExpiryDate)
Option = ql.VanillaOption(Payoff, Exercise)
Option.setPricingEngine(ql.AnalyticEuropeanEngine(GKProcess))
BsPrice = Option.NPV()

ql.Settings.instance().evaluationDate = EvaluationDate
print("Premium is:", Option.NPV()*1000000/Spot)
print("Gamma is:", Option.gamma()*1000000*Spot/100)
print("Vega is:", Option.vega()*1000000*(1/100)/Spot)
print("Theta is:", Option.theta()*1000000*(1/365)/Spot)
print("Delta is:", Option.delta()*1000000)

Lo que da la siguiente salida:

Premium is: 5550.960519027888
Gamma is: 287777.2550015351
Vega is: 551.9015849344515
Theta is: -462.68771985750703
Delta is: 504102.4957777005

Coincide muy bien con Bloomberg, excepto con Theta. Intenté dividir por 255 (días laborables) en lugar de por 365, pero también está mal.

Me pregunto cuál es la respuesta correcta, ya que es necesaria para encontrar la expansión de Taylor P&L.

2 votos

Theta en BBG no es la fórmula de forma cerrada, sino un bache (un día menos hasta el vencimiento) porque así lo prefieren la mayoría de los usuarios.

0 votos

Gracias, y ya que estamos: ¿tienes idea de por qué el Delta tampoco coincide?

2 votos

Puede comprobarlo rápidamente fijando el precio un viernes, en cuyo caso la theta es aproximadamente 3 veces la del día anterior porque se adelanta al siguiente día de negociación. La diferencia en la delta se debe a que una es con prima incluida y la otra no. En OVML tienes un ajuste para esto. 504102 - 5550 = delta bbg

3voto

BC. Puntos 9229

Como se menciona en los comentarios, theta es bump y reprice. Por definición, un griego es todo lo demás igual. En este caso, significa mantener todas las entradas constantes, pero mover la fecha un día hacia adelante, y calcular la diferencia de valor, que es theta.

El lenguaje que aparece a continuación no es Python, sino Julia porque ya tenía este código. Sin embargo, la sintaxis es lo suficientemente similar a la de Python, por lo que debería ser posible seguir la lógica.

Importar todos los paquetes y definir el cdf.

using Distributions
N(x) = cdf(Normal(0,1),x)

Definir las entradas y calcular los índices continuos

spot = 1.1
f = 1.101070
strike = 1.101
ccy1 = 0.05 # EUR
ccy2 = 0.1 # USD
vol = 0.1
days = 7
t = days/365

r1_cont = log(1+ccy1*days/360)/(days/365)
r2_cont = log(1+ccy2*days/360)/(days/365)

Definir Garman Kohlhagen con delantero (técnicamente Negro76) => mismo resultado como se puede ver aquí .

function GKF(F,K,t,ccy2,)
    d1 = ( log(F/K) +  0.5*^2*t ) / (*sqrt(t))
    d2 = d1 - *sqrt(t)
    c  = exp(-ccy2*t)*(F*N(d1) - K*N(d2))
    p  =  exp(-ccy2*t)*(-F*N(-d1) + K*N(-d2))
  return c, p, d1, d2
end

Defina el valor de la opción de hoy y calcule el de mañana, con las mismas entradas pero con un día menos hasta el vencimiento. Theta es la diferencia numérica entre los dos VAN.

t1 = GKF(f,strike, days/365, r2_cont, vol)[1]*1000000/spot
t2 = GKF(f,strike, (days-1)/365, r2_cont, vol)[1]*1000000/spot
theta = t2-t1

enter image description here

Hay pequeñas diferencias de redondeo con el BBG porque sólo he utilizado los puntos fwd visibles en la captura de pantalla, que carece de la precisión decimal exacta.

En términos de quantlib, en lugar de

print("Theta is:", Option.theta()*1000000*(1/365)/Spot)

podría utilizar

print("Theta is:", Option.thetaPerDay()*1000000/Spot)

para ahorrar el cálculo manual de (1/365).

Sin embargo, no utilizo quantlib, así que no puedo comentar si ql puede calcular la diferencia finita theta.

El delta que se muestra en BBG (basado en su configuración) se calcula en ql así:

enter image description here

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