2. "Implementing QuantLib"の和訳
Chapter VIII The Finite-Difference Framework (有限差分法のフレームワーク)
8.1 The Old Framework (古いフレームワーク)
8.1.4 Step Conditions : 時間ステップ遷移時の条件
あるステップ時点に(あるいはステップ間に)おいて、資産価格が変化する事象が発生する事があります(ステップ間に事象が発生する場合の対応については、後で説明します)。例えば、オプションの行使があったり、クーポンが支払われたりする場合です。
Boundary Condition(境界条件)という名前に対して、我々はこのような条件を Step Condition(時間ステップ遷移時に発生する条件)と名付けました。この名前は最善では無いかもしれません。ある時間ステップにおけるデリバティブズ資産の価格を、"オプションの‘行使によって得られる価値’と、‘継続保有した場合の価値’の大きい方とする(訳注:所謂アメリカンオプションの行使条件)”といった条件を、Step Conditionと考えるのは簡単に受け入れられます。しかし、クーポンの支払いを、同じカテゴリーの条件とは考えにくいかもしれません。いずれにしても、そのような Step Conditionのベースクラスの実装を、下記 Listing 8.6に示します。
Listing 8.6:StepConditionクラステンプレートのインターフェース
template <class array_type>
class StepCondition {
public:
virtual ~StepCondition() {}
virtual void applyTo(array_type& a, Time t) const = 0;
};
applyTo( )メソッドは、ある時間ステップにおける資産価格の配列を修正する動作を行いますが、まずその時点において Step Conditionが適用になるかどうかをチェックしなければなりません。従って、例えば、アメリカンオプションの行使であれば、どの時間ステップにいても、常に価格の修正が起こり得ますが、配当金の支払いであれば、その時点が支払日に該当するかチェックし、そうでない場合は、何もしません。
ご覧の通り、ベースクラスはいたってシンプルです。しかし、派生クラスは Over-generalized (訳注:いきすぎた抽象的階層化) されており、相当下の階層まで伸びています。下記 Listing 8.7 に、そうようなクラス階層の例が示されていますが、アメリカンオプションの行使条件のような単純な条件でさえ、このクラスからさらに派生しています。(こんなに複雑に階層化せず)オプションの継続価値と行使価値を比較する単純な applyTo( )メソッドを実装する事も可能でした。しかしそうせずに、我々は何年にも渡って、このクラスのコンストラクターを、(行使価値の情報を持つ様々なオブジェクト毎の)引数の型に合わせて、継ぎ足していきました。すなわち、Intrinsic Values の配列用と、Payoff関数用と、あるいは Payoffを記述するような様々な型のデータ用に (訳注:下記コードにある複数のコンストラクターを参照して下さい)。 当然ながら、そうやって取ってきた様々な型の引数を、一旦メンバー変数に保持する必要があります。その為に type erasure(注:型消去のテクニック。T. Becker, On the Tension Between Object-Oriented and Generic Programming in C++. 2007. を参照)を使って、異なった型をひとつにまとめ(訳注:コード中の CurveWrapper とその派生クラスがそれ)、そこから行使価値を取りだすメソッドを定義し、そのメソッドを、型が配列ベースか PayOffベースに合わせて実装しました。
Listing 8.7:CurveDependentStepConditionクラステンプレートの概要
template <class array_type>
class CurveDependentStepCondition
: public StepCondition<array_type> {
public:
void applyTo(Array &a, Time) const {
for (Size i = 0; i < a.size(); i++) {
a[i] = applyToValue(a[i], getValue(a,i));
}
}
protected:
CurveDependentStepCondition(Option::Type type,
Real strike);
CurveDependentStepCondition(const Payoff *p);
CurveDependentStepCondition(const array_type & a);
class CurveWrapper {
public:
Real getValue(const array_type &a,
Size index) const = 0;
};
boost::shared_ptr<curvewrapper> curveItem_;
Real getValue(const array_type &a, Size index) const {
return curveItem_->getValue(a, index);
}
virtual Real applyToValue(Real, Real) const = 0;
class ArrayWrapper : public CurveWrapper {
array_type value_;
public:
...
};
class PayoffWrapper : public CurveWrapper {
boost::shared_ptr<payoff> payoff_;
public:
...
};
};
皮肉な事に、(ここまで大変な事をしたのに)我々は実装した機能の半分しか使っていません。Libraryにある既存の価格エンジンは、配列ベースのコンストラクターと(行使価値を取りだすメソッドの)実装部分を使っていますが、Payoffクラスに対応する(コンストラクターや)実装部分はどこにも使われていません。使われなかった事自体は、結果的に OKでした。というのは、この章を書くにあたってプログラムコードを再度見直した所、その実装内容が間違っている事がわかりました。そう、まとめて言えば、アメリカンオプションの行使条件は、はるかに簡単な実装で書く事が可能だったのです。すなわち、行使価値の配列を取りだし、applyTo( )をそれに従って実装するだけでよかったのです。もし、読者の方が Step Conditionを実装するのであれば、同様の方法を取られる事をお勧めします。
最後の注意点ですが、次のセクションで見る通り、Step Condition は Evolution Schemeの中の step( )メソッドの中では使われていません。その理由は、Step Conditionが境界条件を壊してしまう可能性があるか、あるいはその逆が起こる可能性があるからです。実務上は、あるモデルで意味のある Step Conditionを設定する事は、通常境界条件も守られるようにしているはずです。
これで、基本的な部品はすべて用意できました。これから、これらを組み立てていきます。
< Aside: お母さん見て、手を離してるよ! >
PayoffWrapperクラスの間違った実装が QuantLibライブラリーに加えられたのは 2003年2月に遡ります。ライブラリーの中で、おそらく最も長く存在していたバグでしょう(まだ見つかっていないものを除けばですが)。もし、私がこの章を書く為にプログラムコードを見直さなかったら、この小動物は自動車の運転ができるくらいまで年を重ねていたことでしょう。
バグが発生する事自体は、ショックを受けるような事ではありません。私ががっかりするのは、この問題は、簡単な単体テストをちょっと行うだけで発見できたはず、という事です。私や他の開発に携わった人たちは、通常、QuantLibライブラリーがどのように動作するか試したり見直したりしますし、完成したコードは、時には実務の中で使われ、明白な問題点は、その段階で取り除かれます。しかし、Test Suiteの中の古いプログラムコードについては、そういった事が十分行われていなかった事に、若干不安を覚えます。もし読者の方が、QuantLibライブラリーを使うツールをお持ちで、そういった事に手を貸してくれるのであれば、是非フィードバックをお願いしたいです。そういった分析結果を是非見たいものです。
<ライセンス表示>
QuantLibのソースコードを使う場合は、ライセンス表示とDisclaimerの表示が義務付けられているので、添付します。 ライセンス