4

I am pricing financial instruments, and each financial instrument object requires a day counter as a property. There are 4 kinds of day counters which have different implementations for each of their two methods, year_fraction and day_count. This day counter property on financial instruments is used in other classes when pricing, to know how to discount curves appropriately, etc. However, all of the day count methods are static, and doing nothing more than applying some formula.

So despite everything I've read online telling me to not use static methods and just have module-level functions instead, I couldn't see a way to nicely pass around the correct DayCounter without implementing something like this

class DayCounter:
    __metaclass__ = abc.ABCMeta

    @abc.abstractstaticmethod
    def year_fraction(start_date, end_date):
        raise NotImplementedError("DayCounter subclass must define a year_fraction method to be valid.")

    @abc.abstractstaticmethod
    def day_count(start_date, end_date):
        raise NotImplementedError("DayCounter subclass must define a day_count method to be valid.")


class Actual360(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula


class Actual365(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula


class Thirty360(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula

class ActualActual(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula

So that in a pricing engine for some particular instrument that is passed an instrument as a parameter, I can use the instrument's day counter property as needed.

Am I missing something more idiomatic / stylistically acceptable in Python or does this seem like appropriate use for static method-only classes?


Example:

I have a class FxPricingEngine, which has an __init__ method passed an FxInstrument and subsequent underlying_instrument property. Then in order to use the Value method of my pricing engine I need to discount a curve with a particular day counter. I have a YieldCurve class with a discount method to which I pass self.underlying_instrument.day_counter.year_fraction such that I can apply the correct formula. Really all that the classes are serving to do is provide some logical organization for the unique implementations.

HavelTheGreat
  • 3,299
  • 2
  • 15
  • 34
  • Those classes are just namespaces. The inheritance that you've implemented is simply artificial and not needed at all. It would be cleaner to turn them into modules with functions IMHO. – freakish Apr 13 '16 at 12:19
  • @freakish Maybe this is too localized and I should just give up on this question but if you look at the example at the bottom of my question, can you see my issue with having modules with functions? I would need to somehow pass around a parameter associated with an instrument representing what module to use? – HavelTheGreat Apr 13 '16 at 12:21
  • Module is an object as well. If you can pass around classes then you can pass around modules. – freakish Apr 13 '16 at 12:26
  • 1
    Take a look at the discussion on the strategy pattern in Python: http://stackoverflow.com/questions/963965/how-to-write-strategy-pattern-in-python-differently-than-example-in-wikipedia – Bernhard Apr 13 '16 at 12:28
  • @HavelTheGreat Oh, you mean that you want to retrieve module dynamically by say a string or int? Then you create a dictionary with keys that map to modules. – freakish Apr 13 '16 at 12:36
  • 1
    @freakish That's what I'm going to end up doing, I think, sort of goes hand in hand with the answer I accepted. Many thanks. – HavelTheGreat Apr 13 '16 at 12:43

3 Answers3

4

As it is, object orientation does not make any sense in your scenario: there is no data associated with an instance of your types, so any two objects of some type (e.g. Thirty360) are going to be equal (i.e. you only have singletons).

It looks like you want to be able to parametrise client code on behaviour - the data which your methods operate on is not given in a constructor but rather via the arguments of the methods. In that case, plain free functions may be a much more straight forward solution.

For instance, given some imaginary client code which operates on your counters like:

def f(counter):
  counter.day_count(a, b)
  # ...
  counter.year_fraction(x, y)

...you could just as well imagine passing two functions as arguments right away instead of an object, e.g. have

def f(day_count, year_fraction):
    day_count(a, b)
    # ...
    year_fraction(x, y)

On the caller side, you would pass plain functions, e.g.

f(thirty360_day_count, thirty360_year_fraction)

If you like, you could also have different names for the functions, or you could define them in separate modules to get the namespacing. You could also easily pass special functions like way (for instance if you only need the day_count to be correct but the year_fraction could be a noop).

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
-1

Well to be frank it doesn't make much sense in defining static methods this way. The only purpose static methods are serving in your case is providing a namespace to your function names i.e. you can call your method like Actual365.day_count making it more clear that day_count belongs to Actual365 functionality.

But you can accomplish the same think by defining a module named actual365.

import actual365
actual365.day_count()

As far as Object Orientation is concerned, your code is not offering any advantage that OOP design offers. You have just wrapped your functions in a class.

Now I noticed all your methods are using start_date and end_date, how about using them as instance variables.

class Actual365(object):

    def __init__(self, start_date, end_date):
        self.start_date, self.end_date = start_date, end_date

    def day_count(self):
        # your unique formula

    ...

Besides AbstractClasses don't make much sense in Duck-Typed languages like Python. As long as some object is providing a behavior it doesn't need to inherit from some abstract class.

If that doesn't work for you, using just functions might be better approach.

hspandher
  • 15,934
  • 2
  • 32
  • 45
  • Perhaps I didn't explain fully - say I have a class FxPricingEngine, which has an `__init__` method passed an FxInstrument. Then in order to use the `Value` method of my pricing engine I need to discount a curve with a particular day counter. Hence I use `some_fx_instrument.day_counter.year_fraction` to apply the correct formula. – HavelTheGreat Apr 13 '16 at 12:02
  • Also, `start_date` and `end_date` change on many calls - making them instance variables would not work. – HavelTheGreat Apr 13 '16 at 12:02
  • So then defining them as static methods don't make much sense either – hspandher Apr 13 '16 at 12:08
  • In OOP paradigm object should represent some real/virtual entity. Your class is not representing anything if it doesn't have properties of its own – hspandher Apr 13 '16 at 12:09
  • It is nothing more than namespace for your functions – hspandher Apr 13 '16 at 12:11
  • I understand that in general, but it's representing a type of day counter. Do you see my issue regarding how I would pass a daycounter from an instrument around as I need to without the classes? – HavelTheGreat Apr 13 '16 at 12:12
  • if you want to persist state of start_date and end_date, why not create multiple instances with dates as instance variables as I mentioned – hspandher Apr 13 '16 at 12:13
  • That is simply not feasible. A day counter is used in a Discount method for a yield curve, for instance. Which is called hundreds and hundreds of times with different dates, after being passed a day counter as a parameter independent of those dates. – HavelTheGreat Apr 13 '16 at 12:15
-1

No

Not that I know of. In my opinion your design pattern is ok. Especially if there is the possibility of your code growing to more than 2 functions per class and if the functions inside a class are connected.

If any combination of function is possible, use the function passing approach. The modules approach and your approach are quite similar. The advantage or disadvantage (it depends) of modules is that your code get split up into many files. Your approach allows you to use isinstance, but you probably won't need that.

Passing functions directly

If you had only one function, you could just pass this function directly instead of using a class. But as soon as you have 2 or more functions with different implementations, classes seem fine to me. Just add a docstring to explain the usage. I assume that the two function implementation in one class are somewhat connected.

Using modules

You could use modules instead of classes (e.g. a module Actual365DayCounter and a module Actual360DayCounter) and use something like if something: import Actual360DayCounter as daycounter and else: import Actual365ayCounter as daycounter.

Or you could import all modules and put them in a dictionary (thanks to the comment by @freakish) like MODULES = { 'Actual360': Actual360, ... } and simply use MODULES[my_var].

But I doubt this would be a better design pattern, as you would split up your source coude in many tiny modules.

Another option:

One way would be to use only one class:

class DayCounter:
    def __init__(self, daysOfTheYear = 360):
        self.days_of_the_year = daysOfTheYear

And make the functions using self.days_of_the_year. But this only works if days_of_the_year is actually a parameter of the function. If you would have to use a lot of if ... elif .. elif ... in your function implementation, this approach would be worse

Bernhard
  • 2,084
  • 2
  • 20
  • 33
  • 1
    You don't do `if something: import ...`. This is ridiculous. You create a dictionary `MODULES = { 'Actual360': Actual360, ... }` and then you do simply `MODULES[my_var]`. You would do exactly the same with classes otherwise (by using `getattr` for example) it would be unsafe. – freakish Apr 13 '16 at 12:45