ELS.ipynb

SEIBro

참고한 상품 정보 보는 사이트

Basic Step Down 신금투 21425

import time
import numpy as np

start = time.time()

S0 = 100  # 최초기준가격

r_1 = 0.00160  # 1년만기 무위험수익률
r_2 = 0.00190      
r_3 = -0.00536

q_1 = 0.013240  # 배당
q_2 = 0.026810
q_3 = 0.021550

sigma_1 = 0.2643  # 변동성
sigma_2 = 0.2551
sigma_3 = 0.2514

rho_12 = 0.13245  # 상관계수 
rho_13 = 0.60590
rho_23 = 0.26899

T = 3.0  # 만기
D = 252  # 영업일 
dt = 1 / D  # time step: 일별 종가기준 
I = 50000  # Iteration

R = np.ones((3,3))
R[0,1] = rho_12
R[1,0] = rho_12
R[0,2] = rho_13
R[2,0] = rho_13
R[1,2] = rho_23
R[2,1] = rho_23

L = np.linalg.cholesky(R) # Correlation matrix를 cholesky decomposition 한 후 남은 lower triangular matrix

S_1 = np.zeros((252*3 + 1, I))
S_1[0] = S0

S_2 = np.zeros((252*3 + 1, I))
S_2[0] = S0

S_3 = np.zeros((252*3 + 1, I))
S_3[0] = S0

for t in range(1, 757):
    A = np.random.standard_normal((3, I))
    B = np.dot(L, A)  # 상관관계가 고려된 난수 생성

    S_1[t] = S_1[t-1] * np.exp((r_1 - q_1 - 0.5 * sigma_1 ** 2) * dt + sigma_1 * np.sqrt(dt) * B[0])
    S_2[t] = S_2[t-1] * np.exp((r_2 - q_2 - 0.5 * sigma_2 ** 2) * dt + sigma_2 * np.sqrt(dt) * B[1])
    S_3[t] = S_3[t-1] * np.exp((r_3 - q_3 - 0.5 * sigma_3 ** 2) * dt + sigma_3 * np.sqrt(dt) * B[2])

WP = np.zeros((252*3 + 1, I))
WP = np.min((S_1, S_2, S_3), axis = 0)

P = np.zeros(I)   # ELS의 path별 PV Matrix

C = np.zeros((6,1)) # PV matrix
C[0] = np.exp(-0.01092 * 0.5) * 101.95 #액면 금액 * 101.95%
C[1] = np.exp(-0.01307 * 1.0) * 103.90 #액면 금액 * 103.90%
C[2] = np.exp(- 0.01480 * 1.5) * 105.85 #액면 금액 * 105.85%
C[3] = np.exp(-0.01655 * 2.0) * 107.80 #액면 금액 * 107.80%
C[4] = np.exp(-0.01753* 2.5) * 109.75 #액면 금액 * 109.75%
C[5] = np.exp(-0.01832 * 3.0) * 111.70 #액면 금액 * 111.70%
 
for r in range(0, I):
    if WP[126, r] >= 85:
        P[r] = C[0]
    elif WP[252, r] >= 85:
        P[r] = C[1]
    elif WP[378, r] >= 80:
        P[r] = C[2]
    elif WP[504, r] >= 80:
        P[r] = C[3]
    elif WP[630, r] >= 75:
        P[r] = C[4]
    elif WP[756, r] >= 70:        # 여기까지가 자동조기상환 성공 시나리오
        P[r] = C[5]
    elif WP[:, r].min() > 50:     # 자동조기상환은 실패했지만, 모든 날짜의 종가가 50%미만 하락하지 않은 경우
        P[r] = C[5]
    else:                          # 원금손실 (참여율 100%)
        P[r] = WP[-1, r] * np.exp(-0.01832 * 3.0)
        
        
PV = np.mean(P) * 100
PV

print(PV.round(2))
print('time :', time.time() - start)

8900.44 time : 12.904228925704956

Monthly Coupon NH투증 21102

import time
import numpy as np

start = time.time()

S0 = 100  # 최초기준가격 

r_1 = 0.00161  # 1년만기 무위험이자율
r_2 = -0.00542

q_1 = 0.005816  # 배당
q_2 = 0.020980

sigma_1 = 0.246606  # 변동성
sigma_2 = 0.253700

rho_12 = 0.22825  # 상관계수

df = 0.0150  # 할인율

T = 3
Nt = 252  # 영업일 
dt = 1 / Nt  # time step: 일별 종가기준 
I = 50000  # Iteration

R = np.ones((2, 2))  # Correlation matrix
R[0,1] = rho_12
R[1,0] = rho_12

L = np.linalg.cholesky(R)

S_1 = np.zeros((int(Nt*T + 1), I))
S_1[0] = S0

S_2 = np.zeros((int(Nt*T + 1), I))
S_2[0] = S0

