Guide to Developing EFS Indicators

ICE Data Services -

Guide to Developing eSignal Indicators


Developing indicators within eSignal is one of the first steps to developing your own custom trading system. eSignal indicators are designed to plot and return values to the chart as well as the cursor window. Indicators can return information to the price chart or a new indicator pane (a new window) but not both at the same time.


There are relatively few tricks to creating custom indicators within eSignal. This guide will
walk you through the basics and even teach you some more advanced topics.  

Indicator Basics

All eSignal EFS files step through the chart (from oldest bar to newest bar  or left to right)and executes your code. The code (or eSignal Formula Script EFS) is a set of instructions that are executed in order (top to bottom).


Within the EFS code, developers control variables, conditions and execute any functions necessary with a series of simple commands. The structure of these commands and of the order of the commands is critical to the accuracy and execution of your proposed systems.


Let's begin by learning some of the EFS components


Components of the eSignal EFS File.



preMain() is a required function of all EFS files. It acts as a Setup routine for your code. Within preMain(), you should include the necessary code to accomplish the following for your custom indicator.


Set The Study Title:


 setStudyTitle("Your Indicator Title"); 


You should include the setStudyTitle in all of your EFS files. This statement plots the title text onto the chart or indicator pane. If you don't want any text to be displayed, simply comment out this line by placing //at the beginning of the statement.  

Set The Cursor Window Title:


 setCursorLabelName("Indicator Value 1"); 


You will also need to define the label for the returned value of your indicator. If your indicator returns more than one value, you will need to add multiple setCursorLabelName statements in your preMain(). For each value your indicator returns, you will need to add a definition to the setCursorLabelName statement ('0' for the first, '1' for the second and so on) An example is below.  

 setCursorLabelName("Value1", 0); 
setCursorLabelName("Value2", 1);


The two statements above define Cursor Window Labels for two values that are returned by our EFS file. So, when your EFS indicator returns the values, the first value will be displayed in Value1 and the second in Value2. If our indicator only returns one value, then the second line (or any other label definition) is ignored.


Set The Label/Indicator Color:  



An optional statement, setDefaultBarFgColor, allows developers to control the color of the indicator and the color of the label in the cursor window. This statement is optional, so it does not need to be included within your code, but it often helps to color code the returned values of the indicator.


Just like with the setCursorLabelName statement, the setDefaultBarFgColor statement should be defined for any returned label name statements. Thus, if you have two setCursorLabelName statements in your code, you should have two setDefaultBarFgColor statements as well.


Available color types are:  

  • Color.yellow
  • Color. ...  

Multiple color statements are also defined by adding the corresponding label order number to the end of the statement just like with the setCursorLabelName statement. An example is below:  

 setDefaultBarFgColor(, 0); 
setDefaultBarFgColor(, 1);  


Set The Indicator Min/Max values:  



The setStudyMin and setStudyMax statements allow you to define the absolute minimum and maximum levels of your custom indicator. If you do not know what the minimum and maximum values of your indicator are, then simply omit these statements from your preMain(). eSignal will automatically scale your indicator within the maximum and minimum range of your indicator.


To use the setStudyMin and setStudyMax statements, simply add the statements to the preMain() function and declare the values for the MINIMUM and MAXIMUM of your custom indicator.


Using the addBand function:  

 addBand(30, PS_SOLID, 1, Color.RGB(0,0,0)); 
addBand(70, PS_SOLID, 1, Color.RGB(0,0,0));


The addBand function allows developers to place horizontal bands on the indicator pane. For example, if you were to develop an indicator that ranged from zero to one hundred in value, you might want to place bands at 20 and 80  as extreme boundaries.


Adding bands is as simple as adding a new statement for each band you wish to include in your indicator.
When placing an addBand statement into your preMain() function, remember to change the first variable to the value you want the band to appear at in the indicator pane.


 addBand(Band Level, Line Type, Line Width, Color);


