작성자: admin 작성일시: 2016-08-24 12:44:41 조회수: 287 다운로드: 25
카테고리: 금융 공학 태그목록:

델타 헤지 백테스트

실제로 델타 헤지 메카니즘이 작동하는지를 확인하기 위해 주가를 시뮬레이션하고 이 주가에 다른 델타헤지 전략을 백테스트해본다.

주가 시뮬레이션

주가는 10,000에서 시작하여 1년간 움직이도록하고 256 매매일을 가정하여 하루 단위로 시뮬레이션한다. 이자율과 변동성은 각각 5%, 25%로 가정한다.

In [1]:
S0 = 10000
M = 256
r = 0.05
sigma = 0.40
T = 1
In [2]:
def stockprice_simulation(S0, T, sigma, r, M, seed=None):
    if isinstance(sigma, np.ndarray):
        if len(sigma) >= M:
            sigma_vec = sigma[:M]
        else:
            raise ValueError("dimension error!")
    else:
        sigma_vec = sigma * np.ones(M + 1)
    if seed is not None:
        np.random.seed(seed)
    dt = T / M
    T_vec = np.linspace(T, 0, M + 1)
    S_vec = np.zeros(M + 1)
    S_vec[0] = S0
    for t in range(1, M + 1):
        S_vec[t] = S_vec[t - 1] * np.exp((r - 0.5 * sigma_vec[t - 1] ** 2) * dt 
                 + sigma_vec[t - 1] * np.sqrt(dt) * np.random.standard_normal())
    S_vec = np.around(S_vec)
    return S_vec.T, T_vec, sigma_vec
In [3]:
S_vec, T_vec, sigma_vec = stockprice_simulation(S0, T, sigma, r, M, seed=3)

옵션 가치 및 델타 계산

옵션은 행사가 10,000원인 ATM(At-The-Money) 옵션으로 만기 1년을 가정한다. 이러한 옵션을 10개 매도한다.

In [4]:
def call_value(S, T, sigma, r, K):
    if not hasattr(T, "__len__") and T == 0:
        return np.maximum(S - K, 0)
    d1 = ((np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T)))
    d2 = ((np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T)))
    value = (S * sp.stats.norm.cdf(d1, 0, 1) - K * np.exp(-r * T) * sp.stats.norm.cdf(d2, 0, 1))
    return value
In [5]:
def call_delta(S, T, sigma, r, K):
    if not hasattr(T, "__len__") and T == 0:
        return int(S > K)
    d1 = ((np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T)))
    delta = sp.stats.norm.cdf(d1, 0, 1)
    return delta
In [6]:
K = 10000
NomialAmount = 10
In [7]:
V_vec = NomialAmount * call_value(S_vec, T_vec, sigma_vec, r, K)
D_vec = NomialAmount * call_delta(S_vec, T_vec, sigma_vec, r, K)

주가의 움직임과 이에 따른 옵션의 가치 및 델타를 그리면 아래와 같다.

In [8]:
plt.subplot(311)
plt.plot(S_vec, 'r-')
plt.subplot(312)
plt.plot(V_vec, 'g-')
plt.subplot(313)
plt.plot(D_vec, 'b-')
plt.show()

이를 평면상에 나타내면 아래와 같다.

In [9]:
maturities = np.linspace(0, 1, 13)
prices = np.linspace(8000, 12000, 101)
_T, S = np.meshgrid(maturities, prices)
V = np.zeros_like(S)
for i, s in enumerate(prices):
    for j, t in enumerate(maturities):
        V[i, j] = NomialAmount * call_value(s, t, sigma, r, K)

plt.plot(prices, V, alpha=0.5)
plt.xlabel('prices')
plt.ylabel('European call value')
plt.legend(["%d month" % i for i in range(13)], loc=2)
plt.hold(True)
plt.scatter(S_vec, V_vec, c=T_vec, cmap=mpl.cm.jet_r)
plt.plot(S_vec, V_vec, c="k", alpha=0.5)
plt.show()

델타 헤지 백테스트

