Complete QuantScript API reference. Documentation for all built-in functions: ta.sma, ta.rsi, ta.macd, ta.bbands, trade.buy, trade.sell, strategy introspection, chart plotting, and risk management.
mode(mode_type: "indicator", script_name: "My Script");
mode(mode_type: "live");
mode(mode_type: "backtest", script_name: "My Strategy");Modes: "indicator", "backtest", "forwardtest", "live". Optional script_name arg.
broker(adapter: "sim", config: {
initial_capital: 100000,
commission: 0.05,
execution_strategy: "bar-match-hedging"
});Parameters: initial_capital, commission, commission_type, slippage, leverage, currency, execution_strategy, fill_model, fee_model, margin_model, stop_out_level.
candles(symbol: "BTCUSD", resolution_type: "1m", bars: 120, adapter: "demotrader.net");ticks(symbol: "BTCUSD", adapter: "demotrader.net");
ticks(symbols: ["BTCUSD", "ETHUSD"], adapter: "demotrader.net");Set the quote stream adapter for real-time tick data. Enables event.onTick() handlers to receive live ticks in forwardtest/live modes.
Authentication: ticks() requires a broker() declaration — the broker's session token is automatically used for quote stream authentication.
Mode behavior: Active in forwardtest and live modes. Ignored in backtest and indicator modes.
Load secondary candles from a different symbol/resolution_type. Takes a single object argument. With a callback, evaluates an expression on native bars (like Pine's request.security()). Without a callback, returns a raw FeedAccessor.
var ethSma = data.loadCandles({ adapter: "demotrader.net", symbol: "ETHUSD", resolution_type: "4h", callback: (c) => ta.sma(c.close, 50) });
// Complex callback with block body
var xauSignal = data.loadCandles({ adapter: "demotrader.net", symbol: "XAUUSD", resolution_type: "1D", callback: (c) => {
const rsi = ta.rsi(c.close, 14);
if (rsi === null) return 0;
return rsi > 70 ? -1 : (rsi < 30 ? 1 : 0);
} });var feed = data.loadCandles({ adapter: "demotrader.net", symbol: "ETHUSD", resolution_type: "4h" });
// feed.close, feed.open, feed.high, feed.low, feed.volumevar prev = ethSma[1]; // previous bar's SMA value(c) => expr evaluated on native bars (optional)All fields go in the single object argument.
Results are forward-filled to the primary resolution_type's timeline. Supports [n] historical lookback on callback results.
broker(adapter: "demotrader.net", email: "user@example.com", password: "Password@123");
// With allocated_capital for multi-strategy capital isolation
broker(adapter: "demotrader.net", email: "user@example.com", password: "Password@123", config: { allocated_capital: 10000 });Only required for live trading. Parameters: adapter name, email, password, token, account_id, position_mode.
Virtual Trading Accounts: Set config: { allocated_capital: N } to give this strategy its own isolated balance, equity, and margin tracking when multiple strategies share one broker account. Risk guards (risk()) are enforced against virtual account values. Opt-in — when omitted, broker-wide account values are used. See the guide for details.
risk(max_position_pct: 20, daily_loss_limit: 3, max_trades_per_day: 10);Parameters: max_position_pct, daily_loss_limit, daily_profit_target, weekly_loss_limit, max_trades_per_day, max_positions, max_consecutive_losses, max_loss_per_trade, min_balance, min_equity, max_margin_pct, kill_switch.
The primary entry point for bar-by-bar strategy logic.
event.onCandle((candle) => {
let closePrice = candle.close;
let highPrice = candle.high;
});Fires reactively for each tick/quote received from the quote stream. Requires ticks() declaration and a connected broker() for authentication. The tick object contains symbol, bid, ask, last, and timestamp.
event.onTick((tick) => {
console.log(`${tick.symbol}: bid=${tick.bid} ask=${tick.ask}`);
});Fires when a bar completes.
Fires at a regular time interval. Default: 60000ms.
Trading lifecycle events — fired when the broker reports changes to your orders and positions:
event.onFill(callback) — an order was executed (full or partial fill)event.onReject(callback) — the broker rejected an orderevent.onCancel(callback) — a pending order was cancelled or expiredevent.onPositionOpened(callback) — a new position was openedevent.onPositionChanged(callback) — position modified (SL/TP, size, openPnl)event.onPositionClosed(callback) — a position was fully closed (exposes closedPnl)| Property | Description |
|---|---|
candleIndex | Current candle index (0-based) |
lastCandleIndex | Index of the last candle |
candle.isFirst | true if first candle |
candle.isLast | true if last candle in the DataFrame (may be a forming bar) |
candle.isForming | true if the bar is still forming (incomplete) |
candle.isHistory | true for confirmed candles before the live edge |
candle.isNew | true if new candle |
candle.isConfirmed | true if candle is confirmed (fully closed) |
candle.isLive | true only on the latest confirmed candle (trading edge) |
candle.hl2 | (high + low) / 2 |
candle.hlc3 | (high + low + close) / 3 |
candle.hlcc4 | (high + low + close + close) / 4 |
candle.ohlc4 | (open + high + low + close) / 4 |
var)#Use var for variables that retain their value across bars.
var highestHigh = 0;
event.onCandle((candle) => {
if (candle.high > highestHigh) highestHigh = candle.high;
});state.*)#Cross-worker persistent storage. Properties survive export/import cycles.
state.entriesToday = 0;
state.lastPrice = 0;let prevClose = close[1]; // Previous bar's close
let twoAgo = high[2]; // High from 2 bars agoNull handling: All ta.* functions return null when there is insufficient data. Use ta.nz() to replace nulls.
Simple Moving Average.
Exponential Moving Average.
Weighted Moving Average.
Recursive Moving Average (Wilder's smoothing).
Sine-Weighted Moving Average.
Hull Moving Average.
Arnaud Legoux Moving Average.
Linear Regression.
Double Exponential Moving Average.
Triple Exponential Moving Average.
Volume-Weighted Moving Average.
Relative Strength Index (0-100).
MACD. Returns [macdLine, signalLine, histogram].
Stochastic Oscillator (0-100).
Rate of Change.
Momentum.
Williams %R (-100 to 0).
Chande Momentum Oscillator (-100 to 100).
Standard Deviation.
Variance.
Mean Deviation.
Bollinger Bands. Returns [lower, middle, upper].
Keltner Channels. Returns [lower, middle, upper].
True Range.
Average True Range.
Volume-Weighted Average Price (cumulative).
Parabolic SAR.
Supertrend. Returns [value, direction].
On Balance Volume.
Check if source1 crosses over source2.
Check if source1 crosses under source2.
Highest value over a period.
Lowest value over a period.
Bar index of highest value (negative offset).
Bar index of lowest value (negative offset).
Change in value over a period.
Check if series is falling.
Check if series is rising.
Bars since condition was true.
Value when condition was last true.
Cumulative sum.
Median over a period.
Percentile rank (0-100).
Pivot high point.
Pivot low point.
Correlation (-1 to 1).
Replace null with default (default: 0).
CCXT-inspired unified trading API. All methods return uniform result objects.
Universal order. Specify side and type explicitly.
Market buy/sell.
Limit buy/sell.
Stop buy/sell.
All order methods accept size as an alternative to qty (mutually exclusive). Exactly one field must be set:
| Field | Example | Behaviour |
|---|---|---|
units | size: { units: 0.5 } | Direct base-asset quantity (same as qty) |
lots | size: { lots: 0.1 } | Standardized lot units — resolved to base quantity via the instrument’s lot size |
cash | size: { cash: 500 } | Spend a fixed quote-currency amount |
equity_percent | size: { equity_percent: 2 } | Percentage of account equity (0–100) |
// FX: 0.5 lots of EURUSD
trade.buy({ symbol: "EURUSD", size: { lots: 0.5 } });
// Crypto: spend $1000 USDT
trade.buy({ symbol: "BTCUSDT", size: { cash: 1000 } });
// Stocks: risk 2% of equity
trade.buy({ symbol: "AAPL", size: { equity_percent: 2 } });Modify a pending order.
Cancel a pending order.
Close a position (full or partial).
Modify position stop loss / take profit.
All open positions.
Returned fields: id, symbol, side, qty, avgEntryPrice, markPrice, openPnl, closedPnl, marginUsed, leverage, liquidationPrice, stopLoss, takeProfit, strategyId, openedAt, updatedAt.
openPnl is the floating P&L on the still-open exposure (marked at markPrice); closedPnl is the P&L already booked by partial closes. Neither name uses the ambiguous “realised/realized” spelling.
All open orders.
All fills (executed trades).
Account info (equity, cash, balance, etc.).
Returned fields: id, name, currency, balance, equity, cash, buyingPower, marginUsed, marginAvailable, openPnl, closedPnl, leverage, positions, marginLevel.
Instrument info.
Broker's supported features.
All available instruments.
In forwardtest and live modes the runtime maintains an incomplete (forming) candle that updates with every incoming tick. These builtins expose that real-time data so your strategy can make execution decisions (entry checks, SL/TP placement, position sizing) using the freshest available price — while indicator/signal logic continues to use the confirmed candle.close to avoid repainting.
let bar = trade.formingCandle();
if (bar != null) {
console.log("Forming close: " + bar.close);
}Returns the current incomplete candle object, or null if no forming bar exists (e.g., in backtest mode).
Returned fields: time, open, high, low, close, volume, incomplete (always true), symbol.
let livePrice = trade.last();
if (livePrice == 0) { livePrice = candle.close; }Returns the freshest last-traded price: the forming bar’s close if available, otherwise the latest quote’s last. Returns 0 when neither exists (e.g., backtest with no quotes).
Tip: Always include the == 0 fallback so the same script works in both backtest and live modes.
let bid = trade.bid();Returns the current best bid price from the quote stream. Returns 0 if no quote data is available.
let ask = trade.ask();Returns the current best ask price from the quote stream. Returns 0 if no quote data is available.
| Use case | Data source | Why |
|---|---|---|
| Indicator / signal logic | candle.close (confirmed bar) | Immutable — prevents repainting |
| Entry condition checks | trade.last() | React to the freshest price |
| SL / TP placement | trade.last() | Bracket relative to actual execution price |
| Position sizing (cash / equity %) | trade.last() | Accurate unit calculation |
| Spread-aware limit orders | trade.bid() / trade.ask() | Place orders at precise quote levels |
Mode behavior: These functions are most useful in forwardtest and live modes. In backtest mode the forming bar is not populated, so trade.last() returns 0 and trade.formingCandle() returns null — hence the fallback pattern.
Read-only introspection. Order submission is via trade.*.
| Property | Description |
|---|---|
strategy.position_size | Current position size |
strategy.position_avg_price | Average entry price |
strategy.position_side | "long", "short", or "flat" |
strategy.equity | Current equity |
strategy.cash | Available cash |
strategy.openprofit | Open position profit |
strategy.netprofit | Net profit |
strategy.opentrades | Number of open trades |
strategy.closedtrades | Number of closed trades |
strategy.wintrades | Winning trades count |
strategy.losstrades | Losing trades count |
strategy.eventrades | Even trades count |
strategy.initial_capital | Initial capital |
Plot a data series. Pass { style: "..." } as the 4th argument to change the visual style. Use pane: "oscillator" for a separate lower pane.
Available styles:
"line" (default) | Solid connected line |
"histogram" | Vertical bars from zero-line |
"area" | Filled area between line and zero |
"areabr" | Area fill with break — color above zero, contrasting color below |
"stepline" | Staircase / step line |
"stepline_diamond" | Step line with diamond markers |
"stepline_square" | Step line with square markers |
"stepline_round" | Step line with round markers |
"cross" | X-shaped markers at each point |
"circles" | Hollow circle outlines at each point |
"line_with_markers" | Solid line with filled circle markers |
"columns" | Full-width column bars from pane bottom |
"candle" | Mini candlestick markers (body + wicks) |
"linebr" | Line that breaks at NaN gaps |
Plot a shape marker.
Draw a horizontal line.
Set per-bar background color. Supports conditional coloring — pass different colors based on conditions (e.g., trend direction). Renders as vertical strips spanning the full pane height.
Parameters:
const isUptrend = close > ta.sma(close, 50);
chart.bgcolor(isUptrend ? "rgba(76,175,80,0.1)" : "rgba(244,67,54,0.1)");Fill area between two plots.
Switch pane context for subsequent plot calls.
Draw text annotations at specific bar/price locations. Labels can be styled with different visual treatments.
Create a text label at bar index x and price y.
Parameters:
Available styles:
"label_up" (default) | Triangle pointing up, text above |
"label_down" | Triangle pointing down, text below |
"label_left" | Text to the left of point |
"label_right" | Text to the right of point |
"label_center" | Text centered on point |
"label_flag" | Small circle with text |
"label_arrow_up" | Arrow pointing up with text |
"label_arrow_down" | Arrow pointing down with text |
"label_none" | Simple box (no triangle/arrow) |
const rsi = ta.rsi(close, 14);
if (rsi > 70) {
chart.label.new(candleIndex, high, "Overbought", "#f44336", "label_down");
}Integer input. Positional arguments in Pine Script order — pass null to skip a slot.
Float input. Same signature as input.int.
Boolean input.
String input. Pass an array for options to render a dropdown.
const rsiLen = input.int(14, "RSI Length", 2, 50, null, null, null, "RSI");
const stopLoss = input.float(2.0, "Stop Loss %", 0.5, 10.0, 0.5, null, null, "Risk");
const useStop = input.bool(true, "Use Stop Loss", null, null, "Risk");See Execution Model & Events for core event callbacks.
Print values to console output.
Print error to console output.
Write a strategy-authored note to the Run Journal. Optional params: { reason, tags }.
Terminate script execution immediately.
QuantScript provides full parity with the JavaScript ES6 standard library for the namespaces and types below. They behave identically to their JavaScript counterparts — refer to any JS reference (e.g. MDN) for complete API details.
| Namespace / Type | Available API |
|---|---|
Math.* | Math.abs(), Math.max(), Math.min(), Math.sqrt(), Math.pow(), Math.round(), Math.ceil(), Math.floor(), Math.log(), Math.exp(), Math.sin(), Math.cos(), Math.tan(), Math.atan2(), Math.random(), Math.sign(), Math.pi, Math.e, etc. |
JSON.* | JSON.parse(text) — parse JSON string into an object/array. Returns null on invalid input.JSON.stringify(value) — serialize any value to a JSON string. |
Date.* | Date.now() — current timestamp in ms.Date.parse(dateString) — parse a date string to timestamp.Date.UTC(y, m, d, h?, min?, s?, ms?) — UTC timestamp from components. |
| String methods | Native instance methods on any string: .length, .includes(), .startsWith(), .endsWith(), .indexOf(), .charAt(), .match(), .toUpperCase(), .toLowerCase(), .trim(), .replace(), .replaceAll(), .substring(), .slice(), .repeat(), .padStart(), .padEnd(), .split(), .reverse() |
| Array methods | Native instance methods on any array: .length, .push(), .pop(), .shift(), .unshift(), .splice(), .slice(), .concat(), .includes(), .indexOf(), .find(), .findIndex(), .map(), .filter(), .reduce(), .forEach(), .every(), .some(), .sort(), .reverse(), .join(), .flat(), .flatMap() |
// Math
let x = Math.sqrt(144); // 12
// JSON
let obj = JSON.parse('{"symbol": "BTCUSD", "qty": 0.5}');
console.log(obj.symbol); // BTCUSD
let text = JSON.stringify(obj);
// Date
let now = Date.now(); // current timestamp in ms
// String methods
let sym = "btcusd".toUpperCase(); // "BTCUSD"
// Array methods
let prices = [100, 102, 98, 105];
let avg = prices.reduce((a, b) => a + b, 0) / prices.length;QuantScript looks like JavaScript, but is a deliberately constrained DSL.
do...while loopOnly while, for, and for...of are supported.
for...in loopUse for...of over an array of known keys instead.
No class, extends, super, new, or constructor.
Errors are fatal and handled by the runtime.
Scripts are synchronous. No async, await, Promise.
Use arr.concat() instead.
Only plain arrays [] and objects {}.
Array destructuring is supported, but object destructuring is not.
typeof or instanceofUse x == null to check for null.
import/exportScripts are self-contained. All built-ins are available through global namespaces.
delete operatorbreak and continue apply to the innermost loop only.
== is strict equalityUnlike JavaScript, == does no type coercion. 0 == "0" is false.
var means something differentIn QuantScript, var declares a persistent variable that retains its value across bars.
Built-ins take either positional arguments (ta.*, input.*, risk.* — e.g. input.int(14, "RSI", 2, 50)) or a single object argument (trade.* orders, data.loadCandles — e.g. trade.buy({ symbol: "BTCUSD", qty: 1 })). Named arguments are only used in top-level declarations like mode() and candles().
Like JavaScript, every statement must end with a semicolon ;.