ScriptingLanguageUser-defined functions

User-Defined Functions

Introduction

User-defined functions are those that you create in Lipi Script, unlike the built-in functions. They are useful when you need to perform calculations repeatedly or if you want to keep certain operations separate from your script’s main calculations. Think of user-defined functions as a way to expand Lipi Script capabilities when a built-in function doesn’t quite fit your needs.

You can define functions in two ways:

  1. In a single line for simple functions
  2. On multiple lines for more complex operations

Functions can be placed in two locations:

  • Within a script: If a function is only used in a single script, include it within that script. See the Style Guide for recommendations on function placement within scripts.
  • In a Lipi Script library: This allows functions to be reusable across different scripts without needing to copy the code. Note that libraries have unique requirements, explained further on the Libraries page.

Whether a function is single- or multi-line, it has these characteristics:

  • No embedding: Functions are always defined in the global scope of the script.
  • No recursion support: Functions cannot call themselves within their own code.
  • Return type is inferred: The type of the returned value is automatically determined based on the argument types in each call.
  • Return value from the last line: The last line’s value in a function’s body is the return value.
  • Independent history: Each function call instance in a script maintains its own history independently.

Single-Line Functions

Simple functions can often be written in a single line. Here’s the formal definition of single-line functions:

<function_declaration>
    <identifier>(<parameter_list>) => <return_value>
 
<parameter_list>
    {<parameter_definition>{, <parameter_definition>}}
 
<parameter_definition>
    [<identifier> = <default_value>]
 
<return_value>
    <statement> | <expression> | <tuple>

Here is an example:

f(int x, int y) {
return x + y
} 

After the function f() has been declared, you can call it using different types of arguments:

a = f(open, close)
b = f(2, 2)
c = f(open, 2)

In the example above:

  • The type of variable a is series because both arguments are of type series.
  • The type of variable b is integer because both arguments are literal integers.
  • The type of variable c is series since adding a series and a literal integer results in a series.

Multi-line Functions

Lipi Script also supports multi-line functions, which follow this syntax:

<identifier>(<parameter_list>) =>
    <local_block>
 
<identifier>(<list of parameters>) =>
    <variable declaration>
    ...
    <variable declaration or expression>

where:

<parameter_list>
    {<parameter_definition>{, <parameter_definition>}}
 
<parameter_definition>
    [<identifier> = <default_value>]

The body of a multi-line function consists of multiple statements, with each statement placed on a new line. Each statement must be preceded by a single indentation (either 4 spaces or 1 tab). This indentation signifies that the statement is part of the function’s body and not part of the global scope of the script. The first statement without indentation following the function’s code indicates the end of the function’s body.

The last statement in the function’s body should either be an expression or a declared variable. The result of this expression (or variable) will be the outcome of the function call. For example:

geom_average(x, y) {
    a = x*x
    b = y*y
   return  math.sqrt(a + b)
}

The function geom_average takes two arguments and creates two variables within its body: a and b. The final statement invokes the function math.sqrt, which calculates the square root. The call to geom_average will return the result of the last expression: math.sqrt(a + b).

Scopes in the Script

Variables that are declared outside the body of a function or any local blocks belong to the global scope. This includes user-defined and built-in functions, as well as built-in variables.

Each function possesses its own local scope. All variables declared within the function, along with the function’s arguments, are confined to that function’s scope. As a result, these variables cannot be accessed from outside the function, such as from the global scope or another function’s local scope.

However, it is possible to reference any variable or function declared in the global scope from within a function’s scope (with the exception of self-referencing recursive calls). This means that the local scope is essentially embedded within the global scope.

In Lipi Script, nested functions are not permitted; you cannot declare one function inside another. All user-defined functions must be declared in the global scope, and local scopes cannot overlap with one another.

Functions That Return Multiple Results

In most cases, a function returns only a single result. However, it is possible for a function to return multiple results in the form of a list, resembling a tuple-like result:

fun(x, y) {
    a = x+y
    b = x-y
return [a, b]
}

Special syntax is required for calling such functions:

[res0, res1] = fun(open, close)
plot(res0)
plot(res1)

Limitations

User-defined functions can utilize any of the Lipi Script built-ins, with the exception of the following functions: barcolor(), fill(), hline(), indicator(), plot(), plotbar(), plotcandle(), plotchar(), plotshape().