델타헤지 백테스트 코드는 아래와 같다. 매일 다음과 같은 값을 구하여 이를 pandas 데이터 프레임에 저장한다.

  • time: 만기 까지 남은 시간 (연단위)
  • stock price: 기초 자산인 주가
  • option value: 옵션의 가치
  • option delta: 옵션의 델타 값
  • position: 매수한 주식의 수
  • cash flow: 주식의 매매에 따라 들어오는 현금
  • cash: 누적된 현금
  • stock value: 보유한 주식의 가치
  • total: 헤지 포트폴리오의 가치 (보유한 주식와 현금의 가치 합계)
  • profit: 헤지 포트폴리오와 매도한 옵션 가치의 차이
In [10]:
def deltahedge_backtest(price, value, delta, time, option_price=None):
    dtime = -np.diff(T_vec)
    if option_price  is None:
        option_price = V_vec[0]

    position = np.around(delta)
    gamma = np.concatenate([position[:1], np.diff(position)]) 
    cashflow = -gamma * price
    cashflow[0] += option_price
    cash = np.zeros_like(cashflow)
    cash[0] = cashflow[0]
    for i, (cf, dt) in enumerate(zip(cashflow[1:], dtime)):
        cash[i + 1] = np.around(cash[i] * np.exp(r * dt) + cf)
    stockvalue = position * price
    totalvalue = cash + stockvalue
    profit = totalvalue - value
    
    df = pd.DataFrame({"time":time, "stock price":price, "option value": value, "option delta": delta, 
                       "position": position, "cash flow": cashflow, "cash": cash, "stock value": stockvalue, 
                       "total": totalvalue, "profit": profit},
                     columns=["time", "stock price", "option value", "option delta", "position",
                             "cash flow", "cash", "stock value", "total", "profit"])
    return df
In [11]:
df = deltahedge_backtest(S_vec, V_vec, D_vec, T_vec)

헤지 결과는 다음과 같다.

In [12]:
df.head()
Out[12]:
time stock price option value option delta position cash flow cash stock value total profit
0 1.000000 10000.0 18022.951450 6.274095 6.0 -41977.04855 -41977.04855 60000.0 18022.95145 0.000000
1 0.996094 10456.0 20940.351798 6.686035 7.0 -10456.00000 -52441.00000 73192.0 20751.00000 -189.351798
2 0.992188 10570.0 21668.714052 6.782674 7.0 -0.00000 -52451.00000 73990.0 21539.00000 -129.714052
3 0.988281 10594.0 21792.193838 6.801791 7.0 -0.00000 -52461.00000 74158.0 21697.00000 -95.193838
4 0.984375 10110.0 18564.046401 6.368370 6.0 10110.00000 -42361.00000 60660.0 18299.00000 -265.046401
In [13]:
df.tail()
Out[13]:
time stock price option value option delta position cash flow cash stock value total profit
252 0.015625 11481.0 14892.483774 9.974669 10.0 -0.0 -101132.0 114810.0 13678.0 -1214.483774
253 0.011719 11317.0 13231.333939 9.980884 10.0 -0.0 -101152.0 113170.0 12018.0 -1213.333939
254 0.007812 11391.0 13949.154808 9.998974 10.0 -0.0 -101172.0 113910.0 12738.0 -1211.154808
255 0.003906 11133.0 11349.534104 9.999920 10.0 -0.0 -101192.0 111330.0 10138.0 -1211.534104
256 0.000000 11089.0 10890.000000 10.000000 10.0 -0.0 -101212.0 110890.0 9678.0 -1212.000000

주식의 최종 가격은 11,089 원이므로 페이오프는 (11,089 - 10,000) x 10 = 10,890 원이다. 헤지 포트폴리오의 가치는 9,678원이므로 1,212원의 헤지 손실이 발생했다.

In [14]:
df1 = df[["stock price", "option value", "total"]]
df1.plot(figsize=(10, 10))
plt.show()
In [15]:
plt.figure(figsize=(9, 10))
plt.subplot(411)
plt.stem(df[["cash flow"]])
plt.title("cash flow")
plt.xlim(0, 260)
plt.subplot(412)
plt.plot(df[["cash"]])
plt.title("cash")
plt.xlim(0, 260)
plt.subplot(413)
plt.plot(df[["stock value"]])
plt.title("stock value")
plt.xlim(0, 260)
plt.subplot(414)
plt.plot(df[["total"]])
plt.title("hedge portfolio")
plt.xlim(0, 260)
plt.tight_layout()
plt.show()

