Although many think that the main focus of EFS2 is the ability to use multiple intervals or symbols that functionality is actually only a part of what constitutes this revision of the formula engine.
A great deal of new functionality has been added to EFS2 that extends its capabilities well beyond multiple intervals or symbols. New functions such as efs() or efsInternal() for example now allow to pass custom variables to builtin studies while the Function Library can be used to create studies and indicators that behave like the builtins. Also creating studies on studies is now a very easy task irrespective of whether one is using builtin or user defined studies.
In this document I will show some relatively basic examples of two of these new functions specifically efs() and efsInternal().
For examples on Library Functions instead you may want to download dsFunctions.efsLib and dsUtilities.efsLib which are available here or amStudies.efsLib which is available here In both cases I would suggest downloading also the corresponding Help files or documentation available at the same links.
efs() and efsInternal() are virtually identical functions the only difference being that efs() calls external studies while efsInternal() calls internal functions. Although similar in concept to call() and callFunction() they are much more powerful in as much as they allow to use the return from either an external efs or an internal function as the input to any builtin study (or study created using the Function Library).
Also when a symbol or interval are passed to the called efs both efs() and efsInternal() control the context in which that efs or function is executed i.e. in what time frame and/or with what symbol that efs or function will run (even if that efs or function is not written using efs2 syntax - more on this later)
Note however that, unlike call() or callFunction(), the efs() and efsInternal() functions will only retrieve values [returned by the called efs or function] that are numbers and not strings.
As a first example let us assume that we want to calculate an exponential moving average of the price range (i.e. High-Low). As we cannot pass a user defined variable to an EFS1 builtin study this means that we would need to write our own exponential moving average.
In EFS1 the required code would be as follows.
In EFS2 instead all we need to do is write a separate function to calculate the range and then create a variable that uses efsInternal() to retrieve the value returned by that function. Since the variable is now treated as a series by the EFS2 engine (rather than being a single value) we can use that variable directly as an input of the builtin study i.e. ema(). Following is the equivalent EFS2 code with comments
Aside from being a lot easier to write the difference in the required code is staggering. This disparity becomes even greater if for example we want to create a double exponential moving average of the range.
In EFS1 the code would be:
It becomes immediately apparent that the formula is exponentially more complex and quite difficult to code for anyone other than a user who is proficient with the language. With EFS2 instead it only takes nesting a second ema() inside the first one as in the following example
Up to this point the functionality of the two scripts is essentially the same i.e. they both execute in the same time frame and using the same symbol plotted in the chart. The only difference - and not a small one - is that the EFS2 version is considerably easier to code than the EFS1 counterpart.
If we now wanted to add to the EFS1 script the ability to compute across multiple intervals we would probably need at least an additional 300 lines of very complex code and even then the formula would likely have some limitations in the functionality. Regardless it would require very advanced programming skills to accomplish this task.
With EFS2 instead all it takes is to pass a Sym/Inv series (see the EFS2 Help files for information on these functions) to the separate function so as to allow the formula engine to take control of that function and to make it execute in the desired symbol or interval context.
Here is the same EFS2 code with the additional functionality to allow running the efs on multiple intervals and/or on a symbol that is different from the one being charted.
As you can see other than the three lines of code required to create the user defined variable we only needed to add the Sym series that is being passed to the external function. A far cry from what would otherwise be required in EFS1 and a task that is within the reach of everyone.
IMPORTANT NOTE: In order for the EFS2 engine to be able to control the context in which an external efs or a separate function execute (in other words in what time frame or with what symbol they will be running) the Sym/Inv series must be the last parameter passed by the efs() or efsInternal() functions
A great deal of new functionality has been added to EFS2 that extends its capabilities well beyond multiple intervals or symbols. New functions such as efs() or efsInternal() for example now allow to pass custom variables to builtin studies while the Function Library can be used to create studies and indicators that behave like the builtins. Also creating studies on studies is now a very easy task irrespective of whether one is using builtin or user defined studies.
In this document I will show some relatively basic examples of two of these new functions specifically efs() and efsInternal().
For examples on Library Functions instead you may want to download dsFunctions.efsLib and dsUtilities.efsLib which are available here or amStudies.efsLib which is available here In both cases I would suggest downloading also the corresponding Help files or documentation available at the same links.
efs() and efsInternal() are virtually identical functions the only difference being that efs() calls external studies while efsInternal() calls internal functions. Although similar in concept to call() and callFunction() they are much more powerful in as much as they allow to use the return from either an external efs or an internal function as the input to any builtin study (or study created using the Function Library).
Also when a symbol or interval are passed to the called efs both efs() and efsInternal() control the context in which that efs or function is executed i.e. in what time frame and/or with what symbol that efs or function will run (even if that efs or function is not written using efs2 syntax - more on this later)
Note however that, unlike call() or callFunction(), the efs() and efsInternal() functions will only retrieve values [returned by the called efs or function] that are numbers and not strings.
As a first example let us assume that we want to calculate an exponential moving average of the price range (i.e. High-Low). As we cannot pass a user defined variable to an EFS1 builtin study this means that we would need to write our own exponential moving average.
In EFS1 the required code would be as follows.
PHP Code:
function preMain() {
setStudyTitle("EMA of High-Low");
setCursorLabelName("H-L", 0);
setCursorLabelName("EMA", 1);
setPlotType(PLOTTYPE_HISTOGRAM, 0);
setDefaultBarFgColor(Color.blue, 0);
setDefaultBarFgColor(Color.red, 1);
var fp1 = new FunctionParameter("Length", FunctionParameter.NUMBER);
fp1.setLowerLimit(1);
fp1.setDefault(10);
}
var nHL = null;
var nArray = null;
var vEMA = null;
var vEMA1 = null;
var dPercent = 0.0;
var bPrimed = false;
function main(Length) {
var nState = getBarState();
if(nArray == null) nArray = new Array(Length);
if (nState == BARSTATE_NEWBAR && nHL != null) {
nArray.pop();
nArray.unshift(nHL);
}
nHL = high(0) - low(0);
nArray[0] = nHL;
if (nArray[Length-1] == null) return;
vEMA = EMA(Length, nArray);
return new Array(nHL, vEMA);
}
function EMA(Length, nArray) {
var nBarState = getBarState();
var dSum = 0.0;
if(nBarState == BARSTATE_ALLBARS || bPrimed == false) {
dPercent = (2.0 / (Length + 1.0));
bPrimed = false;
}
if (nBarState == BARSTATE_NEWBAR) {
vEMA1 = vEMA;
}
if(bPrimed == false) {
for(i = 0; i < Length; i++) {
dSum += nArray[i];
}
bPrimed = true;
return (dSum / Length);
} else {
return (((nArray[0] - vEMA1) * dPercent) + vEMA1);
}
}
PHP Code:
function preMain() {
setStudyTitle("EMA of High-Low");
setCursorLabelName("H-L", 0);
setCursorLabelName("EMA", 1);
setPlotType(PLOTTYPE_HISTOGRAM, 0);
setDefaultBarFgColor(Color.blue, 0);
setDefaultBarFgColor(Color.red, 1);
var fp1 = new FunctionParameter("Length", FunctionParameter.NUMBER);
fp1.setLowerLimit(1);
fp1.setDefault(10);
}
function main(Length) {
var nHL = efsInternal("range"); //this line calls the function "range" and creates a series
var vEMA = ema(Length,nHL); //the series is used as an input to the builtin study
return new Array(nHL, vEMA);
}
//this is the separate function that calculates the range
function range() {
return (high(0)-low(0)); //calculate the range
}
In EFS1 the code would be:
PHP Code:
function preMain() {
setStudyTitle("EMA of EMA of High-Low");
setCursorLabelName("H-L", 0);
setCursorLabelName("EMA", 1);
setPlotType(PLOTTYPE_HISTOGRAM, 0);
setDefaultBarFgColor(Color.blue, 0);
setDefaultBarFgColor(Color.red, 1);
var fp1 = new FunctionParameter("Length", FunctionParameter.NUMBER);
fp1.setLowerLimit(1);
fp1.setDefault(10);
var fp2 = new FunctionParameter("Length2", FunctionParameter.NUMBER);
fp2.setLowerLimit(1);
fp2.setDefault(10);
}
var nHL = null;
var nArray = null;
var nArray2 = null;
var vEMA = new Array(2);
vEMA[0] = null;
vEMA[1] = null;
var vEMA1 = new Array(2);
vEMA1[0] = null;
vEMA1[1] = null;
var dPercent = new Array(2);
dPercent[0] = 0.0;
dPercent[1] = 0.0;
var bPrimed = new Array(2);
bPrimed[0] = false;
bPrimed[1] = false;
function main(Length, Length2) {
var nState = getBarState();
if(nArray == null) nArray = new Array(Length);
if(nArray2 == null) nArray2 = new Array(Length2);
if (nState == BARSTATE_NEWBAR) {
if (nHL != null) {
nArray.pop();
nArray.unshift(nHL);
}
if (vEMA[0] != null) {
nArray2.pop();
nArray2.unshift(vEMA[0]);
}
}
nHL = high(0) - low(0);
nArray[0] = nHL;
if (nArray[Length-1] == null) return;
vEMA[0] = EMA(0, Length, nArray);
nArray2[0] = vEMA[0];
if (nArray2[Length2-1] != null) {
vEMA[1] = EMA(1, Length2, nArray2);
}
return new Array(nHL, vEMA[1]);
}
function EMA(num, Length, Array) {
var nBarState = getBarState();
var dSum = 0.0;
if(nBarState == BARSTATE_ALLBARS || bPrimed[num] == false) {
dPercent[num] = (2.0 / (Length + 1.0));
bPrimed[num] = false;
}
if (nBarState == BARSTATE_NEWBAR) {
vEMA1[num] = vEMA[num];
}
if(bPrimed[num] == false) {
for(i = 0; i < Length; i++) {
dSum += Array[i];
}
bPrimed[num] = true;
return (dSum / Length);
} else {
return (((Array[0] - vEMA1[num]) * dPercent[num]) + vEMA1[num]);
}
}
PHP Code:
function preMain() {
setStudyTitle("EMA of EMA of High-Low");
setCursorLabelName("H-L", 0);
setCursorLabelName("EMA", 1);
setPlotType(PLOTTYPE_HISTOGRAM, 0);
setDefaultBarFgColor(Color.blue, 0);
setDefaultBarFgColor(Color.red, 1);
var fp1 = new FunctionParameter("Length", FunctionParameter.NUMBER);
fp1.setLowerLimit(1);
fp1.setDefault(10);
var fp2 = new FunctionParameter("Length2", FunctionParameter.NUMBER);
fp2.setLowerLimit(1);
fp2.setDefault(10);
}
function main(Length,Length2) {
var nHL = efsInternal("range"); //this calls the function "range" and creates a series
var vEMA = ema(Length,ema(Length2,nHL)); //the series is used as an input to the builtin study
//which is nested in another builtin study
return new Array(nHL, vEMA);
}
//this is the separate function that calculates the range
function range() {
return (high(0)-low(0));
}
If we now wanted to add to the EFS1 script the ability to compute across multiple intervals we would probably need at least an additional 300 lines of very complex code and even then the formula would likely have some limitations in the functionality. Regardless it would require very advanced programming skills to accomplish this task.
With EFS2 instead all it takes is to pass a Sym/Inv series (see the EFS2 Help files for information on these functions) to the separate function so as to allow the formula engine to take control of that function and to make it execute in the desired symbol or interval context.
Here is the same EFS2 code with the additional functionality to allow running the efs on multiple intervals and/or on a symbol that is different from the one being charted.
PHP Code:
function preMain() {
setStudyTitle("EMA of EMA of High-Low");
setCursorLabelName("H-L", 0);
setCursorLabelName("EMA", 1);
setPlotType(PLOTTYPE_HISTOGRAM, 0);
setDefaultBarFgColor(Color.blue, 0);
setDefaultBarFgColor(Color.red, 1);
var fp1 = new FunctionParameter("Length", FunctionParameter.NUMBER);
fp1.setLowerLimit(1);
fp1.setDefault(10);
var fp2 = new FunctionParameter("Length2", FunctionParameter.NUMBER);
fp2.setLowerLimit(1);
fp2.setDefault(10);
}
function main(Length,Length2,Interval,Symbol) {
if(Symbol == null) Symbol = getSymbol();
if(Interval == null) Interval = getInterval();
var vSymbol = Symbol+","+Interval;
var nHL = efsInternal("range",sym(vSymbol)); //this calls the function "range" passing
//a Symbol/Interval and creates a series
var vEMA = ema(Length,ema(Length2,nHL)); //the series is used as an input to a builtin study
//which is nested in another builtin study
return new Array(nHL, vEMA);
}
//this is the separate function that calculates the range
function range(source) {
return (high(0)-low(0));
}
IMPORTANT NOTE: In order for the EFS2 engine to be able to control the context in which an external efs or a separate function execute (in other words in what time frame or with what symbol they will be running) the Sym/Inv series must be the last parameter passed by the efs() or efsInternal() functions
Comment