Replaceable engines and instruments.

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Replaceable engines and instruments.

Johan Bosaeus-3
Hello Luigi,

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 &parameters_; }
     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