Measure asset correlation in Python with custom portfolio analysis

April 2, 2026
Facebook logo.
Twitter logo.
LinkedIn logo.
Newsletter issue count indicatorNewsletter total issues indicator

Measure asset correlation in Python with custom portfolio analysis

Build Your Own Portfolio Visualizer With Python and Negative Correlation Analysis

A portfolio visualizer helps you see how your investments behave together, not just individually. Tools like portfoliovisualizer.com let you do this without code, but they have limits. You can't customize the analysis or automate it. With Python, you can build your own portfolio visualizer that measures how assets moved relative to each other over any period you choose.

Negative correlation means two assets tend to move in opposite directions. When one goes up, the other goes down. This matters because a portfolio full of assets that all move together will fall together. Mixing in assets with negative correlation reduces the overall damage when markets drop. We'll compute the numbers in Python and plot them so you can inspect the relationships directly.

What Negative Correlation Tells You About Your Portfolio

Correlation is measured as a number between –1 and +1. A value of +1 means two assets move in perfect lockstep. A value of –1 means they move in perfectly opposite directions. A value near 0 means the two assets don't show a reliable pattern of moving together or apart.

Correlation does not tell you why two assets moved that way, and it does not guarantee they will keep doing it. It only describes what happened in the data you gave it.

Most stocks are positively correlated with each other, especially within the same sector. If you own five tech stocks, they'll probably all drop on the same bad-news day. That’s why investors look for assets with negative correlation to add balance.

A classic example is stocks and long-term U.S. Treasury bonds. During stock market selloffs, investors often move money into bonds, pushing bond prices up. The correlation between the S&P 500 and long-term Treasuries has historically been negative, though it shifts over time. You can read more about measuring portfolio risk (the chance your total investments lose value) to understand why this matters for your holdings.

Download Price Data and Compute Negative Correlation in Python

We'll convert prices into daily percentage changes before computing anything, because correlation works best when you compare how assets change from day to day rather than comparing raw price levels. Then we'll build a table that shows the correlation for every pair of assets in the portfolio.

We'll use auto_adjust=True when downloading data. This tells the library to use adjusted prices, which account for stock splits and cash dividends. Raw closing prices can distort return calculations if you don't adjust for those events.

import yfinance as yf
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# Download adjusted daily prices for a mixed portfolio
tickers = ["SPY", "TLT", "GLD", "XLE"]
data = yf.download(tickers, start="2018-01-01", end="2024-01-01", auto_adjust=True)["Close"]

# Compute daily returns
returns = data.pct_change().dropna()

# Build the correlation table
corr_matrix = returns.corr()
print(corr_matrix)

This gives you a table where each cell shows the correlation between two assets. SPY (an exchange-traded fund that tracks the S&P 500) and TLT (an exchange-traded fund holding long-term U.S. Treasury bonds) will likely show a negative number, meaning they tended to move in opposite directions over this period. GLD (an exchange-traded fund that tracks gold) often shows low or slightly negative correlation with stocks too.

pct_change() calculates the percentage change from one day to the next. dropna() removes rows with missing values so every asset is compared on the same dates. That matters because if one fund has a shorter history, the dates won't line up otherwise.

Your result also depends heavily on the dates you choose. A five-year window can tell a very different story than a one-year window, even for the same pair of assets.

Visualize the Correlation Matrix as a Heatmap

Numbers in a table are useful but hard to scan quickly. A heatmap makes negative correlation obvious at a glance.

plt.figure(figsize=(8, 6))
sns.heatmap(
    corr_matrix,
    annot=True,
    fmt=".2f",
    cmap="RdBu_r",
    center=0,
    vmin=-1,
    vmax=1,
)
plt.title("Portfolio Asset Correlation Matrix")
plt.tight_layout()
plt.show()

The RdBu_r color scheme shows negative correlations in blue and positive correlations in red. Setting center=0 keeps the color scale balanced around zero, so you can immediately spot which pairs have negative correlation.

Once the chart is up, here’s what to look for. If two assets show a value near +1, they usually rise and fall together. If the value is near 0, they often move independently. If it’s below 0, one may help offset the other when markets move.

You can change the dates you study or run the same code on a much larger set of holdings. For more on working with financial data in pandas, see this guide to pandas for market data analysis.

Why Negative Correlation Doesn’t Mean Free Diversification

There’s a tradeoff worth understanding. If two assets were perfectly negatively correlated, you could combine them in a way that greatly reduces day-to-day swings, but that wouldn’t automatically mean the portfolio earns zero return. The final return still depends on the size of each asset’s moves and how much of each you hold.

In practice, you don’t want perfect negative correlation anyway. You want some negative correlation so that when stocks drop 20%, your bonds or gold holdings cushion the fall instead of dropping 20% too. The practical aim is to hold assets that don’t all fall at the same time, so the portfolio’s losses are smaller in bad periods.

Correlation also changes over time. Stocks and bonds were negatively correlated for most of the 2010s, but in 2022 both fell simultaneously as interest rates rose. A number computed over the last ten years won’t always hold going forward.

You can track changes by recalculating correlation over the most recent 60 days each time. That means you recompute the number each day based on the past 60 trading days, so you see how the relationship evolves instead of relying on one overall number.

rolling_corr = returns["SPY"].rolling(60).corr(returns["TLT"])
rolling_corr.plot(title="60-Day Rolling Correlation: SPY vs TLT", figsize=(10, 4))
plt.axhline(0, color="gray", linestyle="--")
plt.ylabel("Correlation")
plt.tight_layout()
plt.show()

This plot shows periods where the SPY–TLT relationship was strongly negative and periods when it turned positive. A single table misses this change over time, while the moving plot reveals it.

If you want to go further, you can adjust how much money you put into each asset based on how those relationships change over time. The guide to portfolio optimization with Python covers how to do that systematically.

What to Do Next

You now have a working portfolio visualizer that computes and plots negative correlation between any set of assets. Correlation shows how assets moved relative to each other in your sample, and that relationship can change. A single number can hide important shifts. Recomputing it over time gives you a better view of how your portfolio actually behaves.

Try this with your own holdings, then rerun the chart on a one-year window and a five-year window. If the relationships look very different, that’s useful information worth paying attention to.