您好,欢迎来到知库网。
搜索
您的当前位置:首页quantlib入门(5)

quantlib入门(5)

来源:知库网


2009-12-20 22:16

QuantLib入门(五)金融工具(Instrument)框架

前面已经说过,QuantLib将所有的金融工具抽象出一个基类\"Instrument\",这在面向对象的设计里是一个很自然的想法:设计一个通用的接口,通过对这接口的调用,就可以实现对其任何子类的动态调用,这就是多态。但是现实中的金融工具非常繁杂,能抽象出来的公共接口非常有限,因此将接口限于其现值的返回和工具是否到期的判断,如下:

class Instrument

{

public:

virtual ~Instrument;

virutal Real NPV() const=0;

virtual Real errorEstimate() const=0;

virtual bool isExpired() const=0;

void setPricingEngine(const boost::shared_ptr&);

};

这是Instrument的一个简单的描述代码,而非真实代码。 由此Instrument类就派生出诸如债券、股票、互换、期权等等具体的金融工具。如下图:

图中我们可以看到由Instrument派生出了option,bond,swap等等具体的金融工具

子类。同时,我们注意到,Instrument类也是LazyObject类的子类。这个LazyObject类是什么呢?简单地说,LazyObject是一个模板类,作用是定义对缓存中的数据进行重新计算的框架,而将具体的计算细节留给了Instrument类(注意,这与engine不同)。这样的实现方式是使用了设计模式\"template method\",本文末尾将进行简单地介绍,现在只给出一个简单的描述代码(同样并非真实代码)。class LazyObject:public virtual Observer,

public virtual Observable

{

protected:

mutable bool calculated_;

virtual void performCalculations() const=0;

public:

void update(){ calculated_=false;}

virtual void calculate() const

{

if(!calculated_)

{

calculated_=true;

try

{

performCalculation();

}

catch(...)

{

calculated_=false;

throw;

}

}

}

};

LazyObject中,两个虚函数 performCalculations和 calculate都可以在子类中实现,以进行具体的计算工作。

由于这不是QuantLib结构相关的文章(但我确实参考并借鉴了文档Implementing QuantLib),在此就不深入了。在此提一下Observer和Observerable类。因为要对一个金融工具进行计算,需要有数据和计算数据的方法。LazyObject方法可以在诸如LazyObject中定义,那么数据呢?数据自然也要分离。在这分离出去的数据改变时,就需要通知定义了计算方法的类进行重新计算。这种通知机制,正是通过设计模式\"Observer\"来进行的。LazyObject继承自Observer和Observerable类,正是这种机制的实现。本文后面将会对这一设计模式进行简单的介绍。

有了LazyObject类之后,Instrument的实现就变成下面的样子:class Instrument:public LazyObject

{

...

...

...

};

下面看一个实例,是swap的定义代码,大家可以在ql/instruments/swap.hpp中找到(我已经把注释去掉)。

class Swap : public Instrument {

public:

class arguments;

class results;

class engine;

Swap(const Leg& firstLeg,

const Leg& secondLeg);

Swap(const std::vector& legs,

const std::vector& payer);

bool isExpired() const;

void setupArguments(PricingEngine::arguments*) const;

void fetchResults(const PricingEngine::results*) const;

Date startDate() const;

Date maturityDate() const;

Real legBPS(Size j) const {

QL_REQUIRE(jcalculate();

return legBPS_[j];

}

Real legNPV(Size j) const {

QL_REQUIRE(jcalculate();

return legNPV_[j];

}

const Leg& leg(Size j) const {

QL_REQUIRE(jreturn legs_[j];

}

protected:

Swap(Size legs);

void setupExpired() const;

std::vector legs_;

std::vector payer_;

mutable std::vector legNPV_;

mutable std::vector legBPS_;

};

大家可以看到,在类定义的开头,有三个公共类声明:class arguments;

class results;

class engine;

这是类的嵌套定义。利用这三个类,就可以实现向swap的计算传递参数、取得计算结果、传递计算引擎等功能。

至此,我们大概知道Instrument是如何工作的了:所有的金融工具都由Instruemnt类派生而来,Instrument类是LazyObject类的子类,LazyObject负责定义对缓存中的数据重新计算的框架,同时,LazyObject是Observer,Observable的子类,这使LazyObject及其子类具有“观察”数据源数据变化的能力。 那么,要自己实现一个新的金融工具,该如何做呢?大致有以下三个步骤:(1)将自身注册为数据源的Observer。这一步可以在构造函数内通过父类Observer的成员函数registerWith进行。一般来说数据源会作为构造函数的参数传入。比如Swap的构造函数就传入了CashFlow对象作为参数。

(2)实现Instrument类的接口,如NPV,isExpired等。

(3)如果新的金融工具类需要有其它的计算,则也要将这些计算方法实现。

自己实现新的金融工具并不复杂,具体的方法大家可以去读QuantLib的源代码。

虽然到目前为止,还没给大家介绍过一句实用的代码。因为我认为,只有深入了解一个事物的本质,才能更更好的将其加以利用。知其然,还要知其所以然。所以大家不要着急写出一个Hello world!程序。不过,如果你看过了前面几篇文章,现在去看QuantLib网站上那些example,应该都能看懂了。

===============================================

相关设计模式。

1、observer

这种模式定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。之所以不将这些相互依赖的对象设计成紧耦合的方式来维护一致性,是因为紧耦合的方式降低了对象的可重用性。

比如,一个文档编辑器,对一个数据序列可以用柱状图、饼状图来表示,当数据序列改变时,这两种图都要刷新,即两种图依赖于数据序列。并且,不只有柱状图、饼状图,还有曲线图、散点图等等,如果将图与数据设计成紧耦合的方式就很难再添加新的图形表现形式。而使用observer模式,则可使图与数据很好地分离,也很容易添加新的数据表现形式。

在这种设计模式中涉及以下的参与者: subject(目标):相当于上面提到的数据序列(更准确地说为数据序列对象提供一个公共接口),subject知道它有哪些观察者,当它改变时可以通知那些观察者。因此它要提供注册和删除观察者对象的接口。 observer(观察者):相当于上面提到的柱状、饼状图等数据表现形式。它为需要获得通知的对象定义一个更新接口(比如叫update等)。 ConcreteSubject(具体目标):subject子类的实例化,当它的状态改变时,它向各观察者实例发出通知。 ConcreteObserver(具体观察者):observer子类的实例化,它维护着指向ConcreteSubject的引用并存储其状态,实现了observer的更新接口。

在更复杂的模式中,在subject和observer之间有一个ChangeManager,其作用是尽量减少观察者反映其目标的状态变化所需的工作量,它有三个职责:维护观察者和目标之间的映射关系;定义一个特定的更新策略;更新所有依赖于某个目标的观察者。这只是一个很简单的介绍,更多的内容请参考《设计模式》一书。

2、template method

这一设计模式的目的是定义一个算法的框架,而将一些具体的步骤延迟到子类中实现,它使得可以不改变一个算法的结构就可以重定义其某些细节。其参与者包括:

AbstractClass(抽象类):它定义一个算法的框架,或者说“原语操作”。 ConcreteClass(具体类):实现抽象类中定义的“原语”。 这一模式很简单,同样更多的内容请参考《设计模式》一书。

=========================================

参考资料:

Implementing QuantLib

设计模式

因篇幅问题不能全部显示,请点此查看更多更全内容

热门图文

Copyright © 2019-2025 zicool.com 版权所有 湘ICP备2023022495号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务