작성자: admin 작성일시: 2016-08-10 21:06:27 조회수: 531 다운로드: 85
카테고리: 금융 공학 태그목록:

블랙-숄즈-머튼 방정식

블랙-숄즈-머튼 방정식(Black-Sholes-Merton equantion) 또는 더 정확히 블랙-숄즈-머튼 편미분 방정식(Black-Sholes-Merton partial differential equantion)이라는 부르는 방정식은

  • 주식의 가격이 기하 브라운 운동 모형을 따르는 시장에서
  • 단일 주식 가격을 기초 자산으로 하는 모든 파생상품의 가격에 대해

성립하는 관계를 나타내는 편미분 방정식이다.

이 식은 블랙-숄즈-머튼 공식(Black-Sholes-Merton formula)라고 부르는 유러피안 바닐라 옵션(European valina option)의 가치에 대한 closed-form 공식과는 다른 것이다.

이 방정식은 뒤에서 보겠지만 파생상품의 헤지 포트폴리오(hedge portfolio) 혹은 헤지 전략(hedge strategy)을 구하는 과정에서 도출되는 방정식으로

  • 위와 같은 조건을 만족하는 모든 파생상품에 대해 헤지 포트폴리오(전략)가 존재한다

라는 것을 의미한다.

파생상품의 가치

다음과 같은 파생상품을 생각하자.

  • 단일 주식을 기초 자산으로 하고 이 주식의 가격은 $S(t)$로 나타낸다.
  • 만기 시간 $T$에서 $V(T, S(T))$라는 만기 페이오프를 가진다.

이러한 파생상품의 현재 가치 $V(t)$는

  • 현재 시간 $t$
  • 현재 주식 가격 $S(T)

에 의존하게 된다. 즉, $t$와 $S(t)$의 함수이다. 이를 다음과 같이 독립 변수 $t$, $x$를 가지는 2차원 함수로 표기하도록 한다.

$$ V(t, x) = V(t, S(t)) $$

파생 상품 가치의 변화

Ito-Doeblin 공식에 의해 이 파생상품의 가치의 변화는 다음과 같이 나타난다.

$$ \begin{eqnarray} dV(t, S(t)) &=& \dfrac{\partial}{\partial t}V(t, S(t)) \; dt + \dfrac{\partial}{\partial x}V(t, S(t)) \; dS + \dfrac{1}{2} \dfrac{\partial^2}{\partial x^2}V(t, S(t)) \; dS^2 \\ &=& \dfrac{\partial}{\partial t}V(t, S(t)) \; dt + \dfrac{\partial}{\partial x}V(t, S(t)) \; \big(\alpha S(t) \; dt + \sigma S(t) \; dW(t) \big) + \dfrac{1}{2} \dfrac{\partial^2}{\partial x^2}V(t, S(t)) \; \sigma^2 S(t)^2 dt \\ &=& \Big( \dfrac{\partial}{\partial t}V(t, S(t)) + \alpha S(t) \dfrac{\partial}{\partial x}V(t, S(t)) + \dfrac{1}{2} \sigma^2 S(t)^2 \dfrac{\partial^2}{\partial x^2}V(t, S(t)) \Big) \; dt + \sigma S(t) \dfrac{\partial}{\partial x}V(t, S(t)) \; dW(t) \end{eqnarray} \\ $$

헤지 포트폴리오 가치의 변화

단일 주식을 포함하는 포트폴리오 $X$의 가치는 다음과 같은 수식을 따른다.

$$ dX(t) = \big( rX(t) + \Delta(t)(\alpha(t)-r)S(t) \big) \;dt + \Delta(t)\sigma S(t)\;dW(t) $$

만일 이 포트폴리오 $X$가 파생상품 $V$에 대한 헤지 포트폴리오 역할을 하려면 모든 시간 $t$, 모든 가격 $S(t)$에 대해 파생 상품 가치와 포트폴리오 가치가 같아야 한다. 그러려면 변화분 $dX$와 $dV$도 항상 같아야 한다.

$$ dX = dV $$

이 식이 성립하려면 위의 두 식에서 $dt$와 $dW$에 대한 계수값이 같아야 한다. 즉,

