# TrainBard Pine Script Compatibility Guide

| Field | Value |
|---|---|
| Document type | Public scripting compatibility contract |
| Audience | Coding agents and people writing scripts for TrainBard |
| Target language | Pine Script v6-style source |
| Canonical endpoint | `https://www.trainbard.com/learn/docs.md` |
| Scope | Accepted syntax, functions, variables, call shapes, public behavior, and common corrections |

Use this guide when generating or repairing Pine scripts for TrainBard. TrainBard supports a deliberate subset of Pine Script. A name appearing in TradingView documentation does not imply that TrainBard accepts it.

## Compatibility vocabulary

- **Supported**: use the call shape shown in this guide.
- **Supported subset**: the function is accepted only with the arguments, value kinds, and behavior stated here.
- **TrainBard extension**: accepted by TrainBard but not guaranteed to be portable to TradingView.
- **Unsupported**: do not emit it in a TrainBard script.
- **Unlisted**: treat an unlisted function, overload, member, method, named argument, or constant as unsupported.

Parameter names are significant. Do not invent aliases. Optional parameters are marked with `?`. When a supported named parameter occurs after an unsupported Pine parameter, use the named form instead of positional placeholders.

## Instructions for coding agents

When the target is TrainBard:

1. Emit exactly one leading `//@version=6` directive.
2. Put exactly one `strategy()` or `indicator()` declaration immediately after the directive.
3. Use only functions, members, arguments, and overloads documented below.
4. Prefer `strategy.entry()` plus `strategy.close()` for a basic strategy.
5. Use named arguments for `strategy.exit()`, `strategy.close(..., immediately=...)`, `strategy.close_all(..., immediately=...)`, drawing options, and visual options.
6. Give every order a stable string ID. The `strategy.close()` ID must match the entry ID it closes. The `from_entry` value in `strategy.exit()` must match the intended entry ID.
7. Destructure functions documented as tuple-returning. Do not assign a tuple-returning call to one scalar variable.
8. Use a fixed integer or `input.int()` value for indicator lengths. Avoid a length that changes from bar to bar.
9. Use direct market series such as `open`, `high`, `low`, `close`, `volume`, `hl2`, `hlc3`, `ohlc4`, or a previously calculated series as indicator sources.
10. If a requested Pine feature is unsupported, simplify the strategy or calculate an equivalent with supported arithmetic and state. Never silently retain an unsupported call.
11. Preserve the user's trading intent when repairing a script, but prioritize an accepted complete script over Pine features that TrainBard does not expose.
12. Do not add imports, libraries, live alerts, lower-timeframe requests, unsupported drawing setters, or unsupported strategy risk calls.

## Minimal valid strategy

```pine
//@version=6
strategy("EMA Crossover", overlay=true)

fastLength = input.int(10, "Fast length", minval=1)
slowLength = input.int(30, "Slow length", minval=2)

fastEMA = ta.ema(close, fastLength)
slowEMA = ta.ema(close, slowLength)

if ta.crossover(fastEMA, slowEMA)
    strategy.entry("Long", strategy.long)

if ta.crossunder(fastEMA, slowEMA)
    strategy.close("Long")

plot(fastEMA, title="Fast EMA", color=color.aqua)
plot(slowEMA, title="Slow EMA", color=color.orange)
```

## Minimal valid indicator

```pine
//@version=6
indicator("RSI", overlay=false)

length = input.int(14, "Length", minval=1)
rsiValue = ta.rsi(close, length)

plot(rsiValue, title="RSI", color=color.blue)
hline(70, title="Overbought", color=color.red)
hline(30, title="Oversold", color=color.green)
```

## Script declarations

### `strategy()`

Supported call shape:

```pine
strategy(title, shorttitle?, overlay=?, initial_capital=?, pyramiding=?,
    max_boxes_count=?, max_lines_count=?, max_labels_count=?,
    default_qty_type=?, default_qty_value=?,
    commission_type=?, commission_value=?, slippage=?,
    process_orders_on_close=?, calc_on_every_tick=?)
```

Public constraints:

- `title` and optional `shorttitle` must be literal strings.
- `overlay` and `process_orders_on_close` must be literal booleans.
- `initial_capital` must be a positive numeric literal.
- `pyramiding` must be a positive integer literal.
- Drawing limits must be literal integers from 1 through 500.
- `default_qty_type` supports `strategy.fixed` and `strategy.percent_of_equity`.
- `default_qty_value` must be positive. Percent-of-equity sizing accepts values through 100.
- If commission arguments are supplied, use `commission_type=strategy.commission.percent` and `commission_value=0`.
- `slippage` must be a non-negative integer literal.
- `calc_on_every_tick` may be omitted or set to `false`; `true` is unsupported.
- Omit all other declaration arguments.

### `indicator()`

Supported call shape:

```pine
indicator(title, overlay=?, max_boxes_count=?, max_lines_count=?, max_labels_count=?)
```

`title` must be a literal string. `overlay` must be a literal boolean. Drawing limits must be literal integers from 1 through 500. Strategy functions are not available in an indicator script.

## Language subset

Supported language features include:

- Numeric, boolean, string, color, and `na` literals.
- Variables declared with `=` and reassigned with `:=`.
- Top-level persistent variables declared with `var` and an initializer.
- Arithmetic, comparison, boolean, and ternary expressions.
- `if`, `else if`, and `else` blocks.
- Counted `for` loops and `for...in` over a proven array.
- History references such as `close[1]`.
- User-defined scalar functions with all arguments supplied.
- Supported tuple returns and tuple declarations.
- Explicit supported primitive, reference, collection, and user-defined type annotations.
- User-defined types with supported field types, `.new()` construction, field reads, and type-preserving field reassignment.
- `const` on an unreassigned top-level primitive initialized from a constant expression.
- Receiver syntax for a value that is clearly an array, map, matrix, or string, for example `prices.push(close)`.