In this instance, we would want to add two band statements (at our 20 and 80 levels) and probably start out with them both in black. The code would look as follows  

 addBand(20, PS_SOLID, 1, Color.RGB(0,0,0)); 
addBand(80, PS_SOLID, 1, Color.RGB(0,0,0));


Notice: Color.RGB(0,0,0) is just another way of saying With all color statements, developers can replace the default color definitions with user-defined color codes by using the Color.RGB(Red, Green, Blue) option. With this optional color definition, developers are required to use individual color values that represent the colors for Red, Green and Blue. Different combinations can produce a wide variety of color hues.


Using setPriceStudy:  



The use of setPriceStudy() determines if your indicator will plot ON the price chart or within the indicator pane.  If your indicator is designed to plot on the price chart, then developers MUST include setPriceStudy(true) in the preMain() function. If your indicator is designed to plot in an indicator pane, then developers MUST omit the setPriceStudy() statement from the preMain() function.




main() is a required function of all EFS files.This function is the main routine for your code. Developers will write code within the main() function to calculate and execute the indicator/strategy/graphics or other actions. Within main(), you should include the necessary code to accomplish whatever tasks are necessary to calculate and plot your custom indicator.


Notice: Additional sub-functions are available to the developers to better define code segments and to develop modular application.


Returning the Indicator values:  

 Return (Value); 
return new Array (Value1, Value2,...);

Your custom indicators MUST return at least one value  otherwise, the indicator will not plot on the chart or indicator pane. The return function allows developers to define which values are returned from the main() function to the chart.


To return a single value, developers must include a single return statement at the end of the main() function  

 Return value1; 


To return multiple values from your code, developer must include a single return statement that returns an array of values at the end of their main() function  

 return new Array (value1, value2, value3,...); 


Notice: Any value returned by the Return statement will be plotted on the chart or on the indicator pane. Thus, developers may need to separate individual functions of their indicators into multiple EFS files in order to properly display the information on the chart or indicator pane.

Developing Your First Custom Indicator.


The first step in developing a custom indicator is to attempt to define what type of indicator you are going to try to develop. For this example, well start with a velocity indicator.


Our example of a velocity indicator will attempt to monitor the markets ability to accelerate in bullish and
bearish modes. The first indicator well develop will be designed to only return positive values (numbers greater than or equal to zero).


Let's propose developing our indicator to track the difference between two (user-defined) moving averages. Some of you may consider this not really a velocity indicator, but this is a good place to start for people learning to develop new indicators.


Developing the preMain() Function:


The first process of developing a new indicator is to answer some basic questions


  1. Will our indicator plot on the price chart or on an indicator pane?

Answer: On the Indicator Pane

  1. Do we know the range of the values that will be returned by our indicator?

Answer: No. We have no idea as of yet.


