Portfolio visualizer in Python with correlation analysis and paper trading

Portfolio visualizer in Python with correlation analysis and paper trading
Build a Portfolio Visualizer in Python, Understand Correlation Analysis, and Get Started with Quant Trading
A portfolio visualizer shows you how your investments behave together over time, but looking at a chart is only the first step. The real work starts when you ask whether the relationships you see are real, and whether they'll hold up when you test them on data you haven't looked at yet. This article walks through that process in Python, from building your own visualizer to running a live no-money simulation before you risk real capital.
The sequence matters. You start by visualizing your portfolio. Then you measure how assets relate to each other using correlation analysis. Next you check whether those relationships are genuine or just statistical noise (random fluctuations that don’t carry meaningful patterns). Finally you test a trading idea in real time without using real money. Each step feeds the next, and skipping any of them is where most beginners go wrong.
A quick note on data: the examples below use Yahoo Finance via the yfinance library, which is free and good enough for learning. Free data can have gaps, adjusted price errors, and occasional ticker changes, so treat the results as educational rather than production-ready. Always sanity-check your data before trusting any numbers.
Build Your Own Portfolio Visualizer in Python
Web-based tools like portfoliovisualizer.com are useful for a quick look. You can enter a few ticker symbols (short codes like SPY or AAPL) and see historical returns without writing any code. You have less control over the calculations, though, and it’s harder to use your own data or connect the results to the rest of your trading code.
With Python, you own the calculation. Here’s a basic example that downloads price data for three ETFs and plots their cumulative returns (how $1 invested at the start would have grown).
import yfinance as yf
import matplotlib.pyplot as plt
tickers = ["SPY", "TLT", "GLD"]
data = yf.download(tickers, start="2018-01-01", end="2024-01-01")["Adj Close"]
# Calculate daily returns
returns = data.pct_change().dropna()
# Calculate cumulative returns
cumulative = (1 + returns).cumprod()
# Plot
cumulative.plot(figsize=(12, 6))
plt.title("Cumulative Returns: SPY, TLT, GLD")
plt.ylabel("Growth of $1")
plt.xlabel("Date")
plt.legend(tickers)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
This produces the same kind of chart you’d get from a web-based portfolio visualizer. The difference is that you can now swap in any assets, change the date range, or add your own calculations on top. For more on working with financial data in Python, see our free Python resources for quant trading.
The real advantage appears when you calculate measures the web tools don’t offer. Rolling correlation is a good example, and we’ll get to that shortly.
Adding a Correlation Analysis Heatmap
One of the most useful views in any portfolio visualizer is a correlation matrix. It shows how every pair of assets in your portfolio moves relative to each other. A value of +1 means they move in perfect lockstep. A value of -1 means they move in exactly opposite directions. A value near 0 means there’s no consistent straight-line relationship.
Worth noting: correlation measures whether returns tend to move together, not whether one asset causes the other to move. It only captures straight-line relationships, so two assets could have a complex dependency that a correlation number misses entirely.
import seaborn as sns
correlation_matrix = returns.corr()
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap="RdYlGn_r", center=0,
fmt=".2f", square=True)
plt.title("Asset Correlation Matrix (2018-2024)")
plt.tight_layout()
plt.show()
This heatmap shows which assets move differently enough to reduce the chance that your whole portfolio falls at once, and which ones tend to move together. If everything in your portfolio is dark red (high positive correlation), you’re essentially making one big bet on the same outcome.
How Negative Correlation Works in a Portfolio
Negative correlation means that when one asset goes up, the other tends to go down. A frequently cited example is stocks and long-term government bonds. During a stock market sell-off, investors have historically moved money into bonds, pushing bond prices up. That relationship isn’t guaranteed, though. It depends on the economic environment, and we’ll see a clear exception in a moment.
One practical point often gets missed when people first learn about negative correlation. It doesn’t just reduce your losses in bad periods. It also changes how gains and losses build on each other in your favor.
Consider two portfolios over a volatile year. Portfolio A holds only stocks and swings between +20% and -15% each quarter. Portfolio B holds 60% stocks and 40% bonds, where the bonds have a negative correlation to stocks, and might swing between +10% and -5%. The average quarterly return looks similar on paper, but Portfolio B ends the year with more money. That’s because losses hurt more than equivalent gains help. A 50% loss requires a 100% gain just to break even. Reducing the size of your worst losses (the biggest drop from a peak value down to a trough, before recovering) has an outsized effect on long-term growth.
You can measure this in Python by comparing the maximum drawdown of different portfolio mixes. Note that the code below uses fixed weights and does not rebalance. In practice, a 60/40 split drifts over time as prices move, so the actual weights at any point may differ from what you started with.
import numpy as np
# Create a simple 60/40 portfolio
weights = np.array([0.6, 0.0, 0.4]) # 60% SPY, 0% GLD, 40% TLT
portfolio_returns = returns.dot(weights)
# Calculate drawdown
cumulative_portfolio = (1 + portfolio_returns).cumprod()
rolling_max = cumulative_portfolio.cummax()
drawdown = (cumulative_portfolio - rolling_max) / rolling_max
print(f"Max drawdown (60/40 portfolio): {drawdown.min():.2%}")
print(f"Max drawdown (100% SPY): {((1 + returns['SPY']).cumprod() / (1 + returns['SPY']).cumprod().cummax() - 1).min():.2%}")
Over many historical periods, the 60/40 portfolio had a smaller worst loss from peak to trough than the all-stock portfolio. That’s not guaranteed in every window, though. In 2022, both stocks and bonds fell together because rising interest rates hurt both asset classes at the same time. A portfolio built on the assumption that bonds always cushion stock losses ran into serious trouble that year.
That’s why a single correlation number calculated over the full history can mislead you. You need to see how the relationship changes over time. Here’s how to compute a rolling 90-day correlation between SPY and TLT:
# Rolling 90-day correlation between stocks and bonds
rolling_corr = returns["SPY"].rolling(window=90).corr(returns["TLT"])
rolling_corr.plot(figsize=(12, 4))
plt.title("Rolling 90-Day Correlation: SPY vs TLT")
plt.ylabel("Correlation")
plt.axhline(0, color="black", linewidth=0.8, linestyle="--")
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Run this on the 2018-2024 data and you’ll see the correlation flip from negative to positive around 2022. That’s the kind of shift a static heatmap won’t show you.
Spurious Correlation: A Common and Expensive Mistake
Spurious correlation is when two things appear statistically related but have no real connection. The most famous example is the near-perfect correlation between U.S. spending on science and the number of suicides by hanging. Obviously one doesn’t cause the other. In financial data, spurious correlations look far more plausible, which is what makes them dangerous.
When you test many possible relationships between assets, indicators, and economic variables, some will show strong correlations purely by chance. If you have 1,000 variables and test every pair, you get nearly 500,000 combinations. If you use a test that accepts a 5% false-positive rate (meaning it flags a relationship as real even when it isn’t, 5% of the time), you’d expect around 25,000 of those combinations to look significant even if the underlying data is completely random.
This issue is called the multiple comparisons problem (testing many pairs raises the chance of false positives). It’s one major reason a strategy that looks good on historical data often fails with real money.
You can see this with random data.
import pandas as pd
# Generate 10 columns of random data
np.random.seed(42)
random_data = pd.DataFrame(
np.random.randn(252, 10),
columns=[f"series_{i}" for i in range(10)]
)
# Check correlations
random_corr = random_data.corr()
# Find the highest off-diagonal correlation
mask = np.triu(np.ones_like(random_corr, dtype=bool), k=1)
max_corr = random_corr.where(mask).max().max()
print(f"Highest spurious correlation among random series: {max_corr:.3f}")
Run this a few times and you’ll regularly see correlations of 0.15 to 0.25 between completely random series. With 252 data points (one year of trading days), that can look meaningful if you’re not expecting it.
Use separate data to check the idea. First, use 2015 to 2020 to find the relationship. Then see if it still holds from 2021 to 2024. If the correlation disappears on the later data, it was probably spurious. Developing the idea in one period and verifying it in a later period prevents many beginner mistakes.
For more on what correlation numbers actually measure, the pandas documentation on correlation methods is worth reading.
What Is Paper Trading and Why You Should Use It
Paper trading means running your trading strategy in real time with live market data but without using real money. Your code produces buy or sell orders and keeps track of what you would own. It also calculates how much money you would have made or lost, all without touching real capital. It’s a simulation that runs alongside the real market.
Paper trading is different from testing on historical data (called backtesting, where you run your strategy on past prices to see how it would have performed). When you backtest, you already know what happened, so there’s a risk of accidentally using future information to make past decisions. This mistake is called look-ahead bias, where your code uses tomorrow’s price to decide what to do today. Paper trading greatly reduces this problem because prices arrive one update at a time, as they do in real trading.
That said, paper trading doesn’t guarantee your strategy will work with real money. Paper orders often fill at cleaner prices than real orders, especially when markets move fast or when you’re trading something with low volume. You also won’t feel the psychological pressure of watching real money move. Keep both limitations in mind.
Most brokers offer paper trading accounts. Interactive Brokers and Alpaca both provide them. You can also build a simple paper trading loop in Python.
# Pseudocode for a paper trading loop
# (You’d connect this to a real data feed in practice)
portfolio = {"cash": 100000, "positions": {}}
trade_log = []
def on_new_price(ticker, price, timestamp):
# "decision" is the buy or sell output from your trading rule
decision = your_strategy(ticker, price)
if decision == "buy" and portfolio["cash"] >= price * 100:
portfolio["cash"] -= price * 100
portfolio["positions"][ticker] = portfolio["positions"].get(ticker, 0) + 100
trade_log.append({"time": timestamp, "action": "BUY",
"ticker": ticker, "price": price, "shares": 100})
elif decision == "sell" and portfolio["positions"].get(ticker, 0) >= 100:
portfolio["cash"] += price * 100
portfolio["positions"][ticker] -= 100
trade_log.append({"time": timestamp, "action": "SELL",
"ticker": ticker, "price": price, "shares": 100})
Paper trading helps you catch problems that historical testing misses. Your orders may fill at worse prices than you expected (called slippage). Your data may arrive late. Your code may fail when prices update live. You’ll also want to track transaction costs, because even brokers that advertise zero-commission trading still make money on the spread between the buy and sell price. Those costs add up and can turn a profitable-looking strategy into a losing one.
Run your strategy on paper for at least a few weeks before putting real money behind it. If you’re setting up your first paper trading environment, our guide to algorithmic trading platforms covers the tools that support it.
Correlation Analysis as a Starting Point for Quant Trading with Python
Quant trading means using mathematical rules and code to make trading decisions instead of relying on gut feeling or manual chart reading. The process covered in this article—building a portfolio visualizer, running correlation analysis, verifying relationships, and simulating trades without real money—is a solid introduction to how that workflow operates.
Correlation is a starting point, not a finished strategy. Finding that two assets move in opposite directions tells you something interesting, but it doesn’t tell you when to trade, how much to trade, or whether the profit after costs is worth the risk. Those questions require more work.
A useful trading idea needs a clear economic reason behind it. It also needs to keep working on later data and leave enough room to cover trading costs. The negative correlation between oil prices and airline stocks has a clear reason: fuel is a major operating cost for airlines. When oil drops, airline margins improve, and the stocks tend to rise. That relationship has held across many years, though its strength varies. Compare that to a correlation you found between copper futures and a specific biotech stock. Without a reason for the relationship, it’s likely spurious and will eventually break down.
Those middle steps—checking whether a relationship holds on later data and running it through a paper trading simulation—matter because they catch bad ideas before you trade them with real money. Most beginners find a pattern in historical data, assume it’s real, and skip straight to trading. That’s where the losses come from.
A Practical Next Step
Charts are only a starting point. To test an idea properly, you need code and a check that tells you whether the result holds up on data you didn’t use to find it.
If you’re just getting started, build the correlation heatmap from the code above using your own portfolio. Look at which assets move differently enough to reduce your overall risk and which ones just move together. Then pick one pair that interests you and check the rolling correlation over time. Record the date range you used, the correlation value you found, and whether the relationship looked similar when you tested it on a later period. That exercise will give you practical experience and make the rest of the topic easier to understand.