The resource loading... loading...

FMZ PINE Script documentation is provided.

Author: Inventors quantify - small dreams, Created: 2022-05-06 14:27:06, Updated: 2024-10-12 15:27:04

[TOC]

Keywords, grammar, setting up a profile

Code structure

The general structure of the code in Pine is:

<version>
<declaration_statement>
<code>

Notes

FMZ's Pine language supported annotation symbols: single line annotation//This is the first time I've seen it./* */For example, the following examples of commentary spelling:

[macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9)  // 计算MACD指标

/*
plot函数在图表上画出指标线
*/
plot(macdLine, color = color.blue, title='macdLine')
plot(signalLine, color = color.orange, title='signalLine')
plot(histLine, color = color.red, title='histLine')

The version

A compiler instruction in the following form tells the compiler which version of Pine the script is written in:

//@version=5

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

Statement of purpose

  • indicator()
  • strategy()

Statements define the type of script, which in turn determines what content is allowed in it, and how it is used and executed. Sets the key attributes of the script, such as its name, where it will appear when it is added to the chart, the precision and format of the values it displays, and controls certain values of its behavior at runtime, such as the maximum number of drawing objects it will display in the chart. For a policy, the attributes include parameters that control retrieval, such as initial capital, commissions, slippage points, etc. FMZ's Pine does not require a policy code to includeindicator()Orstrategy()The statement is as follows:

The Code

A line in a script that is not a comment or a compiler instruction is a statement that implements the script's algorithm. A statement can be one of these.

  • Variable declaration
  • Reassignment of variables
  • The function declaration
  • Built-in function calls, user defined function calls
  • ifforwhileorswitchand so on.

