KDB knowledge

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.

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:

FunctionDefault periodsFirst value on candleNULL candles at the start
plus_di, minus_di, dxn = 14n + 1 = 1514
adxn = 142n = 2827
adxrn = 143n - 1 = 4140
aroon_up, aroon_down, aroon_oscn = 14n + 1 = 1514
sar0.02, 0.221
ichimoku_tenkan998
ichimoku_kijun262625
ichimoku_senkou_a9, 26, shift 2626 + 26 = 5251
ichimoku_senkou_b52, shift 2652 + 26 = 7877
ichimoku_chikoushift 261 (but the last 26 candles are NULL)0
supertrend, supertrend_directionn = 10, 3n = 109
linearreg, linearreg_slope, linearreg_intercept, linearreg_angle, tsfn = 14n = 1413
ha_open, ha_high, ha_low, ha_closenone10

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.000Z504.916.717.317.9-1505.78
2026-09-10T09:13:00.000Z505.117.918.918.2-1505.84
2026-09-10T09:12:00.000Z504.819.11419.6-1505.9
2026-09-10T09:11:00.000Z504.519.314.920.8-1505.97
2026-09-10T09:10:00.000Z504.619.51521.1-1506.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.000Z11NULL10.13NULLNULL
2026-09-02T00:00:00.000Z12911NULL1
2026-09-03T00:00:00.000Z12.59.0611.751000.5
2026-09-04T00:00:00.000ZNULLNULLNULLNULLNULL
2026-09-05T00:00:00.000Z13NULLNULLNULLNULL
2026-09-06T00:00:00.000Z13.5NULLNULLNULL0.5
2026-09-07T00:00:00.000Z14NULLNULL1000.5
2026-09-08T00:00:00.000Z14.2NULLNULL1000.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).

ArgumentTypeMeaning
a, bnumbertwo series, or a series and a fixed level (cross_above(rsi(close, 14), 30))

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.000Z504.9golden

(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)
CITY2026-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.

ArgumentTypeMeaning
highnumberthe candle's high
lownumberthe candle's low
closenumberthe candle's close
nwhole number, 2 or morethe period; default 14

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.000Z376.127.714.4buyers stronger
2026-09-10T09:13:00.000Z376.226.915.4buyers stronger
2026-09-10T09:12:00.000Z3762916.7buyers stronger
2026-09-10T09:11:00.000Z375.522.518.5buyers stronger
2026-09-10T09:10:00.000Z375.623.819.5buyers 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.000Z505.418.516.6
2026-09-10T05:59:00.000Z506.422.616.4
2026-09-10T06:06:00.000Z505.516.214.7
2026-09-10T06:10:00.000Z505.915.114.9
2026-09-10T06:18:00.000Z505.619.719.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.

ArgumentTypeMeaning
high, low, closenumberthe candle's high, low and close
nwhole number, 2 or morethe period; default 14

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.000Z507.9NULLNULL
2026-08-24T00:00:00.000Z510.3NULLNULL
2026-08-25T00:00:00.000Z513.3NULLNULL
2026-08-26T00:00:00.000Z513.2100NULL
2026-08-27T00:00:00.000Z505.920.9NULL
2026-08-30T00:00:00.000Z503.136.452.4
2026-08-31T00:00:00.000Z505.751.152
2026-09-01T00:00:00.000Z502.417.940.6
2026-09-02T00:00:00.000Z496.470.950.7
2026-09-03T00:00:00.000Z497.970.957.5
2026-09-06T00:00:00.000Z49970.961.9
2026-09-07T00:00:00.000Z498.777.767.2
2026-09-08T00:00:00.000Z497.571.768.7
2026-09-09T00:00:00.000Z504.674.470.6
2026-09-10T00:00:00.000Z504.92756.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:

ArgumentTypeMeaning
high, low, closenumberthe candle's high, low and close
nwhole number, 2 or morethe period; default 14

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.000Z376.117.727.714.4weak
2026-09-10T09:13:00.000Z376.216.626.915.4weak
2026-09-10T09:12:00.000Z37615.82916.7weak
2026-09-10T09:11:00.000Z375.51522.518.5weak
2026-09-10T09:10:00.000Z375.615.423.819.5weak

(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)
CITYstrong down153
CITYstrong up73
CITYwarm-up27
CITYweak227
COASTstrong down159
COASTstrong up16
COASTwarm-up27
COASTweak274

