Declaration statements
Introduction
In Pine Script®, a declaration statement is a mandatory function call that declares the script’s type and its properties at compile time. The available declaration functions are indicator(), strategy(), and library(). Each type of script has different capabilities and behaviors, the compiler uses different rules to compile them, and Pine’s runtime system also executes them differently.
Every script must include exactly one declaration statement, and that statement must be in the script’s global scope. Our style guide recommends placing the statement directly below the @version= compiler annotation at the top of the source code. For example:
The parameters of a declaration statement define various script-wide properties and default behaviors. Only the title parameter, which sets the script’s main title, requires an argument. Supplying arguments to any other parameters is optional. Note that all parameters in each declaration statement require arguments qualified as “const”. They cannot accept values with the “input”, “simple”, or “series” type qualifier.
The indicator(), strategy(), and library() sections below explain the parameters available for each declaration statement and how they affect a script, as well as various unique characteristics of each script type.
indicator()
The indicator() function declares that the script is an indicator. Indicators perform calculations across a dataset to generate visuals, alerts, or Pine Logs. They are the most common type of scripts in Pine.
The built-in Relative Strength Index (RSI) script is an example of an indicator. It calculates the RSI of a specified source series and plots the result in a separate pane. It can also plot a smoothed RSI, display divergence signals, and generate divergence alerts.
Indicators have several distinct characteristics, including the following:
- Indicators are the only scripts that can use alert triggers from calls to both the alert() and alertcondition() functions.
- Unlike strategies, indicators cannot use any
strategy.*built-ins or simulate trades. - Unlike libraries, indicators cannot export code for use in other scripts. However, other scripts that include source inputs can retrieve values from an indicator’s plots created by plot() calls.
- The Pine Screener is compatible with indicators only. The screener can display plotted values from an indicator’s plot() function calls, and filter the results using data from other plot() or alertcondition() calls.
- Indicators always execute once per bar on historical bars, and once per data feed update (tick) on realtime bars.
- Indicators must include at least one call to a function that creates one of the following outputs: plot visuals, drawing visuals, alert triggers, or Pine Logs.
The signature for the indicator() function is as follows:
indicator(title, shorttitle, overlay, format, precision, scale, max_bars_back, timeframe, timeframe_gaps, explicit_plot_zorder, max_lines_count, max_labels_count, max_boxes_count, calc_bars_count, max_polylines_count, dynamic_requests, behind_chart) → voidThe following sections explain the parameters of the indicator() declaration statement and how they work.
title and shorttitle
The required title parameter defines the script’s main title. The script displays the specified “string” title in all possible chart locations by default. Additionally, the “Publish script” window automatically suggests using that title for a script publication.
The optional shorttitle parameter defines a short display title for the script. If the declaration statement includes a shorttitle argument that is not an empty string, the string’s text appears instead of the main title in multiple chart locations, including:
- The script’s status line on the chart.
- The chart’s object tree and data window.
- The script’s “Settings” window.
- The “Condition” section of the “Create alert” dialog box.
- The listed alerts and logs for the script in the “Alerts” pane.
- The Pine Logs pane.
The example script below plots an Exponential Moving Average (EMA) for a selected source series and length. The declaration statement sets the script’s main title to "Exponential Moving Average indicator". However, because the declaration statement also includes the argument shorttitle = "EMA", the script’s status line and the data window display “EMA” instead of the main title. Hovering over the short title in the status line reveals a tooltip containing the script’s main title:

overlay, scale, and behind_chart
The overlay, scale, and behind_chart parameters of the declaration statement configure where the script displays its chart outputs. They control the global default display location and scaling behavior of the script’s visuals, separate to the individual properties of plot visuals or drawing visuals.
The overlay parameter specifies which default chart pane the script uses to display its visuals when the user adds the script to their chart. If the argument is true, the script’s visuals appear in the main chart pane by default, or in another script’s pane if the user adds it to the chart via the “Add indicator/strategy on” option in the other script’s “More” menu. If the overlay argument is false (default), the script’s visuals occupy a separate chart pane by default.
The scale parameter defines the location of the script’s price scale and the scaling behavior of the script’s plots and drawings. The possible arguments are scale.left, scale.right, and scale.none. The behaviors associated with this parameter are as follows:
- If the declaration statement includes any
scaleargument, the script scales its visuals independently to fit the vertical range of the pane that it occupies. - If the argument is scale.left or scale.right, and the script overlays on an existing pane, the script adds a separate scale for its visuals on the specified side of that pane.
- If the script occupies a separate pane, an argument of scale.left or scale.right moves that pane’s scale to the specified side without creating a new scale.
- If the argument is scale.none, which is valid only if the
overlayargument istrue, the script displays plotted numbers directly on the scale of an existing pane without creating a new scale. If the user moves the script to a separate pane, the script displays values on a new price scale in that pane. - If the statement does not include a
scaleargument, the script uses the main price scale for the pane it occupies, and it does not scale its visuals separately if it overlays on an existing pane.
The following example indicator plots an RSI as translucent, color-coded columns. The script displays the columns on the main chart pane because its declaration statement includes overlay = true. Additionally, the script adds a separate scale to the left side of the pane and scales its plotted values independently because the statement uses scale.left as the scale argument:

