- 同一个instrument也会采用不同的定价机制,正如第一篇所述,这是标准的策略模式。
- 此外,不同的instrument所需的数据是大相径庭的,返回数据也是一样,因此这里引入了arguments和results两个辅助类。
#include <ql/patterns/observable.hpp>
class PricingEngine : public Observable {
public:
class arguments;
class results;
virtual ~PricingEngine() {}
virtual arguments* getArguments() const = 0;
virtual const results* getResults() const = 0;
virtual void reset() = 0;
virtual void calculate() const = 0;
};
class PricingEngine::arguments {
public:
virtual ~arguments() {}
virtual void validate() const = 0;
};
class PricingEngine::results {
public:
virtual ~results() {}
virtual void reset() = 0;
};
template<class ArgumentsType, class ResultsType>
class GenericEngine : public PricingEngine, public Observer {
public:
PricingEngine::arguments* getArguments() const { return &arguments_; }
const PricingEngine::results* getResults() const { return &results_; }
void reset() { results_.reset(); }
void update() { notifyObservers(); }
protected:
mutable ArgumentsType arguments_;
mutable ResultType results_;
};
- Instrument的大致接口参见这里。下面是实现部分:
#include <ql/patterns/lazyobject.hpp>
#include <ql/pricingengine.hpp>
#include <ql/utilities/null.hpp>
#include <ql/time/date.hpp>
#include <boost/any.hpp>
#include <map>
#include <string>
class Instrument : public LazyObject {
// ...
};
inline void Instrument::setPricingEngine(const boost::shared_ptr& e) {
if(engine_) unregisterWith(engine_);
engine_ = e;
if(engine_) registerWith(engine_);
update();
}
// Strategy Pattern!
inline void Instrument::calculate() const {
if(isExpired()) {
setupExpired();
calculated_ = true;
} else {
LazyObject::calculate();
}
}
inline void Instrument::setupExpired() const {
NPV_ = errorEstimate_ = 0.0;
valuationDate_ = Date();
additionalResults_.clear();
}
// This is typical Template Method Pattern!
inline void Instrument::performCalculations() const {
QL_REQUIRE(engine_, "null pricing engine");
engine_->reset();
setupArguments(engine_->getArguments());
engine_->getArguments()->validate();
engine_->calculate();
fetchResults(engine_->getResults());
}
inline void setupArguments(PricingEngine::arguments*) const {
QL_FAIL("Instrument::setupArguments() not implemented");
}
inline void Instrument::fetchResults(const PricingEngine::results* r) const {
const Instrument::results* results = dynamic_cast<const Instrument::results*>(r);
QL_ENSURE(results != 0, "no results returned from pricing engine");
NPV_ = results->value;
errorEstimate_ = results->errorEstimate;
valuationDate_ = results->valuationDate;
additionalResults_ = results->additionalResults;
}
cont.