KDB knowledge

Trigonometry and probability

Sine, cosine, tangent and their inverses, hyperbolic functions, and the normal distribution (chance, bell height and inverse).

These functions work with angles and with chances.

Angles. An angle can be measured in degrees (a full circle is 360°) or in radians (a full circle is 2π, about 6.28). All functions here use radians. Change degrees to radians with radians, and back with degrees: sin(radians(30)) is 0.5.

Rules

Example: Angles in degrees and radians, with sine and cosine (sample data: sample)

SELECT deg, round(radians(deg), 4) AS rad, round(sin(radians(deg)), 4) AS sin, round(cos(radians(deg)), 4) AS cos
FROM (SELECT 0 AS deg UNION ALL SELECT 30 UNION ALL SELECT 45 UNION ALL SELECT 90 UNION ALL SELECT 180) t
ORDER BY deg;

Result:

deg (LONG)rad (DOUBLE)sin (DOUBLE)cos (DOUBLE)
0001
300.52360.50.866
450.78540.70710.7071
901.570810
1803.14160-1

(5 rows)

sin

Syntax:

sin(x)

The sine of the angle x (in radians). As the angle goes round the circle, the sine goes smoothly up and down between -1 and 1, like a wave. Use it to make a cycle: sin(2 × π × day / 8) repeats every 8 days.

ArgumentTypeMeaning
xany numberan angle in radians

Example (sample data: sample)

SELECT sin(0) AS a, sin(pi() / 2) AS b, round(sin(radians(30)), 4) AS c, round(sin(pi()), 10) AS d;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)d (DOUBLE)
010.50

(1 row)

Example: An 8-day wave next to CITY's close (sample data: sample)

SELECT time, close, round(sin(2 * pi() * row_number() / 8), 3) AS wave
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-09-02'
ORDER BY time;

Result:

time (TIMESTAMP)close (DOUBLE)wave (DOUBLE)
2026-09-02T00:00:00.000Z496.40.707
2026-09-03T00:00:00.000Z497.91
2026-09-06T00:00:00.000Z4990.707
2026-09-07T00:00:00.000Z498.70
2026-09-08T00:00:00.000Z497.5-0.707
2026-09-09T00:00:00.000Z504.6-1
2026-09-10T00:00:00.000Z504.9-0.707

(7 rows)

cos

Syntax:

cos(x)

The cosine of the angle x (in radians): the same wave as sin, a quarter circle earlier. cos(0) is 1.

ArgumentTypeMeaning
xany numberan angle in radians

Example (sample data: sample)

SELECT cos(0) AS a, round(cos(pi() / 2), 10) AS b, cos(pi()) AS c, round(cos(radians(60)), 4) AS d;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)d (DOUBLE)
10-10.5

(1 row)

Example: Months on a circle: December is next to January, July is far away (sample data: sample)

SELECT m AS month,
       round(sin(2 * pi() * (m - 1) / 12), 3) AS month_sin,
       round(cos(2 * pi() * (m - 1) / 12), 3) AS month_cos
FROM (SELECT 1 AS m UNION ALL SELECT 4 UNION ALL SELECT 7 UNION ALL SELECT 12) t
ORDER BY m;

Result:

month (LONG)month_sin (DOUBLE)month_cos (DOUBLE)
101
410
70-1
12-0.50.866

(4 rows)

tan

Syntax:

tan(x)

The tangent of the angle x (in radians): sin(x) / cos(x). It is the slope of a line with that angle: how much it goes up for one step to the right. tan(radians(45)) is 1.

ArgumentTypeMeaning
xany numberan angle in radians

Example: Rise per step for a line at 10, 30, 45 and 60 degrees (sample data: sample)

SELECT deg, round(tan(radians(deg)), 4) AS rise_per_step
FROM (SELECT 10 AS deg UNION ALL SELECT 30 UNION ALL SELECT 45 UNION ALL SELECT 60) t
ORDER BY deg;

Result:

deg (LONG)rise_per_step (DOUBLE)
100.1763
300.5774
451
601.7321

(4 rows)

cot

Syntax:

cot(x)

The cotangent of the angle x (in radians): 1 / tan(x), or cos(x) / sin(x).

ArgumentTypeMeaning
xany numberan angle in radians

Example (sample data: sample)

