我正在尝试实施Longstaff和Scwartz算法,这种算法本质上是一种最小二乘法,可以为美国期权定价。我使用Matlab代码作为参考,用C ++编程。
到目前为止,我所做的是首先设置名为
的时间步变量 dt = T/N
其中T
是到期时间,N
是时间步数。
然后是时间向量(在Matlab中表示为t = 0:dt:T
)。我在C ++中为此创建了一个函数,该函数发布在下面:
VectorXd range(double min, double max, int N){
VectorXd m(N + 1);
double delta = (max-min)/N;
for(int i = 0; i <= N; i++){
m(i) = min + i*delta;
}
return m;
}
然后我必须生成一个生成一组正态分布随机数的向量。在Matlab中,该函数称为z = randn(M/2,1)
,其中M
是路径数。在C ++中,我为此创建了一个函数,如下所示:
MatrixXd generateGaussianNoise(int n, int m){
MatrixXd M(n,m);
VectorXd V(n);
normal_distribution<double> nd(0.0, 1.0);
random_device rd;
mt19937 gen(rd());
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
M(i,j) = nd(gen);
}
}
return M;
}
现在我们必须创建另一个名为w = (r-sigma^2/2)*T + sigma*sqrt(T)*[z;z]
的向量。在此之前,我必须创建另一个C ++函数来处理Matlab语法[z;z]
,如下所示:
MatrixXd generateMatrix(MatrixXd z){
MatrixXd Dm(2*z.rows(),z.cols());
Dm << z, -z;
return Dm;
}
然后我可以用我在下面创建的另一个C ++函数创建w
变量:
MatrixXd generateWMatrix(double r, double sigma, double T, MatrixXd Dm){
MatrixXd w(Dm.rows(),Dm.cols());
for(int i = 0; i < Dm.rows(); i++){
for(int j = 0; j < Dm.cols(); j++){
w(i,j) = (r - pow(sigma,2)/2)*T + sigma*sqrt(T)*Dm(i,j);
}
}
return w;
}
现在我们必须创建一个新变量S = S0*exp(w)
,其中S0
是初始资产价格。我们可以在下面列出的for循环中执行此操作:
MatrixXd S(w.rows(),w.cols());
for(int i = 0; i < w.rows(); i++){
for(int j = 0; j < w.cols(); j++){
S(i,j) = exp(w(i,j));
}
}
现在,这件事对我来说有点难看,这篇文章的要点。我们必须为实际算法执行后向for循环。我将提供Matlab代码的开头部分以供参考,这是我在C ++中出错的地方:
for i = N:-1:2
z = randn(M/2,1);
w = t(i)*w/(t(i+1)) + sigma*sqrt(dt*t(i)/(t(i+1)))*[z;z];
现在在C ++中,我尝试做的是:
for(int i = N; i >= 2; i--){
z(i) = generateGaussianNoise(M/2, 1);
zz(i) = generateMatrix(z);
w(i) = t(i)*w(i)/(t(i+1)) + sigma*sqrt(dt*t(i)/(t(i+1)))*zz(i);
}
虽然z(i)
出现以下错误:
cannot convert 'Eigen::MatrixXd {aka Eigen::Matrix<double, -1, -1>}' to
'Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka
double}' in assignment
和zz(i)
我收到以下错误:
cannot convert 'Eigen::MatrixXd {aka Eigen::Matrix<double, -1, -1>}' to
'Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka double}' in assignment
和w(i)
我收到以下错误:
invalid arguments '
Candidates are:
double sqrt(double)
float sqrt(float)
long double sqrt(long double)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type sqrt(#0)
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_sqrt_op<#0::Scalar>,const #0> sqrt(const Eigen::ArrayBase<#0> &)
float sqrt(float)
long double sqrt(long double)
std::complex<#0> sqrt(const std::complex<#0> &)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type
我不确定在上面的后者我做错了什么或这些错误意味着什么。当然我试过谷歌搜索他们看看问题是什么,但我没有得到任何有用的信息。为了完整起见,我将在下面发布我的全部代码:
#include <iostream>
#include <cmath>
#include <math.h>
#include <limits>
#include <algorithm>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <random>
using namespace Eigen;
using namespace std;
double LaguerreExplicit(int R, double x); // Generates the (weighted) laguerre value
double payoff_Call(double S, double K); // Pay off of a call option
MatrixXd generateGaussianNoise(int n, int m); // Generates Normally distributed random numbers
double LSM(double T, double r, double sigma, double K, double S0, int N, int M, int R);
// T Expiration time
// r Riskless interest rate
// sigma Volatility
// K Strike price
// S0 Initial asset price
// N Number of time steps
// M Number of paths
// R Number of basis functions
VectorXd range(double min, double max, int N);
MatrixXd generateMatrix(MatrixXd z);
MatrixXd generateWMatrix(double r, double sigma, double T, MatrixXd z);
int main(){
double r = 0.06;
double sigma = 0.25;
int T = 1.0;
int N = 2;
double dt = T/N;
VectorXd t = range(0.0, T, N);
MatrixXd result1 = generateGaussianNoise(2,1);
MatrixXd result2 = generateMatrix(result1);
MatrixXd w = generateWMatrix(r,sigma,T, result2);
}
double payoff_Call(double S, double K){
double payoff;
if((S - K) > 0)
{
payoff = S - K;
}else
{
payoff = 0.0;
}
return payoff;
}
double LaguerreExplicit(int R, double x){
double value;
if(R==0)
{
value = 1;
}
else if(R==1)
{
value = 0.5*(pow(x,2) - 4.0*x + 2);
}
else if(R==3)
{
value = (1.0/6.0)*(-1*pow(x,3) + 9*pow(x,2) - 18*x + 6);
}
else if(R==4)
{
value = (1.0/24.0)*(pow(x,4) - 16*pow(x,3) + 72*pow(x,2) - 96*x + 24);
}
else if(R==5)
{
value = (1.0/120.0)*(-1*pow(x,5) + 25*pow(x,4) - 200*pow(x,3) + 600*pow(x,2) - 600*x + 120);
}
else if (R==6)
{
value = (1.0/720.0)*(pow(x,6) - 36*pow(x,5) + 450*pow(x,4) - 2400*pow(x,3) + 5400*pow(x,2) - 4320*x + 720);
}
else{
cout << "Error!, R is out of range" << endl;
value = 0;
}
value = exp(-0.5*x)*value; // Weighted used in Longstaff-Scwartz
return value;
}
MatrixXd generateGaussianNoise(int n, int m){
MatrixXd M(n,m);
normal_distribution<double> nd(0.0, 1.0);
random_device rd;
mt19937 gen(rd());
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
M(i,j) = nd(gen);
}
}
return M;
}
VectorXd range(double min, double max, int N){
VectorXd m(N + 1);
double delta = (max-min)/N;
for(int i = 0; i <= N; i++){
m(i) = min + i*delta;
}
return m;
}
MatrixXd generateMatrix(MatrixXd z){
MatrixXd Dm(2*z.rows(),z.cols());
Dm << z, -z;
return Dm;
}
MatrixXd generateWMatrix(double r, double sigma, double T, MatrixXd Dm){
MatrixXd w(Dm.rows(),Dm.cols());
for(int i = 0; i < Dm.rows(); i++){
for(int j = 0; j < Dm.cols(); j++){
w(i,j) = (r - pow(sigma,2)/2)*T + sigma*sqrt(T)*Dm(i,j);
}
}
return w;
}
double LSM(double T, double r, double sigma, double K, double S0, int N, int M, int R){
double dt = T/N;
VectorXd t = range(0,T,N);
MatrixXd z = generateGaussianNoise(M/2, 1);
MatrixXd zz = generateMatrix(z); // Need to do this for the [z;-z]
MatrixXd w = generateWMatrix(r, sigma, T, zz);
MatrixXd S(w.rows(),w.cols());
for(int i = 0; i < w.rows(); i++){
for(int j = 0; j < w.cols(); j++){
S(i,j) = exp(w(i,j));
}
}
MatrixXd P(S.rows(), S.cols());
MatrixXd z_new(M,1);
for(int i = N; i >= 2; i--){
z_new.topRows(M/2) = generateGaussianNoise(M/2,1);
z_new.bottomRows(M/2) = -z_new.topRows(M/2);
w = t(i-1)*w/t(i) + sigma*sqrt((dt*t(i-1)/t(i)))*z_new;
}
return 0;
}
更新
我添加了新的完整代码,但我仍然在名为exp()
的函数中的sqrt()
和double LSM(double T, double r, double sigma, double K, double S0, int N, int M, int R)
中出现了一些错误我试图谷歌我能做什么,但我没有想法如何修复以下错误消息:
exp()
我收到此消息:
Invalid arguments '
Candidates are:
double exp(double)
float exp(float)
long double exp(long double)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type exp(#0)
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_exp_op<#0::Scalar>,const #0> exp(const Eigen::ArrayBase<#0> &)
float exp(float)
long double exp(long double)
std::complex<#0> exp(const std::complex<#0> &)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type
对于sqrt()
我收到此消息:
Invalid arguments '
Candidates are:
double sqrt(double)
float sqrt(float)
long double sqrt(long double)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type sqrt(#0)
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_sqrt_op<#0::Scalar>,const #0> sqrt(const Eigen::ArrayBase<#0> &)
float sqrt(float)
long double sqrt(long double)
std::complex<#0> sqrt(const std::complex<#0> &)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type
这是我试图在Eigen中实现的Matlab代码。我将在Matlab代码中发布我已经成功完成的部分以及我很难实现的部分:
function u = LSM(T,r,sigma,K,S0,N,M,k)
% T Expiration time
% r Riskless interest rate
% sigma Volatility
% K Strike price
% S0 Initial asset price
% N Number of time steps
% M Number of paths
% k Number of basis functions
dt = T/N; % Time steps
t = 0:dt:T; % Time vector
z = randn(M/2,1);
w = (r-sigmaˆ2/2)*T + sigma*sqrt(T)*[z;-z];
S = S0*exp(w);
P = max(K-S,0); % Payoff at time T
for i = N:-1:2
z = randn(M/2,1);
w = t(i)*w/t(i+1) + sigma*sqrt(dt*t(i)/t(i+1))*[z;-z];
for循环之后的所有东西都是我在努力的地方......
答案 0 :(得分:2)
以下行没有意义:
zz(i) = generateMatrix(z);
zz(i)
是double&
,而generateMatrix
则返回MatrixXd
。与w(i)
相同。
答案 1 :(得分:1)
你几乎可以逐字翻译这个Matlab代码
for i = N:-1:2
z = randn(M/2,1);
w = t(i)*w/t(i+1) + sigma*sqrt(dt*t(i)/t(i+1))*[z;-z];
end
到Eigen(假设循环外的所有东西都有效):
MatrixXd zz(M,1); // allocate space for [z; -z] only once
for(int i=N; i>=2; --i){
zz.topRows(M/2) = generateGaussianNoise(M/2,1);
zz.bottomRows(M/2) = -zz.topRows(M/2);
w = t(i-1)*w/t(i) + sigma*std::sqrt(dt*t(i-1)/t(i))*zz;
}
基本上,唯一的区别是Matlab开始索引为1而Eigen从0开始。
在Eigen中连接[z;-z]
也不可能“内联”,但我想知道为什么你为z
和-z
做同样的计算......