The resource loading... loading...

FMZ PINE Script Doc

Author: Inventors quantify - small dreams, Created: 2022-04-28 16:05:05, Updated: 2024-10-12 17:25:27

[TOC]

img

Introduction to keywords, grammar, settings

Structure of code

General structure that code in Pine follows:

<version>
<declaration_statement>
<code>

Notes

Notes symbols supported by Pine language of FMZ: single-line notes//, multi-line notes/* */, such as the notes method in the following example:

[macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9)  // calculate the MACD indicator

/*
The plot function draws the indicator line on the chart
*/
plot(macdLine, color = color.blue, title='macdLine')
plot(signalLine, color = color.orange, title='signalLine')
plot(histLine, color = color.red, title='histLine')

Version

A compiler instructions of the following form tells the compiler which version of Pine that the script was written with:

//@version=5

The default is V5 version, which can be omitted from the code //@version=5.

Declaration statement

  • indicator()
  • strategy()

The declaration statement determines the type of script, which in turn determines what is allowed in it, and how it is used and executed. Set key properties of the script, such as its name, where it will appear when it is added to the chart, the precision and format of the numerical values it displays, and certain numerical values that govern its runtime behavior, for example, the maximum number of drawing objects to display in the chart. For strategies, attributes include arguments that control backtesting, such as initial capital, commissions, slippage, etc. There is no requirement that a indicator() or strategy() declaration statement must be included in a strategy code in Pine of FMZ.

Code

Lines in a script that are not comments or compiler instructions, which are statements, which implement the algorithm of the script. A statement can be one of these contents.

  • Variable declaration
  • Reassignment of variables
  • Function declaration
  • Built-in function calls, user-defined function calls
  • if, for, while or switch and other constructs

Statements can be arranged in a variety of ways

  • Some statements can be expressed in one line, such as most variable declarations, lines containing only one function call, or single-line function declarations. Others, like structures, always require multiple lines because they require a local block.
  • Statements in the global scope of a script (i.e. parts that are not part of a local block) cannot begin with a space or tab (tab key). Their first character must also be the first character of the line. Lines that start at the first position of a line are by definition part of the script’s global scope.
  • A local block is always required for structure or multi-line function declarations. A local block must be indented by one tab or four spaces (otherwise, it will be parsed as the concatenated code of the previous line, which is determined to be the continuous content of the previous line of code), and each local block defines a different local scope.
  • Multiple single-line statements can be concatenated on a single line by using commas (,) as delimiters.
  • A line can contain comments or just comments.
  • Lines can also be wrapped (continued on multiple lines).

For example, include three local blocks, one in the custom function declaration, and two in the variable declaration using the if structure, as follows:

indicator("", "", true)             // Declaration statement (global scope), can be omitted

barIsUp() =>                        // Function declaration (global scope)
    close > open                    // Local block (local scope)

plotColor = if barIsUp()            // Variable declaration (global scope)
    color.green                     // Local block (local scope)
else
    color.red                       // Local block (local scope)

runtime.log("color", color = plotColor)  // Call a built-in function to output the log (global scope)

Newline code

Long lines can be split over multiple lines, or “wrapped”. A wrapped line must be indented by any amount of whitespace, as long as it is not a multiple of 4 (these boundaries are used to indent local blocks).

a = open + high + low + close

It can be wrapped as (note that the number of spaces indented per line is not a multiple of 4):

a = open +
      high +
          low +
             close

A long plot() call can be wrapped as:

close1 = request.security(syminfo.tickerid, "D", close)      // closing price data series of syminfo.tickerid daily level of the current trading pair
close2 = request.security(syminfo.tickerid, "240", close)    // closing price data series of syminfo.tickerid 240-minute level of the current trading pair
plot(ta.correlation(close, open, 100),                       // Line-long plot() calls can be wrapped
   color = color.new(color.purple, 40),
   style = plot.style_area,
   trackprice = true)

Statements in user-defined function declarations can also be wrapped. However, since a local block must syntactically begin with an indent (4 spaces or 1 tab), when splitting it onto the next line, the continuation of a statement must begin with more than one indent (not equal to 4 multiples of spaces). For example:

test(c, o) =>
    ret = c > o ?
       (c > o+5000 ? 
          1 :
              0):
       (c < o-5000 ? 
          -1 : 
              0)

a = test(close, open)
plot(a, title="a")

Time Series

Time series is not a data type or format, instead, it is a concept of a basic structure in the PINE language. Used to store values that change continuously in time, each value corresponds to a point in time. The structure of the concept of time series is suitable for processing and recording a series of data that changes over time.

Take the built-in variable open as an example, the open built-in variable records the opening price of each int representation BAR, if this open is a 5-minute int representation period data. Then this open variable records the opening price of each 5-minute int representation BAR (bar). When your strategy program is executing, open in the code refers to the opening price of the current int representation BAR. In order to refer to the previous values (past values) in the time series, we use the [] history operator. When the strategy is executed on a certain int representation BAR, open[1] The meaning is to refer to the opening price of the previous int representation BAR of the current int representation BAR.

