胡扯OO和泛型编程

看了几天Introduction to C++ for Financial Engineers,结合C++ Primer,胡扯几句如何在金融工程中应用OO和generic Programming

首先,纵使是最简单的函数也可以用类的方法加以实现。比如我们定义了一个Max函数,用于比较两个数的大小,但是我们也可以定义一个具有两个数据成员的类,再定义该类的成员函数max。如果原本的函数是函数模板,那么我们就可以定义对应的类模板。但是,这时候使用类显然是画蛇添足,使用OO过度。使用函数模板然后将其声明为inline或者在C中直接使用宏定义可能是最好的解决方法。

思考如何在金融工程中应用OO和generic Programming时,我们可以先考虑是不是直接用函数而不用定义类,也就是不通过类的实例调用成员函数,而直接使用函数解决这一问题,这种完全不使用OO范式很多时候也是可行的。再考虑是不是用定义含有函数指针成员的类来解决。最后考虑是不是需要设计比较复杂的继承层次,使用抽象类和纯虚函数来解决。以下面几个例子来说明。

Q1.我们要实现计算不同交易策略的收益。比如Call的收益是max(S_T-K,0),这一系列交易策略包括Bullspread,BearSpread,BoxSpread等等。

S1.我们分别定义这些交易策略收益的函数,然后将其放入名为Payoff的命名空间。如果这些收益的函数具有相同的返回类型和形参表,以函数类型为double,形参表中都是两个double类型的形参为例,这时我们可以再定义一个泛型函数payoff,

double payoff(double S,double K,double(*myF)(double s,double k))
{
	return (*myF)(S,K);
}

我们可以通过传递S,K以及交易策略的函数名给泛型函数payoff来计算不同交易策略的收益。

S2.在这些收益的函数具有相同的返回类型和形参表,也就是可以使用泛型函数的情形时,我们也可以直接定义包括函数形参数据成员的类来解决这一问题。我们定义名为Payoff的具体类,然后定义其成员函数payoff用来计算不同交易策略的时候,

class Payoff{
private:
	double S;
	double K;
	double(*myF)(double s,double k);
public:
double payoff(double S,double K,double(*myF)(double s,double k)) const
{
	return (*myF)(S,K);
}
};


这种方法在我们设计非线性方程求根问题时也用到了,因为对于非线性方程求根不管是直接使用函数还是封装成类,其形参表中都有一个形参是是函数指针。后面会再提到。

至于我们希望传递给该类型实例的收益函数,我们还是像之前一样放在一个namespace中。

S3.利用继承,抽象类和纯虚函数加以实现,首先定义一个Payoff的抽象类,该类型没有数据成员,其成员函数包含一个纯虚函数payoff

class Payoff{
public:
	virtual double payoff() const=0;
};
class CallPayoff: public Payoff{
private:
	duoble S;
	double K;
public:
	double payoff();
}

Payoff抽象类中payoff这一纯虚函数存在的意义就是为了让派生类来继承,为后代类提供可以覆盖的接口。回顾接口继承和实现继承。然后每种交易策略都是派生类,分别定义自己的payoff版本。

4.Strategy Pattern,再定义一个类,其包含的数据成员是指向S3中Payoff类的指针。


Q2.求解非线性方程的根f(x)=0

S1.定义Solver函数,我们求解非线性方程的根时,Solver函数的形参可以是迭代次数上限int MAXLIMIT,容忍度double tol=0.00001,以及函数指针,即f(.)

由于求解非线性方程有不同的方法,我们可以分别定义这些方法的解,每种函数的形参可能不同,比如二分法不需要猜测初始值但是需要上下界。而Newton,Steffenson等方法都要初始值。然后把这些函数放在一个namespace中。对于具有相同形参和返回类型的求解函数,我们还是可以利用泛型函数。

S2.定义一个NonlinearSolver类,其数据成员就是上面提到的int MAXLIMIT,容忍度double tol=0.00001,以及函数指针,即f(.)。其包含成员函数solver,但是我们将solver声明为纯虚函数,为后面各种具体方法的派生类继承该函数提供了相同的接口,具体的派生类可以定义各自的特有的数据成员和成员函数。


什么时候使用非虚函数,非纯虚函数,纯虚函数,什么时候使用接口继承,实现继承,这些问题在设计继承层次时是十分重要的。纯虚函数是为了仅仅给派生类提供可覆盖的接口,而非纯虚函数不仅为派生类继承了该函数的接口还有缺省实现,而非虚函数则为了让派生类继承接口和一份强制性实现。


Q3.期权定价,这问题简直是蛋碎了,首先有不同种类的期权,对每类期权有不同的定价模型,比如B-S,SV,SVJ,对于各种定价模型有不同的模拟方法。如何设计?


Q4.交易策略,我们可以类似于Websim的方法,

class TradingStrategy{
private:
	Matrix price; //close,open,high,low	
public:
	virtual Matrix DailyWeight()=0; //为派生类提供可以覆盖的接口
};
class PriceVolumeStrategy: public TradingStrategy{
private:
	Matrix volume;
public:
	Matrix DailyWeight() const{
	...//
	}
};

-----------------------------------------------------------------华丽分割线2014年10月16日--------------------------------------------------------------------------------------

当今天看到function object之后,之前的那些设计又显得格外傻叉了,对于function object的使用可以见链接QuantStart网站的学习笔记——C++ Inplementation

下面给一个Payoff使用function object实现的版本。

//Payoff.h
class Payoff
{
public:
	Payoff(){}; //constructor千万不要遗漏了{}
	virtual double operator()(double K, double S) = 0;
};


//用类来封装一个函数功能
class Call_payoff : public Payoff
{
public:
	Call_payoff(){};
	virtual double operator()(double K, double S)
	{	
		return S - K > 0 ? S - K : 0;
	}
};


class Put_payoff : public Payoff
{
public:
	Put_payoff(){};
	virtual double operator()(double K, double S)
	{
		return K - S > 0 ? K - S : 0;
	}
};
//main.cpp
#include 
#include "Payoff.h"

using namespace std;

double payoff(double K, double S, Payoff *ptr)
{
	return (*ptr)(K, S);
}


int main()
{
	double K = 35.0;
	double S = 40.0;


	Payoff *pCall = new Call_payoff(); //经类实例化不同的函数对象,通过函数对象来实现函数的功能
	Payoff *pPut = new Put_payoff();


	std::cout << "Call Option Payoff: " << payoff(K, S, pCall) << std::endl;
	std::cout << "Put Option Payoff: " << payoff(K, S, pPut) << std::endl;


	return 0;
}




你可能感兴趣的:(C++)