This article shows you how to use a simple statistical tool called the Z-Score to find stocks that might be trading at extreme prices. We'll build a basic detection system in Python that flags when prices look unusually high or low.
Z-Scores are everywhere in statistics, but they're surprisingly useful for trading too. By measuring how "weird" a current price is compared to recent history, you can identify moments when a stock might be due for a correction.
Most algo trading content gives you theory.
This gives you the code.3 Python strategies. Fully backtested. Colab notebook included.
Plus a free ebook with 5 more strategies the moment you subscribe.5,000 quant traders already run these:
Subscribe | AlgoEdge Insights
What You'll Learn
- What the strategy is
- Why it works
- How to implement it in Python
- How to test it
- What results to expect
Understanding the Idea
Think of a Z-Score like a "weirdness meter" for prices. It tells you how far the current price is from what's been normal lately.
Imagine you track your daily coffee spending. Most days you spend around $5. If one day you spend $15, that's unusual. A Z-Score quantifies exactly how unusual.
In trading terms, we compare today's stock price against a rolling average of recent prices. The formula divides the difference by standard deviation, giving us a number typically between -3 and +3.
A Z-Score of +2 means the price is two standard deviations above average. That's pretty high. A score of -2 means it's unusually low.
Most prices hover near zero. When they drift to extremes (above +1.5 or below -1.5), something interesting might be happening.
Why This Strategy Can Work
Markets tend to overreact. When prices spike too high or crash too low, they often revert toward their average. This is called mean reversion.
Z-Scores help you catch these moments mathematically instead of guessing. When a stock hits a Z-Score of +2, it's statistically rare. Either something fundamental changed, or the market got carried away.
The idea isn't that extreme prices always reverse. But they flag situations worth investigating.
Implementation in Python
First, grab some historical price data. We'll use yfinance because it's free and simple.
This gives us a few years of Apple's closing prices to work with.
Now we calculate the rolling Z-Score. We need a rolling mean and rolling standard deviation.
Each day, this compares the current price against the last 30 days. The result shows how unusual today's price is.
import yfinance as yf
import pandas as pd
ticker = yf.Ticker("AAPL")
df = ticker.history(start="2021-01-01", end="2024-01-01")
close = df['Close']
window = 30 # 30-day lookback
rolling_mean = close.rolling(window).mean()
rolling_std = close.rolling(window).std()
z_score = (close - rolling_mean) / rolling_std
Enjoying this strategy so far? This is only a taste of what's possible.
Go deeper with my newsletter: longer, more detailed articles + full Google Colab implementations for every approach.
Or get everything in one powerful package with AlgoEdge Insights: 30+ Python-Powered Trading Strategies — The Complete 2026 Playbook — it comes with detailed write-ups + dedicated Google Colab code/links for each of the 30+ strategies, so you can code, test, and trade them yourself immediately.
Exclusive for readers: 20% off the book with code
MEDIUM20.Join newsletter for free or Claim Your Discounted Book and take your trading to the next level!
Building the Strategy
To generate trading signals, we define thresholds. When the Z-Score crosses below -1.5, the stock might be oversold. When it crosses above +1.5, it might be overbought.
A signal of 1 means "consider buying." A signal of -1 means "consider selling or shorting." Zero means hold or stay out.
You can adjust those thresholds. Using ±2 gives fewer but more extreme signals. Using ±1 gives more frequent signals but with weaker conviction.
df['z_score'] = z_score
df['signal'] = 0
df.loc[df['z_score'] < -1.5, 'signal'] = 1 # Buy signal
df.loc[df['z_score'] > 1.5, 'signal'] = -1 # Sell signal
Backtesting the Idea
To evaluate performance, we calculate returns when following the signals. We also measure risk-adjusted performance using the Sharpe ratio.
The Sharpe ratio measures return per unit of risk. Above 1.0 is decent. Max drawdown shows the worst peak-to-trough decline.
df['returns'] = close.pct_change()
df['strategy_returns'] = df['signal'].shift(1) * df['returns']
total_return = (1 + df['strategy_returns']).cumprod().iloc[-1] - 1
sharpe = df['strategy_returns'].mean() / df['strategy_returns'].std() * (252 ** 0.5)
max_drawdown = (df['strategy_returns'].cumsum() - df['strategy_returns'].cumsum().cummax()).min()
print(f"Total Return: {total_return:.2%}")
print(f"Sharpe Ratio: {sharpe:.2f}")
print(f"Max Drawdown: {max_drawdown:.2%}")
Results and Insights
In trending markets, this strategy struggles. If a stock keeps climbing, it stays overbought and the short signals lose money.
In choppy, range-bound markets, Z-Score signals work better. Prices bounce between extremes and mean reversion plays out.
Typical results show modest returns with lower volatility than buy-and-hold. The strategy often reduces drawdowns but may underperform during strong bull runs.
Limitations
Trending markets break it. Strong uptrends or downtrends can stay extreme for months.
The window size matters a lot. A 30-day window behaves differently than 90 days. There's no perfect choice.
Transaction costs aren't included. Frequent signals can eat into returns.
Past statistics don't predict future behavior. A stock can stay "unusual" longer than your account can stay solvent.
Works better as a filter than a standalone system. Combine it with other indicators.
Conclusion
Z-Scores offer a simple way to quantify whether prices look extreme. The math is straightforward, and the intuition is clear: unusual prices sometimes snap back to normal.
This isn't a magic formula. It's a tool for generating hypotheses about which stocks deserve attention. Combine it with fundamental analysis or other technical indicators.
Try adjusting the lookback window, thresholds, and test on different stocks. The best way to learn is by experimenting with real data.
Most algo trading content gives you theory.
This gives you the code.3 Python strategies. Fully backtested. Colab notebook included.
Plus a free ebook with 5 more strategies the moment you subscribe.5,000 quant traders already run these:
Subscribe | AlgoEdge Insights