Important exclusions:

- `library()`, imports, exports, and `enum` declarations are unsupported.
- User-defined `method` declarations are unsupported.
- `varip`, `simple`, and `series` qualifiers are unsupported.
- Default values, qualifiers, or templates on user-defined function parameters are unsupported.
- Recursion is unsupported.

## Built-in market and bar values

| Supported value | Meaning |
|---|---|
| `open`, `high`, `low`, `close`, `volume` | Current candle values |
| `hl2` | `(high + low) / 2` |
| `hlc3` | `(high + low + close) / 3` |
| `ohlc4` | `(open + high + low + close) / 4` |
| `hlcc4` | `(high + low + close + close) / 4` |
| `bar_index` | Zero-based current candle index |
| `last_bar_index` | Final loaded candle index |
| `time` | Current candle timestamp in Unix milliseconds |
| `timenow` | Current evaluation timestamp |
| `last_bar_time` | Final loaded candle timestamp |
| `year`, `month`, `dayofmonth`, `dayofweek` | UTC calendar components |
| `hour`, `minute`, `second` | UTC time components |

### `barstate.*`

Supported members:

`barstate.islast`, `barstate.isfirst`, `barstate.isconfirmed`, `barstate.isrealtime`, `barstate.isnew`, `barstate.ishistory`, `barstate.islastconfirmedhistory`

TrainBard evaluates loaded historical candles. Do not write logic that depends on repeated realtime updates of the same candle.

### `syminfo.*`

| Member | Status and use |
|---|---|
| `syminfo.tickerid` | Supported current symbol identifier |
| `syminfo.ticker` | Supported current symbol |
| `syminfo.mintick` | Supported minimum price increment |
| `syminfo.pointvalue` | Supported when market data provides it; otherwise 1 |

Other `syminfo.*` members, including `syminfo.basecurrency`, `syminfo.currency`, exchange metadata, sector data, and recommendation data, are unsupported.

### `timeframe.*` and `session.*`

| Member | Status |
|---|---|
| `timeframe.period` | Supported |
| `timeframe.multiplier` | Supported |
| `timeframe.isintraday` | Supported |
| `timeframe.isdaily` | Supported |
| `session.isfirstbar_regular` | Supported only for daily regular-session data |
| `session.islastbar_regular` | Supported only for daily regular-session data |

`timeframe.isweekly`, `timeframe.ismonthly`, and other unlisted timeframe or session members are unsupported.

## Input functions

Inputs must be assigned directly to a variable. Defaults and UI labels must use the literal forms described below.

| Function | Supported call shape | Public constraints |
|---|---|---|
| `input.int` | `input.int(defval, title?, minval?, maxval?, options?, tooltip?, inline?, group?)` | Integer literal default. Use either inclusive literal `minval`/`maxval` bounds or a non-empty literal `options` list. `step` is unsupported. |
| `input.float` | `input.float(defval, title?, minval?, maxval?, step?, options?, tooltip?, inline?, group?)` | Finite numeric literal default. Use either bounds with an optional positive literal `step`, or a non-empty literal `options` list. Do not combine options with bounds or step. |
| `input.bool` | `input.bool(defval, title?, tooltip?, inline?, group?)` | Boolean literal default. |
| `input.string` | `input.string(defval, title?, options?, tooltip?, inline?, group?)` | String literal default and optional literal choices. |
| `input.color` | `input.color(defval, title?, tooltip?, inline?, group?)` | Static color default. |
| `input.timeframe` | `input.timeframe(defval, title?, options?, tooltip?, inline?, group?)` | String literal default and optional literal choices. |
| `input.session` | `input.session(defval, title?, options?, tooltip?, inline?, group?)` | String literal default and optional literal choices. This declares a value; it does not by itself filter candles. |
| `input.text_area` | `input.text_area(defval, title?, tooltip?, group?)` | String literal default. |

`confirm`, `display`, `active`, and any unlisted input arguments are unsupported. The generic `input()` function and `input.source`, `input.symbol`, `input.time`, `input.price`, and `input.enum` are unsupported.

Safe input example:

```pine
length = input.int(20, "Length", minval=1, maxval=500, tooltip="Lookback bars")
multiplier = input.float(2.0, "Multiplier", minval=0.1, step=0.1)
mode = input.string("Long", "Mode", options=["Long", "Short"])
```

## `ta.*` technical-analysis functions

Use the parameter names shown. Unless a row says otherwise, the result is one numeric series.

### Moving averages and smoothing

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported | `ta.sma(source, length)` | Simple moving average |
| Supported | `ta.ema(source, length)` | Exponential moving average |
| Supported | `ta.wma(source, length)` | Weighted moving average |
| Supported | `ta.hma(source, length)` | Hull moving average |
| Supported | `ta.dema(source, length)` | Double exponential moving average |
| Supported | `ta.tema(source, length)` | Triple exponential moving average |
| Supported | `ta.rma(source, length)` | Wilder-style moving average |
| Supported | `ta.vwma(source, length)` | Volume-weighted moving average |
| Supported | `ta.alma(series, length, offset, sigma)` | Arnaud Legoux moving average |
| Supported | `ta.swma(source)` | Symmetrically weighted moving average |
| TrainBard extension | `ta.kama(source, length)` | Kaufman adaptive moving average convenience form |
| TrainBard extension | `ta.t3(source, length, factor?)` | T3 moving average; omitted `factor` uses 0.7 |

### Oscillators and momentum

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported | `ta.rsi(source, length)` | Relative Strength Index |
| Supported subset | `ta.stoch(source, peak, valley, period)` | Stochastic oscillator |
| TrainBard extension | `ta.stoch(source, high, low, length)` | Named-argument alias for the same four-input calculation |
| Supported | `ta.cci(source, length)` | Commodity Channel Index |
| Supported | `ta.cmo(source, length)` | Chande Momentum Oscillator |
| Supported | `ta.wpr(length)` | Williams %R using market high, low, and close |
| Supported | `ta.mom(source, length)` | Momentum |
| Supported | `ta.tsi(source, short_length, long_length)` | True Strength Index |
| Supported | `ta.roc(source, length)` | Rate of change |
| Supported | `ta.cog(source, length)` | Center of Gravity oscillator |
| Supported | `ta.macd(source, fastlen, slowlen, siglen)` | Returns `[macdLine, signalLine, histogram]` |

