The Series Function is very special
When a function accesses a previously stored value of one of its own variables, it essentially becomes a “series” function. Few programming languages offer this convenience out of the box. The ability to automatically remember a function’s internal state from one bar (or time step) to the next is known as state retention. In languages like Python, achieving this typically requires using a class structure. In Module #2 of my Easing into EasyLanguage Academy, I explained why EasyLanguage isn’t as simple as its name implies—yet this feature shows how its developers aimed to simplify otherwise complex tasks.
If you’ve ever worked with functions with memory that exchange data using a numericRef input, you’ve essentially been using a pseudo-class—a form of object-oriented programming in its own right. EasyLanguage includes a robust object-oriented library (with excellent resources by Sunny Harris and Sam Tennis – buy their book on Amazon), yet you’re confined to its built-in functionality since it doesn’t yet support user-defined class structures. Nonetheless, the series functionality combined with data passing brings you remarkably close to a true object-oriented approach—and the best part is, you might not even realize it.
Example of a Series Function
I was recently working on the Trend Strength indicator/function and have been mulling this post over for some time, so I thought this would be a good time to write about it. The following indicator to function conversion will create a function of type series (a function with a memory.) The name series is very appropriate in that this type of function runs along with the time series of the chart. It must do this so it can reference prior bar values.
You can ensure a function is treated as a series function in two ways:
-
Using a Prior Value:
When you reference a previous value within the function, EasyLanguage automatically recognizes the need to remember past data and treats the function as a series function. -
Setting the Series Property:
Alternatively, you can explicitly set the function’s property to “series” via a dialog. This instructs EasyLanguage to handle the function as a series function, ensuring that state is maintained across bars.
Importantly, regardless of the function’s name or even if it’s called within control structures (like an if
construct), a series function is evaluated on every bar. This guarantees that the historical data is consistently updated and maintained, which is essential for accurate time series analysis.
Converting an indicator to a function
You can find a wide variety of EasyLanguage indicators online, though many are available solely as indicators. This is fine if you’re only interested in plotting the values. However, if you want to incorporate an indicator into a trading strategy, you’ll need to convert it into a function. For calculation-intensive indicators, it’s best to follow a standard prototype: use inputs for interfacing, perform calculations via function calls, and apply the appropriate plotting mechanisms. By adhering to this development protocol, your indicator functions can be reused across different analysis studies, enhancing encapsulation and modularity. Fortunately, converting an indicator’s calculations into a function is a relatively straightforward process. Here is indicator that I found somewhere.
Now we can functionize it.
Below is an example of how you might convert an indicator into a function called TrendStrengthIndex. Notice that the first change is to replace any hard-coded numbers in the indicator’s inputs with parameters declared as numericSimple (or numericSeries where appropriate). This allows the function to accept dynamic values when called. Not to give anything away, but you can also declare variables as numericRef, numericSeries, numericArrayRef, string, stringRef, and stringArrayRef. Let’s not worry about these types right now.
Below is an example function conversion for the TrendStrengthIndex indicator. The plot statements have been commented out since—rather than plotting—the function now passes back the calculated value to the calling program.
This works great if we just want the TrendStrengthIndex, but this indicator, like many others has a signal line. The signal line for such indicators is usually a smoothed version of the main calculation. Now you could do this smoothing outside the function, but wouldn’t it be easier if we did everything inside of the function?
Oh no! I need to pass more than one value back!
If we just wanted to pass back TSIValue all we need to do is assign the name of the function to this value.
Passing values by reference
We can adjust the function to return multiple values by defining some of the inputs as numericRef. Essentially, when you pass a variable as a numericRef, you’re actually handing over its memory address—okay, let’s get nerdy for a moment! This means that when the function updates the value at that address, the calling routine immediately sees the change, giving the variable a kind of quasi-global behavior. Without numericRef, any modifications made inside the function stay local and never propagate back to the caller. Not only is the function communicating with the calling strategy or indicator it is also remember its own stuff for future use. Take a look at this code.
There is a lot going on here. Since we are storing our calculations in the two numericRef inputs, TrendStrength.index and TrendStrength.signal the function name can simply be assigned the number 1. You only need to do this because the function needs to be assigned something, or you will get a syntax error. Since we are talking objects, I think it would be appropriate to introduce “dot notation.” When programming with objects you access the class members and methods buy using a dot. If you have an exponential moving average class in python you would access the variables and functions (methods) in the class like this.
Since you are using EasyLanguage and a series function, you don’t have to deal with something like this. On the surface this looks a little gross but coming from a programming background this is quite eloquent. I only show this to demonstrate dot notation. In an attempt to mimic dot notation in the EasyLanguage function, I simply add a period ” , ” to the input variable names that will return the numbers we need to plot. Take a look at the nomenclature I am using.
I am using the function name a ” . ” and an appropriate variable name. This is not necessary. Historically, input names that were modified within a function were preceded by the letter “O.” In this example, Oindex and Osignal. This represented “output.” Remember these naming conventions are all up to you. Here is the new indicator using our EasyLanguage “Classy” function and our pseudo dot notation nomenclature.
You might be surprised to learn that you may have been doing object-oriented programming all along without realizing it. Do you prefer the clarity of dot notation for accessing function output, or would you rather stick with a notation that uses a big “O” combined with the input name to represent functions with multiple outputs? Also, notice how each function call behaves like a new instance—the internal values remain discrete, meaning that each call remembers its own state independently. In other words, each function call remembers its own stuff.
