(修正:2026/4/2) showCurveDate関数 という関数を showCvDT(cvOBJ, ixOBJ=None)へ変更
$\quad$
今後しばらく、通貨スワップを含めたスワップ関連の記事を複数回 書く予定。
今回は「3ヶ月Tiborを変動金利とする金利スワップをツーカーブで評価する」という、いたって基本的な内容。拙著「Pythonで学ぶ債券·金利デリバティブ」(以下 テキスト)では 3.4節でこの内容を説明したが、テキスト図3.21 (p.107)はトイモデルで説明したため、この記事で現実のイールドカーブに対するコード例を示す。
ファイナンス実務で「ツーカーブ」は最も基本的な内容であるにも関わらず、多くのファイナンスのテキストではほとんど説明が無い。その理由は複雑な計算のためかと考えるが、QuantLibを使えば、驚くほど簡単に正しい計算が可能となる。
記事を読む注意点を2つ挙げておく。
-
これまでの記事で計算した数値やテキストの数値例は いずれも有料情報端末の計算結果とほぼ一致している
(ズレている場合,その旨を記載) -
記事中のコードはテキストのサポートページ より、取得可能。
(今回のコードはq08-Tibor3mSwap.ipynb)
詳細な説明の前に全体像を示しておく。
- 8-1節でツーカーブを構築
(基本的にはこの構築が全て) - 8-2節は構築したツーカーブでスワップを作成・評価
- ツーカーブのスワップオブジェクト作成はシングルカーブとほぼ同じ
- 8-3節はフォワードカーブのディスカウントファクターの意味と利用上の注意点へのメモ
8-1. Tonaカーブ、3ヶ月Tiborカーブの構築
初めにTonaカーブと3ヶ月Tiborカーブをツーカーブとして作成する。つまり、Tonaカーブがディスカウントカーブで、3ヶ月Tiborカーブがフォワードカーブ。(この辺りの用語はテキスト 図3.17(p.103)参照)
8-1-1. ツーカーブのデータ
$\qquad\qquad\qquad\qquad\quad$(図8-1:2026-01-20 JSCC Fixingデータ)
図8-1の上段は日本証券クリアリング機構 (以下 JSCC) が発表した2026年1月20日引けのFixingデータであり、下段はそれをQuantLib入力用にしたJupyter notebookのセルで、1行目のtnDATAがTonaカーブ用、10行目のtbDATAが3ヶ月Tiborカーブ用。(tnはTona, tbはTiborの略)
上下を見比べて、どのノードをQuantLib用データとしたかを確認しておく。
-
QuantLib用のデータは7年までのデータとした
-
FRAは
9M(6x9)までを使用し、10M, 11Mは未使用 -
もし、これらノードデータへの理解が不足していると思うなら、以下を参照
-
tnDATAは
テキスト図3.9 1番セル (p.91)を参照 -
tbDATAは第3回記事 図3-2のコード 3行目 参照
-
これらのデータ設定が終われば、図8-2のコード 3,4行目のようにmyUTILモジュールで定義したmakeTonaCurve関数、makeTiborCurve関数 を呼び出すことで2つのカーブ構築は完了する。

$\qquad$( 図8-2:Tonaカーブでディスカウントする3ヶ月Tiborカーブ )
8-1-2. makeTiborCurve関数
この4行目の makeTiborCurve関数 が今回の主役で、この関数がディスカウントカーブをTonaカーブとしたTibor3ヶ月の指標金利オブジェクトtbIXとカーブハンドルtbCvHDLを作成する。
オリジナルの makeTiborCurve関数 はテキスト図2.7 (p.47)でmyUTILモジュールに定義され、第3回記事でFRAを処理できるように修正した。
今回は指標金利のテナーを3ヶ月にし、別のカーブでディスカウントできるよう改良した。そのコードが図8-3となる。