SELECT round(cot(radians(45)), 4) AS a, round(cot(radians(60)), 4) AS b, round(1 / tan(radians(60)), 4) AS same, cot(0) AS zero;

Result:

a (DOUBLE)b (DOUBLE)same (DOUBLE)zero (STRING)
10.57740.5774NULL

(1 row)

asin

Syntax:

asin(x)

The arc sine: the angle whose sine is x. It undoes sin. asin(1) is π/2 (90°).

ArgumentTypeMeaning
xnumber from -1 to 1a sine value

Example (sample data: sample)

SELECT asin(1) AS a, degrees(asin(0.5)) AS b_degrees, degrees(asin(-1)) AS c_degrees, asin(2) AS out_of_range;

Result:

a (DOUBLE)b_degrees (DOUBLE)c_degrees (DOUBLE)out_of_range (STRING)
1.570796326794930-90NULL

(1 row)

acos

Syntax:

acos(x)

The arc cosine: the angle whose cosine is x. It undoes cos. acos(1) is 0, acos(-1) is π (180°).

ArgumentTypeMeaning
xnumber from -1 to 1a cosine value

Example (sample data: sample)

SELECT acos(1) AS a, degrees(acos(0.5)) AS b_degrees, degrees(acos(-1)) AS c_degrees, acos(-2) AS out_of_range;

Result:

a (DOUBLE)b_degrees (DOUBLE)c_degrees (DOUBLE)out_of_range (STRING)
060180NULL

(1 row)

atan

Syntax:

atan(x)

The arc tangent: the angle whose tangent is x. It undoes tan, and turns a slope into an angle. degrees(atan(1)) is 45.

ArgumentTypeMeaning
xany numbera tangent value (a slope)

Example (sample data: sample)

SELECT atan(0) AS a, degrees(atan(1)) AS b_degrees, degrees(atan(-1)) AS c_degrees, round(degrees(atan(1000000)), 3) AS almost_90;

Result:

a (DOUBLE)b_degrees (DOUBLE)c_degrees (DOUBLE)almost_90 (DOUBLE)
045-4590

(1 row)

Example: Trend angle of VOLT: the rise over 4 days, in % per day, as an angle (sample data: sample)

SELECT time, close, pct_per_day, round(degrees(atan(pct_per_day)), 1) AS angle_degrees
FROM (SELECT time, close, round((close / lag(close, 4) - 1) * 100 / 4, 3) AS pct_per_day
      FROM ochl_day
      WHERE symbol = 'VOLT' AND time >= '2026-08-23') t
WHERE time >= '2026-09-06'
ORDER BY time;

Result:

time (TIMESTAMP)close (DOUBLE)pct_per_day (DOUBLE)angle_degrees (DOUBLE)
2026-09-06T00:00:00.000Z180.11.08647.4
2026-09-07T00:00:00.000Z176.91.16949.5
2026-09-08T00:00:00.000Z182.41.58957.8
2026-09-09T00:00:00.000Z187.31.60558.1
2026-09-10T00:00:00.000Z191.21.54157

(5 rows)

atan2

Syntax:

atan2(y, x)

The angle of the point (x, y) as seen from (0, 0). Unlike atan(y / x), it knows which quarter of the circle the point is in, and it works when x is 0. Note the order: y comes first.

ArgumentTypeMeaning
yany numberthe up-down position
xany numberthe left-right position

Example: The angle of four points, one in each quarter (sample data: sample)

SELECT x, y, round(degrees(atan2(y, x)), 1) AS angle_degrees, round(degrees(atan(y / x)), 1) AS atan_of_ratio
FROM (SELECT 1 AS x, 1 AS y UNION ALL SELECT -1, 1 UNION ALL SELECT -1, -1 UNION ALL SELECT 1, -1) t;

Result:

x (LONG)y (LONG)angle_degrees (DOUBLE)atan_of_ratio (DOUBLE)
114545
-11135-45
-1-1-13545
1-1-45-45

(4 rows)

sinh, cosh, tanh

Syntax:

sinh(x)
cosh(x)
tanh(x)

The hyperbolic sine, cosine and tangent. They are made from exp: sinh(x) = (e^x - e^-x) / 2, cosh(x) = (e^x + e^-x) / 2, tanh(x) = sinh(x) / cosh(x). The most useful one for data is tanh: it squashes any number into the range -1 to 1. Small values stay almost the same; very big values come close to 1 (or -1).

