想定している読者層
- ビットコインのオプション取引に興味があり、その理論を知りたい人。
今回の目標
- ブラックショールズ方程式の概要を理解する。
- ブラックショールズ方程式の解の振る舞いを理解する。
前回の復習
前回、ビットコインのオプション価格をプットコールパリティという考え方を用いて計算できないかと考察した。
プットコールパリティ:
ただし、C, Pはそれぞれコールオプション、プットオプションのプレミアム、Fは原資産のオプションと満期日が同じ先物価格, Kはオプションの行使価格。
その結果として、
- プットオプションとコールオプションは、同じ満期と行使価格のどちらか片方の価格と先物価格が分かれば、もう片方の理論価格を計算できる。
- Moveコントラクトの理論価格を計算するには、BTCのオプション市場の流動性は不十分。
ということが分かった。
プットコールパリティによるオプションの理論価格の計算は、オプション市場の流動性に依存しているため、流動性に乏しいビットコインのオプション市場では単純な適応はできない、という結論だった。
次は、前回とは別の方法で、オプションの理論価格計算方法として有名なブラックショールズ方程式を利用してBTCのオプションの理論価格、そしてMoveコントラクトの正しいプライシングを行うことを目標とする。今回はその先駆けとしてブラックショールズ方程式とは何かを理解する。
ブラックショールズ方程式
ブラックショールズ方程式は次のように表される偏微分方程式である。
ただし、Cはヨーロピアンコールオプションのプレミアム、は原資産の価格、は、原資産のボラティリティ、rはリスクフリーレート。
この偏微分方程式の導出過程や解の求め方については、様々な文献に記載があるため解説はそちらに任せるとして、解は次のような形で表される。
ただし、Kはコールオプションの行使価格で、は標準正規分布の累積分布関数。Tはオプションの満期。
やや複雑な式に見えるかもしれないが式の意味は単純で、ボラティリティさえ推定すれば、行使価格と現在の株価と満期までの時間によってオプションのプレミアムが決まることを意味している。
ポイントは、
- 満期までの時間が短くなるにつれて、指数関数的にプレミアムが減少する。
- ボラが大きいほどプレミアムも大きい。
あたりだろうか。
アカデミックな研究ではなく、取引などの実務への応用の場合は、こういった数式の定性的な意味を理解しておくことが重要だと考えている。
各変数とプレミアムの関係
さて、ブラックショールズ方程式の定性的な意味をより深く理解するために、シミュレーションを行ってみた。原資産の価格、ボラティリティ、行使価格、満期までの期日の各変数に対して、オプションのプレミアムがどう動くかを視覚的に見る。なお、シミュレーションはいずれもコールオプションの場合を想定している。プットオプションについても同じことができるので、ぜひ手を動かしてみて欲しい。
ボラティリティ vs プレミアム
オプションのプレミアムは、ボラティリティの増大に対して上に凸な増加関数となっている。ボラティリティが高いほど、行使価格に到達する可能性が高いためである。
満期までの時間 vs プレミアム
満期までの時間は、長いほどプレミアムは高くなる。満期まで遠いほど価格変動幅も大きくなる可能性があり、行使価格まで到達する可能性が高いためである。
行使価格 vs プレミアム
行使価格が高いほど、指数関数的にプレミアムが下がる。プレミアムがほぼゼロのオプションはいわゆる「クズオプション」で、もう少しカッコつけて言うと「ファーアウトオブザマネー(Far out of the money)」などと言う。
金利 vs プレミアム
金利は高いほどプレミアムも高くなる。これは上記他3つの変数と比べて直感的には最も理解しづらいが、金利が高いということは、同額の現金なら未来の現金より現在の現金の方が価値が高いということになる。
よって、同じ行使価格で原資産を買える権利についても、今でなく将来買える権利であるコールオプションのプレミアムは、金利が高いほど高くなる。
まとめ
今回の記事では、オプションのプレミアムを解析的に計算することを可能とする、ブラックショールズ方程式について概要を理解した。
ビットコインのオプション価格、そしてFTX Moveコントラクトの理論価格の計算は次回以降の宿題としたい。
付録
最後に、参考までにjupyter Notebookで動かしたシミュレーションコードを置いておく。
# coding: utf-8
# In[6]:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
# In[7]:
def d(T, t, sigma, K, S_t, r):
d1 = (np.log(S_t/K) + (r + sigma**2/2)* (T-t)) / (sigma*np.sqrt(T-t))
d2 = (np.log(S_t/K) + (r - sigma**2/2)* (T-t)) / (sigma*np.sqrt(T-t))
return d1, d2
def premium(T, t, sigma, K, S_t, r):
d1, d2 = d(T, t, sigma, K, S_t, r)
return S_t * norm.cdf(d1) - K * np.exp(-r*(T-t)) * norm.cdf(d2)
# In[17]:
T = 60
t = 0
sigma = 0.01
K = 1000000
S_t = 990000
r = 0
premium(T, t, sigma, K, S_t, r)
# In[21]:
sigmas = [i/100 for i in range(1, 100)]
premiums = [premium(T, t, s, K, S_t, r) for s in sigmas]
plt.figure(figsize=(16, 8))
plt.title("σ VS call option premium")
plt.plot(sigmas, premiums)
# In[27]:
ts = [t for t in range(60)]
premiums = [premium(T, t, sigma, K, S_t, r) for t in ts]
plt.figure(figsize=(16, 8))
plt.title("Remaining time VS call option premium")
plt.plot([T-t for t in ts], premiums)
# In[30]:
ks = [k for k in range(990001, 5000000, 1000)]
premiums = [premium(T, t, sigma, k, S_t, r) for k in ks]
plt.figure(figsize=(16, 8))
plt.title("Strike price VS call option premium")
plt.plot(ks, premiums)
# In[31]:
rs = [r/1000 for r in range(100)]
premiums = [premium(T, t, sigma, K, S_t, r) for r in rs]
plt.figure(figsize=(16, 8))
plt.title("Risk free rate VS call option premium")
plt.plot(rs, premiums)