Example:

```pine
[macdLine, signalLine, histogram] = ta.macd(close, 12, 26, 9)
```

### Trend

| Status | Exact call shape | Result or note |
|---|---|---|
| TrainBard extension | `ta.adx(di_length, adx_smoothing)` | ADX convenience function |
| Supported | `ta.dmi(diLength, adxSmoothing)` | Returns `[plusDI, minusDI, adx]` |
| Supported | `ta.aroon(length)` | Returns `[aroonUp, aroonDown]` |
| Supported | `ta.supertrend(factor, atrPeriod)` | Returns `[supertrendValue, direction]` |
| Supported | `ta.sar(start, inc, max)` | Parabolic SAR |

### Volatility, bands, and regression

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported | `ta.tr(handle_na)` | Callable true range form |
| TrainBard extension | `ta.tr()` | Defaults `handle_na` to `true` |
| Supported | `ta.tr` | Built-in true range series; equivalent to `ta.tr(false)` |
| Supported | `ta.atr(length)` | Average True Range |
| TrainBard extension | `ta.natr(length)` | Normalized ATR |
| Supported | `ta.bb(series, length, mult)` | Returns `[middle, upper, lower]` |
| Supported | `ta.bbw(series, length, mult)` | Bollinger Band Width |
| Supported | `ta.kc(series, length, mult, useTrueRange?)` | Returns `[middle, upper, lower]` |
| Supported | `ta.kcw(series, length, mult, useTrueRange?)` | Keltner Channel Width |
| Supported | `ta.stdev(source, length)` | Standard deviation |
| Supported | `ta.variance(source, length)` | Variance |
| Supported | `ta.linreg(source, length, offset)` | Linear regression |
| TrainBard extension | `ta.donchian(length)` | Returns `[upper, lower, middle]` |

### Volume and cumulative values

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported | `ta.obv` | Built-in On Balance Volume series |
| TrainBard extension | `ta.obv()` or `ta.obv(source)` | Callable OBV form |
| Supported | `ta.mfi(series, length)` | Money Flow Index |
| TrainBard extension | `ta.pvt()` | Price Volume Trend |
| TrainBard extension | `ta.ad()` | Accumulation/distribution line |
| TrainBard extension | `ta.cmf(length?)` | Chaikin Money Flow; omitted length uses 20 |
| TrainBard extension | `ta.ao()` | Awesome Oscillator |
| Supported | `ta.cum(source)` | Cumulative sum |
| Supported | `ta.vwap(source)` | Volume-weighted average price |

The following zero-argument series variables are also supported: `ta.accdist`, `ta.iii`, `ta.nvi`, `ta.pvi`, `ta.wad`, and `ta.wvad`.

### Range, extrema, pivots, and signals

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported | `ta.highest(length)` | Highest market high over the lookback |
| Supported | `ta.highest(source, length)` | Highest source value over the lookback |
| Supported | `ta.lowest(length)` | Lowest market low over the lookback |
| Supported | `ta.lowest(source, length)` | Lowest source value over the lookback |
| Supported | `ta.max(source)` | Running maximum |
| Supported | `ta.min(source)` | Running minimum |
| Supported | `ta.range(source, length)` | Rolling range |
| Supported subset | `ta.change(source, length?)` | Numeric-source change from the prior value or requested lookback |
| Supported | `ta.crossover(source1, source2)` | Cross above |
| Supported | `ta.crossunder(source1, source2)` | Cross below |
| Supported | `ta.cross(source1, source2)` | Cross in either direction |
| Supported | `ta.barssince(condition)` | Bars since condition was true |
| Supported | `ta.valuewhen(condition, source, occurrence)` | Value at a zero-based occurrence |
| Supported | `ta.rising(source, length)` | Source above its prior lookback values |
| Supported | `ta.falling(source, length)` | Source below its prior lookback values |
| Supported | `ta.highestbars(length)` | Offset of the highest market high |
| Supported | `ta.highestbars(source, length)` | Offset of the highest source value |
| Supported | `ta.lowestbars(length)` | Offset of the lowest market low |
| Supported | `ta.lowestbars(source, length)` | Offset of the lowest source value |
| Supported | `ta.pivothigh(leftbars, rightbars)` | Pivot high using market high |
| Supported | `ta.pivothigh(source, leftbars, rightbars)` | Pivot high using a source |
| Supported | `ta.pivotlow(leftbars, rightbars)` | Pivot low using market low |
| Supported | `ta.pivotlow(source, leftbars, rightbars)` | Pivot low using a source |

### Statistics and ranking

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported | `ta.correlation(source1, source2, length)` | Rolling correlation |
| TrainBard extension | `ta.beta(source, benchmark, length)` | Rolling beta |
| Supported | `ta.dev(source, length)` | Mean absolute deviation |
| Supported | `ta.median(source, length)` | Rolling median |
| Supported | `ta.mode(source, length)` | Rolling mode |
| Supported | `ta.percentrank(source, length)` | Percent rank |
| Supported | `ta.percentile_linear_interpolation(source, length, percentage)` | Interpolated percentile |
| Supported | `ta.percentile_nearest_rank(source, length, percentage)` | Nearest-rank percentile |
| Supported | `ta.rci(source, length)` | Rank Correlation Index |

### Technical-analysis usage rules

- Tuple results must be destructured into the documented number of targets.
- Use fixed or input-backed lookback lengths. Do not use a length that is recalculated as a changing series on every candle.
- Prefer a direct series or a named previously calculated series as `source`.
- `ta.pivot_point_levels()` and any unlisted `ta.*` name are unsupported.

