Re: Persistancy example

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Persistancy example

Andre Louw-2
Sorry my reply to Luigi's was mistakely posted directly to him. Here it is
again.

Luigi,

Let me go at this using an example.

Say you want a piece of code used to price any swap instrument. The calendar
to use being passed in as a parameter.

One way of doing it would be:

double priceSwap(Calendar aCal)
{
        Code goes here to price...
}

int main(argc, argv[])
{
        if (!strcmp(argv[1], "JHB"))
                std::cout << priceSwap(Johannesburg());
        else if (!strcmp(argv[1], "HLK"))
                std::cout << priceSwap(Helsinki());
        etc...
}

Unfortunately each time a new calendar is added you would need to change the
code.

I realize that Calendar is only one example, but similarily it could apply
to an Index, and probably a few other data-dependant objects as well. In my
mind by writing the Calendar data to some persistant store and reading it
when needed you could have one generic Calendar class that instantiates
itself from this as needed? This would the reduce the above to:

int main(argc, argv[])
{
        std::cout << priceSwap(Calendar(argv[1])); // where the Calendar
constructor would build itself from the data written away previously.
}

I realize this is not a QuantLib issue, but was wondering how you guys
handle it? Remember also that I come from an Objective-C background, maybe
C++ offers a different, as yet undiscovered, way of doing something like
this?

Thanx
Andre

 
-------------------------------------------------------------------------
This e-mail is intended only for the use of the individual or entity named
above and may contain information that is confidential and privileged,
proprietary to the company and protected by law. If you are not the intended
recipient, you are hereby notified that any dissemination, distribution or
copying of this e-mail is strictly prohibited. Opinions, conclusions and
other information in this message that do not relate to the official
business of our company shall be understood as neither given nor endorsed by
it.


Reply | Threaded
Open this post in threaded view
|

Re: Re: Persistancy example

Luigi Ballabio-4
Hi Andre,
         thanks, now I see your point.

I admit that when you wrote:

>In my mind by writing the Calendar data to some persistant store and
>reading it when needed you could have one generic Calendar class that
>instantiates
>itself from this as needed? This would the reduce the above to:
>
>int main(argc, argv[]) {
>         std::cout << priceSwap(Calendar(argv[1]));
>}

at first I took it as "given a number of calendars I can instantiate, I
want to pass a tag to select which should I use this time" since this is
what we usually do (see below). But then Rod wrote:

>I think you are talking about what I would call "static data".  That is
>any data type which may change (albeit not regularly) and for that reason
>it should be used by the code but not form part of the code.  Things like
>currencies, holidays, countries and trading locations should not really be
>hard-coded.

and I took it to mean that information such as "which days are holidays for
the TARGET calendar" or "what calendar is to be used for Euribor fixings"
should be stored externally. This is a quite different issue, and an
interesting one too. I'm intrigued, but it will require some thought
depending on the class. Two examples just off the top of my head:

Example 1:
the Xibor class constructor is very close to what you want: it takes a
number of parameters (calendar, day count, tenor, etc.) and creates an
instance of a Libor-like index. The Euribor, GBPLibor, USDLibor and such
are just some kind of curried constructors which fix some of the parameters
(e.g., Euribor specifies TARGET as the calendar): one is free to forget
about them and use the Xibor constructor directly. Therefore, on any
specific platform it would not be hard to write a simple function which
takes an index tag, retrieves the corresponding parameters from a database,
and instantiates the desired Libor.
However, it is not so easy to do the same with the base Index class, which
currently has a single child (Xibor) but in future could have children such
as IrsRate. The children would have different data members, and what counts
most, different behavior with regard to forecasting their fixing.
Therefore, the Xibor approach could not be easily generalized: the steps to
instantiate an Index would be:
   - lookup the tag in the database and determine the index type
   - if it's a Libor:
       - fetch parameters from the appropriate table
       - return Handle<Index>(new Xibor(params))
   - if it's a swap rate:
       - fetch parameters from the appropriate table
       - return Handle<Index>(new IrsRate(params))
In particular, the choice between allocating a Xibor or a IrsRate could not
be embodied in an Index constructor (apart from the fact that I wouldn't
even if I could :)

Example 2:
the Calendar class has currently no data at all: this is because we took a
rule-based approach, i.e., we coded "see if this date is a Saturday; if
not, see if it is a Sunday; if not, see if it is New Year's Day; etc."
which is pure code, instead of "look for this date in this list of known
holidays" which relies on data---the holiday list. This is partly for
clarity, and partly because we had the feeling that checking whether a date
satisfied any of a dozen rules (and since the "saturday or sunday" check is
the first if clause, the large majority of holidays return "true" after the
first check) could take less time than using bisection to look up a date in
a big list of (100 holidays/year)*(200 years) dates. Therefore, we have no
static data: only behavior. To take the data-driven approach in Calendar,
we would have two choices. The first is to switch to a date-based approach
and give it a constructor
Calendar(std::vector<Date>& holidays);
or better yet
template<class Iter> Calendar(Iter begin, Iter end);
However, I somehow dislike this since it would obscure the logic in the
calendars, and would make it a lot more difficult to spot errors in the
holiday enumeration.
The second choice would be to reify the calendar rules: something like

class CalendarRule {
   public:
     virtual bool appliesTo(const Date& d) const == 0;
}
class isWeekday : public CalendarRule { ... };
class isDayOfYear : public CalendarRule { ... };
class isNthOfMonth : public CalendarRule { ... };

in terms of which one would implement Calendar as:

Calendar(std::vector<Handle<CalendarRule> >&); // or iterators
bool Calendar::isHoliday(const Date& d) {
     std::vector<Handle<CalendarRule> >::const_iterator rule;
     for (rule = rules_.begin(); i != rules.end(); ++i)
         if (*rule)->appliesTo(d) return true;
     return false;
}

Then, one could instantiate, say, the New York calendar as (omitting the
Handles for easier reading---it would be a bit messier in reality):

std::vector<CalendarRule*> rules;
rules.push_back(new IsWeekday(Saturday));
rules.push_back(new IsWeekday(Sunday));
rules.push_back(new IsDayOfYear(1,January));
// Thanksgiving is the 4th Thursday in November
rules.push_back(new IsNthOfMonth(4,Thursday,November));

NY = Calendar(rules);

However, this has drawbacks, such as:
- it would be less efficient (virtual function galore)
- it wouldn't be easy to store rules in a database table---or in XML
- it's more than I'm motivated to do now :)


Anyway, I'd like to make it very clear that the above was not to reject
your approach, but only to put a few issues on the table so that we can
think about them.


>I realize this is not a QuantLib issue, but was wondering how you guys
>handle it?

Well, we are currently satisfied with the calendars already implemented, so
we simply use something like

Calendar make_calendar(std::string s) {
     s = StringFormatter::toLowercase(s); // make it case-insensitive
     if      (s == "target")  return TARGET();
     else if (s == "london")  return London();
     else if (s == "newyork") return NewYork();
     ...
     else throw Error("unknown calendar: "+s);
}

which allows us to write:

int main(argc, argv[]) {
     std::cout << priceSwap(make_calendar(argv[1]));
}

Also, we mostly use QuantLib-Python for our own work. And since SWIG allows
one to add methods and constructors to the exported Python classes without
actually modifying the C++ classes, the above make_calendar can be packaged
in a constructor and the Python code becomes:

print priceSwap(Calendar(sys.argv[1]))

which for our present needs is close enough to get the cigar.

Bye,
         Luigi