Although time series is very reminiscent of the “array” data structure, although the PINE language also has an array type. But they and time series are completely different concepts.

The time series designed in pine language can easily calculate the cumulative value of the closing price in the strategy code, and there is no need to use loop structures such as for, only the built-in function ta.cum(close) of the PINE language is used. For another example, we need to calculate the average value of the difference between the highest price and the lowest price of the last 14 int representation BARs (that is, the 14 int representation BARs closest to the current moment when the code is executed), which can be written as:ta.sma(high - low, 14)

The result of calling a function on a time series will also leave a trace on the time series, again we use the [] history operator to reference previous values. For example, when testing whether the closing price of the current int representation BAR exceeds the maximum value of the highest price in the last 10 int representation BAR (excluding the current int representation BAR). We can write breach = close > ta.highest(close, 10)[1], and we can also write breach = close > ta.highest(close[1], 10). So ta.highest(close, 10)[1] and ta.highest(close[1], 10) are equivalent.

This can be verified with the following code:

strategy("test pine", "test", true) 

a = ta.highest(close, 10)[1]
b = ta.highest(close[1], 10)

plotchar(true, title="a", char=str.tostring(a), location=location.abovebar, color=color.red)
plotchar(true, title="b", char=str.tostring(b), location=location.belowbar, color=color.green)

The above test code will output the values of a and b on each BAR in the corresponding time series. It can be seen that the values of a and b are always equal, so these two representation methods are equivalent.

Template arguments of pine language trade class library

Instructions for setting the arguments of the built-in template “Pine Language Trade Class Library” of the PINE strategy.

img

Trade settings

  • Execution mode Closing price model: The model is executed only after the current BAR is completed, and the trade is executed when the next BAR starts. Real-time price model: The model is executed every time the price moves, and there is a signal to execute the trade immediately.
  • Default open lot size: If the trade order does not specify the trade amount, the trade will be executed according to the set amount.
  • Maximum order quantity for a single trade: Determine the maximum amount of each order to avoid impacting the market according to the actual market and this argument setting.
  • Slippage Points: Determine the slippage when placing an order according to the Pricing Currency Precision argument and this argument. For example, the pricing currency precision is set to 2, which is accurate to the second decimal point, accurate to 0.01. Then each point of slippage points represents 0.01 pricing units. At this time, the slippage point is set to 5, and the slippage when placing an order is 0.05 (the slippage refers to the part of the price that overflows when placing an order for better and handicap order trade).
  • The longest period number of variable: affects the number of K-line BAR in the chart. It is the same as calling the function SetMaxBarLen in the javascript srategy.

Futures options

  • Variety code: contract code, it only needs to be set when the exchange object is a non-spot exchange object.
  • Minimum contract size: The minimum trading volume of the contract when placing an order.

Live trading options

  • Auto-recovery progress: Auto-recovers the state before the last strategy stop.
  • Order retry times: If the order is not filled, the order will be cancelled, and the order will be re-placed to try to trade. This argument is used to limit the maximum number of retries.
  • Network polling interval (milliseconds): Only valid for REST protocol, it controls the network request interval to prevent requests from being too frequent and exceeding the exchange limit.
  • Account synchronization time (seconds): the time period for synchronizing account data.
  • Position synchronization time after opening a position (milliseconds): Only for repeated positions caused by data delays in some exchanges, setting a larger synchronization time can alleviate such problems.
  • Leverage multiple: sets the leverage multiple.

Spot trading, other settings

  • Trading volume of one lot: the default trading volume of one lot, which is only valid for the spot.
  • Minimum trade volume: The minimum trade volume.
  • Pricing Currency Precision: The price precision, i.e. the number of decimal places in the price.
  • Accuracy of the trading variety: the precision of the order quantity, that is, the number of decimal places of the order quantity.
  • Handling fee: Calculate some data according to this setting, 0.002 means 2/1000.
  • Profit and loss statistics interval: It is only used for displaying profit and loss statistics in the real market.
  • Failed Retry (ms): Retry interval when network request fails.
  • Use proxy: Only valid for REST protocol.
  • Hide common network errors: Hide common error logs in the log area.
  • Switch base address: only valid for REST protocol.
  • Push notifications: push messages to mailboxes, etc.

Order trade

Open position

strategy(title = "open long example", pyramiding = 3)                                // The number of orders placed in the same direction allowed by pyramiding
strategy.entry("long1", strategy.long, 0.01)                                         // Open a long position at the market price, specify the group label as long1
strategy.entry("long2", strategy.long, 0.02, when = close > ta.ema(close, 10))       // The condition is triggered, the order is executed, and the market price opens a long position
strategy.entry("long3", strategy.long, 0.03, limit = 30000)                          // Specify the (lower) price, plan to place a buy order, wait for a deal to open a position, and open a position at a limit price

Close position

