Quickly compute your rolling beta to manage risk

August 2, 2025
Facebook logo.
Twitter logo.
LinkedIn logo.

Quickly compute your rolling beta to manage risk

Stocks don’t always move the way you expect.

Portfolio risk jumps when markets get volatile. Looking at the last value or average missing how risk evolves over time.

That’s why we use rolling metrics.

To see how our risk and performance evolves over time.

By reading today’s newsletter, you’ll get Python code to measure and use rolling beta so you can adjust risk in real time.

Let’s go!

Quickly compute your rolling beta to manage risk

Rolling beta measures how a stock’s sensitivity to market risk changes over time. It tracks the evolving relationship between an asset and broad market movements using a moving regression window.

Today’s portfolio risks are never static so understanding rolling beta’s history explains why this dynamic approach matters.

Beta’s roots come from the Capital Asset Pricing Model, developed in the 1960s, which treats sensitivity to the market as a constant number. Practitioners quickly saw that market environments and company events shift these relationships. Rolling beta came in as a method to capture risk evolution, adding real-world responsiveness to classic finance.

Rolling beta is now a foundational risk tool for portfolio managers.

Most professionals use rolling beta to track real-time risk, monitor asset correlations, and trigger timely rebalancing or hedging. In volatile periods, it gives quantifiable signals for reducing exposure or balancing sector weight.

Let's see how it works with Python.

Imports and setup

We use these libraries to collect historical market data, organize and store it efficiently, and work with dates and times. ArcticDB is an incredible tool to store petabytes of data in a local “DataFrame database.”

1import datetime as dt
2import arcticdb as adb
3import yfinance as yf

Here, we create a direct connection to a local database where we'll keep our financial data. Setting up this library once makes saving and reusing data much faster.

1arctic = adb.Arctic("lmdb://arcticdb_equity")
2lib = arctic.get_library("demo", create_if_missing=True)

This setup initializes our data environment so we can easily store results and access them later. The code creates a workspace that holds our downloaded information, reducing the need for repeated downloads.

Download and store market data

We define the time period to study, the daily frequency, and choose a mix of iconic global stocks and an index. We then fetch all the historical price data at once.

1start = dt.datetime(2013, 1, 1)
2end = dt.datetime(2022, 12, 31)
3freq = "1d"
4symbols = {
5    "^GSPC": "S&P 500",
6    "AAPL": "Apple",
7    "MSFT": "Microsoft",
8    "GOOG": "Google",
9    "AMZN": "Amazon",
10    "NVDA": "Nvidia",
11    "META": "Meta",
12    "TSLA": "Tesla",
13    "TSM": "TSMC",
14    "TCEHY": "Tencent",
15    "005930.KS": "Samsung",
16    "ORCL": "Oracle",
17    "ADBE": "Adobe",
18    "ASML": "ASML",
19    "CSCO": "Cisco",
20}
21
22hist = yf.download(list(symbols.keys()), interval=freq, start=start, end=end)

This block pulls daily data for each chosen company and index from yFinance source covering nearly a decade. We define our universe upfront, making our analysis clear and repeatable.

Clean and process price data

For each price type—like "Close" or "Open"—we save that data to our dataset. This means we can access any type of price history we want, organized for easy future use.

1for l in hist.columns.levels[0]:
2    lib.write(l, hist[l])
3
4hist_adj_close = lib.read("Close").data
5hist_adj_close_clean = hist_adj_close.ffill()
6hist_adj_close_clean.isnull().any().any()
7hist_daily_returns = hist_adj_close_clean.pct_change(1).iloc[1:]
8returns_sym = "hist/returns_Close_clean"
9lib.write(returns_sym, hist_daily_returns)

We loop through different categories of price information and write each one to our data library. This step gives us flexibility to analyze any aspect of the market data later.

We grab all historical closing prices, fill in any missing days with the latest available value, and check for gaps. We then calculate day-to-day returns and store them for analysis.

Calculate and visualize rolling betas

We focus on a more recent time window, then compare each stock’s day-to-day performance with the S&P 500. For each company, we calculate how much it tends to move in line with the market, updating our measure every six months or so.

1index_ticker = "^GSPC"
2roll_days = 130
3beta_start = dt.datetime(2018, 1, 1)
4beta_end = dt.datetime(2022, 12, 31)
5beta_returns = lib.read(returns_sym, date_range=(beta_start, beta_end)).data
6index_returns = beta_returns[index_ticker]
7stock_returns = beta_returns.drop(columns=index_ticker)
8
9rolling_cov = stock_returns.rolling(roll_days).cov(index_returns).iloc[roll_days - 1 :]
10rolling_index_var = index_returns.rolling(roll_days).var().iloc[roll_days - 1 :]
11rolling_beta = rolling_cov.divide(rolling_index_var, axis="index").rename(
12    columns=symbols
13)
14
15ax = rolling_beta.plot(grid=True, linewidth=0.9, title=f"Rolling {roll_days}-day beta")
16ax.legend(loc="upper left")

The result is a chart that looks like this.

By looking at performance in overlapping six-month periods, we see how each stock’s link to the wider market changes over time. We first measure how closely each one tracks the S&P 500, then turn this into an intuitive “beta” score.

A higher beta means a stock tends to move more than the market, while something near zero tracks it less closely. Finally, we plot these results together, letting patterns and differences stand out clearly. This gives us a practical view of risk and correlation across global leaders.

Your next steps

You can now pull, store, and analyze rolling betas for top global stocks. Try swapping in new tickers to compare other sectors or indices—just edit the symbols dictionary. Adjust the roll_days value to see short-term or long-term beta shifts. Tweaking the date range helps you spot different risk patterns over various market cycles.

Man with glasses and a wristwatch, wearing a white shirt, looking thoughtfully at a laptop with a data screen in the background.