2. "Implementing QuantLib"の和訳

Chapter-VII The Tree Framework: Tree を使った価格モデルのフレームワーク

7.1 The Lattice and Discretized Asset classes: 格子クラス および 離散化資産クラス

7.1.2: 具体例:Discretized Optionクラス (離散モデルで表現されたオプションクラス)

皆さん、お待たせしてすみませんでした。ここで、先ほど少し触れた pre- vs post-(事前あるいは事後) の調整の選択肢について説明します。直前の具体例の説明によって、説明の準備が整いました。この説明用に、ある資産クラスの例を使います (DiscretizedOptionクラスで、下記 Listing 7.5 に実装内容を示します)。このクラスは、個別の対象資産を取り込んで、それに対するオプションインスタンスを生成するのに使われます。例えば、Swap を取り込んで Swaption を生成します。ここで示す実装例は、QuantLibライブラリーが提供しているものを若干簡略化しています (QuantLibではバーミューダタイプの行使を想定して作っている)。Libraryでの実装と同じ様に、この例ではオプション行使により対象資産の取引が開始される場合でも、プレミアムの授受が発生しない取引を前提としています。 

Listing 7.5:Implementation of the DiscretizedOptionクラス 

    class DiscretizedOption : public DiscretizedAsset {
      public:
        DiscretizedOption(
                  const shared_ptr<DiscretizedAsset>& underlying,
                  const vector<Time>& exerciseTimes)
        : underlying_(underlying), exerciseTimes_(exerciseTimes) {}

        vector<Time> mandatoryTimes() const {
            vector<Time> times = underlying_->mandatoryTimes();
            for (Size i=0; i<exerciseTimes_.size(); ++i)
                if (exerciseTimes_[i] >= 0.0)
                    times.push_back(exerciseTimes_[i]);
            return times;
        }
        void reset(Size size) {
            QL_REQUIRE(method() == underlying_->method(),
                       "option and underlying were initialized on "
                       "different lattices");
            values_ = Array(size, 0.0);
            adjustValues();
        }
      private:
        void postAdjustValuesImpl() {
            underlying_->partialRollback(time());
            underlying_->preAdjustValues();
            for (Size i=0; i<exerciseTimes_.size(); i++) {
                Time t = exerciseTimes_[i];
                if (t >= 0.0 && isOnTime(t))
                    applyExerciseCondition();
            }
            underlying_->postAdjustValues();
        }
        void DiscretizedOption::applyExerciseCondition() {
            for (Size i=0; i<values_.size(); i++)
                values_[i] = std::max(underlying_->values()[i],
                                      values_[i]);
        }

        shared_ptr<DiscretizedAsset> underlying_;
        vector<Time> exerciseTimes_;
    };  

前に進みます。コンストラクターは、対象資産のインスタンスとオプション行使日の配列を引数として取り、それぞれメンバー変数に保存します。mandatoryTimes( )メソッドは、まず対象資産インスタンスから Lattice上に設定が必要な日付の配列を取ってきて、次にその配列にオプション行使日の情報を加えていきます。もちろん、この作業は対象資産とオプション資産の価格を、同じ Lattice 上で計算する為です。オプション価格を導出するプログラムの実行順序は、次のようになります。 

    underlying = shared_ptr<DiscretizedAsset>(...);
    option = shared_ptr<DiscretizedAsset>( new DiscretizedOption(underlying, exerciseTimes));
    grid = TimeGrid(..., option->mandatoryTimes());
    lattice = shared_ptr<Lattice>(new SomeLattice(..., grid, ...));
    underlying->initialize(lattice, T1);
    option->initialize(lattice, T2);
    option->rollback(t0);
    NPV = option->presentValue(); 

ここでは、まず、対象資産とオプションのインスタンスを両方生成し、オプションインスタンスから mandatory times (訳注: Lattice 上に必ず設定する必要がある日付の配列) を取りだします。次に、Lattice インスタンスを生成し、その Lattice 上に対象資産とオプション資産の初期値を設定します (通常、初期値が設定される’時点’は対象資産とオプションで異なります。対象資産がスワップであれば、その最終期日、オプションがスワップションなら、最終行使日)。そして最後に、オプション資産の価格を Lattice 上で遡って計算し、現時点の価格を得ます。すぐ後で説明しますが、オプションインスタンスは、対象資産価格の Lattice 上の遡及計算の面倒もみています。 

このクラスの実装の説明に戻りましょう。reset( )メソッドは、対象資産とオプションが同じ Lattice 上で初期化されているかどうかをチェックし、次に初期値(の配列)を一旦 0 に設定し (オプションを行使しなかった場合に得られる金額になります)、最後に adjustValues( )メソッドを呼び出して、オプションの行使条件に従った値に修正します。 

