예제 #1
0
class Eiten:
    def __init__(self):
        print("\n--* Eiten has been initialized...")
        self.HISTORY_TO_USE = history_to_use
        self.DATA_GRANULARITY_MINUTES = data_granularity_minutes
        self.FUTURE_BARS_FOR_TESTING = future_bars
        self.APPLY_NOISE_FILTERING = apply_noise_filtering
        self.IS_LONG_ONLY_PORTFOLIO = is_only_long
        self.MARKET_INDEX = market_index
        self.IS_TEST = is_test
        self.EIGEN_PORTFOLIO_NUMBER = eigen_portfolio_number
        self.STOCKS_FILE_PATH = stocks_file_path

        # Create data engine
        self.dataEngine = DataEngine(self.HISTORY_TO_USE,
                                     self.DATA_GRANULARITY_MINUTES,
                                     self.FUTURE_BARS_FOR_TESTING,
                                     self.MARKET_INDEX, self.IS_TEST,
                                     self.STOCKS_FILE_PATH)

        # Monto carlo simulator
        self.simulator = MontoCarloSimulator()

        # Strategy manager
        self.strategyManager = StrategyManager()

        # Back tester
        self.backTester = BackTester()

        # Data dictionary
        self.data_dictionary = {}

        print('\n')

    def calculate_percentage_change(self, old, new):
        """
		Calculate percentage change
		"""
        return ((new - old) * 100) / old

    def create_returns(self, historical_price_info):
        """
		Create log return matrix, percentage return matrix, and mean return vector
		"""

        returns_matrix = []
        returns_matrix_percentages = []
        predicted_return_vectors = []
        for i in range(0, len(historical_price_info)):
            close_prices = list(historical_price_info[i]["Close"])
            log_returns = [
                math.log(close_prices[i] / close_prices[i - 1])
                for i in range(1, len(close_prices))
            ]
            percentage_returns = [
                self.calculate_percentage_change(close_prices[i - 1],
                                                 close_prices[i])
                for i in range(1, len(close_prices))
            ]

            total_data = len(close_prices)
            # Expected returns in future. We can either use historical returns as future returns on try to simulate future returns and take the mean. For simulation, you can modify the functions in simulator to use here.
            future_expected_returns = np.mean([
                (self.calculate_percentage_change(
                    close_prices[i - 1], close_prices[i])) / (total_data - i)
                for i in range(1, len(close_prices))
            ])  # More focus on recent returns

            # Add to matrices
            returns_matrix.append(log_returns)
            returns_matrix_percentages.append(percentage_returns)

            # Add returns to vector
            predicted_return_vectors.append(
                future_expected_returns
            )  # Assuming that future returns are similar to past returns

        # Convert to numpy arrays for one liner calculations
        predicted_return_vectors = np.array(predicted_return_vectors)
        returns_matrix = np.array(returns_matrix)
        returns_matrix_percentages = np.array(returns_matrix_percentages)

        return predicted_return_vectors, returns_matrix, returns_matrix_percentages

    def load_data(self):
        """
		Loads data needed for analysis
		"""
        # Gather data for all stocks in a dictionary format
        # Dictionary keys will be -> historical_prices, future_prices
        self.data_dictionary = self.dataEngine.collect_data_for_all_tickers()

        # Add data to lists
        symbol_names = list(sorted(self.data_dictionary.keys()))
        historical_price_info, future_prices = [], []
        for symbol in symbol_names:
            historical_price_info.append(
                self.data_dictionary[symbol]["historical_prices"])
            future_prices.append(self.data_dictionary[symbol]["future_prices"])

        # Get return matrices and vectors
        predicted_return_vectors, returns_matrix, returns_matrix_percentages = self.create_returns(
            historical_price_info)
        return historical_price_info, future_prices, symbol_names, predicted_return_vectors, returns_matrix, returns_matrix_percentages

    def run_strategies(self):
        """
		Run strategies, back and future test them, and simulate the returns.
		"""
        historical_price_info, future_prices, symbol_names, predicted_return_vectors, returns_matrix, returns_matrix_percentages = self.load_data(
        )
        historical_price_market, future_prices_market = self.dataEngine.get_market_index_price(
        )

        # Calculate covariance matrix
        covariance_matrix = np.cov(returns_matrix)

        # Use random matrix theory to filter out the noisy eigen values
        if self.APPLY_NOISE_FILTERING:
            print(
                "\n** Applying random matrix theory to filter out noise in the covariance matrix...\n"
            )
            covariance_matrix = self.strategyManager.random_matrix_theory_based_cov(
                returns_matrix)

        # Get weights for the portfolio
        eigen_portfolio_weights_dictionary = self.strategyManager.calculate_eigen_portfolio(
            symbol_names, covariance_matrix, self.EIGEN_PORTFOLIO_NUMBER)
        mvp_portfolio_weights_dictionary = self.strategyManager.calculate_minimum_variance_portfolio(
            symbol_names, covariance_matrix)
        msr_portfolio_weights_dictionary = self.strategyManager.calculate_maximum_sharpe_portfolio(
            symbol_names, covariance_matrix, predicted_return_vectors)
        ga_portfolio_weights_dictionary = self.strategyManager.calculate_genetic_algo_portfolio(
            symbol_names, returns_matrix_percentages)

        # Print weights
        print("\n*% Printing portfolio weights...")
        self.print_and_plot_portfolio_weights(
            eigen_portfolio_weights_dictionary, 'Eigen Portfolio', plot_num=1)
        self.print_and_plot_portfolio_weights(
            mvp_portfolio_weights_dictionary,
            'Minimum Variance Portfolio (MVP)',
            plot_num=2)
        self.print_and_plot_portfolio_weights(msr_portfolio_weights_dictionary,
                                              'Maximum Sharpe Portfolio (MSR)',
                                              plot_num=3)
        self.print_and_plot_portfolio_weights(ga_portfolio_weights_dictionary,
                                              'Genetic Algo (GA)',
                                              plot_num=4)
        self.draw_plot()

        # Back test
        print("\n*& Backtesting the portfolios...")
        self.backTester.back_test(symbol_names,
                                  eigen_portfolio_weights_dictionary,
                                  self.data_dictionary,
                                  historical_price_market,
                                  self.IS_LONG_ONLY_PORTFOLIO,
                                  market_chart=True,
                                  strategy_name='Eigen Portfolio')
        self.backTester.back_test(
            symbol_names,
            mvp_portfolio_weights_dictionary,
            self.data_dictionary,
            historical_price_market,
            self.IS_LONG_ONLY_PORTFOLIO,
            market_chart=False,
            strategy_name='Minimum Variance Portfolio (MVP)')
        self.backTester.back_test(
            symbol_names,
            msr_portfolio_weights_dictionary,
            self.data_dictionary,
            historical_price_market,
            self.IS_LONG_ONLY_PORTFOLIO,
            market_chart=False,
            strategy_name='Maximum Sharpe Portfolio (MSR)')
        self.backTester.back_test(symbol_names,
                                  ga_portfolio_weights_dictionary,
                                  self.data_dictionary,
                                  historical_price_market,
                                  self.IS_LONG_ONLY_PORTFOLIO,
                                  market_chart=False,
                                  strategy_name='Genetic Algo (GA)')
        self.draw_plot()

        if self.IS_TEST:
            print("\n#^ Future testing the portfolios...")
            # Future test
            self.backTester.future_test(symbol_names,
                                        eigen_portfolio_weights_dictionary,
                                        self.data_dictionary,
                                        future_prices_market,
                                        self.IS_LONG_ONLY_PORTFOLIO,
                                        market_chart=True,
                                        strategy_name='Eigen Portfolio')
            self.backTester.future_test(
                symbol_names,
                mvp_portfolio_weights_dictionary,
                self.data_dictionary,
                future_prices_market,
                self.IS_LONG_ONLY_PORTFOLIO,
                market_chart=False,
                strategy_name='Minimum Variance Portfolio (MVP)')
            self.backTester.future_test(
                symbol_names,
                msr_portfolio_weights_dictionary,
                self.data_dictionary,
                future_prices_market,
                self.IS_LONG_ONLY_PORTFOLIO,
                market_chart=False,
                strategy_name='Maximum Sharpe Portfolio (MSR)')
            self.backTester.future_test(symbol_names,
                                        ga_portfolio_weights_dictionary,
                                        self.data_dictionary,
                                        future_prices_market,
                                        self.IS_LONG_ONLY_PORTFOLIO,
                                        market_chart=False,
                                        strategy_name='Genetic Algo (GA)')
            self.draw_plot()

        # Simulation
        print("\n+$ Simulating future prices using monte carlo...")
        self.simulator.simulate_portfolio(symbol_names,
                                          eigen_portfolio_weights_dictionary,
                                          self.data_dictionary,
                                          future_prices_market,
                                          self.IS_TEST,
                                          market_chart=True,
                                          strategy_name='Eigen Portfolio')
        self.simulator.simulate_portfolio(
            symbol_names,
            eigen_portfolio_weights_dictionary,
            self.data_dictionary,
            future_prices_market,
            self.IS_TEST,
            market_chart=False,
            strategy_name='Minimum Variance Portfolio (MVP)')
        self.simulator.simulate_portfolio(
            symbol_names,
            eigen_portfolio_weights_dictionary,
            self.data_dictionary,
            future_prices_market,
            self.IS_TEST,
            market_chart=False,
            strategy_name='Maximum Sharpe Portfolio (MSR)')
        self.simulator.simulate_portfolio(symbol_names,
                                          ga_portfolio_weights_dictionary,
                                          self.data_dictionary,
                                          future_prices_market,
                                          self.IS_TEST,
                                          market_chart=False,
                                          strategy_name='Genetic Algo (GA)')
        self.draw_plot()

    def draw_plot(self):
        """
		Draw plots
		"""
        plt.tight_layout()
        plt.grid()
        plt.legend(fontsize=14)
        plt.show()

    def print_and_plot_portfolio_weights(self, weights_dictionary, strategy,
                                         plot_num):
        print("\n-------- Weights for %s --------" % strategy)
        symbols = list(sorted(weights_dictionary.keys()))
        symbol_weights = []
        for symbol in symbols:
            print("Symbol: %s, Weight: %.4f" %
                  (symbol, weights_dictionary[symbol]))
            symbol_weights.append(weights_dictionary[symbol])

        # Plot
        width = 0.1
        x = np.arange(len(symbol_weights))
        plt.bar(x + (width * (plot_num - 1)) + 0.05,
                symbol_weights,
                label=strategy,
                width=width)
        plt.xticks(x, symbols, fontsize=14)
        plt.yticks(fontsize=14)
        plt.xlabel("Symbols", fontsize=14)
        plt.ylabel("Weight in Portfolio", fontsize=14)
        plt.title("Portfolio Weights for Different Strategies", fontsize=14)