ArgumentTypeMeaning
xany numberthe value

Example (sample data: sample)

SELECT sinh(0) AS sinh_0, round(sinh(1), 4) AS sinh_1, cosh(0) AS cosh_0, round(tanh(1), 4) AS tanh_1, round(tanh(5), 4) AS tanh_5, round(tanh(-5), 4) AS tanh_minus_5, sinh(1000) AS too_big;

Result:

sinh_0 (DOUBLE)sinh_1 (DOUBLE)cosh_0 (DOUBLE)tanh_1 (DOUBLE)tanh_5 (DOUBLE)tanh_minus_5 (DOUBLE)too_big (STRING)
01.175210.76160.9999-0.9999NULL

(1 row)

Example: A signal from -1 to 1: tanh of the daily % change (sample data: sample)

SELECT time, symbol, round(chg, 2) AS change_pct, round(tanh(chg), 3) AS signal
FROM (SELECT time, symbol, pct_change(close) OVER (PARTITION BY symbol ORDER BY time) AS chg
      FROM ochl_day
      WHERE time >= '2026-09-06') t
WHERE time IN '2026-09-09'
ORDER BY symbol;

Result:

time (TIMESTAMP)symbol (SYMBOL)change_pct (DOUBLE)signal (DOUBLE)
2026-09-09T00:00:00.000ZCITY1.430.891
2026-09-09T00:00:00.000ZCOAST0.770.646
2026-09-09T00:00:00.000ZVOLT2.690.991

(3 rows)

asinh, acosh, atanh

Syntax:

asinh(x)
acosh(x)
atanh(x)

The inverse hyperbolic functions: they undo sinh, cosh and tanh.

FunctionAllowed xUse
asinh(x)any numberlike a logarithm that also works for 0 and negative numbers: good to shrink big profits and losses for a chart
acosh(x)1 or moreundoes cosh
atanh(x)more than -1 and less than 1undoes tanh; it is the Fisher transform that traders use to make turning points of an oscillator sharper

Example (sample data: sample)

SELECT round(asinh(1), 4) AS asinh_1, acosh(1) AS acosh_1, round(atanh(0.5), 4) AS atanh_half, round(atanh(tanh(0.3)), 4) AS back_to_0_3, acosh(0.5) AS out_of_range, atanh(1) AS atanh_1;

Result:

asinh_1 (DOUBLE)acosh_1 (DOUBLE)atanh_half (DOUBLE)back_to_0_3 (DOUBLE)out_of_range (STRING)atanh_1 (STRING)
0.881400.54930.3NULLNULL

(1 row)

Example: Shrink profits and losses with asinh (works for 0 and minus) (sample data: sample)

SELECT pnl, round(asinh(pnl), 2) AS scaled
FROM (SELECT -100000 AS pnl UNION ALL SELECT -500 UNION ALL SELECT 0 UNION ALL SELECT 500 UNION ALL SELECT 100000) t
ORDER BY pnl;

Result:

pnl (LONG)scaled (DOUBLE)
-100000-12.21
-500-6.91
00
5006.91
10000012.21

(5 rows)

normal_cdf

Syntax:

normal_cdf(x)
normal_cdf(x, mean, stddev)

Many values spread around their average like a bell: most values are near the average, few are far away. The normal distribution is this bell shape. It is described by two numbers: the mean (the middle) and the standard deviation (how wide the bell is; see stddev).

normal_cdf gives the chance that a value is at or below x, as a number from 0 to 1. For example, if CITY's daily return has mean -0.04% and standard deviation 0.75%, normal_cdf(-2, -0.04, 0.75) is the chance of a day worse than -2%.

ArgumentTypeMeaning
xany numberthe value
meanany numberthe middle of the bell; default 0
stddevnumber, more than 0the width of the bell; default 1

Example (sample data: sample)

SELECT normal_cdf(0) AS at_mean, round(normal_cdf(1.96), 4) AS z_1_96, round(normal_cdf(-1), 4) AS z_minus_1, round(normal_cdf(110, 100, 10), 4) AS one_sd_above;

Result:

at_mean (DOUBLE)z_1_96 (DOUBLE)z_minus_1 (DOUBLE)one_sd_above (DOUBLE)
0.50.9750.15870.8413

