Thesis built-ins, version 1#

Every name a script can use, with what it produces and what it costs.

This reference is generated from the compiler's own catalogs, so it lists exactly what the compiler has.

The specification is the language itself: types, na, series, control flow and the determinism contract. state below means the function remembers something between bars, which is why calling one inside an if is warning AS2060 - its history then has gaps.

Bar variables#

A script reads the bar it is running on by name.

Name Type Fixed for the run Meaning
open float no This bar's first traded price.
high float no This bar's highest traded price.
low float no This bar's lowest traded price.
close float no This bar's last traded price - the one a script usually means.
volume float no This bar's traded volume, in the venue's own unit.
hl2 float no The average of the high and the low.
hlc3 float no The average of the high, the low and the close.
ohlc4 float no The average of the open, high, low and close.
time int no This bar's open time, as a millisecond epoch in UTC.
bar_index int no How many bars came before this one; 0 on the first.
last_bar_index int no The index of the last bar of the run.
time_close int no This bar's close time - its open time plus the timeframe - as a millisecond epoch in UTC.
year int no This bar's UTC calendar year.
month int no This bar's UTC month, 1 to 12.
dayofmonth int no This bar's UTC day of the month, 1 to 31.
dayofweek int no This bar's UTC weekday, ISO numbered: Monday is 1 and Sunday is 7.
hour int no This bar's UTC hour, 0 to 23.
minute int no This bar's UTC minute, 0 to 59.
second int no This bar's UTC second, 0 to 59.
weekofyear int no This bar's ISO 8601 week of the year, 1 to 53.

symbol.#

Facts about the instrument. Fixed for the run, so one of these may be a window length.

Name Type Fixed for the run Meaning
symbol.tick_size float yes The smallest price increment of the instrument.
symbol.pip_size float yes The price distance of one pip, which is what a stop distance is usually quoted in.
symbol.pip_value float yes What one pip is worth, in the account currency, for a position of ONE instrument unit. Multiply by the quantity to price a stop.
symbol.tick_value float yes What one tick is worth, in the account currency, for a position of ONE instrument unit.
symbol.spread float no The current spread in price units, or na when the host quotes none.
symbol.bid float no The price a long position would be closed at right now: this bar's close less half the spread.
symbol.ask float no The price a long position would be opened at right now: this bar's close plus half the spread.
symbol.digits int yes Decimal places a price is quoted to.
symbol.lot_size float yes Instrument units in one lot. 1 where the market has no lots.
symbol.min_qty float yes Smallest order size, in instrument units.
symbol.max_qty float yes Largest order size, or na when the venue states none.
symbol.qty_step float yes Granularity of an order size, in instrument units.
symbol.name string yes The instrument's code, as the venue spells it.
symbol.base string yes The asset being bought or sold.
symbol.quote string yes The asset a profit is denominated in.

timeframe.#

The bar period.

Name Type Fixed for the run Meaning
timeframe.minutes int yes Length of one bar, in minutes.
timeframe.name string yes The bar period's name, such as h1.

account.#

The account as of this bar. A bot reads these; an indicator sees an empty account.

Name Type Fixed for the run Meaning
account.balance float no Realized balance.
account.equity float no Balance plus the profit of every open position.
account.margin_free float no Equity the open positions do not tie up.
account.currency string no Currency the balance is denominated in.

position.#

The open positions as of this bar.

Name Type Fixed for the run Meaning
position.count int no How many positions are open.
position.qty float no Net open quantity in instrument units, negative when net short.
position.entry_price float no Volume-weighted entry price, or na when flat.
position.profit float no Open profit in the account currency.
position.id int no The oldest open position's id, or na when flat. What trade.close takes.
position.bars int no Bars since the oldest open position was opened.
position.is_long bool no Whether any open position is long.
position.is_short bool no Whether any open position is short.
position.stop_loss float no The oldest open position's stop level, or na when it has none.
position.take_profit float no The oldest open position's target level, or na when it has none.
position.last_id int no The id of the position opened most recently in this run, or na before the first one. Read it right after trade.buy or trade.sell to address what you just opened.

