Momentum indicators
MACD, stochastic, stochastic RSI, Williams %R, CCI, rate of change, momentum and TRIX on candles, with the same results as TA-Lib.
- Category: Functions — technical indicators
- Keywords: momentum, oscillator, overbought, oversold, crossover, signal line, divergence, TA-Lib, MACD, moving average convergence divergence, signal line, histogram, stochastic, stochastic oscillator, slow stochastic, %K, %D, fast stochastic, STOCHF, stochastic RSI, StochRSI, STOCHRSI, Williams %R, WILLR, %R, commodity channel index, CCI, rate of change, ROC, ROCP, ROCR, MOM, TRIX, triple exponential average, stock market
- See also: Technical indicators, Volatility indicators and bands, Trend indicators, Volume indicators, Returns and risk, Window and series functions
Momentum is the speed of a price move. A momentum indicator tells how strong a rise or a fall is, and when it gets weaker. Many of them are oscillators: numbers that swing between fixed levels (like 0 and 100). Near the top level a share is called overbought (it rose a lot and may fall back); near the bottom level oversold.
These are series functions, like sma, ema, rsi and atr, with the same rules:
- Order: without
OVER, all result rows are one series in time order. With many symbols, always writeOVER (PARTITION BY symbol ORDER BY time). - Periods are whole numbers of candles, written as constants (
macd(close, 12, 26, 9)). You can leave out the ones at the end: they get the usual defaults. - Warm-up: the first rows are
NULLuntil there are enough candles. With the default periods:
| Function | Default periods | First value on candle | In general |
|---|---|---|---|
macd, macd_signal, macd_hist | 12, 26, 9 | 34 | slow + signal - 1 |
stoch_k, stoch_d | 14, 3, 3 | 18 | k + k_slowing + d - 2 |
stochf_k | 14 | 14 | k |
stochrsi_k, stochrsi_d | 14, 5, 3 | 21 | rsi_period + k + d - 1 |
willr | 14 | 14 | n |
cci | 20 | 20 | n |
roc, rocp, rocr, mom | 10 | 11 | n + 1 |
trix | 30 | 89 | 3n - 1 |
- WHERE runs first, and an indicator cannot be in the same
SELECTasSAMPLE BYorGROUP BY: make the candles in a subquery (see technical indicators). - NULL prices:
macd,stochrsiandtrixare built from EMAs or Wilder averages. One NULL price makes that row and every later rowNULL: leave NULL prices out withWHERE close IS NOT NULL. The others only look at a window of candles: they are NULL while the window holds the NULL, and then come back. - Same as TA-Lib: the formulas and the first row with a value match TA-Lib.
- Returns
DOUBLE. - One series function cannot be inside another (
ema(trix(close, 30), 9)): compute the first one in a subquery.
Example: Momentum of CITY's one-minute candles: MACD, stochastic, Williams %R and CCI (the last 5) (sample data: sample)
SELECT time, close, macd, stoch_k, willr, cci
FROM (SELECT time, close,
round(macd(close), 3) AS macd,
round(stoch_k(high, low, close), 1) AS stoch_k,
round(willr(high, low, close), 1) AS willr,
round(cci(high, low, close), 1) AS cci
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | macd (DOUBLE) | stoch_k (DOUBLE) | willr (DOUBLE) | cci (DOUBLE) |
|---|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | -0.093 | 35.2 | -66.7 | -6.3 |
| 2026-09-10T09:13:00.000Z | 505.1 | -0.091 | 29.3 | -55.6 | 16 |
| 2026-09-10T09:12:00.000Z | 504.8 | -0.109 | 21.5 | -72.2 | -57.3 |
| 2026-09-10T09:11:00.000Z | 504.5 | -0.099 | 28.9 | -84.2 | -80.9 |
| 2026-09-10T09:10:00.000Z | 504.6 | -0.054 | 38.8 | -78.9 | -57.7 |
(5 rows)
macd, macd_signal, macd_hist
Syntax:
macd(x [, fast [, slow [, signal]]])
macd_signal(x [, fast [, slow [, signal]]])
macd_hist(x [, fast [, slow [, signal]]])
macd(x, fast, slow, signal) OVER ([PARTITION BY ...] [ORDER BY ...])
MACD (moving average convergence divergence) shows the trend and its strength with three lines:
macd: the MACD line,EMA(fast) - EMA(slow)of the price. Above 0, the short-term average is above the long-term one: the price is going up.macd_signal: the signal line, an EMA of the MACD line oversignalcandles.macd_hist: the histogram,macd - macd_signal. It grows when the move gets stronger.
When the MACD line crosses above the signal line (the histogram turns from minus to plus), traders read it as a buy signal; crossing below is a sell signal.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
fast | whole number, 1 or more | the short EMA period; default 12 |
slow | whole number, 1 or more | the long EMA period; default 26 |
signal | whole number, 1 or more | the EMA period of the signal line; default 9 |
- Returns:
DOUBLE, in the unit of the price (for example dollars). - NULL: all three are
NULLfor the firstslow + signal - 2candles (33 with the defaults), like TA-Lib. Careful: one NULL price makes this and every later valueNULL. - Notes: when
fastis bigger thanslow, the two are swapped (like TA-Lib). Both EMAs start on candleslow, like TA-Lib'sMACD; a chart that starts the fast EMA earlier shows slightly different first values. Load much more history than you show.
Example: MACD, signal and histogram of CITY's one-minute candles (the last 5) (sample data: sample)
SELECT time, close, macd, signal, hist
FROM (SELECT time, close,
round(macd(close), 3) AS macd,
round(macd_signal(close), 3) AS signal,
round(macd_hist(close), 3) AS hist
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | macd (DOUBLE) | signal (DOUBLE) | hist (DOUBLE) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | -0.093 | -0.062 | -0.031 |
| 2026-09-10T09:13:00.000Z | 505.1 | -0.091 | -0.054 | -0.037 |
| 2026-09-10T09:12:00.000Z | 504.8 | -0.109 | -0.045 | -0.063 |
| 2026-09-10T09:11:00.000Z | 504.5 | -0.099 | -0.029 | -0.069 |
| 2026-09-10T09:10:00.000Z | 504.6 | -0.054 | -0.012 | -0.042 |
(5 rows)
Example: MACD crossovers: buy and sell signals of COAST on 10 September (sample data: sample)
SELECT time, close, hist,
CASE WHEN hist > 0 THEN 'BUY' ELSE 'SELL' END AS signal
FROM (SELECT time, close, hist, lag(hist) AS prev_hist
FROM (SELECT time, close, round(macd_hist(close), 3) AS hist
FROM ochl_minutes
WHERE symbol = 'COAST') a) b
WHERE time IN '2026-09-10'
AND ((hist > 0 AND prev_hist <= 0) OR (hist < 0 AND prev_hist >= 0))
ORDER BY time
LIMIT 6;
Result:
| time (TIMESTAMP) | close (DOUBLE) | hist (DOUBLE) | signal (STRING) |
|---|---|---|---|
| 2026-09-10T05:35:00.000Z | 380.8 | -0.026 | SELL |
| 2026-09-10T05:53:00.000Z | 380 | 0.02 | BUY |
| 2026-09-10T06:21:00.000Z | 380.7 | -0.041 | SELL |
| 2026-09-10T06:36:00.000Z | 380.4 | 0.03 | BUY |
| 2026-09-10T06:43:00.000Z | 379.4 | -0.031 | SELL |
| 2026-09-10T06:45:00.000Z | 380.2 | 0.013 | BUY |
(6 rows)
Example: Short periods on daily candles: MACD 3, 6, 3 of every symbol on the last day (sample data: sample)
SELECT time, symbol, close, macd, signal, hist
FROM (SELECT time, symbol, close,
round(macd(close, 3, 6, 3) OVER (PARTITION BY symbol ORDER BY time), 2) AS macd,
round(macd_signal(close, 3, 6, 3) OVER (PARTITION BY symbol ORDER BY time), 2) AS signal,
round(macd_hist(close, 3, 6, 3) OVER (PARTITION BY symbol ORDER BY time), 2) AS hist
FROM ochl_day
WHERE time >= '2026-08-23') t
WHERE time IN '2026-09-10'
ORDER BY symbol;
Result:
| time (TIMESTAMP) | symbol (SYMBOL) | close (DOUBLE) | macd (DOUBLE) | signal (DOUBLE) | hist (DOUBLE) |
|---|---|---|---|---|---|
| 2026-09-10T00:00:00.000Z | CITY | 504.9 | 1.02 | 0.2 | 0.83 |
| 2026-09-10T00:00:00.000Z | COAST | 376.1 | 0.61 | 0.83 | -0.22 |
| 2026-09-10T00:00:00.000Z | VOLT | 191.2 | 3.77 | 2.93 | 0.85 |
(3 rows)
stoch_k, stoch_d
Syntax:
stoch_k(high, low, close [, k [, k_slowing [, d]]])
stoch_d(high, low, close [, k [, k_slowing [, d]]])
stoch_k(high, low, close, k, k_slowing, d) OVER ([PARTITION BY ...] [ORDER BY ...])
The slow stochastic oscillator, from 0 to 100. It tells where the close is inside the range of the last k candles: 100 is at the highest high, 0 at the lowest low.
- The raw value is
(close - lowest low) / (highest high - lowest low) × 100over the lastkcandles. stoch_k(%K) is the SMA of the raw value overk_slowingcandles.stoch_d(%D) is the SMA of %K overdcandles: a slower line.
Above 80 is overbought, below 20 oversold. When %K crosses above %D in the oversold zone, traders read it as a buy signal.
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
close | number | the candle's close |
k | whole number, 1 or more | candles for the highest high and lowest low; default 14 |
k_slowing | whole number, 1 or more | the SMA period of %K; default 3 |
d | whole number, 1 or more | the SMA period of %D; default 3 |
- Returns:
DOUBLEfrom 0 to 100. - NULL: both are
NULLfor the firstk + k_slowing + d - 3candles (17 with the defaults). Like TA-Lib, %K waits for %D, sodalso changes when %K starts. A NULL price gives NULL while it is inside a window; then the values come back. - Notes: when the highest high equals the lowest low (a flat market), the raw value is
0. The same as TA-Lib'sSTOCHwith SMA smoothing.
Example: Slow stochastic 14, 3, 3 of COAST's one-minute candles (the last 5) (sample data: sample)
SELECT time, close, k, d,
CASE WHEN k >= 80 THEN 'overbought' WHEN k <= 20 THEN 'oversold' ELSE 'normal' END AS zone
FROM (SELECT time, close,
round(stoch_k(high, low, close), 1) AS k,
round(stoch_d(high, low, close), 1) AS d
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | k (DOUBLE) | d (DOUBLE) | zone (STRING) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 87.3 | 87.2 | overbought |
| 2026-09-10T09:13:00.000Z | 376.2 | 88.6 | 82.5 | overbought |
| 2026-09-10T09:12:00.000Z | 376 | 85.8 | 71.2 | overbought |
| 2026-09-10T09:11:00.000Z | 375.5 | 73.1 | 52.8 | normal |
| 2026-09-10T09:10:00.000Z | 375.6 | 54.6 | 38.4 | normal |
(5 rows)
Example: Stochastic 5, 3, 3 on daily candles, every symbol (sample data: sample)
SELECT time, symbol, close, k, d
FROM (SELECT time, symbol, close,
round(stoch_k(high, low, close, 5, 3, 3) OVER (PARTITION BY symbol ORDER BY time), 1) AS k,
round(stoch_d(high, low, close, 5, 3, 3) OVER (PARTITION BY symbol ORDER BY time), 1) AS d
FROM ochl_day
WHERE time >= '2026-08-23') t
WHERE time >= '2026-09-08'
ORDER BY symbol, time;
Result:
| time (TIMESTAMP) | symbol (SYMBOL) | close (DOUBLE) | k (DOUBLE) | d (DOUBLE) |
|---|---|---|---|---|
| 2026-09-08T00:00:00.000Z | CITY | 497.5 | 37 | 30.7 |
| 2026-09-09T00:00:00.000Z | CITY | 504.6 | 43 | 37.1 |
| 2026-09-10T00:00:00.000Z | CITY | 504.9 | 50.4 | 43.5 |
| 2026-09-08T00:00:00.000Z | COAST | 377.2 | 81.5 | 77.3 |
| 2026-09-09T00:00:00.000Z | COAST | 380.1 | 70.7 | 78.2 |
| 2026-09-10T00:00:00.000Z | COAST | 376.1 | 45.6 | 65.9 |
| 2026-09-08T00:00:00.000Z | VOLT | 182.4 | 75 | 73.3 |
| 2026-09-09T00:00:00.000Z | VOLT | 187.3 | 78.4 | 75.8 |
| 2026-09-10T00:00:00.000Z | VOLT | 191.2 | 91 | 81.4 |
(9 rows)
Example: %K crosses above %D: buy signals of CITY's one-minute candles on 10 September (sample data: sample)
SELECT time, close, k, d
FROM (SELECT time, close, k, d, lag(k) AS prev_k, lag(d) AS prev_d
FROM (SELECT time, close,
round(stoch_k(high, low, close), 1) AS k,
round(stoch_d(high, low, close), 1) AS d
FROM ochl_minutes
WHERE symbol = 'CITY') a) b
WHERE time IN '2026-09-10' AND k > d AND prev_k <= prev_d AND k < 30
ORDER BY time
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | k (DOUBLE) | d (DOUBLE) |
|---|---|---|---|
| 2026-09-10T05:18:00.000Z | 504.4 | 18.9 | 16.3 |
| 2026-09-10T05:30:00.000Z | 504.5 | 26.2 | 25.5 |
| 2026-09-10T06:06:00.000Z | 505.5 | 15.6 | 13.8 |
| 2026-09-10T06:37:00.000Z | 504.5 | 11.5 | 10 |
| 2026-09-10T06:48:00.000Z | 503.2 | 8.4 | 6.4 |
(5 rows)
stochf_k
Syntax:
stochf_k(high, low, close [, k])
stochf_k(high, low, close, k) OVER ([PARTITION BY ...] [ORDER BY ...])
The fast stochastic %K: the raw stochastic value without smoothing, (close - lowest low) / (highest high - lowest low) × 100 over the last k candles. It reacts at once, so it jumps more than stoch_k.
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
close | number | the candle's close |
k | whole number, 1 or more | how many candles; default 14 |
- Returns:
DOUBLEfrom 0 to 100. - NULL:
NULLfor the firstk - 1candles. A NULL price gives NULL while it is inside the window; then the values come back. - Notes:
0when the highest high equals the lowest low. The same as the fast %K of TA-Lib'sSTOCHF. For the fast %D, take thesmaof it over 3 candles in an outer query.
Example: Fast %K and fast %D (SMA 3 of fast %K) of VOLT (sample data: sample)
SELECT time, close, fast_k, round(sma(fast_k, 3), 1) AS fast_d
FROM (SELECT time, close, round(stochf_k(high, low, close, 5), 1) AS fast_k
FROM ochl_day
WHERE symbol = 'VOLT' AND time >= '2026-08-23') t
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | fast_k (DOUBLE) | fast_d (DOUBLE) |
|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 181 | NULL | NULL |
| 2026-08-24T00:00:00.000Z | 178.5 | NULL | NULL |
| 2026-08-25T00:00:00.000Z | 176.8 | NULL | NULL |
| 2026-08-26T00:00:00.000Z | 174.2 | NULL | NULL |
| 2026-08-27T00:00:00.000Z | 173.3 | 11.2 | NULL |
| 2026-08-30T00:00:00.000Z | 173 | 18.5 | NULL |
| 2026-08-31T00:00:00.000Z | 172.6 | 17.2 | 15.6 |
| 2026-09-01T00:00:00.000Z | 169 | 15.3 | 17 |
| 2026-09-02T00:00:00.000Z | 171.5 | 48.8 | 27.1 |
| 2026-09-03T00:00:00.000Z | 176 | 87 | 50.4 |
| 2026-09-06T00:00:00.000Z | 180.1 | 77.1 | 71 |
| 2026-09-07T00:00:00.000Z | 176.9 | 57.8 | 74 |
| 2026-09-08T00:00:00.000Z | 182.4 | 89.9 | 74.9 |
| 2026-09-09T00:00:00.000Z | 187.3 | 87.5 | 78.4 |
| 2026-09-10T00:00:00.000Z | 191.2 | 95.4 | 90.9 |
(15 rows)
stochrsi_k, stochrsi_d
Syntax:
stochrsi_k(x [, rsi_period [, k [, d]]])
stochrsi_d(x [, rsi_period [, k [, d]]])
stochrsi_k(x, rsi_period, k, d) OVER ([PARTITION BY ...] [ORDER BY ...])
The stochastic RSI, from 0 to 100. It puts the stochastic formula on the RSI values instead of the prices: where is today's RSI inside the range of the last k RSI values? It moves faster than the RSI and reaches overbought (above 80) and oversold (below 20) more often.
stochrsi_k(%K):(RSI - lowest RSI) / (highest RSI - lowest RSI) × 100over the lastkRSI values.stochrsi_d(%D): the SMA of %K overdcandles.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
rsi_period | whole number, 1 or more | the RSI period; default 14 |
k | whole number, 1 or more | how many RSI values for the range; default 5 |
d | whole number, 1 or more | the SMA period of %D; default 3 |
- Returns:
DOUBLEfrom 0 to 100. - NULL: both are
NULLfor the firstrsi_period + k + d - 2candles (20 with the defaults). Careful: the RSI inside is a Wilder average, so one NULL price makes this and every later valueNULL. - Notes:
0when the RSI did not change over thekvalues. The same as TA-Lib'sSTOCHRSI(fast %K and fast %D).
Example: Stochastic RSI 14, 5, 3 of CITY's one-minute candles (the last 5) (sample data: sample)
SELECT time, close, rsi14, k, d
FROM (SELECT time, close,
round(rsi(close, 14), 1) AS rsi14,
round(stochrsi_k(close), 1) AS k,
round(stochrsi_d(close), 1) AS d
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | rsi14 (DOUBLE) | k (DOUBLE) | d (DOUBLE) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 47.6 | 69.4 | 82.4 |
| 2026-09-10T09:13:00.000Z | 505.1 | 50.1 | 100 | 59.3 |
| 2026-09-10T09:12:00.000Z | 504.8 | 46.2 | 77.8 | 25.9 |
| 2026-09-10T09:11:00.000Z | 504.5 | 42 | 0 | 3.6 |
| 2026-09-10T09:10:00.000Z | 504.6 | 43 | 0 | 3.6 |
(5 rows)
willr, williams_r
Syntax:
willr(high, low, close [, n])
williams_r(high, low, close [, n])
willr(high, low, close, n) OVER ([PARTITION BY ...] [ORDER BY ...])
Williams %R, from -100 to 0. Like the stochastic, it shows where the close is inside the range of the last n candles, but counted down from the top: 0 is at the highest high, -100 at the lowest low. Above -20 is overbought, below -80 oversold. williams_r is the same function.
%R = (highest high - close) / (highest high - lowest low) × -100
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
close | number | the candle's close |
n | whole number, 1 or more | how many candles; default 14 |
- Returns:
DOUBLEfrom -100 to 0. - NULL:
NULLfor the firstn - 1candles. A NULL price gives NULL while it is inside the window; then the values come back. - Notes:
%R = fast stochastic - 100. When the highest high equals the lowest low, the result is0(like TA-Lib'sWILLR).
Example: Williams %R 5 of every symbol on the last three days (sample data: sample)
SELECT time, symbol, close, wr,
CASE WHEN wr >= -20 THEN 'overbought' WHEN wr <= -80 THEN 'oversold' ELSE 'normal' END AS zone
FROM (SELECT time, symbol, close,
round(williams_r(high, low, close, 5) OVER (PARTITION BY symbol ORDER BY time), 1) AS wr
FROM ochl_day
WHERE time >= '2026-08-23') t
WHERE time >= '2026-09-08'
ORDER BY symbol, time;
Result:
| time (TIMESTAMP) | symbol (SYMBOL) | close (DOUBLE) | wr (DOUBLE) | zone (STRING) |
|---|---|---|---|---|
| 2026-09-08T00:00:00.000Z | CITY | 497.5 | -60.9 | normal |
| 2026-09-09T00:00:00.000Z | CITY | 504.6 | -44.8 | normal |
| 2026-09-10T00:00:00.000Z | CITY | 504.9 | -43.1 | normal |
| 2026-09-08T00:00:00.000Z | COAST | 377.2 | -22.9 | normal |
| 2026-09-09T00:00:00.000Z | COAST | 380.1 | -53.9 | normal |
| 2026-09-10T00:00:00.000Z | COAST | 376.1 | -86.3 | oversold |
| 2026-09-08T00:00:00.000Z | VOLT | 182.4 | -10.1 | overbought |
| 2026-09-09T00:00:00.000Z | VOLT | 187.3 | -12.5 | overbought |
| 2026-09-10T00:00:00.000Z | VOLT | 191.2 | -4.6 | overbought |
(9 rows)
Example: %R is the fast stochastic minus 100 (sample data: sample)
SELECT time, close,
round(willr(high, low, close, 5), 2) AS willr5,
round(stochf_k(high, low, close, 5) - 100, 2) AS fast_k_minus_100
FROM ochl_day
WHERE symbol = 'COAST' AND time >= '2026-09-03'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | willr5 (DOUBLE) | fast_k_minus_100 (DOUBLE) |
|---|---|---|---|
| 2026-09-03T00:00:00.000Z | 373.2 | NULL | NULL |
| 2026-09-06T00:00:00.000Z | 375.4 | NULL | NULL |
| 2026-09-07T00:00:00.000Z | 379.2 | NULL | NULL |
| 2026-09-08T00:00:00.000Z | 377.2 | NULL | NULL |
| 2026-09-09T00:00:00.000Z | 380.1 | -53.89 | -53.89 |
| 2026-09-10T00:00:00.000Z | 376.1 | -86.31 | -86.31 |
(6 rows)
cci
Syntax:
cci(high, low, close [, n])
cci(high, low, close, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The commodity channel index. It measures how far the typical price (high + low + close) / 3 is from its average of the last n candles, compared with the usual distance. Most values are between -100 and +100. Above +100 the price is unusually high (a strong rise, or overbought); below -100 unusually low.
CCI = (typical price - SMA of the typical price) / (0.015 × mean deviation). The mean deviation is the average distance of the n typical prices from their SMA.
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
close | number | the candle's close |
n | whole number, 1 or more | how many candles; default 20 |
- Returns:
DOUBLE(no fixed range). - NULL:
NULLfor the firstn - 1candles. A NULL price gives NULL while it is inside the window; then the values come back. - Notes:
0when all typical prices of the window are equal. The same as TA-Lib'sCCI.
Example: CCI 20 of COAST's one-minute candles (the last 5) (sample data: sample)
SELECT time, close, cci20,
CASE WHEN cci20 > 100 THEN 'above +100' WHEN cci20 < -100 THEN 'below -100' ELSE 'inside' END AS channel
FROM (SELECT time, close, round(cci(high, low, close), 1) AS cci20
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | cci20 (DOUBLE) | channel (STRING) |
|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 148.5 | above +100 |
| 2026-09-10T09:13:00.000Z | 376.2 | 135.6 | above +100 |
| 2026-09-10T09:12:00.000Z | 376 | 129.4 | above +100 |
| 2026-09-10T09:11:00.000Z | 375.5 | 45.1 | inside |
| 2026-09-10T09:10:00.000Z | 375.6 | 43.4 | inside |
(5 rows)
Example: CCI 5 on daily candles, every symbol on the last day (sample data: sample)
SELECT symbol, close, cci5
FROM (SELECT time, symbol, close,
round(cci(high, low, close, 5) OVER (PARTITION BY symbol ORDER BY time), 1) AS cci5
FROM ochl_day) t
WHERE time IN '2026-09-10'
ORDER BY cci5 DESC;
Result:
| symbol (SYMBOL) | close (DOUBLE) | cci5 (DOUBLE) |
|---|---|---|
| VOLT | 191.2 | 108.6 |
| CITY | 504.9 | 56.2 |
| COAST | 376.1 | -38 |
(3 rows)
roc, rocp, rocr
Syntax:
roc(x [, n])
rocp(x [, n])
rocr(x [, n])
roc(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The rate of change: how much the price changed against the price n candles ago. The three functions give the same change in three forms:
| Function | Formula | 10% rise gives |
|---|---|---|
roc | (x / x n candles ago - 1) × 100 | 10 (percent) |
rocp | (x - x n candles ago) / x n candles ago | 0.1 (a fraction) |
rocr | x / x n candles ago | 1.1 (a ratio) |
Above 0 (above 1 for rocr), the price is higher than n candles ago. When ROC gets smaller while the price still rises, the move is losing speed.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 1 or more | how many candles back; default 10 |
- Returns:
DOUBLE. - NULL:
NULLfor the firstncandles, when this or the old price is NULL, and when the old price is0. - Notes: the same as TA-Lib's
ROC,ROCPandROCR.roc(close, 1)is the same as pct_change; for returns see returns and risk.
Example: 5-day rate of change of CITY in three forms (sample data: sample)
SELECT time, close,
round(roc(close, 5), 2) AS roc5_pct,
round(rocp(close, 5), 4) AS rocp5,
round(rocr(close, 5), 4) AS rocr5
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-08-23'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | roc5_pct (DOUBLE) | rocp5 (DOUBLE) | rocr5 (DOUBLE) |
|---|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 507.9 | NULL | NULL | NULL |
| 2026-08-24T00:00:00.000Z | 510.3 | NULL | NULL | NULL |
| 2026-08-25T00:00:00.000Z | 513.3 | NULL | NULL | NULL |
| 2026-08-26T00:00:00.000Z | 513.2 | NULL | NULL | NULL |
| 2026-08-27T00:00:00.000Z | 505.9 | NULL | NULL | NULL |
| 2026-08-30T00:00:00.000Z | 503.1 | -0.95 | -0.0095 | 0.9905 |
| 2026-08-31T00:00:00.000Z | 505.7 | -0.9 | -0.009 | 0.991 |
| 2026-09-01T00:00:00.000Z | 502.4 | -2.12 | -0.0212 | 0.9788 |
| 2026-09-02T00:00:00.000Z | 496.4 | -3.27 | -0.0327 | 0.9673 |
| 2026-09-03T00:00:00.000Z | 497.9 | -1.58 | -0.0158 | 0.9842 |
| 2026-09-06T00:00:00.000Z | 499 | -0.81 | -0.0081 | 0.9919 |
| 2026-09-07T00:00:00.000Z | 498.7 | -1.38 | -0.0138 | 0.9862 |
| 2026-09-08T00:00:00.000Z | 497.5 | -0.98 | -0.0098 | 0.9902 |
| 2026-09-09T00:00:00.000Z | 504.6 | 1.65 | 0.0165 | 1.0165 |
| 2026-09-10T00:00:00.000Z | 504.9 | 1.41 | 0.0141 | 1.0141 |
(15 rows)
Example: Which symbol rose most in the last 5 trading days? (sample data: sample)
SELECT symbol, close, roc5
FROM (SELECT time, symbol, close,
round(roc(close, 5) OVER (PARTITION BY symbol ORDER BY time), 2) AS roc5
FROM ochl_day) t
WHERE time IN '2026-09-10'
ORDER BY roc5 DESC;
Result:
| symbol (SYMBOL) | close (DOUBLE) | roc5 (DOUBLE) |
|---|---|---|
| VOLT | 191.2 | 8.64 |
| CITY | 504.9 | 1.41 |
| COAST | 376.1 | 0.78 |
(3 rows)
mom, momentum
Syntax:
mom(x [, n])
momentum(x [, n])
mom(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The momentum: the price now minus the price n candles ago, in the unit of the price. Above 0, the price is higher than n candles ago. momentum is the same function.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 1 or more | how many candles back; default 10 |
- Returns:
DOUBLE, in the unit of the price. - NULL:
NULLfor the firstncandles, and when this or the old price is NULL. - Notes: the same as TA-Lib's
MOM. To compare shares with different prices, use roc (percent) instead.
Example: 10-minute momentum of COAST (the last 5) (sample data: sample)
SELECT time, close, mom10
FROM (SELECT time, close, round(momentum(close), 2) AS mom10
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | mom10 (DOUBLE) |
|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 1.5 |
| 2026-09-10T09:13:00.000Z | 376.2 | 1.8 |
| 2026-09-10T09:12:00.000Z | 376 | 1.2 |
| 2026-09-10T09:11:00.000Z | 375.5 | 0.1 |
| 2026-09-10T09:10:00.000Z | 375.6 | 0.2 |
(5 rows)
Example: The first n rows have no old price (sample data: sample)
SELECT time, close, round(mom(close, 3), 1) AS mom3, round(close - lag(close, 3), 1) AS same
FROM ochl_day
WHERE symbol = 'VOLT' AND time >= '2026-09-03'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | mom3 (DOUBLE) | same (DOUBLE) |
|---|---|---|---|
| 2026-09-03T00:00:00.000Z | 176 | NULL | NULL |
| 2026-09-06T00:00:00.000Z | 180.1 | NULL | NULL |
| 2026-09-07T00:00:00.000Z | 176.9 | NULL | NULL |
| 2026-09-08T00:00:00.000Z | 182.4 | 6.4 | 6.4 |
| 2026-09-09T00:00:00.000Z | 187.3 | 7.2 | 7.2 |
| 2026-09-10T00:00:00.000Z | 191.2 | 14.3 | 14.3 |
(6 rows)
trix
Syntax:
trix(x [, n])
trix(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
TRIX: the change from one candle to the next, in percent, of a triple-smoothed EMA (the EMA of the EMA of the EMA of the price). The triple smoothing removes the small moves, so TRIX shows only the bigger trend. Above 0 the trend is up, below 0 down. Traders often add a signal line (a 9-candle EMA of TRIX) and watch the crossings.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 1 or more | the period of the three EMAs; default 30 |
- Returns:
DOUBLE(percent:0.05means +0.05% per candle). - NULL:
NULLfor the first3n - 2candles (88 with the default). Careful: one NULL price makes this and every later valueNULL. - Notes: the same as TA-Lib's
TRIX. It needs many candles: use one-minute candles or a long daily history.
Example: TRIX 30 of CITY's one-minute candles (the last 5) (sample data: sample)
SELECT time, close, trix30
FROM (SELECT time, close, round(trix(close), 4) AS trix30
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | trix30 (DOUBLE) |
|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 0.0047 |
| 2026-09-10T09:13:00.000Z | 505.1 | 0.005 |
| 2026-09-10T09:12:00.000Z | 504.8 | 0.0053 |
| 2026-09-10T09:11:00.000Z | 504.5 | 0.0056 |
| 2026-09-10T09:10:00.000Z | 504.6 | 0.0059 |
(5 rows)
Example: TRIX and its signal line: leave the warm-up rows out before the EMA (sample data: sample)
SELECT time, trix15, round(ema(trix15, 9), 4) AS signal
FROM (SELECT time, trix15
FROM (SELECT time, round(trix(close, 15), 4) AS trix15
FROM ochl_minutes
WHERE symbol = 'COAST') a
WHERE trix15 IS NOT NULL) b
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | trix15 (DOUBLE) | signal (DOUBLE) |
|---|---|---|
| 2026-09-10T09:14:00.000Z | -0.0001 | -0.0035 |
| 2026-09-10T09:13:00.000Z | -0.0015 | -0.0044 |
| 2026-09-10T09:12:00.000Z | -0.0028 | -0.0051 |
| 2026-09-10T09:11:00.000Z | -0.0039 | -0.0057 |
| 2026-09-10T09:10:00.000Z | -0.0045 | -0.0061 |
(5 rows)