(1 row)

Example: Chance of a day worse than -2%, from each share's daily returns (sample data: sample)

SELECT symbol, count(chg) AS days,
       round(avg(chg), 3) AS mean_pct,
       round(stddev(chg), 3) AS stddev_pct,
       round(normal_cdf(-2, avg(chg), stddev(chg)) * 100, 1) AS chance_pct
FROM (SELECT symbol, pct_change(close) OVER (PARTITION BY symbol ORDER BY time) AS chg
      FROM ochl_day
      WHERE time >= '2026-08-23') t
GROUP BY symbol
ORDER BY symbol;

Result:

symbol (SYMBOL)days (LONG)mean_pct (DOUBLE)stddev_pct (DOUBLE)chance_pct (DOUBLE)
CITY14-0.040.7460.4
COAST14-0.2711.1456.5
VOLT140.4091.88510.1

(3 rows)

Example: The standard deviation must be more than 0 (sample data: sample; shows an error)

SELECT normal_cdf(1, 0, 0);

Result:

Error: line 1, column 8: normal_cdf: the standard deviation must be more than 0

normal_pdf

Syntax:

normal_pdf(x)
normal_pdf(x, mean, stddev)

The height of the bell at x (the "density"). It is highest at the mean and gets lower far from it. The height itself is not a chance; compare two heights to see which value is more usual.

ArgumentTypeMeaning
xany numberthe value
meanany numberthe middle of the bell; default 0
stddevnumber, more than 0the width of the bell; default 1

Example: The bell is highest at the mean (sample data: sample)

SELECT z, round(normal_pdf(z), 4) AS height, round(normal_pdf(z) / normal_pdf(0), 3) AS compared_to_mean
FROM (SELECT 0 AS z UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t
ORDER BY z;

Result:

z (LONG)height (DOUBLE)compared_to_mean (DOUBLE)
00.39891
10.2420.607
20.0540.135
30.00440.011

(4 rows)

Example (sample data: sample)

SELECT round(normal_pdf(100, 100, 10), 5) AS at_mean, round(normal_pdf(120, 100, 10), 5) AS two_sd_away;

Result:

at_mean (DOUBLE)two_sd_away (DOUBLE)
0.039890.0054

(1 row)

normal_inv

Syntax:

normal_inv(p)
normal_inv(p, mean, stddev)

The opposite of normal_cdf: the value x that has a chance p of being at or below it. normal_inv(0.975) is about 1.96. Use it to find a level that is crossed only a small part of the time, for example the daily return that is worse only 5% of the days (a simple value at risk; see also value_at_risk).

ArgumentTypeMeaning
pnumber, more than 0 and less than 1the chance
meanany numberthe middle of the bell; default 0
stddevnumber, more than 0the width of the bell; default 1

Example: z-scores for 90%, 95% and 99% confidence (sample data: sample)

SELECT round(normal_inv(0.95), 3) AS z_90_two_sided, round(normal_inv(0.975), 3) AS z_95_two_sided, round(normal_inv(0.995), 3) AS z_99_two_sided, normal_inv(0.5, 100, 10) AS middle;

Result:

z_90_two_sided (DOUBLE)z_95_two_sided (DOUBLE)z_99_two_sided (DOUBLE)middle (DOUBLE)
1.6451.962.576100

(1 row)

Example: The daily return that is worse only 5% of the days (sample data: sample)

SELECT symbol, round(avg(chg), 3) AS mean_pct, round(stddev(chg), 3) AS stddev_pct,
       round(normal_inv(0.05, avg(chg), stddev(chg)), 2) AS worst_5pct_day
FROM (SELECT symbol, pct_change(close) OVER (PARTITION BY symbol ORDER BY time) AS chg
      FROM ochl_day
      WHERE time >= '2026-08-23') t
GROUP BY symbol
ORDER BY symbol;

Result:

symbol (SYMBOL)mean_pct (DOUBLE)stddev_pct (DOUBLE)worst_5pct_day (DOUBLE)
CITY-0.040.746-1.27
COAST-0.2711.145-2.15
VOLT0.4091.885-2.69

(3 rows)

Example: p must be more than 0 and less than 1 (sample data: sample; shows an error)

SELECT normal_inv(1);

Result:

Error: line 1, column 8: normal_inv: the probability must be more than 0 and less than 1