背景
我正在尝试将Black-Litterman模型实现为我已经实现的Markowitz model的子类。 Markowitz模型的主要思想是:遍历date_list
,在每个date
上使用移动平均法来估计预期收益mu
和协方差矩阵sigma
,然后使用均值方差优化器mean_variance(mu, sigma)
计算均值方差组合。从概念上讲,Markowitz模型就是这样
class Markowitz(object):
def __init__(self, params):
self.price_data = ...
self.date_list = ...
def estimate_mu_and_sigma(self, date):
mu = ...
sigma = ...
return mu, sigma
@staticmethod
def mean_variance_optimiser(mu, sigma):
w = ...
return w
def back_test(self):
for date in self.date_list:
mu, sigma = self.estimate_mu_and_sigma(date)
w = Markowitz.mean_variance_optimiser(mu, sigma)
# do some other stuff
pass
Black-Litterman和Markowitz之间的唯一区别是BL对mu
和sigma
使用的估计方法与Markowitz不同,但是随后的均值方差优化过程相同。自然,我想继承Markowitz
以获得BL模型。问题在于在BL中,mu
和sigma
的估计需要其他参数。不仅如此,这组附加参数还动态依赖于date
,因此我不能仅仅重写Markowitz.back_test
来为其提供附加参数。实际上,BL模型是这样的:
class BlackLitterman(Markowitz):
def __init__(self, params, more_parms):
super().__init__(params)
self.some_auxiliary_data = ...
def estimate_mu_and_sigma(self, date, dynamic_params):
mu = ...
sigma = ...
return mu, sigma
def back_test(self, more_params):
for date in self.date_list:
dynamic_params = ... # depends both on date and more params
mu, sigma = self.estimate_mu_and_sigma(date, dynamic_params)
w = Markowitz.mean_variance_optimiser(mu, sigma)
# do some other stuff
pass
当我尝试此操作时,IDE已经抱怨BlackLitterman.estimate_mu_and_sigma
签名不一致而覆盖Markowtiz.estimate_mu_and_sigma
。另外,这实际上并没有重用back_test
中的可重用代码。
有人可以告诉我如何更优雅地继承Markowitz
吗?谢谢!
答案 0 :(得分:2)
您实际上不应该尝试将Markowitz
用作您的基类,而是拥有一个抽象的Model
基类并将这两个模型都实现为子类,或者-为您的用例提供更好的恕我直言-一个单独的Model
具体类,它执行estimate_mu_and_sigma
和mean_variance_optimiser
以外的所有内容,并对这些部分使用策略模式。
基于策略的解决方案:
class Estimator(object):
def __init__(self, params, strategy):
self.price_data = ...
# etc
self.strategy = strategy
def back_test(self):
for date in self.date_list:
mu, sigma = self.strategy.estimate_mu_and_sigma(date)
w = self.strategy.mean_variance_optimiser(mu, sigma)
# do some other stuff
pass
class MarkowitzStrategy(object):
def __init__(self, *args, **kw):
# ...
def estimate_mu_and_sigma(self, date):
mu = ...
sigma = ...
return mu, sigma
class BlackLittermanStrategy(object):
def __init__(self, *args, **kw):
# here you pass `more_params` and store them locally
# etc so you can caculate
# `dynamic_params` here without polluting the Estimator class
self.more_params = ....
def _calc_dyn_params(self, date):
return ...
def estimate_mu_and_sigma(self, date):
dynamic_params = self._calc_dyn_params(date)
mu = ...
sigma = ...
return mu, sigma
然后,使用适当的参数构建策略,并将其传递给估计器。通过将变量部分(策略)与不变量(如何估算)分开,可以避免不必要地用不相关的细节污染估算器。
NB:对于基于继承的解决方案,您必须设计基类,以便它的方法可以接受所有可能的估计模型的所有可能的参数,通常使用*args
和**kwargs
完成从一个具体类到另一个具体类的所有论点。这并没有真正帮助wrt /文档和调试...