order.#

The pending orders resting as of this bar.

Name Type Fixed for the run Meaning
order.count int no How many orders are resting, waiting for their price.
order.id int no The oldest resting order's id, or na when nothing is resting. What trade.cancel takes.
order.last_id int no The id of the order placed most recently in this run, or na before the first one.
order.cancelled int no How many orders have left the book without filling in this run - cancelled by the script, expired, or withdrawn by the host.
order.last_cancel string no Why the most recent order left the book without filling: script, expired, insufficient_margin, invalid_protection or end_of_data. na while none has.

barstate.#

Where in the run this bar is.

Name Type Fixed for the run Meaning
barstate.isfirst bool no True on the first bar of the run.
barstate.islast bool no True on the last bar of the run.

trades.#

The positions this run has already closed. A bot reads these; an indicator sees none.

Name Type Fixed for the run Meaning
trades.closed int no How many positions this run has closed so far.
trades.wins int no How many of them closed at a profit.
trades.losses int no How many of them closed at a loss.
trades.net_profit float no Realized profit of every closed position, net of commission.
trades.gross_profit float no Realized profit of the winning positions only.
trades.gross_loss float no Realized loss of the losing positions, as a positive number.
trades.last_profit float no The most recently closed position's profit, or na before the first one.
trades.last_exit_bar int no The bar index the most recent position closed on, or na before the first one.
trades.max_drawdown float no The largest drop from a peak of equity so far, in the account currency.

Reading one position#

Facts about ONE open position, addressed by its id, by its place in the list or by the label it was opened with. This is how a grid, a pyramid, an averaging-down rule or a hedge reaches its second position; position.last_id is the id of the one just opened.

Call Produces What it reads
position.id_at(index) int The id of the open position at this place in the list, oldest first. na past the last one.
position.qty_of(id) float That position's size in instrument units, signed: negative when it is short.
position.entry_of(id) float The price that position was opened at.
position.profit_of(id) float That position's open profit in the account currency, net of its swap.
position.bars_of(id) int How many bars ago that position was opened.
position.is_long_of(id) bool Whether that position is long. false when it is short, na when there is no such position.
position.sl_of(id) float That position's stop level, or na when it has none.
position.tp_of(id) float That position's target level, or na when it has none.
position.swap_of(id) float The financing that position has accrued so far, in the account currency.
position.pips_of(id) float How far that position has moved in its favour, in pips. Negative when it is losing.
position.label_of(id) string The label trade.buy or trade.sell gave that position, or na when it was opened without one.
position.comment_of(id) string The comment that position was opened with, or na when it has none.
position.id_of(label) int The id of the OLDEST open position carrying this label, or na when none does.
position.last_id_of(label) int The id of the NEWEST open position carrying this label, or na when none does.
position.count_of(label) int How many open positions carry this label. 0 when none does.

Reading one order#

Facts about ONE resting order, addressed by its id, by its place in the list or by its label.

Call Produces What it reads
order.id_at(index) int The id of the resting order at this place in the list, oldest first. na past the last one.
order.price_of(id) float The price that order rests at.
order.qty_of(id) float That order's size in instrument units.
order.is_buy_of(id) bool Whether that order buys. false when it sells, na when there is no such order.
order.label_of(id) string The label that order was placed with, or na when it has none.
order.id_of(label) int The id of the oldest resting order carrying this label, or na when none does.
order.count_of(label) int How many resting orders carry this label. 0 when none does.

Sizing a position#

Turning money into a quantity, and a quantity into margin. These are the arithmetic a bot would otherwise have to do with numbers the host knows and it does not: the pip value in the account currency, the quantity step the venue insists on, and the leverage of the account.

Call Produces What it reads
symbol.qty_for_risk(money) float The largest quantity, in instrument units, whose loss at a stop that far away is at most this much money in the account currency. Rounded DOWN to symbol.qty_step, and 0 when even the smallest tradeable size would risk more.
symbol.round_qty(units) float That quantity rounded DOWN to a whole multiple of symbol.qty_step, or 0 when it is below symbol.min_qty. A quantity the venue would refuse never reaches it.
symbol.margin_for(units) float The margin a position of that size would tie up at this bar's price, in the account currency.