$\qquad\qquad\qquad\quad$( 図8-3:myUTIL.pyのmakeTiborCurve関数 )
-
makeTiborCurve:オリジナル(テキスト図2.7)からの修正点は、引数( tbDATA,dCRV=tnCvHDL,iTNR=3 )を3つにしたこと-
第1引数
tbDATA:これまでと同様、カーブのノードデータ -
第2引数
dCRV=tnCvHDL:ツーカーブ時のディスカウントカーブのハンドルを指定(dCRVはdiscount Curveの略) -
第3引数
iTNR=3:指標金利テナーの月数 (この例では3ヶ月) を指定(iTNRはindex tenorの略)
-
-
第2, 第3の引数を使い、図8-3の四角で囲った行で、処理を分岐させた
-
109行~112行:指標金利indexを
iTNRで指定されたテナーで作成 -
119行~122行:
dCRV=tnCvHDLが指定されると、119, 120行目の引数でヘルパーを作成- Tiborカーブは120行目の最後の引数
dCRVでディスカウントされる - このヘルパーの引数の説明は
テキスト図3.19の7行目 (p.105)参照
- Tiborカーブは120行目の最後の引数
-
-
117行:
knd=fraは第3回記事 図3-1 で追加したFRAを処理させるヘルパー
8-2. ツーカーブでのTibor3ヶ月 スワップ評価
図8-1では、Tibor3ヶ月の5年金利は2.09% (=1.6275%+46.25bp)となっている。この固定金利 cpnRT=2.09%を払い、図8-2の4行目で作成したTibor3ヶ月tbIXを受ける5年スワップが図8-4。
出力結果のスワップNPVtbSwOBJ.NPVは当然 ゼロとなっていて、正しいスワップ評価がツーカーブで行われている。
$\qquad\qquad\qquad\quad$( 図8-4:固定2.095 vs Tibor3ヶ月 スワップ )
ここでシングルカーブのTiborスワップを書いたコードテキスト図2.8の17行目 (p.48)とこの図8-4を比較し、次の各点を確認しよう。
-
両図の最も大きな相違点は9行目の
DiscountingSwapEngine(tnCvHDL)でエンジン設定に使われるカーブ、つまりディスカウントカーブ、はTonaカーブハンドルのtnCvHDL- シングルカーブのテキスト図2.8 23行目でのディスカウントカーブはTiborカーブ
tbCrvHDL
- シングルカーブのテキスト図2.8 23行目でのディスカウントカーブはTiborカーブ
-
次に重要なのが、図8-4の8行目
tbIX。このインデックスは図8-2で作成(makeTiborCurve関数経由)されるているが、ツーカーブで計算されるTibor3ヶ月の指標金利である- テキスト図2.8 22行目のインデックス
tbrIXは同図9行目でシングルカーブから作成されている
- テキスト図2.8 22行目のインデックス
-
マイナーな点として、図8-4の5行目は年2回の
pDfrqSA (旧pdFreqSA)、6行目は年4回のpDfrqQ (旧pdFreqQ)が指定され、2つのレグの利払頻度は異なっている
以上、テキストとの図の比較から導かれる結論は、スワップの評価において シングルカーブか、ツーカーブかはディスカウントのエンジン作成部分(9行目)のみとなる。その際、指標金利インデックスの作成がシングルカーブまたはツーカーブで行われたかに注意する。
8-3. フォワードカーブのディスカウントファクターの意味
最後にフォワードカーブのディスカウントファクター(以下 DF)について説明し、利用する際の注意点を記す。
まず、フォワードカーブのDF つまり、図8-2の3mTiborのDF列に表示されているディスカウントファクターの計算法はテキストp.103 (2度目のブートストラップ)節で説明した。その説明を多少 補足しておく。
-
テキストp.103では「2度目のブートストラップとして、$f_{tn}$を算出」と書いた
-
これには続きがあり、「求めた$f_{tn}$を基にフォワードカーブのDFを逆算し」、図8-2の3mTiborのDF列として表示している
(この部分は著者の現在の理解となり、C++コードを確認した訳ではない) -
有料情報端末が表示する3mTiborのDFもQuantLibとほぼ同じ数値であり、「フォワードカーブのDF」のスタンダードとなっている
以上をまとめると、2度のブートストラップによって、
-
Tonaカーブで1度、Tiborカーブでもう1度ブートストラップが行われ
-
1度目はディスカウントカーブのDFを計算
-
2度目は変動金利インデックスと同じテナーのフォワードレートを計算
-
このフォワードレートをディスカウントファクターに換算し、フォワードカーブのDFとして表示
となる。
この節を書いた理由は、「フォワードカーブのDFは何のために存在するのか?」という疑問に答えるため。結論を先に言えば、「市場の習慣として、カーブがあれば、DFを見たくなるのが人情」あたりが答えであろう。
つまり、2度目のブートストラップはフォワードレートの算出が目的であり、このDFは本来不要で、かなり誤解を招くDFとなっている。この点を以下で例示しよう。