for t in range(1, int(Nt*T + 1)):
    A = np.random.standard_normal((2, I))
    B = np.dot(L, A)

    S_1[t] = S_1[t-1] * np.exp((r_1 - q_1 - 0.5 * sigma_1 ** 2) * dt + sigma_1 * np.sqrt(dt) * B[0])
    S_2[t] = S_2[t-1] * np.exp((r_2 - q_2 - 0.5 * sigma_2 ** 2) * dt + sigma_2 * np.sqrt(dt) * B[1])
    
WP = np.zeros((Nt * T + 1, I)) 
WP = np.min((S_1, S_2), axis = 0)

P = np.zeros(I)  # ELS의 path별 상환금액의 PV
    
C = np.zeros((6,1)) # Payoff의 PV matrix
C[0] = np.exp(-0.011020 * 0.5) * 100
C[1] = np.exp(-0.013240 * 1.0) * 100
C[2] = np.exp(- 0.014680 * 1.5) * 100
C[3] = np.exp(-0.016030 * 2.0) * 100
C[4] = np.exp(-0.017210* 2.5) * 100
C[5] = np.exp(-0.018080 * 3.0) * 100

Cpn = np.zeros(I)  # 쿠폰지급액의 PV

for r in range(0, I):
    if WP[126, r] >= 95:
        P[r] = C[0]
        for c in range(1,7):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)  # 쿠폰을 각각의 현재가치로 더함
        P[r] = P[r] + Cpn[r]  
        
    elif WP[252, r] >= 90:
        P[r] = C[1]
        for c in range(1,13):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)
        P[r] = P[r] + Cpn[r]
        
    elif WP[378, r] >= 85:
        P[r] = C[2]
        for c in range(1,19):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)
        P[r] = P[r] + Cpn[r]
        
    elif WP[504, r] >= 85:
        P[r] = C[3]
        for c in range(1,25):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)
        P[r] = P[r] + Cpn[r]
        
    elif WP[630, r] >= 80:
        P[r] = C[4]
        for c in range(1,31):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)
        P[r] = P[r] + Cpn[r] 
        
    elif WP[756, r] >= 80:        # 여기까지가 자동조기상환 성공 시나리오
        P[r] = C[5]
        for c in range(1,37):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)     
        P[r] = P[r] + Cpn[r]
        
    elif WP[:, r].min() > 50:     # 자동조기상환은 실패했지만, 모든 날짜의 종가가 50%미만 하락하지 않은 경우
        P[r] = C[5]
        for c in range(1,37):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)
        P[r] = P[r] + Cpn[r]
        
    else:                          # 원금손실 (참여율 100%)
        P[r] = WP[-1, r] * np.exp(-0.018080 * 3.0)
        for c in range(1,37):
            if WP[21*c, r] >= 60:
                Cpn[r] = Cpn[r] + (100 * 0.005) * np.exp(-df * 21 * c / Nt)
        P[r] = P[r] + Cpn[r]     
            
PV = np.mean(P)*100
print(PV.round(2))
print('time :', time.time() - start)

9418.54 time : 7.833194017410278

Shooting Up 삼성증권 26661

import time
import numpy as np

#Shooting up: 주식에 투자하는데 투자손실은 -5%로 제한하고, 
#주가 상승에 따른 수익을 일정 비율(참여율)만큼 누릴 수 있는 구조로 
#변동성 장세에 위험관리와 수익추구를 동시에 추구할 수 있는 상품으로 설계가 되었다.

start = time.time()

S0 = 100  #최초기준가격   

r_1 = 0.00150  # 1년만기 무위험이자율

q_1 = 0.00562  # 배당

sigma_1 = 0.240152  # 변동성

T = 0.5  #만기
Nt = 252  # 영업일 
dt = 1 / 252  # time step: 일별 종가기준 
I = 50000  # Iteration

S_1 = np.zeros((int(Nt*T + 1), I))
S_1[0] = S0

for t in range(1, int(Nt*T + 1)):
    A = np.random.standard_normal(I)

    S_1[t] = S_1[t-1] * np.exp((r_1 - q_1 - 0.5 * sigma_1 ** 2) * dt + sigma_1 * np.sqrt(dt) * A)

P = np.zeros(I)   # ELS의 path별 PV Matrix
    
for r in range(0, I):
    if np.mean(S_1[-3:, r]) >= 100:
        P[r] = np.exp(-0.0112 * T) * 100 * (1 + 0.22 * (np.mean(S_1[-3:, r]) / 100 - 1))
    elif np.mean(S_1[-3:, r]) >= 90:
        P[r] = np.exp(-0.0112 * T) * 100 * (0.9 + (np.mean(S_1[-3:, r]) / 100 - 0.9))
    else:
        P[r] = np.exp(-0.0112 * T) * 100 * 0.9

PV = np.mean(P)*100
print(PV.round(2))
print('time :', time.time() - start)

9675.89 time : 1.849083423614502