Trend indicators
Is the price going up, down or sideways, and how strong is the move? ADX and DI, Aroon, parabolic SAR, Ichimoku, SuperTrend, linear regression and Heikin-Ashi candles.
- Category: Functions — technical indicators
- Keywords: cross_above, cross_below, crossover, crossunder, golden cross, death cross, moving average crossover, trend, trend strength, direction, up trend, down trend, sideways, directional movement, DMI, +DI, -DI, DX, average directional index, ADX, ADXR, Aroon, Aroon oscillator, parabolic SAR, SAR, stop and reverse, trailing stop, Ichimoku, Ichimoku cloud, kumo, tenkan-sen, conversion line, kijun-sen, base line, senkou span, chikou span, lagging span, SuperTrend, linear regression, LINEARREG, time series forecast, TSF, Heikin-Ashi, Heiken Ashi, HA candles, TA-Lib, TradingView, stock market
- See also: Technical indicators, Momentum indicators, Volatility indicators and bands, Volume indicators, Window and series functions, Correlation and regression (regr_slope), Candles cookbook
A trend is the main direction of the price over some time: up (higher highs and higher lows), down, or sideways (no clear direction). Trend indicators answer two questions for a trader: which way is the price going, and how strong is the move? Many traders only buy in an up trend and use a trend line as a trailing stop: a stop-loss price that moves up with the price, so you sell when the trend ends.
These indicators are series functions, like sma and ema. They give a value for every candle and follow 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). - Period:
nis a number of candles, a whole number. Every argument after the price columns has a default, soadx(high, low, close)is the usual 14-candle ADX. - WHERE runs first, and candles from
SAMPLE BYmust be made in a subquery, with the indicator outside (see technical indicators). - Warm-up: the first candles have no value (
NULL). With the default periods:
| Function | Default periods | First value on candle | NULL candles at the start |
|---|---|---|---|
plus_di, minus_di, dx | n = 14 | n + 1 = 15 | 14 |
adx | n = 14 | 2n = 28 | 27 |
adxr | n = 14 | 3n - 1 = 41 | 40 |
aroon_up, aroon_down, aroon_osc | n = 14 | n + 1 = 15 | 14 |
sar | 0.02, 0.2 | 2 | 1 |
ichimoku_tenkan | 9 | 9 | 8 |
ichimoku_kijun | 26 | 26 | 25 |
ichimoku_senkou_a | 9, 26, shift 26 | 26 + 26 = 52 | 51 |
ichimoku_senkou_b | 52, shift 26 | 52 + 26 = 78 | 77 |
ichimoku_chikou | shift 26 | 1 (but the last 26 candles are NULL) | 0 |
supertrend, supertrend_direction | n = 10, 3 | n = 10 | 9 |
linearreg, linearreg_slope, linearreg_intercept, linearreg_angle, tsf | n = 14 | n = 14 | 13 |
ha_open, ha_high, ha_low, ha_close | none | 1 | 0 |
- Same as TA-Lib: DI, DX, ADX, ADXR, Aroon, SAR and the linear regression functions give the same numbers as TA-Lib. SuperTrend follows TradingView (
ta.supertrend). Ichimoku and Heikin-Ashi use the usual textbook formulas. - NULL prices: the step-by-step indicators (
plus_di,minus_di,dx,adx,adxr,sar,supertrend,supertrend_direction, theha_functions) stop at the first NULL: that candle and every later one isNULL. The window indicators (Aroon, Ichimoku, linear regression) come back once the NULL is out of their window. Leave NULL candles out withWHERE. - Returns
DOUBLE, exceptsupertrend_direction(LONG). Useround(x, 2)for prices.
Example: The trend of CITY in its last 5 minutes: ADX, DI, SuperTrend and SAR (sample data: sample)
SELECT time, close, adx14, plus_di14, minus_di14, st_dir, sar
FROM (SELECT time, close,
round(adx(high, low, close), 1) AS adx14,
round(plus_di(high, low, close), 1) AS plus_di14,
round(minus_di(high, low, close), 1) AS minus_di14,
supertrend_direction(high, low, close) AS st_dir,
round(sar(high, low), 2) AS sar
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | adx14 (DOUBLE) | plus_di14 (DOUBLE) | minus_di14 (DOUBLE) | st_dir (LONG) | sar (DOUBLE) |
|---|---|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 16.7 | 17.3 | 17.9 | -1 | 505.78 |
| 2026-09-10T09:13:00.000Z | 505.1 | 17.9 | 18.9 | 18.2 | -1 | 505.84 |
| 2026-09-10T09:12:00.000Z | 504.8 | 19.1 | 14 | 19.6 | -1 | 505.9 |
| 2026-09-10T09:11:00.000Z | 504.5 | 19.3 | 14.9 | 20.8 | -1 | 505.97 |
| 2026-09-10T09:10:00.000Z | 504.6 | 19.5 | 15 | 21.1 | -1 | 506.04 |
(5 rows)
Example: A NULL high: the step-by-step indicators stop, the window ones come back (sample data: sample)
Setup:
CREATE TABLE candles (time TIMESTAMP, open DOUBLE, high DOUBLE, low DOUBLE, close DOUBLE) TIMESERIES(time) PARTITION BY DAY;
INSERT INTO candles VALUES
('2026-09-01', 10, 11, 9, 10.5), ('2026-09-02', 10.5, 12, 10, 11.5), ('2026-09-03', 11.5, 12.5, 11, 12),
('2026-09-04', 12, NULL, 11.5, 12.2), ('2026-09-05', 12.2, 13, 12, 12.8), ('2026-09-06', 12.8, 13.5, 12.5, 13.2),
('2026-09-07', 13.2, 14, 13, 13.9), ('2026-09-08', 13.9, 14.2, 13.1, 13.3);
SELECT time, high,
round(sar(high, low), 2) AS sar,
round(ha_close(open, high, low, close), 2) AS ha_close,
round(aroon_up(high, 2), 1) AS aroon_up2,
round(linearreg_slope(high, 2), 2) AS slope2
FROM candles
ORDER BY time;
Result:
| time (TIMESTAMP) | high (DOUBLE) | sar (DOUBLE) | ha_close (DOUBLE) | aroon_up2 (DOUBLE) | slope2 (DOUBLE) |
|---|---|---|---|---|---|
| 2026-09-01T00:00:00.000Z | 11 | NULL | 10.13 | NULL | NULL |
| 2026-09-02T00:00:00.000Z | 12 | 9 | 11 | NULL | 1 |
| 2026-09-03T00:00:00.000Z | 12.5 | 9.06 | 11.75 | 100 | 0.5 |
| 2026-09-04T00:00:00.000Z | NULL | NULL | NULL | NULL | NULL |
| 2026-09-05T00:00:00.000Z | 13 | NULL | NULL | NULL | NULL |
| 2026-09-06T00:00:00.000Z | 13.5 | NULL | NULL | NULL | 0.5 |
| 2026-09-07T00:00:00.000Z | 14 | NULL | NULL | 100 | 0.5 |
| 2026-09-08T00:00:00.000Z | 14.2 | NULL | NULL | 100 | 0.2 |
(8 rows)
cross_above, cross_below
Syntax:
cross_above(a, b) OVER ([PARTITION BY ...] [ORDER BY ...])
cross_below(a, b) OVER ([PARTITION BY ...] [ORDER BY ...])
Crossings: cross_above is true on the candle where a goes from at or below b to above it, cross_below where it goes from at or above b to below it. With two moving averages that is the golden cross (fast above slow) and the death cross. crossover and crossunder are other names for them (TradingView's).
| Argument | Type | Meaning |
|---|---|---|
a, b | number | two series, or a series and a fixed level (cross_above(rsi(close, 14), 30)) |
- Returns:
BOOL:trueon the crossing candle,falseon the others. - NULL: on the first candle, and where
aorbisNULLon this candle or the one before. - Notes:
aandbmay themselves be indicators, as incross_above(sma(close, 20), sma(close, 50)) OVER (...): an indicator written inside another one without its ownOVERtakes thePARTITION BYandORDER BYof the one it is in (indicators inside indicators).
Example: Golden and death crosses of CITY: 3-day average against 8-day (sample data: sample)
SELECT time, close, signal
FROM (
SELECT time, close,
CASE WHEN cross_above(sma(close, 3), sma(close, 8)) OVER (ORDER BY time) THEN 'golden'
WHEN cross_below(sma(close, 3), sma(close, 8)) OVER (ORDER BY time) THEN 'death' END AS signal
FROM ochl_day
WHERE symbol = 'CITY' AND time IN '2026'
) s
WHERE signal IS NOT NULL
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | signal (STRING) |
|---|---|---|
| 2026-09-10T00:00:00.000Z | 504.9 | golden |
(1 row)
Example: Symbols whose 3-day average crossed above their 8-day one on the last day (sample data: sample)
SELECT symbol, time
FROM (
SELECT symbol, time,
cross_above(sma(close, 3), sma(close, 8)) OVER (PARTITION BY symbol ORDER BY time) AS up,
row_number() OVER (PARTITION BY symbol ORDER BY time DESC) AS rn
FROM ochl_day
) s
WHERE rn = 1 AND up
ORDER BY symbol;
Result:
| symbol (SYMBOL) | time (TIMESTAMP) |
|---|---|
| CITY | 2026-09-10T00:00:00.000Z |
(1 row)
plus_di, minus_di
Syntax:
plus_di(high, low, close)
plus_di(high, low, close, n)
minus_di(high, low, close, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The directional indicators +DI and -DI (Welles Wilder's "directional movement"). +DI measures how strongly the highs push up; -DI how strongly the lows push down. Both are in percent of the true range. When +DI is above -DI, the buyers are stronger (an up trend); when -DI is above +DI, the sellers are stronger. A cross of the two lines is a common buy or sell signal.
Each candle's upward move is high - previous high, its downward move is previous low - low; only the bigger one counts (and only when it is more than 0). Both moves and the true range get Wilder's smoothing over n candles, and +DI = 100 × smoothed up move / smoothed true range.
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
close | number | the candle's close |
n | whole number, 2 or more | the period; default 14 |
- Returns:
DOUBLEfrom 0 to 100. - NULL:
NULLfor the firstncandles. A NULLhigh,loworclosemakes that candle and every later oneNULL. - Notes: the same as TA-Lib
PLUS_DIandMINUS_DI. Use adx to see whether the trend is strong enough to follow.
Example: +DI and -DI of COAST in the last 5 minutes (sample data: sample)
SELECT time, close, plus_di14, minus_di14,
CASE WHEN plus_di14 > minus_di14 THEN 'buyers stronger' ELSE 'sellers stronger' END AS side
FROM (SELECT time, close,
round(plus_di(high, low, close), 1) AS plus_di14,
round(minus_di(high, low, close), 1) AS minus_di14
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | plus_di14 (DOUBLE) | minus_di14 (DOUBLE) | side (STRING) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 27.7 | 14.4 | buyers stronger |
| 2026-09-10T09:13:00.000Z | 376.2 | 26.9 | 15.4 | buyers stronger |
| 2026-09-10T09:12:00.000Z | 376 | 29 | 16.7 | buyers stronger |
| 2026-09-10T09:11:00.000Z | 375.5 | 22.5 | 18.5 | buyers stronger |
| 2026-09-10T09:10:00.000Z | 375.6 | 23.8 | 19.5 | buyers stronger |
(5 rows)
Example: DI crossover: the first 5 minutes of 10 September when CITY's +DI crossed above -DI (sample data: sample)
SELECT time, close, plus_di14, minus_di14
FROM (SELECT time, close, plus_di14, minus_di14,
lag(plus_di14) AS prev_plus, lag(minus_di14) AS prev_minus
FROM (SELECT time, close,
round(plus_di(high, low, close), 1) AS plus_di14,
round(minus_di(high, low, close), 1) AS minus_di14
FROM ochl_minutes
WHERE symbol = 'CITY') a) b
WHERE plus_di14 > minus_di14 AND prev_plus <= prev_minus AND time IN '2026-09-10'
ORDER BY time
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | plus_di14 (DOUBLE) | minus_di14 (DOUBLE) |
|---|---|---|---|
| 2026-09-10T05:41:00.000Z | 505.4 | 18.5 | 16.6 |
| 2026-09-10T05:59:00.000Z | 506.4 | 22.6 | 16.4 |
| 2026-09-10T06:06:00.000Z | 505.5 | 16.2 | 14.7 |
| 2026-09-10T06:10:00.000Z | 505.9 | 15.1 | 14.9 |
| 2026-09-10T06:18:00.000Z | 505.6 | 19.7 | 19.3 |
(5 rows)
Example: The period must be 2 or more (sample data: sample; shows an error)
SELECT plus_di(high, low, close, 1) FROM ochl_day;
Result:
Error: line 1, column 8: plus_di: the period must be a whole number of rows (2 or more)
dx
Syntax:
dx(high, low, close)
dx(high, low, close, n)
dx(high, low, close, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The directional movement index: how far apart +DI and -DI are, DX = 100 × |+DI - -DI| / (+DI + -DI). A big DX means one side (buyers or sellers) is much stronger. DX jumps a lot from candle to candle; most traders use its smooth average, adx.
| Argument | Type | Meaning |
|---|---|---|
high, low, close | number | the candle's high, low and close |
n | whole number, 2 or more | the period; default 14 |
- Returns:
DOUBLEfrom 0 to 100. - NULL:
NULLfor the firstncandles. A NULL price stops the series (that candle and every later one isNULL). - Notes: the same as TA-Lib
DX. When +DI and -DI are both 0, DX keeps its previous value.
Example: DX jumps, ADX is smooth (CITY daily, 3-day period) (sample data: sample)
SELECT time, close,
round(dx(high, low, close, 3), 1) AS dx3,
round(adx(high, low, close, 3), 1) AS adx3
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-08-23'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | dx3 (DOUBLE) | adx3 (DOUBLE) |
|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 507.9 | NULL | NULL |
| 2026-08-24T00:00:00.000Z | 510.3 | NULL | NULL |
| 2026-08-25T00:00:00.000Z | 513.3 | NULL | NULL |
| 2026-08-26T00:00:00.000Z | 513.2 | 100 | NULL |
| 2026-08-27T00:00:00.000Z | 505.9 | 20.9 | NULL |
| 2026-08-30T00:00:00.000Z | 503.1 | 36.4 | 52.4 |
| 2026-08-31T00:00:00.000Z | 505.7 | 51.1 | 52 |
| 2026-09-01T00:00:00.000Z | 502.4 | 17.9 | 40.6 |
| 2026-09-02T00:00:00.000Z | 496.4 | 70.9 | 50.7 |
| 2026-09-03T00:00:00.000Z | 497.9 | 70.9 | 57.5 |
| 2026-09-06T00:00:00.000Z | 499 | 70.9 | 61.9 |
| 2026-09-07T00:00:00.000Z | 498.7 | 77.7 | 67.2 |
| 2026-09-08T00:00:00.000Z | 497.5 | 71.7 | 68.7 |
| 2026-09-09T00:00:00.000Z | 504.6 | 74.4 | 70.6 |
| 2026-09-10T00:00:00.000Z | 504.9 | 27 | 56.1 |
(15 rows)
adx
Syntax:
adx(high, low, close)
adx(high, low, close, n)
adx(high, low, close, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The average directional index: the strength of the trend, from 0 to 100, without its direction. It is Wilder's average of dx over n candles. Traders read it like this:
- below 20: no real trend, the price moves sideways;
- above 25: a strong trend. Then look at +DI and -DI for the direction: +DI above -DI is a strong up trend, -DI above +DI a strong down trend;
- ADX rising: the trend is getting stronger.
| Argument | Type | Meaning |
|---|---|---|
high, low, close | number | the candle's high, low and close |
n | whole number, 2 or more | the period; default 14 |
- Returns:
DOUBLEfrom 0 to 100. - NULL:
NULLfor the first2n - 1candles (27 with the default 14). A NULL price stops the series. - Notes: the same as TA-Lib
ADX. Because it is an average of an average, ADX is slow: it needs about2ncandles to start and more to settle. Load more history than you show.
Example: Strong or weak trend? COAST in the last 5 minutes (sample data: sample)
SELECT time, close, adx14, plus_di14, minus_di14,
CASE WHEN adx14 > 25 AND plus_di14 > minus_di14 THEN 'strong up'
WHEN adx14 > 25 THEN 'strong down'
ELSE 'weak' END AS trend
FROM (SELECT time, close,
round(adx(high, low, close), 1) AS adx14,
round(plus_di(high, low, close), 1) AS plus_di14,
round(minus_di(high, low, close), 1) AS minus_di14
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | adx14 (DOUBLE) | plus_di14 (DOUBLE) | minus_di14 (DOUBLE) | trend (STRING) |
|---|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 17.7 | 27.7 | 14.4 | weak |
| 2026-09-10T09:13:00.000Z | 376.2 | 16.6 | 26.9 | 15.4 | weak |
| 2026-09-10T09:12:00.000Z | 376 | 15.8 | 29 | 16.7 | weak |
| 2026-09-10T09:11:00.000Z | 375.5 | 15 | 22.5 | 18.5 | weak |
| 2026-09-10T09:10:00.000Z | 375.6 | 15.4 | 23.8 | 19.5 | weak |
(5 rows)
Example: How many minutes each symbol spent in a strong up, strong down or weak trend (sample data: sample)
SELECT symbol, trend, count(*) AS minutes
FROM (SELECT symbol,
CASE WHEN adx14 IS NULL THEN 'warm-up'
WHEN adx14 > 25 AND plus_di14 > minus_di14 THEN 'strong up'
WHEN adx14 > 25 THEN 'strong down'
ELSE 'weak' END AS trend
FROM (SELECT symbol,
adx(high, low, close) OVER (PARTITION BY symbol ORDER BY time) AS adx14,
plus_di(high, low, close) OVER (PARTITION BY symbol ORDER BY time) AS plus_di14,
minus_di(high, low, close) OVER (PARTITION BY symbol ORDER BY time) AS minus_di14
FROM ochl_minutes) a) b
GROUP BY symbol, trend
ORDER BY symbol, trend;
Result:
| symbol (SYMBOL) | trend (STRING) | minutes (LONG) |
|---|---|---|
| CITY | strong down | 153 |
| CITY | strong up | 73 |
| CITY | warm-up | 27 |
| CITY | weak | 227 |
| COAST | strong down | 159 |
| COAST | strong up | 16 |
| COAST | warm-up | 27 |
| COAST | weak | 274 |
(8 rows)
adxr
Syntax:
adxr(high, low, close)
adxr(high, low, close, n)
adxr(high, low, close, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The average directional movement rating: the average of today's adx and the ADX of n - 1 candles ago. It is an even smoother trend strength. Some traders compare ADX with ADXR: ADX above ADXR means the trend is getting stronger.
| Argument | Type | Meaning |
|---|---|---|
high, low, close | number | the candle's high, low and close |
n | whole number, 2 or more | the period; default 14 |
- Returns:
DOUBLEfrom 0 to 100. - NULL:
NULLfor the first3n - 2candles (40 with the default 14). A NULL price stops the series. - Notes: the same as TA-Lib
ADXR.
Example: ADX against ADXR: is the trend of CITY getting stronger? (sample data: sample)
SELECT time, close, adx14, adxr14,
CASE WHEN adx14 > adxr14 THEN 'stronger' ELSE 'weaker' END AS strength
FROM (SELECT time, close,
round(adx(high, low, close), 1) AS adx14,
round(adxr(high, low, close), 1) AS adxr14
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | adx14 (DOUBLE) | adxr14 (DOUBLE) | strength (STRING) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 16.7 | 21.4 | weaker |
| 2026-09-10T09:13:00.000Z | 505.1 | 17.9 | 22.9 | weaker |
| 2026-09-10T09:12:00.000Z | 504.8 | 19.1 | 24.5 | weaker |
| 2026-09-10T09:11:00.000Z | 504.5 | 19.3 | 25.5 | weaker |
| 2026-09-10T09:10:00.000Z | 504.6 | 19.5 | 26.2 | weaker |
(5 rows)
aroon_up, aroon_down
Syntax:
aroon_up(high)
aroon_up(high, n)
aroon_down(low, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The Aroon indicator ("dawn's early light" in Sanskrit) asks: how long ago was the highest high, and how long ago the lowest low? It looks at this candle and the n candles before it.
aroon_up = 100 × (n - candles since the highest high) / n. 100 means today made a newn-candle high; 0 means the high wasncandles ago.aroon_downis the same with the lowest low.- Aroon up above 70 and Aroon down below 30 is a strong up trend; the other way round a strong down trend. When the two lines cross, the trend may be changing.
| Argument | Type | Meaning |
|---|---|---|
high (or low) | number | the highs for aroon_up, the lows for aroon_down |
n | whole number, 1 or more | the period; default 14 |
- Returns:
DOUBLEfrom 0 to 100. - NULL:
NULLfor the firstncandles, and while a NULL value is in the window ofn + 1candles. - Notes: the same as TA-Lib
AROON. When the highest high appears twice in the window, the later one counts.
Example: Aroon of VOLT on daily candles (5-day period) (sample data: sample)
SELECT time, high, low,
round(aroon_up(high, 5), 1) AS aroon_up5,
round(aroon_down(low, 5), 1) AS aroon_down5
FROM ochl_day
WHERE symbol = 'VOLT' AND time >= '2026-08-23'
ORDER BY time;
Result:
| time (TIMESTAMP) | high (DOUBLE) | low (DOUBLE) | aroon_up5 (DOUBLE) | aroon_down5 (DOUBLE) |
|---|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 182.6 | 178.2 | NULL | NULL |
| 2026-08-24T00:00:00.000Z | 183.6 | 178.5 | NULL | NULL |
| 2026-08-25T00:00:00.000Z | 182.2 | 172.8 | NULL | NULL |
| 2026-08-26T00:00:00.000Z | 178.4 | 172 | NULL | NULL |
| 2026-08-27T00:00:00.000Z | 175.9 | 173 | NULL | NULL |
| 2026-08-30T00:00:00.000Z | 174.2 | 170.6 | 20 | 100 |
| 2026-08-31T00:00:00.000Z | 175.6 | 171.3 | 0 | 80 |
| 2026-09-01T00:00:00.000Z | 172.1 | 167.3 | 0 | 100 |
| 2026-09-02T00:00:00.000Z | 174.6 | 169 | 0 | 80 |
| 2026-09-03T00:00:00.000Z | 177.3 | 171.9 | 100 | 60 |
| 2026-09-06T00:00:00.000Z | 183.9 | 172.4 | 100 | 40 |
| 2026-09-07T00:00:00.000Z | 183.2 | 174.3 | 80 | 20 |
| 2026-09-08T00:00:00.000Z | 183.5 | 178.2 | 60 | 0 |
| 2026-09-09T00:00:00.000Z | 189.5 | 181.7 | 100 | 0 |
| 2026-09-10T00:00:00.000Z | 192.1 | 184.2 | 100 | 0 |
(15 rows)
aroon_osc
Syntax:
aroon_osc(high, low)
aroon_osc(high, low, n)
aroon_osc(high, low, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The Aroon oscillator: aroon_up(high, n) - aroon_down(low, n), one line from -100 to 100. Above 0, the recent high is newer than the recent low (the price is climbing); below 0, the other way round. Near +100 or -100, the trend is strong.
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
n | whole number, 1 or more | the period; default 14 |
- Returns:
DOUBLEfrom -100 to 100. - NULL:
NULLfor the firstncandles, and while a NULL high or low is in the window. - Notes: the same as TA-Lib
AROONOSC. Bothhighandloware needed:aroon_osc(high, 5)reads5as the lows.
Example: Aroon oscillator of every symbol on the last day (sample data: sample)
SELECT time, symbol, close, aroon_osc5
FROM (SELECT time, symbol, close,
round(aroon_osc(high, low, 5) OVER (PARTITION BY symbol ORDER BY time), 1) AS aroon_osc5
FROM ochl_day) t
WHERE time IN '2026-09-10'
ORDER BY aroon_osc5 DESC;
Result:
| time (TIMESTAMP) | symbol (SYMBOL) | close (DOUBLE) | aroon_osc5 (DOUBLE) |
|---|---|---|---|
| 2026-09-10T00:00:00.000Z | VOLT | 191.2 | 100 |
| 2026-09-10T00:00:00.000Z | COAST | 376.1 | 80 |
| 2026-09-10T00:00:00.000Z | CITY | 504.9 | 40 |
(3 rows)
sar, parabolic_sar
Syntax:
sar(high, low)
sar(high, low, acceleration, maximum)
parabolic_sar(high, low, acceleration, maximum) OVER ([PARTITION BY ...] [ORDER BY ...])
The parabolic SAR ("stop and reverse"). On a chart it is a row of dots: below the candles in an up trend, above them in a down trend. Traders use it as a trailing stop: in an up trend, sell when the price falls under the dot. When the price crosses the dot, the SAR jumps to the other side and the trend is "reversed". parabolic_sar is the same function.
Each candle, the dot moves toward the price by acceleration factor × (extreme price - SAR). The factor starts at acceleration, grows by acceleration every time the trend makes a new high (or low), and never goes above maximum. So the dot follows the price faster the longer the trend lasts.
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
acceleration | number, more than 0 | the start and the step of the factor; default 0.02 |
maximum | number, more than 0 | the biggest factor; default 0.2 |
- Returns:
DOUBLE(a price). - NULL:
NULLfor the first candle. A NULLhighorlowstops the series (that candle and every later one isNULL). - Notes: the same as TA-Lib
SAR. The first trend (up or down) is chosen from the first two candles. Anaccelerationbigger thanmaximumis lowered tomaximum. A smalleraccelerationgives a slower dot, further from the price.
Example: SAR of CITY's daily candles: where the trend reversed (sample data: sample)
SELECT time, low, high, close, sar,
CASE WHEN sar <= low THEN 'dot below: up trend'
WHEN sar >= high THEN 'dot above: down trend' END AS trend
FROM (SELECT time, low, high, close, round(sar(high, low), 2) AS sar
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-08-23') t
ORDER BY time;
Result:
| time (TIMESTAMP) | low (DOUBLE) | high (DOUBLE) | close (DOUBLE) | sar (DOUBLE) | trend (STRING) |
|---|---|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 502 | 508.4 | 507.9 | NULL | NULL |
| 2026-08-24T00:00:00.000Z | 508.2 | 510.9 | 510.3 | 502 | dot below: up trend |
| 2026-08-25T00:00:00.000Z | 507.6 | 517 | 513.3 | 502.18 | dot below: up trend |
| 2026-08-26T00:00:00.000Z | 508 | 515.3 | 513.2 | 502.77 | dot below: up trend |
| 2026-08-27T00:00:00.000Z | 505.5 | 514.3 | 505.9 | 503.34 | dot below: up trend |
| 2026-08-30T00:00:00.000Z | 501.7 | 511.2 | 503.1 | 517 | dot above: down trend |
| 2026-08-31T00:00:00.000Z | 500.1 | 506 | 505.7 | 516.69 | dot above: down trend |
| 2026-09-01T00:00:00.000Z | 501.3 | 507.3 | 502.4 | 516.03 | dot above: down trend |
| 2026-09-02T00:00:00.000Z | 494.1 | 502.8 | 496.4 | 515.39 | dot above: down trend |
| 2026-09-03T00:00:00.000Z | 495.5 | 500.9 | 497.9 | 514.12 | dot above: down trend |
| 2026-09-06T00:00:00.000Z | 496 | 500.1 | 499 | 512.91 | dot above: down trend |
| 2026-09-07T00:00:00.000Z | 495 | 501 | 498.7 | 511.79 | dot above: down trend |
| 2026-09-08T00:00:00.000Z | 497.5 | 501.1 | 497.5 | 510.72 | dot above: down trend |
| 2026-09-09T00:00:00.000Z | 504 | 512.4 | 504.6 | 494.1 | dot below: up trend |
| 2026-09-10T00:00:00.000Z | 500.7 | 507 | 504.9 | 494.47 | dot below: up trend |
(15 rows)
Example: A trailing stop from the SAR, for the last 5 minutes of CITY (sample data: sample)
SELECT time, close, sar_stop,
CASE WHEN sar_stop < close THEN 'hold: sell below the stop' ELSE 'down trend: stay out' END AS action
FROM (SELECT time, close, round(sar(high, low), 2) AS sar_stop
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | sar_stop (DOUBLE) | action (STRING) |
|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 505.78 | down trend: stay out |
| 2026-09-10T09:13:00.000Z | 505.1 | 505.84 | down trend: stay out |
| 2026-09-10T09:12:00.000Z | 504.8 | 505.9 | down trend: stay out |
| 2026-09-10T09:11:00.000Z | 504.5 | 505.97 | down trend: stay out |
| 2026-09-10T09:10:00.000Z | 504.6 | 506.04 | down trend: stay out |
(5 rows)
Example: A slower SAR: acceleration 0.01, maximum 0.1 (sample data: sample)
SELECT time, close,
round(sar(high, low), 2) AS sar_default,
round(parabolic_sar(high, low, 0.01, 0.1), 2) AS sar_slow
FROM ochl_day
WHERE symbol = 'COAST' AND time >= '2026-09-01'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | sar_default (DOUBLE) | sar_slow (DOUBLE) |
|---|---|---|---|
| 2026-09-01T00:00:00.000Z | 367.4 | NULL | NULL |
| 2026-09-02T00:00:00.000Z | 369.2 | 365.3 | 365.3 |
| 2026-09-03T00:00:00.000Z | 373.2 | 373.6 | 373.6 |
| 2026-09-06T00:00:00.000Z | 375.4 | 364.1 | 364.1 |
| 2026-09-07T00:00:00.000Z | 379.2 | 364.1 | 364.1 |
| 2026-09-08T00:00:00.000Z | 377.2 | 364.78 | 364.44 |
| 2026-09-09T00:00:00.000Z | 380.1 | 365.43 | 364.77 |
| 2026-09-10T00:00:00.000Z | 376.1 | 367.43 | 365.79 |
(8 rows)
Example: acceleration and maximum must be more than 0 (sample data: sample; shows an error)
SELECT sar(high, low, 0, 0.2) FROM ochl_day;
Result:
Error: line 1, column 8: sar: the acceleration and the maximum must be more than 0
ichimoku_tenkan, ichimoku_kijun
Syntax:
ichimoku_tenkan(high, low)
ichimoku_tenkan(high, low, n)
ichimoku_kijun(high, low, n) OVER ([PARTITION BY ...] [ORDER BY ...])
Ichimoku ("one look" in Japanese) is a whole trend system drawn on the chart. Its lines are middle prices: (highest high + lowest low) / 2 of the last n candles.
ichimoku_tenkanis the tenkan-sen (conversion line), a fast line: default 9 candles.ichimoku_kijunis the kijun-sen (base line), a slow line: default 26 candles.- Tenkan above kijun is a sign of an up trend; a cross of tenkan above kijun is a buy signal ("TK cross").
| Argument | Type | Meaning |
|---|---|---|
high | number | the candle's high |
low | number | the candle's low |
n | whole number, 1 or more | the period; default 9 for tenkan, 26 for kijun |
- Returns:
DOUBLE(a price). - NULL:
NULLfor the firstn - 1candles, and while a NULL high or low is in the window. - Notes: the classic periods 9, 26 and 52 were made for a 6-day trading week. Some traders use other periods; all of them can be changed.
Example: Tenkan and kijun of COAST in the last 5 minutes (sample data: sample)
SELECT time, close, tenkan, kijun,
CASE WHEN tenkan > kijun THEN 'up' WHEN tenkan < kijun THEN 'down' ELSE 'flat' END AS signal
FROM (SELECT time, close,
round(ichimoku_tenkan(high, low), 2) AS tenkan,
round(ichimoku_kijun(high, low), 2) AS kijun
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | tenkan (DOUBLE) | kijun (DOUBLE) | signal (STRING) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 375.45 | 375.4 | up |
| 2026-09-10T09:13:00.000Z | 376.2 | 375.35 | 375.25 | up |
| 2026-09-10T09:12:00.000Z | 376 | 375.3 | 375.05 | up |
| 2026-09-10T09:11:00.000Z | 375.5 | 375 | 374.85 | up |
| 2026-09-10T09:10:00.000Z | 375.6 | 375 | 374.75 | up |
(5 rows)
ichimoku_senkou_a
Syntax:
ichimoku_senkou_a(high, low)
ichimoku_senkou_a(high, low, short, long, shift)
ichimoku_senkou_a(high, low, short, long, shift) OVER ([PARTITION BY ...] [ORDER BY ...])
Senkou span A, the first edge of the Ichimoku cloud (kumo): (tenkan + kijun) / 2, made shift candles ago. A chart draws the cloud 26 candles ahead of the price; KDB puts on each row the cloud value that the chart shows under that candle, so you can compare it with the row's price directly.
| Argument | Type | Meaning |
|---|---|---|
high, low | number | the candle's high and low |
short | whole number, 1 or more | the tenkan period; default 9 |
long | whole number, 1 or more | the kijun period; default 26 |
shift | whole number, 0 or more | how many candles back the value was made; default 26 |
- Returns:
DOUBLE(a price). - NULL:
NULLfor the firstlong + shift - 1candles (51 with the defaults; whenshortis the bigger period,short + shift - 1), and while a NULL high or low is in the window. - Notes: with
shift0 you get the value made on this candle, as a chart would draw it 26 candles later.
Example: Senkou span A with shift 0 is the average of tenkan and kijun (sample data: sample)
SELECT time, tenkan, kijun, span_a_now
FROM (SELECT time,
round(ichimoku_tenkan(high, low), 2) AS tenkan,
round(ichimoku_kijun(high, low), 2) AS kijun,
round(ichimoku_senkou_a(high, low, 9, 26, 0), 2) AS span_a_now
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 3;
Result:
| time (TIMESTAMP) | tenkan (DOUBLE) | kijun (DOUBLE) | span_a_now (DOUBLE) |
|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 505.1 | 505.35 | 505.23 |
| 2026-09-10T09:13:00.000Z | 505.2 | 505.35 | 505.28 |
| 2026-09-10T09:12:00.000Z | 505.2 | 505.35 | 505.28 |
(3 rows)
ichimoku_senkou_b
Syntax:
ichimoku_senkou_b(high, low)
ichimoku_senkou_b(high, low, n, shift)
ichimoku_senkou_b(high, low, n, shift) OVER ([PARTITION BY ...] [ORDER BY ...])
Senkou span B, the second edge of the Ichimoku cloud: the middle price (highest high + lowest low) / 2 of the last n candles (default 52), made shift candles ago. Together with senkou span A:
- price above the cloud (above both spans): up trend;
- price below the cloud: down trend;
- price inside the cloud: no clear trend. A thick cloud is strong support or resistance (a price level that is hard to break).
| Argument | Type | Meaning |
|---|---|---|
high, low | number | the candle's high and low |
n | whole number, 1 or more | the period; default 52 |
shift | whole number, 0 or more | how many candles back the value was made; default 26 |
- Returns:
DOUBLE(a price). - NULL:
NULLfor the firstn + shift - 1candles (77 with the defaults), and while a NULL high or low is in the window.
Example: Is CITY above, below or inside the Ichimoku cloud? (sample data: sample)
SELECT time, close, span_a, span_b,
CASE WHEN close > greatest(span_a, span_b) THEN 'above the cloud: up trend'
WHEN close < least(span_a, span_b) THEN 'below the cloud: down trend'
ELSE 'inside the cloud' END AS position
FROM (SELECT time, close,
round(ichimoku_senkou_a(high, low), 2) AS span_a,
round(ichimoku_senkou_b(high, low), 2) AS span_b
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | span_a (DOUBLE) | span_b (DOUBLE) | position (STRING) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 505.95 | 504.45 | inside the cloud |
| 2026-09-10T09:13:00.000Z | 505.1 | 505.93 | 504.45 | inside the cloud |
| 2026-09-10T09:12:00.000Z | 504.8 | 505.88 | 504.45 | inside the cloud |
| 2026-09-10T09:11:00.000Z | 504.5 | 505.65 | 504.45 | inside the cloud |
| 2026-09-10T09:10:00.000Z | 504.6 | 505.48 | 504.45 | inside the cloud |
(5 rows)
ichimoku_chikou
Syntax:
ichimoku_chikou(close)
ichimoku_chikou(close, shift)
ichimoku_chikou(close, shift) OVER ([PARTITION BY ...] [ORDER BY ...])
Chikou span (the lagging line) of Ichimoku. A chart draws today's close shift candles back in time. So in KDB, each row gets the close from shift rows later. It lets you compare the price then with the price 26 candles later: chikou above the old price means the price has risen since.
| Argument | Type | Meaning |
|---|---|---|
close | number | the candle's close |
shift | whole number, 0 or more | how many candles later the close comes from; default 26 |
- Returns:
DOUBLE(a price). - NULL: the last
shiftcandles areNULL(there is no later close yet). A NULL close givesNULLon the rowshiftcandles before it. - Notes: the same as
lead(close, shift)(lead). Because it looks into the future of each row, never use it as a signal on the last rows.
Example: Chikou with shift 5 on CITY's daily closes: the last 5 days are NULL (sample data: sample)
SELECT time, close, ichimoku_chikou(close, 5) AS close_5_days_later
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-08-30'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | close_5_days_later (DOUBLE) |
|---|---|---|
| 2026-08-30T00:00:00.000Z | 503.1 | 499 |
| 2026-08-31T00:00:00.000Z | 505.7 | 498.7 |
| 2026-09-01T00:00:00.000Z | 502.4 | 497.5 |
| 2026-09-02T00:00:00.000Z | 496.4 | 504.6 |
| 2026-09-03T00:00:00.000Z | 497.9 | 504.9 |
| 2026-09-06T00:00:00.000Z | 499 | NULL |
| 2026-09-07T00:00:00.000Z | 498.7 | NULL |
| 2026-09-08T00:00:00.000Z | 497.5 | NULL |
| 2026-09-09T00:00:00.000Z | 504.6 | NULL |
| 2026-09-10T00:00:00.000Z | 504.9 | NULL |
(10 rows)
supertrend
Syntax:
supertrend(high, low, close)
supertrend(high, low, close, n, multiplier)
supertrend(high, low, close, n, multiplier) OVER ([PARTITION BY ...] [ORDER BY ...])
SuperTrend is one line that follows the price. In an up trend the line is below the price, in a down trend it is above. When the close crosses the line, the trend flips. Traders like it as a simple trailing stop: in an up trend, sell when the close falls below the SuperTrend line.
The line is (high + low) / 2 ± multiplier × ATR. The ATR (average true range, see atr) makes the line keep a bigger distance when the price moves a lot. The line only moves toward the price, never away, until the trend flips. Use supertrend_direction to know which side the line is on.
| Argument | Type | Meaning |
|---|---|---|
high, low, close | number | the candle's high, low and close |
n | whole number, 1 or more | the ATR period; default 10 |
multiplier | number | how many ATRs away the line is; default 3 |
- Returns:
DOUBLE(a price). - NULL:
NULLfor the firstn - 1candles. A NULL price stops the series (that candle and every later one isNULL). - Notes: the same as TradingView
ta.supertrend(multiplier, n). Its ATR is TradingView's: the first true range ishigh - low, and the first ATR is on candlen. So it is a little different from KDB's atr, which starts on candlen + 1. A biggermultipliergives fewer, later flips.
Example: SuperTrend of CITY in the last 5 minutes (sample data: sample)
SELECT time, close, supertrend, direction,
CASE WHEN direction = 1 THEN 'up: line is the stop below' ELSE 'down: line is above' END AS meaning
FROM (SELECT time, close,
round(supertrend(high, low, close), 2) AS supertrend,
supertrend_direction(high, low, close) AS direction
FROM ochl_minutes
WHERE symbol = 'CITY') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | supertrend (DOUBLE) | direction (LONG) | meaning (STRING) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | 504.9 | 506.15 | -1 | down: line is above |
| 2026-09-10T09:13:00.000Z | 505.1 | 506.15 | -1 | down: line is above |
| 2026-09-10T09:12:00.000Z | 504.8 | 506.15 | -1 | down: line is above |
| 2026-09-10T09:11:00.000Z | 504.5 | 506.15 | -1 | down: line is above |
| 2026-09-10T09:10:00.000Z | 504.6 | 506.15 | -1 | down: line is above |
(5 rows)
Example: Daily SuperTrend of every symbol (5 days, multiplier 2) on the last day (sample data: sample)
SELECT time, symbol, close, st, direction
FROM (SELECT time, symbol, close,
round(supertrend(high, low, close, 5, 2) OVER (PARTITION BY symbol ORDER BY time), 2) AS st,
supertrend_direction(high, low, close, 5, 2) OVER (PARTITION BY symbol ORDER BY time) AS direction
FROM ochl_day) t
WHERE time IN '2026-09-10'
ORDER BY symbol;
Result:
| time (TIMESTAMP) | symbol (SYMBOL) | close (DOUBLE) | st (DOUBLE) | direction (LONG) |
|---|---|---|---|---|
| 2026-09-10T00:00:00.000Z | CITY | 504.9 | 511.5 | -1 |
| 2026-09-10T00:00:00.000Z | COAST | 376.1 | 384.2 | -1 |
| 2026-09-10T00:00:00.000Z | VOLT | 191.2 | 173.34 | 1 |
(3 rows)
supertrend_direction
Syntax:
supertrend_direction(high, low, close)
supertrend_direction(high, low, close, n, multiplier)
supertrend_direction(high, low, close, n, multiplier) OVER ([PARTITION BY ...] [ORDER BY ...])
The side of the SuperTrend line: 1** for an up trend (the line is below the price), **-1 for a down trend (the line is above). When it changes from -1 to 1, traders take it as a buy signal; from 1 to -1 as a sell signal.
| Argument | Type | Meaning |
|---|---|---|
high, low, close | number | the candle's high, low and close |
n | whole number, 1 or more | the ATR period; default 10 |
multiplier | number | how many ATRs away the line is; default 3 |
- Returns:
LONG:1or-1. - NULL:
NULLfor the firstn - 1candles. A NULL price stops the series. - Notes: careful: TradingView's
ta.supertrendgives the opposite sign (-1 for up). KDB uses 1 for up because it is easier to read. The first value is always-1, like TradingView's first value.
Example: SuperTrend flips of CITY: buy and sell signals (sample data: sample)
SELECT time, close, supertrend,
CASE WHEN direction = 1 THEN 'BUY' ELSE 'SELL' END AS signal
FROM (SELECT time, close, supertrend, direction, lag(direction) AS prev_direction
FROM (SELECT time, close,
round(supertrend(high, low, close), 2) AS supertrend,
supertrend_direction(high, low, close) AS direction
FROM ochl_minutes
WHERE symbol = 'CITY') a) b
WHERE direction <> prev_direction
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | supertrend (DOUBLE) | signal (STRING) |
|---|---|---|---|
| 2026-09-09T06:47:00.000Z | 505.8 | 504.08 | BUY |
| 2026-09-09T08:42:00.000Z | 508.2 | 510.31 | SELL |
| 2026-09-10T05:43:00.000Z | 506 | 504.19 | BUY |
| 2026-09-10T06:34:00.000Z | 504.8 | 506.76 | SELL |
| 2026-09-10T07:13:00.000Z | 502.9 | 501.07 | BUY |
| 2026-09-10T08:52:00.000Z | 504.7 | 506.91 | SELL |
(6 rows)
Example: How many minutes COAST spent in each SuperTrend direction, per day (sample data: sample)
SELECT to_date(time) AS day, direction, count(*) AS minutes
FROM (SELECT time, supertrend_direction(high, low, close) AS direction
FROM ochl_minutes
WHERE symbol = 'COAST') t
WHERE direction IS NOT NULL
GROUP BY to_date(time), direction
ORDER BY day, direction;
Result:
| day (DATE) | direction (LONG) | minutes (LONG) |
|---|---|---|
| 2026-09-09 | -1 | 200 |
| 2026-09-09 | 1 | 31 |
| 2026-09-10 | -1 | 149 |
| 2026-09-10 | 1 | 87 |
(4 rows)
linearreg, linreg
Syntax:
linearreg(x)
linearreg(x, n)
linreg(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
A moving linear regression. For every candle, KDB draws the best straight line through the last n values (the "least squares" line: the one with the smallest squared distances to the points). linearreg is the value of that line on this candle. It is a moving average that follows the trend with less delay than sma. linreg is the same function.
The other functions of this family read the same line: linearreg_slope (its steepness), linearreg_intercept (its start), linearreg_angle and tsf (the next candle's forecast).
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 2 or more | how many candles the line goes through; default 14 |
- Returns:
DOUBLE. - NULL:
NULLfor the firstn - 1candles, and while a NULL value is in the window. - Notes: the same as TA-Lib
LINEARREG. For one line through all rows of a group, use the aggregate regr_slope.
Example: Linear regression line against SMA (CITY daily, 5 days) (sample data: sample)
SELECT time, close,
round(linearreg(close, 5), 2) AS linreg5,
round(sma(close, 5), 2) AS sma5
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-08-23'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | linreg5 (DOUBLE) | sma5 (DOUBLE) |
|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 507.9 | NULL | NULL |
| 2026-08-24T00:00:00.000Z | 510.3 | NULL | NULL |
| 2026-08-25T00:00:00.000Z | 513.3 | NULL | NULL |
| 2026-08-26T00:00:00.000Z | 513.2 | NULL | NULL |
| 2026-08-27T00:00:00.000Z | 505.9 | 509.9 | 510.12 |
| 2026-08-30T00:00:00.000Z | 503.1 | 504.8 | 509.16 |
| 2026-08-31T00:00:00.000Z | 505.7 | 503.18 | 508.24 |
| 2026-09-01T00:00:00.000Z | 502.4 | 501.7 | 506.06 |
| 2026-09-02T00:00:00.000Z | 496.4 | 498.76 | 502.7 |
| 2026-09-03T00:00:00.000Z | 497.9 | 497.16 | 501.1 |
| 2026-09-06T00:00:00.000Z | 499 | 496.7 | 500.28 |
| 2026-09-07T00:00:00.000Z | 498.7 | 497.92 | 498.88 |
| 2026-09-08T00:00:00.000Z | 497.5 | 498.5 | 497.9 |
| 2026-09-09T00:00:00.000Z | 504.6 | 501.92 | 499.54 |
| 2026-09-10T00:00:00.000Z | 504.9 | 504.48 | 500.94 |
(15 rows)
Example: The period must be 2 or more: one point makes no line (sample data: sample; shows an error)
SELECT linreg(close, 1) FROM ochl_day;
Result:
Error: line 1, column 8: linreg: the period must be a whole number of rows (2 or more)
linearreg_slope, linreg_slope
Syntax:
linearreg_slope(x)
linearreg_slope(x, n)
linreg_slope(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The slope of the moving regression line: how much the line goes up (or down, when negative) per candle. On one-minute closes, a slope of 0.05 means the trend adds about 5 cents a minute. A positive slope is an up trend, a negative slope a down trend; a bigger number is a steeper trend. linreg_slope is the same function.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 2 or more | how many candles; default 14 |
- Returns:
DOUBLE(price per candle). - NULL:
NULLfor the firstn - 1candles, and while a NULL value is in the window. - Notes: the same as TA-Lib
LINEARREG_SLOPE. To compare shares with different prices, divide by the price:slope / close × 100is the trend in percent per candle.
Example: Trend of the last 14 minutes, per symbol, at the close (sample data: sample)
SELECT time, symbol, close, slope14, round(slope14 / close * 100 * 60, 3) AS pct_per_hour
FROM (SELECT time, symbol, close,
round(linearreg_slope(close, 14) OVER (PARTITION BY symbol ORDER BY time), 4) AS slope14
FROM ochl_minutes) t
WHERE time = '2026-09-10T09:14:00Z'
ORDER BY symbol;
Result:
| time (TIMESTAMP) | symbol (SYMBOL) | close (DOUBLE) | slope14 (DOUBLE) | pct_per_hour (DOUBLE) |
|---|---|---|---|---|
| 2026-09-10T09:14:00.000Z | CITY | 504.9 | -0.0534 | -0.635 |
| 2026-09-10T09:14:00.000Z | COAST | 376.1 | 0.107 | 1.707 |
(2 rows)
linearreg_intercept, linreg_intercept
Syntax:
linearreg_intercept(x)
linearreg_intercept(x, n)
linreg_intercept(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The intercept of the moving regression line: the value of the line on the first (oldest) candle of its window. With the slope, it gives the whole line: linearreg = intercept + slope × (n - 1). linreg_intercept is the same function.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 2 or more | how many candles; default 14 |
- Returns:
DOUBLE. - NULL:
NULLfor the firstn - 1candles, and while a NULL value is in the window. - Notes: the same as TA-Lib
LINEARREG_INTERCEPT.
Example: Intercept + slope × (n - 1) is the linearreg value (sample data: sample)
SELECT time, close,
round(linearreg_intercept(close, 5), 2) AS intercept5,
round(linearreg_slope(close, 5), 3) AS slope5,
round(linearreg_intercept(close, 5) + linearreg_slope(close, 5) * 4, 2) AS line_today,
round(linearreg(close, 5), 2) AS linreg5
FROM ochl_day
WHERE symbol = 'VOLT' AND time >= '2026-09-01'
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | intercept5 (DOUBLE) | slope5 (DOUBLE) | line_today (DOUBLE) | linreg5 (DOUBLE) |
|---|---|---|---|---|---|
| 2026-09-01T00:00:00.000Z | 169 | NULL | NULL | NULL | NULL |
| 2026-09-02T00:00:00.000Z | 171.5 | NULL | NULL | NULL | NULL |
| 2026-09-03T00:00:00.000Z | 176 | NULL | NULL | NULL | NULL |
| 2026-09-06T00:00:00.000Z | 180.1 | NULL | NULL | NULL | NULL |
| 2026-09-07T00:00:00.000Z | 176.9 | 169.82 | 2.44 | 179.58 | 179.58 |
| 2026-09-08T00:00:00.000Z | 182.4 | 172.84 | 2.27 | 181.92 | 181.92 |
| 2026-09-09T00:00:00.000Z | 187.3 | 175.56 | 2.49 | 185.52 | 185.52 |
| 2026-09-10T00:00:00.000Z | 191.2 | 177.06 | 3.26 | 190.1 | 190.1 |
(8 rows)
linearreg_angle, linreg_angle
Syntax:
linearreg_angle(x)
linearreg_angle(x, n)
linreg_angle(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The slope of the moving regression line as an angle in degrees: atan(slope) changed to degrees. Near 0 is flat; near 90 a very steep rise, near -90 a very steep fall. linreg_angle is the same function.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 2 or more | how many candles; default 14 |
- Returns:
DOUBLEfrom -90 to 90. - NULL:
NULLfor the firstn - 1candles, and while a NULL value is in the window. - Notes: the same as TA-Lib
LINEARREG_ANGLE. The angle depends on the price unit (dollars per candle), so a 500-dollar share shows steeper angles than a 50-dollar share with the same move in percent. Only compare angles of the same share.
Example: Angle of the 14-minute trend of COAST (sample data: sample)
SELECT time, close, angle14
FROM (SELECT time, close, round(linearreg_angle(close), 1) AS angle14
FROM ochl_minutes
WHERE symbol = 'COAST') t
ORDER BY time DESC
LIMIT 5;
Result:
| time (TIMESTAMP) | close (DOUBLE) | angle14 (DOUBLE) |
|---|---|---|
| 2026-09-10T09:14:00.000Z | 376.1 | 6.1 |
| 2026-09-10T09:13:00.000Z | 376.2 | 4.2 |
| 2026-09-10T09:12:00.000Z | 376 | 1.8 |
| 2026-09-10T09:11:00.000Z | 375.5 | -0.4 |
| 2026-09-10T09:10:00.000Z | 375.6 | -1.8 |
(5 rows)
tsf
Syntax:
tsf(x)
tsf(x, n)
tsf(x, n) OVER ([PARTITION BY ...] [ORDER BY ...])
The time series forecast: the moving regression line carried one candle further. It is a simple guess of the next value if the trend of the last n candles goes on: tsf = linearreg + slope.
| Argument | Type | Meaning |
|---|---|---|
x | number | the price, usually close |
n | whole number, 2 or more | how many candles; default 14 |
- Returns:
DOUBLE. - NULL:
NULLfor the firstn - 1candles, and while a NULL value is in the window. - Notes: the same as TA-Lib
TSF. It is only a straight line: it does not know news or sudden turns.
Example: Forecast against the real next close (CITY daily, 5 days) (sample data: sample)
SELECT time, close, forecast_for_next_day, next_close,
round(next_close - forecast_for_next_day, 2) AS error
FROM (SELECT time, close,
round(tsf(close, 5), 2) AS forecast_for_next_day,
lead(close) AS next_close
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-08-23') t
WHERE forecast_for_next_day IS NOT NULL
ORDER BY time;
Result:
| time (TIMESTAMP) | close (DOUBLE) | forecast_for_next_day (DOUBLE) | next_close (DOUBLE) | error (DOUBLE) |
|---|---|---|---|---|
| 2026-08-27T00:00:00.000Z | 505.9 | 509.79 | 503.1 | -6.69 |
| 2026-08-30T00:00:00.000Z | 503.1 | 502.62 | 505.7 | 3.08 |
| 2026-08-31T00:00:00.000Z | 505.7 | 500.65 | 502.4 | 1.75 |
| 2026-09-01T00:00:00.000Z | 502.4 | 499.52 | 496.4 | -3.12 |
| 2026-09-02T00:00:00.000Z | 496.4 | 496.79 | 497.9 | 1.11 |
| 2026-09-03T00:00:00.000Z | 497.9 | 495.19 | 499 | 3.81 |
| 2026-09-06T00:00:00.000Z | 499 | 494.91 | 498.7 | 3.79 |
| 2026-09-07T00:00:00.000Z | 498.7 | 497.44 | 497.5 | 0.06 |
| 2026-09-08T00:00:00.000Z | 497.5 | 498.8 | 504.6 | 5.8 |
| 2026-09-09T00:00:00.000Z | 504.6 | 503.11 | 504.9 | 1.79 |
| 2026-09-10T00:00:00.000Z | 504.9 | 506.25 | NULL | NULL |
(11 rows)
ha_open, ha_high, ha_low, ha_close
Syntax:
ha_open(open, high, low, close)
ha_high(open, high, low, close)
ha_low(open, high, low, close)
ha_close(open, high, low, close) OVER ([PARTITION BY ...] [ORDER BY ...])
Heikin-Ashi ("average bar" in Japanese) candles are smoothed candles. Each one mixes the candle with the one before, so the chart shows long runs of same-colored candles in a trend and fewer false turns. Many traders read them like this: green candles with no lower wick mean a strong up trend.
| Function | Formula |
|---|---|
ha_close | (open + high + low + close) / 4 |
ha_open | (previous ha_open + previous ha_close) / 2; on the first candle (open + close) / 2 |
ha_high | the biggest of high, ha_open and ha_close |
ha_low | the smallest of low, ha_open and ha_close |
| Argument | Type | Meaning |
|---|---|---|
open, high, low, close | number | the normal candle |
- Returns:
DOUBLE(a price). - NULL: every candle has a value, from the first. A NULL
open,high,loworclosestops the series (that candle and every later one isNULL). - Notes: all four arguments are needed for every function, in the order open, high, low, close. The Heikin-Ashi close is not a real trade price: use the normal close for orders and stop-losses.
Example: Heikin-Ashi candles of VOLT, with their color (sample data: sample)
SELECT time, open, close, ha_open, ha_high, ha_low, ha_close,
CASE WHEN ha_close >= ha_open THEN 'green' ELSE 'red' END AS ha_color
FROM (SELECT time, open, close,
round(ha_open(open, high, low, close), 2) AS ha_open,
round(ha_high(open, high, low, close), 2) AS ha_high,
round(ha_low(open, high, low, close), 2) AS ha_low,
round(ha_close(open, high, low, close), 2) AS ha_close
FROM ochl_day
WHERE symbol = 'VOLT' AND time >= '2026-08-23') t
ORDER BY time;
Result:
| time (TIMESTAMP) | open (DOUBLE) | close (DOUBLE) | ha_open (DOUBLE) | ha_high (DOUBLE) | ha_low (DOUBLE) | ha_close (DOUBLE) | ha_color (STRING) |
|---|---|---|---|---|---|---|---|
| 2026-08-23T00:00:00.000Z | 182.4 | 181 | 181.7 | 182.6 | 178.2 | 181.05 | red |
| 2026-08-24T00:00:00.000Z | 179.8 | 178.5 | 181.38 | 183.6 | 178.5 | 180.1 | red |
| 2026-08-25T00:00:00.000Z | 179.3 | 176.8 | 180.74 | 182.2 | 172.8 | 177.78 | red |
| 2026-08-26T00:00:00.000Z | 177.6 | 174.2 | 179.26 | 179.26 | 172 | 175.55 | red |
| 2026-08-27T00:00:00.000Z | 175.4 | 173.3 | 177.4 | 177.4 | 173 | 174.4 | red |
| 2026-08-30T00:00:00.000Z | 172.5 | 173 | 175.9 | 175.9 | 170.6 | 172.58 | red |
| 2026-08-31T00:00:00.000Z | 173.7 | 172.6 | 174.24 | 175.6 | 171.3 | 173.3 | red |
| 2026-09-01T00:00:00.000Z | 171.3 | 169 | 173.77 | 173.77 | 167.3 | 169.93 | red |
| 2026-09-02T00:00:00.000Z | 170.6 | 171.5 | 171.85 | 174.6 | 169 | 171.43 | red |
| 2026-09-03T00:00:00.000Z | 172.7 | 176 | 171.64 | 177.3 | 171.64 | 174.48 | green |
| 2026-09-06T00:00:00.000Z | 174.2 | 180.1 | 173.06 | 183.9 | 172.4 | 177.65 | green |
| 2026-09-07T00:00:00.000Z | 181.4 | 176.9 | 175.35 | 183.2 | 174.3 | 178.95 | green |
| 2026-09-08T00:00:00.000Z | 178.7 | 182.4 | 177.15 | 183.5 | 177.15 | 180.7 | green |
| 2026-09-09T00:00:00.000Z | 182 | 187.3 | 178.93 | 189.5 | 178.93 | 185.13 | green |
| 2026-09-10T00:00:00.000Z | 185.6 | 191.2 | 182.03 | 192.1 | 182.03 | 188.28 | green |
(15 rows)
Example: 30-minute Heikin-Ashi candles: SAMPLE BY inside, Heikin-Ashi outside (sample data: sample)
SELECT time,
round(ha_open(open, high, low, close), 2) AS ha_open,
round(ha_high(open, high, low, close), 2) AS ha_high,
round(ha_low(open, high, low, close), 2) AS ha_low,
round(ha_close(open, high, low, close), 2) AS ha_close
FROM (SELECT time, first(open) AS open, max(high) AS high, min(low) AS low, last(close) AS close
FROM ochl_minutes
WHERE symbol = 'COAST' AND time IN '2026-09-10'
SAMPLE BY 30m) c
ORDER BY time;
Result:
| time (TIMESTAMP) | ha_open (DOUBLE) | ha_high (DOUBLE) | ha_low (DOUBLE) | ha_close (DOUBLE) |
|---|---|---|---|---|
| 2026-09-10T05:00:00.000Z | 380.9 | 382 | 379.4 | 380.8 |
| 2026-09-10T05:30:00.000Z | 380.85 | 381.9 | 379 | 380.58 |
| 2026-09-10T06:00:00.000Z | 380.71 | 382 | 379.3 | 380.15 |
| 2026-09-10T06:30:00.000Z | 380.43 | 380.7 | 378.8 | 379.58 |
| 2026-09-10T07:00:00.000Z | 380 | 380 | 376.9 | 378.3 |
| 2026-09-10T07:30:00.000Z | 379.15 | 379.15 | 376.9 | 377.93 |
| 2026-09-10T08:00:00.000Z | 378.54 | 378.54 | 375.7 | 377.55 |
| 2026-09-10T08:30:00.000Z | 378.04 | 378.04 | 373.2 | 376.05 |
| 2026-09-10T09:00:00.000Z | 377.05 | 377.05 | 374.3 | 375.6 |
(9 rows)