Efficient Portfolio Adjustment: A Practical Guide to Smart Optimization with Python

Michal Dufek
4 min readApr 6, 2023

--

Introduction

In our previous post, we delved into the concept of advanced portfolio management, focusing on a specific use case: smart stock replacement. By selectively replacing stocks in an existing portfolio, investors can optimize their investments while minimizing transaction costs associated with frequent rebalancing. This approach allows for more precise adjustments to a portfolio, catering to an individual’s risk profile and investment objectives.

Building on that foundation, we now present a practical guide to implementing this smart stock replacement strategy using Python programming. In this post, we provide a step-by-step tutorial and code snippets to empower investors with the tools necessary to optimize their portfolios and make data-driven decisions. By following this guide, you can enhance your investment outcomes and achieve a more efficient and risk-adjusted portfolio.

Join us as we explore how to implement advanced portfolio management techniques using Python, bridging the gap between theory and practice to help you take control of your investments.

  1. Install required libraries:
!pip install pandas numpy yfinance

2. Import required libraries:

import pandas as pd
import numpy as np
import yfinance as yf
from scipy.optimize import minimize
import matplotlib.pyplot as plt

3. Define a function to download stock data:

def download_stock_data(tickers, start_date, end_date):
data = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
return data

4. Calculate daily returns:

daily_returns = stock_data.pct_change().dropna()

5. Define a function to calculate the portfolio performance:

def portfolio_performance(weights, mean_returns, cov_matrix):
returns = np.sum(mean_returns * weights) * 252
std_dev = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
return std_dev, returns

6. Define a function to optimize the portfolio:

def optimize_portfolio(mean_returns, cov_matrix, num_assets, target_return=None):
def objective_function(weights):
return -1 * (np.sum(mean_returns * weights) * 252) / (np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252))

constraints = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1}]
if target_return is not None:
constraints.append({'type': 'eq', 'fun': lambda x: target_return - portfolio_performance(x, mean_returns, cov_matrix)[1]})

bounds = [(0, 1) for _ in range(num_assets)]
initial_guess = np.array(num_assets * [1. / num_assets])

optimized = minimize(objective_function, initial_guess, bounds=bounds, constraints=constraints)
return optimized['x']

7. Remove RTX from the portfolio and add potential replacement stocks:

current_portfolio = ['AMZN', 'F', 'TSLA']
potential_replacements = ['AAPL', 'GOOGL', 'MSFT']

8. Optimize the portfolio with different combinations of replacement stocks:

portfolio_weights = []
for i in range(len(potential_replacements) + 1):
for combo in itertools.combinations(potential_replacements, i):
new_portfolio = current_portfolio + list(combo)
portfolio_weight = optimize_portfolio(mean_returns[new_portfolio], cov_matrix.loc[new_portfolio, new_portfolio], len(new_portfolio))
portfolio_weights.append((new_portfolio, portfolio_weight))

9. Calculate and plot the efficient frontier:

portfolio_returns = []
portfolio_volatility = []

for portfolio, weights in portfolio_weights:
vol, ret = portfolio_performance(weights, mean_returns[portfolio], cov_matrix.loc[portfolio, portfolio])
portfolio_returns.append(ret)
portfolio_volatility.append(vol)

plt.figure(figsize=(12, 6))
plt.scatter(portfolio_volatility, portfolio_returns, c=(np.array(portfolio_returns) / np.array(portfolio_volatility)), marker='o', cmap='viridis')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility')
plt.ylabel('Expected Returns')
plt.title('Efficient Frontier: Portfolio Optimization')
plt.show()

Results

Portfolio 1: AMZN, F, TSLA, AAPL
Weights: AMZN: 34.95%, F: 23.54%, TSLA: 16.84%, AAPL: 24.67%
Expected Return: 30.72%
Volatility: 26.35%

Portfolio 2: AMZN, F, TSLA, GOOGL
Weights: AMZN: 39.67%, F: 26.25%, TSLA: 19.40%, GOOGL: 14.68%
Expected Return: 31.96%
Volatility: 26.33%

Portfolio 3: AMZN, F, TSLA, MSFT
Weights: AMZN: 38.44%, F: 25.19%, TSLA: 18.17%, MSFT: 18.20%
Expected Return: 32.23%
Volatility: 26.12%

Portfolio 4: AMZN, F, TSLA, AAPL, GOOGL
Weights: AMZN: 29.87%, F: 21.02%, TSLA: 14.62%, AAPL: 20.69%, GOOGL: 13.80%
Expected Return: 33.05%
Volatility: 25.97%

Portfolio 5: AMZN, F, TSLA, AAPL, MSFT
Weights: AMZN: 28.87%, F: 19.93%, TSLA: 13.20%, AAPL: 20.46%, MSFT: 17.54%
Expected Return: 33.31%
Volatility: 25.76%

Portfolio 6: AMZN, F, TSLA, GOOGL, MSFT
Weights: AMZN: 34.47%, F: 23.30%, TSLA: 15.98%, GOOGL: 13.11%, MSFT: 13.14%
Expected Return: 34.55%
Volatility: 25.74%

Portfolio 7: AMZN, F, TSLA, AAPL, GOOGL, MSFT
Weights: AMZN: 25.87%, F: 17.93%, TSLA: 11.62%, AAPL: 16.46%, GOOGL: 13.96%, MSFT: 14.16%
Expected Return: 35.03%
Volatility: 25.38%

This example output displays the expected return and volatility for each possible portfolio combination, considering the stocks from current_portfolio and potential_replacements. The plot of the efficient frontier illustrates the trade-offs between risk and return for these different stock combinations, helping you make an informed decision on which stock(s) to replace RTX with based on your risk profile and investment objectives. Please note that the actual output values may vary depending on the specific stock data and date range used.

Conclusion

In conclusion, the provided Python code snippets guide you through the process of implementing a smart stock replacement strategy based on the use case we discussed earlier. Here’s a summary of the steps taken:

  1. Install and import the required libraries (pandas, numpy, yfinance, and scipy.optimize).
  2. Define functions for downloading stock data, calculating portfolio performance, and optimizing the portfolio.
  3. Download stock data for the original portfolio (AMZN, F, TSLA, RTX) and potential replacement stocks.
  4. Calculate daily returns, mean returns, and the covariance matrix.
  5. Remove RTX from the portfolio and identify potential replacement stocks.
  6. Optimize the portfolio with different combinations of replacement stocks.
  7. Calculate and plot the efficient frontier, illustrating the trade-offs between risk and return for different stock combinations.

By following these steps, you can analyze the efficient frontier to determine the optimal stock(s) to replace RTX based on your risk profile and investment objectives. The provided code allows you to customize the current_portfolio and potential_replacements variables to suit your specific investment scenario, offering a flexible and powerful tool for advanced portfolio management.

Utilizing this smart stock replacement strategy, you can make informed decisions on how to adjust your portfolio while minimizing transaction costs associated with frequent rebalancing. This approach enables you to optimize your portfolio according to your risk profile and ultimately achieve a more efficient and risk-adjusted portfolio.

--

--