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 __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 load_data(self): """ Loads data needed for analysis """ # Gather data for all stocks in a dictionary format # Dictionary keys will be -> historical, future de = DataEngine(self.args) self.data_dict = de.collect_data_for_all_tickers() p, f = de.get_data(self.args.market_index) self.market_data["historical"] = pd.DataFrame( columns=[self.args.market_index], data=p) self.market_data["future"] = pd.DataFrame( columns=[self.args.market_index], data=f) # Get return matrices and vectors return self.data_dict
def __init__(self): print("Surpriver has been initialized...") self.TOP_PREDICTIONS_TO_PRINT = top_n self.HISTORY_TO_USE = history_to_use self.MINIMUM_VOLUME = min_volume self.IS_LOAD_FROM_DICTIONARY = is_load_from_dictionary self.DATA_DICTIONARY_PATH = data_dictionary_path self.IS_SAVE_DICTIONARY = is_save_dictionary self.DATA_GRANULARITY_MINUTES = data_granularity_minutes self.IS_TEST = is_test self.FUTURE_BARS_FOR_TESTING = future_bars self.VOLATILITY_FILTER = volatility_filter # Create data engine self.dataEngine = DataEngine(self.HISTORY_TO_USE, self.DATA_GRANULARITY_MINUTES, self.IS_SAVE_DICTIONARY, self.IS_LOAD_FROM_DICTIONARY, self.DATA_DICTIONARY_PATH, self.MINIMUM_VOLUME, self.IS_TEST, self.FUTURE_BARS_FOR_TESTING, self.VOLATILITY_FILTER)
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)
class Surpriver: def __init__(self): print("Surpriver has been initialized...") self.TOP_PREDICTIONS_TO_PRINT = top_n self.HISTORY_TO_USE = history_to_use self.MINIMUM_VOLUME = min_volume self.IS_LOAD_FROM_DICTIONARY = is_load_from_dictionary self.DATA_DICTIONARY_PATH = data_dictionary_path self.IS_SAVE_DICTIONARY = is_save_dictionary self.DATA_GRANULARITY_MINUTES = data_granularity_minutes self.IS_TEST = is_test self.FUTURE_BARS_FOR_TESTING = future_bars self.VOLATILITY_FILTER = volatility_filter # Create data engine self.dataEngine = DataEngine(self.HISTORY_TO_USE, self.DATA_GRANULARITY_MINUTES, self.IS_SAVE_DICTIONARY, self.IS_LOAD_FROM_DICTIONARY, self.DATA_DICTIONARY_PATH, self.MINIMUM_VOLUME, self.IS_TEST, self.FUTURE_BARS_FOR_TESTING, self.VOLATILITY_FILTER) def is_nan(self, object): """ Checks if a value is null. """ return object != object def calculate_percentage_change(self, old, new): return ((new - old) * 100) / old def calculate_return(self, old, new): return new / old def parse_large_values(self, value): if value < 1000: value = str(value) elif value >= 1000 and value < 1000000: value = round(value / 1000, 2) value = str(value) + "K" else: value = round(value / 1000000, 1) value = str(value) + "M" return value def calculate_volume_changes(self, historical_price): volume = list(historical_price["Volume"]) dates = list(historical_price["Datetime"]) dates = [str(date) for date in dates] # Get volume by date volume_by_date_dictionary = collections.defaultdict(list) for j in range(0, len(volume)): date = dates[j].split(" ")[0] volume_by_date_dictionary[date].append(volume[j]) for key in volume_by_date_dictionary: volume_by_date_dictionary[key] = np.sum(volume_by_date_dictionary[key]) # taking average as we have multiple bars per day. # Get all dates all_dates = list(reversed(sorted(volume_by_date_dictionary.keys()))) latest_date = all_dates[0] latest_data_point = list(reversed(sorted(dates)))[0] # Get volume information today_volume = volume_by_date_dictionary[latest_date] average_vol_last_five_days = np.mean([volume_by_date_dictionary[date] for date in all_dates[1:6]]) average_vol_last_twenty_days = np.mean([volume_by_date_dictionary[date] for date in all_dates[1:20]]) return latest_data_point, self.parse_large_values(today_volume), self.parse_large_values(average_vol_last_five_days), self.parse_large_values(average_vol_last_twenty_days) def calculate_recent_volatility(self, historical_price): close_price = list(historical_price["Close"]) volatility_five_bars = np.std(close_price[-5:]) volatility_twenty_bars = np.std(close_price[-20:]) volatility_all = np.std(close_price) return volatility_five_bars, volatility_twenty_bars, volatility_all def calculate_future_performance(self, future_data): CLOSE_PRICE_INDEX = 4 price_at_alert = future_data[0][CLOSE_PRICE_INDEX] prices_in_future = [item[CLOSE_PRICE_INDEX] for item in future_data[1:]] prices_in_future = [item for item in prices_in_future if item != 0] total_sum_percentage_change = abs(sum([self.calculate_percentage_change(price_at_alert, next_price) for next_price in prices_in_future])) future_volatility = np.std(prices_in_future) return total_sum_percentage_change, future_volatility def find_anomalies(self): """ Main function that does everything """ # Gather data for all stocks if self.IS_LOAD_FROM_DICTIONARY == 0: features, historical_price_info, future_prices, symbol_names = self.dataEngine.collect_data_for_all_tickers() else: # Load data from dictionary features, historical_price_info, future_prices, symbol_names = self.dataEngine.load_data_from_dictionary() # Find anomalous stocks using the Isolation Forest model. Read more about the model at -> https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html detector = IsolationForest(n_estimators = 100, random_state = 0) detector.fit(features) predictions = detector.decision_function(features) # Print top predictions with some statistics predictions_with_output_data = [[predictions[i], symbol_names[i], historical_price_info[i], future_prices[i]] for i in range(0, len(predictions))] predictions_with_output_data = list(sorted(predictions_with_output_data)) for item in predictions_with_output_data[:self.TOP_PREDICTIONS_TO_PRINT]: # Get some stats to print prediction, symbol, historical_price, future_price = item # Check if future data is present or not if self.IS_TEST == 1 and len(future_price) < 5: print("No future data is present. Please make sure that you ran the prior command with is_test enabled or disable that command now. Exiting now...") exit() latest_date, today_volume, average_vol_last_five_days, average_vol_last_twenty_days = self.calculate_volume_changes(historical_price) volatility_vol_last_five_days, volatility_vol_last_twenty_days, _ = self.calculate_recent_volatility(historical_price) if average_vol_last_five_days == None or volatility_vol_last_five_days == None: continue if self.IS_TEST == 0: # Not testing so just print the predictions print("Last Bar Time: %s\nSymbol: %s\nAnomaly Score: %.3f\nToday Volume: %s\nAverage Volume 5d: %s\nAverage Volume 20d: %s\nVolatility 5bars: %.3f\nVolatility 20bars: %.3f\n----------------------" % (latest_date, symbol, prediction, today_volume, average_vol_last_five_days, average_vol_last_twenty_days, volatility_vol_last_five_days, volatility_vol_last_twenty_days)) else: # Testing so show what happened in the future future_abs_sum_percentage_change, _ = self.calculate_future_performance(future_price) print("Last Bar Time: %s\nSymbol: %s\nAnomaly Score: %.3f\nToday Volume: %s\nAverage Volume 5d: %s\nAverage Volume 20d: %s\nVolatility 5bars: %.3f\nVolatility 20bars: %.3f\nFuture Absolute Sum Price Changes: %.2f\n----------------------" % (latest_date, symbol, prediction, today_volume, average_vol_last_five_days, average_vol_last_twenty_days, volatility_vol_last_five_days, volatility_vol_last_twenty_days, future_abs_sum_percentage_change)) if self.IS_TEST == 1: self.calculate_future_stats(predictions_with_output_data) def calculate_future_stats(self, predictions_with_output_data): """ Calculate different stats for future data to show whether the anomalous stocks found were actually better than non-anomalous ones """ future_change = [] anomalous_score = [] historical_volatilities = [] future_volatilities = [] for item in predictions_with_output_data: prediction, symbol, historical_price, future_price = item future_sum_percentage_change, future_volatility = self.calculate_future_performance(future_price) _, _, historical_volatility = self.calculate_recent_volatility(historical_price) # Skip for when there is a reverse split, the yfinance package does not handle that well so percentages get weirdly large if abs(future_sum_percentage_change) > 250 or self.is_nan(future_sum_percentage_change) == True or self.is_nan(prediction) == True: continue future_change.append(future_sum_percentage_change) anomalous_score.append(prediction) future_volatilities.append(future_volatility) historical_volatilities.append(historical_volatility) # Calculate correlation and stats correlation = np.corrcoef(anomalous_score, future_change)[0, 1] anomalous_future_changes = np.mean([future_change[x] for x in range(0, len(future_change)) if anomalous_score[x] < 0]) # Anything less than 0 is considered anomalous normal_future_changes = np.mean([future_change[x] for x in range(0, len(future_change)) if anomalous_score[x] >= 0]) anomalous_future_volatilities = np.mean([future_volatilities[x] for x in range(0, len(future_volatilities)) if anomalous_score[x] < 0]) # Anything less than 0 is considered anomalous normal_future_volatilities = np.mean([future_volatilities[x] for x in range(0, len(future_volatilities)) if anomalous_score[x] >= 0]) anomalous_historical_volatilities = np.mean([historical_volatilities[x] for x in range(0, len(historical_volatilities)) if anomalous_score[x] < 0]) # Anything less than 0 is considered anomalous normal_historical_volatilities = np.mean([historical_volatilities[x] for x in range(0, len(historical_volatilities)) if anomalous_score[x] >= 0]) print("\n*************** Future Performance ***************") print("Correlation between future absolute change vs anomalous score (lower is better, range = (-1, 1)): **%.2f**\nTotal absolute change in future for Anomalous Stocks: **%.3f**\nTotal absolute change in future for Normal Stocks: **%.3f**\nAverage future volatility of Anomalous Stocks: **%.3f**\nAverage future volatility of Normal Stocks: **%.3f**\nHistorical volatility for Anomalous Stocks: **%.3f**\nHistorical volatility for Normal Stocks: **%.3f**\n" % ( correlation, anomalous_future_changes, normal_future_changes, anomalous_future_volatilities, normal_future_volatilities, anomalous_historical_volatilities, normal_historical_volatilities)) # Plot FONT_SIZE = 14 colors = ['#c91414' if anomalous_score[x] < 0 else '#035AA6' for x in range(0, len(anomalous_score))] anomalous_vs_normal = np.array([1 if anomalous_score[x] < 0 else 0 for x in range(0, len(anomalous_score))]) plt.scatter(np.array(anomalous_score)[anomalous_vs_normal == 1], np.array(future_change)[anomalous_vs_normal == 1], marker='v', color = '#c91414') plt.scatter(np.array(anomalous_score)[anomalous_vs_normal == 0], np.array(future_change)[anomalous_vs_normal == 0], marker='P', color = '#035AA6') plt.axvline(x = 0, linestyle = '--', color = '#848484') plt.xlabel("Anomaly Score", fontsize = FONT_SIZE) plt.ylabel("Absolute Future Change", fontsize = FONT_SIZE) plt.xticks(fontsize = FONT_SIZE) plt.yticks(fontsize = FONT_SIZE) plt.legend(["Anomalous", "Normal"], fontsize = FONT_SIZE) plt.title("Absolute Future Change", fontsize = FONT_SIZE) plt.tight_layout() plt.grid() plt.show()
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)