VBAでブラックショールズ #1

oryzaeです。

前回ボラティリティスマイルをRSSで作ってみましたが、少し気になるのは先物と違い、オプションはあまり取引が大きくないという問題です。軽く計算してみると、RSSで取得できるインプライドボラティリティは、現在の日経平均の価格(15秒に一度くらい更新されているのかと思いますが)と現在のオプションの価格から導き出されたもの。問題は現在のオプションの価格がいつ付いた価格かがわからないというところです。もしかすると人気薄のオプションであれば、最後に約定した価格は一時間前のものかもしれなということ。一時間もあれば日経平均の価格は大きく動いていることもあり、現在の日経平均の値と一時間前のオプションの価格から導き出されたインプライドボラティリティはほぼ意味がないようなものと考えるのが良さそうです。

そこでオプションの最後についた価格を使うことをやめて、オプションの売り気配、買い気配を代わりに使って行使価格ごとのインプライドボラティリティが計算できないかというのが今回の話。

市場想定より大きくずれた価格での売り気配や買い気配は裁定取引業者がかならず約定させるので、現在見えている売り気配の価格や買い気配の価格と現在の現在の日経平均から計算されるインプライドボラティリティの間のどこかに市場の期待するボラティリティがあるというのが今回のアイデアです。

と思いながら、オプションの売り気配、買い気配に対するインプライドボラティリティがないかとRSS関数マニュアルをひっくり返してみました・・・が残念ながらなさそう。あるのは最良売り気配、買い気配のデータのみ。とするとインプライドボラティリティは自分で計算するしかないのかなという結論です。

ブラックショールズのオプションプレミアム(オプションの値段)を求める計算式自体は日々の株価変動は互いに独立という少し現実からは離れた仮定ではあるものの、その分とてもシンプルな数式になります。必要な引数は(現在の日経平均、行使価格、ボラティリティ、無リスク金利、配当利回り、残存日数、コール・プットの別)だけ。

だからエクセルのワークシートでも計算はできます。ところがインプライドボラティリティの計算は色々なボラティリティでオプション価格を計算してみて、計算結果と実際のオプション価格が一致するようなボラティリティがそのオプションのそのときのインプライドボラティリティという計算(もしかするとブラックショールズのオプションプレミアムの式に、ものすごい式変形をしていくと インプライドボラティリティ=( 現在の日経平均、行使価格、オプションプレミアム、無リスク金利、配当利回り、残存日数、コール・プットの別 )みたいなものができるかもですが、見たことがないので、おそらくそんな変形はできないのかな・・・)です。

上記の色々なボラティリティを当てはめて試してみるなんてことはエクセルのワークシートだとソルバーを使わないとできそうもないし、日経平均の値が変わるたびにソルバー回すなんてVBA作るのも面倒なので、ブラックショールズのオプションプレミアムを求める式、インプライドボラティリティを求める式、すべてをVBAの関数で作っちゃいましょう。今回はブラックショールズのオプション価格式の先性。次回以降にインプライドボラティリティの計算や、その他オプションの指標を書いてみようと思います。

ここではブラックショールズ式の導出をするつもりはないので、簡単にwikipediaを見てみると

C(S_{t},t)=e^{{-q(T-t)}}S_{t}N(d_{1})-Ke^{{-r(T-t)}}N(d_{2})

ただし、

N(x)={\frac  {1}{{\sqrt  {2\pi }}}}\int _{{-\infty }}^{{x}}e^{{-{\frac  {y^{2}}{2}}}}dy,

d_{1}={\frac  {\log({\frac  {S_{t}}{K}})+(r-q+{\frac  {\sigma ^{2}}{2}})(T-t)}{\sigma {\sqrt  {T-t}}}},

d_{2}={\frac  {\log({\frac  {S_{t}}{K}})+(r-q-{\frac  {\sigma ^{2}}{2}})(T-t)}{\sigma {\sqrt  {T-t}}}}

とすでに書かれていますね。ありがたやwikipedia様です。「VBAで書くブラックショールズ」でGoogle先生に検索してもらっても山のように出てきます。なのでお好きに書いて頂ければいいのですが、下記は私の書いたオプションプレミアムを配当付きブラックショールズで書いたものになります。

' 配当込みブラックショールズモデル関数

Function bsPrem(ByVal S As Double, ByVal K As Double, ByVal sigma As Double, ByVal r As Double, ByVal d As Double, ByVal t As Double, ByVal CorP As Integer)
    ' S: 原資産価格 - 例えば日経平均指数
    ' K: オプション行使価格 - 27500とか
    ' sigma: ボラティリティ - ここでは%ではなく、小数点で(30ではなく、0.3)
    ' r: 無リスク金利 - %ではなく、小数点で
    ' d: 配当利回り - %ではなく、小数点で
    ' t: 残存年数 - 残存日数/365
    ' CorP: Call or Put, コール=1, プット=2の整数
    
    Dim d1, d2, nsdD1, nsdD2 As Double
    ' 残存年数がプラスの場合(SQ日より前)
        If t > 0 Then
            d1 = ((Log(S / K) + (r - d + sigma * sigma / 2) * t)) / (sigma * Sqr(t))
            d2 = ((Log(S / K) + (r - d - sigma * sigma / 2) * t)) / (sigma * Sqr(t))
            
            If CorP = 1 Then
            ' コールのケース
                nsdD1 = WorksheetFunction.NormSDist(d1)
                nsdD2 = WorksheetFunction.NormSDist(d2)
                bsPrem = Exp(-d * t) * S * nsdD1 - Exp(-r * t) * K * nsdD2
                
            Else
            ' プットのケース
                nsdD1 = WorksheetFunction.NormSDist(-d1)
                nsdD2 = WorksheetFunction.NormSDist(-d2)
                bsPrem = -Exp(-d * t) * S * nsdD1 + Exp(-r * t) * K * nsdD2
            End If
    ' 残存年数がゼロの場合(SQ日) - 最終評価
        ElseIf t = 0 Then
        If CorP = 1 Then
        ' コールのケース
            bsPrem = WorksheetFunction.Max(0, S - K)
        Else
        ' プットのケース
            bsPrem = WorksheetFunction.Max(0, K - S)
        End If
    ' 残存年数がマイナスの場合は適宜エラー処理
        Else
            'エラー処理省略
        End If
End Function

これを使って次回はインプライドボラティリティを求めてみましょう。

コメント

タイトルとURLをコピーしました