이번 글은
2023.04.27 - [금융공학] - 델타, 감마, 스피드! 콜옵션의 가격 변화를 쫓아가보자 #1
델타, 감마, 스피드! 콜옵션의 가격 변화를 쫓아가보자 #1
이 글은 테일러 전개 : 파생상품 헤지의 준비 이론 테일러 전개 : 파생상품 헤지의 준비 이론 이 글은 예전글인 2022.05.19 - [수학의 재미/아름다운 이론] - 테일러 전개 #1 테일러 전개 #1 무한번 미
sine-qua-none.tistory.com
와 관련이 있습니다.
파생상품의 민감도(Greeks) 들은 파생상품의 가격 공식을 미분하여 얻어집니다. 예컨대, 시점 t, 기초자산 S에서의 가격이 f(t,S)로 주어지는 파생상품의 델타, 감마, 스피드는 각각
Δ=∂f∂S , Γ=∂2f∂S2 , Speed=∂3f∂S3
으로 정의되죠. 하지만, 이렇게 구하는 방법에는 몇 가지 애로사항이 있습니다.
○ 파생상품의 가격 f(t,S)가 공식으로 주어지지 않는 다면 어쩔 것이냐?
우리가 앞서 알아본 콜옵션/풋옵션은 상품 가격이 공식으로 주어집니다. 이른바 Black Scholes Formula 이죠. 그런데 대부분의 상품에 가격 공식이 있는 것이 아닙니다. 예컨대, ELS ([금융공학] - 1star 스텝다운 ELS의 계산(시뮬레이션) 참고)의 경우만 하더라도 공식이 없어서, MC나 FDM 또는 이항트리(binomial tree)를 이용하여 구하는 실정입니다. 공식이 주어지지 않으면 식(1)을 쓸 수 조차 없겠죠.
○ 미분은 틀리기 마련이다?!
식 (1)을 쓰기 위해서는 정확한 미분 실력이 있어야 합니다. 공식 자체가 복잡해지면, 한 번 미분하는 것(델타)도 어렵습니다. 하물며, 감마, 스피드는 오죽할까요? 꾸역꾸역 미분, 2차 도함수, 3차 도함수들을 구해보더라도 이것이 맞는지 검증이 필요합니다.
이번 글에서는 다른 방법으로 그릭들을 구하는 방법을 소개합니다.
수치해석적 미분
시점 t, 기초자산 S에서 어떤 파생상품의 가격을 f(t,S) 라 합시다. 이 함수 f는 공식이 없어도 되고, 미분 가능한지 안 한 지 따질 수도 없다고 합시다(사실은 2번까지는 미분가능하다는 것이 금융공학의 전제조건이긴 합니다. 암묵적으로 f는 2번까지는 미분 가능합니다.)
이 때, 수치해석적인 방법으로 1차, 2차, 3차 도함수를 구할 수 있습니다(각각 델타, 감마, 스피드에 해당되겠죠.)
이번 설명에서 관심 있는 변수는 S이므로 t는 고정되어 있다고 생각하여 f(t,S):=f(S)로 한 변수인 것처럼 생각하겠습니다.
1차 도함수
∂f∂S≈f(S+h/2)−f(S−h/2)h
입니다. 위 식에서 h는 (아주) 작은 양수입니다. 이렇게 정의하는 방법을 중앙차분법(central difference)라 합니다. 다른 방법으로,
∂f∂S≈f(S+h)−f(S)h
∂f∂S≈f(S−h)−f(S)−h
로 정의하는 경우도 많습니다. 식(3)을 전방 차분 (forward difference), 식(4)을 후방 차분(backward difference)라고 합니다. 무슨 근사치를 써도 상관은 없으나, 보통 식(2)의 중앙 차분을 많이 사용합니다.
식(2), (3), (4) 공히 h가 무한히 작아지게 된다면, 실제로 1차 도함수로 가죠. 고등학교 때 배웠던 미분의 정의입니다.
2차 도함수
2차 도함수는 어떻게 수치해석적 근사식을 만들 수 있을까요?
f″
첫 번째 줄은 식(2)을 적용한 결과입니다. 두 번째 줄은 f'(S+h/2)와 f'(S-h/2)에 다시 한번 식(2)를 적용한 결과입니다.
3차 도함수
3차 도함수의 근사식은 아래처럼 구합니다.
\begin{align} f'''(S) & \approx \frac { f''(S+h/2)-f''(S-h/2) }{h} \\ &\approx \Bigg(\frac{f(S+h/2+h/2)-2f(S+h/2)+f(S+h/2-h/2)}{(h/2)^2} \\ & ~~~~~~~~~~-\frac{f(S-h/2+h/2)-2f(S-h/2)+f(S-h/2-h/2}{(h/2)^2}\Bigg)\Big/ h\\ &\approx \frac{f(x+h)-2f(x+h/2)+2f(x-h/2)-f(x-h)}{h^3/4}\tag{6} \end{align}
이제 식(2) , (5), (6)을 주목해 주시기 바랍니다. 이것들이 각각 델타, 감마, 스피드가 되니까요!
그럼 이렇게 수치해석적으로 구한 그릭들이 여기에 기재한 콜옵션의 공식 그릭과 비슷한지 아닌지 코딩을 통하여 알아보겠습니다.
Python Code: Greeks들을 수치해석적으로 구하기
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):
# 전의 글들을 참고하기 바랍니다.
# -----------------------------------------------------
# ---- CallOptionBS_NumericalGreeks 함수 설명 ----------
# delta, gamma, speed를 수치해석적으로 구하는 함수
# call option value 는 Black Scholes Formula를 그대로 씀
# -----------------------------------------------------
def CallOptionBS_NumericalGreeks(S, K, T, r, q, sigma):
Ncdf = norm.cdf
npdf = norm.pdf
ds = 0.01 * S # 본문의 h로 표시한 것(h=dS), S의 크기에 1%를 h로 설정
val = CallOptionBS(S, K, T, r, q, sigma)[0]
val_up = CallOptionBS(S + ds / 2, K, T, r, q, sigma)[0] # h/2 bumping up
val_up2 = CallOptionBS(S + ds, K, T, r, q, sigma)[0] # h bumping up
val_down = CallOptionBS(S - ds / 2, K, T, r, q, sigma)[0] # h/2 bumping down
val_down2 = CallOptionBS(S - ds, K, T, r, q, sigma)[0] # h bumping down
# 본문의 식(2), (5), (6)을 코딩한 결과
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)
# 0. value
# 1. delta
# 2. gamma
# 3. speed
return val, delta, gamma, speed # value, delta, gamma, speed 를 return
def analysis_call_option_numerical_greeks():
s0 = 100
strike = 100
maturity = 1
rfr = 0.03
div = 0
vol = 0.3
spot_array = np.arange(50, 150 + 1, 1) # 기초자산은 50~ 150까지 1간격으로 array 만듬
delta_list = []
gamma_list = []
speed_list = []
for s in spot_array:
res_analytic = CallOptionBS(s, strike, maturity, rfr, div, vol) # 공식으로 구한 greeks
res_numerical = CallOptionBS_NumericalGreeks(s, strike, maturity, rfr, div, vol)
# 수치해석적 greeks
delta_list.append([res_analytic[1], res_numerical[1]]) # [공식 델타, 수치해석 델타] list
gamma_list.append([res_analytic[2], res_numerical[2]]) # [공식 감마, 수치해석 감마] list
speed_list.append([res_analytic[3], res_numerical[3]]) # [공식 speed, 수치해석 speed] list
delta_array = np.array(delta_list) #list의 array화 (밑에 slicing을 위하여)
gamma_array = np.array(gamma_list)
speed_array = np.array(speed_list)
from matplotlib import gridspec
fig = plt.figure(figsize=(10, 30))
gs = gridspec.GridSpec(nrows=3, ncols=1, height_ratios=[1, 1, 1])
ax = [fig.add_subplot(gs[0]), fig.add_subplot(gs[1]), fig.add_subplot(gs[2])]
# 기초자산 가격에 따른 공식 델타와, 수치해석 델타를 그래프에 같이 표시
ax[0].plot(spot_array, delta_array[:, 0], color='lightgray', linewidth=5, label='delta_closedform')
ax[0].plot(spot_array, delta_array[:, 1], color='blue', linewidth=2, linestyle='--'
, label='delta numerical')
ax[0].legend()
# 공식 델타와 수치해석 델타 array의 원소중 차이가 가장 큰 것을 출력
print('Maximum difference between closed form delta and numerical delta : {:.10f}'.format(
np.max(np.abs(delta_array[:, 1] - delta_array[:, 0]))))
# 기초자산 가격에 따른 공식 감마와, 수치해석 감마를 그래프에 같이 표시
ax[1].plot(spot_array, gamma_array[:, 0], color='lightgray', linewidth=5, label='gamma_closedform')
ax[1].plot(spot_array, gamma_array[:, 1], color='tomato', linewidth=2, linestyle='--', label='gamma numerical')
ax[1].legend()
# 공식 감마와 수치해석 감마 array의 원소중 차이가 가장 큰 것을 출력
print('Maximum difference between closed form gamma and numerical gamma : {:.10f}'.format(
np.max(np.abs(gamma_array[:, 1] - gamma_array[:, 0]))))
# 기초자산 가격에 따른 공식 스피드와, 수치해석 스피드를 그래프에 같이 표시
ax[2].plot(spot_array, speed_array[:, 0], color='lightgray', linewidth=5, label='speed_closedform')
ax[2].plot(spot_array, speed_array[:, 1], color='green', linewidth=2, linestyle='--', label='speed numerical')
ax[2].legend()
# 공식 스피드와 수치해석 스피드 array의 원소중 차이가 가장 큰 것을 출력
print('Maximum difference between closed form speed and numerical speed : {:.10f}'.format(
np.max(np.abs(speed_array[:, 1] - speed_array[:, 0]))))
plt.show()
if __name__ == '__main__':
analysis_call_option_numerical_greeks()
결과를 보겠습니다.
Maximum difference between closed form delta and numerical delta : 0.0000148013
Maximum difference between closed form gamma and numerical gamma : 0.0000014086
Maximum difference between closed form speed and numerical speed : 0.0000000613
기초자산 가격이 50에서 150까지 각각 델타, 감마, 스피드를 수치해석적으로 구하여, 이를 공식과 비교하여 차이가 가장 큰 값을 계산해 본 결과입니다. 공식과 수치해석 결과가 거의 차이가 나지 않는다는 것을 알 수 있습니다. 이는 아래 그래프를 봐도 알 수 있습니다. 델타, 감마, 스피드 각각 공식과 수치해석적 방법 두 그래프가 완전히 겹치는 모습이죠.

이제 이 분석을 통하여 우리는 두 가지 정보를 얻을 수 있습니다.
○ 수치해석적 방법과 공식(미분)이 거의 차이가 없으니 우리가 미분을 실수 없이 잘했었구나. 그거 그대로 믿고
사용해도 되겠다!
○ 굳이 델타, 감마 등을 미분해서 구할 필요가 있나? 계산 실수할 수도 있는데.. 그냥 수치 해석적 방법을 써야겠다!
파생상품의 가격 공식이 공식으로만 끝나는 경우는 없습니다. 이 공식을 프로그래밍하여 파생상품의 움직임을 분석하고 운용하는 게 목적이죠. 어차피 프로그래밍을 할 것이라면, 이렇게 수치해석적인 방법론이, 연습장과 연필로 푼 미분 공식값과 일치하는지 따져보는 일은 충분히 가치 있는 일이 될 것입니다.
또한, 공식이 없는 파생상품들을 위해 그릭들을 수치해석적으로 구하는 방법을 알아두면 큰 도움이 되겠죠.
'금융공학' 카테고리의 다른 글
몬테카를로 시뮬레이션과 그릭의 안정성 #2 : 시드 고정 (0) | 2023.07.12 |
---|---|
몬테카를로 시뮬레이션과 그릭의 안정성 #1 (0) | 2023.07.07 |
풋옵션의 민감도들은? feat. 풋콜패리티 (0) | 2023.06.19 |
로(Rho)! 콜옵션은 이자율에 어떤 영향을 받을까? (0) | 2023.06.14 |
로(Rho)! 콜옵션의 이자율 민감도는? (0) | 2023.06.09 |
댓글