본문 바로가기
금융공학

MC로 콜옵션 델타 구하기: likelihood 방법

by hustler78 2023. 7. 14.
728x90
반응형

 

 

이번 글은 [금융공학] - 몬테카를로 시뮬레이션과 그릭의 안정성 #2 : 시드 고정

 

몬테카를로 시뮬레이션과 그릭의 안정성 #2 : 시드 고정

이번 글은 2023.07.07 - [금융공학] - 몬테카를로 시뮬레이션과 그릭의 안정성 #1 몬테카를로 시뮬레이션과 그릭의 안정성 #1 이번 글은 2023.06.23 - [금융공학] - 그릭을 수치 해석적인 방법으로 해결하

sine-qua-none.tistory.com

 에서 이어집니다. 저번 글에서는

 

1) MonteCarlo 시뮬레이션을 이용하여 콜옵션의 가격을 구하고

 

2) 수치해석적(유한차분법)으로 콜옵션의 델타를 구했습니다.

 

즉, 콜옵션의 델타를 MC 시뮬레이션으로 구하는 법이라고 볼 수 있겠습니다. 이 글에서는

 

 MC를 이용하여 콜옵션 델타를 구하는 또 다른 방법

 

에 대해 알아보겠습니다. 

 

 

 

파생상품의 가치 복습

 

예전 글

[금융공학] - Black Scholes Equation의 풀이: 확률프로세스를 이용하자.

 

Black Scholes Equation의 풀이: 확률프로세스를 이용하자.

이번 글은 2022.08.04 - [금융공학] - Black Scholes Equation의 풀이 Black Scholes Equation의 풀이 이번 글은 2022.08.03 - [금융공학] - Black Scholes Equation과 Heat Equation의 관계 Black Scholes Equation과 Heat Equation의 관계

sine-qua-none.tistory.com

를 이용하면 시점 $t=0$에서의 콜옵션의 가치는 

$$ c(t,S) = e^{-r T}\mathbb{E}\left[ \max(S_T-K,0)\right] \tag{1}$$
로 정의합니다.

 

원래는 

$$ c(t,S) = e^{-r (T-t)}\mathbb{E}\left[ \max(S_T-K,0) | \mathcal{F}_t \right] $$

라고 filtration을 사용하여 표현해야 하나, 뒤에 등장한 수식 전개를 간단하게 설명하기 위해 일반성을 잃지 않고 $t=0$이라 생각하는 것입니다.

 

 

 

콜옵션 델타 구하기! 기댓값의 미분

 

이제 식 (1)과 미분의 정의를 시용하여 델타를 구해봅시다. 델타는 

$$ \frac{\partial c(t,S)}{\partial S} $$

로 정의됩니다. 

우선 델타를 구하는 수식을 쭉 나열해보고 하나씩 설명해 보겠습니다.


$$
\begin{align}
\frac{\partial c(t,S)}{\partial S} &= \frac{\partial}{\partial S} e^{-rT} \mathbb{E}\left[ \max(S_T-K,0)\right]\\
& = e^{-rT}\mathbb{E}\left[ \frac{\partial}{\partial S} \max(S_T-K,0) \right]\\
& = e^{-rT} \mathbb{E} \left[ \frac{\partial}{\partial S_T} \max(S_T-K,0) \cdot \frac{\partial S_T}{\partial S} \right]\\
& = e^{-rT} \mathbb{E} \left[ I(S_T\geq K) \cdot \frac{\partial S_T}{\partial S} \right]\\
& = e^{-rT} \mathbb{E} \left[ I(S_T\geq K) \cdot \frac{S_T}{S} \right] \tag{2}
\end{align}
$$

 

 

○ 2번째 등식은 편미분과 기댓값의 순서를 바꾸는 장면입니다. 기댓값은 보통 적분이므로, 이 뜻은 미분과 적분의 순서를 바꿔준다는 뜻이 되겠습니다.

 

○ 세 번째 등식은 Chain Rule입니다. 

 