(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.

ArgumentTypeMeaning
high, low, closenumberthe candle's high, low and close
nwhole number, 2 or morethe period; default 14

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.000Z504.916.721.4weaker
2026-09-10T09:13:00.000Z505.117.922.9weaker
2026-09-10T09:12:00.000Z504.819.124.5weaker
2026-09-10T09:11:00.000Z504.519.325.5weaker
2026-09-10T09:10:00.000Z504.619.526.2weaker

(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.

ArgumentTypeMeaning
high (or low)numberthe highs for aroon_up, the lows for aroon_down
nwhole number, 1 or morethe period; default 14

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.000Z182.6178.2NULLNULL
2026-08-24T00:00:00.000Z183.6178.5NULLNULL
2026-08-25T00:00:00.000Z182.2172.8NULLNULL
2026-08-26T00:00:00.000Z178.4172NULLNULL
2026-08-27T00:00:00.000Z175.9173NULLNULL
2026-08-30T00:00:00.000Z174.2170.620100
2026-08-31T00:00:00.000Z175.6171.3080
2026-09-01T00:00:00.000Z172.1167.30100
2026-09-02T00:00:00.000Z174.6169080
2026-09-03T00:00:00.000Z177.3171.910060
2026-09-06T00:00:00.000Z183.9172.410040
2026-09-07T00:00:00.000Z183.2174.38020
2026-09-08T00:00:00.000Z183.5178.2600
2026-09-09T00:00:00.000Z189.5181.71000
2026-09-10T00:00:00.000Z192.1184.21000

(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.

ArgumentTypeMeaning
highnumberthe candle's high
lownumberthe candle's low
nwhole number, 1 or morethe period; default 14

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.000ZVOLT191.2100
2026-09-10T00:00:00.000ZCOAST376.180
2026-09-10T00:00:00.000ZCITY504.940

(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.

ArgumentTypeMeaning
highnumberthe candle's high
lownumberthe candle's low
accelerationnumber, more than 0the start and the step of the factor; default 0.02
maximumnumber, more than 0the biggest factor; default 0.2

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.000Z502508.4507.9NULLNULL
2026-08-24T00:00:00.000Z508.2510.9510.3502dot below: up trend
2026-08-25T00:00:00.000Z507.6517513.3502.18dot below: up trend
2026-08-26T00:00:00.000Z508515.3513.2502.77dot below: up trend
2026-08-27T00:00:00.000Z505.5514.3505.9503.34dot below: up trend
2026-08-30T00:00:00.000Z501.7511.2503.1517dot above: down trend
2026-08-31T00:00:00.000Z500.1506505.7516.69dot above: down trend
2026-09-01T00:00:00.000Z501.3507.3502.4516.03dot above: down trend
2026-09-02T00:00:00.000Z494.1502.8496.4515.39dot above: down trend
2026-09-03T00:00:00.000Z495.5500.9497.9514.12dot above: down trend
2026-09-06T00:00:00.000Z496500.1499512.91dot above: down trend
2026-09-07T00:00:00.000Z495501498.7511.79dot above: down trend
2026-09-08T00:00:00.000Z497.5501.1497.5510.72dot above: down trend
2026-09-09T00:00:00.000Z504512.4504.6494.1dot below: up trend
2026-09-10T00:00:00.000Z500.7507504.9494.47dot 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.000Z504.9505.78down trend: stay out
2026-09-10T09:13:00.000Z505.1505.84down trend: stay out
2026-09-10T09:12:00.000Z504.8505.9down trend: stay out
2026-09-10T09:11:00.000Z504.5505.97down trend: stay out
2026-09-10T09:10:00.000Z504.6506.04down 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.000Z367.4NULLNULL
2026-09-02T00:00:00.000Z369.2365.3365.3
2026-09-03T00:00:00.000Z373.2373.6373.6
2026-09-06T00:00:00.000Z375.4364.1364.1
2026-09-07T00:00:00.000Z379.2364.1364.1
2026-09-08T00:00:00.000Z377.2364.78364.44
2026-09-09T00:00:00.000Z380.1365.43364.77
2026-09-10T00:00:00.000Z376.1367.43365.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.

ArgumentTypeMeaning
highnumberthe candle's high
lownumberthe candle's low
nwhole number, 1 or morethe period; default 9 for tenkan, 26 for kijun

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.000Z376.1375.45375.4up
2026-09-10T09:13:00.000Z376.2375.35375.25up
2026-09-10T09:12:00.000Z376375.3375.05up
2026-09-10T09:11:00.000Z375.5375374.85up
2026-09-10T09:10:00.000Z375.6375374.75up

(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.

ArgumentTypeMeaning
high, lownumberthe candle's high and low
shortwhole number, 1 or morethe tenkan period; default 9
longwhole number, 1 or morethe kijun period; default 26
shiftwhole number, 0 or morehow many candles back the value was made; default 26

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.000Z505.1505.35505.23
2026-09-10T09:13:00.000Z505.2505.35505.28
2026-09-10T09:12:00.000Z505.2505.35505.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:

ArgumentTypeMeaning
high, lownumberthe candle's high and low
nwhole number, 1 or morethe period; default 52
shiftwhole number, 0 or morehow many candles back the value was made; default 26

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.000Z504.9505.95504.45inside the cloud
2026-09-10T09:13:00.000Z505.1505.93504.45inside the cloud
2026-09-10T09:12:00.000Z504.8505.88504.45inside the cloud
2026-09-10T09:11:00.000Z504.5505.65504.45inside the cloud
2026-09-10T09:10:00.000Z504.6505.48504.45inside 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.

ArgumentTypeMeaning
closenumberthe candle's close
shiftwhole number, 0 or morehow many candles later the close comes from; default 26

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.000Z503.1499
2026-08-31T00:00:00.000Z505.7498.7
2026-09-01T00:00:00.000Z502.4497.5
2026-09-02T00:00:00.000Z496.4504.6
2026-09-03T00:00:00.000Z497.9504.9
2026-09-06T00:00:00.000Z499NULL
2026-09-07T00:00:00.000Z498.7NULL
2026-09-08T00:00:00.000Z497.5NULL
2026-09-09T00:00:00.000Z504.6NULL
2026-09-10T00:00:00.000Z504.9NULL

(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.

ArgumentTypeMeaning
high, low, closenumberthe candle's high, low and close
nwhole number, 1 or morethe ATR period; default 10
multipliernumberhow many ATRs away the line is; default 3

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.000Z504.9506.15-1down: line is above
2026-09-10T09:13:00.000Z505.1506.15-1down: line is above
2026-09-10T09:12:00.000Z504.8506.15-1down: line is above
2026-09-10T09:11:00.000Z504.5506.15-1down: line is above
2026-09-10T09:10:00.000Z504.6506.15-1down: 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.000ZCITY504.9511.5-1
2026-09-10T00:00:00.000ZCOAST376.1384.2-1
2026-09-10T00:00:00.000ZVOLT191.2173.341

(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.

ArgumentTypeMeaning
high, low, closenumberthe candle's high, low and close
nwhole number, 1 or morethe ATR period; default 10
multipliernumberhow many ATRs away the line is; default 3

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.000Z505.8504.08BUY
2026-09-09T08:42:00.000Z508.2510.31SELL
2026-09-10T05:43:00.000Z506504.19BUY
2026-09-10T06:34:00.000Z504.8506.76SELL
2026-09-10T07:13:00.000Z502.9501.07BUY
2026-09-10T08:52:00.000Z504.7506.91SELL

(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-1200
2026-09-09131
2026-09-10-1149
2026-09-10187

(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).

ArgumentTypeMeaning
xnumberthe price, usually close
nwhole number, 2 or morehow many candles the line goes through; default 14

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.000Z507.9NULLNULL
2026-08-24T00:00:00.000Z510.3NULLNULL
2026-08-25T00:00:00.000Z513.3NULLNULL
2026-08-26T00:00:00.000Z513.2NULLNULL
2026-08-27T00:00:00.000Z505.9509.9510.12
2026-08-30T00:00:00.000Z503.1504.8509.16
2026-08-31T00:00:00.000Z505.7503.18508.24
2026-09-01T00:00:00.000Z502.4501.7506.06
2026-09-02T00:00:00.000Z496.4498.76502.7
2026-09-03T00:00:00.000Z497.9497.16501.1
2026-09-06T00:00:00.000Z499496.7500.28
2026-09-07T00:00:00.000Z498.7497.92498.88
2026-09-08T00:00:00.000Z497.5498.5497.9
2026-09-09T00:00:00.000Z504.6501.92499.54
2026-09-10T00:00:00.000Z504.9504.48500.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.

ArgumentTypeMeaning
xnumberthe price, usually close
nwhole number, 2 or morehow many candles; default 14

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.000ZCITY504.9-0.0534-0.635
2026-09-10T09:14:00.000ZCOAST376.10.1071.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.

ArgumentTypeMeaning
xnumberthe price, usually close
nwhole number, 2 or morehow many candles; default 14

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.000Z169NULLNULLNULLNULL
2026-09-02T00:00:00.000Z171.5NULLNULLNULLNULL
2026-09-03T00:00:00.000Z176NULLNULLNULLNULL
2026-09-06T00:00:00.000Z180.1NULLNULLNULLNULL
2026-09-07T00:00:00.000Z176.9169.822.44179.58179.58
2026-09-08T00:00:00.000Z182.4172.842.27181.92181.92
2026-09-09T00:00:00.000Z187.3175.562.49185.52185.52
2026-09-10T00:00:00.000Z191.2177.063.26190.1190.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.

ArgumentTypeMeaning
xnumberthe price, usually close
nwhole number, 2 or morehow many candles; default 14

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.000Z376.16.1
2026-09-10T09:13:00.000Z376.24.2
2026-09-10T09:12:00.000Z3761.8
2026-09-10T09:11:00.000Z375.5-0.4
2026-09-10T09:10:00.000Z375.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.

ArgumentTypeMeaning
xnumberthe price, usually close
nwhole number, 2 or morehow many candles; default 14

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.000Z505.9509.79503.1-6.69
2026-08-30T00:00:00.000Z503.1502.62505.73.08
2026-08-31T00:00:00.000Z505.7500.65502.41.75
2026-09-01T00:00:00.000Z502.4499.52496.4-3.12
2026-09-02T00:00:00.000Z496.4496.79497.91.11
2026-09-03T00:00:00.000Z497.9495.194993.81
2026-09-06T00:00:00.000Z499494.91498.73.79
2026-09-07T00:00:00.000Z498.7497.44497.50.06
2026-09-08T00:00:00.000Z497.5498.8504.65.8
2026-09-09T00:00:00.000Z504.6503.11504.91.79
2026-09-10T00:00:00.000Z504.9506.25NULLNULL

(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.

FunctionFormula
ha_close(open + high + low + close) / 4
ha_open(previous ha_open + previous ha_close) / 2; on the first candle (open + close) / 2
ha_highthe biggest of high, ha_open and ha_close
ha_lowthe smallest of low, ha_open and ha_close
ArgumentTypeMeaning
open, high, low, closenumberthe normal candle

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.000Z182.4181181.7182.6178.2181.05red
2026-08-24T00:00:00.000Z179.8178.5181.38183.6178.5180.1red
2026-08-25T00:00:00.000Z179.3176.8180.74182.2172.8177.78red
2026-08-26T00:00:00.000Z177.6174.2179.26179.26172175.55red
2026-08-27T00:00:00.000Z175.4173.3177.4177.4173174.4red
2026-08-30T00:00:00.000Z172.5173175.9175.9170.6172.58red
2026-08-31T00:00:00.000Z173.7172.6174.24175.6171.3173.3red
2026-09-01T00:00:00.000Z171.3169173.77173.77167.3169.93red
2026-09-02T00:00:00.000Z170.6171.5171.85174.6169171.43red
2026-09-03T00:00:00.000Z172.7176171.64177.3171.64174.48green
2026-09-06T00:00:00.000Z174.2180.1173.06183.9172.4177.65green
2026-09-07T00:00:00.000Z181.4176.9175.35183.2174.3178.95green
2026-09-08T00:00:00.000Z178.7182.4177.15183.5177.15180.7green
2026-09-09T00:00:00.000Z182187.3178.93189.5178.93185.13green
2026-09-10T00:00:00.000Z185.6191.2182.03192.1182.03188.28green

(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.000Z380.9382379.4380.8
2026-09-10T05:30:00.000Z380.85381.9379380.58
2026-09-10T06:00:00.000Z380.71382379.3380.15
2026-09-10T06:30:00.000Z380.43380.7378.8379.58
2026-09-10T07:00:00.000Z380380376.9378.3
2026-09-10T07:30:00.000Z379.15379.15376.9377.93
2026-09-10T08:00:00.000Z378.54378.54375.7377.55
2026-09-10T08:30:00.000Z378.04378.04373.2376.05
2026-09-10T09:00:00.000Z377.05377.05374.3375.6

(9 rows)