The Dragon (spine, belly & northern skin)
A fast +/-0.5 SD band on the 10-period mean of RL10. The spine is the centerline, the belly is the lower (southern) skin, and the northern skin is the upper band.
The Dragon is a tight band built on the 10-period mean of the RL10 line. Its spine is the centerline itself - the SMA(10) of RL10. The belly (the lower, or southern, skin) sits 0.5 SD below the spine, and the northern skin sits 0.5 SD above it.
Because it is built on a short, smoothed base, the Dragon hugs price as a noise boundary during trends and flips about six times faster than the River at trend inflection points - which is what makes price crossing the belly or the northern skin a meaningful early signal.
7.11e-14 on a 60-bar reference price series (Python vs JavaScript across the Dragon spine (centerline), belly (lower skin), and northern skin (upper) - float64 round-off only).Pythonpermalink →
import numpy as np
def _rl(values, n=10): # RL10 endpoint (see the RL10 page)
v = np.asarray(values, float); out = np.full(len(v), np.nan)
if n <= 0 or len(v) < n: return out
x = np.arange(n); xm = (n - 1) / 2.0; xd = x - xm
denom = float(np.sum(xd ** 2))
if denom == 0: return out
w = 1.0 / n + xm * xd / denom
out[n - 1:] = np.correlate(v, w, mode="valid")
return out
def _sma(values, n):
v = np.asarray(values, float); out = np.full(len(v), np.nan)
for i in range(n - 1, len(v)):
win = v[i - n + 1:i + 1]
if not np.isnan(win).any(): out[i] = win.mean()
return out
def _rolling_std(values, n):
v = np.asarray(values, float); out = np.full(len(v), np.nan)
for i in range(n - 1, len(v)):
win = v[i - n + 1:i + 1]
if not np.isnan(win).any(): out[i] = win.std() # population std
return out
def dragon(closes):
"""The Dragon - a fast +/-0.5 SD band on the 10-period mean of RL10.
spine = the centerline itself, SMA(10) of RL10
belly = spine - 0.5 SD (lower / southern skin)
northern_skin = spine + 0.5 SD (upper skin)
The Dragon hugs price as a noise boundary during trends and flips about six
times faster than the River at trend inflection points."""
spine = _sma(_rl(closes, 10), 10) # centerline
sd = _rolling_std(spine, 10)
return {"spine": spine, # centerline
"belly": spine - 0.5 * sd, # lower / southern skin
"northern_skin": spine + 0.5 * sd} # upper skin
JavaScriptpermalink →
// The Dragon - a fast +/-0.5 SD band on the 10-period mean of RL10.
// spine = the centerline itself, SMA(10) of RL10
// belly = spine - 0.5 SD (lower / southern skin)
// northern skin = spine + 0.5 SD (upper skin)
// Flips ~6x faster than the River at trend inflections.
function rl(closes, n = 10) { // RL10 endpoint (see the RL10 page)
const len = closes.length, out = new Array(len).fill(null);
if (n <= 0 || len < n) return out;
const sx = (n * (n - 1)) / 2, sx2 = (n * (n - 1) * (2 * n - 1)) / 6, d = n * sx2 - sx * sx;
if (d === 0) return out;
for (let e = n; e <= len; e++) {
let sy = 0, sxy = 0, bad = false;
for (let j = 0; j < n; j++) { const v = closes[e - n + j]; if (v == null || Number.isNaN(v)) { bad = true; break; } sy += v; sxy += j * v; }
if (bad) continue;
const m = (n * sxy - sx * sy) / d, b = (sy - m * sx) / n;
out[e - 1] = m * (n - 1) + b;
}
return out;
}
function sma(values, n) {
const len = values.length, out = new Array(len).fill(null);
let sum = 0, count = 0;
for (let i = 0; i < len; i++) {
const v = values[i];
if (v != null && !Number.isNaN(v)) { sum += v; count++; }
if (i >= n) { const o = values[i - n]; if (o != null && !Number.isNaN(o)) { sum -= o; count--; } }
if (i >= n - 1 && count === n) out[i] = sum / n;
}
return out;
}
function rollingStd(values, n) {
const len = values.length, out = new Array(len).fill(null);
for (let i = n - 1; i < len; i++) {
let s = 0, c = 0;
for (let j = i - n + 1; j <= i; j++) { const v = values[j]; if (v != null && !Number.isNaN(v)) { s += v; c++; } }
if (!c) continue;
const mn = s / c; let sq = 0;
for (let j = i - n + 1; j <= i; j++) { const v = values[j]; if (v != null && !Number.isNaN(v)) sq += (v - mn) * (v - mn); }
out[i] = Math.sqrt(sq / c);
}
return out;
}
export function dragon(closes) {
const spine = sma(rl(closes, 10), 10); // centerline
const sd = rollingStd(spine, 10);
return {
spine, // centerline
belly: spine.map((c, i) => (c != null && sd[i] != null) ? c - 0.5 * sd[i] : null), // lower / southern skin
northernSkin: spine.map((c, i) => (c != null && sd[i] != null) ? c + 0.5 * sd[i] : null), // upper skin
};
}
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.