Functions

Let's look at our double-SMA strategy again:

1 # SMA-14 starts here
2 applyTo = open
3 period = 14
4
5 sum = 0
6
7 for distance from 0 to (period - 1)
8 sum = sum + applyTo[distance]
9
10 sma14 = sum / period
11
12 # SMA-26 starts here
13 applyTo = close
14 period = 26
15
16 sum = 0 # We make sure to reset our sum
17
18 for distance from 0 to (period - 1)
19 sum = sum + applyTo[distance]
20
21 sma26 = sum / period
22
23 # Check that both SMAs have risen
24 enter long when sma14 > sma14[1] and sma26 > sma26[1]
25 # Check that both SMAs have fallen
26 exit long when sma14 < sma14[1] and sma26 < sma26[1]

Lines 5-10 and 16-21 are practically indentical. They work differently though, because they're using the variables

applyTo
and
period
, which have different values on line 5 and on line 16.

Two things would help here:

  • A way to mark a part of our code as reusable; name it, so that we could refer to it; and, optionally, declare a list of variables (called parameters), values for which must be provided in order for the code to work. That's what a function is.
  • A way to execute that code and provide values for its parameters, if any. That's what a function call is.

Essentially, functions are a way to write code once and execute it many times, customising each execution according to our needs.

Let's rework our strategy, using a function:

1 function SMA(applyTo, period):
2 sum = 0
3 for distance from 0 to (period - 1)
4 sum = sum + applyTo[distance]
5 sum / period
6
7 sma14 = SMA(applyTo: open, period: 14)
8 sma26 = SMA(applyTo: close, period: 26)
9
10 enter long when sma14 > sma14[1] and sma26 > sma26[1]
11 exit long when sma14 < sma14[1] and sma26 < sma26[1]

Let's analyse what's happening here:

Lines 1-5 comprise the function definition.
Taking a closer look at line 1, we see the keyword

function
, followed by
SMA(applyTo, period)
- the function name and a list of parameter names, enclosed in
()
parentheses. The line ends with a
:
colon.

Lines 2-5 make up the function's body.
This code is not executed yet, only saved for future use. Notice how the body is indented by 2 spaces - this marks it as part of the function. Any variable created in the function body is not accessible outside of it .

Lines 7 and 8 are function calls. A function call begins with the name of the function and an open parenthesis:

SMA(
. Then, values are passed for each of the function's parameters. Each value is preceded by the parameter's name, and a colon, like this:
applyTo: open
. We top things off with a
)
closing parenthesis.

However, in addition to the function call, we also have assignments on lines 7 and 8 - how does that work?

Whenever you call a function, that function's body is executed, and a value is returned. That value is whatever the function body's last line evaluates to. In the case of our function, the last line is line 5, so we get the average as the resulting value. Then, we assign that value to

sma14
on line 7 and
sma26
on line 8.

In essence, on lines 7 and 8, we're telling QuantScript, "Hey, go execute that code for me. Give it these values to work with. Then, assign whatever it returns, to this variable".

Let's remove even more code duplication by creating two functions which return whether some value has risen or fallen, compared to the previous bar.

Here are the functions:

1 function Rises(value):
2 value > value[1]
3
4 function Falls(value):
5 value < value[1]

Now let's use them in our strategy's signal condition statements:

1 function Rises(value):
2 value > value[1]
3
4 function Falls(value):
5 value < value[1]
6
7 function SMA(applyTo, period):
8 sum = 0
9 for distance from 0 to (period - 1)
10 sum = sum + applyTo[distance]
11 sum / period
12
13 sma14 = SMA(applyTo: open, period: 14)
14 sma26 = SMA(applyTo: close, period: 26)
15
16 enter long when Rises(sma14) and Rises(sma26)
17 exit long when Falls(sma14) and Falls(sma26)

Did you notice? When we called

Rises(sma14)
, we did not specify the parameter name, only the value. This is perfectly okay in QuantScript - it's up to you whether you want to specify the name or not. However, if you don't, you have to make sure to pass in the values in the exact order in which the function expects them to be.

That about wraps up how functions work in QuantScript. I hope you agree that our code is much more readable now.

Next, let's implement a function which returns the larger of two numbers.