Calculating the Pearson correlation between Bitcoin and Ethereum in Python

By Caio Marchesani · 5 February 2025

In my previous post on correlation I talked about the Pearson coefficient and why it matters once you hold more than one asset. This is the practical part. I’m going to work through the actual calculation for Bitcoin and Ethereum in Python, using daily prices, so that anyone who wants to check the relationship for themselves can do it in a few minutes instead of taking a number from a chart someone posted.

Scatter chart of weekly Bitcoin returns against weekly Ethereum returns from November 2021 to November 2026, with a fitted line and a Pearson correlation of 0.82

A quick reminder of what the number means. The Pearson coefficient measures how strongly two series move together in a straight-line sense, and it sits between -1 and 1. A value of 1 means they move together perfectly, -1 means they move in exact opposition, and 0 means there is no linear relationship at all. For two large cryptocurrencies you will usually get something fairly high and positive. How high, and how much it changes over time, is the interesting part.

One thing I want to be clear about before the code. I calculate the correlation on daily returns, not on prices. Two prices that both trend upwards over a year will show a very high correlation even if their day-to-day moves have little to do with each other. Returns strip the trend out and tell you whether the two things actually react to the same news on the same day, which is what you care about if you hold both.

The data

For this example I used the daily BTC/USD and ETH/USD files from the Gemini exchange. They are ordinary CSV files with a date column and a close column, and they have a line of text above the headers, which is why there is a skiprows=1 in the code below. Any daily price file with a date and a close will do, as long as you have both assets over the same period.

The code

Two libraries: pandas to handle the tables, and scipy.stats for the correlation itself. You could do it with pandas alone using .corr(), but scipy also gives you the p-value, which I come back to further down.

import pandas as pd
from scipy import stats

btc = pd.read_csv("Gemini_BTCUSD_d.csv", skiprows=1)
eth = pd.read_csv("Gemini_ETHUSD_d.csv", skiprows=1)

# make sure both files are in date order, then work out daily returns
for df in (btc, eth):
    df["date"] = pd.to_datetime(df["date"])
    df.sort_values("date", inplace=True)
    df["ret"] = df["close"].pct_change()

# line the two series up on the same dates and drop the first row,
# which has no return because there is no previous day
merged = pd.merge(
    btc[["date", "ret"]], eth[["date", "ret"]],
    on="date", suffixes=("_btc", "_eth")
).dropna()

r, p = stats.pearsonr(merged["ret_btc"], merged["ret_eth"])
print(f"Pearson correlation: {r:.3f}")
print(f"p-value: {p:.3g}")

That is the whole thing. A few notes on it, because the small decisions matter more than the function call.

The sort matters. Exchange files sometimes come newest first, and pct_change works on whatever order the rows are in, so if you skip the sort you get the sign of every return reversed and the correlation is still “right”, which is the worst kind of error because nothing warns you. The merge on date matters too. If one file is missing a day and the other isn’t, you want those days dropped rather than quietly shifted against each other, and merging on the date column does that for you.

Reading the result

The coefficient is the headline number. Close to 1 and the two coins have been moving together day to day; close to 0 and they haven’t. The p-value tells you whether a correlation of that size could plausibly have come from random noise given the number of days you used. With a few years of daily data the p-value for BTC and ETH will be tiny, which confirms the relationship is real. It does not tell you anything about how strong or how useful the relationship is, and people mix those two things up all the time.

The more useful thing to do once this runs is to stop treating the correlation as a single number. Run it over a rolling window of 60 or 90 days and plot it. You will see it move around a great deal, and you will usually see it jump when the whole market sells off, which is exactly the moment you would want your two holdings to behave differently. What that means for a portfolio is the subject of the next post.

Related articles

About the author

Caio Marchesani is a hedge fund manager, trader and engineer, with an MEng in Mechanical Engineering from University College London and more than fifteen years applying quantitative models to energy and macro markets, including as founder of a London quantitative macro energy fund. He also invests in and builds businesses outside finance, and founded Acai Berry Foods, the açaí café brand that began on Brick Lane and now has shops in London, the UAE and New York.

Read the full biography

Scroll to Top