我是一个类的菜鸟(主要是完成函数式编程),所以虽然我使用了一种特定的方法来实现以下功能,但是如果有一个“最佳实践”来实现我正在寻找的东西(除了属性和属性之外,我很乐意听到它。
我正在创建一个具有以下属性的投资组合对象:
date_range
:相关时段的第一个和最后一个日期的元组portfolio
:date_range[0]:date_range[-1]
benchmark
:date_range[0]:date_range[-1]
我想对这两个系列进行一些统计计算(仅供参考,Class
定义可以在帖子的底部找到。)
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))
现在我想更改投资组合指标计算中使用的日期范围,所以假设我选择了dt_rng[15], dt_rng[60]
的区间。所以:
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))
因此我们知道date_range
已更改,但我的@set
方法无法正常运行,可以通过(众多方法之一)看到:
In [16:]: port_object.alpha()
Out [17:]: 0.030392115051819824 #same as above
我试图关注this post,但无法在班级内实施。
这是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()
当Series
发生变化时,人们会建议什么是“更新投资组合Series
和基准date_range
”的最有效方式?
非常感谢,
-B
答案 0 :(得分:3)
查看属性文档:
http://docs.python.org/2/library/functions.html#property
特别是示例:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
您需要将值存储在单独的“私有”变量中,而不是在getter / setter中使用相同的属性名称。通常,这会给你一个递归错误,但由于你不是从对象继承,你使用的是旧式类,它与描述符无法正常工作。因此,无论如何,构造函数的self.date_range = ...
赋值都会替换您的属性。
简而言之,您需要:
答案 1 :(得分:0)
这里有一些让我觉得有点滑稽的东西......
object
... @property def portfolio(self): return self.portfolio
我真的很惊讶这样的事情并没有给你一个递归错误...通常,对于像这样的东西,你包装一个不同的(非属性)属性:
@property
def portfolio(self):
return self._portfolio # Note the leading underscore.
@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]]