c++ でバニラオプションの価格をモンテカルロで算出

今日で6月も終わり、1年の半分が終了…。

ということで、前々からやろうやろうと思いつつやっていなかったオプション価格をモンテカルロ(MC)で算出、ということをやってみた。超簡単、と思ったけど基本をすっとばしてきた自分にとっては色々と勉強になった。

0.準備
オプション価格は5変数(原資産価格、Vol、期間、ストライク、金利)からなるのでこれらの変数が必要。あと、MCでは正規乱数を発生させることが必要。

変数は適当にセッティングするとして、乱数生成は実はかなり奥が深い。最も基本的(と思われる)BoxMuller法を使ったが、簡単なのでは12個の一様乱数の和から6をひく、というものがあったり、他に基本的なのではメルセンヌツイスターなんかがある。

1.手順
例によって株価が幾何ブラウンとすると、St=S*exp{(μ-0.5*sigma^2)t+Nrand()*sigma*sqrt(t)}となる。平均的にはドリフトμに従って成長するが、ランダム項でその周りを少し動く。その部分に正規乱数を用いる。

で、株価のパスを作ってStの株価がわかったら、payoffはmax(St-K,0)なのでそれらをパスの数だけ足し合わせる。最後はパス数で割れば、満期におけるオプション価値がわかる。それを割り引けば終了。

2.比較
計算結果をWolframでの計算結果と比較した。大体いい感じ。

3.メモ
・一様乱数生成方法
正規乱数の生成にはrand()によって発生させた一様乱数を用いたが、そもそもその一様乱数の精度がうんぬんという話もある。のでそこもポイント。

・正規乱数生成方法
メルセンヌツイスター、ボックスコックス変換も知りたい。

4.書いたやつ
長いし汚いけど一応。めんどいので金利は0、pathは10,000。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <math.h>

int main(){

	double S, sigma, r, k, a;
	double x;
	double pathnum;
	double price, strike;
	double kakaku[10000];
	double T;

	std::cout << "5変数からオプション価格を出します\n";
	std::cout << "Sは?\n";
	std::cin >> S;
	std::cout << "Volは?\n";
	std::cin >> sigma;
	std::cout << "満期は?\n";
	std::cin >> T;
	std::cout << "ストライクは?\n";
	std::cin >> strike;

	pathnum = 10000;
	price =0.0;
	r =0.0;

	//変数の宣言
	double Nrand;
	double Urand_1, Urand_2;
	double Nrand_1, Nrand_2;
	int sw;
	static const double PI = 6*asin(0.5);
	double N[10000];

	sw=0;
	Nrand_1 =0, Nrand_2 = 0;

	//一様乱数からボックスミューラーで正規分布・正規乱数を生成
	for (int i=0; i<pathnum; i++){
	if(sw==0){
		sw=1;
		Urand_1 = rand()/32768.0;
		Urand_2 = rand()/32768.0;
		Nrand_1 = sqrt(-2*log(Urand_1))*cos(2*PI*Urand_2);
		Nrand_2 = sqrt(-2*log(Urand_1))*sin(2*PI*Urand_2);
		Nrand = Nrand_1;
	}
	else{
		sw=0;
		Nrand = Nrand_2;
	}
	N[i] = Nrand;
	}

	//モンテカルロで株価のパス発生・オプション価値を計算
	for (int k =0; k<pathnum; k++){
		kakaku[k] = S*exp((-0.5*sigma*sigma*T)+sigma*N[k]*sqrt(T));
		if ( kakaku[k] >= strike){
			price += kakaku[k] - strike;
		}
	}

	//オプション価値アウトプット
	price = price/pathnum;
	std::cout << price << std::endl;
	
	return 0;
}