Linear Regression Slope: The Number Our Engine Returns
A linear regression slope is the gradient of the straight line that fits recent closes best. Our engine computes it as batch_linearreg_slope, over a default window of fourteen bars, and hands back a single number per bar with no scaling, no smoothing and no interpretation attached.
That plainness is the whole point, and it is also where people get hurt. The returned figure is measured in the price series' own units per bar, so it means something completely different on Bitcoin than on a token worth a hundredth of a cent — a gap this page puts at roughly seven billion to one on live data. Below is the arithmetic exactly as the crate runs it, the identity you can use to check any implementation, and three ways the raw output misleads.
What a linear regression slope measures
Fit a straight line through a run of closes so that the squared distances from the line are as small as they can be. The gradient of that line is the answer.
Positive means the fit tilts up over the window; negative means it tilts down. Steepness is how fast, in price per bar. Nothing about the construction predicts the next bar, and nothing about it says whether the fit is any good — a wildly scattered set of closes and a tidy staircase can share an identical gradient, because the residuals never reach the output.
Below is the steepest fourteen-bar fit on the whole tape we scanned: DODO, at 3.31% of price each bar. Price then gave back 8.1% across the following month, which is the first thing to know about this indicator and the reason the rest of the page is about mechanics rather than signals.
The exact slope our engine computes
batch_linearreg_slope does per bar. The intercept exists inside the helper and does not leave it, and nothing in the kernel reports how well the line actually fitted.Ordinary least squares in closed form, over an x-axis that counts bars.
How Vike computes it. For every bar i,batch_linearreg_slopetakes the fourteen closes ending at i inclusive and labels them x = 0 through 13. It computes the exact integer sums Σx and Σx², folds Σy and Σxy over the window, and returnsb = (p·Σxy − Σx·Σy) / (p·Σx² − (Σx)²). The intercept is computed too but thrown away — only the gradient leaves the function. Bars before the window fills return NaN.
When I ported this one I transcribed the crate kernel, transcribed the Python function beside it, then ran both across 243 Binance pairs and their full daily history. That is 344,012 compared values, worst absolute difference 1.876e-11, and every warm-up mask agreeing bar for bar.
Only 44.36% of the values came back bit-identical, and the cause is worth naming because it is not a bug in either file. CPython's builtin sum() compensates its floating-point error while the Rust port folds naively, and the crate's own module header says it does that deliberately to stay bit-compatible with its sibling ports. One rounding philosophy apart, eleven decimal places down.
The slope carries units, and that decides how you can use it
Here is the single most important property of the number, and it is invisible if you only ever look at one chart.
Because x counts bars and y is price, b is priced in dollars per bar. On the last bar of our Bitcoin tape it read −134.96. On Ethereum, −1.16. On Dogecoin, +0.00102, and on SHIB, +0.0000000199. Those four readings span a factor of about 6.8 billion, and every one of them describes an unremarkable two-week drift.
Normalise by price and the picture inverts completely: −0.212%, −0.061%, +0.938% and +0.315% of price per bar. Dogecoin, whose raw slope is the smallest of the three majors by five orders of magnitude, has by far the steepest trend of the four. Our engine does not do that division for you, and any threshold you set on the raw value is therefore a threshold about one asset at one price level.
RAD, below, shows the other end of the range: a fit sitting at −0.001% of price a bar, which is a line level to three decimal places. Compare that with any moving average reading, where the output is a price and so at least stays on the chart's own axis. A gradient is not a price, and it does not belong on the price scale.
The angle output, and where it stops working
Our crate also ships linearreg_angle, which is this same gradient passed through degrees(atan(b)).
Look at what that expression takes the arctangent of. A quantity in dollars per bar goes into a function whose argument is supposed to be a pure ratio, so the result depends on how expensive the asset is rather than on how steeply it moved. Above a gradient of about 57 the arctangent has already passed 89 degrees, and everything steeper is squeezed into the last fraction of a degree.
I measured how often that happens. On Bitcoin, 69.9% of the 3,274 angle readings sat beyond 89 degrees, so the output was effectively pinned for two thirds of that history. Ethereum reached the ceiling on 4.0% of bars, and Dogecoin never got there at all — 0.0%, because its prices stay small enough that the arctangent still has somewhere to go.
Identical code, then, gives an informative reading on a cheap asset and a saturated constant on an expensive one. Dividing by price before taking the arctangent fixes it. No default setting anywhere does that.
Warm-up, sign and an identity you can check
Three smaller details separate a correct reimplementation from a plausible one.
Warm-up returns NaN, never zero. Across 243 tapes that is 3,159 unavailable readings, exactly thirteen per symbol — and the choice matters, because zero is a real slope value that means "flat" while NaN cannot be mistaken for anything. Several of our candlestick detectors initialise to zero instead and lose that distinction, which is a difference in kind rather than in style.
Then the sign census. Over 344,012 readings the gradient was positive 44.5% of the time and negative 55.5%, and it landed on exactly zero in 0.00% of cases — a least-squares fit through fourteen genuine prices essentially never comes out flat, so "the slope turned positive" is a thing that happens constantly rather than an event.
The identity is the useful part. linearreg returns a + b(p−1) and tsf returns a + b·p, both from this same fit, so subtracting one from the other must give back the gradient exactly. Measured over 59,118 bars, the largest discrepancy was 7.905e-14. That is floating-point noise. If your implementation fails that check, the bug is in the fit rather than in the slope itself, which is a much easier place to look. The GNS window below catches a sign change, at just over half a percent of price a bar.
Where linear regression slope fails
Lag first, since it is arithmetic rather than opinion.
A fourteen-bar fit is dominated by bars that are already a week old, so the gradient keeps rising for several sessions after a top. That is not a flaw to tune away — a shorter window reacts sooner and reports noise, exactly the trade every smoothed tool makes, as the trading indicators overview sets out.
Fit quality never reaches you. The function computes residuals nowhere, so a gradient through a clean trend and a gradient through violent chop are indistinguishable in the output. The crate does ship std_error for precisely this, and reading the two together is a habit I learned after being fooled by a confident-looking gradient over a window that was pure noise.
And a steep slope is a record, not a promise. POND, below, printed a fit rising at 1.30% of price per bar, and then fell 46.8% over the twenty sessions that followed. The kernel was right about every bar it read. It simply had nothing to say about the ones it had not.
Frequently asked questions
What does the linear regression slope indicator tell you? The gradient of a least-squares line through the last fourteen closes, in price units per bar. It describes the window and says nothing about what follows it.
Is there a good linear regression slope value? There is no threshold that transfers, because the raw figure scales with price — our four sample assets spanned a factor of 6.8 billion on one day. Divide by price first if you want a number that means the same thing on two charts.
How does linear regression slope differ from the angle output?
linearreg_angle is degrees(atan(slope)). On Bitcoin that saturated past 89 degrees on 69.9% of bars, so the angle carried less information than the gradient it came from.
Is linear regression slope the same as a moving average? No. An average returns a price level; this returns a rate of change, and the two live on different axes. Pairing it with a momentum tool like the MACD tells you more than pairing it with another trend measure.
Why does the indicator return nothing for the first bars? The window is not full, so there is no fit. Our engine returns NaN there rather than zero, for exactly thirteen bars at the default period.
This is educational material, not financial advice. A gradient describes closes that have already printed, every figure above was measured on past bars, and trading carries substantial risk of loss.