Why Your RSI Differs Between Platforms
One session, one formula, different amounts of warm-upranking ·
2026-08-17 · 10×3
Where the minute bars actually are, by ET hourranking ·
2026-08-17 · 16×3
RSI(14) on identical closes: Wilder's smoothing against a simple averageseries ·
2026-08-17 · 60×4
Two definitions of one daily close, side by sideseries ·
2026-08-17 · 21×4
Reproducible Backtest in Python, No API Key
A 20/50 moving-average crossover on SPY, year by year, against holdingranking ·
2026-08-06 · 9×4
The same 20/50 rule on five liquid names, 2021 through 2025ranking ·
2026-08-06 · 5×4
Same rule, prior-session signal against same-session signal, SPY by yearranking ·
2026-08-06 · 9×4
One session, one formula, different amounts of warm-up
One session, one formula, different amounts of warm-up
| warmup_bars | rsi_wilder | rsi_simple |
|---|---|---|
| 0 | 49.07 | 49.07 |
| 1 | 42.35 | 49.07 |
| 2 | 39.73 | 49.07 |
| 5 | 38.03 | 49.07 |
| 10 | 43.08 | 49.07 |
| 20 | 46.95 | 49.07 |
| 40 | 47.14 | 49.07 |
| 80 | 46.92 | 49.07 |
| 160 | 46.91 | 49.07 |
| 250 | 46.91 | 49.07 |
the exact SQL behind every number
WITH
daily AS
(
SELECT arraySort(groupArray((day, px))) AS pts
FROM
(
SELECT
date AS day,
toFloat64(max(close)) AS px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'AAPL'
AND date >= '2025-01-02'
AND date <= '2026-06-30'
GROUP BY day
)
),
steps AS
(
SELECT arrayPopFront(arrayDifference(arrayMap(p -> p.2, pts))) AS chg
FROM daily
),
grid AS
(
SELECT
arrayMap(x -> greatest(x, 0.0), chg) AS up,
arrayMap(x -> greatest(-x, 0.0), chg) AS dn,
toInt64(length(chg)) AS e,
toInt64(arrayJoin([0, 1, 2, 5, 10, 20, 40, 80, 160, 250])) AS warmup
FROM steps
),
seeded AS
(
SELECT
warmup,
(arraySum(arraySlice(up, e - warmup - 13, 14)) / 14) * pow(13.0 / 14.0, warmup)
+ arraySum(arrayMap((g, j) -> g * pow(13.0 / 14.0, toInt64(j) - 1),
arrayReverse(arraySlice(up, e - warmup + 1, warmup)),
arrayEnumerate(arraySlice(up, e - warmup + 1, warmup)))) / 14 AS up_wilder,
(arraySum(arraySlice(dn, e - warmup - 13, 14)) / 14) * pow(13.0 / 14.0, warmup)
+ arraySum(arrayMap((g, j) -> g * pow(13.0 / 14.0, toInt64(j) - 1),
arrayReverse(arraySlice(dn, e - warmup + 1, warmup)),
arrayEnumerate(arraySlice(dn, e - warmup + 1, warmup)))) / 14 AS dn_wilder,
arraySum(arraySlice(up, e - 13, 14)) / 14 AS up_simple,
arraySum(arraySlice(dn, e - 13, 14)) / 14 AS dn_simple
FROM grid
)
SELECT
toString(warmup) AS warmup_bars,
round(100 - 100 / (1 + up_wilder / greatest(dn_wilder, 0.000001)), 2) AS rsi_wilder,
round(100 - 100 / (1 + up_simple / greatest(dn_simple, 0.000001)), 2) AS rsi_simple
FROM seeded
ORDER BY warmup
More from this analysisWhy Your RSI Differs Between Platforms
Where the minute bars actually are, by ET hour
ranking 16×3
→
RSI(14) on identical closes: Wilder's smoothing against a simple average
series 60×4
→
Two definitions of one daily close, side by side
series 21×4
→
How many of the 390 session minutes each US symbol traded in
ranking 10×2
→
See all 2,170 queries →