Sentences can be arranged in many ways.

  • Some statements can be expressed in a single line, such as most variable declarations, which contain only one function call line, or single-line function declarations; others, like structures, always require multiple lines because they require a local block.
  • The global statements of the script (i.e. the parts that do not belong to the sub-block) cannot be used to describe the entire script.空格or制表符(tab key) start. Their first character must also be the first character of the line. A line that starts at the first position in the line is, by definition, part of the global scope of the script.
  • A structure or multi-line function statement always requires alocal blockA local block must be compressed into a semicolon or four spaces (otherwise, it will be parsed as the serial code of the previous line, i.e. determined to be the continuous content of the previous line of code), and each local block defines a different local range.
  • Multiple single-line statements can be connected in a single line by using the comma ((,) as a separator.
  • A line can contain a commentary or just a commentary.
  • A line can also be wrapped (continue on multiple lines).

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

indicator("", "", true)             // 声明语句(全局范围),可以省略不写

barIsUp() =>                        // 函数声明(全局范围)
    close > open                    // 本地块(本地范围)

plotColor = if barIsUp()            // 变量声明 (全局范围)
    color.green                     // 本地块 (本地范围)
else
    color.red                       // 本地块 (本地范围)

runtime.log("color", color = plotColor)  // 调用一个内置函数输出日志 (全局范围)

Change the code

Long rows can be split into multiple rows, or "wrapped" up. The wrapped row must compress any number of spaces, as long as it is not a multiple of 4 (these boundaries are used to compress local blocks).

a = open + high + low + close

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

a = open +
      high +
          low +
             close

A long plot ((()) call can be wrapped up in a.

close1 = request.security(syminfo.tickerid, "D", close)      // syminfo.tickerid 当前交易对的日线级别收盘价数据系列
close2 = request.security(syminfo.tickerid, "240", close)    // syminfo.tickerid 当前交易对的240分钟级别收盘价数据系列
plot(ta.correlation(close, open, 100),                       // 一行长的plot()调用可以被包装
   color = color.new(color.purple, 40),
   style = plot.style_area,
   trackprice = true)

Statements in user-defined function declarations can also be wrapped. However, since the local block must syntactically start with a contraction (four spaces or one check mark), when dividing it into the next line, the continuation of the statement must start with more than one contraction (not equal to a multiple of four 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, but a basic structure concept in the PINE language. It is used to store values that change continuously over time, each value corresponding to a point in time. The structure of this concept is well suited for processing and recording a series of data that changes over time. with built-in variablesopenFor example,openThe built-in variable records the opening price of each K-line BAR, if thisopenSo this is the data for the five-minute K-line cycle.openWhat is recorded in the variable is the opening price of the K-line BAR (column) every 5 minutes.openThis refers to the opening price of the current location of the K-line BAR. To refer to the previous value in the time sequence (past value), we use[]The history operator, when a policy is executed on a certain K-line BAR, is used to display the policy.open[1]This means that the opening price of the previous K line BAR of the current K line BAR is referenced.

AlthoughTime seriesIt's easy to think of data structures as "array", although the PINE language also has array types.

The PINE language designed time sequences in this way to calculate the cumulative value of the closing price in the strategy code very easily, and without the need to use loop structures such as for, just using the built-in functions of the PINE language.ta.cum(close)To give another example, we need to calculate the average of the maximum price and minimum price difference of the last 14 K-string BAR (i.e. the 14 K-string BAR closest to the current moment of execution of the code) which can be written as:ta.sma(high - low, 14)

The result of calling a function on a time sequence also leaves a trace on the time sequence.[]The historical operator refers to the previous value. For example, we can write that the closing price of the current K-line BAR exceeds the maximum value of the highest price in the last 10 K-line BARs (excluding the current K-line BAR).breach = close > ta.highest(close, 10)[1]It can also be written asbreach = close > ta.highest(close[1], 10)So what?ta.highest(close, 10)[1]andta.highest(close[1], 10)It's not just a question of time.

The following code can be used to verify:

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 outputs a and b on each BAR with their corresponding values in the time series, and it can be seen that a and b are always equal, so the two representation methods are equivalent.

Template parameters for the Pine language transaction library

The built-in template for the PINE policy, "Pine language transaction library", has parametric settings.

img

Settings for transactions

  • How to execute Closing price model: The model is executed at the end of the current BAR and executes the transaction at the beginning of the lower root BAR. Real-time price model: The model is executed every time the price changes, with signals to execute the transaction immediately.
  • Default number of open positions: If the trading instruction does not specify the number of trades, the number of trades executed according to this setting;
  • Maximum number of orders per transaction: based on the actual discount, in combination with this parameter setting, determine the maximum number of orders per transaction to avoid impacting the discount.
  • The number of price points:定价货币精度Parameters and this parameter determine the slippage price when the order is placed. For example, if the pricing currency precision is set to 2, i.e. precise to the second decimal place, precise to 0.01 then the slippage point number represents 0.01 of each pricing unit.
  • The number of longest cycles of the variable: affects the number of K-line BARs in the graph, withjavascriptCalls in policySetMaxBarLenThe function works the same way.

Futures options

  • Variety codes: Contract codes, which are only required when the exchange object is a non-cash exchange object.
  • Minimum number of contracts: the minimum amount of contracts traded when the order is placed.

The real disk option

  • Auto-reset progress: Auto-reset to the state before the last policy was stopped.
  • Order retry number: The order is not executed and the order is cancelled and the order is retried. This parameter is used to limit the maximum number of retries.
  • Network query interval ((milliseconds): valid only for the REST protocol, control the network request interval, avoid requests that are too frequent and exceed the limits of the exchange.
  • Account synchronization time ((seconds): The time period for synchronizing account data.
  • Post-opening position synchronization time (milliseconds): Only for repeated openings caused by data delays on some exchanges, setting the synchronization time to be larger can mitigate such problems.
  • Leverage multiplier: Set the leverage multiplier.

Cash transactions, other settings

  • One-handed transaction volume: The default one-handed transaction volume is only valid for spot transactions.
  • Minimum trading volume: Minimum trading volume is the minimum amount of transactions.
  • Price accuracy: Price accuracy, i.e. the small number of digits of the price.
  • Transaction variety accuracy: the precision of the next unit, i.e. the small number of digits of the next unit.
  • Fee: 0.002 is 2 parts per thousand for some data calculated according to this setting.
  • Gain-loss statistics interval: only on the physical disk shows the use of gain-loss statistics.
  • Failed retry (millisecond): Interval of retry when network request fails.
  • Use of proxies: valid only for the REST protocol.
  • Hide common network errors: Hide common error logs in the log area.
  • Switch base addresses: valid only for the REST protocol.
  • Push notifications: Push messages to the inbox etc.

Subscribe

Opening of the market

strategy(title = "open long example", pyramiding = 3)                                // pyramiding 允许的同方向下单的次数
strategy.entry("long1", strategy.long, 0.01)                                         // 市价开多仓,指定分组标签为long1
strategy.entry("long2", strategy.long, 0.02, when = close > ta.ema(close, 10))       // 条件触发,执行下单,市价开多仓
strategy.entry("long3", strategy.long, 0.03, limit = 30000)                          // 指定(较低的)价格,计划下买单订单,等待成交开仓,限价开仓

Plainly

strategy(title = "close long example", pyramiding = 2)                              // pyramiding 允许的同方向下单的次数
strategy.entry("long1", strategy.long, 0.1)                                         // 市价开多仓,指定分组标签为long1
strategy.entry("long2", strategy.long, 0.1)                                         // 市价开多仓,指定分组标签为long2
strategy.close("long1", when = strategy.position_size > 0.1, qty_percent = 50, comment = "close buy entry for 50%")   // 平仓,指定平掉分组标签为long1的仓位的50%持仓
strategy.close("long2", when = strategy.position_size > 0.1, qty_percent = 80, comment = "close buy entry for 80%")   // 平仓,指定平掉分组标签为long2的仓位的80%持仓

Mechanism of trade

The PINE language holdings mechanism is similar to one-way holdings. For example, when holding a multi-headed position ("multi-headed holdings"), if there are sell orders, plan lists, etc. (in the reverse direction of the holdings), the order is triggered to execute. The multi-headed position is first flattened ("flatten all multi-headed holdings") and then executed (in the reverse direction of the holdings).

Schedule of events

When using the order ordering command, the default is market ordering if no price is specified. In addition to market ordering, you can also order from a plan order, which does not immediately operate the order. Plan ordering can be performed in the plan order queue of a program that exists when it is not triggered.Discs and re-testsThe time status information (i.e. the status bar when the policy is running) is seen in the "schedule orders" tab section. The system will only actually place orders when the real-time market price conditions are met to trigger these orders.strategy.entrySo we can specify that when we order a function, we can specifylimitstopParameters are.

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 orders

    Set a limit price for the order, i.e. when the order is for paymentdirectionThe parameter isstrategy.longThe order is triggered only when the current market price is below that price. When the order is for sale (i.e.directionThe parameter isstrategy.shortThe order is triggered only when the current market price is higher than that price.

  • Stop order

    Set the stop-loss price of the order, when the order is a buy, and only trigger the order when the current market price is higher than that price. When the order is a sell order, the order is triggered only when the current market price is below that price.

  • Stop-limit orders

    Can be set simultaneouslylimitstopParameters, orders are triggered at the first price that meets the conditions.

Percentage of rights and interests

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

// 简单的均线交叉策略
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))  

// 如果均线交叉条件满足,则买入或卖出
if (longCondition)
    strategy.entry("Long", strategy.long)  

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

Specifydefault_qty_type=strategy.percent_of_equityThen, setdefault_qty_valueFor a percentage number ((0-100), 1 is 1%;; calculate the unit quantity according to the number of billing currencies in the account;; for example: the current account has 10000 USDT, set the order quantity to 1%, i.e. use a 100 USDT scale order quantity ((calculated according to the current price at the time of sale)).

Statements, logical structure keywords and so on.

var

var is the keyword for assignment and one-time initialization of variables. Typically, variable assignment syntax that does not include the keyword var will result in variable values being overlaid each time the data is updated. Conversely, when variables are assigned with the keyword var, they can be kept in a state-like state even though the data is updated, changing it only when the conditions in the if-expressions are met.

var variable_name = expression

Explained:

  • variable_name- Any name of user variable allowed in Pine Script ((can contain uppercase and lowercase Latin characters, numbers and underscores ((_), but cannot begin with a number) )).
  • expression- any arithmetic expression, like defining a regular variable.

Examples

// 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 maintains the closing price of the first column of each column in the series. Variable b remained the closing price of the first in the series. Variable c remained the closing price of the tenth in the series.

The FMZ is divided into real-time price models, closing price models, and price comparisons.varvaripWe test the declared variable using the following code.

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

// 测试 var varip
var i = 0
varip ii = 0

// 将策略逻辑每轮改变的i、ii打印在图上
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)

// 每轮逻辑执行都给i、ii递增1
if true
    i := i + 1
    ii := ii + 1
  • Real-time pricing model The above test code is divided into two phases during execution: 1st, the historical K-line phase; 2nd, the real-time K-line phase.varvaripThe declared variable i, ii will perform incremental operations every time the policy code is executed, becauseif trueSo it is certain to execute the corresponding conditional code block); so it can be seen that the numbers shown on the retrieval result K line BAR are each incremented by 1; when the historical K line phase ends, the real-time K line phase begins.varvaripThe declared variables start to change differently. Because it is a real-time price model, every price change in a K-line BAR is executed with a repeated strategy code.i := i + 1andii := ii + 1The difference is that ii is modified every time. Although i is also modified each time, the value of i is restored when the next round of execution of the policy logic is executed, until the current K-line BAR runs out and the update determines the value of i (i.e. the value is no longer restored when the next round of execution of the policy logic is executed).

  • The closing model Since the closing price model executes one strategy logic at the end of each K-line BAR, the historical K-line phase and the real-time K-line phase are used in the closing price model.varvaripThe declared variables are perfectly consistent in the incremental representation in the above example, with BAR incrementing by 1 for each K line.

varip

varip (var intrabar persist) is a keyword used to allocate and initialize variables once. It is similar to the var keyword, but a variable with a varip declaration retains its value between real-time K-line updates.

varip variable_name = expression

Explained:

  • variable_name- Any name of user variable allowed in the Pine script ((can include uppercase and lowercase Latin characters, numbers and underscores ((_), but cannot begin with a number)).
  • expression- any arithmetic expression, as when defining a regular variable. On the first K line, the expression is computed only once and assigned to the variable once.

Examples

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

When var is used, the graph returns the value of bar_index. Using varip, the same behavior occurs on the historical K line, but on the real-time K line, the graph returns a value that increases by one for each tick.

NotesCan only be used with simple types such as float, int, boolean, string, and arrays of these types.

true

Indicates the value of a Boolean variable, or when an expression is usedComparisonorLogicThe value that can be calculated when the operator is used.

NotesSee alsoComparisonOperators andLogicDescription of the operator.

See you later bool

false

Indicates the value of a Boolean variable, as well as the results of comparison operations, logic operations.

NotesSee alsoComparisonOperators andLogicDescription of the operator.

See you later bool

if

The if statement defines a block of statements that must be executed when the expression condition is met. The 4th edition of the Pine scripting language allows you to use the else if syntax.

The common codes come 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

Notes var_declarationX- This variable takes the value of the if statementcondition- Use the sentence block if the condition is truethenThe logic of thevar_decl_then0var_decl_then1etc) ⇒ If the condition is false, use the sentence blockelse ifOrelseThe logic of thevar_decl_else0var_decl_else1I'm not sure what you mean.return_expression_then , return_expression_else- The last expression in the module or an expression from the blockelse will return the final value of the statement. If the variable is declared at the end, its value will be the result value.

The type of the return value of the if statement depends onreturn_expression_thenandreturn_expression_elseTypes. When running on TradingView, their types must match: it is impossible to return an integer value from the then statement block when you have a string value in theelse block. When running on FMZ, the following example does not return an error, when the y value is taken to be "open", the value when the plot is drawn is n/a.

Examples

// 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)

Can be omittedelseblocks. In this case, if the condition is false, the variable var_declarationX is assigned a??empty threshold ((na、false or??):

Examples

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

You can use multiple else if blocks or not use them at all. then, else if, else if blocks are moved to four spaces:

Examples

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

Can be ignoredifThe result value of the statement ((var_declarationX= can be omitted)). It can be useful if you need a side effect of the expression, for example in strategy trading:

Examples

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

If statements can contain each other:

Examples

// 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' string structure 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 return_expression of the return loop.counter- Stores the variable of the countdown counter value, increasing/decreasing 1 or step_num value in each iteration of the countdown;from_num- Start value of the counter. It allows the use of the int/float threshold/expression of the array.to_num- The final value of the counter. The loop is interrupted when the counter is greater than to_num (or less than to_num in the case of from_num > to_num). The use of the int/float thresholds/expressions of the arrays is allowed, but they are evaluated only at the first iteration of the loop.step_num- Increase/decrease the value of the counter. It is optional. The default value is +1 or −1, depending on the largest from_num or to_num. When using the value, the counter also increases/decrease according to the largest from_num or to_num, so the +/- symbol for step_num is optional.statements | continue | break- Any number of statements, or the keyword "continue" or "break", compressed into 4 spaces or one tab.return_expression- The return value of the loop, if any, is assigned to a variable in the var_declaration. If the loop exits due to the keyword "continue" or "break", the return value of the loop is the value of the last variable assigned a value before the loop exits.continue- keyword that can only be used in the loop. It causes the next iteration of the loop to be executed.break- The key word to get out of the loop.

Examples

// 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 you later for...in while

for…in

for...inThe structure allows multiple statements to be executed repeatedly for each element in the array. It can be used with any of the following parameters:array_element, or used with two parameters:[index, array_element]The second form does not affect the function of the loop. It tracks the index of the current iteration in the first variable of the array.

[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 to the loopreturn_expressionThe value of.index- Tracks the optional variables of the current iterative index. The index starts at zero. The variable is invariant in the loop. When used, it must be contained in a also containedarray_elementIn the elementary group of.array_element- contains a variable for each successive array element to be processed in the loop. This variable is invariant in the loop.array_id- Array ID of the loop iteration.statements | continue | break- Any number of statements, or the keyword "continue" or "break", compressed into 4 spaces or one tab.return_expression- the return value of the loop is assigned tovar_declarationThe variables in the loop, if any. If the loop exits due to the keyword "continue loop" or "break loop", the return value of the loop is the last variable assigned before the loop exits.continue- keyword that can only be used in the loop. It causes the next iteration of the loop to be executed.break- The key word to get out of the loop.

Allows modification of array elements or their size in the loop. Here, we usefor...inThe formula for determining how many OHLCs of each K-line are greater than the SMA of the threshold of the k-close is given by a single parameter:

Examples

// 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 parameters form of for...in to get ourisPosThe value of the array is set totrueAnd when they're in ourvaluesArrayThe corresponding value in the array is:

Examples

// 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 you later for while array.sum array.min array.max

while

whileStatements allow for the condition iteration of local code blocks.

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

Explained:variable_declaration- Optional declaration of variables.return expressionAn initialization value can be provided for this variable.boolean_expression- If true, executewhileThe local block of the statement. If false, then inwhileAfter the sentence, continue to execute the script.continue - continueThe keyword causes the loop to branch to the next iteration.break - breakThe keyword causes the loop to terminate.whileThe sentence is restarted afterwards.return_expression- ProvidedwhileOptional lines for which statements return values.

Examples

// 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)

NotesEarlywhileThe local code block after the line must be compressed into four spaces or a punctuation mark.whileThe circle.whileThe following Boolean expression must eventually become false, or it must be executed.break

switch

The switch operator transfers control to one of several statements based on the value of the condition and 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

It's the same with the switch with the expression:

Examples

// 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)

It's not just the words that make up the name of the game.

Examples

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 valueThe value of the last expression in the executed local statement block.

NotesCan only be executedlocal_blockExample ordefault_local_blockOne of them.default_local_blockOnly with=>Markers are introduced together, and are executed only when the previous block is not executed; ifswitchThe result of the statement is assigned to a variable and is not specifieddefault_local_blockIf not executedlocal_blockThe sentence is returned.naI will.switchWhen the result of the statement is assigned to a variable, alllocal_blockThe instance must return a value of the same type.

See you later if ?:

series

series is a keyword for the data series type.seriesKeywords are usually unnecessary.

The operator

=

Used to assign variables, but only when declaring variables (the first time used).

:=

An assignment operator, assigning a value to the left-hand variable. It is used to assign values to previously declared variables.

!=

It is not equal to..........

expr1 != expr2

Returns the valueA Boolean value, or a set of Boolean values.

%

Modes ((integer residuals) ⇒ are used for numerical expressions ⇒

expr1 % expr2

Returns the valueAn integer or floating-point value, or a series of values.

NotesIn the Pine script, when calculating the remainder of an integer, the dealer will be cut off; that is, its square fours into the lowest absolute value. The resulting value will have the same symbol as the dividend.

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

%=

Modal designation. It is used for numerical expressions.

expr1 %= expr2

Examples

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

Returns the valueAn integer or floating-point value, or a series of values.

*

Multiplication. It is used for numerical expressions.

expr1 * expr2

Returns the valueAn integer or floating-point value, or a series of values.

*=

Multiplication assignment. It is used for numerical expressions.

expr1 *= expr2

Examples

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

Returns the valueAn integer or floating-point value, or a series of values.

+

Adding or uniting digits. Use for numeric expressions or strings.

expr1 + expr2
+ expr

Returns the valueString binary+Returns the sum of express1 and express2 A digit returns an integer or floating point value, or a series of values: The binomial r +'returns express1 plus express2. One-way + one-way returns express (adding nothing to the one-way operator symmetry).

NotesYou can use arithmetic operators with numbers as well as arrays of variables. In the case of arrays, the operator applies to elements.

+=

Additive notation. Useful for numerical expressions or strings.

expr1 += expr2

Examples

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

Returns the valueFor strings, returns a string of expres1 and expres2; for numbers, returns an integer or floating point value, or a series of values.

NotesYou can use arithmetic operators with numbers as well as arrays of variables. In the case of arrays, the operator applies to elements.

-

Subtraction law or unit negative number.

expr1 - expr2
- expr

Returns the valueReturns an integer or floating point value, or a series of values: The binomial r +'returns express1 minus express2. One dollar-Returns the negation of expr.

NotesYou can use arithmetic operators with numbers as well as arrays of variables. In the case of arrays, the operator applies to elements.

-=

Subtraction assignment ⇒ Useful for numerical expressions.

expr1 -= expr2

Examples

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

Returns the valueAn integer or floating-point value, or a series of values.

/

Except for the fact that it applies to numerical expressions.

expr1 / expr2

Returns the valueAn integer or floating-point value, or a series of values.

/=

Except assignment. It is used for numerical expressions.

expr1 /= expr2

Examples

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

Returns the valueAn integer or floating-point value, or a series of values.

<

Less than. Applies to numerical expressions.

expr1 < expr2

Returns the valueA Boolean value, or a set of Boolean values.

<=

Less than or equal to. Applies to numerical expressions.

expr1 <= expr2

Returns the valueA Boolean value, or a set of Boolean values.

==

Equivalent to ▽ applicable to any type of expression.

expr1 == expr2

Returns the valueA Boolean value, or a set of Boolean values.

=>

The '=>' operator is used for user-defined function declarations andswitchI'm not sure what you mean by that.

The syntax of the function declaration is:

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

One<local_block>It's zero or more Pine sentences.<function_result>A variable, an expression, or an elementary group.

Examples

// 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))

NotesYou can learn more about user-defined functions on the declaration and script library pages of the user manual.

>

Greater than. Applies to numerical expressions.

expr1 > expr2

Returns the valueA Boolean value, or a set of Boolean values.

>=

greater than or equal to ≠ ≠ ≠ ≠ ≠ ≠

expr1 >= expr2

Returns the valueA Boolean value, or a set of Boolean values.

?:

The triangular conditional operator.

expr1 ? expr2 : expr3

Examples

// 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 the valueIf express1 is evaluated as true, then express2 is evaluated as true, otherwise it is considered to be express3。 The zero value ((0 and NaN+, Infinity,-Infinity) is considered false, all other values are true。

NotesIf you don't need it, use na as a branch of the else. You can combine using two or more?: operators to implement statements similar to a switch button (see example above). You can use numeric arithmetic operators as well as arrays of variables. In the case of arrays, the operator applies to elements.

See you later na

[]

Series subtitles ─ providing access to previous values of the series express1 ─ expr2 is the number of lines past k and must be a value ─ floating will be omitted ─

expr1[expr2]

Examples

// [] 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 the valueA series of values.

See you later math.floor

and

Logical AND↑ is used for Boolean expressions↑

expr1 and expr2

Returns the valueA Boolean value, or a set of Boolean values.

or

Logical OR↑ is used for Boolean expressions↑

expr1 or expr2

Returns the valueA Boolean value, or a set of Boolean values.

not

The logical inverse ((NOT) ⇒ applies to Boolean expressions.

not expr1

Returns the valueA Boolean value, or a set of Boolean values.

Keyword for data type

bool

A keyword of the type "Bool" for explicitly declared variables or arguments. The value of the variable "Bool" can be true, false or na.

Examples

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

NotesIt is optional to explicitly mention a type in the variable declaration unless it is initialized with na. Learn more about the type type in the user manual page of the type system.

See you later var varip int float color string true false

int

Keyword of type int ((integer)) used to explicitly declare variables or parameters.

Examples

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

NotesIt is optional to explicitly mention a type in the variable declaration unless it is initialized with na. Learn more about the type type in the user manual page of the type system.

See you later var varip float bool color string

float

Keyword of type float float (floating point) used to explicitly declare variables or parameters.

Examples

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

NotesIt is optional to explicitly mention the type in the variable declaration, unless it is initialized with na.

See you later var varip int bool color string

string

A keyword of the "string" type used to explicitly declare a variable or parameter.

Examples

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

NotesIt is optional to explicitly mention a type in the variable declaration unless it is initialized with na. Learn more about the type type in the user manual page of the type system.

See you later var varip int float bool str.tostring str.format

color

Keyword for the type "color" used to explicitly declare variables or parameters.

Examples

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

NotesThe color character has the following format: #RRGGBB or #RRGGBBAA. The letter represents a sixteenth digit value from 00 to FF (0 to 255 in the decimal system), where RR, GG and BB are the values of the red, green and blue components of the color. AA is an optional value for color transparency (or alpha component), where 00 is invisible and FF is opaque. It is optional to explicitly mention a type in the variable declaration unless it is initialized with na. Learn more about the type type in the user manual page of the type system.

See you later var varip int float string color.rgb color.new

array

The keyword for the type of array array array that is explicitly declared as a variable or parameter.array.new<type>,array.fromThe function creates array objects (or IDs).

Examples

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

NotesArray objects are always in the form of arrays in a hierarchical array.

See you later var array.new array.from

Objects

Objects in the PINE language are instances of a user-defined type (UDT), which can be understood as a methodless class that allows users to create custom types in a policy that organizes different values in an entity.

Definition of type

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

type order
    float price
    float amount
    string symbol
  • UsetypeKeyword declaration type.
  • Type is followed by type name.
  • After the first line type defines the type name, narrow down to four spaces to define the fields that the type contains.
  • Each field needs to declare its data type, e.g. int, float, string.

Create objects

Use the declared type, callnew()The function creates objects:

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

Here is a real 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)   // 输出 {"data":{"price":46002.8,"amount":1,"symbol":"swap"},"_meta":0,"_type":"order"}

In the example, this sentence:

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

It can also be written in the following form:

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

Object type used for 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 a variable is assigned to an object of a user-defined type using the var keyword declaration, the keyword is automatically applied to all fields of that object. This means that an object declared with the var keyword declaration will maintain its state between each iteration without having to re-initialize its field value in each iteration.

  • The firstBar object is declared using the var keyword, so its fields (index, price, vol) will keep their values in each iteration, starting from the first entry until the end of the last entry.
  • The currentBar object does not use the var keyword declaration, so its field will be re-initialized in each entry, and there will be a new object in each iteration.

By drawing the index fields of the two objects, you can compare the differences between them. firstBar.index will keep the previously set value in each iteration, while currentBar.index will re-initialize the bar_index value of the current entry in each iteration.

Object type used for varip keywords

//@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 use of the varip keyword indicates that the object's field persists throughout the execution of the script, without scrolling back in an unconfirmed column. In the Counter type declaration, the bars field does not use the varip keyword, so it scrolls in every unconfirmed column; whereas the ticks field uses the varip keyword, so it does not scroll in every unconfirmed column. The counter object is declared using the var keyword, so it will persist throughout the script execution. In each iteration, the bars and ticks fields are added together. The bars field scrolls in each unconfirmed column, while the ticks field does not scroll. Finally, by drawing the counter.bars and counter.ticks fields, the differences between them can be compared. The value of the counter.bars will roll back in each unconfirmed column, while the value of the counter.ticks will continue to increase until the script is finished.

Change the field value

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)

if strategy.position_size != 0
    runtime.log(order1)
    order1.price := 999
    order1.amount := 100
    runtime.log(order1)
    runtime.error("stop")

Can be used:=Reassignment operator changes the value of the object field.

The collection of objects

The example declares an empty array that will store objects of the user-defined order type:

type order
    float price
    float amount
    string symbol

arrOrder = array.new<order>()

order1 = order.new(99, 1, "BTC_USDT")
order2 = order.new(100, 2, "ETH_USDT")

array.push(arrOrder, order1)
array.push(arrOrder, order2)

runtime.log(arrOrder)
runtime.error("stop")

Or

type order
    float price
    float amount
    string symbol

var array<order> arrOrder = na
arrOrder := array.new<order>()

order1 = order.new(99, 1, "BTC_USDT")
order2 = order.new(100, 2, "ETH_USDT")

array.push(arrOrder, order1)
array.push(arrOrder, order2)

runtime.log(arrOrder)
runtime.error("stop")

Replicated objects

In Pine, objects are assigned by reference. When an existing object is assigned to a new variable, they both point to the same object.

//@version=5
indicator("")
type pivotPoint
    int x
    float y
pivot1 = pivotPoint.new()
pivot1.x := 1000
pivot2 = pivot1
pivot2.x := 2000
// Both plot the value 2000.
plot(pivot1.x)
plot(pivot2.x)

In the example below, we create a pivot1 object and set its x-field to 1000. Then we declare a pivot2 contains a variable that refers to that pivot1 object, so they both point to the same instance. So changing pivot2.x also changes pivot1.x, because they both refer to the x-field of the same object.

To create a copy independent of the original object, in this case we can use the built-in copy() method. In this example, we declare pivot2 to refer to a variable of the replica instance of pivot1 object. Now, changing pivot2.x does not change pivot1.x, because it refers to a field of x as a separate object:

//@version=5
indicator("")
type pivotPoint
    int x
    float y
pivot1 = pivotPoint.new()
pivot1.x := 1000
pivot2 = pivotPoint.copy(pivot1)
pivot2.x := 2000
// Plots 1000 and 2000.
plot(pivot1.x)
plot(pivot2.x)

It is important to note that the copy method in TradingView is shorthand. If an object has fields of a special type (array, etc.), the fields in the shorthand copy of that object will point to the same instance as that object. The FMZ platform implements deep copying directly without any additional processing, as can be seen in the following examples:

Deep copying

//@version=5

indicator("test deepCopy")

type orderInfo
    float price
    float amount

type labelInfo
    orderInfo order
    string labelMsg

labelInfo1 = labelInfo.new(orderInfo.new(100, 0.1), "test labelInfo1")
labelInfo2 = labelInfo.copy(labelInfo1)

labelInfo1.labelMsg := "labelInfo1->2"    // 修改 labelInfo1 的基础类型字段,看是否影响 labelInfo2
labelInfo1.order.price := 999             // 修改 labelInfo1 的复合类型字段,看是否影响 labelInfo2

runtime.log(labelInfo1)
runtime.log(labelInfo2)
runtime.error("stop")

Test results, labelInfo.copy ((labelInfo1) is executed as a deep copy, modifying any field in labelInfo1 does not affect labelInfo2。

Methods

Methods in the Pine language are specialized functions associated with the built-in or user-defined type of a particular instance. In most respects, they are essentially the same as regular functions, but provide shorter, more convenient syntax. Users can directly access methods on variables using dot symbols, just as they would access fields on a Pine object.

Built-in methods

For example, a script code like this:

//@version=5
indicator("Custom Sample BB", overlay = true)

float sourceInput  = input.source(close, "Source")
int   samplesInput = input.int(20, "Samples")
int   n            = input.int(10, "Bars")
float multiplier   = input.float(2.0, "StdDev")

var array<float> sourceArray = array.new<float>(samplesInput)
var float        sampleMean  = na
var float        sampleDev   = na

// Identify if `n` bars have passed.
if bar_index % n == 0
    // Update the queue.
    array.push(sourceArray, sourceInput)
    array.shift(sourceArray)
    // Update the mean and standard deviaiton values.
    sampleMean := array.avg(sourceArray)
    sampleDev  := array.stdev(sourceArray) * multiplier

// Calculate bands.
float highBand = sampleMean + sampleDev
float lowBand  = sampleMean - sampleDev

plot(sampleMean, "Basis", color.orange)
plot(highBand, "Upper", color.lime)
plot(lowBand, "Lower", color.red)

The equivalent can be written as:

//@version=5
indicator("Custom Sample BB", overlay = true)

float sourceInput  = input.source(close, "Source")
int   samplesInput = input.int(20, "Samples")
int   n            = input.int(10, "Bars")
float multiplier   = input.float(2.0, "StdDev")

var array<float> sourceArray = array.new<float>(samplesInput)
var float        sampleMean  = na
var float        sampleDev   = na

// Identify if `n` bars have passed.
if bar_index % n == 0
    // Update the queue.
    sourceArray.push(sourceInput)
    sourceArray.shift()
    // Update the mean and standard deviaiton values.
    sampleMean := sourceArray.avg()
    sampleDev  := sourceArray.stdev() * multiplier

// Calculate band values.
float highBand = sampleMean + sampleDev
float lowBand  = sampleMean - sampleDev

plot(sampleMean, "Basis", color.orange)
plot(highBand, "Upper", color.lime)
plot(lowBand, "Lower", color.red)

You can see that PINE supportsMethodsAfter that, code.array.avg(sourceArray)The user can write the following in the form of methods:sourceArray.avg()I'm not sure. Please note FMZ is currently not supported.array.avgI'm not going to say anything about it.

User-defined methods

Pine allows a user to define a custom method to be used with any built-in or user-defined type object. The definition method is essentially the same as the definition function, but with two key differences:

The method keyword must be included before the function name. 2, the parameter of the method, where the type of the first parameter must be explicitly declared, as it indicates the type of the object to which the method will be associated.

For example, using the following code to wrap the code for calculating the Brin indicator as a user-defined method:

//@version=5
indicator("Custom Sample BB", overlay = true)

float sourceInput  = input.source(close, "Source")
int   samplesInput = input.int(20, "Samples")
int   n            = input.int(10, "Bars")
float multiplier   = input.float(2.0, "StdDev")

var array<float> sourceArray = array.new<float>(samplesInput)
var float        sampleMean  = na
var float        sampleDev   = na

// Identify if `n` bars have passed.
if bar_index % n == 0
    // Update the queue.
    sourceArray.push(sourceInput)
    sourceArray.shift()
    // Update the mean and standard deviaiton values.
    sampleMean := sourceArray.avg()
    sampleDev  := sourceArray.stdev() * multiplier

// Calculate band values.
float highBand = sampleMean + sampleDev
float lowBand  = sampleMean - sampleDev

plot(sampleMean, "Basis", color.orange)
plot(highBand, "Upper", color.lime)
plot(lowBand, "Lower", color.red)

Changed to:

//@version=5
indicator("Custom Sample BB", overlay = true)

float sourceInput  = input.source(close, "Source")
int   samplesInput = input.int(20, "Samples")
int   n            = input.int(10, "Bars")
float multiplier   = input.float(2.0, "StdDev")

var array<float> sour

More

wuhuoyanHow do you do it if you want to have multiple transactions running simultaneously?

Light cloudsPlease tell me, can pine do more transactions? Can it also go through transactions like JS? Thank you.

lisa20231Thank you for providing detailed documentation.

artistryWow! How does this pine script use the okex simulation on the platform?

artistryThis is equivalent to copying the tradingview platform's strategy directly to the inventor platform and using it!

Inventors quantify - small dreamsThe PINE language can only do single-variety strategies, multi-variety strategies are best written in python, javascript, c++.

Inventors quantify - small dreamsOh, yes, OKX is special, their analog environment and the real disk environment have the same address, only the difference is made elsewhere.

Light cloudsI can't use the okx analogue disc.

Inventors quantify - small dreamsThis multi-variety architecture problem cannot be solved, because each exchange has a different interface, and the frequency limitation of the interface is not the same, which causes many problems.

Inventors quantify - small dreamsWell, thank you for the suggestion, please report this request here.

Light cloudsIt feels better to be able to mix with JS and JS can be better adapted to different trading methods.

The trend hunterIn the future, will we consider more varieties?

Inventors quantify - small dreamsI'm not being polite.

Light cloudsGood, thank you very much.

Inventors quantify - small dreamsHello, the PINE language policy is currently only for single varieties.

Inventors quantify - small dreamsThank you for your support. The documentation will continue to be improved.

Inventors quantify - small dreamsYes, I did.

Inventors quantify - small dreamsPINE template library, where parameters can be set to switch exchange base addresses.