strategy(title = "close long example", pyramiding = 2)                              // The number of orders placed in the same direction allowed by pyramiding
strategy.entry("long1", strategy.long, 0.1)                                         // Open a long position at the market price, specify the group label as long1
strategy.entry("long2", strategy.long, 0.1)                                         // Open a long position at the market price, specify the group label as long2
strategy.close("long1", when = strategy.position_size > 0.1, qty_percent = 50, comment = "close buy entry for 50%")   // To close a position, specify to close 50% of the positions whose group label is long1
strategy.close("long2", when = strategy.position_size > 0.1, qty_percent = 80, comment = "close buy entry for 80%")   // To close a position, specify to close 80% of the positions whose group label is long2

Trade mechanism

The position mechanism of the PINE language is similar to one-way position. For example, when holding a position in the long direction (long position), if there is an order for sell operation, a planned order, etc. (in the opposite direction of the position), the execution will be triggered, and the position in the long direction will be closed first. (Close all long positions), and then execute the triggered order (in the opposite direction relative to the position before the close).

Planned order

When placing an order using the order placement command, if no price is specified, the default is a market order. In addition to the market order, you can also place an order via a planned order, which does not operate immediately to place an order. The planned order exists in the planned order queue of the program when it is not triggered, and can be seen in the “Planned Order” table tab of the status information (that is, the status bar when the strategy is running) during real order/backtesting. The system will only place an order when the real-time market price meets the conditions to trigger these planned orders. Therefore, it is normal for these orders to have a slight deviation in the trade price. When using the strategy.entry function to place an order, we can specify the limit, stop arguments.

var isTrade = false 
if not barstate.ishistory and not isTrade
    isTrade := true 
    strategy.entry("test 1", strategy.long, 0.1, stop=close*1.3, comment="test 1 order")                     // stop
    strategy.entry("test 2", strategy.long, 0.2, limit=close*0.7, comment="test 2 order")                    // limit
    strategy.entry("test 3", strategy.short, 0.3, stop=close*0.6, limit=close*1.4, comment="test 3 order")   // stop-limit    
  • limit order

    Set the limit price of the order. When the order is a buy order (that is, the direction argument is strategy.long), the order will only be triggered when the current market price is lower than this price. When the order is a sell order (that is, the direction argument is strategy.short), the order will only be triggered if the current market price is higher than this price.

  • stop order

    Set the stop loss price of the order. When the order is a buy order, the order will only be triggered when the current market price is higher than this price. When an order is a sell order, the order will only be triggered if the current price of the market is lower than that price.

  • stop-limit order

    The limit and stop arguments can be set at the same time, and the order will be triggered at the price that meets the conditions first.

Equity percent order

//@version=5
strategy("Percent of Equity Order", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100)  

// Simple moving average crossover strategy
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))  

// If the moving average crossover condition is met, buy or sell
if (longCondition)
    strategy.entry("Long", strategy.long)  

if (shortCondition)
    strategy.entry("Short", strategy.short)
  

After specifying default_qty_type=strategy.percent_of_equity, set default_qty_value to a percentage amount (0~100), 1 means 1%. The order quantity is calculated according to the amount of the denominated currency in the account. For example: if the current account has 10,000 USDT, setting a 1% order means placing an order with a scale of 100 USDT (calculated based on the current price when selling).

Declaration, logical structure keywords

var

var is a keyword used for allocating and one-time initialization of variables. In general, variable assignment grammar that does not contain the keyword var causes the variable’s value to be overwritten every time the data is updated. In contrast, when variables are assigned using the keyword var, they can “keep state” despite data updates, changing it only when the conditions in the if-expressions are met.

var variable_name = expression

Explanation:

  • variable_name - Any name of a user variable allowed in Pine Script (it can contain uppercase and lowercase Latin characters, numbers and underscores (_), but it cannot start with a number).
  • expression - Any arithmetic expression, just like defining a regular variable. The expression will be evaluated and assigned to the variable for one time.

Example

// Var keyword example
var a = close
var b = 0.0
var c = 0.0
var green_bars_count = 0
if close > open
    var x = close
    b := x
    green_bars_count := green_bars_count + 1
    if green_bars_count >= 10
        var y = close
        c := y
plot(a, title = "a")
plot(b, title = "b")
plot(c, title = "c")

The variable ‘a’ holds the close price of the first bar of each bar in the series. The variable ‘b’ holds the closing price of the first ‘green’ price bar in the series. The variable ‘c’ holds the closing price of the tenth ‘green’ bar in the series.

On FMZ, it is divided into real-time price model and closing price model. We use the following code to test the variables declared by var and varip.

strategy("test pine", "test 1", true) 

// Test var varip
var i = 0
varip ii = 0

// Print the i and ii changed in each round of the strategy logic on the graph
plotchar(true, title="ii", char=str.tostring(ii), location=location.abovebar, color=color.red)
plotchar(true, title="i", char=str.tostring(i), location=location.belowbar, color=color.green)