○ 네 번째 등식은  $\max(x,0)$ 형태의 함수에 대한 미분입니다. 사실 이러한 형태의 함수는 $x=0$ 에서 꺾어지는 그래프로 이 점에서 미분이 불하하지만, 이 점을 제외한 나머지 영역에서는 미분이 가능합니다. 즉,  $x>=0$일 때는 미분계수가 $1$이고 $x <0$ 영역에서는 미분계수가 0이 됩니다. 즉, 러프하게

$$ \frac {d}{dx} \max(x,0) = I(x\geq 0)$$

이 됩니다. $I(\cdot)$는 인디케이터 함수(indicator function)로서, 괄호 안의 조건을 만족하면 $1$, 아니면 $0$을 함숫값으로 가지는 함수입니다.

 

○ 다섯 번째 등식은
$$ S_T = S \exp \left( (r-q-\frac12\sigma^2) T+\sigma \sqrt {T} z \right)$$
이므로 
$$ \frac{\partial S_T}{\partial S} =\exp \left( (r-q-\frac12\sigma^2)T+\sigma \sqrt{T} z \right) =S_T/S$$ 
을 만족하기 때문입니다.

 

 

이제 식(2)을 이용하여 MC 시뮬레이션 방법을 이용하여 델타를 구할 수 있습니다. 이 방법을 likelihood method라고도 합니다.

 

 

 

 

 Python Code: 콜옵션의 델타 구하기(feat. MC)

 

델타를 MC로 구하는 방법은 식(2)를 이용하는 것입니다. $S_T$ 샘플을 가능한 많이 만든 뒤,

$$ I(S_T\geq K) \cdot S_T/S$$

의 값을 채취하여 기댓값을 구한 후,

여기에 할인펙터 $e^{-rT}$를 곱해주면 되겠죠.

 

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
import pandas as pd

def CallOptionBS(S, K, T, r, q, sigma):
    # 지난 글 참조

# call option value를  MC로 구하기
def callvalue_by_MC(svalue, strike, maturity, rfr, div, vol, nIter):
    np.random.seed(0)
    drift = (rfr - div - 0.5 * vol ** 2) * maturity  # 주가 패스의 drift term
    volsqrtmat = vol * np.sqrt(maturity)  # 주가 패스생성의 diffusion term

    rvec = np.random.normal(size=nIter)  # nIter (시뮬레이션 횟수) 만큼의 random number
    s_maturity = svalue * np.exp(drift + volsqrtmat * rvec)  # 만기 종가 sample 산출
    payoff = np.array([np.maximum(0, s_mat - strike) for s_mat in s_maturity])  # 각 종가 sample별 만기 payoff
    dfactor = np.exp(-rfr * maturity)  # disounct factor 산출
    opt_value = payoff.mean() * dfactor  # 만기 payoff의 평균(기댓값) * 할인율

    return opt_value

# 위의 함수를 토대로 민감도(delta, gamma, speed) 모두 구하는 함수
# 구하는 과정은 수치해석적으로 유한차분법을 통해 구한다.
def callvalueGreeks_MC(svalue, strike, maturity, rfr, div, vol, nIter):
    ds = svalue * 0.01
    val = callvalue_by_MC(svalue, strike, maturity, rfr, div, vol, nIter)
    val_up = callvalue_by_MC(svalue + ds / 2, strike, maturity, rfr, div, vol, nIter)
    val_up2 = callvalue_by_MC(svalue + ds, strike, maturity, rfr, div, vol, nIter)
    val_down = callvalue_by_MC(svalue - ds / 2, strike, maturity, rfr, div, vol, nIter)
    val_down2 = callvalue_by_MC(svalue - ds, strike, maturity, rfr, div, vol, nIter)

    delta = (val_up - val_down) / (ds)
    gamma = (val_up2 - 2 * val + val_down2) / (ds ** 2)
    speed = (val_up2 - 2 * val_up + 2 * val_down - val_down2) / (ds ** 3 / 4)

    return val, delta, gamma, speed


