Пример #1
0
    def test_all_inputs_none(self):
        """
        Test allocation when all inputs are None.
        """

        with self.assertRaises(ValueError):
            herc = HierarchicalEqualRiskContribution()
            herc.allocate(asset_names=self.data.columns)
Пример #2
0
    def test_value_error_for_non_date_index(self):
        """
        Test ValueError on passing dataframe not indexed by date.
        """

        with self.assertRaises(ValueError):
            herc = HierarchicalEqualRiskContribution()
            data = self.data.reset_index()
            herc.allocate(asset_prices=data, asset_names=self.data.columns)
Пример #3
0
    def test_value_error_for_non_dataframe_input(self):
        """
        Test ValueError on passing non-dataframe input.
        """

        with self.assertRaises(ValueError):
            herc = HierarchicalEqualRiskContribution()
            herc.allocate(asset_prices=self.data.values,
                          asset_names=self.data.columns)
Пример #4
0
    def test_value_error_with_no_asset_names(self):
        """
        Test ValueError when not supplying a list of asset names and no other input
        """

        with self.assertRaises(ValueError):
            herc = HierarchicalEqualRiskContribution()
            returns = ReturnsEstimators().calculate_returns(
                asset_prices=self.data)
            herc.allocate(asset_returns=returns.values, optimal_num_clusters=6)
Пример #5
0
    def test_value_error_for_risk_measure(self):
        """
        Test HERC when a different allocation metric string is used.
        """

        with self.assertRaises(ValueError):
            herc = HierarchicalEqualRiskContribution()
            herc.allocate(asset_names=self.data.columns,
                          asset_prices=self.data,
                          risk_measure='random_metric')
Пример #6
0
    def test_value_error_for_expected_shortfall(self):
        """
        Test ValueError when expected_shortfall is the allocation metric, no asset_returns dataframe
        is given and no asset_prices dataframe is passed.
        """

        with self.assertRaises(ValueError):
            herc = HierarchicalEqualRiskContribution()
            herc.allocate(asset_names=self.data.columns,
                          optimal_num_clusters=5,
                          risk_measure='expected_shortfall')
Пример #7
0
    def test_no_asset_names(self):
        """
        Test HERC when not supplying a list of asset names.
        """

        herc = HierarchicalEqualRiskContribution()
        herc.allocate(asset_prices=self.data, optimal_num_clusters=6)
        weights = herc.weights.values[0]
        assert (weights >= 0).all()
        assert len(weights) == self.data.shape[1]
        np.testing.assert_almost_equal(np.sum(weights), 1)
Пример #8
0
    def test_no_asset_names_with_asset_returns(self):
        """
        Test HERC when not supplying a list of asset names and when the user passes asset_returns.
        """

        herc = HierarchicalEqualRiskContribution()
        returns = ReturnsEstimators().calculate_returns(asset_prices=self.data)
        herc.allocate(asset_returns=returns, optimal_num_clusters=6)
        weights = herc.weights.values[0]
        assert (weights >= 0).all()
        assert len(weights) == self.data.shape[1]
        np.testing.assert_almost_equal(np.sum(weights), 1)
Пример #9
0
    def test_herc_with_input_as_returns(self):
        """
        Test HERC when passing asset returns dataframe as input.
        """

        herc = HierarchicalEqualRiskContribution()
        returns = ReturnsEstimators().calculate_returns(asset_prices=self.data)
        herc.allocate(asset_returns=returns, asset_names=self.data.columns)
        weights = herc.weights.values[0]
        assert (weights >= 0).all()
        assert len(weights) == self.data.shape[1]
        np.testing.assert_almost_equal(np.sum(weights), 1)
Пример #10
0
    def test_dendrogram_plot(self):
        """
        Test if dendrogram plot object is correctly rendered.
        """

        herc = HierarchicalEqualRiskContribution()
        herc.allocate(asset_prices=self.data, optimal_num_clusters=5)
        dendrogram = herc.plot_clusters(assets=self.data.columns)
        assert dendrogram.get('icoord')
        assert dendrogram.get('dcoord')
        assert dendrogram.get('ivl')
        assert dendrogram.get('leaves')
        assert dendrogram.get('color_list')
Пример #11
0
    def test_quasi_diagnalization(self):
        """
        Test the quasi-diagnalisation step of HERC algorithm.
        """

        herc = HierarchicalEqualRiskContribution()
        herc.allocate(asset_prices=self.data,
                      linkage='single',
                      optimal_num_clusters=5,
                      asset_names=self.data.columns)
        assert herc.ordered_indices == [
            13, 9, 10, 8, 14, 7, 1, 6, 4, 16, 3, 17, 12, 18, 22, 0, 15, 21, 11,
            2, 20, 5, 19
        ]
Пример #12
0
    def test_herc_expected_shortfall(self):
        """
        Test the weights calculated by the HERC algorithm - if all the weights are positive and
        their sum is equal to 1.
        """

        herc = HierarchicalEqualRiskContribution()
        herc.allocate(asset_prices=self.data,
                      asset_names=self.data.columns,
                      optimal_num_clusters=5,
                      risk_measure='expected_shortfall')
        weights = herc.weights.values[0]
        assert (weights >= 0).all()
        assert len(weights) == self.data.shape[1]
        np.testing.assert_almost_equal(np.sum(weights), 1)