$$ \dfrac{\partial}{\partial t}V(t, S(t)) + \alpha S(t) \dfrac{\partial}{\partial x}V(t, S(t)) + \dfrac{1}{2} \sigma^2 S(t)^2 \dfrac{\partial^2}{\partial x^2}V(t, S(t)) = rV(t,S(t)) + \Delta(t)(\alpha(t)-r)S(t) $$$$ \sigma S(t) \dfrac{\partial}{\partial x}V(t, S(t)) = \Delta(t)\sigma S(t) $$

이 성립해야 한다.

정리하면

$$ \Delta(t) = \dfrac{\partial}{\partial x}V(t, S(t)) $$

이고 이를 위 식에 대입하면

$$ \dfrac{\partial}{\partial t}V(t, S(t)) + r S(t) \dfrac{\partial}{\partial x}V(t, S(t)) + \dfrac{1}{2} \sigma^2 S(t)^2 \dfrac{\partial^2}{\partial x^2}V(t, S(t)) = rV(t,S(t)) $$

즉 위의 파생상품의 가격이 아래의 식을 만족하고 헤지 포트폴리오를 위의 식에 맞에 델타 헤지(delta hedge)하면 헤지 포트폴리와 파생상품의 가치는 언제나 동일하다.

이는 만기시 $T$ 시점에도 역시 성립하므로 만기 페이오프와 만기시의 헤지 포트폴리오 가치는 같다.

블랙-숄즈-머튼 공식

파생상품이 유러피안 바닐라 옵션(European valina option)인 경우에 대해 블랙-숄즈-머튼 방정식의 해를 구한 것이 블랙-숄즈-머튼 공식(Black-Sholes-Merton formula)이다.

만기가 $T$, 행사가가 $K$인 콜옵션 $C$의 가치는 다음과 같이 구할 수 있다.

$$ C = S(t)N\big(d_{+}(T-t,S(t))\big)-Ke^{-r(T-t)}N\big(d_{-}(T-t,S(t))\big) $$

여기에서 $N$ 은 다음과 같은 표준 정규 분포(standard normal distribution)의 누적 밀도 함수(culumative density function)이고

$$ N(y) = \dfrac{1}{\sqrt{2\pi}} \int_{-\infty}^y e^{-\frac{z^2}{2}} \; dz $$

$d_{+}$, $d_{-}$는 다음과 같이 정의된다.

$$ \begin{eqnarray} d_{+}(T-t,S(t)) &=& \dfrac{1}{\sigma \sqrt{(T-t)}} \Big( \log \dfrac{S(t)}{K} + \big(r + \dfrac{\sigma^2}{2}\big)(T-t) \Big) \\ d_{-}(T-t,S(t)) &=& \dfrac{1}{\sigma \sqrt{(T-t)}} \Big( \log \dfrac{S(t)}{K} + \big(r - \dfrac{\sigma^2}{2}\big)(T-t) \Big) \\ \end{eqnarray} $$

한편, 풋옵션의 가치는 다음과 같다.

$$ P = Ke^{-r(T-t)}N\big(-d_{-}(T-t,S(t))\big)-S(t)N\big(-d_{+}(T-t,S(t))\big) $$

Python 구현

다음은 Yves Hilpisch가 저서 "파이썬을 활용한 금융분석"(한빛미디어)에서 공개한 블랙-숄즈-머튼 공식에 대한 Python 구현이다. 이 코드는 다음 웹사이트에서 구할 수 있다.

In:
#
# Valuation of European call options in Black-Scholes-Merton model
# incl. Vega function and implied volatility estimation
# bsm_functions.py
#

# Analytical Black-Scholes-Merton (BSM) Formula


