Writing Our Own Indicator

Implementing SMA in QuantScript

Let's create our own QuantScript implementation of a Simple Moving Average.

QuantScript includes a built-in implementation of SMA, and many other indicators. However, for the purposes of this guide, we are going to write one ourselves.

A Simple Moving Average represents the average of some value, e.g.

open
, for the last x bars (usually 14).

Let's use everything we have learned so far. We begin by creating two variables -

applyTo
and
period
. We will refer to these variables, instead of writing
open
and
14
directly - this way, we could easily change our value/period later, should we decide to do so.

1 applyTo = open
2 period = 14

Next, we need to calculate the sum of the last 14

open
prices. We'll use a for loop:

1 applyTo = open
2 period = 14
3
4 sum = 0
5
6 for distance from 0 to (period - 1)
7 sum = sum + applyTo[distance]

Two things need explaining here:

  • What happens when the distance is 0?
    We're accessing
    applyTo[0]
    , which is equivalent to
    open[0]
    . We are instructing the
    []
    time-travel operator to go back
    0
    bars, so it stays in place - this is equivalent to just
    open
    .
  • The distance ends at
    period - 1
    . Why?
    We don't want to add
    applyTo[14]
    to the sum, because that would make
    sum
    the sum of the last 15 open prices, instead of the last 14. Remember, we start from 0.

All that's left is to divide our sum by the period. Here's what our SMA looks like:

1 applyTo = open
2 period = 14
3
4 sum = 0
5
6 for distance from 0 to (period - 1)
7 sum = sum + applyTo[distance]
8
9 sma = sum / period

Done! Now, let's write some entry/exit rules that use our SMA.

Creating a strategy based on SMA

Let's enter a long position whenever our SMA has increased and exit that position whenever it has decreased, compared to the previous bar.

We can use the

[]
time travel operator even on a complex variable such as our
sma
:

1 applyTo = open
2 period = 14
3
4 sum = 0
5
6 for distance from 0 to (period - 1)
7 sum = sum + applyTo[distance]
8
9 sma = sum / period
10
11 enter long when sma > sma[1]
12 exit long when sma < sma[1]

Here,

sma
is equal to
open + open[1] + open[2] + open[3] + ... + open[13]

and
sma[1]
is equal to
open[1] + open[2] + open[3] + open[4] + ... + open[14]
.

Let's make our strategy more robust by adding a second SMA. This time we'll calculate it over the

close
price and with a period of 26 bars.

Creating a strategy based on two SMAs

Creating a close-based 26-period SMA is easy - we just change the

applyTo
variable to
close
and the
period
variable to 26.

However, we want to have the two SMAs simultaneously. To do that, we need to first compute our 14-period SMA, which we'll save in a variable called

sma14
. Then, we need to change
applyTo
and
period
, and copy-paste our
sum
, for loop and division:

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]

This works, but once again we have a problem with code duplication.

Next, we'll look at how functions can help us solve this problem.