documentation/cookbook/sql/finance/rsi.md
The Relative Strength Index (RSI) is a momentum oscillator that measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions. RSI oscillates between 0 and 100, with readings above 70 typically indicating overbought conditions and below 30 indicating oversold.
You want to identify when an asset may be overbought or oversold based on recent price momentum. Raw price changes don't account for the relative strength of up moves versus down moves over a lookback period.
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
WITH changes AS (
SELECT
timestamp,
symbol,
close,
close - lag(close) OVER (PARTITION BY symbol ORDER BY timestamp) AS change
FROM market_data_ohlc_15m
WHERE symbol = @symbol
AND timestamp IN @lookback
),
gains_losses AS (
SELECT
timestamp,
symbol,
close,
CASE WHEN change > 0 THEN change ELSE 0 END AS gain,
CASE WHEN change < 0 THEN -change ELSE 0 END AS loss
FROM changes
),
smoothed AS (
SELECT
timestamp,
symbol,
close,
avg(gain, 'period', 14) OVER (PARTITION BY symbol ORDER BY timestamp) AS avg_gain,
avg(loss, 'period', 14) OVER (PARTITION BY symbol ORDER BY timestamp) AS avg_loss
FROM gains_losses
)
SELECT
timestamp,
symbol,
round(close, 5) AS close,
round(100 - (100 / (1 + avg_gain / avg_loss)), 2) AS rsi
FROM smoothed
ORDER BY timestamp;
The query:
lag()avg(value, 'period', N)100 - (100 / (1 + avg_gain / avg_loss)):::note EMA vs Wilder's smoothing
This recipe uses standard EMA smoothing via avg(value, 'period', 14) where α = 2/(N+1). Traditional RSI (Wilder's) uses α = 1/N, which is more gradual. For exact Wilder smoothing with a 14-period lookback, use avg(value, 'period', 27). Most modern platforms offer both variants.
:::
:::info Related documentation