金利の期間構造YieldTermStructureクラスの設計を始めたのは、そのベースクラスであるTermStructureクラスの設計よりも前でした。StructureをTermStructureというクラス名でオブジェクトライブラリを作り始めていました。Structureを取り扱ったのは金利しか無く、ライブラリの全体像がまだ見えていませんでした。そのクラスが持つインターフェースは、イールドカーブ全体の期間の中でなら、どんな日付でも、その時点の(ForwardあるいはSpotの)金利を導出したり、割引率を計算したりするメソッドを提供していました。具体的にイールドカーブを描く作業を簡単にするような仕組みも用意していました。インターフェースと実装まずYieldTermStructureクラスの宣言のソースコードを示します。};コンストラクターは、引数を、ベースクラスであるTermStructureクラスへ渡しているだけであり、それ以外の情報をベースクラスに送っている訳ではありません。Structureに関する情報を返しますが、二通りの方法で対応しています。Aで説明するInterestRateクラスのインスタンスとして)返すメソッド群を用意しています。二通りの方法とは、これらのメソッドをオーバーロードして、引数として、日付を使う方法と、期間を使う方法を用意しています。ご存知のとおり、“ゼロ金利”と“フォワード金利”と“割引率”はそれぞれ密接にリンクしており、その内のどれか一つのカーブの情報があれば他の2つのカーブを導出できます(その計算式はあえて書きませんが、読者の方は十分ご存知かと思います)。この事は、下記のListing3.4の実装を見ればわかる通りです。)という抽象化されたprotectedメソッドを直接あるいは間接的に介在させて実装されています。)を実装するだけで、上記の3つの値を返す事ができます。)を呼び出して計算をしています。)がきちんと実装されていなければなりません。Wodehouseの小説に出てくる忠実で優秀な執事Jeevesのように、)QuantLibは、それに必要なクラスを2つ用意しています。3.5にある通り、ZeroYieldStructureとForwardRateStructureです。この2つのクラスは、Adapterパターンを使って(これも、デザインパターンに関する有名な4人組の本にある、根幹となるパターンのひとつです。)、ディスカウントカーブをベースにしたYieldTermStructureクラスのインターフェースを、ゼロ金利カーブあるいは瞬間フォワード金利カーブを基にしたインターフェースにそれぞれ変換したものです。};ZeroYieldStructureの実装は、単純明快です。(上記のコードでは書かれていませんが)複数用意されているコンストラクターは、引数をベースクラスであるYieldTermStrucutreのコンストラクターに渡しています。Adapterパターンがprotectedの部分で使われています。)メソッドの中で使われています。)メソッドのみを実装するだけで、きちんと機能するイールドカーブを得ることができます。)など)も同様に実装する必要がありますが。)が返すゼロ金利は連続複利収益率ベースの年率で返す必要があります。Structureを描く方法を提供します。)メソッドを実装する事によって、それが可能になります。その為には、ひとつ工夫が必要でした。Factorを計算するためには、時間0からTまでの瞬間フォワード金利の平均を計算しなければなりません。それが時間Tにおけるゼロ金利に相当します。このクラスはフォワード金利カーブの形状について何の仮定もおいていないので(訳注:Interpolationの方法が特定されていれば、ある程度、瞬間フォワード金利のカーブを式(何等かの関数)で表現できるが、この段階ではそれが決まっていない)、平均値を出すには計算時間がかかる数値積分を行うしかありません。)を仮想関数にして、より早い計算方法が見つかればそれをオーバーライドできるようにしています。この構成に対し反対意見があるかもしれません。ゼロ金利が必要なら、ZeroYieldStructureから持って来ればいいではないか、と。Structureをもっておくのは、考え方としてはスッキリしています。今説明した2つのAdapterクラス(ZeroYieldStructure、ForwardYieldStructure)とベースクラスであるYieldTermStructureクラスは、Interpolationしたディスカウントカーブ、ゼロ金利カーブ、およびフォワード金利カーブを実装するために使われます。下のListing3.6はInterpolatedZeroCurveクラスのテンプレートです。InterpolatedDiscontCurve)も同様に作れます。};テンプレート引数である“Interpolator”オブジェクトは2つの仕事を行います。ひとつは、Traitsクラスとしての役割です(下記[1]のMyersの文献参照)。どのInterpolationの方法を使うか指定し、かつその為に必要ないくつかの属性を指定します。その属性とは、例えば、いくつのデータポイントが必要になるのか(例えば線形補間なら最低2点のデータポイントが必要)とか、指定されたInterpolationの方法がGlobalかLocalなのかとかです。(すなわち、あるデータポイントのレートを動かした影響が、カーブ全体に及ぶのか、そのデータポイントの近辺だけに留まるのかという事。SplineなどSmoothingを行う方法を使うと、影響がカーブ全体に及ぶ)もう一つは、データポイントの集合が与えられると、それに対応するInterpolationクラスのインスタンスを作成し返してきます。Aで、ライブラリで提供されているいくつかの方法と、それに必要なTraits(属性)について説明します。)publicで宣言されたコンストラクターはカーブを構築するのに必要な情報を引数として取ります。(Pillar)となる日付の配列それぞれのNodeの日に対応するゼロ金利DayCounter(日数計算方法)オブジェクトInterpolatorオブジェクト(任意)ほとんどのインターポレーションンにおいて、上の最後の引数は不要(任意)です。インターポレーションを行う際にパラメータが必要な場合だけ、その情報を取り込めばいいからです。Dateに該当、およびDayCounter(日数計算方法))を渡します。その他の引数はメンバー変数に代入されます。いくつかのデータ整合性チェックのプロセスを経て、日付の配列を年数の配列に変換します。Interpolatorを使ってInterpolationインスタンスを生成し、最後にそのインスタンスをメンバー変数に代入します。この段階でカーブを使うことができます。他のメソッドは、1行で記述できるものばかりです。)は日付の配列の最後の日を返します。)はゼロ金利カーブの補間された値を返します。TermStructureクラスで、既に日付の範囲のチェックが終わっているので、Interpolatorクラスのインスタンスを呼び出すメソッドはtrueの引数を持ちます。この場合は、引数で渡された年数が、与えられた期間の範囲を越えている場合は、イールドカーブはExtrapolation(補外)されます。最後に、InterpolatedZeroCurveクラスは、いくつかのprotectedで宣言されたコンストラクターも定義しています。これらのコンストラクターはベースクラスであるZeroYieldStructureクラスと同じ引数を取り、それには任意引数であるInterpolatorインスタンスも含まれます。それらの引数を対応する親クラスのコンストラクターへ渡します。これらの親クラスはInterpolationを行うことはできません。そもそもゼロ金利のデータを持っていないからです。そもそも、これらのコンストラクターは、InterpolatedZeroCurveの派生クラスの為につくられたものです。派生クラスで、Interpolationに必要なデータを提供し、それと、その他の必要な情報を引数として取得し、Interpolationを行います。(これの例を、この章の残りのセクションで示します。同じ理由から(訳注:派生クラスで具体的にデータを操作する事を想定している理由から)、ほとんどのメンバー変数はmutableで宣言されています。Breakの事)で示した通り、派生クラスにおいて、イールドカーブ構築に使うデータに変更があった場合、インターポレーションをLazilyに行えます。(訳注:LazyObjectと呼ばれるベースクラスから派生させる事により、原データの変更があっても、直ちに再計算をするのでは無く、必要な時だけ再計算、すなわちイールドカーブの再構築を行えるようにしている事。Curve)は、お互い平等に取り扱った方がいいのではないかと主張されるかもしれません。Curveが他のカーブより優越的な役割を果たしているように見えます。)を定義し、それらに対応する3つのAdapterを作成する方法もあるかも知れません。その為には、(既存のZeroYieldStructureとForwardYieldStructureクラスに加え)DiscountStructureクラスというのを作る必要があります。その論点はごもっともで、最初に設計したYieldTermStructureクラスの作り方は、そのように対称的でした。ディスカントファクターをベースにしたインターフェースへの変更と、その理由については、時間とともに霧の中へ消えてしまいましたが、おそらく様々な金利を表現するオブジェクトとしてInterestRateクラスのインスタンスを使うようになった事が原因かもしれません。)の結果(連続複利ベースのゼロ金利)をそのまま直接返す訳にはいかなかったからではないかと思います。>読者の方は、InterpolatedDiscountCurveやInterpolatedForwardCurveクラスの中で使われるコードは、InterpolatedZeroCurveのコードと、非常に似たものになると推察されるかもしれません。すると、次のような疑問がわきます。そのような似たコードは、抽象化して一本のコードにできないのかと。ひとつのTemplateクラスにまとめられないのかと。それに対する答えは、それぞれYesとNoです。いくつかのコードは既にTemplateクラスに抽象化されています。)を実装してやる必要があります。従って、3つの別々のクラスが必要で、それに加えて共通のコードのためのTemplateクラスが必要なのです。例:InterpolationされたカーブのBootstrappingこのセクションでは、何でも使えるイールドカーブのテンプレートを構築します。前のセクションで説明したクラスを使って構築しながら、そのイールドカーブテンプレートに、ディスカウントファクター、ゼロ金利、あるいは瞬間フォワード金利を、様々な方法でインターポレーションできる機能を与えます。カーブ上のNodeポイント(訳注:3か月、6か月、1、2,3,4,5年、10年、20年など基準となる日付。Rateを)導出していきます。申し上げると、ここに示す例はかなり複雑です。ここで説明するクラステンプレート(PiecewiseYieldCurveクラス)は、いくつかのHelperクラスを利用しており、またTemplateを作る際のちょっとした工夫が含まれています。必要に合わせて、そのすべてを説明するようにします。クラステンプレートの実装内容を、下記Listingに示します。base_curve::discountImpl(t);}このクラスは3種類のテンプレート引数を取ります。最初の2つの引数は、Interpolationの対象データに関する情報と、具体的なインターポレーションの方法です。我々のゴールはこのテンプレートを使って次の様なインスタントを生成することです。traitsに該当しますが、これについては後で説明します。2番目のテンプレート引数(この例ではLogLinear)はすでに前のセクションで説明したInterpolator(インターポレーションの方法を設定しているクラス)です。3番目のテンプレートパラメータは(この例では宣言の時にデフォールト値を設定しているため省略されている)、見た目はややこしそうですが、Bootstrapの計算アルゴリズムを特定するクラスです。おいて、このデフォールト値の方法を使って良い)。探究したいプログラマーが、後で自ら開発した別のBootstrapの方法や、ライブラリで提供されている別のBootstrap法に入れ替える事が出来るように、こういう構成にしました。parameterです。templateが2回でてきますが、間違いではありません。テンプレートの引数として、特定のデータ型ではなく、具体化される前のクラステンプレート(このケースでは、3番目の、テンプレート引数を1個持つクラステンプレートです)を取っているという意味です。(具体化される前のテンプレートとは、例えばstd::vectorのようなもので、反対に具体化されたクラステンプレートはstd::vector<double>のようなものです。後者は具体的な型を指定していますが、前者はしていません)クラスのインターフェースを宣言する前に、もうひとつテンプレートのプログラミング技法を使って、カーブの親クラスを決める必要があります。IIを参照)から継承されており、これによりこのTermStructureクラスは必要な時に(原データの更新があった時に)再Bootstrapをかける事ができます。ひとつ、我々はこのTermStructureクラスを、前のセクションで説明した、インターポレートされたカーブからも継承したいと考えます。(Interpolationされる)原データを何にするかによって(ディスカウントファクターか、ゼロクーポンレートか、または瞬間フォワード金利なのか)、我々は用意されているクラステンプレートの中からそれを選択し、それに適切なInterpolatorクラスを組み合わせて、そのインスタンスを生成します。traitsの中にそのクラステンプレートを保存することによって成されます。残念ながら、C++は最近までtemplateのtypedef機能はありませんでした(2011年のC++の見直しの時、templateのaliasが加えられました)。traitsは、内部クラスとしてクラステンプレート“curve”を定義し、そのcurveがテンプレート引数として“Interpolator”クラスを取り、typedefを使って、その具体化されたベースクラスを定義します。traitsの例で示します。}上記に説明した仕組みを使って、ようやく選択されたベースクラスを下記例のような表現を使って、参照できます。curve::type(テンプレート構文の詳しい働きについてあまり詳しくない人の為に説明を加えると、上記構文の中のtemplateというKeywordはコンパイラーに対する一種のヒントと見做せます。コンパイラーがこのKeywordを読んだとき、Traitsが何かわかっていません。従ってTraits::curveがクラステンプレートかどうか判断するすべがありません。そのKeywordを加える事によって、残りの構文を処理するために必要な情報を与えています。curve<Interpolator>::type)はDiscount::curve<LogLinear>::typeのインスタンスを生成したことになり、さらにそれは(望んだように)Discountクラスの定義の中にあるInterpolatedDiscountCurve<LogLinear>に対応するものとなります。最終的にイールドカーブの生成に行く前に少し寄り道をします。長いテンプレートクラスの表現を避ける為に、いくつかのテンプレートクラスをtypedefで定義しています。base_curve、this_curve、helperがそれです。traitsから持ってきたhelperクラスになります。このhelperクラスについては後で詳しく説明しますが、ここで簡単に前説しておくと、このクラスは原商品の市場レートを提供すると同時に、Bootstrapされたイールドカーブを使ってその原商品の価格を再計算する機能を持っています。Bootstrapの目的は、(入力に使われた)原商品の価格と、生成されたイールドカーブで計算されたその商品の価格が一致するように、カーブを何度も微調整していく事です(訳注:Solverを使った最小値問題の解を出す手順)。interpolation_typeにはそれぞれ、テンプレート引数で取り込まれたものが格納され、後で使われる時に引き出されます。実際のインターフェースの説明に入ります。curveのインスタンスを生成するのに必要な引数helperインスタンスの配列Bootstrapアルゴリズムにおける目標精度を取ります。)が親クラスの関数をOverrideする(書き換える)かたちで定義されています。後で説明しますが、これによってイールドカーブは要求されたデータを返す前に、きちんと完成された事を確認します。