# 이 글에서 다뤘던 로직으로 델타구하기
def callvalue_delta_likelihood(svalue, strike, maturity, rfr, div, vol, nIter):
    np.random.seed(0)
    drift = (rfr - div - 0.5 * vol ** 2) * maturity  # 주가 패스의 drift term
    volsqrtmat = vol * np.sqrt(maturity)  # 주가 패스생성의 diffusion term

    rvec = np.random.normal(size=nIter)  # nIter (시뮬레이션 횟수) 만큼의 random number
    s_maturity = svalue * np.exp(drift + volsqrtmat * rvec)  # 만기 종가(ST) sample 산출
    indicator = np.where(s_maturity >= strike, 1, 0)     # I(S_T>=K) 산출 : indicator function

    sample = indicator * s_maturity / svalue             # 식(2)의 기댓값 E() 속 샘플의 값

    dfactor = np.exp(-rfr * maturity)  # disounct factor 산출
    delta_likelihood = sample.mean() * dfactor

    return delta_likelihood

if __name__ == '__main__':
    strike = 100
    maturity = 1
    rfr = 0.03
    div = 0
    vol = 0.3
    nIter = 10000

    spot_array = np.arange(50, 150 + 1, 1)  # stock은 50 - 150 까지 1 간격으로 생성

    closed_form_delta = []    # closed form delta
    mc_delta = []             # MC로 구한 value에서 유한 차분으로 뽑아낸 델타
    likelihood_delta = []	  # 이 글에서 다룬 델타 (likelihood method)

    for s in spot_array:
        closed_form_delta.append(CallOptionBS(s, strike, maturity, rfr, div, vol)[1])  # call closed form
        mc_delta.append(callvalueGreeks_MC(s, strike, maturity, rfr, div, vol, nIter)[1])  # call MC
        likelihood_delta.append(callvalue_delta_likelihood(s, strike, maturity, rfr, div, vol, nIter))

    closed_form_delta = np.array(closed_form_delta)
    mc_delta = np.array(mc_delta)
    likelihood_delta = np.array(likelihood_delta)
    
    # closed form과 이 글에서 다룬 방법간의 델타 차이 최댓값
    print('Max. diff. between closed form delta and likelihood delta : {:.10f}'.format(
        np.max(np.abs(closed_form_delta - likelihood_delta))))
        
    # MC delta갑과 이 글에서 다룬 방법간의 델타 차이
    print('Max. diff. between      MC     delta and likelihood delta : {:.10f}'.format(
        np.max(np.abs(mc_delta - likelihood_delta))))

    plt.plot(spot_array, closed_form_delta, label='closed form', linestyle='dashed', linewidth=3, color='gray')
    plt.plot(spot_array, mc_delta, label='mc', color='c', linewidth=5)
    plt.plot(spot_array, likelihood_delta, 'o', markersize=4, label='likelihood', color='blue')
    plt.legend()
    plt.show()

 

결과는 다음과 같습니다.

Max. diff. between closed form delta and likelihood delta : 0.0195719511
Max. diff. between      MC     delta and likelihood delta : 0.0008158635

 

우선, closed form으로 구한 값과 이 글의 로직을 통한 값은 차이가 좀 발생합니다. 그런데 MC로 구한 값과의 차이는 거의 안 나죠?

 

이 글의 로직을 likelihood method라고도 하는데, 이 로직과 MC로직은 위 그래프에서도 보듯이 얼마 차이가 나지 않습니다. closed form과도 역시 큰 차이는 나지 않죠.

 

따라서 식(2)은 델타를 구하는 아주 훌륭한 방법입니다. 뿐만 아니라, MC 및 유한차분을 통한 방법은 주가를 위아래로 올렸다 내렸다 하는 값들을 모두 구해야 하므로 계산 속도나 발생시켜야 하는 난수의 개수 등에서 likelihood method 보다 비효율적입니다.

 