Note that:
- The script formats the plotted numbers and the values in the left-side scale as percentages because the indicator() statement includes the argument
format = format.percent. See theformatandprecisionsection below to learn more.
The behind_chart parameter determines the visual order of the script’s plots and drawings relative to the main chart series. Specifying an argument for this parameter affects the script’s visuals only if the overlay argument is true, because the behavior does not apply to non-overlay scripts. If the behind_chart value is true (default), the script’s visuals appear behind the main series. If the value is false, they appear in front of the main series and can cover the chart’s bars.
format and precision
The format and precision parameters of the declaration statement control the default appearance of plotted numbers in the script’s status line, the price scales, and the data window.
The precision parameter determines the default number of fractional digits that the script shows for plotted values and the numbers in the price scale. It accepts a value from 0 to 16. This parameter affects the appearance of all plotted numbers except for those formatted using format.volume, because the decimal precision rules of the built-in volume format supersede other precision settings. If the declaration statement does not include a precision argument, the script inherits its default precision settings from the main chart series, or from another script if it accesses one of that script’s plots using a source input.
The format parameter determines whether the script displays plotted numbers and the numbers in the price scale using a price, percentage, or volume format, or if it inherits formatting settings from the chart or another script. The possible arguments are format.price, format.percent, format.volume and format.inherit. The default is format.inherit.
Below, we list how a script formats plotted values when using each of these arguments:
format.price
1e+21).
format.percent
%) to express plotted values as percentages. By default, the format rounds plotted numbers to two fractional digits. For example, it formats the value 39.787 as 39.79%. This format does not recalculate values to express them as percentages. To represent a ratio as a percentage when using this format, multiply the value by 100 before plotting it.
format.volume
format.inherit
The example indicator below plots volume values as color-coded columns, and it plots the average value over a specified number of bars as a line. The indicator() declaration statement includes format.volume as the format argument to apply the volume formatting rules described above to the script’s plots and scale. On our daily “NASDAQ:NFLX” chart, the current plotted values are in millions, so the script displays the numbers in an abbreviated format with “M” as the suffix:

Note that the plot*() functions also include format and precision parameters, which enable scripts to define specific formatting behaviors for each separate plot. By default, a plot automatically inherits the default format and precision settings defined by the declaration statement, as demonstrated by the previous example. However, if a plot*() call includes format or precision arguments, those arguments take precedence over the script’s default settings.
For example, in the script version below, we added the argument format = format.price to the plot() call for the average volume display. With this change, the script formats the average volume values using the rules defined by format.price, while the volume plot and the price scale both continue to use the default format.volume rules specified by the declaration statement:

max_bars_back
The max_bars_back parameter of the declaration statement, if it has a specified argument, sets the initial maximum history-referencing length for each series in a script. It accepts an “int” value from 0 to 5000, representing the number of past data points maintained in memory for all variables and expressions.
As a script executes, Pine’s runtime system stores data for each variable and expression across bars in fixed-length historical buffers. The script can access past bar data from these buffers by using the [] history-referencing operator or the built-in functions that reference history internally. For example, the expression close[10] retrieves the last saved value of the close variable from 10 bars back.
By default, the system automatically sizes each historical buffer by analyzing the historical references that the script executes as it loads across historical bars. For resource efficiency, each buffer typically contains only enough past data to accommodate the script’s historical references, but not more. For instance, if a script requests the value of a variable from up to 500 bars back as it loads across a chart’s history, the buffer for that variable typically includes data for only the latest 500 past bars.
In most cases, this automatic sizing process accommodates a script’s historical references without issues. Therefore, manually setting the sizes of historical buffers is often unnecessary. However, in some cases, the system might fail to determine appropriate buffer sizes on its own, resulting in a runtime error. One possible way to resolve that error is to set the default size of the script’s historical buffers in advance by including a max_bars_back argument in the declaration statement.
Before using this parameter, ensure that all or most of the series in the script actually require historical buffers with the same specific size. Manually setting buffers in a script to use a specific size when unnecessary can negatively impact the script’s performance. If only specific series require manually sized buffers, either of the following approaches is far more efficient:
- Use the max_bars_back() function to set the sizes of only the problematic historical buffers.
- Structure the script’s history-referencing operations to request the maximum required amount of history on the first bar.
See the historical buffer limit error page to learn more. For advanced details about the workings of historical buffers, refer to the Historical buffers section of the Execution model page.
timeframe and timeframe_gaps
The timeframe parameter of the indicator() declaration statement sets the script’s main timeframe. It enables the script to perform calculations on the data for a different timeframe than that of the chart without requiring request.*() function calls. The parameter accepts a valid timeframe string, such as "1D" for the daily timeframe or "30" for the 30-minute timeframe. If an argument is not specified, or if the value is an empty string (""), the script executes on the data for the current chart’s timeframe.
The timeframe_gaps parameter determines how the script handles time gaps when plotting data from a higher timeframe. It allows an argument only if the declaration statement also includes a timeframe argument. The parameter works similarly to the gaps parameter of request.security() and other request.*() functions. If the value is true (default), the script plots values only on the chart bars where new, confirmed data is available from the specified timeframe, and displays na results on other bars. If false, the script plots the last retrieved values from the higher timeframe on the chart bars where new data is not available.
If the declaration statement specifies a timeframe argument, the script automatically adds a “Calculation” group with a “Timeframe” input to the “Settings/Inputs” tab. If the statement includes a timeframe_gaps argument, the script also adds a “Wait for timeframe closes” input below the “Timeframe” input. These inputs enable users to customize the script’s main timeframe and its gap-handling behavior without modifying the source code. To learn more about them, see the Leveraging multi-timeframe analysis article in our Help Center.
The following example demonstrates the behavior of both parameters. The indicator below calculates and plots the 14-bar average of close values on a specified timeframe. The indicator() declaration statement includes "1D" as the timeframe argument, so it performs calculations using daily data for the current chart’s symbol by default, regardless of the chart’s timeframe. On an intraday chart, the script plots an “x-cross” shape only on the last chart bar for each trading day by default, and na on other bars, because the declaration statement also includes the argument timeframe_gaps = true:

Note that:
- If the specified timeframe is lower than or equal to the chart’s timeframe, the script plots an “x-cross” shape on every chart bar.
- An alternative way to achieve this script’s default result without using these parameters is to plot the value returned by the call
request.security(syminfo.tickerid, "1D", ta.sma(close, 14), gaps = barmerge.gaps_on). Refer to the Other timeframes and data page to learn more aboutrequest.*()functions.
explicit_plot_zorder
The explicit_plot_zorder parameter of the declaration statement determines the visual order in which the script’s plots, horizontal levels, and fills stack on the chart.
If the value is true, the script visually stacks plots, levels, and fills based on the order of the plot()*, hline(), and fill() function calls in the source code, where each written call’s output appears on top of the outputs from the calls that precede it. For example, if the code lists a fill() call after a plot() call, the resulting fill appears on top of the plot. Likewise, if the code lists a plot() call after an hline() call, the plot appears on top of the horizontal line.
If the value is false (default), the script visually stacks its plots, levels, and fills based on the order of those visuals in the z-index, regardless of the order in which the function calls for each type of output occur in the code. Horizontal levels always appear on top of plots, and plots always appear on top of fills. However, visual outputs of the same type or group still stack on top of each other based on the order of their function calls. For example, if a script includes two calls to the plot() function, the second plot appears on top of the first.
max_lines_count, max_labels_count, max_boxes_count, and max_polylines_count
The max_lines_count, max_labels_count, max_boxes_count, and max_polylines_count parameters of the declaration statement limit the number of line, label, box, and polyline drawing objects that the script can maintain in memory. As the script creates new objects of a given drawing type, the runtime system deletes the oldest drawings of that type as necessary if the number of active objects exceeds the script’s limit.
The max_lines_count, max_labels_count, and max_boxes_count parameters accept an “int” value from 1 to 500, and the max_polylines_count parameter accepts an “int” value from 1 to 100. The default for each parameter is 50.
See the Line, box, polyline, and label limits section of the Limitations page and the Total number of objects section of the Lines and boxes page to learn more about drawing limits.
calc_bars_count
The calc_bars_count parameter of the declaration statement sets the default maximum number of most recent historical bars that the script can access for its calculations. It accepts an “int” value that is greater than or equal to 0.
If the value is 0 (default), the script executes on all the available bars in the dataset, starting from the first available bar. If the value is greater than 0, the script instead starts executions on the bar that is N bars before the latest available bar at loading time, or on the dataset’s first bar if the value exceeds the number of available bars. Additionally, a positive calc_bars_count argument adds a “Calculation” group with a “Calculated bars” input to the script’s “Settings/Inputs” tab, where users can adjust the number of historical bars available to the script without editing the source code.
The following example script plots the close series across a limited number of historical bars and all realtime bars. The indicator() declaration statement includes the argument calc_bars_count = 40, which forces the script to treat the last 40 historical bars as the only ones available in the dataset by default:

dynamic_requests
The dynamic_requests parameter of the declaration statement specifies whether the script can use request.*() function calls to execute dynamic requests. If the value is true (default), the script can:
- Include calls to
request.*()functions inside the local scopes of conditional structures and loops, and in the operands of conditional expressions. - Use “series” arguments that vary across bars to specify the ticker identifier, timeframe, and other settings of a
request.*()call. - Execute nested requests, where one
request.*()call evaluates another inside its context.
If the value is false, the script is more limited in how it can use request.*() functions:
- All
request.*()calls must execute in the script’s global scope, and outside the conditional operands of ternary or and/or operations. - All
request.*()parameters except forexpressionrequire arguments with the “simple” type qualifier or a weaker qualifier, meaning their values cannot change across bars. - A
request.*()call whoseexpressionargument depends on anotherrequest.*()call cannot evaluate the other call within its context.
The following example script calculates a weighted moving average (WMA) of hl2 values over a specified number of chart bars. It also uses a request.security() call within an if structure to optionally calculate the latest confirmed WMA on a specified higher timeframe. The script can use the request inside the if structure because the indicator() declaration statement’s dynamic_requests argument is true:

Note that:
- The script behaves the same if we remove the
dynamic_requestsargument from the declaration statement, because the default argument istrue. - If we change the
dynamic_requestsargument tofalse, the request.security() call causes a compilation error because the script cannot use it inside the if statement. To resolve the error without enabling dynamic requests, programmers must move the call to the global scope. - Users can change the “Higher timeframe” input in the “Settings/Inputs” tab only if they select the “Show higher-timeframe WMA” checkbox, because the input.timeframe() call includes the argument
active = htfRequestInputto control when the input is active. See the Input function parameters section of the Inputs page to learn more aboutactiveand other input parameters.
To learn more about the request.*() functions and the differences between dynamic and non-dynamic requests, refer to the Other timeframes and data page.
strategy()
The strategy() function declares that the script is a strategy. Strategies can simulate orders and trades across a dataset, enabling users to backtest and forward test their trading systems. They have many similar capabilities to indicators, while also providing the ability to analyze hypothetical trading performance in a dedicated tab.
The built-in RSI Strategy script is an example of a simple strategy. The script simulates entering and exiting positions based on the RSI crossing the defined overbought and oversold levels. It displays trade markers directly on the chart and shows a detailed strategy report in a separate panel below the chart.
Scripts declared as strategies have several unique characteristics, including the following:
- Strategies are the only scripts that can send orders to the broker emulator and display simulated performance results using the Strategy Tester.
- The “Settings” window for strategy scripts features a unique “Properties” tab, where users can customize the properties of the strategy simulation. Programmers can specify default properties for this tab via the unique parameters in the strategy() statement.
- Unlike indicators, strategies cannot run on data for other timeframes. They always use the same timeframe as the chart.
- Strategies cannot create alert triggers using the alertcondition() function, but they can create them by using calls to the alert() function. Additionally, unlike indicators, they can generate special alerts from order fill events.
- Unlike the plots created by indicators or libraries, strategy plots are not accessible to source inputs in other scripts.
- Strategies execute differently from indicators or libraries. By default, they execute strictly once per closed bar and do not execute on open bars. However, users can customize a strategy’s calculation behavior to enable additional executions on open bars or after the broker emulator fills an order.
- Strategies must include at least one call to an order placement command, or to a function that creates plot visuals, drawing visuals, alert triggers, or Pine Logs.
The strategy() function has the following signature:
strategy(title, shorttitle, overlay, format, precision, scale, pyramiding, calc_on_order_fills, calc_on_every_tick, max_bars_back, backtest_fill_limits_assumption, default_qty_type, default_qty_value, initial_capital, currency, slippage, commission_type, commission_value, process_orders_on_close, close_entries_rule, margin_long, margin_short, explicit_plot_zorder, max_lines_count, max_labels_count, max_boxes_count, calc_bars_count, risk_free_rate, use_bar_magnifier, fill_orders_on_standard_ohlc, max_polylines_count, dynamic_requests, behind_chart) → voidBecause strategies have many of the same features as indicators, the strategy() function includes most of the indicator() function’s parameters. The only exceptions are the timeframe and timeframe_gaps parameters, because strategies cannot execute on other timeframes.
The unique parameters in the strategy() declaration statement define the default properties of the strategy simulation, including the initial simulated capital, default order sizes, hypothetical trading costs, and calculation behaviors. The sections below explain these unique parameters. To learn about the other parameters that are common to both indicators and strategies, see the indicator() section above.
For detailed information about how to use the unique strategy() function parameters and the built-ins in the strategy namespace, refer to the Strategies page.
pyramiding
The pyramiding parameter of the strategy() declaration statement accepts an “int” value specifying the default maximum number of open trades, from the orders created by strategy.entry() calls, that a strategy allows for a single position. The default argument is 1, meaning that the strategy can open only one long or short trade at a time using orders from strategy.entry() calls and cannot execute another entry order in the same direction until after the existing trade closes. Users can adjust the script’s pyramiding limit without editing the code by using the “Pyramiding” input in the script’s “Settings/Properties” tab.
The following example strategy uses two calls to the strategy.entry() command to create market orders for entering long and short trades. The call for long orders executes once every five bars, excluding multiples of 30, and the one for short orders executes once every 30 bars. The strategy() declaration statement includes the argument pyramiding = 3, meaning that the strategy can enter up to three trades for the same position using strategy.entry() calls by default.
As shown below, although the strategy’s long condition (highlighted by the purple background) occurs five times before the short condition (highlighted by the orange background), the strategy executes only three entry orders for each long position instead of five. Once the number of open trades reaches three, it does not execute new long entry orders until after the short order closes the existing long position:

Note that:
- By default, the orders from the strategy.entry() command automatically close an existing position in the opposite direction and enter a new trade with the specified quantity. See the Reversing positions section of the Strategies page for more information about this behavior.
- The
default_qty_valueargument in the declaration statement specifies the initial default size of the strategy’s orders. See thedefault_qty_typeanddefault_qty_valuesection to learn more. - The strategy enters a new trade after every occurrence of the long condition only if the
pyramidingvalue is at least 5.
calc_on_every_tick, calc_on_order_fills, and process_orders_on_close
The calc_on_every_tick, calc_on_order_fills, and process_orders_on_close parameters of the strategy() declaration statement specify the strategy’s default calculation behaviors. If the argument for each of these parameters is false (default), the strategy executes strictly once per bar, on each bar’s closing tick, and the broker emulator fills each order from the strategy on the open of the next available bar. Specifying a value of true for any of these parameters changes the strategy’s default execution and order-fill behaviors. Users can also change these behaviors via the “On every tick”, “After order is filled”, and “On bar close” checkboxes in the script’s “Settings/Properties” tab.
The calc_on_every_tick parameter specifies whether the strategy performs a new execution on each new tick of a realtime bar by default. If the value is true, the strategy executes once after every update from the realtime data feed, similar to how an indicator executes, instead of waiting for each realtime bar to close. This parameter does not affect the strategy’s executions on historical bars, because realtime tick information is not available on those bars.
The calc_on_order_fills parameter specifies whether the strategy can immediately recalculate and place additional orders on any bar where an order fills by default. If the value is true, the strategy re-executes on the next available tick following any tick where the broker emulator fills an order, even if that tick occurs during an open bar. This behavior enables the script to execute more than once on any bar where an order fill occurs — up to four times per historical bar by default (at the open, high, low, and close), and up to once for each new tick on a realtime bar.
The process_orders_on_close parameter specifies whether the broker emulator can fill an order on the same closing tick where the strategy creates the order by default. If the value is false (default), the earliest point at which the broker emulator can fill an order that occurs on a bar’s close is at the open of the following bar, because that point is the next possible tick. If the value is true, the emulator fills the order immediately on the bar’s close instead of waiting for the next bar’s opening tick.
For example, the following strategy simulates opening a position after one exponential moving average (EMA) crosses over another. On each bar where the EMAs cross, the script highlights the chart’s background, then creates a long or short market order on that bar’s closing tick. With the default behavior defined by process_orders_on_close = false, the broker emulator does not fill each order on the same bar where the strategy creates it. Instead, it fills the order at the open of the following bar, because that point is the next available tick:

If we include process_orders_on_close = true in the strategy() declaration statement, the broker emulator is no longer limited to filling our strategy’s orders on the next available tick by default. Instead, it fills the orders immediately on each bar’s close:

See the Altering calculation behavior section of the Strategies page to learn more about the calc_on_every_tick, calc_on_order_fills, and process_orders_on_close parameters. For detailed information about how scripts execute on historical and realtime bars, and how these parameters affect executions, refer to the Execution model page.
slippage and backtest_fill_limits_assumption
The slippage parameter of the strategy() declaration statement specifies the default fixed number of ticks that the strategy applies to the fill prices of all market orders and stop orders to simulate slippage. If the argument is a positive “int” value, the strategy adds the specified number of ticks to the fill prices of long orders and subtracts it from the fill prices of short orders. This behavior helps simulate the disparity between expected and actual fill prices that might occur in real-world trading. If the slippage argument is 0 (default), the strategy fills orders at their expected prices without simulating any slippage. Users can change the specified slippage amount via the “Slippage” input in the strategy’s “Settings/Properties” tab.
The backtest_fill_limits_assumption parameter specifies the default number of ticks by which the market price must exceed the prices of limit orders before the broker emulator can fill the orders. If the argument is a positive “int” value, the broker emulator fills a limit order at the defined price only if the market price moves past it by the specified number of ticks in the favorable direction. This behavior helps simulate the possibility of unfilled limit orders, as filling limit orders in the real world requires sufficient liquidity and price action around the limit level. If the argument is 0 (default), the emulator fills orders as soon as the market price reaches the limit price or a more favorable value. Users can adjust a strategy’s limit verification requirements via the “Verify price for limit orders” input in the “Settings/Properties” tab.
default_qty_type and default_qty_value
The default_qty_type and default_qty_value parameters of the strategy() declaration statement specify the initial default order size for the strategy.entry() and strategy.order() commands. If a call to either command does not specify an order size, the resulting order uses the default order size defined by these parameters. Users can adjust these properties via the “Default order size” inputs in the script’s “Settings/Properties” tab.
The default_qty_type parameter specifies the default quantity type for each order from strategy.entry() and strategy.order() calls. The possible arguments and their effects are as follows:
- strategy.fixed — The default order size is a fixed number of contracts, shares, lots, or units, depending on the instrument.
- strategy.cash — The default size is a fixed number of units of the account currency specified by the
currencyargument. - strategy.percent_of_equity — The default size is a fixed percentage of the strategy’s available equity.
The default argument is strategy.fixed.
The default_qty_value parameter accepts a “float” value that specifies the amount of the defined quantity type to use as the default order size. The default argument is 1, meaning that the strategy uses the default order size of one contract/share/lot/unit, one unit of the account currency, or one percent of the available equity, depending on the default_qty_type argument.
The specified default order size applies only to the orders from strategy.entry() and strategy.order() calls that do not include a qty argument. If a call to either command does include a qty argument, that call creates an order for the number of contracts/shares/lots/units specified by the argument instead of using the default quantity type and value. See the Position sizing section of the Strategies page for an example.
The following example demonstrates how different default order sizes can affect a strategy’s entry orders. The script below uses a strategy.entry() call, without a qty argument, to place a long market order when the close and volume values are rising over a specified number of bars, then uses a strategy.close_all() call to close the open position when the close value is falling while the volume value is rising. It also plots the value of the strategy.position_size variable in a separate pane to visualize the size of each open position.
The strategy() statement in this example includes the arguments default_qty_type = strategy.fixed and default_qty_value = 20, which set the strategy’s default order size to 20 contracts/shares/lots/units. As shown by the trade markers and the plot on our NYSE:UBER chart below, each order from the strategy.entry() command consistently opens a 20-share trade:

If we edit the declaration statement to use the argument default_qty_type = strategy.percent_of_equity, the strategy sets the default size of each entry order to allocate 20% of its current available equity instead of the amount required to purchase 20 shares. Now, the trade markers and plot show varying sizes, because the number of shares that corresponds to the default order size varies with both the strategy’s available equity and the current market price:

initial_capital and currency
The initial_capital parameter of the strategy() declaration statement specifies the default initial account balance for the strategy’s simulation, as a quantity of the account currency. It accepts a positive “int” or “float” argument. The default is 1000000. Users can change the strategy’s initial account balance by adjusting the “Initial capital” input in the script’s “Settings/Properties” tab.
The currency parameter specifies the strategy’s default account currency. It is the currency unit for the strategy’s initial capital and for the internal calculations in the simulation that express values as currency amounts (equity, profit and loss, commission, etc.). The parameter accepts a currency.* constant (e.g., currency.USD) or a string representing a valid currency code, (e.g., "USD"). The default is currency.NONE, which specifies that the strategy uses the same currency as that of the quoted prices on the chart. Users can change the strategy’s account currency via the “Base currency” input in the “Settings/Properties” tab.
If the specified account currency differs from the chart’s currency, the strategy converts monetary values in its calculations to express them in the account currency. However, the prices of the strategy’s orders remain expressed in the chart’s currency. To convert necessary monetary values to the account currency, the strategy typically uses the previous daily value of a corresponding currency pair as the conversion rate, or the value from a spread if no direct currency pair is available. See the Currency section of the Strategies page for more information.
commission_type and commission_value
The commission_type and commission_value parameters of the strategy() declaration statement specify the default commission fees that the broker emulator applies to the strategy’s simulated transactions. Users can customize the strategy’s commission settings via the “Commission” inputs in the “Settings/Properties” tab.
The commission_type parameter determines the default commission type for each executed order. The possible arguments and their effects are as follows:
- strategy.commission.cash_per_order — The default commission for each transaction is a fixed number of units in the strategy’s account currency.
- strategy.commission.cash_per_contract — The commission is a fixed account currency amount for each traded contract/lot/share/unit.
- strategy.commission.percent — The commission is a fixed percentage of each transaction’s value.
The default argument is strategy.commission.percent.
The commission_value parameter accepts a positive “int” or “float” value specifying the default fee amount for the commission type. For example, if the value is 1, the strategy simulates a fee of one unit of the account currency per transaction, one unit of the account currency per contract/share/lot/unit, or one percent of each transaction’s size by default, depending on the commission_type value. The default argument is 0, meaning that the strategy does not simulate commission unless the user specifies a nonzero value for the first “Commission” input in the “Properties” tab.
close_entries_rule
The close_entries_rule parameter of the strategy() declaration statement determines the order in which the strategy simulation closes the trades in an open market position. It accepts one of two “string” arguments: "FIFO" or "ANY". If the value is "FIFO", the broker emulator follows First In, First Out (FIFO) rules when closing market positions. Under these rules, the earliest open trade is always the first to close, regardless of the entry IDs specified by the script’s strategy.exit() or strategy.close() calls. If the value is "ANY", the broker emulator ignores FIFO rules and closes the trades specified by the exit commands, even if an earlier trade with a different entry ID is open. The default is "FIFO".
Refer to the Closing a market position section of the Strategies page for an example of how changing the close_entries_rule argument can affect a strategy’s exit behavior.
margin_long and margin_short
The margin_long and margin_short parameters of the strategy() declaration statement specify the default margin requirements for the strategy’s long and short positions, respectively. Users can adjust the strategy’s long and short margin requirements via the “Margin for long positions” and “Margin for short positions” inputs in the “Settings/Properties” tab.
Margin is the percentage of a position’s value that the simulated account must retain in its balance as collateral for the broker emulator to cover the rest of the position. It is the inverse of leverage. For example, if the margin requirement for a long position is 50%, the strategy must maintain sufficient funds to cover half of the open position. This level of margin means that the strategy’s leverage is 2:1. In other words, the strategy can risk up to twice its available balance on a simulated trade.
The default margin_long and margin_short arguments are 100, meaning that the strategy must cover 100% of each long and short position using its simulated account balance.
If a strategy’s available funds drop below the required margin percentage, the broker emulator triggers a margin call, which forcibly liquidates part or all of the simulated position to cover the loss. For detailed information about margin simulation and margin call events, refer to the How to simulate trading with leverage in Pine Script article in our Help Center.
risk_free_rate
The risk_free_rate parameter of the strategy() declaration statement specifies the annual percentage return of a hypothetical risk-free investment. The strategy uses the specified risk-free rate to calculate the Sharpe ratio and Sortino ratio metrics displayed in the “Strategy report” panel. The default value is 2, meaning that these metrics assess the strategy’s risk-adjusted returns relative to a hypothetical 2% risk-free rate.
use_bar_magnifier
The use_bar_magnifier parameter of the strategy() declaration statement specifies whether the strategy enables the Bar Magnifier backtesting mode by default. Users can activate or deactivate the Bar Magnifier mode by selecting the “Using bar magnifier” checkbox in the strategy’s “Settings/Properties” tab. If the value is true, the broker emulator retrieves available prices from a lower timeframe on historical bars by default for more precise intrabar order fills. If the argument is false (default), the broker emulator relies on default assumptions about intrabar price movement instead of using prices from a lower timeframe. See the Broker emulator section of the Strategies page to learn more.
fill_orders_on_standard_ohlc
The fill_orders_on_standard_ohlc parameter of the strategy() declaration statement specifies whether the broker emulator fills the strategy’s orders using actual prices by default when the strategy executes on a Heikin Ashi chart. Users can activate or deactivate the feature via the “Using standard OHLC” input in the strategy’s “Settings/Properties” tab. If the value is false, the emulator fills the strategy’s orders using the chart’s synthetic prices by default. If true, it fills the orders using the actual open, high, low, and close prices from a standard chart dataset for more realistic results. The default argument is false.
library()
The library() function declares that the script is a library. Libraries export reusable functions, methods, user-defined types (UDTs), enum types, or constant variables. Libraries can also include non-exported code to demonstrate how they work and how to use them. Indicators, strategies, and other libraries can use the import keyword to import a published library’s exported code components. Importing components from libraries often helps programmers streamline script creation and simplify source code.
The VisibleChart publication from PineCoders is an example of a library. It exports functions that perform calculations on the chart’s visible bars. The example script in the FAQ entry Can I create an indicator that plots like the built-in Volume or Volume Profile indicators demonstrates how scripts can import and use functions from this library.
Because the primary purpose of a library is to export components for other scripts, they have multiple unique characteristics, including the following:
- Libraries are the only scripts that can use the export keyword.
- Libraries cannot directly create alert triggers, but they can export custom functions that contain alert() calls. Indicators and strategies can use the alert triggers from calls to those functions.
- A library’s title acts similarly to a namespace identifier when another script imports the library. Therefore, unlike indicators and strategies, libraries must follow identifier naming rules in their titles.
- User-defined functions and methods exported by libraries must prefix each declared parameter with a type keyword.
- The example code of a library executes similarly to an indicator. When applied to a chart, the code executes once per bar on historical bars and once per tick on realtime bars.
- Libraries use default indicator properties when their code executes on a chart. The declaration statement of a library does not include parameters for setting decimal precision, plot formatting, scales, drawing limits, or other script properties.
- Unlike indicators, libraries can use the available
strategy.*built-ins. However, unlike strategies, a library’s example code does not display trade markers on the chart or generate a strategy report. - For a library to compile, it must use the export keyword to export at least one function, method, enum, UDT, or “const” variable.
The library() function’s signature is as follows:
library(title, overlay, dynamic_requests) → voidThe overlay parameter behaves the same as that of the indicator() and strategy() declaration statements. Refer to the overlay, scale, and behind_chart section above for information about this parameter.
The title and dynamic_requests parameters are also common to the indicator() and strategy() functions. However, they have some unique characteristics in libraries, as explained in the sections below.
title
The title parameter of the library() declaration statement specifies the library’s unique name, which other scripts reference to import and use the library’s code. For example, if a userName user publishes a library that uses "foo" as the title argument, another script imports version 1 of the library using the following import statement:
The script can then use the library’s defined title (or a specified alias) similarly to a namespace to access the imported components. For example, if the library exports a function named bar(), the script that imports the library references the library’s title using dot notation when calling the function:
Because a library’s title behaves as a code identifier in other scripts, the title argument must follow identifier naming rules. The “string” argument can contain ASCII letters (a-z and A-Z), numeric digits (0-9), and underscores (_). The argument cannot be an empty string, cannot contain spaces or special characters, and cannot start with a numeric digit. Special characters include any of the following:
- Basic punctuation, including periods (
.), commas (,), quotation marks ("), apostrophes ('), exclamation points (!), etc. - Symbols that scripts use for syntax, such as parentheses (
( )), square brackets ([ ]), plus signs (+), hyphens (-), asterisks (*), slashes (/), and percent signs (%). - Currency symbols, such as
$or€. - Non-ASCII letters and digits, such as the Unicode character
𝖠(U+1D5A0). - Other Unicode characters, such as emoji or special-purpose symbols.
For example, a string such as "Library_for_14_day_averages" is a valid title argument for the library() declaration statement, but an argument such as "Library for 14-day averages" causes a compilation error.
If a user applies the library directly to their chart, the title argument’s text appears as the display name in all relevant chart locations, including the script’s status line, the data window, and the Pine Logs pane.
dynamic_requests
The dynamic_requests parameter of the library() declaration statement specifies whether the library can use dynamic requests. If the argument is true (default), the library can use request.*() function calls with “series” arguments to define the requested ticker ID and timeframe, include request.*() calls in the local scopes of conditional structures or loops, and execute nested requests. Additionally, the library can export user-defined functions and methods that use request.*() calls within their function scopes.
If the dynamic_requests argument is false, the library allows request.*() calls only in the global scope or within non-exported functions, and those calls require arguments with “simple” or a weaker type qualifier for all parameters except for expression.
The example library below exports a custom requestFinancialInsights() function, which uses multiple request.*() calls to retrieve the quarterly Earnings Per Share (EPS), total revenue, total outstanding shares for a stock, and estimates the instrument’s market capitalization. The function returns a tuple containing all four values. The library can export this function because its declaration statement enables dynamic requests.
The library’s example code, listed below the user-defined function, demonstrates one way that programmers who import the library can use the function. The code creates a table and populates its cells with a requestFinancialInsights() call’s results on the last available bar:

Note that:
- We included
dynamic_requests = truein the library() statement only to emphasize thedynamic_requestsparameter. Specifying this argument is unnecessary; the value istrueby default. A compilation error occurs if we change the value tofalse, because the library cannot export the custom function or call it within the example code’s if structure. - The
\\@descriptionannotation at the top of the script sets a default description for the library. Similarly, the\\@function,\\@param, and\\@returnsannotations specify documentation for the exported function. Users who import this hypothetical library can hover over its identifiers to view the formatted text from these annotations. Additionally, the “Publish script” window uses these annotations to generate a default publication description. - The source code includes
//#regionand//#endregionannotations to define collapsible regions that visually separate the library’s exported code from its non-exported code in the Pine Editor.
See the Request publication from the TradingView account for an advanced example of a library that exports custom functions using dynamic requests.