So, now we know what needs to be in the preMain() function. All we need is the study title and the cursor window label name. An example of our preMain() function for our indicator is  

 function preMain() { 


We don't need to add anything else at the moment, because we don't know how our new indicator will react. All we need to do is add labels to our code to assist us in identifying our code.


Developing the main() function:


Developing the main() function is a little more difficult, but it is still rather simple to understand. The first thing we need to do is determine what user-defined variables we need for our function. The variables we're going to define for our indicator are


VLength = the length of our initial short-term Moving Average.

VFactor = the multiplier of vLength to be used to calculate our long-term Moving Average.


Defining a user-input is simple, but we also need to check the input value for an erroneous value or missing value immediately after the main() function starts. So our first main() code might look like.

 function main(vLength, vFactor) { 
if (vLength == null) {
vLength = 7;
if (vFactor == null) {
vFactor = 3;


For every user-input, we need to check for a "null' input, or missing initial value, then define the initial values (if necessary) You can see from the examples (above), that creating the user-input is as simple as adding them between the () of the main() function (separated by commas).For every user-input, you also need to add the code to check and verify the value of the input.


So, at this point, we have begun to create our custom indicator, but it will do nothing yet  we have not
developed the code to calculate, test and return the indicator values. Let's get started.


The process of our proposed velocity indicator is to calculate a short-term moving average based on a user input, then calculate a second moving average based on a factor of the first moving average this also will be a user input. Then, well calculate the difference between the short-term moving average and the long-term moving average.This will give us a relevant indicator for trend direction and strength.  

function main(vLength, vFactor){
	if (vLength == null){
		vLength = 7;
	if (vFactor == null){
		vFactor = 3;
	// create the MA studies for our indicator
	var study1 = new MAStudy(vLength, 0, "Close", MAStudy.WEIGHTED);
	var study2 = new MAStudy(vLength * vFactor, 0, "Close", MAStudy.WEIGHTED);
	  //Get the values of the Moving Average studies
	var vMA1 = study1.getValue(MAStudy.MA);
	var vMA2 = study2.getValue(MAStudy.MA);
	  //Test our variables for null values/returns.
	//If vMA1 or vMA2 = null, then RETURN (nothing)
	// || is a Boolean OR statement
	if ((vMA1 == null) || (vMA2 == null))
	// Return the short-term average the long-term average.
	return (vMA1 - vMA2);


That's it. You've just created your first indicator. It is not as difficult as you might think is it?  

Now, let's get into some more advanced topics, such as  

  • Returning arrays of variables to the cursor window
  • Using price variables
  • Returning text variables to the cursor window
  • Returning price action to the cursor window  

All of these are easily addressed by changing just a few lines of our code. Let's start with How to return an array of variables. First, what is an Array? It is simply a list of variables that you want to return to the cursor window. The only thing a developer needs to do to return an Array of variables is change the RETURN line and address the new variables in the preMain() function. Let's look at an example (below)


function preMain(){
	// Define the returned value labels in the cursor window
	setCursorLabelName("Velocity", 0);
	setCursorLabelName("MA1", 1);
	setCursorLabelName("MA2", 2);
	// Set colors for the returned values in the cursor window
	setDefaultBarFgColor(, 0);
	setDefaultBarFgColor(, 1);
	setDefaultBarFgColor(, 2);
function main(vLength, vFactor){
	if (vLength == null){
		vLength = 7;
	if (vFactor == null){
		vFactor = 3;
	// create the MA studies for our indicator
	var study1 = new MAStudy(vLength, 0, "Close", MAStudy.WEIGHTED);
	var study2 = new MAStudy(vLength * vFactor, 0, "Close", MAStudy.WEIGHTED);
	// Get the values of the Moving Average studies
	var vMA1 = study1.getValue(MAStudy.MA);
	var vMA2 = study2.getValue(MAStudy.MA);
	// Test our variables for null values/returns.
	// If vMA1 or vMA2 = null, then RETURN (nothing)
	// || is a Boolean OR statement
	if ((vMA1 == null) || (vMA2 == null))
	// Return the ARRAY of variables to the cursor window.
	return new Array(vMA1 - vMA2, vMA1, vMA2);


The Difference between Global Variables and Local Variables


As we begin to develop more and more complex indicators and trading systems, it will become important to know the difference between a Local variable and a Global variable and where/why you want to use them. As developers, we want to develop our indicators based on logical progressions or mathematic calculations. Either way, we may need to include some variables that stay active throughout the entire instance of our code and still other variables that are only temporary. This is the primary difference between Global (variables that stay active throughout the entire use of your code) and Local (variables that are created, used and destroyed within a specific function) variables:


The difference in variable life is called Scope. Scope should be understood as the lifetime of your declared variable. Local variables have limited scope only for use within the function they are declared. Global variables have unlimited scope they can be used/modified anywhere within your code.


Global variables.

  • Are declared outside the main() and preMain() functions
  • Are available within any portion of your code
  • Can be manipulated by other functions within your code.
  • Carry previous values to the next instance of your code.  

Local variables.

  • Are declares within the main() or other function
  • Are only available within the function they are declared.
  • Are only available for use AFTER being declared.  

If you are trying to declare a new temporary variable for use within your code, you would want to declare it within your function (above your use of the variable).


If you are trying to declare a new global variable (one that will be used to control global logic within your
code or one that needs to continue through the entire scope of your code), then you would want to declare it above your main() function.


Here is an example of the variable declarations. Notice the global variables are declared outside the main() function.


function preMain() { 
var NewGlobalVariable;
function main() {
var NewLocalVariable;  


Creating Additional Functions To Handle Specific Tasks


As we begin to develop more and more complex indicators and trading systems, it will become necessary to develop unique functions within your code to accomplish specific tasks. The reasons why you would want to create a new function to complete a certain tasks might include.  

  1. Functions simplify your code by creating a single source code (function) that can be called throughout your program.
  2. Functions allow you to segment your code into easily to understand groups of orders and make
    it easier to debug problems.  

Some things you might look for in your code that indicates you should start using functions.


  1. Your code uses the same code segment over and over again (throughout different sections of  your code). These repeat code segment can be simplified into a function.
  2. Similar tasks can be grouped into a single function. Simply by passing your new function a
    parameter, your function can accomplish multiple tasks.
  3. Most graphic calls can be grouped into a single function.
  4. Most trading system logic can be grouped into a single function.

Rules For Creating Additional Functions

  1. New functions should always be created before the preMain() and main() functions  at the top of your EFS file.
  2. New functions should be given a unique name.
  3. Function Parameters should be handled just like User-Inputs checking for null entries

Here is an example of an additional function declared within an EFS file

function rnd(value) {
//<Rounds a price value to two decimal places
value *= 100;
return Math.round(value,2) / 100;
function preMain() {
function main() {
return rnd(close());

Using Price Values in your EFS code.
You're probably asking how do we address price variables in our code (for use with price patterns, indicator patterns and buy/sell signal patterns). Well, here we go Let's learn about how to compare and use price values in an EFS file.


All price variables are easily accessible in any EFS by simply using   

  • open()
  • high()
  • low()
  • close()


These automatic variables return the current bar's price action. Remember, the current bar changes from oldest to newest as the EFS is running through your chart. To access older bar information, developers simply add a numeric parameter to designate how many bars in the past to offset the price variable (-1 = one bar in the past,-3 = three bars in the past).  

  • open(-1) = the open of the previous bar.
  • high(-1) = the high of the previous bar.
  • low(-1) = the low of the previous bar.
  • close(-1) = the close of the previous bar.

  Using this information to create a price pattern is simple. We would create a compound if statement using

Boolean operators (such as && (AND) and || (OR)). The best advice that can offered about complex if statements and Booleans is Always use parenthesis to separate or join your complex conditions.


An example of these types of statements would be


 if (high() == high(-1)) {
// Japanese Candlestick Tweezers Tops
//This pattern occurs when two bars have the same HIGH price.
Do something
if ((high(-2) <high(-1)) &&="&&" (high(-1)="(high(-1)"><high()){> </high()){></high(-1))>
// Pivot High Pattern
//This pattern occurs when a single bar forms with a higher high
//than the previous and subsequent bar.
Do something

if ((low(-2) low (-1)) && (low (-1) low ()){
// Pivot low Pattern
//This pattern occurs when a single bar forms with a lower low
//than the previous and subsequent bar.
Do something


Using debugPrintln to debug your EFS code.


Now that we've shown you how to begin creating your own indicator (which will help lead you to create your own trading system), it might be wise to show you how to debug errors in your code. ESignal provides a couple of tools for you to debug your code and coding logic. There are really three types of errors that you may experience when trying to develop EFS code  

  1. Syntax Errors - Syntax Errors are errors in the coding language  very similar to grammatical errors in a letter or spelling errors. These normally occur when a user mis-spells a function or uses an incorrect function parameter. Other instances where a syntax error may occur is with Case Sensitivity. EFS codeis VERY case sensitive.
  2. Logic Errors - These types of errors are normally user created where the code is instructing
    something to change/happen when it should not. For example, let's say we create code to do something if the price is above a moving average variable (close() vMA). If we make a mistake and reverse the greater than sign or make it greater than or equal to, then our logic is messed up and our code will not operate effectively. The syntax checker within eSignal will not identify these errors, so the user must attempt to identify these problems.
  3. Assignment Errors - These types of errors normally happen in the use of and conditional
    statements including variables. One problem that is common is the mixing of = and == The single
    equal sign (=) is used to assign a variable a value. The double equal sign (==) is used to test the condition of a variable value. Often, developers will mix-up the use of these operators, resulting is
    ineffective code. Also, these errors are not identified as errors of syntax, so it is up to the user to identify/resolve these errors.


ESignal does provide a syntax checker that will check your code for grammatical errors and some spelling errors. Simply click on the Check mark button within the editor and your code will be verified for syntax errors. Any potential problems will be presented in the Output Window To view the output window, simply
click on the TOOLS menu, then click on OUTPUT WINDOW.


ESignal also provides users with the ability to write information into the output window for debug and system reporting abilities. This function is called debugPrintln(). Users can place any information necessary into the debugPrintln statement  variables, text, date/time. Developers should place the debugPrintln statement into portions of the code they believe are not operating properly to assist in debugging the code.




DebugPrintln(Sample text : +close()+ : +variable); 
DebugPrintln(variable1+ : +variable2+ : +variable3);


Example Code : Matheny Enterprises (Velocity Indicator)

Copyright Matheny Enterprises 2002. All rights reserved.


function preMain() {
  setStudyTitle("Ment Velocity");
  setCursorLabelName("Ment Velocity");

function main(vLength, vFactor, vSTDLength) {
  if (vLength == null) {
    vLength = 7;

  if (vFactor == null) {
    vFactor = 3;
  if (vSTDLength == null) {
    vSTDLength = 11;

  // create the MA studies.

  var study1 = new MAStudy(vLength, 0, "Close", MAStudy.WEIGHTED);

  var study2 = new MAStudy(vLength * vFactor, 0, "Close", MAStudy.WEIGHTED);

  //Get the values of the MA studies

  var vMA1 = study1.getValue(MAStudy.MA);

  var vMA2 = study2.getValue(MAStudy.MA);

  //Test for null returns.

  if (vMA1 == null || vMA2 == null) return;
  return vMA1 - vMA2;

Indicator Building Tips.


  • Remember to use the setCursorLabelName() in the preMain()to identify your returned variables.
  • Remember to use the setDefaultBarFgColor() to color each returned value. This helps developer to identify conditions as they change within your indicator.
  • Remember to use the setPriceStudy(true) if your indicator will return/plot values on the price chart and not on a separate indicator pane.
  • Remember to test all user-inputs for null parameters before attempting to execute your EFS code.
  • Remember to create a user input for setComputeOnClose() within your indicator. This allows you to quickly and easily change the indicator to/from real-time mode.
  • Remember to create all indicator logic variables as Global Variables. These variables need to be global as they will be manipulated by your code and control the logic of your indicator as it progresses.
  • Remember to create all indicator temporary variables as Local Variables. These are variables
    that will created, used by your code, then dumped.
  • Remember to create the proper return statement for your indicator  


Coding examples:


Testing for the current bar


 If (getCurrentBarIndex() == 0) { 
// Do something

  Testing for a new bar formation (using the time of the bar)

 //First, declare a global variable to keep track of the last time of the previous bar(s). 
var nLastRawTime;
If (getvalue(rawtime,0) != nLastRawTime) {
//New Bar so do something
nLastRawTime = getvalue(rawtime,0);


Written by Brad L. Matheny for eSignal, A division of Interactive Data Corporation, November 2002.