Declarations#

These are not ordinary functions: they say what the script IS, so each one must appear at the top level of the main file, with values written out rather than computed.

Form What it declares
indicator(title, label=, on_price=, precision=) The script is an indicator.
bot(title, qty_type=, qty_value=, warmup=) The script is a bot.
module(name) The file is a module: functions only, no inputs and no trading.
import "File.thesis" as alias Brings a module's exported functions in under an alias.
input.int(default, title, min=, max=, step=, group=, tooltip=) A whole-number input. One with min, max and step can be optimized.
input.float(default, title, min=, max=, step=, group=, tooltip=) A decimal input.
input.bool(default, title, group=, tooltip=) A true/false input.
input.string(default, title, opts=, group=, tooltip=) A text input, optionally one of a fixed set.
input.source(default, title, group=, tooltip=) Which price series to read: a series, not a fixed value.
input.color(default, title, group=, tooltip=) A colour input.
plot(value, name, color=, width=, style=, on_price=) One output series. na means "not calculated on this bar".
hline(value, name, color=, style=) A fixed horizontal level. The value is written out here.
marker(condition, name, shape=, position=, color=, value=) A mark on the bars where the condition holds.

Trading and logging#

Platform and market agnostic: a quantity is in INSTRUMENT UNITS - coins, shares, contracts, or the units of a currency pair - and lots are a presentation detail the host applies through symbol.lot_size. Every call returns true when the host accepted it; a rejection is a value, and trade.error names the last one. Only a bot may trade.

Call Produces What it does
trade.buy([qty], sl=, tp=, sl_dist=, tp_dist=, trail=, breakeven=, tp1=, tp1_qty=, tp2=, tp2_qty=, tp3=, tp3_qty=, tp4=, tp4_qty=, label=, comment=) bool Buys at market. Omitted quantity uses the bot(...) declaration. A label is text the position carries, so a bot can find its own positions and a report can group trades by the rule that opened them; a comment is free text beside it.
trade.sell([qty], sl=, tp=, sl_dist=, tp_dist=, trail=, breakeven=, tp1=, tp1_qty=, tp2=, tp2_qty=, tp3=, tp3_qty=, tp4=, tp4_qty=, label=, comment=) bool Sells at market.
trade.close(id) bool Closes one position.
trade.close_all() bool Closes every open position of this run's instrument.
trade.modify(id, sl=, tp=) bool Moves a position's protection; na clears a level.
trade.close_partial(id, qty) bool Closes qty units of a position and leaves the rest open at the same entry.
trade.trail(id, dist) bool Tightens a position's stop to dist from this bar's close and never loosens it. It may move the stop PAST the entry price, which is how a profit is locked in; only a level on the wrong side of the market is refused.
trade.buy_limit([qty], price, sl=, tp=, sl_dist=, tp_dist=, trail=, breakeven=, tp1=, tp1_qty=, tp2=, tp2_qty=, tp3=, tp3_qty=, tp4=, tp4_qty=, expire=, label=, comment=) bool Rests a buy limit at price; it fills when the market falls to it. The position it becomes inherits its label, comment and every protection argument.
trade.sell_limit([qty], price, sl=, tp=, sl_dist=, tp_dist=, trail=, breakeven=, tp1=, tp1_qty=, tp2=, tp2_qty=, tp3=, tp3_qty=, tp4=, tp4_qty=, expire=, label=, comment=) bool Rests a sell limit at price; it fills when the market rises to it.
trade.buy_stop([qty], price, limit=, sl=, tp=, sl_dist=, tp_dist=, trail=, breakeven=, tp1=, tp1_qty=, tp2=, tp2_qty=, tp3=, tp3_qty=, tp4=, tp4_qty=, expire=, label=, comment=) bool Rests a buy stop above the market; limit= makes it a stop-limit.
trade.sell_stop([qty], price, limit=, sl=, tp=, sl_dist=, tp_dist=, trail=, breakeven=, tp1=, tp1_qty=, tp2=, tp2_qty=, tp3=, tp3_qty=, tp4=, tp4_qty=, expire=, label=, comment=) bool Rests a sell stop below the market; limit= makes it a stop-limit.
trade.cancel(id) bool Cancels one resting order.
trade.modify_order(id, price=, limit=, qty=, sl=, tp=, expire=) bool Moves a resting order and keeps its id. Every argument left out keeps what the order already had, and the moved order is validated as a new one would be.
trade.cancel_all() bool Cancels every resting order of this run's instrument.
trade.error string Why the last call was refused: none, insufficient_margin, invalid_volume, invalid_protection, invalid_order_price, not_found, not_supported or closed.
log.info(text) - Records a line in the run's log.
log.warn(text) - As log.info, marked as a warning.
log.error(text) - As log.info, marked as an error.

