2. "Implementing QuantLib"の和訳
Chapter-IV Cash Flows and Coupons
4.2 Interest-Rate Coupons
Couponクラス(下記Listing 4.2参照)は、特定の期間に対応して、特定の日数計算方法を使い、利息を発生させる、あらゆるキャッシュフローのベースクラスとして使えます。当然ながら、このクラスは抽象的なベースクラスとして、キャッシュフローを取り扱う追加のインターフェース・メソッドを定義していますが、いくつかの日数計算に関する具体的なメソッドの実装も行っています。
Listing 4.2: Interface of the Coupon class
class Coupon : public CashFlow {
public:
Coupon(Real nominal,
const Date& paymentDate,
const Date& accrualStartDate,
const Date& accrualEndDate,
const Date& refPeriodStart = Date(),
const Date& refPeriodEnd = Date());
Date date() const {
return paymentDate_;
}
Real nominal() const {
return nominal_;
}
const Date& accrualStartDate() const; // similar to the above
const Date& accrualEndDate() const;
const Date& referencePeriodStart() const;
const Date& referencePeriodEnd() const;
Time accrualPeriod() const {
return dayCounter().yearFraction(accrualStartDate_,
accrualEndDate_,
refPeriodStart_,
refPeriodEnd_);
}
Integer accrualDays() const; // similar to the above
virtual Rate rate() const = 0;
virtual DayCounter dayCounter() const = 0;
virtual Real accruedAmount(const Date&) const = 0;
virtual void accept(AcyclicVisitor&);
protected:
Real nominal_;
Date paymentDate_, accrualStartDate_, accrualEndDate_,
refPeriodStart_, refPeriodEnd_;
};
抽象的なインターフェースとして rate( )メソッドが純粋仮想関数として宣言されており、派生クラスで、そのクーポンの利率を返すよう実装されることになります。また dayCounter( ) と accruedAmount( )メソッドも同様に、それぞれ日数計算方法と、ある特定の日までの経過利息金額を返すよう、派生クラスで実装されます。
rate( )メソッドを純粋仮想関数として宣言している理由は明らかでしょう。しかし、他の2つのメソッドもそうしたのは、必ずしも必然ではありません。dayCounter( )について言えば、Couponクラスのメンバー変数として Day Counter(日数計算方法を司るオブジェクト)を保持する事も考え得ると思います。この方法は、実際に TermStrucutreクラスを設計する際に取った方法です。さらに言えば、nominal( )メソッドについては(概念的には同じであるものの)抽象メソッドとしておらず、メンバー変数を返すよう Couponクラスの中で実装されています。私としては、Devil’s Advocate(問題点の提起者)として、ベースクラスのインターフェースは、抽象的に(仮想関数として)宣言する方に賛成ですが、この例の方法に強く反対するものでもありません。しかし、整合性に欠ける点は、気になります。
accruedAmount( )メソッドは、別の問題を抱えています。このメソッドは、間違った理由で抽象メソッド(純粋仮想関数)になっています。このメソッドは、rate( )メソッドを呼び出して、その返し値(利率)に Notional(みなし元本)と経過期間を掛けるというデフォールトの実装をベースクラスで行う事が可能でした。しかし、後からやむなく抽象メソッドにした理由は、いくつかの派生クラスにおいて、rate( )メソッドを amount( )メソッドを使って実装するという事をやってしまった為でした(本来、その逆にすべきでした)。そのような派生クラスでは、accruedAmount( )メソッドは、その方が効率的であろうというやや疑わしい理由から、amount( )メソッドを使って定義されています。しかし、正しい選択肢は、Couponクラスで標準となる実装を行った上で、派生クラスでは必要に応じて Overrideするという方法であったかも知れません。将来、バージョンアップの際に、そのように変更するかもしれません (注: amount( )メソッドについても同様に、標準となる実装をベースクラスで行う事が可能であったと言えます)。
その他のインターフェースは、具体的に実装されたメソッドから成っています。コンストラクターは、いくつかの変数を引数として取り、メンバー変数に代入しています。具体的に言うと、額面(nominal)、クーポンの支払日(payment Date)、経過利息期間を計算するための日付(accrualStartDateと accrualEndDate)です。通常は、経過利息期間は開始日と終了日の情報で十分なのですが、日数計算方法によっては、さらに追加の情報として、参照期間のスタート日と終了日の情報が必要になる場合があります。(訳注:米国のモーゲージ証券など、一部の債券では、クーポンの参照期間と経過利息発生期間がずれる場合がある。)
Couponクラスでは、各メンバー変数に対応して、それぞれの Inspectorメソッド(訳注:メンバー変数の値を、なんらかのデータ整合性のチェックを行った上で返す関数)を定義しています。支払日を返すメソッドである date( )メソッドは、CashFlowクラスのインターフェースとして宣言され(訳注:実際にはその親クラスの Eventクラスで純粋仮想関数として宣言されている)、ここで実装されています。さらに、accrualPeriod( ) と accrualDays( )メソッドが実装されており、Listing 4.2にある通り、日数計算方法(のオブジェクト)と経過利息期間および参照期間(それぞれスタート日とエンド日)を使って(訳注:プログラムコード中で純粋仮想関数として宣言されている dayCounter( )メソッドが DayCounterオブジェクトを返し、そのオブジェクトが保持するメソッドを使って計算している)必要な計算を行っています。
先に進む前に、2点、注意点をあげます。1点目は、dayCounter( )メソッドについては、ここにある様な、計算に必要な日付を保持しているにもかかわらず、それに対応するメソッドを抽象メソッドとして宣言するのとは、別の選択肢があったかも知れません (訳注:このクラスでdayCounter( )メソッドの具体的な実装を行ってしまう選択肢があったということ)。既に述べたように、私自身は極力抽象メソッドを使う方の支持者ですが、このケースでは、現実的には、すべての派生クラスで、必要な日付を保持し、同じ内容の Inspectorメソッドを実装するのはあまりいい考えではなかったかも知れません。(注:派生クラスでクーポン日をメンバー変数として保持する必要のないクラスは、おそらく、すでにそれを保持するクラスをDecorateする為に作られたクラス(Decoratorパターンによる構成)のみであろうと思われます。) dayCounter( )メソッドを具体的なメソッドとして(Couponクラスの中で)実装すべきかどうか、ひとつの観点になるかと思います。
2点目は、様々な目的で必要とされる‘日付’の情報を、対応するInspectorメソッドを使ってクラス外で使えるようにする事は、正当な事だと思いますが、一方で、accrualPeriod( )のような提供されているメソッドを使うのではなく、その情報を使ってユーザーが自分で計算してしまう動機づけにもなってしまいます。もちろん、こういった情報へのアクセスを制限する事は出来ませんが、それに対する注意喚起することは可能です。
最後ですが、accept( )メソッドの説明については、忘れている訳ではありません。後に、Visitorパターンの説明をする際に、あらためて説明します。
4.2.1 Fixed Rate Coupons (固定金利クーポン)
では、Couponクラスのインターフェースを実装する具体的な派生クラスの説明に進みましょう。そういったクラスの中で最もシンプルなものは、当然「固定金利クーポン」になるでしょう。そのクラス名は FixedRateCoupon で、その実装の概要を Listing 4.3に示します。実際のところ、この実装はそんなに単純という訳ではありません。このクラスの構成は、当初は単利のクーポンを想定していましたが、後に、様々なタイプの複利のルールを取り込めるように、より一般化しました(未熟な汎用モデルは悪であるという例です)。
Listing 4.3: Sketch of the FixedRateCoupon class
class FixedRateCoupon : public Coupon {
public:
FixedRateCoupon(Real nominal,
const Date& paymentDate,
Rate rate,
const DayCounter& dayCounter,
const Date& accrualStartDate,
const Date& accrualEndDate,
const Date& refPeriodStart = Date(),
const Date& refPeriodEnd = Date())
: Coupon(nominal, paymentDate,
accrualStartDate, accrualEndDate,
refPeriodStart, refPeriodEnd),
rate_(InterestRate(rate,dayCounter,Simple)),
dayCounter_(dayCounter) {}
Real amount() const {
return nominal() *
(rate_.compoundFactor(accrualStartDate_,
accrualEndDate_,
refPeriodStart_,
refPeriodEnd_) - 1.0);
}
Rate rate() const { return rate_; }
DayCounter dayCounter() const { return dayCounter_; }
Real accruedAmount(const Date&) const; // similar to amount
private:
InterestRate rate_;
DayCounter dayCounter_;
};
コンストラクターは、ベースクラスである Couponクラスのコンストラクター用の引数に加えて、rate(利率)と DayCounter(日数計算方法)も取り込んでいます。この Listingにあるコンストラクターは、rateとして、実数を取っていますが、別のコンストラクターでは(この例では簡略化の為、省略しています) InterestRateクラスのインスタンスを取っています。nominal(額面)と、いくつかの日付の情報は、ベースクラスのコンストラクターにそのまま渡されますが、それ以外の引数はこのオブジェクトのメンバー変数に代入されます。特に、(単純な浮動小数点付き実数として渡される)利率は InterestRateクラスのインスタンスを生成するために使われます。
ベースクラスの仮想関数を実装する部分については ( rate( )と dayCounter( )メソッド)、単純に保持されたメンバー変数の値を返す動作を実装しています。残りの amount( )と accruedAmount( )メソッドの実装は、用意されているデータを使って実装されています。クーポン金額を返す amount( )は、額面に利率を掛け、それをクーポン期間に渡って対応する複利ベースで元利合計を計算し、そこから額面部分を差し引いて、クーポン金額を算出します。accruedAmount( )メソッドの計算も、同様の方法で行われますが、計算に使われるクーポンの経過期間のみが異なります。
最後にひとつ注意点を述べます。すでに述べた通り、amount( )メソッドの実装をベースクラスであるCouponクラスの中で行う事も可能でした。その計算は、単純に元本に利率と経過期間を掛けるだけだと推察されるからでしょう。でも、そのような単純に思える計算にもかかわらず、この単純な具体例においてさえ、そうなっていないのです。amount( )メソッドを Couponクラスで実装すること事に対する合理的な疑問をなげかけている事がお判りでしょうか。ソフトウェアの設計は、本当に難しいですね。
4.2.2 Floating Rate Coupons (変動金利クーポン)
FloatingRateCouponクラスの設計は、ほとんどのソフトウェアのライフサイクルの象徴といっていいでしょう。簡単なものからスタートし、時が経つにつれて複雑になって行き、今では、いくつかの設計変更が必要な段階かも知れません。現時点の実装は (Listing 4.4参照) いくつかの問題点を抱えており、これから説明していく中でそれを指摘していきます。(注:古いバージョンとの互換性を壊さない範囲での修正は行うでしょうが、(まだ具体的な計画は無いものの)Release 2.0での大幅修正までの間は、これらの欠点と共存しなければならないでしょう。)
Listing 4.4: Sketch of the FloatingRateCoupon class
class FloatingRateCoupon : public Coupon, public Observer {
public:
FloatingRateCoupon(
const Date& paymentDate,
const Real nominal,
const Date& startDate,
const Date& endDate,
const Natural fixingDays,
const shared_ptr<InterestRateIndex>& index,
const Real gearing = 1.0,
const Spread spread = 0.0,
const Date& refPeriodStart = Date(),
const Date& refPeriodEnd = Date(),
const DayCounter& dayCounter = DayCounter(),
bool isInArrears = false);
Real amount() const;
Rate rate() const;
Real accruedAmount(const Date&) const;
DayCounter dayCounter() const;
const shared_ptr<InterestRateIndex>& index() const;
Natural fixingDays() const;
Real gearing() const;
Spread spread() const;
virtual Date fixingDate() const;
virtual Rate indexFixing() const;
virtual Rate convexityAdjustment() const;
virtual Rate adjustedFixing() const;
bool isInArrears() const;
void update();
virtual void accept(AcyclicVisitor&);
void setPricer(const shared_ptr<FloatingRateCouponPricer>&);
shared_ptr<FloatingRateCouponPricer> pricer() const;
protected:
Rate convexityAdjustmentImpl(Rate fixing) const;
// data members
};
FloatingRateCoupon::FloatingRateCoupon(
const Date& paymentDate, const Real nominal,
...other arguments...)
: Coupon(nominal, paymentDate,
startDate, endDate, refPeriodStart, refPeriodEnd),
/* store the other data members */ {
registerWith(index_);
registerWith(Settings::instance().evaluationDate());
}
Real FloatingRateCoupon::amount() const {
return rate() * accrualPeriod() * nominal();
}
Rate FloatingRateCoupon::rate() const {
pricer_->initialize(*this);
return pricer_->swapletRate();
}
Date FloatingRateCoupon::fixingDate() const {
Date d = isInArrears_ ? accrualEndDate_ : accrualStartDate_;
return index_->fixingCalendar().advance(
d, -fixingDays_, Days, Preceding);
}
Rate FloatingRateCoupon::indexFixing() const {
return index_->fixing(fixingDate());
}
Rate FloatingRateCoupon::adjustedFixing() const {
return (rate()-spread())/gearing();
}
Rate FloatingRateCoupon::convexityAdjustmentImpl(Rate f) const {
return (gearing() == 0.0 ? 0.0 : adjustedFixing()-f);
}
Rate FloatingRateCoupon::convexityAdjustment() const {
return convexityAdjustmentImpl(indexFixing());
}
最初の問題点は、クラスの名前そのものです。FloatingRateCouponというクラス名は、ある特定のタイプのクーポン、すなわち LIBOR金利に基づく変動金利を想起させます。しかし乍ら、このクラスはもっと広範に変動金利をモデル化しており、例えば CMS といった別のタイプの変動金利を持つクーポンも含まれています。残念ながら、別の名前を使っても、もっと悪くなるのが落ちかもしれません。例えば、この箇所を書いている最中に思いついた VariableRateCoupon というのは、金利の定義まで変えてしまうような名前で、こうやってみていくと、現時点でクラス名を変更しなければならないような理由はないでしょう。
横道にそれたので、実装に戻りましょう。上記の実装内容を見てください。コンストラクターは、引数として、ベースクラスである Couponクラスに必要な、さまざまな日付の情報や notional(元本額面)を取り込み、ベースクラスのコンストラクターに渡しています。それ以外にも、引数として日数計算方法 (DayCounterオブジェクト) や金利の fixing (訳注:変動金利を特定の日の金利インデックスに従い決定するプロセス) のために必要ないくつかの情報を取り込みます。その中には、変動金利の決定に使う為の InterestRateIndexオブジェクトや(注:このクラスの詳細については、Appendix A の InterestRateIndexのセクションをご参照下さい。ここでの説明としては、このクラスの役割は過去の Index の fixing の情報と将来の fixing の予想を提供するものである、というので十分でしょう)、fixingの為に必要な他の詳細情報も含まれています。その情報とは、fixingDays (訳注:金利を決定する日から金利期間がスタートする日までの間の日数。LIBORであれば通常2営業日)、金利が後決めかどうか (訳注:引数’inArrears’のことで、Bool変数。デフォールトはFalse)、さらに、(必要であれば) 倍率(gearing) とスプレッド(spread) の情報などです。Couponクラスのコンストラクターに渡されない引数は、自分自身のメンバー変数に保持されます。さらに、このクラスのインスタンスが生成される際、自分自身を InterestRateIndexインスタンスと(グローバル変数である) Evaluation Dateインスタンスに対する Observer として登録します。この後すぐに説明しますが、fixingDays と inArrears の引数は、変動金利の決定日を特定するのに必要な情報です。また、gearing と spread の引数が渡された場合、変動金利クーポンは、以下の式で計算されます。
\( R = g \times F + s \) 但し、g: gearing, F: 金利インデックスにより決定されたレート、 s: spread
(注: Reverse-Floaterのクーポンの決定式として、一般的には 固定金利 - 倍率 × 金利インデックス、 の形の式が使われる為、倍率の符号をマイナスにし、spreadで固定金利の情報を与えれば、このクラスは Reverse Floater のクーポンにも使えそうですが、それはお勧めできません。理由は、この式では、Reverse Floater に内包されているクーポンの Floor (=0%) の情報が取り込めないからです。)
コンストラクターの引数をこのように決めた事で (それによりどのようなメンバー変数を持つかも決まる)、このクラスが取扱える変動金利のタイプが限定されてしまう事になります。このオブジェクトモデルでは、変動金利が一種類の金利インデックスにより決定されるものしか取扱えません。他の種類の変動金利で、例えば2種類の金利インデックスの差でクーポンが決まるような変動金利は、このオブジェクトモデルでは取扱えないという事です。そういった金利インデックスを無理やりこのクラスに押し込むことも出来ない訳ではありません。InterestRateIndexクラスから2種類の金利インデックスのスプレッドをモデル化したクラスを派生させ、そのオブジェクトを FloatingRateCouponインデックスのコンストラクターに渡すような方法です。しかし、この方法は、特定の金融商品に関する概念をモデル化した階層構造の中に、無理やり違った概念を押し込む事になります。2種類の金利インデックスのスプレッドは、それ自体はもはや金利インデックスでは無いからです。
コンストラクターの次に宣言されているいくつかのメソッドは、ベースクラスである CashFlowクラスと Couponクラスで宣言されたインターフェースの実装です。不思議なことに、変動金利クーポンは固定金利クーポンより複雑なのにもかかわらず、amount( )メソッドの実装内容は、固定金利の場合よりシンプルです。計算内容は、金利と経過期間とみなし元本を掛け合わせているだけです。計算がこれだけであるなら、実装を Couponクラスで行ってしまうという考え方を支持する根拠になるかもしれません。accrualAmout( )メソッドの実装内容も同様にシンプルです(上記コードには含まれていませんが、経過期間の部分が異なるだけです)。rate( )メソッドの説明はここでは飛ばしますが、少し後でその実装内容について説明します。
その次に、いくつかの inspectorメソッド (訳注:メンバー変数の (データの整合性をチェックした上で) データを返すメソッド) が宣言されています。(Couponクラスのインターフェースとして宣言され、派生クラスで実装が必要な) dayCounter( )メソッドを除いて、変動金利クーポンの特有のパラメータを返すメソッドとして、index( )、 fixingDays( ) gearing( ) spread( ) などのメソッドが用意されています。
最後に、Business Logic(実務的な慣行) を表現しているいくつかのメソッドについて説明します。その内の最初の2種類のメソッドは、fixingDate( ) とindexFixing( ) です。いずれも見ての通りですが、fixingDate( )メソッドは、まず金利の決定方法が後決めかどうかチェックし、次にそれに従って参照日付を選択し(後決めならばクーポン期間の最後の日で、そうでなければ期間のスタート日になります)、さらにそこから fixing days(金利決定期間) の営業日数分、日付を後戻りした日が Fixing Date(金利決定日) になります。その間にインデクスに適用されるカレンダーで休日があれば、その日は飛ばします。indexFixing( )メソッドは、メンバー変数で保持されている FloatingRateIndexインスタンスのインターフェースを使って、金利を決定する日を渡せば、その日の決定金利を返します。
上記の両方のメソッドの実装方法について、「straightforward(見てのとおり)」と言いましたが、その構造に一点問題があります。コンストラクターが、1種類の金利インデックスしか想定していないのと同様、この2つのメソッドとも、使う金利インデックスが1種類しかないと想定しています。その結果、若干の汎用性を失っています。例えば、金利決定日が複数あって、その平均でクーポンを決めているような例や、クーポン期間を複数に分割してその間の複利で金利が決定されるような例は取扱えません。
最後の2つのメソッドは、金利インデックスによるクーポンレート決定の際に Convexity Adjustment の必要がある場合に使用されます。adjustedFixing( )メソッドは、rate( )メソッドを使って実装されており、クーポンレートの決定式 ( \( R=g \times \hat F + s \) ) を逆算して、もとの金利インデックス ( \( Fixing\ Rate = \hat F= \frac{R-s}{g}\) ) の決定金利を導出します。この実装方法は、過去の金利インデックスとクーポンレートの関係に依存している為、かなり脆弱です。仮に派生クラスでこのメソッドを修正するような場合は (例えば、過去のクーポンに Cap あるいは Floor による修正が入っていた場合など。これについては後で説明します)、このメソッドそのものも修正される必要があります。残念ながら、その修正は、今後のプログラマーにまかされています。プログラム言語の中で、2種類のメソッドを同時に Overrideする事を強制するような構文は存在していません。
convexityAdjustment( )メソッドは、当初の Fixing Rate と調整後レートとの差を取って、調整幅の値だけを返します。実際には、その動作を、protectedメソッドである convexityAdjustmentImpl( ) に委託しています。この方法は、過去の実装方法のなごりで、こうする事によって計算を最適化することを意図したものでした。現時点の実装方法としてはもはや必要のないものであり、今後、単純化するため、protectedメソッドを publicメソッドのなかに in-line化して、このメソッドを削除してもいいかもしれません。
< Aside:汎用性と実用性のバランス >
FloatingRateCouponオブジェクトを設計するにあたって、金利インデックスや金利決定日がそれぞれ1つしかないという前提を取ったことは、もちろん残念な事でした。しかし、そうなった理由は、汎用性の要請と、クラスの提供するインターフェースの有用性との間でバランスを取るためでした。クラスの設計がより汎用的になるほど、それが持つことの出来るインターフェースや情報は少なくなります。そうした問題点は、オブジェクトモデルの階層構造をより多層にする事によって、一部解消可能ですが (必要が出てくれば、将来そうするかも知れません)、それによって複雑性が増し、それによる問題点も出てきます。現在の FloatingRateCouponクラスの実装は、おそらく最適な妥協点とは言えないでしょうが、とりあえず、今の段階では何とか使えるものだと思います。
rate( )メソッドの説明に戻ります。QuantLib Libraryの以前のバージョンでは、読者の方も予想出来たかも知れませんが、以下のような実装内容で、InterestRateIndexクラスのインスタンスが提供する fixing( ) (訳注:変動金利の決定機能を持つメソッド) を使って、変動金利レートを取ってきていました。
Rate f = index_->fixing(fixingDate());
return gearing_ * (f + convexityAdjustment(f)) + spread_;
(注:読者の方は気づかれると思いますが、convexityAdjustment( )の実装と上記実装が相まって、無限再帰計算を引き起こす可能性がありました。convexityAdjustment( )の実装内容も、実は以前のバージョンは異なっていて、調整幅の計算を外生的 (訳注:FloatingRateCouponクラスの外で) に行って返すものでした。)
簡潔性は大事ですが、新たな要請(様々な変動金利の決定方法に対応する必要性)が出てくると、実装方法も修正せざるを得ませんでした。これは、Instrumentクラスの設計の時に直面した問題でもありました(Chapter IIのPricing Engineの項を参照)。
今回も、Instrumentクラスの時と同じく、解決策として Strategy Pattern を使って対応しました。ただ、FloatingRateCouponクラスで選択した実装方法は、若干異なっています。今回は、実装で要求されている内容はより具体的で、どういう計算結果が必要かは明確でした。また FloatingRateCouponクラスは Instrumentクラスより多くのインターフェースを備えていました (訳注:Fixingの計算に必要な情報を、具体的に持っていた)。従って、Pricing Engineクラスで使った Argument と Result クラスによる引数と返値の抽象化を避ける事が出来ました。
最終的に、多様な変動金利クーポンのレート計算の為に設計された FloatingRateCouponPricerクラス (訳注:Strategy Patternの中で、実際の計算の動作を委託されたオブジェクト。Instrumentが使うPricingEngineに相当) の定義を下記 Listing 4.5 に示します。何種類かの‘金利’を返すメソッドが (純粋仮想関数として) 宣言されています。swapletRate( )メソッドは、コンベクシティや倍率やスプレッドといった調整を行った後に、変動金利クーポンの利率を返します。capletRate( ) は、金利インデックスの fixing の際、Capで調整された利率を返します。floorletRate( )メソッドは、同様に Floor調整後の利率を返します。(注:このクラスは、他にもメソッドを宣言していますが、下記 Listingでは省略されています。)
Listing 4.5: Sketch of the FloatingRateCouponPricer class
class FloatingRateCouponPricer: public virtual Observer, public virtual Observable {
public:
virtual ~FloatingRateCouponPricer();
virtual void initialize(const FloatingRateCoupon&) = 0;
virtual Rate swapletRate() const = 0;
virtual Rate capletRate(Rate effectiveCap) const = 0;
virtual Rate floorletRate(Rate effectiveFloor) const = 0;
// other methods
};
initialize( )メソッドは、FloatingRateCouponオブジェクトへの参照を引数として取り、それをメンバー変数として保持します。その参照を使って、Pricerの持つ各メソッドが必要とする情報で、Pricerのコンストラクター起動時には引数として取り込まれなかった FloatingRateCouponオブジェクトの情報を、取りだします。
FloatingRateCouponクラスは setPricer( )メソッドを定義しており、引数として取得した Pricerインスタンスをメンバー変数に保持します。(注:実際の実装は、そんなに単純ではありませんが、ここでは詳細は飛ばします。) rate( )メソッドは、保持されている Pricerインスタンスを、自分自身のポインターを渡して初期化し (訳注:上記コードにあるinitialize( )に参照を渡して起動すること)、そのPricerによって計算された変動金利を返します。
このコードを見て、Pricerの初期化を、setPricer( )ではなくrate( )メソッドの中で行われている事に気がつかれたかも知れません。なぜこうしたかと言うと、同じPricerを使って、別の変動金利クーポンの計算を行う可能性があるからです。従って、Pricerに計算をさせる度に、呼び出し元のCouponインスタンスを保持する事を明確にするための動作です。そのPricerが行った前回の計算では、別のCouponインスタンスの参照を保持していたかも知れませんので。
もちろん、この実装方法が十分納得のいく方法ではありません (注:さらに、この方法は、並列処理を妨げています。 並列処理は、2年ほど前からますます重要になってきています。しかし現段階では、同じ Pricer を複数の Couponオブジェクトに渡して、同時に計算させる事はできません。) Pricerで定義するメソッドを以下のようにして、initialize( )メソッドを何度も呼び出すのを避けた方が良かったかも知れません。
Rate swapletRate(const FloatingRateCoupon& coupon);
ここでも、オブジェクトモデル設計の最適化が未熟であったことを認めざるを得ません。swapletRate( )メソッドや類似のメソッドが連続して呼ばれたとき (例えば、Floor付きのクーポンの計算をするような場合)、事前に行う初期化のメソッドが、それぞれのクーポン計算の際に必要な事前の計算を行う可能性があったので、その可能性を勘案してオブジェクトモデルの設計を行ったのです。その結果、ほとんどの Pricer において、いくつかの必要な計算を initialize( )メソッドの中で行うことになりました。しかし、私見では、金利を計算するのにテキサス2ステップ(訳注:アメリカのカントリーウェスタンのリズムをベースにした、ダンスステップ。) をすることを正当化するには十分ではないと思います。(訳注:金利計算のステップを2段階に分けてしまったのは、設計として最適では無かった。)
この項の最後に、発想を転換するようなアイデアを差し上げます。もし、独自の変動金利クーポンクラスの実装をしたいけれども複雑な Pricer の仕組みを避けたいのであれば、FloatingRateCouponクラスから派生クラスを作り、そこでrate( )メソッドを Overrideして Pricer を使わずに計算を直接行わせる方法もあります。Pricerは後から必要に応じて加えることも出来ます。
<ライセンス表示>
QuantLibのソースコードを使う場合は、ライセンス表示とDisclaimerの表示が義務付けられているので、添付します。 ライセンス