A Guide to Portfolio Optimization with Python and Modern Portfolio Theory

Portfolio optimization plays a crucial role in modern investment strategies, and one widely recognized approach is the implementation of Modern Portfolio Theory (MPT). In this article, we will present a Python script that showcases how to optimize a stock portfolio using MPT. By leveraging Yahoo Finance data and the Scipy library, we will determine the optimal asset weights that maximize the Sharpe ratio.

If you’re looking to optimize your portfolio using Python and Modern Portfolio Theory, hiring a skilled Financial Analyst is crucial. With their expertise in quantitative analysis and programming, they can leverage Python’s powerful capabilities to construct efficient portfolios that maximize returns and minimize risks. A proficient Financial Analyst will apply the principles of Modern Portfolio Theory to identify the ideal asset allocation, taking into account historical data, risk tolerance, and investment objectives. By utilizing Python’s libraries and algorithms, they can analyze large datasets, perform risk assessments, and optimize your portfolio for superior performance. Don’t miss out on the opportunity to enhance your investment strategy – hire a Financial Analyst experienced in portfolio optimization with Python and Modern Portfolio Theory today.


Section 1: Define Tickers and Time Range

To begin, we define a list of tickers representing the assets to include in our portfolio. For this demonstration, we will employ five exchange-traded funds (ETFs) that span various asset classes: SPY, BND, GLD, QQQ, and VTI. Furthermore, we establish the start and end dates for our analysis, utilizing a historical time range of five years.


tickers = [‘SPY’,’BND’,’GLD’,’QQQ’,’VTI’]

end_date = datetime.today()

start_date = end_date – timedelta(days = 5*365)


Section 2: Download Adjusted Close Prices

Next, we create an empty DataFrame to store the adjusted close prices for each asset. By leveraging the yfinance library, we can easily download the necessary data from Yahoo Finance.


adj_close_df = pd.DataFrame()

for ticker in tickers:

    data = yf.download(ticker, start = start_date,end = end_date)

    adj_close_df[ticker] = data[‘Adj Close’]


Section 3: Calculate Lognormal Returns

The subsequent step involves computing the lognormal returns for each asset, removing any missing values from the calculations.

console.log( ‘Code is Poetry’ );


Section 4: Calculate Covariance Matrix

Using the annualized log returns, we proceed to compute the covariance matrix.


cov_matrix = log_returns.cov() * 252


Section 5: Define Portfolio Performance Metrics

To evaluate portfolio performance, we define functions that calculate the portfolio’s standard deviation, expected return, and Sharpe ratio.


def standard_deviation(weights, cov_matrix):

    variance = weights.T @ cov_matrix @ weights

    return np.sqrt(variance)


def expected_return(weights, log_returns):

    return np.sum(log_returns.mean()*weights)*252


def sharpe_ratio(weights, log_returns, cov_matrix, risk_free_rate):

    return (expected_return(weights, log_returns) – risk_free_rate) / standard_deviation(weights, cov_matrix)


Section 6: Portfolio Optimization

In this section, we set the risk-free rate, establish a function to minimize the negative Sharpe ratio, and define constraints and bounds for the optimization process.


risk_free_rate = .02


def neg_sharpe_ratio(weights, log_returns, cov_matrix, risk_free_rate):

    return -sharpe_ratio(weights, log_returns, cov_matrix, risk_free_rate)


constraints = {‘type’: ‘eq’, ‘fun’: lambda weights: np.sum(weights) – 1}

bounds = [(0, 0.4) for _ in range(len(tickers))]

initial_weights = np.array([1/len(tickers)]*len(tickers))


optimized_results = minimize(neg_sharpe_ratio, initial_weights, args=(log_returns, cov_matrix, risk_free_rate), method=’SLSQP’, constraints=constraints, bounds=bounds)


Section 7: Analyze the Optimal Portfolio

We extract the optimal weights and calculate the expected annual return, expected volatility, and Sharpe ratio for the optimized portfolio. Finally, we create a bar chart to visualize the asset weights within the portfolio.


optimal_weights = optimized_results.x


print(“Optimal Weights:”)

for ticker, weight in zip(tickers, optimal_weights):

    print(f”{ticker}: {weight:.4f}”)


optimal_portfolio_return = expected_return(optimal_weights, log_returns)

optimal_portfolio_volatility = standard_deviation(optimal_weights, cov_matrix)

optimal_sharpe_ratio = sharpe_ratio(optimal_weights, log_returns, cov_matrix, risk_free_rate)


print(f”Expected Annual Return: {optimal_portfolio_return:.4f}”)

print(f”Expected Volatility: {optimal_portfolio_volatility:.4f}”)

print(f”Sharpe Ratio: {optimal_sharpe_ratio:.4f}”)


Display the Final Portfolio in a Plot


We create a bar chart to visualize the optimal weights of the assets in the portfolio.


import matplotlib.pyplot as plt


plt.figure(figsize=(10, 6))

plt.bar(tickers, optimal_weights)



plt.ylabel(‘Optimal Weights’)

plt.title(‘Optimal Portfolio Weights’)




Bottom Line

This Python script demonstrates the application of Modern Portfolio Theory in optimizing a stock portfolio. By determining the optimal weights for each asset, we aim to maximize the portfolio’s Sharpe ratio, which provides a risk-adjusted measure of return. Employing this approach enables investors to construct well-diversified portfolios and make informed decisions when allocating their investments.

Interesting Related Article: “What Are Medical Coding Audits and Why Do You Need One?