이 글은
2022.12.21 - [금융공학] - 1star 스텝다운 ELS의 계산(Binomial Tree)
에서 계속됩니다.
1star 스텝다운 ELS의 가격을 이항트리모형을 이용해 구해보겠습니다. 구하는 이론적 배경은 이전 글에서 설명했으니 참고하시기 바랍니다.
python code
def OneDimELS_BinomialTree(objUnderlying: Underlying, objMarket: Market, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration):
vol = objUnderlying._volatility
div = objUnderlying._dividend
rfr = objMarket._rfr
current_spot = objUnderlying._spot
refprice = objUnderlying._refprice
dt = 1 / 250
maturity = redemption_schedule[-1]
nSchedule = len(redemption_schedule)
# time variable setting
t_min, t_max = 0, maturity
nNode = t_max - t_min
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))
ki_valueNode = valueNode
nth_chance = nSchedule - 2 # 마지막 조기상환 index
start_time = time.time()
for n in range(nNode + 1)[::-1]:
for i in range(n + 1):
spotS = current_spot * u ** i * d ** (n - i)
if n == nNode:
payoff = 1 + coupon[-1] if spotS / refprice >= barrier[
-1] else 1 + full_dummy if spotS / refprice >= ki_barrier else spotS / refprice
ki_payoff = 1 + coupon[-1] if spotS / refprice >= barrier[-1] else spotS / refprice
valueNode[n, i], ki_valueNode[n, i] = payoff, ki_payoff
else:
up_val, ki_up_val = valueNode[n + 1, i + 1], ki_valueNode[n + 1, i + 1]
down_val, ki_down_val = valueNode[n + 1, i], ki_valueNode[n + 1, i]
df = np.exp(-rfr * dt)
valueNode[n, i] = (p * up_val + (1 - p) * down_val) * df
ki_valueNode[n, i] = (p * ki_up_val + (1 - p) * ki_down_val) * df
if n == redemption_schedule[nth_chance]:
if spotS / refprice >= barrier[nth_chance]:
valueNode[n, i] = 1 + coupon[nth_chance]
ki_valueNode[n, i] = 1 + coupon[nth_chance]
if spotS / refprice < ki_barrier:
valueNode[n, i] = ki_valueNode[n, i]
if n == redemption_schedule[nth_chance]:
nth_chance -= 1
cal_time = round(time.time() - start_time, 3)
return valueNode[0, 0], cal_time, valueNode
코드 설명은 다음과 같습니다.
def OneDimELS_BinomialTree(objUnderlying: Underlying, objMarket: Market, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration):
# class Underlying 과 class Market은 예전 글들에서 설명
1star 스텝다운 ELS의 계산(FDM) #2 등의 글을 참고하시면, Underlying과 Market class의 정의를 볼 수 있습니다.
nSchedule = len(redemption_schedule) # 상환시점 횟수 (3y6m의 경우 6번)
# time variable setting
t_min, t_max = 0, maturity # 현재시점 0, 만기시점: 3년(=750일)
nNode = t_max - t_min # time node는 0, 1, ..., 750 : nNode+1 개로 할 예정
u = np.exp(vol * np.sqrt(dt)) # 이항모형에서 상승률
d = 1 / u # 하락률, ud=1
a = np.exp((rfr - div) * dt)
p = (a - d) / (u - d) # 상승확률
valueNode = np.zeros((nNode + 1, nNode + 1)) # Node: timeNode는 nNode+1개, 각 시점 노드당
# 주식노드도 같은 갯수
ki_valueNode = valueNode # 낙인 쳤을 상황의 가격을 뜻하는 노드
nth_chance = nSchedule - 2 # the last 조기상환시점 index 뜻함 : 4 (=6-2)
for n in range(nNode + 1)[::-1]: # time step을 backward로 진행시키며
for i in range(n + 1): # 해당 time step에서 가능한 주가의 경우에 대해
spotS = current_spot * u ** i * d ** (n - i)
# 주가 생성 s= s0 u^i d^(n-i)
if n == nNode: # 만일 만기시점이면,
payoff = 1 + coupon[-1] if spotS / refprice >= barrier[
-1] else 1 + full_dummy if spotS / refprice >= ki_barrier else spotS / refprice
# 낙인 안쳤을때의 3갈래의 페이오프
ki_payoff = 1 + coupon[-1] if spotS / refprice >= barrier[-1] else spotS / refprice
# 낙인 쳤을 때의 두 갈래 페이오프
valueNode[n, i], ki_valueNode[n, i] = payoff, ki_payoff
# 위 두 페이오프를 각각 노낙인트리, 낙인트리에 대입
else:
up_val, ki_up_val = valueNode[n + 1, i + 1], ki_valueNode[n + 1, i + 1]
# 재귀식을 사용하기 위해 n+1번째 time node 값 추출
down_val, ki_down_val = valueNode[n + 1, i], ki_valueNode[n + 1, i]
# 재귀식을 사용하기 위해 n+1번째 time node 값 추출
df = np.exp(-rfr * dt) # 할인팩터
valueNode[n, i] = (p * up_val + (1 - p) * down_val) * df
# recursive formula
ki_valueNode[n, i] = (p * ki_up_val + (1 - p) * ki_down_val) * df
# recursive formula
if n == redemption_schedule[nth_chance]:
# 조기상환 시점에 닿으면
if spotS / refprice >= barrier[nth_chance]:
valueNode[n, i] = 1 + coupon[nth_chance]
ki_valueNode[n, i] = 1 + coupon[nth_chance]
# 낙인/노낙인 트리 모두 배리어이상의 주가에 대해서 쿠폰+원금으로 치환
if spotS / refprice < ki_barrier:
valueNode[n, i] = ki_valueNode[n, i]
# 각 time step별 낙인배리어 이하에 대해서는
# 낙인 트리의 값으로 update
if n == redemption_schedule[nth_chance]:
nth_chance -= 1 # 모든 주가에 대해 실행 후, 조기상환 단계를 전단계로 갱신
return valueNode[0, 0], cal_time, valueNode # timestep =0, 기초자산 step =0 이 현재가이고 이것을 반환
# 계산 소요시간 및 트리값 모두 반환
결과 테스트
대상상품은 이번에도 아래의 구조로 하겠습니다.
def els_price_various_test():
underlying_spot = Underlying(refprice=100, spotvalue=100, volatility=0.3, dividend=0)
interest_rate = Market(0.03)
redemption_schedule = np.array([1, 2, 3, 4, 5, 6]) * 125
coupon = np.array([1, 2, 3, 4, 5, 6]) * 0.05
full_dummy = coupon[-1]
barrier = np.array([0.9, 0.9, 0.85, 0.85, 0.8, 0.8])
ki_barrier = 0.6
n_iteration = 10000
els_price_bb, cal_time_bb, prob_bb = OneDimELS_MC_BB(underlying_spot, interest_rate, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration)
els_fdm, uu, cal_time_fdm, s_seq, t_seq = OneDimELS_FDM(underlying_spot, interest_rate, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration)
els_bt, cal_time_bt, vnode = OneDimELS_BinomialTree(underlying_spot, interest_rate, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration)
np.set_printoptions(suppress=True)
print('ELS value(MC with BB): {:.3f}'.format(els_price_bb))
print('elapsed time : {}'.format(cal_time_bb))
print('\n')
print('ELS value(FDM) : {:.3f}'.format(els_fdm))
print('elapsed time : {}'.format(cal_time_fdm))
print('\n')
print('ELS value(Binom.Tree) : {:.3f}'.format(els_bt))
print('elapsed time : {}'.format(cal_time_bt))
위 code는 Montecarlo Simulation, FDM , Binomial Tree의 값을 비교한 것입니다. 설명을 생략해도 될 정도로 단순한 코드입니다. 결과를 보시면,
ELS value(MC with BB): 0.988
elapsed time : 1.979
ELS value(FDM) : 0.984
elapsed time : 13.492
ELS value(Binom.Tree) : 0.981
elapsed time : 1.481
조금의 차이는 보이지만, 비슷하게 나옵니다.
이제 여러 기초자산의 값에 대해서 얼마나 비슷한지 MC, FDM 방법과 비교해 보겠습니다.
def comparisonTest():
underlying_spot = Underlying(refprice=100, spotvalue=100, volatility=0.3, dividend=0)
interest_rate = Market(0.03)
redemption_schedule = np.array([1, 2, 3, 4, 5, 6]) * 125
coupon = np.array([1, 2, 3, 4, 5, 6]) * 0.05
full_dummy = coupon[-1]
barrier = np.array([0.9, 0.9, 0.85, 0.85, 0.8, 0.8])
ki_barrier = 0.6
n_iteration = 10000
els_fdm, uGrid, cal_time_fdm, s_seq, t_seq = OneDimELS_FDM(underlying_spot, interest_rate, redemption_schedule,
coupon,
full_dummy, barrier, ki_barrier, n_iteration)
mc_list = []
fdm_list = []
bt_list = []
diff_fdm_bt_list = []
x = []
cal_time_mc = 0
cal_time_bt = 0
for i in range(20):
curr_price = 50 + 5 * i
underlying_spot = Underlying(refprice=100, spotvalue=curr_price, volatility=0.3, dividend=0)
mc_value, ct, _ = OneDimELS_MC_BB(underlying_spot, interest_rate, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration)
bt_value, ct_bt, vnode = OneDimELS_BinomialTree(underlying_spot, interest_rate, redemption_schedule, coupon,
full_dummy, barrier, ki_barrier, n_iteration)
x.append(curr_price)
mc_list.append(mc_value)
fdm_value = np.interp(curr_price, s_seq, uGrid[0, :])
fdm_list.append(fdm_value)
bt_list.append(bt_value)
diff_fdm_bt_list.append(bt_value - fdm_value)
cal_time_mc += ct
cal_time_bt += ct_bt
print('Elapsed time: MC={}, FDM={}, Binom.Tree ={}'.format(cal_time_mc, cal_time_fdm, cal_time_bt))
fig, ax1 = plt.subplots() # subplots() 함수를 사용하여 ax설계
ax1.plot(x, mc_list, c='r', marker='o', label='MC')
ax1.plot(x, fdm_list, c='b', marker='x', label='FDM')
ax1.plot(x, bt_list, c='c', marker='^', label='Binom.Tree')
plt.xticks([50, 100, 150])
ax1.legend()
ax2 = ax1.twinx() # 같은 축에다 그리기 위해 동일 ax1과 동일한 Axes를 ax2로 설계
ax2.bar(x, diff_fdm_bt_list, color='royalblue', label='difference bt-fdm')
ax2.legend()
plt.show()
○ 기준가가 100인 기초자산을 50부터 5 단위씩 증가시켜 145까지 20개의 경우에 대해서 MC, FDM, Binomial Tree로 계산한 결과입니다.
○ 그 중, binomial tree방법과 FDM의 가격의 차이를 계산하여 그래프를 표현했습니다.
○ 이전 글의 코드와 비슷하므로 자세한 설명은 생략합니다.
결과를 보겠습니다.
Binomial Tree 방법이 다른 방법과 비교해서 큰 차이점이 없네요. 또한 파란 bar chart는 binomial tree와 FDM 값의 차이인데 오른쪽 축의 값을 보시면 차이가 미미하다는 것을 알 수 있습니다.
어느 정도 세 방법의 구현이 서로 서로 체크가 되네요.
'금융공학' 카테고리의 다른 글
아메리칸 옵션의 평가 #1 (이론) (0) | 2022.12.27 |
---|---|
옵션에도 아메리칸 스타일이 있다 (0) | 2022.12.27 |
1star 스텝다운 ELS의 계산(Binomial Tree) #1 (0) | 2022.12.21 |
1star 스텝다운 ELS의 계산(FDM) #2 (2) | 2022.12.20 |
1star 스텝다운 ELS의 계산(FDM) #1 (0) | 2022.12.20 |
댓글