## Strategy functions and values

### Public backtest behavior

TrainBard evaluates strategies against OHLC candle data, not tick-by-tick updates. Market orders normally fill on the next eligible candle. `process_orders_on_close=true` allows newly placed market orders to fill at the current close. `immediately=true` is supported for close calls. If one candle reaches both a stop and a limit for the same open trade, TrainBard uses the conservative outcome for that trade.

### Order functions

| Status | Supported call shape | Public constraints |
|---|---|---|
| Supported subset | `strategy.entry(id, direction, qty?, limit?)` | `direction` is `strategy.long` or `strategy.short`. `qty`, when supplied, must be positive. A limit entry must use a stable literal string ID. `stop`, OCA, alert, and disable-alert arguments are unsupported. |
| Supported subset | `strategy.order(id, direction, qty?)` | Market order only. `qty`, when supplied, must be positive. Limit, stop, OCA, alert, and disable-alert arguments are unsupported. |
| Supported subset | `strategy.close(id, comment?, immediately=?)` | Use `immediately` as a named argument. Quantity, quantity-percent, alert, and disable-alert arguments are unsupported. |
| Supported subset | `strategy.close_all(comment?, immediately=?)` | Use `immediately` as a named argument. Alert and disable-alert arguments are unsupported. |
| Supported subset | `strategy.exit(id, from_entry=?, qty=?, qty_percent=?, profit=?, limit=?, loss=?, stop=?, trail_points=?, trail_offset=?, oca_name=?, comment=?, comment_profit=?, comment_loss=?, comment_trailing=?)` | Use named arguments. Supply at least one of `profit`, `limit`, `loss`, `stop`, or `trail_points`. Trailing exits require both `trail_points` and `trail_offset`. `qty`, `trail_points`, and `trail_offset` must be positive literals; `qty_percent` must be greater than 0 and no greater than 100. `id` and `from_entry` must be stable strings. Omit `oca_name` unless there is only one constant exit/from-entry pair. `trail_price`, alert fields, and `disable_alert` are unsupported. |
| Supported | `strategy.cancel(id)` | Cancels pending orders with the matching ID. |
| Supported | `strategy.cancel_all()` | Cancels all pending orders. |

Do not copy the complete TradingView positional signature for `strategy.exit()`. Some unsupported parameters occur between supported parameters. Named arguments avoid accidentally binding a value to an unsupported slot.

Risk-managed example:

```pine
//@version=6
strategy("Breakout with exits", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10)

length = input.int(20, "Breakout length", minval=2)
atrLength = input.int(14, "ATR length", minval=1)
riskATR = input.float(2.0, "Stop ATR", minval=0.1, step=0.1)
rewardATR = input.float(3.0, "Target ATR", minval=0.1, step=0.1)

priorHigh = ta.highest(high, length)[1]
atrValue = ta.atr(atrLength)

if close > priorHigh and strategy.position_size <= 0
    strategy.entry("Long", strategy.long)

if strategy.position_size > 0
    stopPrice = strategy.position_avg_price - atrValue * riskATR
    targetPrice = strategy.position_avg_price + atrValue * rewardATR
    strategy.exit("Long Exit", from_entry="Long", stop=stopPrice, limit=targetPrice)
```

### Strategy state

Supported values:

`strategy.position_size`, `strategy.position_avg_price`, `strategy.equity`, `strategy.openprofit`, `strategy.netprofit`, `strategy.closedtrades`, `strategy.opentrades`, `strategy.wintrades`, `strategy.losstrades`, `strategy.eventrades`, `strategy.initial_capital`, `strategy.grossprofit`, `strategy.grossloss`, `strategy.avg_trade`, `strategy.avg_winning_trade`, `strategy.avg_losing_trade`, `strategy.position_entry_name`

Supported constants:

`strategy.long`, `strategy.short`, `strategy.fixed`, `strategy.percent_of_equity`, `strategy.cash`, `strategy.commission.percent`

`strategy.cash` is available as a value constant but cash-based declaration sizing is unsupported.

### Closed-trade inspection

Every supported function takes exactly one zero-based `trade_num` argument:

```pine
strategy.closedtrades.profit(trade_num)
strategy.closedtrades.profit_percent(trade_num)
strategy.closedtrades.entry_price(trade_num)
strategy.closedtrades.exit_price(trade_num)
strategy.closedtrades.size(trade_num)
strategy.closedtrades.entry_id(trade_num)
strategy.closedtrades.exit_id(trade_num)
strategy.closedtrades.entry_bar_index(trade_num)
strategy.closedtrades.exit_bar_index(trade_num)
strategy.closedtrades.entry_time(trade_num)
strategy.closedtrades.exit_time(trade_num)
```

### Open-trade inspection

Every supported function takes exactly one zero-based `trade_num` argument:

```pine
strategy.opentrades.profit(trade_num)
strategy.opentrades.profit_percent(trade_num)
strategy.opentrades.entry_price(trade_num)
strategy.opentrades.size(trade_num)
strategy.opentrades.entry_id(trade_num)
strategy.opentrades.entry_bar_index(trade_num)
strategy.opentrades.entry_time(trade_num)
```

All `strategy.risk.*` functions and unlisted trade-inspection members are unsupported.

## `request.security()`

Supported call shape:

```pine
request.security(symbol, timeframe, expression, gaps?, lookahead?)
```

Supported subset:

- Assign the result directly to one scalar variable or destructure a matching supported tuple.
- Use the current symbol or a literal symbol.
- Use a valid non-empty literal timeframe. An `input.timeframe()` value is supported for the current symbol.
- Prefer direct OHLC-derived expressions. Simple `ta.sma()` and `ta.ema()` expressions and a restricted no-argument scalar function are also accepted.
- A tuple may contain a bounded set of direct OHLC-derived values.
- A script may request at most 40 output series.
- `gaps` supports `barmerge.gaps_off`.
- `lookahead` supports `barmerge.lookahead_off` and `barmerge.lookahead_on`.
- Omitted lookahead behaves as `barmerge.lookahead_off`.
- `barmerge.lookahead_on` can expose an unfinished higher-timeframe value and may repaint.
- Returned history is chart-candle history after timeframe alignment. For example, `dailyHigh[1]` means the previous chart candle's aligned value.

Safe example:

```pine
dailyClose = request.security(
    syminfo.tickerid,
    "D",
    close,
    gaps=barmerge.gaps_off,
    lookahead=barmerge.lookahead_off)
```

`request.security_lower_tf`, `request.financial`, `request.economic`, `request.dividends`, `request.splits`, `request.earnings`, `request.currency_rate`, and `request.seed` are unsupported.

## Array functions

Prefer a typed constructor and `var` for an array that must retain mutations across candles.

### Construction

| Exact call shape | Note |
|---|---|
| `array.new<type>(size?, initial_value?)` | `type` may be `float`, `int`, `bool`, `string`, or a declared user-defined type. |
| `array.new_float(size?, initial_value?)` | Float array |
| `array.new_int(size?, initial_value?)` | Integer array |
| `array.new_bool(size?, initial_value?)` | Boolean array |
| `array.new_string(size?, initial_value?)` | String array |
| `array.from(value1, ...)` | Variadic array constructor; this is not a copy-existing-array overload. |
| `array.copy(id)` | Returns a new array copy. |

### Mutation and access

| Exact call shape | Result or effect |
|---|---|
| `array.push(id, value)` | Append; returns no value |
| `array.pop(id)` | Remove and return last value |
| `array.unshift(id, value)` | Prepend; returns no value |
| `array.shift(id)` | Remove and return first value |
| `array.get(id, index)` | Read an element; negative indexing is supported |
| `array.set(id, index, value)` | Replace an element; returns no value |
| `array.first(id)` | Read first element |
| `array.last(id)` | Read last element |
| `array.insert(id, index, value)` | Insert; returns no value |
| `array.remove(id, index)` | Remove and return an element |
| `array.clear(id)` | Remove all elements; returns no value |
| `array.fill(id, value, index_from?, index_to?)` | Fill an optional half-open range; returns no value |
| `array.reverse(id)` | Reverse in place; returns no value |
| `array.concat(id1, id2)` | Append `id2` to `id1` and return `id1` |
| `array.splice(id, index, how_many?)` | TrainBard extension; remove and return a segment |

### Query, ordering, and statistics

| Exact call shape | Result or note |
|---|---|
| `array.size(id)` | Element count |
| `array.includes(id, value)` | Membership test |
| `array.indexof(id, value)` | First matching index |
| `array.lastindexof(id, value)` | Last matching index |
| `array.sort(id, order?)` | In-place sort; `order` is `order.ascending` or `order.descending`; returns no value |
| `array.sort_indices(id, order?)` | Array of sorted indexes |
| `array.binary_search(id, val)` | Binary search on sorted values |
| `array.binary_search_leftmost(id, val)` | Leftmost binary-search result |
| `array.binary_search_rightmost(id, val)` | Rightmost binary-search result |
| `array.join(id, separator?)` | Join values into a string |
| `array.every(id)` | No-callback predicate for a bool, int, or float array |
| `array.some(id)` | No-callback predicate for a bool, int, or float array |
| `array.avg(id)` | Float-array average |
| `array.sum(id)` | Numeric-array sum |
| `array.min(id)` | Numeric-array minimum |
| `array.max(id)` | Numeric-array maximum |
| `array.abs(id)` | Numeric array of absolute values |
| `array.median(id)` | Float-array median |
| `array.mode(id)` | Mode |
| `array.stdev(id)` | Population standard deviation subset |
| `array.variance(id)` | Population variance subset |
| `array.range(id)` | Numeric range |
| `array.covariance(id1, id2)` | Population covariance subset |
| `array.percentrank(id, index)` | Rank of the element at `index` |
| `array.percentile_linear_interpolation(id, percentage)` | Interpolated percentile |
| `array.percentile_nearest_rank(id, percentage)` | Nearest-rank percentile |

Receiver syntax removes the first `id` parameter. For example, `array.push(values, close)` and `values.push(close)` are equivalent supported forms when `values` is clearly an array.

`array.slice`, `array.standardize`, `array.new_color`, callback overloads, `biased` arguments, and unlisted array APIs are unsupported. Mutating procedures documented as returning no value must be standalone statements.

Safe example:

```pine
var values = array.new<float>(0)
values.push(close)
if values.size() > 100
    values.shift()
meanValue = values.size() > 0 ? values.avg() : na
```

## Map functions

Use a typed constructor:

```pine
map.new<K, V>()
```

`K` and `V` may each be `float`, `int`, `bool`, `string`, or `color`. Untyped `map.new()` is unsupported.

| Exact call shape | Result or effect |
|---|---|
| `map.put(id, key, value)` | Insert or replace and return the previous value |
| `map.get(id, key)` | Return the value or `na`; there is no default-value overload |
| `map.remove(id, key)` | Remove and return the previous value |
| `map.contains(id, key)` | Membership test |
| `map.keys(id)` | Copied array of keys in insertion order |
| `map.values(id)` | Copied array of values in insertion order |
| `map.size(id)` | Pair count |
| `map.clear(id)` | Remove all pairs; returns no value |
| `map.copy(id)` | Shallow map copy |
| `map.put_all(id, id2)` | Copy pairs from a map with matching declared types; returns no value |

Receiver syntax is supported for a value that is clearly a map.

## Matrix functions

Prefer `matrix.new<float>(rows, columns, initial_value?)` or `matrix.new<int>(rows, columns, initial_value?)`. Numeric matrix functions require a clearly numeric matrix.

