【问题标题】:Python: how to reuse a base method while allowing in-method modifications?Python:如何在允许方法内修改的同时重用基本方法?
【发布时间】:2019-01-14 14:48:59
【问题描述】:

背景

我正在尝试将 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 对 musigma 使用的估计方法与 Markowitz 不同,但随后的均值方差优化过程是相同的。自然我想继承Markowitz 来获得一个BL 模型。问题是在BL中,musigma的估计需要额外的参数。不仅如此,这组附加参数还动态地依赖于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?谢谢!

【问题讨论】:

    标签: python oop inheritance overriding


    【解决方案1】:

    您实际上不应该尝试将Markowitz 设为您的基类,而是拥有一个抽象的Model 基类并将两个模型都实现为子类,或者-恕我直言,您的用例更好-只有一个@987654323 @ 具体类,除了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
    

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

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

    【讨论】:

    • 谢谢。 mean_variance_optimiser 是静态的,所以我假设它可以封装在 Estimator?另外,double def 是错字吗?
    • @Vim if mean_variance_optimiser (我认为应该命名为optimize_mean_variance - 函数和方法是动作,所以它们应该使用动词)无论采用何种策略都是一样的,那么它不必确实是策略的一部分 - 你在 BlackLitterman 课程中提到它的事实让我认为它也被覆盖了。是的,当然def def 是一个错字;-)
    • 哎呀我的错。我不应该在BL中提到它。它实际上是为了继承 Markowitz。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 1970-01-01
    • 2016-05-23
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多