// Each round of logic execution increments i and ii by 1
if true
    i := i + 1
    ii := ii + 1
  • Real-time price model The above test code is executed in two phases: 1. historical int representation phase. 2. real-time int representation phase. In the real-time price model, historical int representation phase, the variables i and ii declared by var, varip are executed incrementally at each round of strategy code execution (because if true so the corresponding conditional code block is definitely executed). Therefore, it can be seen that the numbers displayed on the int representation BAR of the backtest result are incremented by 1 one by one. When the historical int representation phase ends, the real-time int representation phase begins. var, varip declared variables start to change differently. Because it is a real-time price model, the strategy code will be executed once for each price change in a int representation BAR, i := i + 1 and ii := ii + 1 will be executed once. The difference is that ii is modified every time. Although i is also modified every time, the previous value will be restored when the strategy logic is executed in the next round, and the value of i will not be updated until the current int representation BAR is completed (that is, the previous value will not be restored when the strategy logic is executed in the next round) . So it can be seen that the variable i is still increased by 1 for each BAR. But variable ii is accumulated several times for each BAR.

  • Closing price model Since the closing price model executes the strategy logic only once per int representation BAR gone. So the variables declared by var and varip in the above example behave exactly the same incrementally at the closing price model, both in the historical int representation phase and the real-time int representation phase, incrementing by 1 per int representation BAR.

varip

varip (var intrabar persist) is a keyword used for assigning and one-time initialization of variables. It is similar to the var keyword, but a variable declared with varip retains its value between live candlestick updates.

varip variable_name = expression

Explanation:

  • variable_name - Any name of a user variable allowed in a Pine script (it can contain uppercase and lowercase Latin characters, numbers, and underscores (_), but it cannot start with a number).
  • expression - Any arithmetic expression, as the time defining regular variables. On the first K-line bar, the expression is evaluated and assigned to the variable only one time.

Example

// varip
varip int v = -1
v := v + 1
plot(v)

When using var, the plot will return the value of bar_index. With varip, the same behavior occurs on historical bars, but on live bars, the chart returns a value that increases by one for each tick.

Remarks It can only be used with simple types such as float, int, bool, string, and arrays of these types.

true

It represents the value of a bool variable, or a value that can be computed when an expression uses a comparison or logical operator.

Remarks Please see the descriptions of Comparison Operators and Logical Operators.

See also bool

false

It represents the value of a bool variable and the result of comparison operations and logical operations.

Remarks Please see the descriptions of Comparison Operators and Logical Operators.

See also bool

if

An If statement defines a block of statements that must be executed when the condition of an expression is met. Version 4 of the Pine scripting language allows you to use the “else if” grammar.

Universal code from:

var_declarationX = if condition
    var_decl_then0
    var_decl_then1
    ...
    var_decl_thenN
    return_expression_then
else if [optional block]
    var_decl_else0
    var_decl_else1
    ...
  var_decl_elseN
  return_expression_else
else
    var_decl_else0
    var_decl_else1
    ...
    var_decl_elseN
    return_expression_else

Remarks var_declarationX - This variable gets the value of the if statement condition - If the condition is true, the logic in the statement block then is used (var_decl_then0, var_decl_then1, etc.). If the condition is false, the logic in the statement block else if or else is used (var_decl_else0, var_decl_else1, etc.). return_expression_then and return_expression_else - The last expression in the module or the expression from the block else returns the final value of the statement. If the variable was declared last, its value will be the result value.

The type of the return value of the if statement depends on the type of return_expression_then and return_expression_else. When running on TradingView, their types must be matched: when you have a string value in the else block, it is not possible to return an integer value from the then block. When running on the FMZ, the following example will not report an error. When the y value is “open”, the value of the plot when drawing is n/a.

Example

// This code compiles
x = if close > open
    close
else
    open  

// This code doesn't compile by trading view
// y = if close > open
//     close
// else
//     "open"
plot(x)

The else block can be omitted. In this case, if the condition is false, the var_declarationX variable is assigned an “empty” value (na, false, or “”):

Example

// if
x = if close > open
    close
// If current close > current open, then x = close.
// Otherwise the x = na.
plot(x)

Multiple “else if” blocks can be used or none at all. The blocks of “then”, “else if”, “else” are moved four spaces:

Example

// if
x = if open > close
    5
else if high > low
    close
else
    open
plot(x)

The result value of the if statement can be ignored (“var_declarationX=” can be omitted). It can be useful if you need side effects of expressions, for example, in strategy trading:

Example

if (ta.crossover(high, low))
    strategy.entry("BBandLE", strategy.long, stop=low)
else
    strategy.cancel(id="BBandLE")

If statements can contain each other:

Example

// if
float x = na
if close > open
    if close > close[1]
        x := close
    else
        x := close[1]
else
    x := open
plot(x)

for

The ‘for’ construct allows multiple statements to be executed repeatedly:

