Hi,
My first impression is that it is really good. Nice "pattern-thinking". A possible extension could be to make use of an abstract factory (Gang of Four, Design Patterns), in order to create "sets" of <parameter, result, engine and instrument> objects. For example, one subclass of such a factory could be "EuropeanOptionWithXXEngineFactory". The create() method of that class should create all relevant objects and "link" them together the way you describe. What do you think? I like using the "Prototype pattern" also to provide object "sets" for an application. You are using "degenerated" base classes for arguments and results. Have you considered using a template as the engine subclass instead. Where the template parameters indicate which type of parameters and results you are using as "strategies"? It's just an alternative, which, of my knowledge, is used extensively. (For example in ACE/TAO (www.cs.wustl.edu/¨schmidt)). Nice suggestion indeed, /Johan Bosaeus _________________________________________________________________ MSN Photos is the easiest way to share and print your photos: http://photos.msn.com/support/worldwide.aspx |
Tjena Johan,
thanks for the kind words. At 03:25 PM 12/27/01 +0000, johan bosaeus wrote: >A possible extension could be to make use of an abstract factory (Gang of >Four, Design Patterns), in order to create "sets" of ><parameter, result, engine and instrument> objects. For example, one >subclass of such a factory could be "EuropeanOptionWithXXEngineFactory". >The create() method of that class should create all relevant objects and >"link" them together the way you describe. What do you think? Well, I think this is an external layer that can be easily added on top of the design. Being lazy though, I wouldn't start writing factories for all the XXXOptionWithYYYEngines---I would probably write each of them as I need it. Also, the QuEP didn't mention the possibility to create an option with an engine and change it later (mostly because I didn't give it much thought) but it would be straightforward to do it. In this case, it might be a bit confusing to create the option with a strategy hidden inside a factory, and later change the calculation model by explicitly passing the engine. For instance, the following code (with Handles removed for clarity) // here the option parameters (real-world quantities) are well separated // from the engine and its own parameters (implementation details) EuropeanOption opt(Option::Call, underlying, strike, dividendYield, termStructure, maturity, volatility, EuropeanMCEngine(accuracy)); // now we reprice it with another engine opt.setEngine(AnalyticEuropeanEngine()) looks to me more consistent and less confusing than // option and calculation parameters are not separated EuropeanOption opt = EuropeanOptionWithMCEngine::create( Option::Call, underlying, strike, dividendYield, termStructure, maturity, volatility, accuracy) // now we reprice it with another engine opt.setEngine(AnalyticEuropeanEngine()) // what is this engine thing now? I didn't see it when I created the option. // and what happened to accuracy anyway? Is it still used or is it lost? >You are using "degenerated" base classes for arguments and results. Have >you considered using a template as the engine subclass instead. Where the >template parameters indicate which type of parameters and results you are >using as "strategies"? It's just an alternative, which, of my knowledge, >is used extensively. (For example in ACE/TAO (www.cs.wustl.edu/¨schmidt)). I admit that the template design you suggest is not entirely clear to me, so please do correct me if I'm wrong. I kind of suspect that the templatization would propagate to the given option class, i.e., the option should be an EuropeanOption<ParameterType,ResultType> in order to be able to interact with an EuropeanEngine<ParameterType,ResultType>. I'd rather trade this for a bit more run-time flexibility---such as the possibility of setting a different engine to an already constructed option. Also, scripting languages come to mind towards which we export the library, such as Python. The latter doesn't know about templates, which means that two different instantiations of the same template class would have to be exported as two different classes in Python. This would be against the goal of having, e.g., a single "European option" concept. However, it might just be that I misunderstood your proposal---wouldn't be the first time, either :) Thanks again for the feedback, Luigi |
In reply to this post by johan bosaeus-2
At 11:25 PM 12/30/01 +0000, johan bosaeus wrote:
> >Well, I think this is an external layer that can be easily added on > >top of the design. Being lazy though, I wouldn't start writing > >factories for all the XXXOptionWithYYYEngines---I would probably > >write each of them as I need it. > >Right. It's only when one need a few configuration options - that is a few >object sets - and when each "object set" is quite complicated, my idea >works well. Sure, one can view it as an external layer. However, my >thought was, that if the framework provided an/a few interface(s) for such >an abstract factory, each vendor could provide its own implementation of >them. An analogy in TAO: There are Acceptor- and Connector registries >which are abstract factories for creating transport protocols. If I tell >TAO to use IIOP as transport, the corresponding subclass of the registries >are created, and their create() methods will create all the objects I need >to make use of this protocol. The implementation of those registries can >be exchanged dynamically using the ACE Service Configurator. If you think >one will make use of most combinations of <parameters, result, engine, >instrument>, I do indeed agree with you though. > > >Also, the QuEP didn't mention the possibility to create an option > >with an engine and change it later (mostly because I didn't give it > >much thought) but it would be straightforward to do it. In this > >case, it might be a bit confusing to create the option with a > >strategy hidden inside a factory, and later change the calculation > >model by explicitly passing the engine. > >Sure, I do agree, but I had hoped one could simply let the abstract >factory encapsulate all those parameters. Such as: >MyEuropeanOptionCalculator::create(). Sending the engine as a parameter >(strategy) is nice though, and then in run-time substitute it for another one. 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. > >I admit that the template design you suggest is not entirely clear > >to me, so please do correct me if I'm wrong. I kind of suspect that > >the templatization would propagate to the given option class. > >I'd rather trade this for a bit more run-time flexibility---such as > >the possibility of setting a different engine to an already constructed > >option. > >Well, my intention was that templatization wouldn't necessarily propagate >to the option class nor restrict any run-time flexibility. Maybe I'm wrong >though. It's just that I really don't like subclassing, unless it is >necessary, because of its strong binding. When I feel it is necessary, is >when I can say "this subclass IS A baseclass", and then I have some >virtual methods to write. So, if one needs an arbitrary parameter type, >such as the result or parameters, used by the engine, I would rather like >the engine class look like: > >template<class PARAMETERS, class RESULT> >class xxEngine { >public: > xxEngine(PARAMETERS* param, RESULT* result); >private: > PARAMETERS* _param; > RESULT* _result; >} > >The engine could then use the use the parameters and result straight on, >without any downcasting, which would be required when using "degenerated" >base classes. It's perfectly OK then to subclass the template, provided >it's done appropriately (you know, "subclasses should require no more and >promise no less"), the engine would then, transparently, make use of C++ >polymorphic behaviour. Does it make sense for you? 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. >Sure, assume you pass a templatized engine as a parameter in the >EuropeanOption as you described above, one need at least a template >function. But the engine's base class can be a non-template! Does the >option need to know the types of the result and parameters? If so, I think >it boils down to whether that knowledge should be hard-coded as downcasts >in the option and engine classes/subclasses or determined at creation >through templates. Do you follow me? 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: class MyOptionEngine { private: // parameter class defined on the fly and private class MyPrivateParametersClass : public OptionParams, public UnderlyingParams, etc. {}; // the same for results class MyPrivateResultsClass : public OptionValue, public OptionGreeks {} // instances MyPrivateParametersClass parameters_; MyPrivateResultsClass results_; public: Arguments* parameters() { return ¶meters_; } const Results* results() const { return &results_; } etc. }; void MyOption::setupEngine() const { // get the pointer to base class Parameters* params = engine_->parameters(); // I want to set the option parameters, so I try to cast to // the corresponding parameter group OptionParams* optionParams = dynamic_cast<OptionParams*>(params); if (optionParams != 0) { // succeeded optionParams->type = Call; optionParams->strike = 100.0; // etc. } else { // take some action, most probably raise an error } // the same goes for other parameter groups } void MyOption::performCalculations() const { // trigger the calculation in the engine engine_->calculate(); // collect the results // get the pointer to base class const Results* results = engine_->results(); const OptionValue* optionValue = dynamic_cast<const OptionValue*>(results); if (optionValue != 0) { // succeeded NPV_ = optionValue->value; } else { // raise an error since this is a required result } // now check whether the engine could calculate greeks as well const OptionGreeks* greeks = dynamic_cast<const OptionGreeks*>(results); if (greeks != 0) { // succeeded delta_ = greeks->delta; etc. } else { // take some action - maybe we won't raise an error here // but rather just signal that greeks are not available } } >Well, exporting templates to Python seems to be a bit of a problem. Yes, but luckily it is one we avoided since we cleared up how templates are to be used. They won't show up in Python this way. Thanks for your observations---forcing me to clarify these matters will be of great help the day I have to write some documentation on this. Bye, Luigi |
Free forum by Nabble | Edit this page |