$\qquad\qquad\qquad\quad$( 図8-5:<上> Tibor3ヶ月スワップの変動レグCF
$\qquad\qquad\qquad\qquad\quad\quad$ <下> フォワードレートの手計算$\qquad$)
図8-5は2つのセルのスクショであり、上セルはswapCashFlow関数からの出力、下セルはフォワードレートを手計算した。
-
上セルの
swapCashFlow関数への説明はテキスト図2.11(p.55)を参照- 2つ目の
dfDSP(dfL1,5)はswapCashFlow関数で作られた変動レグCFのデータフレームdfL1の頭とシッポを5行で表示する関数- 関数のコードは図8-7 下段の40行目 を参照
- 引数はデータフレーム名
dfL1と表示したい行数5
- 2つ目の
-
まず、DF列に表示されたディスカウントファクターは図8-2で作成されたDFと一致している点を確認しよう
- 例えば、index20の
0.90067906は図8-2のindex13と等しい
- 例えば、index20の
-
次に上セルの
rate列に表示されたフォワードレートと、下セルの手計算から出力されたnumpy配列が完全に一致していることを確認しよう-
下セルのフォワードレートの計算式は
テキストp.65 式(2.6)を参照 -
2行目
DF.shift(1)はPandasでよく使うテクニックの1つで、1行前のDFの値を参照する
-
-
この手計算から、先ほど記した「2度目のブートストラップで$f_{tn}$が算出され、フォワードカーブのDFを$f_{tn}$から逆算した」と考えた
筆者のこの考察よりも、上記比較から「フォワードカーブのDFを使うと、フォワードカーブの指標金利と同じテナーのフォワードレートを式(2.6)で計算できる」ことを理解することが重要である。
ただし テキストp106でも指摘したが、フォワードカーブのDFから、異なるテナーのフォワードレートやスワップレートは算出できない。