[var_declaration =] for counter = from_num to to_num [by step_num]
    statements | continue | break
    return_expression

var_declaration - An optional variable declaration that will be assigned as the value of the loop’s return_expression. counter - A variable that holds the loop counter value, incrementing/decrementing by 1 or the step_num value on each iteration of the loop. from_num - The starting value of the counter. “series int/float” values/expressions are allowed. to_num - The final value of the counter. The loop breaks when the counter is greater than to_num (or less than to_num in the case from_num > to_num). “series int/float” values/expressions are allowed, but they are only evaluated on the first iteration of the loop. step_num - The increment/decrement value of the counter. It is optional. The default is +1 or -1, depending on the largest of from_num or to_num. When using values, the counter is also incremented/decremented according to the largest of from_num or to_num, so the +/- sign of step_num is optional. statements | continue | break - Any number of statements, or the ‘continue’ or ‘break’ keywords, indented by 4 spaces or a single tab. return_expression - The return value of the loop, if present, is assigned to the variable in var_declaration. If the loop exits due to the “continue” or “break” keywords, the return value of the loop is the return value of the last variable assigned a value before the loop exits. continue - A keyword that can only be used in loops. It causes the next iteration of the loop to be executed. break - The keyword to exit the loop.

Example

// Here, we count the quantity of bars in a given 'lookback' length which closed above the current bar's close
qtyOfHigherCloses(lookback) =>
    int result = 0
    for i = 1 to lookback
        if close[i] > close
            result += 1
    result
plot(qtyOfHigherCloses(14))

See also for...in while

for…in

The for...in construct allows multiple statements to be repeated for each element in the array. It can be used with either argument: array_element, or with two arguments: [index, array_element]. The second form does not affect the function of the loop. It keeps track of the index of the current iteration in the first variable of the tuple.

[var_declaration =] for array_element in array_id
    statements | continue | break
    return_expression

[var_declaration =] for [index, array_element] in array_id
    statements | continue | break
    return_expression

var_declaration - An optional variable declaration that will be assigned the value of the loop’s return_expression. index - An optional variable that keeps track of the current iteration index. The index starts at 0. Variables are immutable within the loop body. When used, it must be contained in a tuple that also contains array_element. array_element - A variable containing each consecutive array element to be processed in the loop. This variable is immutable within the loop body. array_id - The array ID of the loop iteration. statements | continue | break - Any number of statements, or the ‘continue’ or ‘break’ keywords, indented by 4 spaces or a single tab. return_expression - The return value of the loop is assigned to the variable in var_declaration, if present. If the loop exits due to the ‘continue’ or ‘break’ keywords, the return value of the loop is the variable that was last assigned before the loop exited. continue - A keyword that can only be used in loops. It causes the next iteration of the loop to be executed. break - The keyword to exit the loop.

Allows to modify elements of an array or their size within a loop. Here, we use the one-argument form of for...in to determine, for each bar, how many bars have an OHLC value greater than the SMA of the ‘close’ value:

Example

// Here we determine on each bar how many of the bar's OHLC values are greater than the SMA of 'close' values
float[ ] ohlcValues = array.from(open, high, low, close)
qtyGreaterThan(value, array) =>
    int result = 0
    for currentElement in array
        if currentElement > value
            result += 1
        result
plot(qtyGreaterThan(ta.sma(close, 20), ohlcValues))

Here, we use the two-argument form of for…in to set the values of our isPos array to true when their corresponding values in our valuesArray array are positive:

Example

// for...in
var valuesArray = array.from(4, -8, 11, 78, -16, 34, 7, 99, 0, 55)
var isPos = array.new_bool(10, false)  

for [index, value] in valuesArray
    if value > 0
        array.set(isPos, index, true)  

if barstate.islastconfirmedhistory
    runtime.log(str.tostring(isPos))

See also for while array.sum array.min array.max

while

The while statement allows conditional iteration of native code blocks.

variable_declaration = while boolean_expression
    ...
    continue
    ...
    break
    ...
    return_expression

Explanation: variable_declaration - Optional variable declaration. return expression can provide an initialization value for this variable. boolean_expression - If true, execute the local block of the while statement. If false, script execution continues after the while statement. continue - The continue keyword causes the loop to branch to the next iteration. break - The break keyword causes the loop to terminate. Execution of the script resumes after the while statement. return_expression - Optional line providing the return value of the while statement.

Example

// This is a simple example of calculating a factorial using a while loop.
int i_n = input.int(10, "Factorial Size", minval=0)
int counter   = i_n
int factorial = 1
while counter > 0
    factorial := factorial * counter
    counter   := counter - 1

plot(factorial)

Remarks The native code block after the initial while line must be indented by four spaces or a tab. To terminate a while loop, the boolean expression following while must eventually become false, or break must be executed.

switch

The switch operator transfers control to one of several statements based on the condition and the value of the expression.

[variable_declaration = ] switch expression
    value1 => local_block
    value2 => local_block
    ...
    => default_local_block