### Construction, dimensions, and access

| Exact call shape | Result or effect |
|---|---|
| `matrix.new<float>(rows, columns, initial_value?)` | Float matrix |
| `matrix.new<int>(rows, columns, initial_value?)` | Integer matrix |
| `matrix.get(id, row, column)` | Read an element |
| `matrix.set(id, row, column, value)` | Replace an element; returns no value |
| `matrix.rows(id)` | Row count |
| `matrix.columns(id)` | Column count |
| `matrix.elements_count(id)` | Total element count |
| `matrix.row(id, row)` | Return a row as an array |
| `matrix.col(id, column)` | Return a column as an array |
| `matrix.copy(id)` | Return a matrix copy |

### Mutation and structural operations

| Exact call shape | Result or effect |
|---|---|
| `matrix.fill(id, value, from_row?, to_row?, from_column?, to_column?)` | Fill an optional region; returns no value |
| `matrix.add_row(id, row?, array_id?)` | Add a row; returns no value |
| `matrix.add_col(id, column?, array_id?)` | Add a column; returns no value |
| `matrix.remove_row(id, row)` | Remove and return a row array |
| `matrix.remove_col(id, column)` | Remove and return a column array |
| `matrix.reshape(id, rows, columns)` | Reshape in place with the same element count; returns no value |
| `matrix.swap_rows(id, row1, row2)` | Swap rows; returns no value |
| `matrix.swap_columns(id, column1, column2)` | Swap columns; returns no value |
| `matrix.submatrix(id, from_row?, to_row?, from_column?, to_column?)` | Return a matrix using end-exclusive bounds |
| `matrix.reverse(id)` | Reverse in place; returns no value |
| `matrix.concat(id1, id2)` | Append rows of `id2` to `id1` and return `id1` |
| `matrix.sort(id, column?, order?)` | Sort rows in place; returns no value |
| `matrix.transpose(id)` | Return the transpose |

### Numeric operations and properties

| Exact call shape | Result or note |
|---|---|
| `matrix.sum(id1, id2)` | Add a matrix or scalar `id2` |
| `matrix.diff(id1, id2)` | Subtract a matrix or scalar `id2` |
| `matrix.mult(id1, id2)` | Multiply by a matrix, numeric scalar, or array vector |
| `matrix.kron(id1, id2)` | Kronecker product |
| `matrix.avg(id)` | Float-matrix average |
| `matrix.min(id)` | Numeric minimum |
| `matrix.max(id)` | Numeric maximum |
| `matrix.median(id)` | Float-matrix median |
| `matrix.mode(id)` | Numeric mode |
| `matrix.trace(id)` | Diagonal sum |
| `matrix.det(id)` | Determinant of a square numeric matrix |
| `matrix.is_square(id)` | Shape predicate |
| `matrix.is_symmetric(id)` | Property predicate |
| `matrix.is_antisymmetric(id)` | Property predicate |
| `matrix.is_diagonal(id)` | Property predicate |
| `matrix.is_antidiagonal(id)` | Property predicate |
| `matrix.is_identity(id)` | Property predicate |
| `matrix.is_binary(id)` | Property predicate |
| `matrix.is_zero(id)` | Property predicate |
| `matrix.is_triangular(id)` | Property predicate |
| `matrix.is_stochastic(id)` | Property predicate |

Receiver syntax is supported for a value that is clearly a matrix. `matrix.inv`, `matrix.pinv`, `matrix.eigenvalues`, `matrix.eigenvectors`, `matrix.rank`, `matrix.pow`, and unlisted matrix APIs are unsupported.

## String functions

| Status | Exact call shape | Result or note |
|---|---|---|
| Supported subset | `str.tostring(value, format?)` | Number, bool, string, or `na`; supported formats are described below |
| Supported | `str.tonumber(string)` | Strict decimal parse |
| Supported | `str.length(string)` | String length |
| Supported | `str.contains(source, str)` | Contains predicate |
| Supported | `str.startswith(source, str)` | Prefix predicate |
| Supported | `str.endswith(source, str)` | Suffix predicate |
| Supported | `str.replace(source, target, replacement, occurrence?)` | Replace one occurrence |
| Supported | `str.replace_all(source, target, replacement)` | Replace all occurrences |
| Supported | `str.split(string, separator)` | Return an array of strings |
| Supported | `str.lower(source)` | Lowercase |
| Supported | `str.upper(source)` | Uppercase |
| Supported | `str.trim(source)` | Trim surrounding whitespace |
| Supported | `str.substring(source, begin_pos, end_pos?)` | Substring |
| Supported | `str.pos(source, str)` | Position or `na` when absent |
| Supported subset | `str.format(template, arg0, ...)` | Positional `{0}`, `{1}`, and later replacements; advanced format specifiers are unsupported |
| Supported subset | `str.match(source, regex)` | Literal regular-expression subset; returns the first match or an empty string |
| TrainBard extension | `str.indexof(source, str)` | Returns `-1` when absent |
| Supported | `str.repeat(source, repeat, separator?)` | Repeat with optional separator |

`str.tostring()` accepts:

- No format argument.
- `format.volume`.
- `format.mintick`.
- A literal numeric placeholder pattern using `#` and `0`, an optional decimal portion, one optional grouping comma, and an optional trailing `%`.

Dynamic format patterns, locale-aware formatting, and unlisted `format.*` members are unsupported. Receiver syntax is available when the receiver is clearly a string.

## Math functions and constants