이번에는 주가를 다르게 생성하여 백테스트를 한다. 이 경우에는 1,140원의 헤지 이익이 발생하였다.

In [16]:
seed = 7
S_vec, T_vec, sigma_vec = stockprice_simulation(S0, T, sigma, r, M, seed=seed)
V_vec = NomialAmount * call_value(S_vec, T_vec, sigma_vec, r, K)
D_vec = NomialAmount * call_delta(S_vec, T_vec, sigma_vec, r, K)
df = deltahedge_backtest(S_vec, V_vec, D_vec, T_vec)
df.tail()
Out[16]:
time stock price option value option delta position cash flow cash stock value total profit
252 0.015625 7889.0 9.918401e-04 1.290090e-05 0.0 -0.0 1140.0 0.0 1140.0 1139.999008
253 0.011719 7851.0 8.088217e-06 1.409844e-07 0.0 -0.0 1140.0 0.0 1140.0 1139.999992
254 0.007812 7937.0 1.581907e-08 3.850017e-10 0.0 -0.0 1140.0 0.0 1140.0 1140.000000
255 0.003906 7948.0 5.173897e-18 2.448160e-19 0.0 -0.0 1140.0 0.0 1140.0 1140.000000
256 0.000000 8143.0 0.000000e+00 0.000000e+00 0.0 -0.0 1140.0 0.0 1140.0 1140.000000
In [17]:
df1 = df[["stock price", "option value", "total"]]
df1.plot()
plt.show()

통계적 특성

옵션 델타 헤지가 반복되는 경우 헤지 손익이 어떤 통계적 특성을 보이는지 살펴보기 위해 100개의 서로 다른 주가를 테스트해본다.

In [18]:
N = 100
profits = np.zeros(N)
for i in xrange(N):
    S_vec, T_vec, sigma_vec = stockprice_simulation(S0, T, sigma, r, M)
    V_vec = NomialAmount * call_value(S_vec, T_vec, sigma_vec, r, K)
    D_vec = NomialAmount * call_delta(S_vec, T_vec, sigma_vec, r, K)
    df = deltahedge_backtest(S_vec, V_vec, D_vec, T_vec)
    profits[i] = df.profit.iloc[-1]
In [19]:
sns.distplot(profits)
plt.show()
In [20]:
sns.distplot(profits/V_vec[0])
plt.show()
In [21]:
sm.qqplot(profits/V_vec[0], fit=True, line='45')
plt.axis("equal")
plt.show()
In [22]:
np.std(profits/V_vec[0])
Out[22]:
0.0722337156417307

헤지 손익이 표준 편차가 약 6.7% 인 정규 분포를 보임을 알 수 있다.

변동성 수익

실제 주가의 변동성이 헤지 변동성과 달라지면 어떻게 되는지 살펴보자.

In [24]:
N = 100
profits = np.zeros(N)
for i in xrange(N):
    S_vec, T_vec, sigma_vec = stockprice_simulation(S0, T, sigma * 1.1, r, M)
    V_vec = NomialAmount * call_value(S_vec, T_vec, sigma_vec / 1.1, r, K)
    D_vec = NomialAmount * call_delta(S_vec, T_vec, sigma_vec / 1.1, r, K)
    df = deltahedge_backtest(S_vec, V_vec, D_vec, T_vec)
    profits[i] = df.profit.iloc[-1]
In [25]:
np.mean(profits)
Out[25]:
-1408.4100000000001
In [26]:
sns.distplot(profits)
plt.show()

옵션을 매도하고 변동성이 상대적으로 10% 증가 즉 40% -> 44% 로 절대 변동성 4%가 증가한 경우 평균 손실은 약 1,408 원이 된다.

이 값은 옵션의 베가에 의해 계산된 값 1,509 원과 유사하다.

In [27]:
def call_vega(S, T, sigma, r, K):
    if not hasattr(T, "__len__") and T == 0:
        return 0
    d1 = ((np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T)))
    vega = S * sp.stats.norm.pdf(d1, 0, 1) * np.sqrt(T)
    return vega
In [32]:
call_vega(S0, T, 0.44, r, K) * NomialAmount * 0.04
Out[32]:
1509.3803710996187

질문/덧글

아직 질문이나 덧글이 없습니다. 첫번째 글을 남겨주세요!