[variable_declaration = ] switch
    boolean_expression1 => local_block
    boolean_expression2 => local_block
    ...
    => default_local_block

switch with expression:

Example

// Switch using an expression

string i_maType = input.string("EMA", "MA type", options = ["EMA", "SMA", "RMA", "WMA"])

float ma = switch i_maType
    "EMA" => ta.ema(close, 10)
    "SMA" => ta.sma(close, 10)
    "RMA" => ta.rma(close, 10)
    // Default used when the three first cases do not match.
    => ta.wma(close, 10)

plot(ma)

switch without expression:

Example

strategy("Switch without an expression", overlay = true)

bool longCondition  = ta.crossover( ta.sma(close, 14), ta.sma(close, 28))
bool shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))

switch
    longCondition  => strategy.entry("Long ID", strategy.long)
    shortCondition => strategy.entry("Short ID", strategy.short)

Returns The value of the last expression in the executed local statement block.

Remarks Only one of local_block instances or default_local_block can be executed. default_local_block is only introduced with the => tag, and is only executed if the preceding block is not executed. If the result of a switch statement is assigned to a variable and default_local_block is not specified, the statement returns na if local_block is not executed. When assigning the result of a switch statement to a variable, all local_block instances must return a value of the same type.

See also if ?:

series

series is a keyword that indicates the data series type. It is usually unnecessary to explicitly use the series keyword.

Operator

=

Used to assign values to variables, but only when the variable is declared (first used).

:=

The assignment operator assigns a value to the variable on the left. Used to assign values to previously declared variables.

!=

Not equal to. Applicable to expressions of any type.

expr1 != expr2

Returns Boolean value, or a sequence of Boolean values.

%

Modulo (integer remainder). Applicable to numerical expressions.

expr1 % expr2

Returns Integer or float value, or series of values.

Remarks In Pine Script, when the integer remainder is calculated, the quotient is truncated, i.e. rounded towards the lowest absolute value. The resulting value will have the same sign as the dividend.

Example: -1 % 9 = -1 - 9 * truncate(-1/9) = -1 - 9 * truncate(-0.111) = -1 - 9 * 0 = -1.

%=

Modulo assignment. Applicable to numerical expressions.

expr1 %= expr2

Example

// Equals to expr1 = expr1 % expr2.
a = 3
b = 3
a %= b
// Result: a = 0.
plot(a)

Returns Integer or float value, or series of values.

*

Multiplication assignment. Applicable to numerical expressions.

expr1 * expr2

Returns Integer or float value, or series of values.

*=

Multiplication assignment. Applicable to numerical expressions.

expr1 *= expr2

Example

// Equals to expr1 = expr1 * expr2.
a = 2
b = 3
a *= b
// Result: a = 6.
plot(a)

Returns Integer or float value, or series of values.

+

Addition or unary plus. Applicable to numerical expressions or strings.

expr1 + expr2
+ expr

Returns The binary + of the string returns the combination of expr1 and expr2 Number returns an integer or floating point value, or a sequence of values: Binary ‘+’ returns expr1 plus expr2. Unary “+” returns expr (nothing is added to unary operator symmetry).

Remarks You may use arithmetic operators with numbers as well as with series variables. In case of usage with series the operators are applied elementwise.

+=

Additive assignment. Applies to numeric expressions or strings.

expr1 += expr2

Example

// Equals to expr1 = expr1 + expr2.
a = 2
b = 3
a += b
// Result: a = 5.
plot(a)

Returns For strings, returns the concatenation of expr1 and expr2. For numbers, returns an integer or float value, or series of values.

Remarks You may use arithmetic operators with numbers as well as with series variables. In case of usage with series the operators are applied elementwise.

-

Subtraction or unary minus. Applicable to numerical expressions.

expr1 - expr2
- expr

Returns Return an integer or floating-point value, or series of values: Binary ‘+’ returns expr1 minus expr2. Unary - returns the negation of expr.

Remarks You may use arithmetic operators with numbers as well as with series variables. In case of usage with series, the operators are applied elementwise.

-=

Subtraction assignment. Applicable to numerical expressions.

expr1 -= expr2

Example

// Equals to expr1 = expr1 - expr2.
a = 2
b = 3
a -= b
// Result: a = -1.
plot(a)

Returns Integer or float value, or series of values.

/

Division assignment. Applicable to numerical expressions.

expr1 / expr2

Returns Integer or float value, or series of values.

/=

Division assignment. Applicable to numerical expressions.

expr1 /= expr2

Example

// Equals to expr1 = expr1 / expr2.
a = 3
b = 3
a /= b
// Result: a = 1.
plot(a)

Returns Integer or float value, or series of values.

<

Less than. Applicable to numerical expressions.

expr1 < expr2

Returns Boolean value, or series of boolean values.

<=

Less than or equal to. Applicable to numerical expressions.

expr1 <= expr2

Returns Boolean value, or series of boolean values.

==