| Exact call shape | Note |
|---|---|
| `math.abs(number)` | Absolute value |
| `math.sign(number)` | Sign |
| `math.min(value1, value2, ...)` | At least two positional values |
| `math.max(value1, value2, ...)` | At least two positional values |
| `math.avg(value1, ...)` | At least one positional value |
| `math.sum(source, length)` | Rolling sum |
| `math.round(number, precision?)` | Optional integer precision |
| `math.floor(number)` | Floor |
| `math.ceil(number)` | Ceiling |
| `math.trunc(number)` | Truncate toward zero |
| `math.exp(number)` | Exponential |
| `math.sqrt(number)` | Square root |
| `math.cbrt(number)` | Cube root |
| `math.pow(base, exponent)` | Power |
| `math.log(number)` | Natural logarithm |
| `math.log10(number)` | Base-10 logarithm |
| `math.sin(angle)` | Sine in radians |
| `math.cos(angle)` | Cosine in radians |
| `math.tan(angle)` | Tangent in radians |
| `math.asin(angle)` | Arc sine |
| `math.acos(angle)` | Arc cosine |
| `math.atan(angle)` | Arc tangent |
| `math.atan2(y, x)` | Two-argument arc tangent |
| `math.hypot(x, y)` | Hypotenuse |
| `math.sinh(number)` | Hyperbolic sine |
| `math.cosh(number)` | Hyperbolic cosine |
| `math.tanh(number)` | Hyperbolic tangent |
| `math.random()` | Random value |
| `math.random(min)` | Random value with a lower bound |
| `math.random(min, max)` | Random value between bounds; `seed` is unsupported |
| `math.round_to_mintick(number)` | Round to `syminfo.mintick` |
| `math.todegrees(radians)` | Convert to degrees |
| `math.toradians(degrees)` | Convert to radians |

Supported constants: `math.pi`, `math.e`, `math.phi`, and `math.rphi`.

## Color functions and constants

| Exact call shape | Result or note |
|---|---|
| `color.new(color, transp)` | Replace transparency; `transp` is interpreted from 0 through 100 |
| `color.rgb(red, green, blue, transp?)` | Construct a color |
| `color.from_gradient(value, bottom_value, top_value, bottom_color, top_color)` | Interpolate between colors |
| `color.r(color)` | Red component |
| `color.g(color)` | Green component |
| `color.b(color)` | Blue component |
| `color.t(color)` | Transparency component |

Supported color constants:

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

Hex literals in `#RRGGBB` and `#RRGGBBAA` form are supported.

## Utility and time functions

| Status | Exact call shape | Note |
|---|---|---|
| Supported subset | `na(x)` | Numeric value test |
| Supported subset | `nz(source, replacement?)` | Numeric source and optional numeric replacement |
| Supported subset | `fixnan(source)` | Numeric source; carries the last available value forward |
| Supported subset | `int(x)` | Numeric conversion, truncating toward zero |
| Supported subset | `float(x)` | Numeric conversion |
| Supported subset | `bool(x)` | Boolean or numeric conversion |
| Supported | `runtime.error(message)` | Stop evaluation with a string message; use as a statement |
| Supported | `max_bars_back(var, num)` | Series identifier and non-negative fixed integer hint |
| Supported subset | `dayofweek(timestamp)` | One integer timestamp, evaluated in UTC |
| Supported subset | `time(timeframe)` | Fixed timeframe, `timeframe.period`, or `input.timeframe()` value |
| Supported subset | `time(timeframe.period, session, timezone)` | Literal or input session and non-empty constant timezone |
| Supported subset | `timeframe.change(timeframe)` | Fixed timeframe, `timeframe.period`, or `input.timeframe()` value |
| Supported subset | `timeframe.in_seconds(timeframe?)` | Same timeframe forms; omitted means chart timeframe |

The `na` literal is supported. `timestamp()` and calendar-function timezone overloads are unsupported.

Supported weekday constants are `dayofweek.sunday`, `dayofweek.monday`, `dayofweek.tuesday`, `dayofweek.wednesday`, `dayofweek.thursday`, `dayofweek.friday`, and `dayofweek.saturday`.

## Visual functions

### `plot()`

Accepted signature:

```pine
plot(series, title?, color?, linewidth?, style?, trackprice?, histbase?, offset?,
    join?, editable?, show_last?, display?, format?, precision?, force_overlay?, linestyle?)
```

Reliable visual options include numeric `series`, literal `title`, supported color expressions, positive integer `linewidth`, a supported `plot.style_*`, integer `offset`, non-negative integer `show_last`, `display.none`, literal `force_overlay`, and a supported `plot.linestyle_*`.

Supported plot styles:

`plot.style_line`, `plot.style_stepline`, `plot.style_stepline_diamond`, `plot.style_histogram`, `plot.style_cross`, `plot.style_area`, `plot.style_areabr`, `plot.style_columns`, `plot.style_circles`, `plot.style_linebr`

Supported line styles:

`plot.linestyle_solid`, `plot.linestyle_dashed`, `plot.linestyle_dotted`

`trackprice`, `histbase`, `join`, `editable`, non-chart display combinations, `format`, and `precision` may be accepted as descriptive plot settings but should not be relied on to change the rendered chart.

### `plotshape()`

Accepted signature:

```pine
plotshape(series, title?, style?, location?, color?, offset?, text?, textcolor?,
    editable?, size?, show_last?, display?, format?, precision?, force_overlay?)
```

- `series` may be boolean or numeric. With `location.absolute`, use a numeric coordinate.
- `title` must be literal.
- `color` and `textcolor` must be static.
- `text` must be constant.
- `size` supports `size.tiny` and `size.small`.
- `display` supports direct `display.all` and `display.none`.

Supported shape styles:

`shape.xcross`, `shape.cross`, `shape.triangleup`, `shape.triangledown`, `shape.flag`, `shape.circle`, `shape.arrowup`, `shape.arrowdown`, `shape.labelup`, `shape.labeldown`, `shape.square`, `shape.diamond`

Supported locations:

`location.abovebar`, `location.belowbar`, `location.top`, `location.bottom`, `location.absolute`

### Other visual functions

