Build a Stock Portfolio Analyzer
Use Python to analyze real stock data and visualize portfolio performance.
Introduction
30 Second Summary
Every investor wants to know: is my portfolio actually performing well, or am I just getting lucky? Financial analysts answer this question every day by crunching numbers on stock returns, risk, and diversification.
In this project, you will build a stock portfolio analyzer in Python that pulls real market data, calculates professional-grade performance metrics, and creates a visual chart comparing stock performance over time.
What You'll Build
A Python script that downloads live stock price data for Apple, Microsoft, and Tesla, then calculates returns, volatility, and the Sharpe ratio for each stock and your overall portfolio.
By the end of this project, you'll have:
- A working Python script that fetches real stock market data and calculates portfolio performance metrics.
- A performance comparison chart saved as a PNG image showing the growth of $1 invested in each stock.
- Foundational Python skills (variables, functions, loops, libraries) applied to a real finance use case.
- Secret Mission: Add a correlation matrix heatmap to visualize how your stocks move together.
Are there any prerequisites?
None. This project includes full setup instructions for Python, VS Code, and all required libraries. No prior programming experience is needed.
Install Python and VS Code
Before you can analyze stock data, you need the tools that make it possible.
Python is the programming language that powers your analyzer. VS Code is the code editor where you will write and run your script. In this step, you will install both tools and set up your project folder.
In this step, get ready to:
- Install Python 3.14.5 on your computer.
- Install VS Code with the Python extension.
- Create your project folder and confirm everything works.
Install Python
Python is the programming language your portfolio analyzer is written in. Let's check whether it is already installed on your computer.
- Press the Windows key to open your search bar.
- Type cmd and press Enter to open Command Prompt.
- Check your Python version by running this command:
python --version
Look at what appears in your terminal and pick the tab that matches.
✔️ I see Python 3.14 or higher
Python is ready to go. You can move on to installing VS Code.
ⓧ I see an older version
You have Python installed, but your project needs version 3.14.5 or higher. An older version can cause silent failures when you install the libraries later.
- Open https://www.python.org/downloads/release/python-3145/ in your browser.
- Scroll down to Files and click the Windows installer (64-bit) link to download it.
- Run the downloaded installer.
- Check the box that says Add python.exe to PATH at the bottom of the first screen.
- Click Install Now.
- Close your Command Prompt window after the install finishes.
- Open a new Command Prompt (press the Windows key, type cmd, press Enter).
- Verify the new version by running:
python --version
You should see Python 3.14.5 in the output.
Why do I need to close and reopen Command Prompt?
When Python is installed, it adds itself to your system's PATH. PATH is a list of locations your computer searches when you type a command. Command Prompt only reads PATH when it first opens, so you need a fresh window to pick up the change.
ⓧ Command not found
Python is not installed yet. On some Windows machines, typing python may open the Microsoft Store instead of showing an error. Either way, follow the steps below to install Python.
- Open https://www.python.org/downloads/release/python-3145/ in your browser.
- Scroll down to Files and click the Windows installer (64-bit) link to download it.
- Run the downloaded installer.
- Check the box that says Add python.exe to PATH at the bottom of the first screen.
- Click Install Now.
- Close your Command Prompt window after the install finishes.
- Open a new Command Prompt (press the Windows key, type cmd, press Enter).
- Verify Python installed correctly by running:
python --version
You should see Python 3.14.5 in the output.
What is PATH?
PATH is a list of folder locations your computer searches when you type a command. Checking the PATH box during install means you can type python from any Command Prompt window and your computer will find it.
Still seeing an older version or command not found?
Make sure you checked the Add python.exe to PATH box during installation. If you missed it, run the installer again and select Modify to enable it.
Also confirm you opened a fresh Command Prompt window after installing. Old windows do not pick up PATH changes.
Help me troubleshoot my Python installation on Windows.
Install VS Code
VS Code is a free code editor that gives you syntax highlighting, a built-in terminal, and extensions that make writing Python much easier. Let's check if you already have it.
- In your Command Prompt, check if VS Code is installed by running:
code --version
✔️ I see a version number
VS Code is already installed. Skip ahead to installing the Python extension below.
ⓧ Command not found
VS Code is not installed yet. Follow these steps to set it up.
- Open https://code.visualstudio.com/Download in your browser.
- Click the Windows button to download the User Setup installer.
- Run the downloaded installer and follow the prompts.
- When you see the Select Additional Tasks screen, check Add to PATH if it is offered.
- Click Install and wait for it to finish.
- Close your Command Prompt and open a fresh one (press the Windows key, type cmd, press Enter).
- Verify VS Code is available by running:
code --version
You should see a version number printed in the terminal.
Now install the Python extension so VS Code understands your code.
- Press the Windows key to open your search bar.
- Type Visual Studio Code and press Enter to open it.
- Open the Extensions panel by pressing Ctrl+Shift+X.
- Type Python into the search bar at the top of the panel.
- Find the extension named Python by Microsoft (it should be the first result).
- Click Install.
What does the Python extension do?
The Python extension by Microsoft adds syntax highlighting, error detection, and autocomplete suggestions for Python code. It also lets you run Python scripts directly from VS Code's built-in terminal.
Don't see the Python extension?
Make sure you are searching in the Extensions panel (the icon looks like four squares on the left sidebar) and not in the file search. The extension by Microsoft has millions of downloads and a blue checkmark.
Help me find and install the Python extension in VS Code.
Create your project folder
Your analyzer needs its own folder to keep all the files organized in one place. You will create this folder on your Desktop so it is easy to find.
- Switch back to your Command Prompt window.
- Move to your Desktop by running this command:
cd %USERPROFILE%\Desktop
- Create your project folder and move into it by running these commands:
mkdir portfolio-analyzer
cd portfolio-analyzer
- Open this folder in VS Code by running:
code .
What does code . do?
The code command launches VS Code from the terminal. The dot (.) means "the current folder." Together, they open VS Code with your portfolio-analyzer folder loaded as the workspace.
VS Code should open with your project folder visible in the Explorer sidebar on the left.
- In VS Code, open the integrated terminal by pressing Ctrl+` (that is the backtick key, above Tab on your keyboard).
- Confirm Python works in this terminal by running:
python --version
You should see Python 3.14.5 printed in the terminal.
VS Code terminal says python is not recognized?
This usually means the terminal opened before Python was added to PATH. Close the terminal panel (click the trash icon) and reopen it with Ctrl+`.
If that does not fix it, close VS Code entirely and reopen it using code . from a fresh Command Prompt.
Help me get python --version working in VS Code's terminal.
Your development environment is ready. Next up, you will install the Python libraries that fetch stock data and create charts.
Install Libraries and Set Up Your Script
Your Python environment is ready and VS Code is open. Now it's time to add the specialized tools that make financial analysis possible.
Python on its own doesn't know how to fetch stock data or create charts. Libraries extend Python's capabilities for specific tasks. In this step, you'll install three libraries and write your first lines of code to pull real market data.
In this step, get ready to:
- Install yfinance, pandas, and matplotlib.
- Create the portfolio_analyzer.py script with imports.
- Download real stock price data for Apple, Microsoft, and Tesla.
Install the libraries
You need three libraries for this project. yfinance fetches stock market data from Yahoo Finance. pandas handles data in table format. matplotlib creates charts and visualizations.
- Install all three libraries by running this command in the VS Code terminal:
pip install yfinance==1.3.0 pandas==3.0.3 matplotlib==3.10.9
What does this command do?
The pip install command downloads and installs Python packages from the Python Package Index (PyPI). The == after each package name pins it to a specific version so your results match this project exactly.
- Wait for the installation to complete. You should see a "Successfully installed" message listing all three packages with their version numbers.
Seeing an error during install?
If you see a permissions error, try running the command again with --user added at the end.
If you see "pip is not recognized", Python was not added to PATH during installation. Reinstall Python and make sure to check the "Add python.exe to PATH" checkbox.
Help me fix my pip install error
Create your script file
With your libraries installed, you can now create the Python script that will hold all your analysis code.
- In VS Code, click File in the top menu bar.
- Click New File.
- Type portfolio_analyzer.py as the file name and press Enter.
- Select the portfolio-analyzer folder as the save location if prompted, then click Save.
- Add the following imports at the top of portfolio_analyzer.py:
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
What do these imports do?
- import yfinance as yf loads the stock data library and gives it the short name yf so you can type less.
- import pandas as pd loads the data analysis library. pd is the standard abbreviation used in the Python community.
- import matplotlib.pyplot as plt loads the plotting module from matplotlib. plt is the conventional shorthand.
- Save portfolio_analyzer.py by pressing Ctrl+S.
- Run the script to confirm the imports work by entering this command in the terminal:
python portfolio_analyzer.py
- If the imports are correct, the script finishes with no output and no errors. A blank line appearing is a success signal.
Seeing a ModuleNotFoundError?
This means Python cannot find one of the libraries you installed. Make sure you are running the script in the same terminal where you ran pip install. If you have multiple Python versions, the pip that installed the packages might not match the python that runs the script.
Help me fix my ModuleNotFoundError
Download stock data
Now for the exciting part. You'll pull one year of real closing prices for Apple, Microsoft, and Tesla directly from Yahoo Finance.
- In portfolio_analyzer.py, add the following code below your imports:
# Define the stocks and time period
tickers = ["AAPL", "MSFT", "TSLA"]
period = "1y"
# Download historical closing prices
data = yf.download(tickers, period=period)["Close"]
print(data.head())
What does this code do?
- tickers is a list of stock ticker symbols. AAPL is Apple, MSFT is Microsoft, and TSLA is Tesla.
- period = "1y" tells yfinance to fetch the last one year of trading data.
- yf.download() fetches the historical data. Adding ["Close"] filters down to just closing prices, which is what financial analysts use for return calculations.
- data.head() prints the first 5 rows so you can verify the data looks correct.
- Save portfolio_analyzer.py by pressing Ctrl+S.
- Run the script again:
python portfolio_analyzer.py
- You should see a table with dates in the left column and closing prices for AAPL, MSFT, and TSLA in the remaining columns. These are real prices from the past year.
Not seeing any data?
If you see a connection error, check that your computer is connected to the internet. yfinance needs an active connection to fetch data from Yahoo Finance.
If you see an empty table or a warning about tickers, double check that your ticker symbols are exactly "AAPL", "MSFT", and "TSLA" with uppercase letters and straight quotes.
Help me fix my yfinance download issue
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here is what your complete portfolio_analyzer.py should look like at this point:
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
# Define the stocks and time period
tickers = ["AAPL", "MSFT", "TSLA"]
period = "1y"
# Download historical closing prices
data = yf.download(tickers, period=period)["Close"]
print(data.head())
Your script is pulling live market data. Next up, you'll use that data to calculate financial metrics that portfolio managers rely on daily.
Calculate Returns and Risk Metrics
You have real stock data flowing into your script. Now you need to transform those raw prices into something meaningful.
Financial analysts care about returns (how much did the stock gain or lose?) and risk (how wildly did those returns swing?). In this step, you will calculate both and combine them into the Sharpe ratio, a single number that tells you whether a stock's returns are worth the risk.
In this step, get ready to:
- Calculate daily percentage returns for each stock.
- Compute annualized return and volatility.
- Calculate the Sharpe ratio and print a formatted report.
Calculate daily returns
Raw stock prices tell you the current value, but not how much the stock gained or lost each day. Daily returns express each day's price change as a fraction of the previous day's price.
- In portfolio_analyzer.py, find the print(data.head()) line at the bottom of your file.
- Delete that line and replace it with the following code:
# Calculate daily percentage returns
daily_returns = data.pct_change().dropna()
What does this code do?
The .pct_change() method calculates the fractional change between each day's closing price and the previous day's. A value of 0.02 means the stock went up 2% that day.
The .dropna() removes the first row, which is always NaN because there is no "previous day" to compare against for the very first data point.
- Save portfolio_analyzer.py.
- Run the script in your terminal to confirm no errors appear:
python portfolio_analyzer.py
You should see the stock download output from yfinance without any error messages. The script runs silently now because you removed the print statement.
Seeing a NameError or AttributeError?
- Make sure data is defined on the line above. It should be data = yf.download(tickers, period=period)["Close"].
- Check that you typed .pct_change() with the underscore between pct and change.
Help me debug an error when calculating daily returns with pct_change.
Calculate annualized return and volatility
Daily returns are useful, but investors think in yearly terms. To annualize daily metrics, you multiply by 252 (the standard number of trading days in a year).
- Add the following code below your daily_returns line in portfolio_analyzer.py:
# Calculate annualized metrics for each stock
trading_days = 252
annualized_returns = daily_returns.mean() * trading_days
annualized_volatility = daily_returns.std() * (trading_days ** 0.5)
What does this code do?
The daily_returns.mean() calculates the average daily return for each stock. Multiplying by 252 scales it to a full year of trading.
Volatility is the standard deviation of returns, which measures how wildly a stock's price swings. You multiply by the square root of 252 (not 252 itself) because volatility scales with the square root of time.
Why 252 and not 365?
Stock markets are closed on weekends and holidays. The NYSE typically operates about 252 days per year. Using 365 would overstate both return and risk because you would be counting days when no trading happens.
- Save portfolio_analyzer.py.
You won't see any new output yet. The next chunk adds the Sharpe ratio and a formatted print that displays all the results together.
Calculate the Sharpe ratio and print a report
The Sharpe ratio answers a critical question: is this stock's return worth the risk? It compares how much extra return a stock earns above a "risk-free" baseline (like US Treasury bonds) relative to how volatile it is.
- Add the following code below your annualized_volatility line:
# Calculate Sharpe ratio (risk-free rate = 5%)
risk_free_rate = 0.05
sharpe_ratios = (annualized_returns - risk_free_rate) / annualized_volatility
What is the Sharpe ratio?
The formula is: (Annualized Return - Risk-Free Rate) / Annualized Volatility. The risk-free rate of 0.05 (5%) represents the approximate return you could get from US Treasury bonds with zero risk.
A Sharpe ratio above 1 is considered good. Above 2 is great. Below 0 means you are losing money compared to just holding risk-free bonds.
- Now add the formatted print block that displays everything in a clean report:
# Print individual stock metrics
print("=" * 60)
print("STOCK PORTFOLIO ANALYSIS REPORT")
print("=" * 60)
print(f"\n{'Stock':<8}{'Return':<12}{'Volatility':<14}{'Sharpe Ratio':<12}")
print("-" * 46)
for ticker in tickers:
ret = annualized_returns[ticker] * 100
vol = annualized_volatility[ticker] * 100
sharpe = sharpe_ratios[ticker]
print(f"{ticker:<8}{ret:<12.2f}%{vol:<13.2f}%{sharpe:<12.2f}")
What does this print block do?
This creates a formatted table with aligned columns. The :<8 syntax left-aligns text in an 8-character-wide column. The :.2f formats numbers to 2 decimal places.
Multiplying by 100 converts the decimal return and volatility into percentages for readability. This is the kind of output you would send to a portfolio manager.
- Save portfolio_analyzer.py.
- Run the script in your terminal:
python portfolio_analyzer.py
You should see a formatted report with columns for Stock, Return, Volatility, and Sharpe Ratio. Each of AAPL, MSFT, and TSLA shows its annualized metrics.
Seeing a KeyError or empty output?
- A KeyError means the ticker name does not match what yfinance returned. Make sure your tickers list at the top uses the exact strings "AAPL", "MSFT", and "TSLA".
- If the report prints but all values are 0 or NaN, check that daily_returns uses data.pct_change().dropna() and not just data.pct_change() by itself.
- If you see a SyntaxError, check that f-string quotes are consistent. Each print(f"...") line uses double quotes on the outside and single quotes inside (or vice versa).
Help me fix an error in my Sharpe ratio output.
✔️ Awesome, I've got everything!
Great. Double check you have saved portfolio_analyzer.py before moving on.
ⓧ I'd like to double check the full code
Here is the complete portfolio_analyzer.py file at this point:
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
# Define the stocks and time period
tickers = ["AAPL", "MSFT", "TSLA"]
period = "1y"
# Download historical closing prices
data = yf.download(tickers, period=period)["Close"]
# Calculate daily percentage returns
daily_returns = data.pct_change().dropna()
# Calculate annualized metrics for each stock
trading_days = 252
annualized_returns = daily_returns.mean() * trading_days
annualized_volatility = daily_returns.std() * (trading_days ** 0.5)
# Calculate Sharpe ratio (risk-free rate = 5%)
risk_free_rate = 0.05
sharpe_ratios = (annualized_returns - risk_free_rate) / annualized_volatility
# Print individual stock metrics
print("=" * 60)
print("STOCK PORTFOLIO ANALYSIS REPORT")
print("=" * 60)
print(f"\n{'Stock':<8}{'Return':<12}{'Volatility':<14}{'Sharpe Ratio':<12}")
print("-" * 46)
for ticker in tickers:
ret = annualized_returns[ticker] * 100
vol = annualized_volatility[ticker] * 100
sharpe = sharpe_ratios[ticker]
print(f"{ticker:<8}{ret:<12.2f}%{vol:<13.2f}%{sharpe:<12.2f}")
Your script now pulls live data and crunches the numbers that professional analysts use every day. Next up, you will combine these individual stock metrics into a portfolio-level view and see how diversification changes the picture.
Calculate Portfolio-Level Metrics
You now have metrics for each individual stock. But a real investor does not hold just one stock.
In this step, you will combine your three stocks into a single portfolio and calculate how the group performs together. This is how fund managers evaluate whether a mix of assets is working as a team.
In this step, get ready to:
- Define equal portfolio weights for your three stocks.
- Calculate the portfolio's annualized return, volatility, and Sharpe ratio.
- Print a formatted report combining individual and portfolio metrics.
Define portfolio weights
A portfolio weight determines how much of your total investment goes into each stock. Equal weighting means splitting your money evenly across all three stocks.
- In portfolio_analyzer.py, add the following code at the bottom of your file (after the for loop that prints individual stock metrics):
# Calculate portfolio metrics (equal weight)
weights = [1/3, 1/3, 1/3]
portfolio_daily_return = (daily_returns * weights).sum(axis=1)
What does this code do?
The weights list assigns each stock an equal share of the portfolio (one-third each). The three weights add up to 1.0 (100% of your investment).
The second line multiplies each stock's daily return by its weight, then sums across all three stocks to produce a single daily return for the combined portfolio.
Calculate portfolio-level return, volatility, and Sharpe ratio
Now that you have the portfolio's daily return, you can annualize it using the same formulas you applied to individual stocks in the previous step.
- Add this code directly below the lines you just wrote:
portfolio_annual_return = portfolio_daily_return.mean() * trading_days
portfolio_annual_volatility = portfolio_daily_return.std() * (trading_days ** 0.5)
portfolio_sharpe = (portfolio_annual_return - risk_free_rate) / portfolio_annual_volatility
What does this code do?
These three lines apply the exact same annualization math from Step 3, but to the combined portfolio instead of individual stocks.
- Multiply the mean daily return by 252 trading days to get the annualized return.
- Multiply the standard deviation by the square root of 252 to get annualized volatility.
- Divide the excess return (return minus the 5% risk-free rate) by volatility to get the portfolio Sharpe ratio.
Print a formatted summary report
A clean output table makes it easy to compare the portfolio against each individual stock. This is the kind of summary a portfolio manager would review.
- Add the following print statements below the portfolio calculations:
print("-" * 46)
print(f"{'Portfolio':<8}{portfolio_annual_return*100:<12.2f}%{portfolio_annual_volatility*100:<13.2f}%{portfolio_sharpe:<12.2f}")
print("=" * 60)
print("\nSharpe Ratio Guide: > 1 = Good, > 2 = Great, < 0 = Losing money vs risk-free")
What does this code do?
The dashes separate the portfolio row from the individual stock rows above it. The portfolio line uses the same column formatting so everything lines up neatly.
The final line prints a quick reference guide for interpreting the Sharpe ratio. A Sharpe above 1 means the stock or portfolio is earning good returns relative to its risk. Below 0 means you would have been better off in a risk-free Treasury bond.
- Save portfolio_analyzer.py.
- Run your script in the terminal:
python portfolio_analyzer.py
- You should see a formatted table with AAPL, MSFT, and TSLA rows, followed by a dashed line and a Portfolio row showing combined return, volatility, and Sharpe ratio. The Sharpe Ratio Guide prints at the bottom.
Seeing an error when you run the script?
- If you see NameError: name 'portfolio_daily_return' is not defined, make sure the weights code comes before the annual metrics code. Order matters.
- If columns look misaligned, double-check that your f-string formatting matches the code above exactly (the :<8 and :<12.2f padding).
- If you see TypeError on the weights line, confirm you used square brackets [1/3, 1/3, 1/3] not parentheses.
Why is my portfolio report printing incorrectly?
✔️ Awesome, I've got everything!
Great. Double check you have saved your file before moving on.
ⓧ I'd like to double check the full code
Here is the complete portfolio_analyzer.py file up to this point:
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
# Define the stocks and time period
tickers = ["AAPL", "MSFT", "TSLA"]
period = "1y"
# Download historical closing prices
data = yf.download(tickers, period=period)["Close"]
# Calculate daily percentage returns
daily_returns = data.pct_change().dropna()
# Calculate annualized metrics for each stock
trading_days = 252
annualized_returns = daily_returns.mean() * trading_days
annualized_volatility = daily_returns.std() * (trading_days ** 0.5)
# Calculate Sharpe ratio (risk-free rate = 5%)
risk_free_rate = 0.05
sharpe_ratios = (annualized_returns - risk_free_rate) / annualized_volatility
# Print individual stock metrics
print("=" * 60)
print("STOCK PORTFOLIO ANALYSIS REPORT")
print("=" * 60)
print(f"\n{'Stock':<8}{'Return':<12}{'Volatility':<14}{'Sharpe Ratio':<12}")
print("-" * 46)
for ticker in tickers:
ret = annualized_returns[ticker] * 100
vol = annualized_volatility[ticker] * 100
sharpe = sharpe_ratios[ticker]
print(f"{ticker:<8}{ret:<12.2f}%{vol:<13.2f}%{sharpe:<12.2f}")
# Calculate portfolio metrics (equal weight)
weights = [1/3, 1/3, 1/3]
portfolio_daily_return = (daily_returns * weights).sum(axis=1)
portfolio_annual_return = portfolio_daily_return.mean() * trading_days
portfolio_annual_volatility = portfolio_daily_return.std() * (trading_days ** 0.5)
portfolio_sharpe = (portfolio_annual_return - risk_free_rate) / portfolio_annual_volatility
print("-" * 46)
print(f"{'Portfolio':<8}{portfolio_annual_return*100:<12.2f}%{portfolio_annual_volatility*100:<13.2f}%{portfolio_sharpe:<12.2f}")
print("=" * 60)
print("\nSharpe Ratio Guide: > 1 = Good, > 2 = Great, < 0 = Losing money vs risk-free")
Your script now calculates both individual and portfolio-level performance. Next up, you will create a visual chart that shows how each stock grew over time.
Create a Performance Visualization
Your script now calculates and prints every metric a portfolio manager cares about. Numbers alone can be hard to interpret though.
A line chart showing the growth of $1 invested in each stock makes performance differences immediately obvious. In this step, you will use matplotlib to transform your daily returns into a visual comparison chart and save it as an image file.
In this step, get ready to:
- Calculate cumulative returns to show the growth of $1 over time.
- Plot a line chart comparing all three stocks.
- Save the chart as a PNG image file.
Calculate cumulative returns
Daily returns tell you how much a stock moved each day, but they do not show the big picture. Cumulative returns answer the question: if you invested $1 on day one, how much would it be worth today?
What are cumulative returns?
The formula (1 + daily_returns).cumprod() works by multiplying each day's growth factor together. A daily return of 2% becomes 1.02, and chaining these multiplications shows total growth over time.
If the cumulative return for AAPL reaches 1.25, that means $1 invested at the start grew to $1.25 by the end of the period.
Plot the chart
- In portfolio_analyzer.py, scroll to the bottom of your file (below the Sharpe Ratio Guide print statement).
- Add the cumulative returns calculation and chart creation code by copying the following:
# Calculate cumulative returns (growth of $1)
cumulative_returns = (1 + daily_returns).cumprod()
# Create performance chart
plt.figure(figsize=(10, 6))
for ticker in tickers:
plt.plot(cumulative_returns.index, cumulative_returns[ticker], label=ticker)
plt.title("Portfolio Performance - Growth of $1")
plt.xlabel("Date")
plt.ylabel("Growth of $1")
plt.legend()
plt.grid(True)
plt.tight_layout()
What does this code do?
- cumulative_returns = (1 + daily_returns).cumprod() multiplies each day's growth factor together to show the total growth of $1 over the year.
- plt.figure(figsize=(10, 6)) creates a new figure that is 10 inches wide and 6 inches tall.
- The for loop plots a separate line for each stock, using the date as the x-axis and cumulative return as the y-axis.
- plt.legend() adds a color-coded key so you can tell which line belongs to which stock.
- plt.tight_layout() adjusts spacing so labels do not get clipped at the edges.
- Save portfolio_analyzer.py.
You will not see a visible change yet because the chart has not been saved to a file. The next chunk handles that.
Save and display the chart
- Directly below the code you just added, add these lines to save the chart and clean up:
plt.savefig("portfolio_performance.png")
print("\nChart saved as 'portfolio_performance.png'")
plt.close()
What does this code do?
- plt.savefig("portfolio_performance.png") writes the current figure to a PNG image file in your project folder.
- The print() statement confirms the file was created so you know the script finished successfully.
- plt.close() frees the figure from memory. This prevents resource leaks when scripts generate multiple charts.
- Save portfolio_analyzer.py.
- Run the script in your terminal:
python portfolio_analyzer.py
- You should see the full portfolio report printed in your terminal, followed by the line Chart saved as 'portfolio_performance.png'.
- Open the portfolio-analyzer folder in File Explorer (Windows) to see portfolio_performance.png. Double-click the file to view your chart.
Don't see the PNG file?
- Make sure you saved portfolio_analyzer.py before running it. Unsaved changes will not execute.
- Check that plt.savefig() appears BEFORE plt.close() in your code. Closing the figure first produces a blank image.
- Confirm your terminal is in the portfolio-analyzer folder. The PNG saves to whatever directory the terminal is pointing at.
help me troubleshoot why my chart is not saving correctly
✔️ Awesome, I've got everything!
Great. Double check you have saved your file.
ⓧ I'd like to double check the full code
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
# Define the stocks and time period
tickers = ["AAPL", "MSFT", "TSLA"]
period = "1y"
# Download historical closing prices
data = yf.download(tickers, period=period)["Close"]
# Calculate daily percentage returns
daily_returns = data.pct_change().dropna()
# Calculate annualized metrics for each stock
trading_days = 252
annualized_returns = daily_returns.mean() * trading_days
annualized_volatility = daily_returns.std() * (trading_days ** 0.5)
# Calculate Sharpe ratio (risk-free rate = 5%)
risk_free_rate = 0.05
sharpe_ratios = (annualized_returns - risk_free_rate) / annualized_volatility
# Print individual stock metrics
print("=" * 60)
print("STOCK PORTFOLIO ANALYSIS REPORT")
print("=" * 60)
print(f"\n{'Stock':<8}{'Return':<12}{'Volatility':<14}{'Sharpe Ratio':<12}")
print("-" * 46)
for ticker in tickers:
ret = annualized_returns[ticker] * 100
vol = annualized_volatility[ticker] * 100
sharpe = sharpe_ratios[ticker]
print(f"{ticker:<8}{ret:<12.2f}%{vol:<13.2f}%{sharpe:<12.2f}")
# Calculate portfolio metrics (equal weight)
weights = [1/3, 1/3, 1/3]
portfolio_daily_return = (daily_returns * weights).sum(axis=1)
portfolio_annual_return = portfolio_daily_return.mean() * trading_days
portfolio_annual_volatility = portfolio_daily_return.std() * (trading_days ** 0.5)
portfolio_sharpe = (portfolio_annual_return - risk_free_rate) / portfolio_annual_volatility
print("-" * 46)
print(f"{'Portfolio':<8}{portfolio_annual_return*100:<12.2f}%{portfolio_annual_volatility*100:<13.2f}%{portfolio_sharpe:<12.2f}")
print("=" * 60)
print("\nSharpe Ratio Guide: > 1 = Good, > 2 = Great, < 0 = Losing money vs risk-free")
# Calculate cumulative returns (growth of $1)
cumulative_returns = (1 + daily_returns).cumprod()
# Create performance chart
plt.figure(figsize=(10, 6))
for ticker in tickers:
plt.plot(cumulative_returns.index, cumulative_returns[ticker], label=ticker)
plt.title("Portfolio Performance - Growth of $1")
plt.xlabel("Date")
plt.ylabel("Growth of $1")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig("portfolio_performance.png")
print("\nChart saved as 'portfolio_performance.png'")
plt.close()
Secret mission
Add a Correlation Matrix Heatmap
Your portfolio analyzer already calculates returns and risk. But how do you know if your stocks are actually diversified? A correlation matrix heatmap reveals whether your stocks move together or independently, giving you a visual answer to one of the most important questions in portfolio management.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally on your machine, so there are no ongoing cloud costs. Decide whether to keep your files and tools installed, or remove them.
Resources you used:
- The portfolio-analyzer folder on your Desktop (contains portfolio_analyzer.py, portfolio_performance.png, and correlation_matrix.png).
- Python libraries installed via pip (yfinance, pandas, matplotlib).
- Python 3.14.5 installed on your system.
- VS Code installed on your system.
Keep everything running
No action needed. Choose this if you plan to keep experimenting with your portfolio analyzer or want to reuse Python and VS Code for other projects.
- Your portfolio-analyzer folder stays on your Desktop, ready to run anytime.
- Python and VS Code remain installed for future projects.
- The pip libraries remain available for any Python script on your machine.
Pause - I'll come back to this later
Close VS Code to free up memory. Your project files and installed tools stay on disk so you can pick up where you left off.
- Close VS Code.
- Your portfolio-analyzer folder, Python, and all libraries remain installed.
- To resume later, open VS Code and reopen the portfolio-analyzer folder.
Delete - I don't want to use this again
Remove all project files, libraries, and tools from your machine.
- Delete the project folder by opening Command Prompt and running:
cd ~/Desktop
rm -rf portfolio-analyzer
On Windows, use this instead:
cd $HOME\Desktop
rmdir /s /q portfolio-analyzer
- Uninstall the Python libraries by running:
pip uninstall yfinance pandas matplotlib -y
- Uninstall Python:
- Press the Windows key and search for Add or remove programs.
- Search for Python in the apps list.
- Click the three dots next to Python 3.14.5 and select Uninstall.
- Uninstall VS Code:
- In the same Add or remove programs window, search for Visual Studio Code.
- Click the three dots next to it and select Uninstall.
Nice Work!
Nice Work!
You just built a real financial analysis tool with Python. Your script pulls live market data, crunches the numbers that portfolio managers care about, and produces professional visualizations.
You've learned how to:
- Used yfinance to download real stock market data and pandas to calculate daily returns, annualized returns, volatility, and the Sharpe ratio for individual stocks.
- Built an equal-weight portfolio and calculated portfolio-level metrics that measure combined performance and risk.
- Created a professional line chart with matplotlib showing the growth of $1 invested across all three stocks over time.
- Built a correlation matrix heatmap to visualize how your stocks move together and evaluate portfolio diversification.
Ready to quiz yourself?