Equal to. Applicable to expressions of any type.

expr1 == expr2

Returns Boolean value, or series of boolean values.

=>

The ‘=>’ operator is used in user-defined function declarations and in switch statements.

The function declaration grammar is:

<identifier>([<argument_name>[=<default_value>]], ...) =>
    <local_block>
    <function_result>

A <local_block> is zero or more Pine Script statements. <function_result> is a variable, an expression, or a tuple.

Example

// single-line function
f1(x, y) => x + y
// multi-line function
f2(x, y) => 
    sum = x + y
    sumChange = ta.change(sum, 10)
    // Function automatically returns the last expression used in it
plot(f1(30, 8) + f2(1, 3))

Reamrks You can learn more about user-defined functions in the User Manual’s pages on Declaring functions and Script libraries.

>

Greater than. Applicable to numerical expressions.

expr1 > expr2

Returns Boolean value, or series of boolean values.

>=

Greater than or equal to. Applicable to numerical expressions.

expr1 >= expr2

Returns Boolean value, or series of boolean values.

?:

Ternary conditional operator.

expr1 ? expr2 : expr3

Example

// Draw circles at the bars where open crosses close
s2 = ta.cross(open, close) ? math.avg(open,close) : na
plot(s2, style=plot.style_circles, linewidth=2, color=color.red)  

// Combination of ?: operators for 'switch'-like logic
c = timeframe.isintraday ? color.red : timeframe.isdaily ? color.green : timeframe.isweekly ? color.blue : color.gray
plot(hl2, color=c)

Returns expr2 if expr1 is evaluated to true, expr3 otherwise. Zero value (0 and also NaN, +Infinity, -Infinity) is considered to be false, any other value is true.

Remarks Use na for ‘else’ branch if you do not need it. You can combine two or more ?: operators to achieve the equivalent of a ‘switch’-like statement (see examples above). You may use arithmetic operators with numbers as well as with series variables. In case of usage with series the operators are applied elementwise.

See also na

[]

Series subscript. Provides access to previous values of series expr1. expr2 is the number of bars in the past, and it must be numerical. Floats will be rounded down.

expr1[expr2]

Example

// [] can be used to "save" variable value between bars
a = 0.0 // declare `a`
a := a[1] // immediately set current value to the same as previous. `na` in the beginning of history
if high == low // if some condition - change `a` value to another
    a := low
plot(a)

Returns A series of values.

See also math.floor

and

Logical AND. Applicable to boolean expressions.

expr1 and expr2

Returns Boolean value, or series of boolean values.

or

Logical OR. Applicable to boolean expressions.

expr1 or expr2

Returns Boolean value, or series of boolean values.

not

Logical negation (NOT). Applicable to boolean expressions.

not expr1

Returns Boolean value, or series of boolean values.

Data type keywords

bool

Keyword used to explicitly declare the “bool” (boolean) type of a variable or an argument. “Bool” variables can have values: true, false or na.

Example

// bool
bool b = true    // Same as `b = true`
b := na
plot(b ? open : close)

Remarks Explicitly mentioning the type in a variable declaration is optional, except when it is initialized with na. Learn more about Pine Script types in the User Manual page on the Type System.

See also var varip int float color string true false

int

Keyword used to explicitly declare the “int” (integer) type of a variable or an argument.

Example

// int
int i = 14    // Same as `i = 14`
i := na
plot(i)

Remarks Explicitly mentioning the type in a variable declaration is optional, except when it is initialized with na. Learn more about Pine Script types in the User Manual page on the Type System.

See also var varip float bool color string

float

Keyword used to explicitly declare the “float” (floating point) type of a variable or an argument.

Example

// float
float f = 3.14    // Same as `f = 3.14`
f := na
plot(f)

Remarks Explicitly mentioning the type in a variable declaration is optional, except when it is initialized with na.

See also var varip int bool color string

string

Keyword used to explicitly declare the “string” type of a variable or an argument.

Example

// string
string s = "Hello World!"    // Same as `s = "Hello world!"`
// string s = na // same as "" 
plot(na, title=s)

Remarks Explicitly mentioning the type in a variable declaration is optional, except when it is initialized with na. Learn more about Pine Script types in the User Manual page on the Type System.

See also var varip int float bool str.tostring str.format

color

Keyword used to explicitly declare the “color” type of a variable or an argument.

Example

// color
color textColor = color.green
if barstate.islastconfirmedhistory
    runtime.log("test", textcolor = textColor)

Remarks Color literals have the following format: #RRGGBB or #RRGGBBAA. The letter pairs represent 00 to FF hexadecimal values (0 to 255 in decimal) where RR, GG and BB pairs are the values for the color’s red, green and blue components. AA is an optional value for the color’s transparency (or alpha component) where 00 is invisible and FF opaque. When no AA pair is supplied, FF is used. The hexadecimal letters can be upper or lower case.

Explicitly mentioning the type in a variable declaration is optional, except when it is initialized with na. Learn more about Pine Script types in the User Manual page on the Type System.