$\qquad\qquad\qquad\quad$( 図8-6:5年スワップレートの手計算 )
図8-6でスワップレートをテキストp.67 式(2.15)で手計算したが、結果は2.08262%で、本来の2.09%を算出(復元)できていない。フォワードカーブのDFは使わないほう良いだろう。
まとめ
-
ツーカーブで金利スワップを評価する手順
-
ディスカウントカーブはシングルカーブで作成
-
フォワードカーブはツーカーブで作成
-
スワップオブジェクトはシングルカーブのものとほぼ同じ。ただし、割引エンジンにはディスカウントカーブを指定
-
-
フォワードカーブのDFを使うと、フォワードカーブの指標金利と同じテナーのフォワードレートのみ算出可能
(補足) myABBR, myUTIL 両モジュールへの修正点
ここではmyABBRとmyUTILの両モジュールに、新たに追加した関数や変数名などの修正した部分について、補足しておく。まず テキスト全体の変数名作成のルールを確認する。
-
テキスト p.23 脚注10でメモしたように、変数や関数名で使われる小文字のdfはデータフレームを、大文字のDFはディスカウントファクターを表している- このルールにより、変数の内容や関数から戻される値が「データフレーム関連なのか」、「ディスカウントファクター関連なのか」を類推しやすくなる
-
テキスト 1.3.8節 (p.23)に記したように、なるべく短く、小文字から始まるキャメル文字(ラクダ文字)を変数名とした- そして、変数名から型が連想できるようにしている
-
IX,OBJ,HDL,RTはインデックス、オブジェクト、ハンドル、レート -
DTはdateの日付型でtrdDTはtrade dateの略 -
DSはdaysの整数型でstlDSはsettle daysでTp2等の整数
-
- そして、変数名から型が連想できるようにしている
これらのルールに従って、テキストや記事のコードを書いている。
( 図8-2で使用した関数 : dfNodes, dfDSP )
では、図8-2に戻り、使用した関数について説明をする。
-
1行目
myUTIL:以前はmyUtilであったが、今後 myUTILのように後ろ4文字は大文字を使用- 小文字のままではエラーとなる点に注意
(サポートページのコードは大文字に修正済み)
- 小文字のままではエラーとなる点に注意
-
3行目
makeTonaCurve:変更は無く、説明はテキスト図3.1 (p.77)参照 -
6行目
dfNodes(tnCvOBJ,tnParRT,cmpd=CNT):イールドカーブで計算されるディスカウントファクターをパーレート等と共に表示させるために追加した関数でデータフレームを戻す- カーブオブジェクトのnodesメソッドから戻るリストはデータフレームへ変換して表示させることが多かったため、作成
(コードは図8-7 上段 31行目を参照) - 6行目ではこの関数によって、データフレーム
dfTNを作成 - 関数名
dfNodesは「カーブオブジェクトのnodesメソッドをデータフレームdf化させる」から命名 - この関数は4つの引数
(crvOBJ, parRT, isoFG=True, cmpd=CMP)を取る- 3番目の引数
isoFG=Trueはiso日付用のFlagで、nodesメソッドで戻される日付をISO型に変換するフラグ - 4番目の引数 cmpd=CMPはゼロレートの計算法を指定
- 円スワップはcmpd=CNT、ドルはcmpd=CMPでゼロレートを計算するようだが、定まった慣習はない
- 3番目の引数
- カーブオブジェクトのnodesメソッドから戻るリストはデータフレームへ変換して表示させることが多かったため、作成
-
6行目の右端にある関数
dfDSP(dfTN,5)は 長いデータフレームのdfTNの頭(head)とシッポ(tail)の5行を表示する- コードは図8-7 下段 40行目を参照
- 第3引数
fm=fmSによって、スタイル書式用変数を指定可能
- 第3引数
- 関数名は「データフレーム
dfをdisplayさせる」から命名
- コードは図8-7 下段 40行目を参照
( その他 新しく定義した関数等 : showCvDT, isoDT, qlDT )
この記事用にmyUTIL, myABBRの両モジュールに手を加えた。図8-7が新しく定義した5つの関数のコードと新しい変数名。各関数がどのように書かれているかは、コードを読もう。以下、若干の補足説明をしておく。
-
showCvDT関数:取引日、受渡日、インデックス名をプリントする関数- 使用例は図8-2の8行目で、
tradeDT:2026-01-20, ... Tibor3M Actual/365 (Fixed) )を最後の行で出力 - イールドカーブが正しく計算されているかを確認する際、取引日や受渡日は重要となるので作成した
- 使用例は図8-2の8行目で、
-
isoDT関数,qlDT関数:データフレームの日付列をISO型、QuantLib日付型へ変換する関数。データフレームの列名が引数となる
( 変数名の修正に関して )
本体のコードをより短く記述する為、変数名の一部を修正している。図8-7のmyABBRモジュールでは、スタイル書式用変数名を29行目fmSと34行目fmBに修正した。この変数名はformat Swap, format Bondから命名。(古い名称は37行目にあるfmtSCFとfmtFUT)
-
使用例は同じ図8-7のdfDSP関数の3番目の引数
fm=fmS -
ただし 37行目から判るように、古い変数名でもエラーは発生しない
myABBRモジュールでは他の変数名にも、同じような修正を行っている。
- 図8-3の109行~112行で使われた短縮形
pDfrqSA等の古い変数名はpdFreqSA - 図8-4の7,8行では
swPAY,spdRT0という短縮形を追加- この2つの短縮形は
ql.VanillaSwap.PayerとsprdRT=0.0に相当
- この2つの短縮形は
( myABBRとmyUTILを分ける基準 )
myABBRとmyUTILを分ける基準は単純か、複雑かであり、複雑な関数はmyUTILモジュールに記述。
-
複雑とは「QuantLibで作成されたファイナンス関係のオブジェクトが必要となる」ことを意味
( 備忘録 と ハイパーリンクできるエディタ )
両モジュールでは短縮形や特殊な関数を多数設定した。これらの関数等は使わなければ、すぐに忘れてしまう。 そんな時、myABBR.pyとmyUTIL.pyを見返せば、引数の入力法やコーディング例等を簡単に確認できる。
この確認の為、テキストp.7 脚注1に記したようにVS Code等のハイパーリンクできるPythonエディタの利用を強く勧める。
筆者はmyABBR.pyとmyUTIL.pyを備忘録として活用している。


