I'm a bit of a noob to classes (mostly done functional programming), so although I've used one specific method to achieve the following, if there a "best practices" that implement what I'm looking for (other than properties & attributes), I'd love to hear about it.
I'm creating a portfolio object that has the following attributes:
date_range
: a tuple of the first and last date for the relevant periodportfolio
: the values of the portfolio betweendate_range[0]:date_range[-1]
benchmark
: the values of the benchmark betweendate_range[0]:date_range[-1]
and I'd like to run some statistical calculations on both series (FYI, the Class
definition can be found at the bottom of the post).
import pandas
import numpy
#create the date range
In [1]: dt_rng = pandas.DatetimeIndex(start = '01/01/2000', freq = 'b', periods = 100)
#create the portfolio & benchmark series
In [ 2]: p1 = 1000*numpy.exp(numpy.cumsum(numpy.random.randn(len(dt_rng),)/252.))
In [ 3]: p2 = 1000*numpy.exp(numpy.cumsum(numpy.random.randn(len(dt_rng),)/252.))
In [ 4]: port = pandas.Series(p1, dt_rng)
In [ 5]: bench = pandas.Series(p2, dt_rng)
#create the Portfolio Object (Class Code at the bottom)
In [ 6]: port_object = PortObj(port, bench)
In [ 7]: port_object.port_return()
Out [10]: -0.00066236017291987359
In [11]: port_object.bech_return()
Out [12]: -0.031054475224739697
In [13]: port_object.alpha()
Out [14]: 0.030392115051819824
In [15]: port_object.date_range
Out [16]:
(Timestamp('2000-01-03 00:00:00', tz=None),
Timestamp('2000-05-19 00:00:00', tz=None))
Now I would like to change the range of the dates that is used in the calculation of portfolio metrics, so let's say I chose an interval of dt_rng[15], dt_rng[60]
. So:
In [14]: port_object.date_range = ((dt_rng[15], dt_rng[50]))
Out [15]:
(Timestamp('2000-01-24 00:00:00', tz=None),
Timestamp('2000-03-13 00:00:00', tz=None))
So we know the date_range
has changed, but my @set
methods didn't function properly, as can be seen by (one of many methods):
In [16:]: port_object.alpha()
Out [17:]: 0.030392115051819824 #same as above
I've tried to follow this post but wasn't able to implement it inside of my class.
Here's the class:
class PortObj:
def __init__(self, portfolio, benchmark):
self.date_range = ((portfolio.index[0], portfolio.index[-1]))
self.portfolio = portfolio
self.benchmark = benchmark
@property
def date_range(self):
return self.date_range
@date_range.setter
def date_range(self, date_range):
self.date_range = date_range
self.portfolio = self.portfolio.loc[date_range[0]:date_range[1]]
self.benchmark = self.benchmark.loc[date_range[0]:date_range[1]]
@property
def portfolio(self):
return self.portfolio
@portfolio.setter
def portfolio(self, date_range):
self.date_range = date_range
self.portfolio = self.portfolio.loc[date_range[0]:date_range[1]]
self.benchmark = self.benchmark.loc[date_range[0]:date_range[1]]
@property
def benchmark(self):
return self.benchmark
@portfolio.setter
def benchmark(self, date_range):
self.date_range = date_range
self.portfolio = self.portfolio.loc[date_range[0]:date_range[1]]
self.benchmark = self.benchmark.loc[date_range[0]:date_range[1]]
def port_return(self):
return numpy.divide(self.portfolio[-1], self.portfolio[0]) - 1
def bench_return(self):
return numpy.divide(self.benchmark[-1], self.benchmark[0]) - 1
def alpha(self):
return self.port_return() - self.bench_return()
What would folks recommend as the most effective way to "update portfolio Series
and benchmark Series
" when the date_range
is changed?
Thanks so much,
-B