1. QuantLibを使ってみる
1.2 Example を試す
1.2.8 Replication ; バリアオプションを、ヨーロピアンオプションのポートフォリオでReplicattionする
1.2.8.4 ソースコードの解析
1.2.8.4.1 バリアオプションオブジェクトと、価格エンジンの作成(51~114行目)
これまでのプロジェクト例と同じく、Instrument(ここでは BarrierOption クラスの)オブジェクトと、PricingEngine(ここでは AnalyticBarrierEngine と AnalyticEuropeanEngine クラスの)オブジェクトを部品から組み立てて行きます。基本的には、EquityOption プロジェクトで解説した方法と同じ要領で組み立てます。
(1) 商品と価格エンジンの部品(の原料)の作成
まず、バリアオプションの部品として、オプションの条件等の情報を設定します。(57~91行目) コードを見れば簡単に分かると思いますが、ここでは、
- 期間1年の
- donw-and-outのバリア付き
- ヨーロピアンタイプのプットオプションで、
- ストライクは 100、バリアは 70
に設定されています。それ以外に、対象資産価格(100)、リスクフリー金利(4%)、Volatility(20%)などの市場データも用意されています。
(2) そして、94と95行目で、オプションの主要部品である、行使日(EuropeanExercise)とPayoff条件(PlainVanillaPayoff)のオブジェクトを作成しています。
(3) また、97行目で、価格エンジンの主要部品となる、確率過程のオブジェクト(ここでは BlackScholesProcess オブジェクト)を作成した上で、100 行目と 101 行目で 2 種類の価格エンジンオブジェクトを作成しています(下記にコードを抜き出しました)。
auto barrierEngine = ext::make_shared< AnalyticBarrierEngine> (bsProcess);
auto europeanEngine = ext::make_shared< AnalyticEuropeanEngine> (bsProcess);
前者は、バリアオプション用の解析解を使った価格エンジンです。QuantLibのマニュアルによれば、具体的な計算式は、Espen-Gaarder-Haug著の“The Complete Guide to Option Pricing Formula”(p70~71)から引用したとの事。さらに、その書籍がバリアオプションの価格式の参考としている論文のURLも参考の為に載せておきます。 "Breaking down the barrier" Rubinstein, Reiner
後者の価格エンジンは Black-Scholes のオプション価格公式を使った価格エンジンです。こちらの解説は不要でしょう。
(4) 用意された部品を使って、103行目で、バリアオプションオブジェクトを生成しています。
BarrierOption referenceOption(
barrierType, :バリアのタイプ。ここではdown-and-out
barrier, :バリアのレベル。ここでは70
rebate, :バリアがヒットした際に支払われる補填額。ここでは 0
payoff, :ここではストライク100のプット
exercise :ここでは、ヨーロピアンタイプで、期間1年
);
さらに、105 行目で、このバリアオプションオブジェクトに、バリアオプション用の価格エンジンを設定しています。これで価格計算の準備が出来ました。
(5) 107 行目で商品オブジェクト(Instrumentクラスのオブジェクト)から関数 NPV()を呼び出して価格計算を行い、109 行目で、計算結果を Console 画面に出力しています。
1.2.8.4.2 バリアオプションをReplicateするオブジェクトの作成(116~139行目)
まず 117 行目で、CompositeInstrument クラスのオブジェクトを3種類作成しています。変数名は、portfolio1, portfolio2, portfolio3 となっています。CompositeInstrument は、複数の Instrument オブジェクトを格納するオブジェクトです。このクラスに用意されている関数 add() と subtract() を使って、ポートフォリオにポジション(Instrumentオブジェクト)を増やしたり減らしたりします。ポジションがゼロの状態で subtract()を使うと、その Instrument のショートポジションになります。
そして、今作成した3種類のポートフォリオに、“1.2.8.1 はじめに”で解説した 1 と 2 のポジションを加えます。
(1) まず、ストライクが100のプットオプションを作成します。
シンプルなヨーロピアンオプションなので、EuropeanOptionクラスのオブジェクトを payoff と exercise を部品として作成します(変数名put1)。さらに、作成済みの価格エンジン(変数名 europeanEngine)を、この商品オブジェクトに設定します。そして、これを下記のコードの通り、ポートフォリオに加えます(ロングポジションになる)。(121~125行目)
portfolio1.add(put1);
portfolio2.add(put1);
portfolio3.add(put1);
(2) 次に、同じ満期日のデジタルオプションを作成します。
auto digitalPut = ext::make_shared< EuropeanOption> (
digitalPayoff, :バリアが70でPayoffが1.0のdigital payoff
exercise :行使日(1年後)
);
そして、下記のコードの通り、これをポートフォリオから引きます(ショートポジションになる)。
portfolio1.subtract(digitalPut, strike-barrier);
portfolio2.subtract(digitalPut, strike-barrier);
portfolio3.subtract(digitalPut, strike-barrier);
subtract()の2番目の引数 strike - barrier は、ポジションの数になります。すなわち、digital payoff が 1.0 のデジタルオプションを 100-70 = 30 単位ショートした事になります。なので、オプションが行使されるとポートフォリオ全体で-30 のキャッシュフローが発生し、プット・スプレッドの利益を消すようになっています。
(3) さらに、ストライクが 70 のプットオプションを作成しポートフォリオから引く。
portfolio1.subtract(put2);
portfolio2.subtract(put2);
portfolio3.subtract(put2);
このコードでは、subtract()の2番目の引数が省略されていますが、デフォールトで 1 に設定されています。put2 もショートポジションになり、put1 と put2 を合わせて、いわゆるプット・スプレッドのポジションになっています。
(1)、(2)、(3)のポジションを合わせると、オプション満期日における、バリアオプションのPayoffをReplicateした事になります。
1.2.8.4.3 バリアヒットの観測点設定と、Replicattion に追加のプットオプションを作成(141~165行目)
「はじめに」の所で述べたように、バリアオプションは、満期以前にバリアをヒットすると消滅し、価値が0になりますが、上記でReplicationしたポジションは、その場合でも満期まで待たないとオプションは消滅しません。すると、対象資産価格が、満期日にバリア以上に戻ると、デジタルオプションは行使されず、プットのみ行使される可能性があり、それがオプション価値として残ります。
そこで、満期日以前に、いくつかの観測時点を設けて、仮にその時点でバリアをヒットした場合に、Replication したポートフォリオのオプション価値を消すようなオプションを作成し、それをポートフォリオに加えます。これは、バリアが仮にヒットした場合、ポートフォリオの期待値が 0 になるような操作になります。
145~165 行目にある For~ループの中味が、それにあたります。その中味をみていきます。
(1) 追加のプットオプションの生成
まず、先ほど述べた 、期限前にバリアをヒットした際に、Replication したポジションに残るオプション価値を消す為の、新たなオプションを生成します。147~150 行目で、そのオプションの期日及び Payoff を作成し、ヨーロピアンのプットオプションを生成しています。コードを見れば判る通り、オプション期日は、1年を 12 期に分割し、各期の最終期日になります。またストライクは barrier となっているので、70 になります。
(2) バリアヒット時の市場価格を70にして、Replicationポートフォリオの再評価
次に、今作成したオプション期日の一期前(ここでは一か月前)の日を時価評価基準日とし、また市場価格を Barrier すなわち 70 として、Replication したポジションと、(1)で生成したプットオプションの時価を計算します。その基準日の変数名は KillDate となっていますが、バリアがヒットしてバリアオプションが消滅した時点という趣旨の名前です。
(3) 追加のプットオプションの必要ポジション額を計算し Replication ポートフォリオに追加
そして、Replication したポジションの価値と、(1)で生成したオプション価値の比を計算し、それを、(1)のプットオプションのポジション量として、Replicationポートフォリオに加えます(subtract()なのでショートポジションを加える形になります)。この操作で、その時点でバリアヒットした場合、残存ポジションのオプション価値はネットで 0 になります。
(4) (1)~(3)の操作を、すべてのバリアヒット観測時で繰り返す
(1)~(3)の操作を、観測期間を 11か月、10か月… 1か月と、少しずつ短くしていきながら繰り返します。繰り返す中で、Replication ポートフォリオの中のポジションは、少しずつプットの売りが増えていきます。
(5) それを12回繰り返せば、Replicationポートフォリオが完成です。
1.2.8.4.4 Replicattion の価格計算を行い、バリアオプション価格と比較(166~177行目)
前のセクションで作成した追加のプットオプションのシリーズを含む Replication ポートフォリオの価格を計算し、それをバリアオプションの価格と比較し、画面出力します。 価格計算は、170行目のコードを下記に抜き出しましたが、そこにある通り、CompositeInstrument オブジェクト(変数名 portfolio1)から、NPV()を呼び出して行います。
Real portfolioValue = portfolio1.NPV();
このNPV()は、CompositeInstrument に含まれている各 Instrument オブジェクトから NPV()を呼び出し、それを合計した値を返します。
計算結果は、Console 画面出力(section 1.2.8.3 参照)の通りです。バリアオプションの価格が4.260726であったのに対し、Replicationポートフォリオの価値は(12 datesと表示のある行にある通り)4.322358で、誤差は0.061632となっています。誤差率は、約1.4%で、まあまあの誤差で近似できています。
もともとのバリアオプションは、バリアヒットの観測を、オプション期間中のすべての時間(連続時間)でモニターしているのに対し、Replication ポートフォリオでは、離散的に限られた時点でしか観測していません。なので、その分バリアヒットの確率が低く(従ってオプションが無価値になる確率が低くなる)オプション価値は大きめになるバイアスがかかります。
1.2.8.4.5 オプション期間の分割数を26,52、に変えて同じ操作を行う。(179~205行目と207~233行目)
前のセクションで説明した、Replication ポートフォリオの構築を、バリアヒットの観測時点を 26 と 52(2週間ごと、および1週間)ごとにして行い、同様に価格計算をしています。計算結果は、Console 画面の出力の通りです。観測時点を増やすほど、Replication ポートフォリオの価値は、バリアオプションの価格に近づいていきます。
1.2.8.4.6 さらに現在の対象資産価格を変更して同じ計算を行う(235~325行目)。
以上で 3 種類の Replicationポートフォリオを使って、対象資産価格が100の時のバリアオプション価格の近似値を計算・比較しましたが、238~280 行目で、同じ操作を、市場価格を110 にして(なので、すべてのオプションがout of the money)行っています。 さらに、同じ操作を、市場価格を 90 にして(なので、ストライク 100 のプットとバリアオプションがin the money)行っています。(284~325行目)。これらの計算結果はConsole画面出力の通りです。
今回のプロジェクトの解説は以上です。Replicationポートフォリオを使って、価格の近似値を計算するのは、本来の価格計算エンジンの性能をテストする際に使われ事があります。特に、価格エンジンが、モンテカルロシミュレーションのような数値解を求めるアルゴリズムの場合、解析解で価格が求まるシンプルなヨーロピアンオプションを使ってReplicationポートフォリオを組み立て、近似解を求める手法がよく取られます。今回のケースでは、価格に上方バイアスがかかったReplicationポートフォリオを使っていますが、価格に上方バイアスがかかったものと、下方バイアスがかかったものを使って、両側からはさみうちにして、数値解に近づいていく様子を観測し、数値解の正しさを証明していく方法が、よく使われます。
Replicationポートフォリオのもうひとつの使い方は、バリアオプションのように、バリアを境にPayoffがジャンプする(非連続な)商品のリスクヘッジ手段として検討される事があります。そのような商品では、バリア近辺でオプション価格が激しく動き、それをヘッジするためのデルタが、オプション期日直前ではバリア近辺で無限大に発散します。実務上、デルタヘッジだけではリスクを十分ヘッジできないので、他のオプションポートフォリオを組み合わせてヘッジをする手段として、このようなReplicationポートフォリオが検討される事があります。
<ライセンス表示>
QuantLibのソースコードを使う場合は、ライセンス表示とDisclaimerの表示が義務付けられているので、添付します。 ライセンス