Maths
24 functions
ABS(X)Absolute value.
- X(series)
- The value to take the magnitude of.
// size of the gap, regardless of direction
GAP: ABS(OPEN - REF(CLOSE, 1));
// total distance travelled over 10 bars, used as a
// denominator for trend-efficiency style measures
TRAVEL: SUM(ABS(CLOSE - REF(CLOSE, 1)), 10);MAX(A, B, …)The largest of up to six arguments, compared bar by bar.
- A(series)
- First value to compare.
- B(series)
- Second value. Up to six may be given in total.
Also written as MAX6
// true range, spelled out — the built-in TR does the same
MTR: MAX(HIGH - LOW,
ABS(REF(CLOSE, 1) - HIGH),
ABS(REF(CLOSE, 1) - LOW));
// clamp a value at a floor of zero
POSITIVE: MAX(CLOSE - MA(CLOSE, 20), 0);MIN(A, B, …)The smallest of up to six arguments, compared bar by bar.
- A(series)
- First value to compare.
- B(series)
- Second value. Up to six may be given in total.
Also written as MIN6
// the body of the candle, whichever way it closed
BODYLOW: MIN(OPEN, CLOSE);
BODYHIGH: MAX(OPEN, CLOSE);
// cap an oscillator at 100
CAPPED: MIN(RSI, 100);MOD(A, B)Remainder of A divided by B, with sign handling for mixed signs.
- A(series)
- The dividend.
- B(series)
- The divisor.
// every 5th bar — useful for thinning out labels
EVERY5 := MOD(BARPOS, 5) = 0;
DRAWNUMBER(EVERY5, HIGH, CLOSE, 2), DRAWABOVE;POW(X, N)X raised to the power N.
- X(series)
- The base.
- N(float)
- The exponent — not a bar count.
// squared deviation, the building block of variance
DEV2: POW(CLOSE - MA(CLOSE, 20), 2);
// weight recent bars more aggressively than a linear ramp
W := POW(0.9, CURRBARSCOUNT);SQRT(X)Square root.
- X(series)
- The value to take the root of. Negative input is invalid.
// annualise a daily standard deviation (250 trading days)
DAILY := STD(CLOSE / REF(CLOSE, 1) - 1, 20);
ANNUAL: DAILY * SQRT(250) * 100, COLORYELLOW;EXP(X)e raised to the power X.
- X(series)
- The exponent.
// undo a log transform: average in log space, then come back
LOGMA := MA(LN(CLOSE), 20);
GEOMEAN: EXP(LOGMA), COLORYELLOW;LN(X)Natural logarithm.
- X(series)
- The value. Must be positive.
// log returns add up cleanly across bars, unlike percentages
LOGRET: LN(CLOSE / REF(CLOSE, 1)) * 100, COLORSTICK;
// so a 20-bar cumulative return is just their sum
CUM: SUM(LOGRET, 20);LOG(X)Base-10 logarithm.
- X(series)
- The value. Must be positive.
// compress a volume series that spans several orders of magnitude
LOGVOL: LOG(VOL), COLORSTICK;CEILING(X)Round up to the next integer.
- X(series)
- The value to round up.
// round a price up to the next whole unit — a conservative
// resistance level to draw
RES: CEILING(HHV(HIGH, 20)), COLORGRAY, DOTLINE;FLOOR(X)Round down to the previous integer.
- X(series)
- The value to round down.
// conservative support, rounded down to a whole unit
SUP: FLOOR(LLV(LOW, 20)), COLORGRAY, DOTLINE;INTPART(X)Integer part, truncating toward zero. INTPART(−3.5) is −3.
- X(series)
- The value to truncate.
// FLOOR and INTPART agree on positives and differ on negatives:
// FLOOR(-3.5) is -4, INTPART(-3.5) is -3
STEPS: INTPART((CLOSE - OPEN) / OPEN * 100);
// derive a whole-number lookback from a ratio
LEN := 10 + INTPART(STD(CLOSE, 20) / CLOSE * 200);FRACPART(X)Fractional part of X.
- X(series)
- The value whose decimals are kept.
// how far price sits above the whole unit below it —
// prices clustering near .00 often mark round-number levels
TICKPOS: FRACPART(CLOSE);
NEARROUND: TICKPOS < 0.05 OR TICKPOS > 0.95;ROUND(X)Round to the nearest integer.
- X(series)
- The value to round.
// nearest whole-number level to the current price
LEVEL: ROUND(CLOSE), COLORGRAY, STEPLINE;ROUND2(X, N)Round to N decimal places.
- X(series)
- The value to round.
- N(integer)
- Number of decimal places to keep — not a bar count.
// keep two decimals for display
PCT: ROUND2((CLOSE - OPEN) / OPEN * 100, 2);
// rounding for display only — VAR2STR already formats,
// so use ROUND2 when the rounded number feeds further maths
DRAWTEXT(ISLASTBAR, HIGH, VARCAT(VAR2STR(PCT, 2), '%'));SIGN(X)1, 0 or −1 according to the sign of X.
- X(series)
- The value whose sign is taken.
// direction of the bar, as +1 / 0 / -1
DIR: SIGN(CLOSE - OPEN);
// signed volume in one line, no nested IF
FLOW: SUM(SIGN(CLOSE - REF(CLOSE, 1)) * VOL, 0), COLORYELLOW;RAND(N)A random integer in 1…N.
- N(integer)
- Upper bound of the range — not a bar count.
// a random walk to compare a strategy against —
// redraws differently on every run, so never use it in a signal
STEP := IF(RAND(2) = 1, 1, -1);
WALK: SUM(STEP, 0), COLORGRAY;NOT(X)1 where X is 0, otherwise 0.
- X(condition)
- The condition to invert.
// the first bar of a run — true now, false on the bar before
ABOVE := CLOSE > MA(CLOSE, 20);
ENTRY := ABOVE AND NOT(REF(ABOVE, 1));
DRAWICON(ENTRY, LOW, 85);SIN(X)Sine of X in radians.
- X(series)
- Angle in radians.
// a 20-bar cycle wave, for eyeballing rhythm against price
WAVE: SIN(BARPOS / 20 * 6.2832) * 100, COLORGRAY;COS(X)Cosine of X in radians.
- X(series)
- Angle in radians.
// quarter-cycle ahead of the sine wave above
WAVE2: COS(BARPOS / 20 * 6.2832) * 100, COLORLIBLUE;TAN(X)Tangent of X in radians.
- X(series)
- Angle in radians.
// slope of a trend line, expressed as a price change per bar
ANGLE := ATAN(SLOPE(CLOSE, 20));
PERBAR: TAN(ANGLE);ASIN(X)Arcsine. Values outside −1…1 are invalid.
- X(series)
- A value between −1 and 1.
// map a normalised oscillator back onto an angle
NORM := (CLOSE - MA(CLOSE, 20)) / (2 * STD(CLOSE, 20));
ANG: ASIN(MAX(MIN(NORM, 1), -1)); // clamp first, or it goes invalidACOS(X)Arccosine. Values outside −1…1 are invalid.
- X(series)
- A value between −1 and 1.
// angle between two series, from their correlation
R := RELATE(CLOSE, VOL, 20);
ANG: ACOS(MAX(MIN(R, 1), -1));ATAN(X)Arctangent.
- X(series)
- Any value — unlike ASIN and ACOS there is no valid range to respect.
// trend angle in degrees: steeper slope, larger angle,
// but always bounded, which makes it comparable across symbols
SLP := SLOPE(CLOSE, 20) / CLOSE * 100;
DEG: ATAN(SLP) * 57.2958, COLORYELLOW;