Core functions#

Absent values, and what to do about them.

Call Produces State What it does
fixnan(value) float yes the last value that was not na, carried forward.
na(value) bool no true when the value is absent.
na(text) bool no true when the text is absent - the form na takes for a string argument.
nz(value[, replacement]) float no the value, or the replacement when it is na - 0 by default.
nz(text[, replacement]) string no the text, or the replacement when it is na - an empty string by default; the form nz takes for a string argument.

math.#

Arithmetic. Deterministic: there is no math.random.

Call Produces State What it does
math.abs(value) float no the value without its sign.
math.acos(value) float no the angle whose cosine is the value; na outside -1..1.
math.asin(value) float no the angle whose sine is the value; na outside -1..1.
math.atan(value) float no the angle whose tangent is the value.
math.atan2(y, x) float no the angle of the point (x, y) from the x axis.
math.avg(first, second) float no the mean of two values; na when either is na.
math.ceil(value) int no the smallest whole number at or above the value.
math.clamp(value, lower, upper) float no the value held inside lower..upper; na when any of the three is na.
math.cos(angle) float no the cosine of an angle in radians.
math.exp(value) float no e raised to the value.
math.floor(value) int no the largest whole number at or below the value.
math.idiv(dividend, divisor) int no whole division, truncated towards zero; na when dividing by zero.
math.log(value) float no the natural logarithm; na at or below zero.
math.log10(value) float no the base-10 logarithm; na at or below zero.
math.max(first, second) float no the larger of two values; na when either is na.
math.min(first, second) float no the smaller of two values; na when either is na.
math.pow(base, exponent) float no the base raised to the exponent.
math.round(value[, simple digits]) float no the value rounded to the given number of digits, half away from zero.
math.round_to_tick(price) float no the price rounded to the instrument's tick size, half away from zero.
math.sign(value) int no -1, 0 or 1 by the value's sign.
math.sin(angle) float no the sine of an angle in radians.
math.sqrt(value) float no the square root; na for a negative value.
math.sum(value, simple length) float yes the sum of the last length values.
math.tan(angle) float no the tangent of an angle in radians.
math.todegrees(radians) float no radians as degrees.
math.toradians(degrees) float no degrees as radians.

ta.#

Technical analysis. Every one of these keeps state per call site (spec section 9).