ここから、核心の部分に移ります。すなわち postAdjustValuesImpl( )メソッドです。考え方は極めて単純です。 Lattice上でオプション行使日にいる場合、オプションをそのまま保有し続けた場合の価値が、行使して対象資産に乗換えた場合の価値を上回るかどうかをチェックします。そのチェックの為に、対象資産の価格を、Lattice上の現時点(オプション行使日)まで遡り、各 Node で高い方の値をオプション価格として設定します。この最後の部分の動作は、applyExerciseCondition( )メソッドに委託されています。 

この動作を行う上での厄介な部分は、対象資産インスタンスの価格を Lattice上の現時点(オプション行使日)まで遡及計算する際に、対象資産価格の調整(訳注:クーポン額を加えることなど)が必要になる事です。その調整は、オプション行使の判断の前にすべきでしょうか、後にすべきでしょうか? 答えは、個別の調整内容次第です。前のセクションで示した DiscretizedFixedRateBond の例で見てみましょう。もし固定金利債で、かつ Lattice 上で(オプション行使日が)クーポン支払日にもなっているる場合は、その対象資産価格にクーポン額を加える調整が必要になります。しかし、そのクーポンは、オプション行使により対象資産を取得する場合は支払い後になるので、行使者の手元には入ってきません。従って、オプションを行使するかどうか判断に使う対象資産の価値には加えるべきではありません。すなわち、applyExerciseCondition( )メソッドは、対象資産価格の(クーポン額による)調整を行う前に呼び出されなければなりません。 

DiscretizedFloatingRateBondクラスの場合は、話が違ってきます。このクラスではクーポン額の調整を金利の Fixing日に行いますが、そのクーポン自体は Fixing日ではなく支払日に支払われるので、オプション行使の判断を行う前に対象資産の価格に加えられなければなりません。従って、固定金利債の場合と順番は逆になります。applyExerciseCondition( )メソッドは対象資産の価格調整を行った後で呼び出されなければなりません。 

オプション資産側では何かすべきでしょうか?オプション資産側では、対象資産側の個別の動作については何も知らないので、対象資産側にこの問題の処理を任せるしかありません。まず、対象資産の価格計算を、Lattice上の現時点(オプション行使日)まで行います(partialRollback( )メソッドがそれを行います)。しかし最終的な価格調整を行う前に、まず対象資産側の preAdjustValues( )を呼び出します。その後で、オプション資産側は自らの価格調整を実行します(訳注:すなわち、行使条件のチェックを行い、必要な価格調整をする)。そして最後に対象資産側の postAdjustValues( )を呼び出す事になります。 

以上が、DiscretizedAssetクラスが preAdjustValues( ) と postAdjustValues( )メソッドの2つを持っている理由です。これらのメソッドは、対象資産をオプション資産と組み合わせた場合に、対象資産側の価格修正をオプション資産側の修正(例えばオプション行使)の前と後のどちらでするか、対象資産側で選択できるようになっています。上記の例では、固定金利債の場合は、クーポン額の調整を postAdjustValues( )で行い、変動金利債の場合は preAdjustValues( )で行うことになります。
 残念ながら、この方法は、堅牢なプログラムとは言えません。例えば、オプション行使日がクーポン支払日の1~2週間前だったとすると (実際にそういったケースは多々あると思いますが)、固定金利債においてはオプション価格がきちんと計算できなくなる可能性があります。 Lattice上での対象資産価格の調整プロセスが、オプション行使判断の前に行われてしまうからです。(訳注: オプション行使日がクーポン日の少し前の場合でも、対象資産の取引はクーポン日に発生するのが普通で、その場合対象資産の価格はクーポン額を含めない価格で取引されます。Latticeを遡及する場合、クーポン支払日が先に来ると、資産価格に、どうしてもクーポン額が含まれてしまうことになり、オプション行使の判断が正しく行われなくなります。) この問題を無理やり解決する方法もあります。QuantLibライブラリーにある DiscretizedInterestRateSwapクラスでは、固定金利債のクーポン額の調整を、変動金利債の場合も同じように (訳注:DiscretizedFloatingRateBondでは、クーポン額の調整を、金利支払い期間のスタート時=fixing日 に行っている)、金利期間のスタート日に行うようにして、問題を回避しています。別の対処方法としては、対象資産の価格調整の遡及計算を、オプション行使により資産を取得する日までしか行わず、その時点で、一旦対象資産のコピーを生成し、価格調整を行わず行使日まで遡及計算する方法です。いずれも、かなり面倒くさいい解決策にしかなりません。QuantLibライブラリーで、もう少し自然な方法でこの問題を解決できればよかったなと思います。  

 

 

<ライセンス表示>

QuantLibのソースコードを使う場合は、ライセンス表示とDisclaimerの表示が義務付けられているので、添付します。   ライセンス

目次

Page Top に戻る

// // //