def bsm_call_value(S0, K, T, r, sigma):
    ''' Valuation of European call option in BSM model.
    Analytical formula.
    
    Parameters
    ==========
    S0 : float
        initial stock/index level
    K : float
        strike price
    T : float
        maturity date (in year fractions)
    r : float
        constant risk-free short rate
    sigma : float
        volatility factor in diffusion term
    
    Returns
    =======
    value : float
        present value of the European call option
    '''
    from math import log, sqrt, exp
    from scipy import stats

    S0 = float(S0)
    d1 = (log(S0 / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    d2 = (log(S0 / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    value = (S0 * stats.norm.cdf(d1, 0.0, 1.0)
            - K * exp(-r * T) * stats.norm.cdf(d2, 0.0, 1.0))
      # stats.norm.cdf --> cumulative distribution function
      #                    for normal distribution
    return value

# Vega function


def bsm_vega(S0, K, T, r, sigma):
    ''' Vega of European option in BSM model.
    
    Parameters
    ==========
    S0 : float
        initial stock/index level
    K : float
        strike price
    T : float
        maturity date (in year fractions)
    r : float
        constant risk-free short rate
    sigma : float
        volatility factor in diffusion term
    
    Returns
    =======
    vega : float
        partial derivative of BSM formula with respect
        to sigma, i.e. Vega

    '''
    from math import log, sqrt
    from scipy import stats

    S0 = float(S0)
    d1 = (log(S0 / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    vega = S0 * stats.norm.pdf(d1, 0.0, 1.0) * sqrt(T)
    return vega

# Implied volatility function


def bsm_call_imp_vol(S0, K, T, r, C0, sigma_est, it=100):
    ''' Implied volatility of European call option in BSM model.
    
    Parameters
    ==========
    S0 : float
        initial stock/index level
    K : float
        strike price
    T : float
        maturity date (in year fractions)
    r : float
        constant risk-free short rate
    sigma_est : float
        estimate of impl. volatility
    it : integer
        number of iterations
    
    Returns
    =======
    simga_est : float
        numerically estimated implied volatility
    '''
    for i in range(it):
        sigma_est -= ((bsm_call_value(S0, K, T, r, sigma_est) - C0)
                        / bsm_vega(S0, K, T, r, sigma_est))
    return sigma_est
In:
#
# Valuation of European call options in Black-Scholes-Merton Model
# incl. Vega function and implied volatility estimation
# -- class-based implementation
# bsm_option_class.py
#

from math import log, sqrt, exp
from scipy import stats

class call_option(object):
    ''' Class for European call options in BSM model.
    
    Attributes
    ==========
    S0 : float
        initial stock/index level
    K : float
        strike price
    T : float
        maturity (in year fractions)
    r : float
        constant risk-free short rate
    sigma : float
        volatility factor in diffusion term
        
    Methods
    =======
    value : float
        return present value of call option
    vega : float
        return Vega of call option
    imp_vol: float
        return implied volatility given option quote
    '''
    
    def __init__(self, S0, K, T, r, sigma):
        self.S0 = float(S0)
        self.K = K
        self.T = T
        self.r = r
        self.sigma = sigma
        
    def value(self):
        ''' Returns option value. '''
        d1 = ((log(self.S0 / self.K)
            + (self.r + 0.5 * self.sigma ** 2) * self.T)
            / (self.sigma * sqrt(self.T)))
        d2 = ((log(self.S0 / self.K)
            + (self.r - 0.5 * self.sigma ** 2) * self.T)
            / (self.sigma * sqrt(self.T)))
        value = (self.S0 * stats.norm.cdf(d1, 0.0, 1.0)
            - self.K * exp(-self.r * self.T) * stats.norm.cdf(d2, 0.0, 1.0))
        return value
        
    def vega(self):
        ''' Returns Vega of option. '''
        d1 = ((log(self.S0 / self.K)
            + (self.r + 0.5 * self.sigma ** 2) * self.T)
            / (self.sigma * sqrt(self.T)))
        vega = self.S0 * stats.norm.pdf(d1, 0.0, 1.0) * sqrt(self.T)
        return vega

    def imp_vol(self, C0, sigma_est=0.2, it=100):
        ''' Returns implied volatility given option price. '''
        option = call_option(self.S0, self.K, self.T, self.r, sigma_est)
        for i in range(it):
            option.sigma -= (option.value() - C0) / option.vega()
        return option.sigma

위의 코드를 사용하여 여러가지 만기와 행사가에 대해 콜옵션의 가치는 구하면 다음과 같다.

In:
r = 0.05
sigma = 0.2

maturities = np.linspace(0.05, 2.0, 20)
strikes = np.linspace(80, 120, 20)
T, K = np.meshgrid(strikes, maturities)
C = np.zeros_like(K)
for i, t in enumerate(maturities):
    for j, k in enumerate(strikes):
        o = call_option(100, k, t, r, sigma)
        C[i, j] = o.value()
In:
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(T, K, C, rstride=1, cstride=1, cmap=plt.cm.coolwarm, linewidth=0.5)
ax.set_xlabel('strike')
ax.set_ylabel('maturity')
ax.set_title('European call value')
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
In:
plt.plot(strikes, C.T[:,::2])
plt.xlabel('strike')
plt.ylabel('European call value')
plt.legend(maturities[::2])
plt.show()

질문/덧글

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