Quant500 Academy

3. The linear regression indicator against the moving average

Level 6: Regression and Pricing Models

The linear regression indicator (LRI, for *Linear Regression Indicator*) is the channel's little brother, and probably the most elegant use of regression in technical analysis.

The idea is this: at each bar a regression line is fitted over the last N bars, and only the final value of that line is drawn, that is, the point where the line ends. Repeating the process bar by bar gives a continuous line that shows, statistically, where the price is expected to be. A 20-period linear regression indicator is the end value of a regression line fitted over those bars.

The interpretation resembles that of a moving average, but it has one advantage over it. Instead of drawing an average of past price action, it draws where a regression line would expect the price to be. That makes the linear regression indicator more sensitive than a moving average.

It is worth understanding why, because it is a rather elegant statistical argument. A moving average gives you the mean level of the window: if the price has been rising in a straight line for 20 sessions, the moving average stays anchored in the middle of the window, some 10 sessions behind. Regression, by contrast, estimates level and slope, and by evaluating the line at the last point it has already absorbed that slope. The result is a line that hugs the current price far more closely: less lag, in exchange for reacting more to abrupt moves.

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

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

# 2. Linear regression trend with pandas-ta
linreg = ta.linreg(data['Close'], length=50)
data['LINREG'] = linreg

# We convert index and column into numpy arrays
x_dates = data.index.to_numpy()
y_linreg = data['LINREG'].to_numpy()

# 3. Candlestick chart with the trend overlaid
ap = [mpf.make_addplot(y_linreg, color='red', width=1.5)]

mpf.plot(data, type='candle', style='yahoo', addplot=ap,
         title=f'{stock_symbol} con tendencia de regresion lineal',
         volume=True, figsize=(15, 10))

Unlike the previous module's channel, ta.linreg really is a rolling window function: it only looks backwards. On each row it uses the previous 50 bars and none after them, so it drags in no look-ahead bias and can be used inside a backtest without cheating. The price to pay is that the first 49 rows come out as NaN, because there is not enough window to fit the line.

That last point has practical consequences: if you later compute a signal by comparing the close with LINREG, those initial rows will produce comparisons against NaN, which in pandas are always false. It is best to decide explicitly what to do with them rather than letting the code decide for you in silence.

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.