Beispiel #1
0
    def properties(self, verbose=False):
        """Calculates and prints out Expected annualised Return,
        Volatility and Sharpe Ratio of optimised portfolio.

        :Input:
         :verbose: ``boolean`` (default= ``False``), whether to print out properties or not
        """
        if not isinstance(verbose, bool):
            raise ValueError("verbose is expected to be a boolean.")
        if self.weights is None:
            raise ValueError("Perform an optimisation first.")
        expected_return, volatility, sharpe = annualised_portfolio_quantities(
            self.weights,
            self.mean_returns,
            self.cov_matrix,
            risk_free_rate=self.risk_free_rate,
            freq=self.freq,
        )
        if verbose:
            string = "-" * 70
            string += "\nOptimised portfolio for {}".format(self.last_optimisation)
            string += "\n\nTime window/frequency: {}".format(self.freq)
            string += "\nRisk free rate: {}".format(self.risk_free_rate)
            string += "\nExpected annual Return: {:.3f}".format(expected_return)
            string += "\nAnnual Volatility: {:.3f}".format(volatility)
            string += "\nSharpe Ratio: {:.3f}".format(sharpe)
            string += "\n\nOptimal weights:"
            string += "\n" + str(self.df_weights.transpose())
            string += "\n"
            string += "-" * 70
            print(string)
        return (expected_return, volatility, sharpe)
Beispiel #2
0
def test_annualised_portfolio_quantities():
    x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
    y = np.array([9, 8, 7, 6, 5, 4, 3, 2, 1])
    Sigma = np.cov(x, y)
    weights = np.array([1, 1])
    mean = np.array([1, 2])
    weights = np.array([-3, 5])
    res = annualised_portfolio_quantities(weights, mean, Sigma, 0, 252)
    orig = (1764, 347.79304190854657, 5.071981861166303)
    for i in range(len(res)):
        assert abs(res[i] - orig[i]) <= 1e-15
Beispiel #3
0
    def plot_optimal_portfolios(self):
        """Plots markers of the optimised portfolios for

         - minimum Volatility, and
         - maximum Sharpe Ratio.
        """
        # compute optimal portfolios
        min_vol_weights = self.minimum_volatility(save_weights=False)
        max_sharpe_weights = self.maximum_sharpe_ratio(save_weights=False)
        # compute return and volatility for each portfolio
        min_vol_vals = list(
            annualised_portfolio_quantities(
                min_vol_weights, self.mean_returns, self.cov_matrix, freq=self.freq
            )
        )[0:2]
        min_vol_vals.reverse()
        max_sharpe_vals = list(
            annualised_portfolio_quantities(
                max_sharpe_weights, self.mean_returns, self.cov_matrix, freq=self.freq
            )
        )[0:2]
        max_sharpe_vals.reverse()
        plt.scatter(
            min_vol_vals[0],
            min_vol_vals[1],
            marker="X",
            color="g",
            s=150,
            label="EF min Volatility",
        )
        plt.scatter(
            max_sharpe_vals[0],
            max_sharpe_vals[1],
            marker="X",
            color="r",
            s=150,
            label="EF max Sharpe Ratio",
        )
        plt.legend()
Beispiel #4
0
    def _random_weights(self):
        """Computes random weights for the stocks of a portfolio and the
        corresponding Expected Return, Volatility and Sharpe Ratio.

        :Output:
         :(weights, quantities): Tuple of weights (np.ndarray) and a
             list of [expected return, volatility, sharpe ratio].
        """
        # select random weights for portfolio
        w = np.array(np.random.random(self.num_stocks))
        # rebalance weights
        w = w / np.sum(w)
        # compute portfolio return and volatility
        portfolio_values = annualised_portfolio_quantities(
            w, self.return_means, self.cov_matrix, self.risk_free_rate,
            self.freq)
        return (w, list(portfolio_values))
    def efficient_frontier(self, targets=None):
        """Gets portfolios for a range of given target returns.
        If no targets were provided, the algorithm will find the minimum
        and maximum returns of the portfolio's individual stocks, and set
        the target range according to those values.
        Results in the Efficient Frontier.

        :Input:
         :targets: ``list``/``numpy.ndarray`` (default= ``None``) of ``floats``,
             range of target returns.

        :Output:
         :efrontier: ``numpy.ndarray`` of (volatility, return) values
        """
        if targets is not None and not isinstance(targets, (list, np.ndarray)):
            raise ValueError(
                "targets is expected to be a list or numpy.ndarray")
        elif targets is None:
            # set range of target returns from the individual expected
            # returns of the stocks in the portfolio.
            min_return = self.mean_returns.min() * self.freq
            max_return = self.mean_returns.max() * self.freq
            targets = np.linspace(round(min_return, 3), round(max_return, 3),
                                  100)
        # compute the efficient frontier
        efrontier = []
        for target in targets:
            weights = self.efficient_return(target, save_weights=False)
            efrontier.append([
                annualised_portfolio_quantities(weights,
                                                self.mean_returns,
                                                self.cov_matrix,
                                                freq=self.freq)[1],
                target,
            ])
        self.efrontier = np.array(efrontier)
        return self.efrontier
Beispiel #6
0
 def plot_results(self):
     """Plots the results of the Monte Carlo run, with all of the
     randomly generated weights/portfolios, as well as markers
     for the portfolios with the minimum Volatility and maximum
     Sharpe Ratio.
     """
     if (self.df_results is None or self.df_weights is None
             or self.opt_weights is None or self.opt_results is None):
         raise Exception("Error: Cannot plot, run the Monte Carlo " +
                         "optimisation first.")
     # create scatter plot coloured by Sharpe Ratio
     plt.scatter(
         self.df_results["Volatility"],
         self.df_results["Expected Return"],
         c=self.df_results["Sharpe Ratio"],
         cmap="RdYlBu",
         s=10,
         label=None,
     )
     cbar = plt.colorbar()
     # mark in green the minimum volatility
     plt.scatter(
         self.opt_results.loc["Min Volatility"]["Volatility"],
         self.opt_results.loc["Min Volatility"]["Expected Return"],
         marker="^",
         color="g",
         s=100,
         label="min Volatility",
     )
     # mark in red the highest sharpe ratio
     plt.scatter(
         self.opt_results.loc["Max Sharpe Ratio"]["Volatility"],
         self.opt_results.loc["Max Sharpe Ratio"]["Expected Return"],
         marker="^",
         color="r",
         s=100,
         label="max Sharpe Ratio",
     )
     # also set marker for initial portfolio, if weights were given
     if self.initial_weights is not None:
         # computed expected return and volatility of initial portfolio
         initial_values = annualised_portfolio_quantities(
             self.initial_weights,
             self.return_means,
             self.cov_matrix,
             self.risk_free_rate,
             self.freq,
         )
         initial_return = initial_values[0]
         initial_volatility = initial_values[1]
         plt.scatter(
             initial_volatility,
             initial_return,
             marker="^",
             color="k",
             s=100,
             label="Initial Portfolio",
         )
     plt.title("Monte Carlo simulation to optimise the portfolio based " +
               "on the Efficient Frontier")
     plt.xlabel("Volatility [period=" + str(self.freq) + "]")
     plt.ylabel("Expected Return [period=" + str(self.freq) + "]")
     cbar.ax.set_ylabel("Sharpe Ratio [period=" + str(self.freq) + "]",
                        rotation=90)
     plt.legend()