Indicator Code · Owl Group Trading
R10 / Range Stat
One-tenth of the typical daily range (mean+stddev of high-low over 30 prior bars), the standard minimum-manageable-risk sizing box.
R10 is the range stat divided by 10: (mean + population standard deviation of the daily high-low range) over the 30 bars strictly before the current day, then divided by 10. It represents one-tenth of the typical daily range — the standard minimum-manageable-risk box used to size positions. The strictly-before window keeps the value free of look-ahead so it can drive next-session sizing.
Verified. Python and JavaScript implementations agree to
1.11e-16 on a 60-bar reference high/low series (canonical Python (edge-scan) vs JavaScript, comparable positions).Pythonpermalink →
import numpy as np
def r10(high, low):
"""R10 / Range Stat: one-tenth of the typical daily range.
R10 = (mean(range) + population_stddev(range)) / 10 computed over the 30
EOD bars STRICTLY BEFORE the current bar (the current bar is excluded so the
value is safe for no-look-ahead sizing). ``range`` is high - low per bar.
This is the standard minimum-manageable-risk box used for position sizing:
a risk unit of one-tenth of the typical daily range.
Faithful to edge-scan ``_rangestat_from_window`` / ``compute_rangestat_for_date``
(n_div=10, fixed 30-bar strictly-before lookback).
Args:
high: sequence of bar highs, ascending by date.
low: sequence of bar lows, ascending by date.
Returns:
list aligned to the input: r10[i] uses the 30 bars before index i;
None where fewer than 2 prior bars are available.
"""
high = np.asarray(high, dtype=float)
low = np.asarray(low, dtype=float)
ranges = high - low
out = []
for i in range(len(ranges)):
window = ranges[max(0, i - 30):i] # 30 bars STRICTLY BEFORE bar i
if len(window) < 2:
out.append(None)
continue
mean = float(np.mean(window))
std_pop = float(np.std(window, ddof=0)) # population stddev
out.append((mean + std_pop) / 10.0)
return out
JavaScriptpermalink →
/**
* R10 / Range Stat: one-tenth of the typical daily range.
*
* R10 = (mean(range) + populationStdDev(range)) / 10 over the 30 EOD bars
* STRICTLY BEFORE the current bar (current bar excluded -> no look-ahead).
* `range` is high - low per bar. This is the standard minimum-manageable-risk
* box used for position sizing.
*
* Faithful to edge-canvas calcR10 (window = slice(-(n+1), -1), n<=30).
*
* @param {number[]} high - bar highs, ascending by date
* @param {number[]} low - bar lows, ascending by date
* @returns {(number|null)[]} r10[i] uses the 30 bars before index i;
* null where fewer than 2 prior bars exist
*/
function r10(high, low) {
const out = [];
for (let i = 0; i < high.length; i++) {
const n = Math.min(i, 30); // bars available STRICTLY BEFORE i
if (n < 2) { out.push(null); continue; }
const ranges = [];
for (let j = i - n; j < i; j++) ranges.push(high[j] - low[j]);
const mean = ranges.reduce((s, v) => s + v, 0) / ranges.length;
const variance =
ranges.reduce((s, v) => s + (v - mean) ** 2, 0) / ranges.length;
out.push((mean + Math.sqrt(variance)) / 10.0); // population stddev
}
return out;
}
Improve Your Craft Every Morning
A short note from Dr. Ken Long on the craft of trading. One idea to think about and work on that day, drawn from decades of teaching and live trading. Free.
Your email:
Tue–Fri mornings. Unsubscribe anytime. No spam, no hype.