Пример #13
0
    def test_herc_with_input_as_covariance_matrix(self):
        """
        Test HERC when passing a covariance matrix as input.
        """

        herc = HierarchicalEqualRiskContribution()
        returns = ReturnsEstimators().calculate_returns(asset_prices=self.data)
        herc.allocate(asset_names=self.data.columns,
                      covariance_matrix=returns.cov(),
                      optimal_num_clusters=6,
                      asset_returns=returns)
        weights = herc.weights.values[0]
        assert (weights >= 0).all()
        assert len(weights) == self.data.shape[1]
        np.testing.assert_almost_equal(np.sum(weights), 1)
Пример #14
0
    def test_herc_with_asset_returns_as_none(self):
        """
        Test HERC when asset returns are not required for calculating the weights.
        """

        herc = HierarchicalEqualRiskContribution()
        returns = ReturnsEstimators().calculate_returns(asset_prices=self.data)
        herc.allocate(asset_names=self.data.columns,
                      covariance_matrix=returns.cov(),
                      optimal_num_clusters=5,
                      risk_measure='equal_weighting')
        weights = herc.weights.values[0]
        assert (weights >= 0).all()
        assert len(weights) == self.data.shape[1]
        np.testing.assert_almost_equal(np.sum(weights), 1)
class HierarchicalEqualRiskContributionStrategy(object):
    def __init__(self):

        # Get the data:
        self.loadDirectory = os.path.expandvars(
            '${HOME}/Desktop/quant-research-env/DARWINStrategyContentSeries/Data/ClosePricePortfolio.csv'
        )
        self.saveDirectory = os.path.expandvars(
            '${HOME}/Desktop/quant-research-env/DARWINStrategyContentSeries/OnlinePortfolioStrategies/_OPTIMIZATIONS/HERC/'
        )
        self.DF_CLOSE = self._loadTechnicalDataset()

    def _loadTechnicalDataset(self):

        # Load it:
        ASSET_UNIVERSE = pd.read_csv(self.loadDirectory,
                                     index_col=0,
                                     parse_dates=True,
                                     infer_datetime_format=True)
        print('¡Asset Universe file LOADED!')

        return ASSET_UNIVERSE

    def _generateAllocations(self):

        # Create object:
        self.STRATEGY = HierarchicalEqualRiskContribution()

        # Allocate:
        self.STRATEGY.allocate(
            asset_names=self.DF_CLOSE.columns,
            asset_prices=self.DF_CLOSE,
            #risk_measure='expected_shortfall',
            risk_measure='conditional_drawdown_risk',
            linkage='ward')

        # Plot portfolio metrics:
        self._plotOptimalPortfolio()
        self._plotClusters()

    def _plotOptimalPortfolio(self):

        print(
            f'Optimal number of clusters: {self.STRATEGY.optimal_num_clusters}'
        )

        # Get weights:
        weights = self.STRATEGY.weights
        y_pos = np.arange(len(weights.columns))

        # Create the figure:
        f1, ax = plt.subplots(figsize=(10, 5))

        # Create the plots:
        ax.bar(list(weights.columns), weights.values[0], label='Assets')
        plt.xticks(y_pos, rotation=45, size=10)
        plt.xticks(y_pos, rotation=45, size=10)
        ax.grid(True)

        plt.grid(linestyle='dotted')
        plt.xlabel('Assets',
                   horizontalalignment='center',
                   verticalalignment='center',
                   fontsize=14,
                   labelpad=20)
        plt.ylabel('Asset Weights',
                   horizontalalignment='center',
                   verticalalignment='center',
                   fontsize=14,
                   labelpad=20)
        ax.legend(loc='best')
        plt.title(
            f'Optimal portfolio for {self.STRATEGY.__class__.__name__} optimization'
        )
        plt.subplots_adjust(left=0.09,
                            bottom=0.20,
                            right=0.94,
                            top=0.90,
                            wspace=0.2,
                            hspace=0)
        f1.canvas.set_window_title('OPTIMIZATION METHODS')

        # In PNG:
        plt.savefig(self.saveDirectory + 'OptimalPortfolio.png')

        # Show:
        plt.show()

    def _plotClusters(self):

        # Create the figure:
        f1, ax = plt.subplots(figsize=(10, 5))

        # Create the plots:
        self.STRATEGY.plot_clusters(self.DF_CLOSE.columns)
        ax.grid(True)

        plt.grid(linestyle='dotted')
        plt.title(
            f'Dendrogram for {self.STRATEGY.__class__.__name__} optimization')
        plt.xticks(rotation=45)
        plt.subplots_adjust(left=0.09,
                            bottom=0.20,
                            right=0.94,
                            top=0.90,
                            wspace=0.2,
                            hspace=0)
        f1.canvas.set_window_title('OPTIMIZATION METHODS')

        # In PNG:
        plt.savefig(self.saveDirectory + 'Dendogram.png')

        # Show:
        plt.show()

    def _predictOutcome(self):

        pass