RL10 - Regression Line
The fitted endpoint of a 10-bar linear regression - a smoothed read of true price that filters candle noise.
RL10 fits a least-squares straight line to the last 10 bars and reads its value at the most recent bar (the regression endpoint). It expresses the underlying price path with the noise of individual candle wicks removed.
Traders read its slope to confirm a trend is intact, and watch for it to peak and roll over as an exhaustion signal that a move is complete. The 10-bar window is the default; a longer window (RL30) gives a slower, smoother line.
7.11e-14 on a 60-bar reference price series (canonical Python (np.correlate) vs JavaScript (loop) - float64 round-off only).Pythonpermalink →
import numpy as np
def rl10(values, n=10):
"""RL10 - the fitted value of an n-bar linear regression at the most
recent bar (the regression-line 'endpoint'). Canonical Owl Group Trading
implementation; vectorized with np.correlate for O(N) speed.
Returns an array the same length as `values`; the first n-1 entries are
NaN (not enough lookback). n defaults to 10, hence 'RL10'.
"""
values = np.asarray(values, dtype=float)
out = np.full(len(values), np.nan)
if n <= 0 or len(values) < n:
return out
# Fixed regression weights for x = [0, 1, ..., n-1] so the endpoint value
# equals sum(w_i * y_i) for each sliding window.
x = np.arange(n)
x_mean = (n - 1) / 2.0
x_diff = x - x_mean
denom = float(np.sum(x_diff ** 2))
if denom == 0:
return out
w = 1.0 / n + x_mean * x_diff / denom
out[n - 1:] = np.correlate(values, w, mode="valid")
return out
JavaScriptpermalink →
// RL10 - the fitted value of an n-bar linear regression at the most recent
// bar (the regression-line 'endpoint'). Canonical Owl Group Trading
// implementation. Returns an array the same length as `closes`; the first
// n-1 entries are null (not enough lookback). n defaults to 10, hence 'RL10'.
export function rl10(closes, n = 10) {
const len = closes.length;
const result = new Array(len).fill(null);
if (n <= 0 || len < n) return result;
// Fixed sums for x = [0, 1, ..., n-1]
const sumX = (n * (n - 1)) / 2;
const sumX2 = (n * (n - 1) * (2 * n - 1)) / 6;
const denom = n * sumX2 - sumX * sumX;
if (denom === 0) return result;
for (let end = n; end <= len; end++) {
const start = end - n;
let sumY = 0, sumXY = 0, hasNaN = false;
for (let j = 0; j < n; j++) {
const v = closes[start + j];
if (v == null || Number.isNaN(v)) { hasNaN = true; break; }
sumY += v;
sumXY += j * v;
}
if (hasNaN) continue;
// slope + intercept of the least-squares line, evaluated at x = n-1
const slope = (n * sumXY - sumX * sumY) / denom;
const intercept = (sumY - slope * sumX) / n;
result[end - 1] = slope * (n - 1) + intercept;
}
return result;
}
Improve Your Craft Every Morning
Daily commentary from Dr. Ken Long — what he's seeing in markets, how he's framing trades, and what's worth practicing today. Free.
Your email:
Tue–Fri mornings. Unsubscribe anytime. No spam, no hype.