Call Produces State What it does
ta.accdist() float yes the accumulation/distribution line.
ta.alma(source, simple length[, simple offset, simple sigma]) float yes Arnaud Legoux's moving average: a Gaussian window of length, centred at offset of 0..1 and as wide as length/sigma.
ta.atr(simple length) float yes the average true range over length bars, smoothed as ta.rma.
ta.barssince(condition) int yes how many bars ago the condition was last true; na until it has been.
ta.bb(source, simple length, multiplier) 3 x float yes the middle, upper and lower Bollinger bands.
ta.bbw(source, simple length, multiplier) float yes the width of the Bollinger bands as a share of the middle band.
ta.cci(source, simple length) float yes the commodity channel index over length bars.
ta.change(source[, simple length]) float yes the value minus its value length bars ago - 1 by default.
ta.cmo(source, simple length) float yes Chande's momentum oscillator over length bars, -100 to 100.
ta.cog(source, simple length) float yes the centre of gravity of the window, in bars and negative.
ta.correlation(first, second, simple length) float yes Pearson's correlation of the two sources over the window, -1 to 1.
ta.cross(first, second) bool yes true on the bar the two values cross in either direction.
ta.crossover(first, second) bool yes true on the bar the first value crosses above the second.
ta.crossunder(first, second) bool yes true on the bar the first value crosses below the second.
ta.cum(value) float yes the running total of every value so far.
ta.dev(source, simple length) float yes the mean absolute deviation from the simple moving average.
ta.dmi(simple length, simple smoothing) 3 x float yes the positive and negative directional indicators and the average directional index.
ta.ema(source, simple length) float yes the exponential moving average, smoothing 2/(length+1), seeded with the first simple average.
ta.falling(source, simple length) bool yes true when the source fell on each of the last length bars.
ta.highest(source, simple length) float yes the highest value of the last length bars.
ta.highestbars(source, simple length) int yes how many bars ago the highest value of the window was.
ta.hma(source, simple length) float yes Hull's moving average: 2*wma(length/2) - wma(length), smoothed over sqrt(length).
ta.iii() float yes the intraday intensity index of this bar.
ta.kc(source, simple length, multiplier) 3 x float yes the middle, upper and lower Keltner channels, widened by the average true range.
ta.kcw(source, simple length, multiplier) float yes the width of the Keltner channels as a share of the middle.
ta.linreg(source, simple length[, simple offset]) float yes the value of a least-squares line fitted to the window, offset bars along it.
ta.lowest(source, simple length) float yes the lowest value of the last length bars.
ta.lowestbars(source, simple length) int yes how many bars ago the lowest value of the window was.
ta.macd(source, simple fast, simple slow, simple signal) 3 x float yes the MACD line, its signal line and the histogram between them.
ta.max(source) float yes the highest value the source has had in the run so far.
ta.median(source, simple length) float yes the middle value of the window, averaging the two middles of an even window.
ta.mfi(source, simple length) float yes the money flow index over length bars, 0 to 100.
ta.min(source) float yes the lowest value the source has had in the run so far.
ta.mode(source, simple length) float yes the most frequent value of the window; the smallest of them when several tie.
ta.mom(source[, simple length]) float yes the same as ta.change, named for momentum.
ta.nvi() float yes the negative volume index: 100, moved by the close's percentage change on the bars whose volume fell.
ta.obv() float yes on-balance volume: the running total of volume signed by the close's direction.
ta.percentile_linear(source, simple length, percentile) float yes the percentile of the window, interpolated between the two neighbouring ranks.
ta.percentile_nearest(source, simple length, percentile) float yes the percentile of the window, taken at the nearest rank.
ta.percentrank(source, simple length) float yes the percentage of the window's values at or below the current one.
ta.pivothigh(source, simple left, simple right) float yes the source right bars ago when it is the highest of the left+right+1 bars around it - confirmed right bars late.
ta.pivotlow(source, simple left, simple right) float yes the source right bars ago when it is the lowest of the left+right+1 bars around it - confirmed right bars late.
ta.pvi() float yes the positive volume index: 100, moved by the close's percentage change on the bars whose volume rose.
ta.pvt() float yes the price-volume trend.
ta.range(source, simple length) float yes the highest value of the window minus its lowest.
ta.rising(source, simple length) bool yes true when the source rose on each of the last length bars.
ta.rma(source, simple length) float yes Wilder's moving average, smoothing 1/length - what ta.rsi and ta.atr are built on.
ta.roc(source, simple length) float yes the change over length bars as a percentage of the older value.
ta.rsi(source, simple length) float yes the relative strength index over length bars, 0 to 100.
ta.sar([, simple start, simple increment, simple maximum]) float yes Wilder's parabolic stop and reverse, from this run's highs and lows.
ta.sma(source, simple length) float yes the simple moving average of the last length values.
ta.stdev(source, simple length) float yes the population standard deviation of the last length values.
ta.stoch(source, high, low, simple length) float yes the raw stochastic %K of the source against the high and low of the window, 0 to 100.
ta.supertrend(factor, simple length) 2 x float yes the supertrend level and its direction: -1 while the trend is up, 1 while it is down.
ta.swma(source) float yes the symmetrically weighted average of the last four values, weighted 1, 2, 2, 1.
ta.tr() float yes the true range of this bar: the widest of high-low, high-previous close and previous close-low.
ta.tsi(source, simple short, simple long) float yes the true strength index: momentum smoothed twice, -100 to 100.
ta.valuewhen(condition, source[, simple occurrence]) float yes the source's value the nth most recent time the condition was true.
ta.variance(source, simple length) float yes the population variance of the last length values.
ta.vwap(source) float yes the volume-weighted average price of every bar of the run so far; it never resets.
ta.vwma(source, simple length) float yes the volume-weighted moving average.
ta.wad() float yes Williams' accumulation/distribution line.
ta.wma(source, simple length) float yes the linearly weighted moving average, heaviest on the newest value.
ta.wpr(simple length) float yes Williams %R over length bars, -100 to 0.
ta.wvad() float yes Williams' variable accumulation/distribution of this bar.