그렇다면 식(2)을 더욱더 정리해서 우리가 델타, 감마, 스피드! 콜옵션의 가격 변화를 쫓아가보자 #2에서 구한 콜옵션의 델타

$$ \Phi(d_1)$$

이 나오는지를 간단히 알아보도 넘어가겠습니다($d_1$ 등의 기호의 정의는 링크된 글에서 확인해 보시기 바랍니다.)

 

 

 

여담

식(2)를 더욱 전개하여, 우리가 예전에 알아본 콜옵션 델타가 얻어지는지를 알아보겠습니다. 식(2)은 아래와 같이 적분 형태로 바꿀 수 있습니다(기댓값이 적분이기 때문이죠.)

 

$$ \mathbb{E} \left[ I(S_T\geq K) \cdot \frac{S_T}{S} \right] = \int_{ I(S_T\geq K)}  \frac{S_T}{S} dP$$

여기서, $P$는 확률측도입니다. 이것을 표준정규분포를 따르는 매개변수 $z$로 바꿔봅시다. 우선
$$ S_T\geq K $$ 는 $$ z\geq \frac{\ln(K/S)-(r-q-\frac12\sigma^2)T}{\sigma\sqrt{T}}:=\alpha $$
과 동치입니다. $$ S_T = S \exp \left( (r-q-\frac12\sigma^2)T+\sigma \sqrt{T} z \right)$$
이기 떄문이죠. 또한, $$dP = \phi(z) dz$$이므로


$$ \mathbb{E} \left[ I(S_T\geq K) \cdot \frac{S_T}{S} \right] = \int_\alpha^{\infty} \exp \left( (r-q-\frac12\sigma^2)T+\sigma \sqrt{T} z \right) \phi(z)dz$$
가 됩니다.

 

그런데, 먼저 아래식을 구해 봅시다.
$$
\begin{align}
\int_\alpha^\infty e^{\sigma \sqrt{T} z} \phi(z)dz & = \int_\alpha\infty \frac1{\sqrt{2\pi}} e^{-\frac12 z^2+\sigma\sqrt{T}z}dz\\
 &=e^{\frac12\sigma^2 T} \int_\alpha^\infty \frac1{\sqrt{2\pi}} e^{-\frac12(z-\sigma\sqrt{T})^2}dz \\
 &=e^{\frac12\sigma^2 T} \int_{\alpha-\sigma\sqrt{T}}^\infty \frac1{\sqrt{2\pi}} e^{-\frac12w^2}dw \\
 &=e^{\frac12\sigma^2 T} \int_{\alpha-\sigma\sqrt{T}}^\infty \phi(w)dw \\
 &=e^{\frac12\sigma^2 T} \Phi(-\alpha+\sigma\sqrt{T})\\
 & = e^{\frac12\sigma^2 T} \Phi(d_1)

\end{align}
$$


따라서 콜옵션의 델타는

$$
\begin{align}
\frac{\partial c(t,S)}{\partial S} & = e^{-rT} \mathbb{E} \left[ I(S_T\geq K) \cdot \frac{S_T}{S} \right] \\
& = e^{-rT}\int_\alpha^{\infty} \exp \left( (r-q-\frac12\sigma^2)T+\sigma \sqrt{T} z \right) \phi(z)dz\\
&= e^{-rT}\exp \left( (r-q-\frac12\sigma^2)T\right) \int_\alpha^{\infty} e^{\sigma \sqrt{T} z} \phi(z)dz\\
& = e^{(-q-\frac12\sigma^2)T} \cdot e^{\frac12\sigma^2 T} \Phi(d_1)\\
& = e^{-qT} \Phi(d_1)
\end{align}
$$

 

 

이처럼, 기댓값(가격)과 미분(델타)의 순서를 바꾸어, 먼저 만기 페이오프를 미분하고, 그것을 적분하여 델타를 구할 수도 있습니다.

728x90
반응형

댓글