You wrote:
I'm kind of puzzled
by this create() without arguments. Is this meant to
create an option
instance, or an option calculator? The former is an
instrument with
a definite identity, i.e., a given type, strike, underlying
instrument,
etc. while the latter is not an instrument but rather a facility
which can instantiate
an instrument and return its value. More explicitly, in
the first case
the factory would be used as:
EuropeanOption
option = MyEuropeanOptionCalculator::create();
double value
= option.NPV();
while in the second case the use would be:
EuropeanOptionCalculator
calculator = MyEuropeanOptionCalculator::create();
double value
= calculator.NPV(underlying,strike,...);
In the first
case, setting up the factory would require the same parameters
one would pass
to the option constructor, so I don't see much use for the
former, unless
you want to create the very same option over and over again.
But then you
would have to create a factory per option, instead than a factory
per option _type_.
In this case, I would rather store the option in some kind
of map and retrieve
it later, as in:
EuropeanOption
option = myGlobalOptionMap["optionCode"];
double value
= option.NPV();
Instead, if it
is a calculator that you want to create, it could be provided.
But then again,
I would rather see it as a facility for an external layer
since Option
instances are much more powerful. For one thing, an option object
stored somewhere
can keep track of changes in the parameters it depends upon,
recalculate
itself only when needed, and notify the change if asked to do so.
Calculator objects
as the one outlined above would create Option instances
only temporarily,
thus preventing this kind of "smart" calculation.
Furthermore,
options could be grouped into portfolios and books were the
latter classes
available (they will when we wrap our head around a decent
design). Doing
the same with parameter sets together with the associated
calculators
would be a lot more messy.
Sure, I agree. It is better to have an abstract factory as an external service. The intention with my idea is to encapsulate the parameters in the factory object, but as you argue below, this idea doesn't fit very well into this context. When you mention storing options in a map, makes me think of the Prototype pattern (Gamma et. al.). The idea is that the "instances" could serve as "classes" in run-time. So if I have two instances created from the EuropeanOption class, possessing different values, and both are stored in the map under different names. I could get a copy of either of them by doing:
EuropeanOption option = myGlobalPrototypeMap["name1"].clone();
EuropeanOption option2 = myGlobalPrototypeMap["name2"].clone();
Do you think there is
a need to provide a facility like this?
Yes, it does now. Holidays
must have obfuscated my brain somehow :)
However, I think
templatization is orthogonal to the problem of avoiding
downcast in
the engine. As a matter of fact, the latter is already implemented
in the proof-of-concept
EuropeanEngine currently in the library: the
implementation
is like (not precisely):
class OptionEngine
{
public:
virtual Arguments* parameters() = 0;
virtual const Results* results() const = 0;
// etc.
};
class EuropeanEngine
{
private:
EuropeanParameters parameters_;
EuropeanResults results_;
public:
Arguments* parameters() { return ¶meters_; }
const Results* results() const { return &results_; }
// etc.
};
so that the engine
can already read the parameters and write the results
without downcasting.
The template
class you propose, instead, is a useful device for making
declarations
easier, just as inheriting from std::unary_function<This,That>
gives you a
few useful typedefs for free. For instance, the above
EuropeanEngine
declaration would be shortened to:
class EuropeanEngine
: public xxEngine<EuropeanParameters,EuropeanResults> {
public:
Arguments* parameters() { return parameters_; }
const Results* results() const { return results_; }
// etc.
};
I'm pretty much in favor of adding this to the library.
OK! Yes, I am also in
favor of adding some base templatized base classes
to the library.
You wrote:
Absolutely. The option
doesn't need to know the _exact_ type of the results
and the parameters,
therefore we don't need to templatize it (is this a real
word, or am
I making it up?) The key is defining a number of classes
corresponding
to small parameter groups; then the full parameter structure can
be built by
multiple inheritance. What the option does is just to test whether
the parameter/result
pointer can be downcasted to the type it needs. The exact
type could even
be hidden from the option, as in:
Well, I got some comments here though. "Templatize" sounds OK for me, but I honestly don't know if it is a correct word or not? The downcasting you suggest is perfectly OK for me, but I would like a wrapper around the parameters & results objects. This reminds me of the "Extension Interface" pattern and one well known implementation of it, Microsoft COM & ATL.
Downcasting to a specific class, is like retrieving an interface. In COM, there is an interface called IUnknown (which is the most "known" interface of them all...). Every COM object must implement it. There are three methods: Release(), AddRef() and QueryInterface(). The first two provides life-time management. The last one is the most interesting in this context. It permits you to retrieve a pointer to any interface the object supports. "IID_IDispatch" is just a scalar ID. Such as:
IDispatch* pDisp;
QueryInterface(IID_IDispatch,&pDisp);
pDisp->invoke(...);
I think it separates what you want to expose and not expose (i.e. facade/interface and pure implementation better). Life-time support wouldn't hurt either, sharing instances will be easier.
A standard correspondance to an "IUnknown" implementation could be stored in the library.
We have some further issues we would like to discuss with you:
1) In quantlib, there is a distinct separate class "Currency", which doesn't seem to be related with "Instruments"? In our view "Currency" IS-AN instrument! In our trading system, an order transaction always involve two instruments, the stock you want to buy/sell and the currency instrument you want to sell/buy in exchange. So trade a stock for money is equivalent to trade a stock for another stock. We think this way of thinking simplifies our code and is good design! Is there any reason why Currency cannot be an Instrument? What do you think?
2) We have a distributed environment, where the underlying middleware is TAO. TAO is a CORBA implementation. So current "Subject/Observer" implementation in quantlib's Instrument isn't much use to us, unless we are able to make it distributed. OK, maybe it is sufficient that we override the methods of the Quantlib::Patterns::Observable class. So for example, registerObserver(Observer*) would register the Observer instance in a CORBA event channel. The Observer instance must then be a CORBA object. Making our instrument both a "CORBA object" and an "Observer" can be solved with multiple inheritance, though. Our Observable instance must, in effect, be a CORBA event channel in this case. I would like a templatized Observer, where the template parameter would define the Strategy?
Like:
template<STRATEGY>
class ObservableStrategy public Observable
{
public:
Observable(STRATEGY* impl);
changeStrategy(STRATEGY* impl) { _impl->close(); _impl=impl; _impl->open();
}
registerObserver(Observer*);
.....
private:
STRATEGY* _impl;
}
So those who want another
way of distribution would benefit from a more decoupled way of
setting their implementation.
Of course, STRATEGY must have a fixed interface, but our implementation
can maintain its "inheritance" hierarchy. I think the Observer would benefit
of an analogous template class also.
Bye,
Johan
Free forum by Nabble | Disable Popup Ads | Edit this page |