Contents

QuantLib设计模式之:工厂模式

问题

在给金融产品定价时,QuantLib底层的对象输入的参数较多,例如欧式期权需要输入:标的资产的价格、执行价格、波动率、到期日以及期权类型等,众多的输入参数,给用户带来的诸多的不便,比如输入参数的顺序问题,虽然可以使用C++的默认参数的特性,对于部分参数设置默认值,但是设置的默认参数需要放置在函数参数列表的最后。

下面是底层MyOption的类的定义,testingFactory1是如何使用MyOption的函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class MyOption{
public:
 enum Type{Call=1,Put=-1,None=0};
 
 MyOption(Time mat, Volatility vol, Type type, Real spot,
  Rate forRate, Rate domRate, Real strike):mat_(mat),vol_(vol),
  type_(type),spot_(spot),forRate_(forRate),domRate_(domRate),
  strike_(strike){
 }

 Time getMat()const{return mat_;}
 Real getSpot()const{return spot_;}
 Real getStrike()const{return strike_;}
 
private:
 Time mat_; Volatility vol_;
 Real spot_,strike_;
 Rate forRate_,domRate_;
 Type type_;
};

void testingFactory1(){

 Real spot=100.0, strike=110.0;
 Rate rd=0.03, rf=0.01;
 Volatility vol=0.20;
 Time mat=1.0;
 MyOption::Type type(MyOption::Call);
 
 MyOption option(mat,vol,type,spot,rf,rd,strike);

 std::cout << "Mat:"    << option.getMat() << std::endl;
 std::cout << "Spot:"   << option.getSpot() << std::endl;
 std::cout << "Strike:" << option.getStrike() << std::endl;
}

上述测试结果如下:

1
2
3
Mat:1
Spot:100
Strike:110

工厂(Factory)模式

QuantLib中的工厂模式解决了这些问题,通过定义创建对的接口,封装了对象的创建,如本示例中,定义MakeMyOption类用来创建MyOption的对象,其类的代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class MakeMyOption{
public:

 MakeMyOption(): mat_(Null<Real>()),vol_(Null<Real>()),spot_(Null<Real>()),
     strike_(Null<Real>()),forRate_(Null<Real>()), 
     domRate_(Null<Real>()),type_(MyOption::None){
 }
 MakeMyOption& withMat(const double& mat){
  mat_=mat;
  return *this;
 }
 MakeMyOption& withVol(const double& vol){
  vol_=vol;
  return *this;
 }
 MakeMyOption& withSpot(const double& spot){
  spot_=spot;
  return *this;
 }
 MakeMyOption& withStrike(const double& strike){
  strike_=strike;
  return *this;
 }
 MakeMyOption& withForRate(const double& forRate){
  forRate_=forRate;
  return *this;
 }
 MakeMyOption& withDomRate(const double& domRate){
  domRate_=domRate;
  return *this;
 }
 MakeMyOption& withType(const MyOption::Type& type){
  type_=type;
  return *this;
 }
 operator MyOption()const{
  QL_REQUIRE(mat_!=Null<Real>(),"Maturity not set!");
  // Check other parameters too
  QL_REQUIRE(type_!=MyOption::None,"Option type not set!");
  return MyOption(mat_,vol_,type_,spot_,forRate_,domRate_,strike_);
 }

 Time getMat()const{return mat_;}
 Real getSpot()const{return spot_;}
 Real getStrike()const{return strike_;}
 
private:
 Time mat_; 
 Volatility vol_;
 Real spot_,strike_;
 Rate forRate_,domRate_;
 MyOption::Type type_;
};

在MakeMyOption的类中,首先,构造函数无限输入期权的参数,同时提供了设置参数的的接口,其次,类中重载了"()“运算符,通过重载将MakeMyOption对象转化为原来的MyOption对象,并且在重载函数中,针对用户没有定义的参数进行了检查,如果使用者没有输入参数,程序会给出报错,我们可以通过下面的代码创建对象:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
void testingFactory2(){

 Real spot=100.0, strike=110.0;
 Rate rd=0.03, rf=0.01;
 Volatility vol=0.20;
 Time mat=1.0;
 MyOption::Type type(MyOption::Call);

 MyOption optionMade=MakeMyOption()
   .withType(type)
   .withMat(mat)
   .withSpot(spot)
   .withForRate(rf)
   .withStrike(strike)
   .withVol(vol)
   .withDomRate(rd);

 std::cout << "Mat Made:"    << optionMade.getMat() << std::endl;
 std::cout << "Spot Made:" << optionMade.getSpot() << std::endl;
 std::cout << "Strike Made:" << optionMade.getStrike() << std::endl;

}

上述代码的输出结果为:

1
2
3
Mat Made:1
Spot Made:100
Strike Made:110