time.#

The calendar, UTC only. A bar's own date and time are read as bar variables instead.

Call Produces State What it does
time.in_session(start, end) bool no true when this bar opens inside the UTC window, each bound written hhmm; a window whose end is at or before its start wraps midnight.
time.timestamp(year, month, day[, hour, minute, second]) int no a UTC calendar moment as a millisecond epoch; na when the parts are not a real date.

str.#

Text. Invariant everywhere: str.upper("i") is "I" on every machine.

Call Produces State What it does
str.contains(value, part) bool no true when the text contains the part, compared exactly.
str.endswith(value, part) bool no true when the text ends with the part.
str.format(template[, first, second, third, fourth]) string no the template with {0}..{3} replaced by the arguments, formatted invariantly.
str.format_time(time) string no a millisecond epoch as ISO 8601 in UTC, such as 2026-11-03T14:00:00Z.
str.length(value) int no how many characters the text has.
str.lower(value) string no the text in lower case, invariant.
str.pos(value, part) int no where the part first occurs, counted in UTF-16 code units; na when it does not.
str.repeat(value, simple count[, separator]) string no the text repeated count times, joined by the separator.
str.replace(value, part, replacement[, simple occurrence]) string no the text with one occurrence of the part replaced - the nth, counted from 0.
str.replace_all(value, part, replacement) string no the text with every occurrence of the part replaced.
str.startswith(value, part) bool no true when the text starts with the part.
str.substring(value, simple start[, simple length]) string no length characters from start; clipped to the text.
str.tonumber(value) float no the text as a number, invariant; na when it is not one.
str.tostring(value[, simple digits]) string no the number as text, invariant, with the given number of digits.
str.trim(value) string no the text without leading or trailing white space.
str.upper(value) string no the text in upper case, invariant - str.upper("i") is "I" everywhere.

color.#

Colours, as 0xAARRGGBB.

Call Produces State What it does
color.b(color) int no the colour's blue channel, 0..255.
color.from_gradient(value, bottom_value, top_value, bottom_color, top_color) color no the colour between two colours, by where the value sits between the two bounds.
color.g(color) int no the colour's green channel, 0..255.
color.new(color, transparency) color no the colour with a transparency of 0..100 applied.
color.r(color) int no the colour's red channel, 0..255.
color.rgb(red, green, blue[, alpha]) color no a colour from red, green and blue of 0..255, and an optional alpha.
color.t(color) int no the colour's transparency, 0..100, which is the inverse of its alpha.

Constants#

Name Value
math.pi 3.141592653589793
math.e 2.718281828459045

Colours are written #RRGGBB or #RRGGBBAA, or taken by name:

color.red color.green color.lime color.blue color.navy color.teal color.aqua color.yellow color.orange color.purple color.fuchsia color.maroon color.olive color.gray color.silver color.white color.black

A plot style is line, histogram, points, area or step. A marker shape is circle, square, triangle_up, triangle_down, arrow_up, arrow_down, cross or label, and its position is above, below or absolute. An hline style is solid, dashed or dotted.