See also var varip int float string color.rgb color.new

array

Keyword used to explicitly declare the “array” type of a variable or an argument. Array objects (or IDs) can be created with the array.new<type>, array.from function.

Example

// array
array<float> a = na
a := array.new<float>(1, close)
plot(array.get(a, 0))

Remarks Array objects are always of “series” form.

See also var array.new array.from

Objects

Objects in the PINE language are instances of user-defined types (UDTs), which can be understood as methodless classes that allow users to create custom types in strategies to organize different values in an entity.

Defining types

Let’s define an order type to store order information:

type order
    float price
    float amount
    string symbol
  • Types are declared using the type keyword.
  • The type keyword is followed by the type name.
  • The first line type defines the type name, indented four spaces, and defines the fields contained in the type.
  • Each field needs to declare its data type, such as int, float, string.

Creating objects

Using the declared type, call the new() function to create an object:

order1 = order.new()
order1 = order.new(100, 0.1, "BTC_USDT")
order1 = order.new(amount = 0.1, symbol = "BTC_USDT", price = 100)

You can also create empty objects:

order order1 = na

Let’s look at a practical example:

type order
    float price
    float amount
    string symbol

if strategy.position_size == 0 and open > close
    strategy.entry("long", strategy.long, 1)

order1 = order.new(strategy.opentrades.entry_price(strategy.opentrades - 1), strategy.opentrades.size(strategy.opentrades - 1), syminfo.ticker)
// runtime.log(order1)   // Output {"data":{"price":46002.8,"amount":1,"symbol":"swap"},"_meta":0,"_type":"order"}

In this example:

order1 = order.new(strategy.opentrades.entry_price(strategy.opentrades - 1), strategy.opentrades.size(strategy.opentrades - 1), syminfo.ticker)

It can also be written as:

order order1 = na
order1 := order.new(strategy.opentrades.entry_price(strategy.opentrades - 1), strategy.opentrades.size(strategy.opentrades - 1), syminfo.ticker)

Object type for the use of var keyword

//@version=5
indicator("Objects using `var` demo")

//@type A custom type to hold index, price, and volume information.
type BarInfo
    int   index = bar_index
    float price = close
    float vol   = volume

//@variable A `BarInfo` instance whose fields persist through all iterations, starting from the first bar.
var BarInfo firstBar = BarInfo.new()
//@variable A `BarInfo` instance declared on every bar.
BarInfo currentBar = BarInfo.new()

// Plot the `index` fields of both instances to compare the difference.
plot(firstBar.index, "firstBar")
plot(currentBar.index, "currentBar")

When you use the var keyword to declare a variable assigned to an object of a user-defined type, the keyword automatically applies to all fields of the object. This means that an object declared via the var keyword will maintain its state between each iteration without the need to reinitialize its field values in each iteration.

  • The firstBar object is declared using the var keyword, so its fields (index, price, vol) will retain their values in each iteration, starting from the first entry and ending with the last entry.
  • The currentBar object is not declared with the var keyword, so its fields will be reinitialized on each entry and you will have a new object on each iteration.

By plotting the index fields of the two objects, you can compare the differences between them. firstBar.index will maintain the previously set value in each iteration, while currentBar.index will be reinitialized in each iteration to the bar_index value of the current entry.

Object types for use of the varip keyword

//@version=5
indicator("Objects using `varip` fields demo")

//@type A custom type that counts the bars and ticks in the script's execution.
type Counter
    int       bars  = 0
    varip int ticks = 0

//@variable A `Counter` object whose reference persists throughout all bars.
var Counter counter = Counter.new()

// Add 1 to the `bars` and `ticks` fields. The `ticks` field is not subject to rollback on unconfirmed bars.
counter.bars  += 1
counter.ticks += 1

// Plot both fields for comparison.
plot(counter.bars, "Bar counter", color.blue, 3)
plot(counter.ticks, "Tick counter", color.purple, 3)

In Pine, the varip keyword is used to indicate that an object’s fields persist throughout the script execution and do not roll back on unconfirmed bars. In the declaration of the Counter type, the bars field does not use the varip keyword, so it rolls back on each unconfirmed bar. The ticks field uses the varip keyword, so it does not roll back on unconfirmed bars. The counter object is declared using the var keyword, so it persists throughout the script execution. In each iteration, both the bars field and the ticks field are incremented by 1. The bars field rolls back on each unconfirmed bar, while the ticks field does not roll back. Finally, by plotting the counter.bars and counter.ticks fields, you can compare the difference between them. The value of counter.bars rolls back on each unconfirmed bar, while the value of counter.ticks continues to increase until the end of the script execution.


More

The BeggarWhy the strategy of the square replica of the strategy of the pine can not be realized

Inventors quantify - small dreamsWell, let's have a look.

The BeggarChang's Optimized Trend Tracker is a great tool.

Inventors quantify - small dreamsHello, what exactly is the strategy?