본문 바로가기
금융공학

배리어옵션 - UOC 옵션 #5 Binomial Tree(이항트리)

by hustler78 2022. 8. 29.
728x90
반응형

 

 

이번 글은 UOC(Up and Out Call option) 상품을 Binomial Tree로 구해보는 내용으로써

2022.08.29 - [금융공학] - 배리어옵션 - UOC 옵션 #4 MonteCarlo Simulation

 

배리어옵션 - UOC 옵션 #4 MonteCarlo Simulation

이번 글 역시 UOC(Up and Out Call) 옵션의 가격을 구하는 방법에 대해 알아봅니다. 여태까지 ○ Closed Form으로 구하는 방법 ○ Implicit FDM으로 구하는 방법 을 알아보았습니다. 저번 글은 2022.08.25 - [금융

sine-qua-none.tistory.com

에서 이어집니다. 우선 Binomial Tree를 복습해보고, UOC의 가격을 계산할 때는 어떤 점을 주의해야 하는지 알아보겠습니다.

 

 

 

Binomial Tree  복습

주식은 상승(상승률 $u$), 하락(하락률 $d$) 두 가지 상태이고, $ud=1$ 을 만족하며 GBM의 기댓값과 분산을 만족하도록 상승확률 $p$와 하락 확률 $1-p$를 설계하며 다음과 같았습니다.

 

너무 지겹게 등장해, 이제 외울떄도 될만한 그림

이러한 이항 모델(binomial model)을 붙여 다음처럼 이항 트리를 만듭니다.

○ 만기까지 $N$개의 time step으로 분할합니다.

○ $n$번째 time step에는 $n$개의 주가분포가 있는데 $ S_0 u^i d^{n-i}, 0\leq i\leq n$ 형태입니다.

○ 각 node에서 결정된 파생상품 값을 $f(n,i)$라 하면

○ $f(N,i)$ 는 만기 시점 페이오프, 배리어 위에서는 리베이트, 아닌 경우 콜옵션 페이오프
○ $ f(n,i) = e^{-r\Delta t} \left[ p f(n+1,i+1) + (1-p) f(n+1,i)\right]$ 의 점화식을 만족
○ $f(n,i)$ 를 위의 점화식으로 구한 뒤, 배리어 위쪽에 위치한 노드의 값은 리베이트로 대체(중요!)
○ $ f(0,0)$ 이 바로 현재 시점, 현재 주가 에서의 파생상품의 가치

 

 

점화식으로 backwar방향으로 시점 0까지 내려오면 되나, 각 time step의 배리어 이상에 위치한 노드값은 리베이트로 대체한다.

 

 

 

UOC 가격 계산 Python Code

 

 

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

N = norm.cdf

def UOC_by_BinomialTree(s0, strike, maturity, upBarrier, rfr, vol, div, rebate):
    nNode = 1000
    dt = maturity / nNode

    u = np.exp(vol * np.sqrt(dt))
    d = 1 / u
    a = np.exp((rfr - div) * dt)
    p = (a - d) / (u - d)

    valueNode = np.zeros((nNode + 1, nNode + 1))
    for n in reversed(range(nNode + 1)):
        for i in range(n + 1):
            spotS = s0 * u ** i * d ** (n - i)
            if n == nNode:
                if spotS > upBarrier:
                    valueNode[n, i] = rebate
                else:
                    valueNode[n, i] = np.max([spotS - strike, 0])
            else:
                if spotS > upBarrier:
                    valueNode[n, i] = rebate
                else:
                    up_val = valueNode[n + 1, i + 1]
                    down_val = valueNode[n + 1, i]
                    df = np.exp(-rfr * dt)
                    valueNode[n, i] = (p * up_val + (1 - p) * down_val) * df

    return valueNode[0, 0]

def calculate_UOC():
    s0 = 100
    strike = 100
    maturity = 1
    upBarrier = 120
    rfr = 0.02
    vol = 0.2
    div = 0.01
    rebate = 3

    uoc_value_binomial_tree = UOC_by_BinomialTree(s0, strike, maturity,upBarrier,rfr,vol,div,rebate)
    print('UOC_value_Binomial tree: {}'.format(uoc_value_binomial_tree))
    print('UOC_value_ClosedForm: {}'.format(UOcall_ClosedForm(s0, strike, maturity, upBarrier, rfr, vol, div, rebate)))

if __name__ == '__main__':
    calculate_UOC()

 

Binomial Tree 구현하는 부분을 검토해 보겠습니다.

def UOC_by_BinomialTree(s0, strike, maturity, upBarrier, rfr, vol, div, rebate):
    nNode = 1000	# time step를 1000개로 쪼개고
    dt = maturity / nNode	# 시점 간격을 dt로 정의합니다.

    u = np.exp(vol * np.sqrt(dt))	# 이항모델의 u,d 및 p를 계산하고
    d = 1 / u
    a = np.exp((rfr - div) * dt)
    p = (a - d) / (u - d)

    valueNode = np.zeros((nNode + 1, nNode + 1))	# 각 node의 값 저장을 위해 2차원 배열 정의
    for n in reversed(range(nNode + 1)):	# n을 역순으로 감소시키면서 0까지 for문 돌리며
        for i in range(n + 1):
            spotS = s0 * u ** i * d ** (n - i)	#각 주가node에 주가를 정의하고
            if n == nNode:	# 만일 만기시점이면
                if spotS > upBarrier:	# 배리어 위에서 리베이트를
                    valueNode[n, i] = rebate
                else:
                    valueNode[n, i] = np.max([spotS - strike, 0])	#배리어 밑에서 콜옵션페이오프를
            else:
                if spotS > upBarrier:
                    valueNode[n, i] = rebate	#배리어 위에서는 rebate
                else:
                    up_val = valueNode[n + 1, i + 1]
                    down_val = valueNode[n + 1, i]
                    df = np.exp(-rfr * dt)
                    valueNode[n, i] = (p * up_val + (1 - p) * down_val) * df	# 배리어 밑에서 점화식으로

    return valueNode[0, 0]	#현재시점 현재가에서의 node가격을 return함

 

 

 

결과를 보겠습니다.

UOC_value_Binomial tree: 2.150678731567234
UOC_value_ClosedForm: 2.1397093466460846

아주 좋은 결과를 얻었습니다. Closed form의 결과와 상당히 유사하죠.

 

 

 

참고 사항

 

2022.08.22 - [금융공학] - 옵션 #7. 옵션 프리미엄 구하기 실습: Binomial Tree에서 옵션의 가격을 Binomial Tree로 계산할 때, 재귀적 함수 형식으로 코딩하였습니다. 즉,

 

def UOC_by_BinomialTree_recursiveform(s0, strike, maturity, upBarrier, rfr, vol, div, rebate):
    nNode = 20
    dt = maturity / nNode

    u = np.exp(vol * np.sqrt(dt))
    d = 1 / u
    a = np.exp((rfr - div) * dt)
    p = (a - d) / (u - d)

    def treeNode(n, i):
        spotS = s0 * u ** i * d ** (n - i)
        if n == nNode:
            if spotS > upBarrier:
                return rebate
            else:
                return np.max([spotS - strike, 0])
            # return np.max([s0 * u ** (2 * i - n) - strike, 0])
        elif n < nNode:
            if spotS > upBarrier:
                return rebate
            else:
                up_val = treeNode(n + 1, i + 1)
                down_val = treeNode(n + 1, i)
                df = np.exp(-rfr * dt)
                return (p * up_val + (1 - p) * down_val) * df

    start_time = time.time()
    res = treeNode(0, 0)
    elapsed_time = time.time() - start_time

    return res

위와 같이 함수 treeNode 안에 또 treeNode를 구현하는 형식으로 코딩을 했었죠. 그런데, 이 방법이 계산시간이 하세월이 걸리는 겁니다. 코드의 어느 부분이 잘못됐는지, 아님 재귀적 함수 사용 알고리즘이 원래 시간을 많이 잡아먹는 건지.. 어쨌든 계산시간이 너무 걸려 부득불 본문처럼 valueNode라는 배열을 선언하여 다시 코딩했더니 거의 실시간 계산이 가능했습니다. 이러한 현상을 좀 더 공부해 봐야겠습니다.

 

이로써, UOC 옵션의 가격에 대해서 글을 마치겠습니다. 다음 글에서는 더욱 유명한 파생상품을 소개해 보도록 하겠습니다.

 

 

 

 

 

728x90
반응형

댓글