| Status | Supported call shape | Public constraints |
|---|---|---|
| Supported subset | `hline(price, title?, color?, linestyle?, linewidth?, editable?, display?)` | `price` is constant or input-backed. `display` supports direct `display.all` and `display.none`. |
| Supported subset | `fill(plot1, plot2, color, title?)` | `plot1` and `plot2` are direct IDs returned by `plot()`. Color is static. |
| Supported subset | `bgcolor(color, title=?)` | Only color and named literal title. |
| Supported subset | `barcolor(color, title=?)` | Only color and named literal title. |
| Supported subset | `alertcondition(condition, title?, message?)` | Global scope, boolean condition, and optional literal strings. This records conditions; it does not send live alerts. |

Supported hline styles: `hline.style_solid`, `hline.style_dotted`, `hline.style_dashed`.

`plotchar`, `plotcandle`, `plotbar`, `plotarrow`, `alert`, and `log.*` are unsupported.

## Drawing functions

Use only the listed constructor options. Other drawing arguments and setter APIs are unsupported.

| Status | Supported call shape | Public constraints |
|---|---|---|
| Supported subset | `line.new(x1, y1, x2, y2, extend=?, color=?, style=?, width=?)` | Numeric coordinates; `extend.right`; `line.style_solid`, `line.style_dashed`, or `line.style_dotted`; width 1 through 100. |
| Supported | `line.delete(id)` | Standalone statement. |
| Supported subset | `box.new(left, top, right, bottom, border_color=?, border_style=?, bgcolor=?, text=?, text_size=?, text_color=?)` | Numeric coordinates; supported line styles; `size.tiny` or `size.small`. |
| Supported | `box.delete(id)` | Standalone statement. |
| Supported | `box.get_top(id)` | Read top price. |
| Supported | `box.get_bottom(id)` | Read bottom price. |
| Supported subset | `label.new(x, y, text?, yloc=?, color=?, style=?, textcolor=?, size=?)` | `yloc.abovebar` or `yloc.belowbar`; `label.style_label_up`, `label.style_label_down`, or `label.style_label_left`; `size.tiny` or `size.small`. |
| Supported | `label.delete(id)` | Standalone statement. |
| Supported subset | `table.new(position.top_right, columns, rows, bgcolor=?, border_color=?, border_width=?)` | Positive literal dimensions. |
| Supported subset | `table.cell(table_id, column, row, text, text_color=?, text_halign=?, text_size=?, bgcolor=?)` | Non-negative integer coordinates; `text.align_left` or `text.align_right`; `size.tiny` or `size.small`; standalone statement. |

Drawing coordinates use `bar_index`. Drawing setters, copies, `*.all`, `chart.point`, polylines, linefills, table deletion, table merging, and unlisted drawing APIs are unsupported.

## Common unsupported features and corrections

| If a script contains | Corrective action for TrainBard |
|---|---|
| `input.source(close, "Source")` | Use a fixed built-in source such as `close`, or offer a string choice and select among supported sources with a ternary. |
| Generic `input(...)` | Replace it with a supported typed `input.*` function. |
| `input.int(..., step=...)` | Remove `step`, or use `input.float` if a step is essential and floating-point values are acceptable. |
| `strategy.risk.*` | Express the rule as a supported condition and gate `strategy.entry()`, or close with `strategy.close()` / `strategy.close_all()`. |
| `strategy.entry(..., stop=...)` | Use a supported market or limit entry. Stop-entry orders are unsupported. |
| `strategy.order(..., limit=...)` or `stop=...` | Use a market `strategy.order()`, or a limit `strategy.entry()` when that matches the intent. |
| `strategy.exit(..., trail_price=...)` | Remove `trail_price`; use both `trail_points` and `trail_offset`. |
| Positional `strategy.exit()` arguments | Rewrite supported exit parameters as named arguments. |
| `strategy.close(..., qty=...)` | Use `strategy.exit()` with `qty` or `qty_percent`, or close the full entry with `strategy.close()`. |
| `request.security_lower_tf()` | Use the chart timeframe or a supported higher-timeframe `request.security()` call. |
| Fundamental/economic request functions | Remove the dependency or replace it with supported price/volume data. |
| `array.slice()` | Copy the desired elements with a supported loop and `array.push()`. |
| `array.standardize()` | Calculate mean and standard deviation with supported array functions, then build a transformed array. |
| `map.get(id, key, default)` | Use `map.contains(id, key) ? map.get(id, key) : defaultValue`. |
| Untyped `map.new()` | Declare both template types, for example `map.new<string, float>()`. |
| `matrix.inv()`, `matrix.pinv()`, eigen, or rank calls | Simplify the calculation or use the supported matrix operations. |
| `plotchar`, `plotcandle`, `plotbar`, or `plotarrow` | Use `plot()` or `plotshape()` when that preserves the intended visual. |
| Drawing setter methods | Calculate the desired coordinates before constructing a supported drawing, or delete and create a replacement. |
| `alert()` or `log.*` | Remove it. Use `alertcondition()` only when historical condition observations are useful. |
| `library()`, import, or exported declarations | Inline the required supported code into one self-contained script. |
| `varip` or intrabar logic | Rewrite for one evaluation per historical candle using `var` where persistence is needed. |
| An unknown function or named argument | Remove it or replace it with a function and exact call shape listed in this document. |

## Final agent checklist

Before returning a TrainBard script, verify all of the following:

- The script begins with `//@version=6`.
- There is one immediate `strategy()` or `indicator()` declaration.
- Every called function appears in this guide.
- Every named argument appears in the documented call shape.
- Tuple-returning calls are destructured correctly.
- Indicator lengths are fixed or input-backed.
- Order IDs and `from_entry` values are stable and consistent.
- `strategy.exit()` uses named supported parameters and at least one supported trigger.
- No `strategy.risk.*`, unsupported request, live alert, library, import, unsupported visual, or drawing setter remains.
- The result is self-contained and does not depend on unavailable libraries or external Pine modules.

When uncertain, choose the smaller supported script and explain any removed unsupported behavior outside the Pine code.