예제 #2
0
class Eiten:
    def __init__(self, args):
        plt.style.use('seaborn-white')
        plt.rc('grid', linestyle="dotted", color='#a0a0a0')
        plt.rcParams['axes.edgecolor'] = "#04383F"
        plt.rcParams['figure.figsize'] = (12, 6)

        print("\n--* Eiten has been initialized...")
        self.args = args

        # Create data engine
        self.dataEngine = DataEngine(args)

        # Monto carlo simulator
        self.simulator = MontoCarloSimulator()

        # Strategy manager
        self.strategyManager = StrategyManager()

        # Back tester
        self.backTester = BackTester()

        # Data dictionary
        self.data_dictionary = {}

        print('\n')

    def calculate_percentage_change(self, old, new):
        """
        Calculate percentage change
        """
        return ((new - old) * 100) / old

    def create_returns(self, historical_price_info):
        """
        Create log return matrix, percentage return matrix, and mean return 
        vector
        """

        returns_matrix = []
        returns_matrix_percentages = []
        predicted_return_vectors = []
        for i in range(0, len(historical_price_info)):
            close_prices = list(historical_price_info[i]["Close"])
            log_returns = [
                math.log(close_prices[i] / close_prices[i - 1])
                for i in range(1, len(close_prices))
            ]
            percentage_returns = [
                self.calculate_percentage_change(close_prices[i - 1],
                                                 close_prices[i])
                for i in range(1, len(close_prices))
            ]

            total_data = len(close_prices)

            # Expected returns in future. We can either use historical returns as future returns on try to simulate future returns and take the mean. For simulation, you can modify the functions in simulator to use here.
            future_expected_returns = np.mean([
                (self.calculate_percentage_change(
                    close_prices[i - 1], close_prices[i])) / (total_data - i)
                for i in range(1, len(close_prices))
            ])  # More focus on recent returns

            # Add to matrices
            returns_matrix.append(log_returns)
            returns_matrix_percentages.append(percentage_returns)

            # Add returns to vector
            # Assuming that future returns are similar to past returns
            predicted_return_vectors.append(future_expected_returns)

        # Convert to numpy arrays for one liner calculations
        predicted_return_vectors = np.array(predicted_return_vectors)
        returns_matrix = np.array(returns_matrix)
        returns_matrix_percentages = np.array(returns_matrix_percentages)

        return predicted_return_vectors, returns_matrix, returns_matrix_percentages

    def load_data(self):
        """
        Loads data needed for analysis
        """
        # Gather data for all stocks in a dictionary format
        # Dictionary keys will be -> historical_prices, future_prices
        self.data_dictionary = self.dataEngine.collect_data_for_all_tickers()

        # Add data to lists
        symbol_names = list(sorted(self.data_dictionary.keys()))
        historical_price_info, future_prices = [], []
        for symbol in symbol_names:
            historical_price_info.append(
                self.data_dictionary[symbol]["historical_prices"])
            future_prices.append(self.data_dictionary[symbol]["future_prices"])

        # Get return matrices and vectors
        predicted_return_vectors, returns_matrix, returns_matrix_percentages = self.create_returns(
            historical_price_info)
        return historical_price_info, future_prices, symbol_names, predicted_return_vectors, returns_matrix, returns_matrix_percentages

    def run_strategies(self):
        """
        Run strategies, back and future test them, and simulate the returns.
        """
        historical_price_info, future_prices, symbol_names, predicted_return_vectors, returns_matrix, returns_matrix_percentages = self.load_data(
        )
        historical_price_market, future_prices_market = self.dataEngine.get_market_index_price(
        )

        # Calculate covariance matrix
        covariance_matrix = np.cov(returns_matrix)

        # Use random matrix theory to filter out the noisy eigen values
        if self.args.apply_noise_filtering:
            print(
                "\n** Applying random matrix theory to filter out noise in the covariance matrix...\n"
            )
            covariance_matrix = self.strategyManager.random_matrix_theory_based_cov(
                returns_matrix)

        # Get weights for the portfolio
        eigen_portfolio_weights_dictionary = self.strategyManager.calculate_eigen_portfolio(
            symbol_names, covariance_matrix, self.args.eigen_portfolio_number)
        mvp_portfolio_weights_dictionary = self.strategyManager.calculate_minimum_variance_portfolio(
            symbol_names, covariance_matrix)
        msr_portfolio_weights_dictionary = self.strategyManager.calculate_maximum_sharpe_portfolio(
            symbol_names, covariance_matrix, predicted_return_vectors)
        ga_portfolio_weights_dictionary = self.strategyManager.calculate_genetic_algo_portfolio(
            symbol_names, returns_matrix_percentages)

        # Print weights
        print("\n*% Printing portfolio weights...")
        self.print_and_plot_portfolio_weights(
            eigen_portfolio_weights_dictionary, 'Eigen Portfolio', plot_num=1)
        self.print_and_plot_portfolio_weights(
            mvp_portfolio_weights_dictionary,
            'Minimum Variance Portfolio (MVP)',
            plot_num=2)
        self.print_and_plot_portfolio_weights(msr_portfolio_weights_dictionary,
                                              'Maximum Sharpe Portfolio (MSR)',
                                              plot_num=3)
        self.print_and_plot_portfolio_weights(ga_portfolio_weights_dictionary,
                                              'Genetic Algo (GA)',
                                              plot_num=4)
        self.draw_plot("output/weights.png")

        # Back test
        print("\n*& Backtesting the portfolios...")
        self.backTester.back_test(symbol_names,
                                  eigen_portfolio_weights_dictionary,
                                  self.data_dictionary,
                                  historical_price_market,
                                  self.args.only_long,
                                  market_chart=True,
                                  strategy_name='Eigen Portfolio')
        self.backTester.back_test(
            symbol_names,
            mvp_portfolio_weights_dictionary,
            self.data_dictionary,
            historical_price_market,
            self.args.only_long,
            market_chart=False,
            strategy_name='Minimum Variance Portfolio (MVP)')
        self.backTester.back_test(
            symbol_names,
            msr_portfolio_weights_dictionary,
            self.data_dictionary,
            historical_price_market,
            self.args.only_long,
            market_chart=False,
            strategy_name='Maximum Sharpe Portfolio (MSR)')
        self.backTester.back_test(symbol_names,
                                  ga_portfolio_weights_dictionary,
                                  self.data_dictionary,
                                  historical_price_market,
                                  self.args.only_long,
                                  market_chart=False,
                                  strategy_name='Genetic Algo (GA)')
        self.draw_plot("output/backtest.png")

        if self.args.is_test:
            print("\n#^ Future testing the portfolios...")
            # Future test
            self.backTester.future_test(symbol_names,
                                        eigen_portfolio_weights_dictionary,
                                        self.data_dictionary,
                                        future_prices_market,
                                        self.args.only_long,
                                        market_chart=True,
                                        strategy_name='Eigen Portfolio')
            self.backTester.future_test(
                symbol_names,
                mvp_portfolio_weights_dictionary,
                self.data_dictionary,
                future_prices_market,
                self.args.only_long,
                market_chart=False,
                strategy_name='Minimum Variance Portfolio (MVP)')
            self.backTester.future_test(
                symbol_names,
                msr_portfolio_weights_dictionary,
                self.data_dictionary,
                future_prices_market,
                self.args.only_long,
                market_chart=False,
                strategy_name='Maximum Sharpe Portfolio (MSR)')
            self.backTester.future_test(symbol_names,
                                        ga_portfolio_weights_dictionary,
                                        self.data_dictionary,
                                        future_prices_market,
                                        self.args.only_long,
                                        market_chart=False,
                                        strategy_name='Genetic Algo (GA)')
            self.draw_plot("output/future_tests.png")

        # Simulation
        print("\n+$ Simulating future prices using monte carlo...")
        self.simulator.simulate_portfolio(symbol_names,
                                          eigen_portfolio_weights_dictionary,
                                          self.data_dictionary,
                                          future_prices_market,
                                          self.args.is_test,
                                          market_chart=True,
                                          strategy_name='Eigen Portfolio')
        self.simulator.simulate_portfolio(
            symbol_names,
            eigen_portfolio_weights_dictionary,
            self.data_dictionary,
            future_prices_market,
            self.args.is_test,
            market_chart=False,
            strategy_name='Minimum Variance Portfolio (MVP)')
        self.simulator.simulate_portfolio(
            symbol_names,
            eigen_portfolio_weights_dictionary,
            self.data_dictionary,
            future_prices_market,
            self.args.is_test,
            market_chart=False,
            strategy_name='Maximum Sharpe Portfolio (MSR)')
        self.simulator.simulate_portfolio(symbol_names,
                                          ga_portfolio_weights_dictionary,
                                          self.data_dictionary,
                                          future_prices_market,
                                          self.args.is_test,
                                          market_chart=False,
                                          strategy_name='Genetic Algo (GA)')
        self.draw_plot("output/monte_carlo.png")

    def draw_plot(self, filename="output/graph.png"):
        """
        Draw plots
        """
        # Styling for plots

        plt.grid()
        plt.legend(fontsize=14)
        plt.tight_layout()
        plt.show()

        """if self.args.save_plot:
            plt.savefig(filename)
        else:
            plt.tight_layout()
            plt.show()""" # Plots were not being generated properly. Need to fix this.

    def print_and_plot_portfolio_weights(self, weights_dictionary: dict,
                                         strategy, plot_num: int) -> None:
        print("\n-------- Weights for %s --------" % strategy)
        symbols = list(sorted(weights_dictionary.keys()))
        symbol_weights = []
        for symbol in symbols:
            print("Symbol: %s, Weight: %.4f" %
                  (symbol, weights_dictionary[symbol]))
            symbol_weights.append(weights_dictionary[symbol])

        # Plot
        width = 0.1
        x = np.arange(len(symbol_weights))
        plt.bar(x + (width * (plot_num - 1)) + 0.05,
                symbol_weights,
                label=strategy,
                width=width)
        plt.xticks(x, symbols, fontsize=14)
        plt.yticks(fontsize=14)
        plt.xlabel("Symbols", fontsize=14)
        plt.ylabel("Weight in Portfolio", fontsize=14)
        plt.title("Portfolio Weights for Different Strategies", fontsize=14)