Quant500 Academy

2. Regression channels: the trend and its volatility

Level 6: Regression and Pricing Models

Before getting into the mathematical description of pricing models, it is worth seeing how traders use regression in technical analysis, because it is the most direct and intuitive use of all.

In technical analysis, the linear regression indicator and regression channels stand out as tools that give the trader two things at once: a view on the direction of the trend and a measure of the potential volatility around that trend. Underneath they are pure statistical analysis applied to a chart: a quantifiable approach to market dynamics.

Channels are an important component of technical analysis and there are quite a few different techniques: the Fibonacci channel, Andrews' pitchfork, the Keltner channel. The linear regression channel is a three-line indicator that marks out the ceiling, the floor and the center of the price movement being analyzed.

The central line is the regression line fitted to the price. The upper channel line (UCL) and the lower one (LCL) are drawn a given number of standard deviations above and below, normally two. The space between UCL and LCL represents the range of movement expected for the asset given its past trend and volatility. When the price leaves the channel, it may be signaling an overextension and a possible return to the mean.

It is common to combine Bollinger bands and a regression channel to build strategies:

import pandas as pd
import yfinance as yf
import mplfinance as mpf
import pandas_ta as ta
import numpy as np

# 1. We download the NVIDIA data
start_date = '2020-08-01'
end_date = '2021-01-01'
stock_symbol = 'NVDA'
data = yf.download(stock_symbol, start=start_date, end=end_date)

# 2. Bollinger bands with pandas-ta
data.ta.bbands(close='Close', length=20, append=True)

# 3. Regression channel
x = np.array(range(len(data)))
y = data['Close'].values
slope, intercept = np.polyfit(x, y, 1)
data['Regression'] = slope * x + intercept

residuals = y - data['Regression']
std_error = np.std(residuals)

data['Upper Regression'] = data['Regression'] + (2 * std_error)
data['Lower Regression'] = data['Regression'] - (2 * std_error)

Note a detail that gets overlooked constantly: the variable x is not dates, it is an ordinal counter 0, 1, 2, 3... By regressing the price against that counter, the slope is read as dollars gained per bar, and weekend or holiday gaps disappear from the calculation.

And a still more important warning: this channel is fitted over the whole sample at once. The line at day 10 has been computed using the prices of day 100 as well. As a descriptive snapshot of a past stretch it is perfectly valid, but if you use it as it stands inside a backtest you are introducing look-ahead bias, because you are deciding with information that did not exist at that moment. To trade for real, the channel has to be recomputed at each bar using only the preceding window.

And a conceptual difference with Bollinger: Bollinger bands are drawn around a moving average that is recomputed bar by bar, whereas the regression channel is drawn around a static line fitted to the whole stretch.

To go deeper into this lesson

The rest of Quant500

What you are learning, applied to the index every day:

The model portfolio, weekly in your inbox

Every Saturday, its week in one minute: how it went, the best and the worst, and which insiders bought with their own money. Plus, the day the model is rebuilt, which stocks come in and which go out. A simulation, not advice. At most one email a week, no ads, no account; one-click unsubscribe. Made by one person: Pol Gracia.

A model portfolio with simulated results, not a personalized recommendation. Your email is used for this only: privacy.

Behind the Academy and the rest of Quant500 there is one person: Pol Gracia Serrahima.