背景

我试图将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对Mark和cc使用的估计方法与Markowitz不同,但是随后的均值方差优化过程相同。自然,我想对mu进行子类化以获得BL模型。问题在于在BL中,sigmaMarkowitz的估计需要附加参数。不仅如此,这组附加参数还动态依赖于mu,因此我不能仅仅重写sigma来为其提供附加参数。实际上,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已经抱怨date用不一致的签名覆盖了Markowitz.back_test。另外,这实际上并没有重用BlackLitterman.estimate_mu_and_sigma中的可重用代码。

有人可以告诉我如何更优雅地从Markowtiz.estimate_mu_and_sigma继承吗?谢谢!

最佳答案

您实际上不应该尝试将Markowitz用作您的基类,但是要么拥有一个抽象的Model基类并将这两个模型都实现为子类,要么-为您的用例提供更好的恕我直言-具有一个单独的Model具体类除了estimate_mu_and_sigmamean_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


然后,使用适当的参数构建策略,并将其传递给估算器。通过将变量部分(策略)与不变量(如何估计)分开,您可以避免不得不用不相关的细节来污染估计器。

注意:对于基于继承的解决方案,您必须设计您的基类,以便它的方法可以接受所有可能的估计模型的所有可能的参数,通常对所有与一个不同的参数使用*args**kwargs来完成具体班级到另一个。这并没有真正帮助wrt /文档和调试...

09-27 17:44