Beginner Tutorial 1: EFS Basics and Tools

ICE Data Services -

Guide to Developing eSignal Graphics

 

Introduction.

Developing custom graphics features into any eSignal application is reallyquite simple. In this guide, we will discuss and illustrate the feature ofdeploying graphic features into any code (or eSignal Formula Script - EFS)files. First, we will discuss the more simple commands where users can display"shapes" on charts. Next, we will discuss where and how users shoulddeploy these commands within their EFS files for the desired results.

Secondly, we will discuss the "Line" features where users can drawand place trend lines on any chart from within their EFS files. We will alsodiscuss some of the common "tricks" to using trend lines on a chartand how to effectively create and maintain "rotating" trend lines.

This guide is designed for users that have read and understand the"Guide To Developing eSignal Strategies" - as we will use some of thesame code as examples within this guide. So, if you are not familiar withdeveloping strategies or the examples within this guide are a little toocomplex, then please re-read the "Guide To Developing eSignalStrategies".

Graphics Command Basics

The eSignal graphics commands fall in to two categories

- Shapes 

- Lines

Within the EFS code, developers would deploy (place) the proper type ofgraphics command to place (draw) the graphic on the chart. Remember, everythingin your EFS file functions as we have illustrated in previous guides (from leftto right on the chart - or from oldest bar to newest bar). There are a fewtricks that we will get into later in this guide to assist you

Let's begin by learning some of the graphic functions 

eSignal Graphics Functions.

- drawImageRelative and drawImageAbsolute

drawImageRelative(xBar, yValue, Image, Url, Flags, TagName);
drawImageAbsolute(xBar, yValue, Image, Url, Flags, TagName);

The drawImage functions allows users to display any "user-defined"image or an image from a set of system images. Images are different than"Shapes" in their content. Images contain items such as "happyfaces", "Check Marks", "Circles" and other common imagefiles. The drawImage feature is ideal for Non Trading System display functions.

drawImageRelative allows placement of images onto charts that are relative tothe active real-time chart. This means that the images move/scroll to the leftas new bars are formed on the chart.

drawImageAbsolute allows placement of images onto charts that are fixed anddo not move/scroll to the left as new bars are formed.

- Parameters

xBar - Refers to the bar index (bar number) where the graphic is to beplaced.

yValue - Refers to the Y location of the image - or price value where theimage is to be placed.

Image - refers to the image type to display on the chart.

A system image can be used, or an image on the local file system can bereferenced (eg: c:/someimage.bmp"). Supported image types are GIF, BMP, JPG,PNG, 

  • System Images
  • SystemHappyFace
  • SystemNotHappy
  • SystemSadFace
  • SystemReallyHappyFace
  • SystemCheckMarkRed
  • SystemCheckMarkGreen
  • SystemCheckMarkYellow
  • SystemCheckMarkBlue
  • SystemCheckMarkBlack
  • SystemCheckMarkWhite
  • SystemLightOn
  • SystemLightOff
  • SystemCircleRed
  • SystemCircleGreen
  • SystemCircleYellow
  • SystemCircleBlue
  • SystemCircleBlack
  • SystemCircleWhite
  • SystemCircleButtonRed
  • SystemCircleButtonGreen
  • SystemCircleButtonYellow
  • SystemCircleButtonBlue
  • SystemCircleButtonBlack
  • SystemCircleButtonWhite
  • SystemQuestionRed
  • SystemQuestionGreen
  • SystemQuestionYellow
  • SystemQuestionBlue
  • SystemQuestionBlack
  • SystemQuestionWhite
  • SystemExclamationRed
  • SystemExclamationGreen
  • SystemExclamationYellow
  • SystemExclamationBlue
  • SystemExclamationBlack
  • SystemExclamationWhite
  • SystemInfoRed
  • SystemInfoGreen
  • SystemInfoYellow
  • SystemInfoBlue
  • SystemInfoBlack
  • SystemInfoWhite
  • SystemStopRed
  • SystemStopGreen
  • SystemStopYellow
  • SystemStopBlue
  • SystemStopBlack
  • SystemStopWhite
  • SystemLightning
  • SystemSnowflake
  • SystemSun

Url - refers to a linked web page for the image. If the user places a link toa web page here, when any user clicks on this image, eSignal will launch a webbrowser and display the linked page.

Flags - refer to the available "Image Flags" which are availablefor all images.

  • Image.LEFT (default) (left align image with x/y value)
  • Image.RIGHT (right align text image x/y value)
  • Image.TOP (default) (top align image with x/y value)
  • Image.BOTTOM (bottom align image with x/y value)
  • Image.ONTOP (Draws the image on top of the study. Otherwise, the study willbe drawn on top of the image)

TagName - is an essential component to controlling the number and placementof multiple images. We'll discuss the in much more detail later.

- drawShapeRelative and drawShapeAbsolute

drawShapeRelative(xBar, yValue, nShape, Url, Color, Flags, TagName);
drawShapeAbsolute(xBar, yValue, nShape, Url, Color, Flags, TagName);

The drawShape function allows users to display common shapes on a chart from aset of system shapes. Shapes resize automatically as users expand and contractthe number of bars on the chart. So, the drawShape function is a moreappropriate solution for trading system graphics - like stops, reversals andentry/exit signals. Some of the available shapes include UpArrows, DownArrows,Diamonds, Circles, Squares and others.

drawShapeRelative allows placement of shapes onto charts that are relative tothe active real-time chart. This means that the images move/scroll to the leftas new bars are formed on the chart.

drawShapeAbsolute allows placement of shapes onto charts that are fixed anddo not move/scroll to the left as new bars are formed.

- Parameters

xBar - refers to the bar index (bar number) where the graphic is to beplaced.

vValue - refers to the Y location of the image - or price value where theimage is to be placed.

nShape - refers to one of the defined system shapes.

Url - refers to a linked web page for the image. If the user places a link toa web page here, when any user clicks on this image, eSignal will launch a webbrowser and display the linked page.

Flags - refer to the available "Image Flags" which are availablefor all images.

Flags (these can be Or'd together)

  • Shape.LEFT (default) (left align shape x/y value)
  • Shape.RIGHT (right align text shape x/y value)
  • Shape.TOP (default) (top align image with x/y value)
  • Shape.BOTTOM (bottom align image with x/y value)
  • Shape.ONTOP (Draws the image on top of the study. Otherwise, the study willbe drawn on top of the image)
  • Shape.CIRCLE
  • Shape.SQUARE
  • Shape.TRIANGLE
  • Shape.DIAMOND
  • Shape.LEFTARROW
  • Shape.RIGHTARROW
  • Shape.UPARROW
  • Shape.DOWNARROW

TagName - is an essential component to controlling the number and placementof multiple images. We'll discuss the in much more detail later.


- drawLineRelative and drawLineAbsolute

drawLineRelative(x1, y1, x2, y2, style, thickness, color, TagName);
drawLineAbsolute(x1, y1, x2, y2, style, thickness, color, TagName);

These functions produce lines on the chart. Users can create functions tohandle as many lines as necessary, or simply a single line. These line functionsdraw from a fixed starting point to a fixed ending point. Thus, if users want todraw lines that automatically extend as new bars form, then users must createfunctions to handle the list extensions. An example of this is given later inthis guide.

drawLineRelative allows placement of lines onto charts that are relative tothe active real-time chart. This means that the images move/scroll to the leftas new bars are formed on the chart.

drawLineAbsolute allows placement of lines onto charts that are fixed and donot move/scroll to the left as new bars are formed.

- Parameters

x1 & y1 - refer to the x location (bar number) and y location (pricevalue) of the starting point of the line.

X2 & y2 - refer to the x location (bar number) and y location (pricevalue) of the ending point of the line.

Style
PS_SOLID


Thickness
Thickness of line. Minimum of 1.

Color
Color.RGB or Color.colorname

TagName - is an essential component to controlling the number and placementof multiple lines. We'll discuss the in much more detail later.

- drawTextRelative and drawTextAbsolute

drawTextRelative(xBar, yValue, Text, FGColor, BGColor, Flags, FontName,FontSize, TagName);
drawTextAbsolute(xBar, yValue, Text, FGColor, BGColor, Flags, FontName,FontSize, TagName);

These functions allow users to draw and place text on the chart or indicatorpane. These functions should be used only when necessary as charts can becomecluttered with text, graphics, images and lines. Text placed onto the chart willbegin drawing (left to right) at the xBar and yValue location specified withinthe function. Thus, long text drawn on each bar will potentially overwriteprevious existing text on the chart.

drawTextRelative allows placement of text onto charts that are relative tothe active real-time chart. This means that the images move/scroll to the leftas new bars are formed on the chart.

drawTextAbsolute allows placement of text onto charts that are fixed and donot move/scroll to the left as new bars are formed.

- Parameters

xBar - Relative or absolute bar where text should appear.

yValue - yValue where text should appear.

Text - This is the text that will appear on the study. You can associate aURL with this text. When the user clicks on the text, a browser will be invoked.To associate a URL, add (eg) "@URL=http://www.yoururl.com/index.asp?parmeter1=abc&parameter2=xyz"to the end of your text string.

FGColor and BGColor - These are optional. If you don't provide them, pass"null" in their place. If null is passed, the FG/BG color from thechart will be used. Otherwise, use Color.colorname (eg) Color.blue or,
Color.RGB(rValue, gValue, bValue)

Flags - (these can be Or'd together) If you don't provide any flags, pass"null"

  • Text.BOLD (draws bold text)
  • Text.ITALIC (draws italic text)
  • Text.UNDERLINE (draws underline text)
  • Text.LEFT (default) (left align text with x/y value)
  • Text.RIGHT (right align text with x/y value)
  • Text.TOP (default) (top align text with x/y value)
  • Text.BOTTOM (bottom align text with x/y value)
  • Text.ONTOP (Draws the text on top of the study. Otherwise, the study will bedrawn on top of the text)
  • Text.FRAME (draws a frame around the text using FGColor as the frame color)
  • Text.BUTTON (draws the text as a button. FGColor and BGColor are ignored)

FontName - Optional. If not provided, pass "null". The font fromthe chart will be used. Otherwise, pass a font name (eg) "Courier","Arial", "Helv"FontSize

FontSize - Optional. If not provided, pass "null". The font sizefrom the chart will be used. Otherwise, pass a point size. (eg) 12

TagName - is an essential component to controlling the number and placementof multiple lines. We'll discuss the in much more detail later.


Deploying Graphic Functions

Users wishing to deploy or incorporate the graphics functions need to simplyplace the graphic function statements within their EFS code where the code istaking a trading action or where the essential variables (stops, profit targetsor trade executions) are being modified. An example of this would be.

if ( /* Buy Signal */ ){
	Strategy.doLong(.);
	DrawShapeRelative(0, low(), Shape.UPARROW, Color.Green, Image.ONTOP, "Buy");
}
if ( /* Sell Signal */ ){
	Strategy.doShort(.);
	DrawShapeRelative(0, high(), Shape.DOWNARROW, Color.Red, Image.ONTOP, "Sell");
}

This simple example will plot two arrows, one for the buy signal and one forthe sell signal. Notice the use of UPARROW and DOWNARROW shapes to designate BUYand SELL signals. Also notice the reference to low() and high() as pricevariables and the Color.Green and Color.Red to designate the proper signaltypes. The TagName parameter is the next item we need to discuss in more detailbecause it is an essential component of your trading systems ability to handlegraphics.

I learned, very early in my coding efforts, that the TagName parameter actsas an Identifier for the text, image, shape or line that we are attempting todraw. In the example above, the buy signal drawShapeRelative function includes a"Buy" TagName. This will only allow a single BUY ARROW to be drawn onthe chart because only one unique TagName has been defined - "Buy". Inorder to resolve this issue, unique TagName parameters must be passed within thegraphics function for each new graphic shape to be drawn on the chart. Toaccomplish this easily, users should add the following to their TagName fields

getValue("RawTime",0) + "Buy"

- or -

getValue("RawTime",0) + "Sell"

The "getValue("RawTime",0)" portion of this code returnsa unique number that refers to the exact time of the current bar. Next, byadding "+ "Sell"" to the end of this statement adds a uniquetext identifier to the graphic function. Together, this solution provides anautomatic and function unique TagName parameter for multiple graphics, text orline function calls.

So, our new code would look like this

if ( /* Buy Signal */ ){
	Strategy.doLong(.);
	DrawShapeRelative(0, low(), Shape.UPARROW, Color.Green, Image.ONTOP, getValue("RawTime") + "Buy");
}
if ( /* Sell Signal */ ){
	Strategy.doShort(.);
	DrawShapeRelative(0, high(), Shape.DOWNARROW, Color.Red, Image.ONTOP, getValue("RawTime") + "Sell");
}

Before we move on, I would like to point out that our graphics functions areplaced immediately after our "Strategy" functions. This is done toassociate a trading action with a graphic function. Every time our EFS codeissues a buy or sell signal, our EFS code also places a corresponding shape ontothe chart.

Of course, users could change the SHAPE, COLOR and PRICE parameters of thesegraphics functions to anything they like. I personally like to use the followingset of graphic shapes in my trading systems

Buy Signals
UPARROW - GREEN

Sell Signals
DOWNARROW - RED

Stop Levels
DIAMOND - BLUE

Bullish Profit Targets
DOWNARROW - MAGENTA

Bearish Profit Targets
UPARROW - MAGENTA

This organization of the trading system graphics allows for a standard to beestablished for all my systems. It also presents a clear and recognizablegraphic solution for my trading systems


Text Graphics

Users can also add "text graphics" to their charting programs byplacing drawTextRelative functions within their code. I find the benefit for thetext functions are as follows.

  1. Clear definition of trading signals.
  2. Color coded information.
  3. Ability to link to a web page.
  4. Ability to control placement of the text.

Additionally, I have found two methods of deploying the text message onto achart that are functional. The first, is a "histogram" type ofindicator that allows for easily distinguished reversal/entry signals. Thesecond is simply placing the text onto the price chart above and below the pricebars.

The strength of the text graphic functions can be discussed in simple detailto help users decide which type of graphics to use in their own systems. Let'sgo over some of the most common uses of both.

  • A. If your trading system includes only ONE entry signal for both long andshort trades, then the SHAPE graphics system is ideal for your application.
    Entry signals can be marked with RED and GREEN arrows to indicate entrypositions.
  • B. If your trading system includes a trailing stop level, variable trailing stoplevel or multi-stage trailing stop level, then the SHAPE graphics systems isideal for your application.
    Stop levels can be shown as CIRCLES or DIAMONDS on the chart and color changescan designate multiple stages for the stop levels.
  • C. If your trading system includes multiple profit targets or a fixed profittarget, then the SHAPE graphics system is ideal for your application

Alternately.

  • A. If your trading system includes many different entry signals for both longand short trades, then the TEXT graphics system is ideal for your application
  • B. If your trading system includes UNIQUE TRADING ACTIONS (such as wanting toprompt on the chart the trading action - BUY or SELL, cross market informationor other text designators, then the TEXT graphics system is ideal for yourapplication.
  • C. If you are developing a custom indicator or histogram indicator and want toidentify changes in conditions or trading condition status, then the TEXTgraphics system is ideal for your application.

Lets take a look at a real code example of a stochastic cross over systemthat deploys the TEXT graphics system.

Download Formula:  Sto_Text.efs

//------ Beginning of code
/****************************************************************************************************
Copyright © Matheny Enterprises. 2003. All rights reserved. This sample Formula Script (EFS) may be 
modified and saved under a new filename; however, matheny Enterprises is no longer responsible for 
the functionality once modified.

Matheny Enterprises reserves the right to modify and overwrite this 
EFS file with each new release.
*****************************************************************************************************/
var study = new StochStudy(14, 7, 3);

var LastStoK = -1;
var LastStoD = -1;

function preMain() {
  setStudyTitle("Sto Cross System");
  setCursorLabelName("Sto Cross System");
}

function main() {
  var vFast = study.getValue(StochStudy.FAST);
  var vSlow = study.getValue(StochStudy.SLOW);

  if (vFast != null || vSlow != null) {
    if (vFast > vSlow) {
      setBarBgColor(Color.RGB(0x9d, 0xfc, 0x8d));
    } else {
      setBarBgColor(Color.RGB(0xfc, 0x8d, 0x8d));
    }

    if (LastStoK < LastStoD && vFast >= vSlow) {
      drawTextRelative(
        0,
        vFast,
        "X+",
        Color.black,
        Color.lime,
        Text.FRAME | Text.ONTOP | Text.BOLD,
        null,
        null,
        getValue("rawtime")
      );
    }
    if (LastStoK > LastStoD && vFast <= vSlow) {
      drawTextRelative(
        0,
        vFast,
        "X-",
        Color.black,
        Color.red,
        Text.FRAME | Text.ONTOP | Text.BOLD,
        null,
        null,
        getValue("rawtime")
      );
    }

    LastStoK = vFast;
    LastStoD = vSlow;

    return new Array(vFast, vSlow);
  } else {
    return;
  }
} //------ End of code

The drawTextRelative functions are added to the code within the"if" statement that tests for stochastics crossovers. If we find acrossover, then we issue the drawTextRelative function and tell it to draw atthe vFast level - the current level of the Stochastics %K value.

This system could easily be converted to a "strategy back testing"system by adding the Strategy.doLong and Strategy.doShort code just below thedrawTextRelative functions.


Background Graphics Control

Additionally, the developers at eSignal have provided us with another tool todeploy within our trading systems or custom indicators. This tool is the set issetBarBgColor, which allows users to specify chart background color changes todesignate trading system actions (red for bearish, green for bullish, white forneutral - for example).

Let's look at some EFS code examples

setBarBgColor Line Indicator Example

Download Formula:  BarRange.efs

//------ Beginning of code
/********************************************************************
********************************
Copyright © Matheny Enterprises. 2002. All rights reserved. 
This sample Formula Script (EFS) may be modified and saved under a 
new 
filename; however, matheny Enterprises is no longer responsible for 
the functionality once modified.
Matheny Enterprises reserves the right to modify and overwrite this 
EFS file with each new release.
*********************************************************************
********************************/
var LastRange;

function preMain() {
  setStudyTitle("Range Comparison");
  setCursorLabelName("Range Comparison");
  // setStudyMin(-10);
  // setStudyMax(10);
}

function main() {
  if (high() - low() - (high(-1) - low(-1)) > LastRange) {
    setBarBgColor(Color.lime);
  } else {
    setBarBgColor(Color.red);
  }

  // Test for null returns.
  if (high() == null || low() == null || high(-1) == null || low(-1) == null) {
    return;
  } else {
    LastRange = high() - low() - (high(-1) - low(-1));

    return high() - low() - (high(-1) - low(-1));
  }
} //------ End of code

This example compares the current price bar's range to the previous bar'srange and plots the difference in an indicator pane. It also color-codes thebackground based on the expansion/retraction of the range difference.

Notice that we are simply comparing the current bar's price range to theprevious bar's price range and setting the background color accordingly. This,very simply example, is an ideal source for users to begin learning how to useand deploy the background color system into their custom EFS applications.

Now, let's take this same system and convert it to a histogram type ofindicator. We'll force a +10 as a return value if the range is expanding and a-10 value if the range is contracting.
setBarBgColor Histogram Indicator Example

//------ Beginning of code/********************************************************************/
var LastRange;
var HistogramValue = 0;

function preMain(){
	setStudyTitle("Range Comparison");
	setCursorLabelName("Range Comparison");
	setStudyMin(-10);
	setStudyMax(10);
}

function main(){ // Test for null returns. 
	if ((high() == null) || (low() == null) || (high(-1) == null) || (low(-1) == null))	{
		return;
	}
	if ((high() - low()) - (high(-1) - low(-1)) > LastRange){
		HistogramValue = 10;
		setBarBgColor(Color.lime);
	}
	else{
		HistogramValue = -10;
		setBarBgColor(Color.red);
	}
	LastRange = (high() - low()) - (high(-1) - low(-1));
	return (HistogramValue);
} //------ End of code

Users can easily see the additional lines of code needed to convert thissystem into a histogram are highlighted in BOLD . The conversion process israther simple.

Now, let's add the background color control to our "StochasticsCrossover System"

//------ Beginning of code/**************************************************************/
var study = new StochStudy(14, 7, 3);
var LastStoK = -1;
var LastStoD = -1;

function preMain()
{
	setStudyTitle("Sto Cross System");
	setCursorLabelName("StoK", 0);
	setCursorLabelName("StoD", 1);
}

function main()
{
	var vFast = study.getValue(StochStudy.FAST);
	var vSlow = study.getValue(StochStudy.SLOW);
	if ((vFast != null) || (vSlow != null))
	{ // Add Background Color Code. 
		if (vFast > vSlow)
		{
			setBarBgColor(Color.RGB(0x9D, 0xFC, 0x8D));
		}
		else
		{
			setBarBgColor(Color.RGB(0xFC, 0x8D, 0x8D));
		} // Test for Stochastics Cross. 
		if ((LastStoK < LastStoD) && (vFast >= vSlow))
		{
			drawTextRelative(0, vFast, "X+", Color.black, Color.lime, Text.FRAME | Text.ONTOP | Text.BOLD, null, null, getValue("rawtime"));
		}
		if ((LastStoK > LastStoD) && (vFast <= vSlow))
		{
			drawTextRelative(0, vFast, "X-", Color.black, Color.red, Text.FRAME | Text.ONTOP | Text.BOLD, null, null, getValue("rawtime"));
		} // Record last Stochastic Values.
		LastStoK = vFast;
		LastStoD = vSlow;
		return new Array(vFast, vSlow);
	}
	else
	{
		return;
	}
} //------ End of code

The setBarBgColor code is a very useful solution for nearly any tradingsystem or technical indicator. It clearly shows the actions of the indicator oftrading system and is rather easy to deploy.

One suggestion I should make is the once the background color is set with thesetBarBgColor command, the background does not stay in this color mode. ThesetBarBgColor command must be issued for each bar in order for the color to bepainted on your background. So, users much include a unique function to handlethis color control that is separate from the entry, exit, stop and profit targetcode.

If users simply include the setBarBgColor into their entry, exit, stop andprofit target code sections, then only the background of the bar that issuesthese signals will be changed.


Lines and Trend Lines

Adding and manipulating lines and trend lines is a bit more difficult foradvanced features - such as automatically extending trend lines and multipleline control. We'll start out by explaining the function of adding a trend lineto a chart.

In eSignal, adding a trend line to a chart is as simple as placing the trendline function into your existing code - just like adding the SHAPE or TEXTfunctions. The tricky part in deploying trend line functions is that we not onlyneed to know the current bar and price level (or ending point), we also need toknow the previous bar's index and price level (the starting point).

Let's say we wanted to draw a trend line from the closing price of 5 bars agoand extend it to the current bar. We would want to add the following statementto our code

drawLineRelative(5, close(-5), 0, close(-5), PS_SOLID, 1, color.blue, "NEWLINE");

This would perpetually draw a line on the chart and "roll" thechart forward as new bars are drawn onto the chart. The reason this singlestatement creates a "rolling" trend line (as I call it) is because theTagName ("NEWLINE") is a fixed text identifier. This means that onlyONE trend line can be labeled "NEWLINE", thus this single trend line"rolls" over to the new bars as they are formed on the chart.

If users wanted to maintain more than one trend line, they would need toidentify each trend line with a unique TagName variable. Users would need tocreate two or more unique TagName variables in order to draw two or more trendlines on the price chart.

Let's say we wanted to identify "Pivot Bottoms" and "PivotTops" in market price, then draw trend lines from these reversal pointsthrough the LOW or HIGH of the price bars that follow the pivot points. Thisbegins a more difficult quest - how to automatically manage and extend trendlines.

I have recently taken on this task and am going to present the code thataccomplishes it. The following code can be used as an example by anyone todevelop and maintain multiple trend lines that automatically extend to thecurrent bar. The following code includes the following

  1. Maintains a total of 5 upper trend lines and 5 lower trend lines (based onpivot highs and lows).
  2. Automatically extends the trend lines to the current bar.
  3. Automatically "rolls-over" as new trend lines are drawn - meaningit removed the oldest trend line when a new trend line is drawn.

Users can modify this code to handle as many or as little trend lines as theywant. This code gives detailed examples of the following EFS features.

  1. Handling advanced features by creating sub-functions within the EFS code.
  2. Simple "Pivot" Patter recognition.
  3. Calculation examples for handling advanced trend line features.

The method I have developed to handle the "automatically extending trendlines" is to calculate the price factor (price change) from the beginningof the trend line to 1 bar after the trend line starts. This generates amultiple value that I can then use to calculate the current trend line pricelevel. If the multiple is say 0.25 and the start of the bar was 10 bars ago @901.00, then the current price level would be (901 + (0.25 * 10)) - or 903.50.

I've also created functions to handle the ADDING, UPDATING and PLOTTING ofthe trend lines. This way, the functions handle all of the necessary work ofmaintaining the trend lines while my main() function simply looks for and addsnew trend lines (when necessary) based on price action.

I'm making this code available to everyone in an effort to assist the usersof eSignal in better understanding how to use and deploy trend line systems.

Here is the code.

Download Formula:  Trendlines_R2.efs

/* ---------------------------------------------------------------
Declare Functions...
------------------------------------------------------------------*/

function rnd(value) {
  value *= 100;
  return Math.round(value, 2) / 100;
}

function rndQTR(value) {
  value *= 100;
  return Math.round(value, 2) / 100;
}

function Add_TL(X0, Y0, X1, Y1, LineType, LineNumber) {
  if (LineNumber == 1 && LineType == -1) {
    LSB1SBar = X0;
    LSB1SPrice = Y0;
    LSB1EBar = X1;
    LSB1EPrice = Y1;
    LSB1Factor = (Y1 - Y0) / (X1 - X0);
    //      debugPrintln("TL1:" + LSBCount + ":" + BLBarOffset + ":" + LSB1SBar + ":" + LSB1SPrice + ":" + LSB1EBar + ":" + LSB1EPrice + ":" + TrackCurrentLSB);
  }
  if (LineNumber == 2 && LineType == -1) {
    LSB2SBar = X0;
    LSB2SPrice = Y0;
    LSB2EBar == X1;
    LSB2EPrice = Y1;
    LSB2Factor = (Y1 - Y0) / (X1 - X0);
    //      debugPrintln("TL2:" + LSBCount + ":" + BLBarOffset + ":" + LSB2SBar + ":" + LSB2SPrice + ":" + LSB2EBar + ":" + LSB2EPrice + ":" + TrackCurrentLSB);
  }
  if (LineNumber == 3 && LineType == -1) {
    LSB3SBar = X0;
    LSB3SPrice = Y0;
    LSB3EBar = X1;
    LSB3EPrice = Y1;
    LSB3Factor = (Y1 - Y0) / (X1 - X0);
    //      debugPrintln("TL3:" + LSBCount + ":" + BLBarOffset + ":" + LSB3SBar + ":" + LSB3SPrice + ":" + LSB3EBar + ":" + LSB3EPrice + ":" + TrackCurrentLSB);
  }
  if (LineNumber == 4 && LineType == -1) {
    LSB4SBar = X0;
    LSB4SPrice = Y0;
    LSB4EBar = X1;
    LSB4EPrice = Y1;
    LSB4Factor = (Y1 - Y0) / (X1 - X0);
    //      debugPrintln("TL4:" + LSBCount + ":" + BLBarOffset + ":" + LSB4SBar + ":" + LSB4SPrice + ":" + LSB4EBar + ":" + LSB4EPrice + ":" + TrackCurrentLSB);
  }
  if (LineNumber == 5 && LineType == -1) {
    //  Swap Line 1 with Line 2...
    LSB1SBar = LSB2SBar;
    LSB1SPrice = LSB2SPrice;
    LSB1EBar = LSB2EBar;
    LSB1EPrice = LSB2EPrice;
    LSB1Factor = LSB2Factor;
    //  Swap Line 2 with Line 3...
    LSB2SBar = LSB3SBar;
    LSB2SPrice = LSB3SPrice;
    LSB2EBar = LSB3EBar;
    LSB2EPrice = LSB3EPrice;
    LSB2Factor = LSB3Factor;
    //  Swap Line 3 with Line 4...
    LSB3SBar = LSB4SBar;
    LSB3SPrice = LSB4SPrice;
    LSB3EBar = LSB4EBar;
    LSB3EPrice = LSB4EPrice;
    LSB3Factor = LSB4Factor;
    //  Swap Line 4 with Line 5...
    LSB4SBar = LSB5SBar;
    LSB4SPrice = LSB5SPrice;
    LSB4EBar = LSB5EBar;
    LSB4EPrice = LSB5EPrice;
    LSB4Factor = LSB5Factor;
    //  Add new line information....
    LSB5SBar = X0;
    LSB5SPrice = Y0;
    LSB5EBar = X1;
    LSB5EPrice = Y1;
    LSB5Factor = (Y1 - Y0) / (X1 - X0);
    //      debugPrintln("TL5:" + LSBCount + ":" + BLBarOffset + ":" + LSB5SBar + ":" + LSB5SPrice + ":" + LSB5EBar + ":" + LSB5EPrice + ":" + TrackCurrentLSB);
  }

  if (LineNumber == 1 && LineType == 1) {
    HSB1SBar = X0;
    HSB1SPrice = Y0;
    HSB1EBar = X1;
    HSB1EPrice = Y1;
    HSB1Factor = (Y1 - Y0) / (X1 - X0);
    //      debugPrintln("TL1:" + HSBCount + ":" + BLBarOffset + ":" + HSB1SBar + ":" + HSB1SPrice + ":" + HSB1EBar + ":" + HSB1EPrice + ":" + TrackCurrentHSB);
  }
  if (LineNumber == 2 && LineType == 1) {
    HSB2SBar = X0;
    HSB2SPrice = Y0;
    HSB2EBar = X1;
    HSB2EPrice = Y1;
    HSB2Factor = (Y1 - Y0) / (X1 - X0);
  }
  if (LineNumber == 3 && LineType == 1) {
    HSB3SBar = X0;
    HSB3SPrice = Y0;
    HSB3EBar = X1;
    HSB3EPrice = Y1;
    HSB3Factor = (Y1 - Y0) / (X1 - X0);
  }
  if (LineNumber == 4 && LineType == 1) {
    HSB4SBar = X0;
    HSB4SPrice = Y0;
    HSB4EBar = X1;
    HSB4EPrice = Y1;
    HSB4Factor = (Y1 - Y0) / (X1 - X0);
  }
  if (LineNumber == 5 && LineType == 1) {
    //  Swap Line 1 with Line 2...
    HSB1SBar = HSB2SBar;
    HSB1SPrice = HSB2SPrice;
    HSB1EBar = HSB2EBar;
    HSB1EPrice = HSB2EPrice;
    HSB1Factor = HSB2Factor;
    //  Swap Line 2 with Line 3...
    HSB2SBar = HSB3SBar;
    HSB2SPrice = HSB3SPrice;
    HSB2EBar = HSB3EBar;
    HSB2EPrice = HSB3EPrice;
    HSB2Factor = HSB3Factor;
    //  Swap Line 3 with Line 4...
    HSB3SBar = HSB4SBar;
    HSB3SPrice = HSB4SPrice;
    HSB3EBar = HSB4EBar;
    HSB3EPrice = HSB4EPrice;
    HSB3Factor = HSB4Factor;
    //  Swap Line 4 with Line 5...
    HSB4SBar = HSB5SBar;
    HSB4SPrice = HSB5SPrice;
    HSB4EBar = HSB5EBar;
    HSB4EPrice = HSB5EPrice;
    HSB4Factor = HSB5Factor;
    //  Add new line information....
    HSB5SBar = X0;
    HSB5SPrice = Y0;
    HSB5EBar = X1;
    HSB5EPrice = Y1;
    HSB5Factor = (Y1 - Y0) / (X1 - X0);
  }
  return;
}

function Update_TL(CrntBar, CrntLow, LineType, LineNumber) {
  if (LineType == -1) {
    if (LineNumber == 1 && CrntLow <= LSB1EPrice) {
      LSB1EBar = CrntBar;
      LSB1EPrice = CrntLow;
      LSB1Factor = (LSB1EPrice - LSB1SPrice) / (LSB1EBar - LSB1SBar);
      //      debugPrintln("UTL1:" + LSBCount + ":" + BLBarOffset + ":" + LSB1SBar + ":" + LSB1SPrice + ":" + LSB1EBar + ":" + LSB1EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 2 && CrntLow <= LSB2EPrice) {
      LSB2EBar = CrntBar;
      LSB2EPrice = CrntLow;
      LSB2Factor = (LSB2EPrice - LSB2SPrice) / (LSB2EBar - LSB2SBar);
      //debugPrintln("UTL2:" + LSBCount + ":" + BLBarOffset + ":" + LSB2SBar + ":" + LSB2SPrice + ":" + LSB2EBar + ":" + LSB2EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 3 && CrntLow <= LSB3EPrice) {
      LSB3EBar = CrntBar;
      LSB3EPrice = CrntLow;
      LSB3Factor = (LSB3EPrice - LSB3SPrice) / (LSB3EBar - LSB3SBar);
      //      debugPrintln("UTL3:" + LSBCount + ":" + BLBarOffset + ":" + LSB3SBar + ":" + LSB3SPrice + ":" + LSB3EBar + ":" + LSB3EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 4 && CrntLow <= LSB4EPrice) {
      LSB4EBar = CrntBar;
      LSB4EPrice = CrntLow;
      LSB4Factor = (LSB4EPrice - LSB4SPrice) / (LSB4EBar - LSB4SBar);
      //      debugPrintln("UTL4:" + LSBCount + ":" + BLBarOffset + ":" + LSB4SBar + ":" + LSB4SPrice + ":" + LSB4EBar + ":" + LSB4EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 5 && CrntLow <= LSB5EPrice) {
      LSB5EBar = CrntBar;
      LSB5EPrice = CrntLow;
      LSB5Factor = (LSB5EPrice - LSB5SPrice) / (LSB5EBar - LSB5SBar);
      //      debugPrintln("UTL5:" + LSBCount + ":" + BLBarOffset + ":" + LSB5SBar + ":" + LSB5SPrice + ":" + LSB5EBar + ":" + LSB5EPrice + ":" + TrackCurrentLSB);
    }
  }

  if (LineType == 1) {
    if (LineNumber == 1 && CrntLow >= HSB1EPrice) {
      HSB1EBar = CrntBar;
      HSB1EPrice = CrntLow;
      HSB1Factor = (HSB1EPrice - HSB1SPrice) / (HSB1EBar - HSB1SBar);
      //      debugPrintln("UTL1:" + LSBCount + ":" + BLBarOffset + ":" + LSB1SBar + ":" + LSB1SPrice + ":" + LSB1EBar + ":" + LSB1EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 2 && CrntLow >= HSB2EPrice) {
      HSB2EBar = CrntBar;
      HSB2EPrice = CrntLow;
      HSB2Factor = (HSB2EPrice - HSB2SPrice) / (HSB2EBar - HSB2SBar);
      //debugPrintln("UTL2:" + LSBCount + ":" + BLBarOffset + ":" + LSB2SBar + ":" + LSB2SPrice + ":" + LSB2EBar + ":" + LSB2EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 3 && CrntLow >= HSB3EPrice) {
      HSB3EBar = CrntBar;
      HSB3EPrice = CrntLow;
      HSB3Factor = (HSB3EPrice - HSB3SPrice) / (HSB3EBar - HSB3SBar);
      //      debugPrintln("UTL3:" + LSBCount + ":" + BLBarOffset + ":" + LSB3SBar + ":" + LSB3SPrice + ":" + LSB3EBar + ":" + LSB3EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 4 && CrntLow >= HSB4EPrice) {
      HSB4EBar = CrntBar;
      HSB4EPrice = CrntLow;
      HSB4Factor = (HSB4EPrice - HSB4SPrice) / (HSB4EBar - HSB4SBar);
      //      debugPrintln("UTL4:" + LSBCount + ":" + BLBarOffset + ":" + LSB4SBar + ":" + LSB4SPrice + ":" + LSB4EBar + ":" + LSB4EPrice + ":" + TrackCurrentLSB);
    }
    if (LineNumber == 5 && CrntLow >= HSB5EPrice) {
      HSB5EBar = CrntBar;
      HSB5EPrice = CrntLow;
      HSB5Factor = (HSB5EPrice - HSB5SPrice) / (HSB5EBar - HSB5SBar);
      //      debugPrintln("UTL5:" + LSBCount + ":" + BLBarOffset + ":" + LSB5SBar + ":" + LSB5SPrice + ":" + LSB5EBar + ":" + LSB5EPrice + ":" + TrackCurrentLSB);
    }
  }

  return;
}

function Plot_TL() {
  if (LSBCount >= 1) {
    LSB1PlotPrice = LSB1Factor * (BLBarOffset - LSB1SBar) + LSB1SPrice;
    //      debugPrintln("TL1:" + LSB1SBar + ":" + LSB1SPrice);
    //      debugPrintln("pL1:" + LSBCount + ":" + BLBarOffset + ":" + LSB1SBar + ":" + LSB1SPrice + ":" + LSB1EBar + ":" + LSB1EPrice + ":" + LSB1Factor);
    drawLineRelative(
      LSB1SBar - BLBarOffset,
      LSB1SPrice,
      0,
      LSB1PlotPrice,
      PS_SOLID,
      1,
      Color.blue,
      "LSB1"
    );
  }
  if (LSBCount >= 2) {
    LSB2PlotPrice = LSB2Factor * (BLBarOffset - LSB2SBar) + LSB2SPrice;
    //    debugPrintln("pL2:" + LSBCount + ":" + BLBarOffset + ":" + LSB2SBar + ":" + LSB2SPrice + ":" + LSB2EBar + ":" + LSB2EPrice + ":" + LSB2Factor);
    drawLineRelative(
      LSB2SBar - BLBarOffset,
      LSB2SPrice,
      0,
      LSB2PlotPrice,
      PS_SOLID,
      1,
      Color.blue,
      "LSB2"
    );
  }
  if (LSBCount >= 3) {
    LSB3PlotPrice = LSB3Factor * (BLBarOffset - LSB3SBar) + LSB3SPrice;
    //      debugPrintln("pL3:" + LSBCount + ":" + BLBarOffset + ":" + LSB3SBar + ":" + LSB3SPrice + ":" + LSB3EBar + ":" + LSB3EPrice + ":" + LSB3Factor);
    drawLineRelative(
      LSB3SBar - BLBarOffset,
      LSB3SPrice,
      0,
      LSB3PlotPrice,
      PS_SOLID,
      1,
      Color.blue,
      "LSB3"
    );
  }
  if (LSBCount >= 4) {
    LSB4PlotPrice = LSB4Factor * (BLBarOffset - LSB4SBar) + LSB4SPrice;
    //      debugPrintln("pL4:" + LSBCount + ":" + BLBarOffset + ":" + LSB4SBar + ":" + LSB4SPrice + ":" + LSB4EBar + ":" + LSB4EPrice + ":" + LSB4Factor);
    drawLineRelative(
      LSB4SBar - BLBarOffset,
      LSB4SPrice,
      0,
      LSB4PlotPrice,
      PS_SOLID,
      1,
      Color.blue,
      "LSB4"
    );
  }
  if (LSBCount >= 5) {
    LSB5PlotPrice = LSB5Factor * (BLBarOffset - LSB5SBar) + LSB5SPrice;
    //      debugPrintln("pL5:" + LSBCount + ":" + BLBarOffset + ":" + LSB5SBar + ":" + LSB5SPrice + ":" + LSB5EBar + ":" + LSB5EPrice + ":" + LSB5Factor);
    drawLineRelative(
      LSB5SBar - BLBarOffset,
      LSB5SPrice,
      0,
      LSB5PlotPrice,
      PS_SOLID,
      1,
      Color.blue,
      "LSB5"
    );
  }
  //  ------  HSB Lines
  if (HSBCount >= 1) {
    HSB1PlotPrice = HSB1Factor * (BLBarOffset - HSB1SBar) + HSB1SPrice;
    //      debugPrintln("TL1:" + HSB1SBar + ":" + HSB1SPrice);
    //      debugPrintln("pL1:" + HSBCount + ":" + BLBarOffset + ":" + HSB1SBar + ":" + HSB1SPrice + ":" + HSB1EBar + ":" + HSB1EPrice + ":" + HSB1Factor);
    drawLineRelative(
      HSB1SBar - BLBarOffset,
      HSB1SPrice,
      0,
      HSB1PlotPrice,
      PS_SOLID,
      1,
      Color.red,
      "HSB1"
    );
  }
  if (HSBCount >= 2) {
    HSB2PlotPrice = HSB2Factor * (BLBarOffset - HSB2SBar) + HSB2SPrice;
    //    debugPrintln("pL2:" + LSBCount + ":" + BLBarOffset + ":" + LSB2SBar + ":" + LSB2SPrice + ":" + LSB2EBar + ":" + LSB2EPrice + ":" + LSB2Factor);
    drawLineRelative(
      HSB2SBar - BLBarOffset,
      HSB2SPrice,
      0,
      HSB2PlotPrice,
      PS_SOLID,
      1,
      Color.red,
      "HSB2"
    );
  }
  if (HSBCount >= 3) {
    HSB3PlotPrice = HSB3Factor * (BLBarOffset - HSB3SBar) + HSB3SPrice;
    //      debugPrintln("pL3:" + LSBCount + ":" + BLBarOffset + ":" + LSB3SBar + ":" + LSB3SPrice + ":" + LSB3EBar + ":" + LSB3EPrice + ":" + LSB3Factor);
    drawLineRelative(
      HSB3SBar - BLBarOffset,
      HSB3SPrice,
      0,
      HSB3PlotPrice,
      PS_SOLID,
      1,
      Color.red,
      "HSB3"
    );
  }
  if (HSBCount >= 4) {
    HSB4PlotPrice = HSB4Factor * (BLBarOffset - HSB4SBar) + HSB4SPrice;
    //      debugPrintln("pL4:" + LSBCount + ":" + BLBarOffset + ":" + LSB4SBar + ":" + LSB4SPrice + ":" + LSB4EBar + ":" + LSB4EPrice + ":" + LSB4Factor);
    drawLineRelative(
      HSB4SBar - BLBarOffset,
      HSB4SPrice,
      0,
      HSB4PlotPrice,
      PS_SOLID,
      1,
      Color.red,
      "HSB4"
    );
  }
  if (HSBCount >= 5) {
    HSB5PlotPrice = HSB5Factor * (BLBarOffset - HSB5SBar) + HSB5SPrice;
    //      debugPrintln("pL5:" + LSBCount + ":" + BLBarOffset + ":" + LSB5SBar + ":" + LSB5SPrice + ":" + LSB5EBar + ":" + LSB5EPrice + ":" + LSB5Factor);
    drawLineRelative(
      HSB5SBar - BLBarOffset,
      HSB5SPrice,
      0,
      HSB5PlotPrice,
      PS_SOLID,
      1,
      Color.red,
      "HSB5"
    );
  }

  return;
}

//----------------  End of Function Declarations

/****************************************************************************************************
Trendline System.
Copyright © Matheny Enterprises.
*****************************************************************************************************/
var nnumber;
var nLastRawTime = 0;
var BLBarOffset = 0;
var TrackCurrentLSB;
var TrackCurrentHSB;

var HSBCount = 0;
var LSBCount = 0;

var HSB1SBar = 0;
var HSB1SPrice = 0;
var HSB1EBar = 0;
var HSB1EPrice = 0;
var HSB1Factor = 0;
var HSB1PlotPrice = 0;
var HSB2SBar = 0;
var HSB2SPrice = 0;
var HSB2EBar = 0;
var HSB2EPrice = 0;
var HSB2Factor = 0;
var HSB2PlotPrice = 0;
var HSB3SBar = 0;
var HSB3SPrice = 0;
var HSB3EBar = 0;
var HSB3EPrice = 0;
var HSB3Factor = 0;
var HSB3PlotPrice = 0;
var HSB4SBar = 0;
var HSB4SPrice = 0;
var HSB4EBar = 0;
var HSB4EPrice = 0;
var HSB4Factor = 0;
var HSB4PlotPrice = 0;
var HSB5SBar = 0;
var HSB5SPrice = 0;
var HSB5EBar = 0;
var HSB5EPrice = 0;
var HSB5Factor = 0;
var HSB5PlotPrice = 0;

var LSB1SBar = 0;
var LSB1SPrice = 0;
var LSB1EBar = 0;
var LSB1EPrice = 0;
var LSB1Factor = 0;
var LSB1PlotPrice;
var LSB2SBar = 0;
var LSB2SPrice = 0;
var LSB2EBar = 0;
var LSB2EPrice = 0;
var LSB2Factor = 0;
var LSB2PlotPrice;
var LSB3SBar = 0;
var LSB3SPrice = 0;
var LSB3EBar = 0;
var LSB3EPrice = 0;
var LSB3Factor = 0;
var LSB3PlotPrice;
var LSB4SBar = 0;
var LSB4SPrice = 0;
var LSB4EBar = 0;
var LSB4EPrice = 0;
var LSB4Factor = 0;
var LSB4PlotPrice;
var LSB5SBar = 0;
var LSB5SPrice = 0;
var LSB5EBar = 0;
var LSB5EPrice = 0;
var LSB5Factor = 0;
var LSB5PlotPrice;

function preMain() {
  setStudyTitle("BL Trendlines (R2)");
  setCursorLabelName("BLTrends");
  //    setStudyMin(-10);
  //    setStudyMax(10);
  //    setPlotType(PLOTTYPE_HISTOGRAM);

  setPriceStudy(true);
  //setColorPriceBars(true);
  //setDefaultPriceBarColor(Color.black);
}

function main() {
  //    var study = new MAStudy(Filter1, 0, "Close", MAStudy.WEIGHTED);

  setComputeOnClose(true);

  var BarPointer;
  var nBars = 10;
  var LSBScannedLow;
  var HSBScannedHigh;
  var LSBsignal = 0;
  var HSBsignal = 0;
  var vOpen;
  var vHigh;
  var vLow;
  var vClose;

  vOpen = getValue("Open", 0, -nBars);
  vHigh = getValue("High", 0, -nBars);
  vLow = getValue("Low", 0, -nBars);
  vClose = getValue("Close", 0, -nBars);

  if (getValue("rawtime", getCurrentBarIndex()) != nLastRawTime) {
    nLastRawTime = getValue("rawtime", getCurrentBarIndex());
    BLBarOffset += 1;
  }

  //debugPrintln("Time " + getValue("rawtime", getCurrentBarIndex() +i, 0));
  //debugPrintln("Open(1) " + vOpen);

  LSBsignal = 0;
  HSBsignal = 0;

  //  Scan for HSB / LSB...
  //    for(i = 0; i <= 4; i++) {
  //  Test for bearish candlestick signals
  //     if (vClose[0] > study.getValue(MAStudy.MA)) {

  //      debugPrintln("Pre:" + LSBCount + ":" + BLBarOffset + ":" + TrackCurrentLSB);

  /*
      // LSB Pivot - 5 bar
        if((BLBarOffset >= 5) && (LSBsignal == 0) && (vLow[4] >= vLow[3]) && (vLow[2] > vLow[3]) && (vLow[1] > vLow[3]) && (vLow[0] > vLow[3]) )
        {
//           debugPrintln("Time:" + getValue("rawtime", 0 - i) + "  LTime:" + nLastRawTime);
           LSBScannedLow = low();
           BarPointer = 0;
           if (low(-1) > LSBScannedLow) {
             LSBScannedLow = low(-1);
             BarPointer = 1;
           }
           if (low(-2) > LSBScannedLow) {
             LSBScannedLow = low(-2);
             BarPointer = 2;
           }
           LSBsignal = 1;
          if (TrackCurrentLSB == false) {
           if (LSBCount < 5) {
             LSBCount += 1;
           }
           TrackCurrentLSB = true;
           Add_TL(BLBarOffset-3, low(-3), BLBarOffset-BarPointer, LSBScannedLow, -1, LSBCount);
          } else {
           Update_TL(BLBarOffset-BarPointer, LSBScannedLow, -1, LSBCount);
          }
        }
*/

  // LSB Pivot - 4 bar
  if (
    BLBarOffset >= 5 &&
    LSBsignal == 0 &&
    vLow[3] >= vLow[2] &&
    vLow[1] > vLow[2] &&
    vLow[0] > vLow[2]
  ) {
    //           debugPrintln("Time:" + getValue("rawtime", 0 - i) + "  LTime:" + nLastRawTime);
    LSBScannedLow = low();
    BarPointer = 0;
    if (low(-1) > LSBScannedLow) {
      LSBScannedLow = low(-1);
      BarPointer = 1;
    }
    LSBsignal = 1;
    if (TrackCurrentLSB == false) {
      if (LSBCount < 5) {
        LSBCount += 1;
      }
      TrackCurrentLSB = true;
      Add_TL(
        BLBarOffset - 2,
        low(-2),
        BLBarOffset - BarPointer,
        LSBScannedLow,
        -1,
        LSBCount
      );
    } else {
      Update_TL(BLBarOffset - BarPointer, LSBScannedLow, -1, LSBCount);
    }
  }
  // LSB Pivot - 3 bar
  if (
    BLBarOffset >= 5 &&
    LSBsignal == 0 &&
    vLow[2] >= vLow[1] &&
    vLow[0] > vLow[1]
  ) {
    //           debugPrintln("Time:" + getValue("rawtime", 0 - i) + "  LTime:" + nLastRawTime);
    LSBsignal = 1;
    if (TrackCurrentLSB == false) {
      if (LSBCount < 5) {
        LSBCount += 1;
      }
      TrackCurrentLSB = true;
      Add_TL(BLBarOffset - 1, low(-1), BLBarOffset, low(), -1, LSBCount);
    } else {
      Update_TL(BLBarOffset, low(), -1, LSBCount);
    }
  }
  if (LSBsignal == 0) {
    TrackCurrentLSB = false;
  }

  //-----------  HSB  ------------------------------------
  /*
      // HSB Pivot - 5 bar
        if((BLBarOffset >= 5) && (HSBsignal == 0) && (vHigh[4] <= vHigh[3]) && (vHigh[2] < vHigh[3]) && (vHigh[1] < vHigh[3]) && (vHigh[0] < vHigh[3]) )
        {
//           debugPrintln("Time:" + getValue("rawtime", 0 - i) + "  LTime:" + nLastRawTime);
           LSBScannedLow = high();
           BarPointer = 0;
           if (high(-1) < LSBScannedLow) {
             LSBScannedLow = high(-1);
             BarPointer = 1;
           }
           if (high(-2) < LSBScannedLow) {
             LSBScannedLow = high(-2);
             BarPointer = 2;
           }
           HSBsignal = 1;
          if (TrackCurrentHSB == false) {
           if (HSBCount < 5) {
             HSBCount += 1;
           }
           TrackCurrentHSB = true;
           Add_TL(BLBarOffset-3, high(-3), BLBarOffset-BarPointer, LSBScannedLow, 1, HSBCount);
          } else {
           Update_TL(BLBarOffset-BarPointer, LSBScannedLow, 1, HSBCount);
          }
        }
*/

  // LSB Pivot - 4 bar
  if (
    BLBarOffset >= 5 &&
    HSBsignal == 0 &&
    vHigh[3] <= vHigh[2] &&
    vHigh[1] < vHigh[2] &&
    vHigh[0] < vHigh[2]
  ) {
    //           debugPrintln("Time:" + getValue("rawtime", 0 - i) + "  LTime:" + nLastRawTime);
    LSBScannedLow = high();
    BarPointer = 0;
    if (high(-1) < LSBScannedLow) {
      LSBScannedLow = high(-1);
      BarPointer = 1;
    }
    LSBsignal = 1;
    if (TrackCurrentHSB == false) {
      if (HSBCount < 5) {
        HSBCount += 1;
      }
      TrackCurrentHSB = true;
      Add_TL(
        BLBarOffset - 2,
        high(-2),
        BLBarOffset - BarPointer,
        LSBScannedLow,
        1,
        HSBCount
      );
    } else {
      Update_TL(BLBarOffset - BarPointer, LSBScannedLow, 1, HSBCount);
    }
  }
  // LSB Pivot - 3 bar
  if (
    BLBarOffset >= 5 &&
    HSBsignal == 0 &&
    vHigh[2] <= vHigh[1] &&
    vHigh[0] < vHigh[1]
  ) {
    //           debugPrintln("Time:" + getValue("rawtime", 0 - i) + "  LTime:" + nLastRawTime);
    HSBsignal = 1;
    if (TrackCurrentHSB == false) {
      if (HSBCount < 5) {
        HSBCount += 1;
      }
      TrackCurrentHSB = true;
      Add_TL(BLBarOffset - 1, high(-1), BLBarOffset, high(), 1, HSBCount);
    } else {
      Update_TL(BLBarOffset, high(), 1, HSBCount);
    }
  }
  if (HSBsignal == 0) {
    TrackCurrentHSB = false;
  }

  Plot_TL();
  return;
}

Closing

The best way to show users of eSignal how to deploy graphics within theirtrading strategy is to give them a working example. To this extent, I haveincluded a working example of a Moving Average Crossover system that includesthe following features

  1. Crossover entry signals - displayed with a GREEEN UPARROWs and REDDOWNARROWs on the chart and includes the "Strategy" functions for backtesting.
  2. User-Defined Trailing Stop Levels - displayed with BLUE DIAMONDS on the chartand includes the "Strategy" functions for back testing.
  3. User-Defined Profit Target Levels - displayed with MAGENTA ARROWS on thechart and includes the "Strategy" functions for back testing.
  4. Multiple Profit Target levels and stages.
  5. Variable entry price options (Open,High,Low,Close).
  6. Stop Level ON/OFF Switch
  7. Profit Target ON/OFF Switch.
  8. User-Input variables for controlling the Moving Average settings.

This code has been developed for use on "Historical data" and wouldneed to be modified to develop a real-time trading system. We'll get into thatin the next guide - the "Guide to Developing Real-Time Trading Strategiesin eSignal". There are subtle changes that need to be made to the code inorder for it to operate properly in a tick-by-tick environment.

The examples included within this code will clearly show you how to developyour own system using the graphics functions as well as some advanced topics(such as profit targets, stop levels, on/off switches, user inputs and manymore). Essentially, users can modify this code to include their own entrytriggers and test with. It is a blueprint of a functional system thatincorporates many of the advanced features within eSignal.

I assume some of you may have questions. If so, please email Bmatheny@ment.comwith your comments so I can try to help you.

Download Formula:  Ment-Ma-X_System.efs

/*******************************************************************
Description : Moving Average Analysis System.
Provided By : Matheny Enterprises (www.ment.com)
********************************************************************/
//  User Defined System Variables
var vStartHour = 06;
var vStartMin = 26;
var vEndHour = 12;
var vEndMin = 58;
///  ---  Entry Variable Options.
var DefEntryContracts = 500;
var Exit1Contracts = 200;
var Exit2Contracts = 200;
///  ---  Stop Variable Options.
var Stopsswitch = 1; //  0=OFF / 1=ON  -  NOT USED!!
var StopOffset = 0.5;
//var nEntryBarCount = 0;
///  ---  Profit Target Options.
var ProfitTargetswitch = 1; //  0=OFF / 1=ON
var ProfitTarget1 = 1.25;
var ProfitTarget2 = 2.5;
/*---------------------------------------------------------
Entry Options.....
Setting:
     0 = OPEN OF NEXT BAR
     1 = HIGH +/- EntryOffset
     2 = LOW +/- EntryOffset
     3 = CLOSE +/- EntryOffset
---------------------------------------------------------*/
var LongEntryOption = 1;
var ShortEntryOption = 2;
/*---------------------------------------------------------
Entry Offset Option.....
Enter the amount you want to offset the entry for LONG &
SHORT entry signals.
For example : if LongEntryOption is set to 1 and LongEntryOffset
is set to 0.50, then the system will set a limit order to enter
1/2 point above the current HIGH (if breached).
---------------------------------------------------------*/
var LongEntryOffset = 0.25;
var ShortEntryOffset = 0.25;

// ---------------------   NOTICE !!!!! ---------------------------------
//  DO NOT CHANGE ANY OF THE VARIABLES BELOW THIS LINE...
var ProfitTargetStage; // 0=new trade, 1 = stage 1 complete, 2 = stage 2 complete
var EntryTargetPrice;
var TradeType; // 0= Neutral, 1 = BULLISH, 2 = BEARISH

//  System Variables...
var MAtrend = 0;
var lastMA13;
var lastMA2;
var nLastRawTime = 0;
var nNewTrade; // 1 = Execute New Trade, 0 = No New Trade To Execute
var signal; // this is a text variable
var nsignal; // the numeric value of the signal (0=neutral, -1 = bearish, 1 = bullish)

//  Stop Variables....
var nStopStage; //  1 = Stage 1, 2 = Stage 2, 3 = Stage 3
var nStopPrice;
var nTradeEntryPrice;
var nEntryBarCount;

var mAvg13 = null;
var mAvg2 = null;

function preMain() {
  setPriceStudy(true);
  setStudyTitle("MENT MAX Analysis System V1.01a");
  setCursorLabelName("Signal", 0);
  setCursorLabelName("Stop", 1);
}

function main(vmAVG13, vmAVG2, vSCOC, vPLOTARROWS) {
  /*---------------------------------------------------/*
 Set Default Variables for User Inputs...
MODIFY any of the variables below - only adjust the variables in
RED color.  Do not adjust anything below the line that reads
---- [ END OF USER VARIABLES ]-----
-----------------------------------------------------*/
  if (vmAVG13 == null) {
    vmAVG13 = 18;
  }
  if (vmAVG2 == null) {
    vmAVG2 = 3;
  }
  if (vSCOC == null) {
    vSCOC = 1; // 1 = ON , 0 = OFF
  }
  if (vPLOTARROWS == null) {
    vPLOTARROWS = 1; // 1 = ON , 0 = OFF
  }
  /*------------------------------------------------------
     ----------[ END OF USER VARIABLES ]------------
------------------------------------------------------*/

  //---------------------------------------------------
  //  SET COMPUTE ON CLOSE OPTION...
  if (vSCOC == 1) {
    setComputeOnClose(true);
  }

  //---------------------------------------------------
  //  Define System Variables...
  var vUpCount = 0;
  var vDownCount = 0;
  var vTime = new Date();
  var vHour;
  var vMin;

  //---------------------------------------------------
  //  Get Time Variables
  vTime = getValue("Time", 0);
  vHour = vTime.getHours();
  vMin = vTime.getMinutes();

  //---------------------------------------------------
  //  ---->  Trade Entry Configuration....
  //  Places variable entry trades and sets variables.
  //---------------------------------------------------
  if (
    (vHour > vStartHour && vHour < vEndHour) ||
    (vHour == vStartHour && vMin >= vStartMin) ||
    (nNewTrade == 1 && vHour == vEndHour && vMin <= vEndMin)
  ) {
    //Execute New Trade
    if (Strategy.isInTrade() == false) {
      if (LongEntryOption == 0 || ShortEntryOption == 0) {
        // Handle all MARKET Orders
        nTradeEntryPrice = open();
        ProfitTargetStage = 0;
        EntryTargetPrice = 0;
      }
      if (EntryTargetPrice > 0 && TradeType == 2) {
        // Shorts
        if (
          ShortEntryOption >= 1 &&
          high() >= EntryTargetPrice &&
          low() <= EntryTargetPrice
        ) {
          if (high() < EntryTargetPrice) {
            Strategy.doShort(
              "SE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              open()
            );
          } else {
            Strategy.doShort(
              "SE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              EntryTargetPrice
            );
          }
          nTradeEntryPrice = EntryTargetPrice;
          ProfitTargetStage = 0;
          EntryTargetPrice = 0;
        }
      }
      if (EntryTargetPrice > 0 && TradeType == 1) {
        if (
          LongEntryOption >= 1 &&
          low() <= EntryTargetPrice &&
          high() >= EntryTargetPrice
        ) {
          if (low() > EntryTargetPrice) {
            Strategy.doLong(
              "LE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              open()
            );
          } else {
            Strategy.doLong(
              "LE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              EntryTargetPrice
            );
          }
          nTradeEntryPrice = EntryTargetPrice;
          ProfitTargetStage = 0;
          EntryTargetPrice = 0;
        }
      }
    } else {
      //  Is In Trade
      if (LongEntryOption == 0 || ShortEntryOption == 0) {
        // Handle all MARKET Orders
        nTradeEntryPrice = open();
        ProfitTargetStage = 0;
        EntryTargetPrice = 0;
      }
      if (EntryTargetPrice > 0 && TradeType == 2) {
        // Shorts
        if (
          ShortEntryOption >= 1 &&
          high() >= EntryTargetPrice &&
          low() <= EntryTargetPrice
        ) {
          if (high() < EntryTargetPrice) {
            Strategy.doSell(
              "LE.Exit",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              open()
            );
            Strategy.doShort(
              "SE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              open()
            );
          } else {
            Strategy.doSell(
              "LE.Exit",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              EntryTargetPrice
            );
            Strategy.doShort(
              "SE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              EntryTargetPrice
            );
          }
          nTradeEntryPrice = EntryTargetPrice;
          ProfitTargetStage = 0;
          EntryTargetPrice = 0;
          TradeType = 0;
        }
      }
      if (EntryTargetPrice > 0 && TradeType == 1) {
        // Longs
        if (
          LongEntryOption >= 1 &&
          low() <= EntryTargetPrice &&
          high() >= EntryTargetPrice
        ) {
          if (low() > EntryTargetPrice) {
            Strategy.doCover(
              "SE.Exit",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              open()
            );
            Strategy.doLong(
              "LE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              open()
            );
          } else {
            Strategy.doCover(
              "SE.Exit",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              EntryTargetPrice
            );
            Strategy.doLong(
              "LE.Entry",
              Strategy.LIMIT,
              Strategy.THISBAR,
              DefEntryContracts,
              EntryTargetPrice
            );
          }
          nTradeEntryPrice = EntryTargetPrice;
          ProfitTargetStage = 0;
          EntryTargetPrice = 0;
          TradeType = 0;
        }
      }
    } //  If in TRADE == FALSE
  } // If within TIME restrictions

  setDefaultBarFgColor(Color.black, 1);
  //---------------------------------------------------
  //  ---->  SET/TEST STOPS
  //---------------------------------------------------
  if (Stopsswitch == 1) {
    //  Stops turned ON
    if (Strategy.isInTrade() == true) {
      //  Build Testing Variables
      // Calculate Total Higher Lows/Lower High
      var i;
      var nLastLSB = 0;
      var nLastHSB = 0;
      var nLSBSet = 0;
      var nHSBSet = 0;
      //  Calculate ASL Low variables...
      for (i = 0; i >= -20; i--) {
        if (
          (nHSBSet == 0 &&
            high(i) < high(i - 1) &&
            high(i - 2) < high(i - 1)) ||
          (nHSBSet == 0 &&
            high(i) == high(i - 1) &&
            high(i - 2) < high(i - 1)) ||
          (nHSBSet == 0 && high(i) == high(i - 1))
        ) {
          nLastHSB = high(i - 1) + StopOffset;
          nHSBSet = 1;
        }
        if (
          (nLSBSet == 0 && low(i) > low(i - 1) && low(i - 2) > low(i - 1)) ||
          (nLSBSet == 0 && low(i) == low(i - 1) && low(i - 2) > low(i - 1)) ||
          (nLSBSet == 0 && low(i) == low(i - 1))
        ) {
          nLastLSB = low(i - 1) - StopOffset;
          nLSBSet = 1;
        }
      } // END OF FOR LOOP
      // Set Stop Level
      if (
        (vHour > vStartHour && vHour < vEndHour) ||
        (vHour == vStartHour && vMin >= vStartMin) ||
        (vHour == vEndHour && vMin <= vEndMin)
      ) {
        //Execute New Stop
        if (Strategy.isShort() == true) {
          // SET SHORT STOPS
          nStopPrice = nLastHSB;
          setDefaultBarFgColor(Color.red, 1);
          drawShapeRelative(
            0,
            nStopPrice,
            Shape.DIAMOND,
            null,
            Color.red,
            Shape.ONTOP,
            getValue("rawtime") + "SS"
          );
        }
        if (Strategy.isLong() == true) {
          // SET LONG STOPS
          nStopPrice = nLastLSB;
          setDefaultBarFgColor(Color.blue, 1);
          drawShapeRelative(
            0,
            nStopPrice,
            Shape.DIAMOND,
            null,
            Color.blue,
            Shape.ONTOP,
            getValue("rawtime") + "LS"
          );
        }
      } //  if within TIME restrictions.
    } // if within a trade
  } //  End if Stopsswitch == 1

  //  Test for Profit Targets
  if (ProfitTargetswitch == 1) {
    // Profit Target Turned ON
    if (Strategy.isInTrade() == true) {
      if (
        Strategy.isShort() == true &&
        ProfitTargetStage == 1 &&
        low() <= nTradeEntryPrice - ProfitTarget2
      ) {
        ProfitTargetStage += 1;
        Strategy.doCover(
          "SE.PT2.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          Exit2Contracts,
          nTradeEntryPrice - ProfitTarget2
        );
        drawShapeRelative(
          0,
          low() - 1.25,
          Shape.UPARROW,
          null,
          Color.magenta,
          Shape.ONTOP,
          getValue("rawtime") + "B"
        );
      }
      if (
        Strategy.isShort() == true &&
        ProfitTargetStage == 0 &&
        low() <= nTradeEntryPrice - ProfitTarget2
      ) {
        ProfitTargetStage += 2;
        Strategy.doCover(
          "SE.PT1+2.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          Exit1Contracts + Exit2Contracts,
          nTradeEntryPrice - ProfitTarget2
        );
        drawShapeRelative(
          0,
          low() - 1.25,
          Shape.UPARROW,
          null,
          Color.magenta,
          Shape.ONTOP,
          getValue("rawtime") + "B"
        );
      }
      if (
        Strategy.isShort() == true &&
        ProfitTargetStage <= 0 &&
        low() <= nTradeEntryPrice - ProfitTarget1
      ) {
        ProfitTargetStage += 1;
        Strategy.doCover(
          "SE.PT1.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          Exit1Contracts,
          nTradeEntryPrice - ProfitTarget1
        );
        drawShapeRelative(
          0,
          low() - 1.25,
          Shape.UPARROW,
          null,
          Color.blue,
          Shape.ONTOP,
          getValue("rawtime") + "B"
        );
      }
      //  Long profit targets
      if (
        Strategy.isLong() == true &&
        ProfitTargetStage == 1 &&
        high() >= nTradeEntryPrice + ProfitTarget2
      ) {
        ProfitTargetStage += 1;
        Strategy.doSell(
          "LE.PT2.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          Exit2Contracts,
          nTradeEntryPrice + ProfitTarget2
        );
        drawShapeRelative(
          0,
          high() + 1.25,
          Shape.DOWNARROW,
          null,
          Color.magenta,
          Shape.ONTOP,
          getValue("rawtime") + "B"
        );
      }
      if (
        Strategy.isLong() == true &&
        ProfitTargetStage == 0 &&
        high() >= nTradeEntryPrice + ProfitTarget2
      ) {
        ProfitTargetStage += 2;
        Strategy.doSell(
          "LE.PT1+2.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          Exit1Contracts + Exit2Contracts,
          nTradeEntryPrice + ProfitTarget2
        );
        drawShapeRelative(
          0,
          high() + 1.25,
          Shape.DOWNARROW,
          null,
          Color.magenta,
          Shape.ONTOP,
          getValue("rawtime") + "B"
        );
      }
      if (
        Strategy.isLong() == true &&
        ProfitTargetStage <= 0 &&
        high() >= nTradeEntryPrice + ProfitTarget1
      ) {
        ProfitTargetStage += 1;
        Strategy.doSell(
          "LE.PT1.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          Exit1Contracts,
          nTradeEntryPrice + ProfitTarget1
        );
        drawShapeRelative(
          0,
          high() + 1.25,
          Shape.DOWNARROW,
          null,
          Color.blue,
          Shape.ONTOP,
          getValue("rawtime") + "B"
        );
      }
    }
  } //  End ProfitTargetswitch == 1

  if (Stopsswitch == 1) {
    //  Stops turned ON
    var StopExitContracts;
    var StopFilled = 0; // Logical
    if (ProfitTargetStage == 2) {
      StopExitContracts = DefEntryContracts - (Exit1Contracts + Exit2Contracts);
    }
    if (ProfitTargetStage == 1) {
      StopExitContracts = DefEntryContracts - Exit1Contracts;
    }
    if (ProfitTargetStage == 0) {
      StopExitContracts = DefEntryContracts;
    }
    //  Test for STOP breaches
    if (Strategy.isInTrade() == true) {
      if (
        Strategy.isShort() == true &&
        high() >= nStopPrice &&
        StopFilled == 0
      ) {
        Strategy.doCover(
          "SE.Stop.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          StopExitContracts,
          nStopPrice
        );
        StopFilled = 1;
        Strategy.doLong(
          "LE.SR.Entry",
          Strategy.LIMIT,
          Strategy.THISBAR,
          DefEntryContracts,
          nStopPrice
        );
        drawShapeRelative(
          0,
          low() - 1.25,
          Shape.UPARROW,
          null,
          Color.blue,
          Shape.ONTOP,
          getValue("rawtime") + "SR"
        );
      }
      if (Strategy.isLong() == true && low() <= nStopPrice && StopFilled == 0) {
        Strategy.doSell(
          "LE.Stop.Exit",
          Strategy.STOP,
          Strategy.THISBAR,
          StopExitContracts,
          nStopPrice
        );
        StopFilled = 1;
        Strategy.doShort(
          "SE.SR.Entry",
          Strategy.LIMIT,
          Strategy.THISBAR,
          DefEntryContracts,
          nStopPrice
        );
        drawShapeRelative(
          0,
          high() + 1.25,
          Shape.DOWNARROW,
          null,
          Color.blue,
          Shape.ONTOP,
          getValue("rawtime") + "SR"
        );
      }
    } //  within a trade.
  } //  End if Stopsswitch == 1
  //---------------------------------------------------
  //  ---->  END SET/TEST STOPS
  //---------------------------------------------------

  //---------------------------------------------------
  //  Moving Averave Variables
  if (mAvg13 == null) {
    mAvg13 = new MAStudy(vmAVG13, 0, "Close", MAStudy.EXPONENTIAL);
  }
  if (mAvg2 == null) {
    mAvg2 = new MAStudy(vmAVG2, 0, "Close", MAStudy.SIMPLE);
  }

  /*-------------------------------------------------------------
Set the "last" values to the current values.  These "last" values
will be passed onto the next bar on the chart
---------------------------------------------------------------*/
  if (getValue("rawtime", 0) != nLastRawTime) {
    nLastRawTime = getValue("rawtime", 0);
  }

  //---------------------------------------------------
  //--[  Return MA Values  ]-------------------------------
  var MA13 = mAvg13.getValue(MAStudy.MA);
  var MA2 = mAvg2.getValue(MAStudy.MA);
  lastMA13 = mAvg13.getValue(MAStudy.MA, -1);
  lastMA2 = mAvg2.getValue(MAStudy.MA, -1);
  //--[  END Return MA Values  ]---------------------------

  //---------------------------------------------------
  //  Calculate and plot BUY/SELL signals...
  if (MAtrend == 0) {
    nsignal = 0;
    signal = "Neutral";
    setDefaultBarFgColor(Color.magenta, 0);
  }

  if (MAtrend == 1 && MA2 > MA13 && lastMA2 < lastMA13) {
    //  TSI Trend is Bullish - now switch to bearish.
    MAtrend = -1; // bearish
    nNewTrade = 1;
    nsignal = -1;
    signal = "Bearish";
    setDefaultBarFgColor(Color.red, 0);
  }
  if (MAtrend == -1 && MA2 < MA13 && lastMA2 > lastMA13) {
    //  TSI Trend is Bearish - now switch to bullish.
    MAtrend = 1; // bullish
    nNewTrade = 1;
    nsignal = 1;
    signal = "Bullish";
    setDefaultBarFgColor(Color.green, 0);
  }

  //  ESTABLISH NEW TSI TREND DIRECTION - if NONE.
  if (MAtrend == 0 && MA2 < MA13 && lastMA2 > lastMA13) {
    //  NEW TSI Trend is Bearish.
    MAtrend = -1; // bearish
    nNewTrade = 1;
    nsignal = -1;
    signal = "Bearish";
    setDefaultBarFgColor(Color.red, 0);
  }
  if (MAtrend == 0 && MA2 > MA13 && lastMA2 < lastMA13) {
    //  NEW TSI Trend is Bullish.
    MAtrend = 1; // bullish
    nNewTrade = 1;
    nsignal = 1;
    signal = "Bullish";
    setDefaultBarFgColor(Color.green, 0);
  }

  //---------------------------------------------------
  //  Execute Trades within TIME restrictions ....
  if (
    (vHour > vStartHour && vHour < vEndHour) ||
    /*(nNewTrade == 1) && */ (vHour == vStartHour && vMin >= vStartMin) ||
    /*(nNewTrade == 1) && */ (vHour == vEndHour && vMin <= vEndMin)
  ) {
    //Execute New Trade
    if (nNewTrade == 1) {
      // new or reversed trade position
      if (Strategy.isInTrade() == true) {
        if (nsignal > 0 && Strategy.isShort() == true) {
          drawShapeRelative(
            0,
            low() - 1.25,
            Shape.UPARROW,
            null,
            Color.green,
            Shape.ONTOP,
            getValue("rawtime") + "B"
          );
          nNewTrade = 0;
          if (LongEntryOption == 0) {
            Strategy.doLong(
              "Go Long",
              Strategy.MARKET,
              Strategy.NEXTBAR,
              DefEntryContracts
            );
            ProfitTargetStage = 0;
            TradeType = 1;
          }
          if (LongEntryOption == 1) {
            EntryTargetPrice = high() + LongEntryOffset;
            TradeType = 1;
          }
          if (LongEntryOption == 2) {
            EntryTargetPrice = low() + LongEntryOffset;
            TradeType = 1;
          }
          if (LongEntryOption == 3) {
            EntryTargetPrice = close() + LongEntryOffset;
            TradeType = 1;
          }
        }
        if (nsignal < 0 && Strategy.isLong() == true) {
          nNewTrade = 0;
          drawShapeRelative(
            0,
            high() + 1.25,
            Shape.DOWNARROW,
            null,
            Color.red,
            Shape.ONTOP,
            getValue("rawtime") + "S"
          );
          if (ShortEntryOption == 0) {
            Strategy.doShort(
              "Go Short",
              Strategy.MARKET,
              Strategy.NEXTBAR,
              DefEntryContracts
            );
            ProfitTargetStage = 0;
            TradeType = 2;
          }
          if (ShortEntryOption == 1) {
            EntryTargetPrice = high() - ShortEntryOffset;
            TradeType = 2;
          }
          if (ShortEntryOption == 2) {
            EntryTargetPrice = low() - ShortEntryOffset;
            TradeType = 2;
          }
          if (ShortEntryOption == 3) {
            EntryTargetPrice = close() - ShortEntryOffset;
            TradeType = 2;
          }
        }
      } else {
        if (nsignal > 0) {
          nNewTrade = 0;
          drawShapeRelative(
            0,
            low() - 1.25,
            Shape.UPARROW,
            null,
            Color.green,
            Shape.ONTOP,
            getValue("rawtime") + "B"
          );
          if (LongEntryOption == 0) {
            Strategy.doLong(
              "Go Long",
              Strategy.MARKET,
              Strategy.NEXTBAR,
              DefEntryContracts
            );
            ProfitTargetStage = 0;
            TradeType = 1;
          }
          if (LongEntryOption == 1) {
            EntryTargetPrice = high() + LongEntryOffset;
            TradeType = 1;
          }
          if (LongEntryOption == 2) {
            EntryTargetPrice = low() + LongEntryOffset;
            TradeType = 1;
          }
          if (LongEntryOption == 3) {
            EntryTargetPrice = close() + LongEntryOffset;
            TradeType = 1;
          }
        }
        if (nsignal < 0) {
          nNewTrade = 0;
          drawShapeRelative(
            0,
            high() + 1.25,
            Shape.DOWNARROW,
            null,
            Color.red,
            Shape.ONTOP,
            getValue("rawtime") + "S"
          );
          if (ShortEntryOption == 0) {
            Strategy.doShort(
              "Go Short",
              Strategy.MARKET,
              Strategy.NEXTBAR,
              DefEntryContracts
            );
            TradeType = 2;
          }
          if (ShortEntryOption == 1) {
            EntryTargetPrice = high() - ShortEntryOffset;
            TradeType = 2;
          }
          if (ShortEntryOption == 2) {
            EntryTargetPrice = low() - ShortEntryOffset;
            TradeType = 2;
          }
          if (ShortEntryOption == 3) {
            EntryTargetPrice = close() - ShortEntryOffset;
            TradeType = 2;
          }
        }
      } //  end if IN TRADE
    } // END IF NEW TRADE
  } //  END WITHIN TIME RESTRICTIONS

  //---------------------------------------------------
  //  Close any OPEN trades after ENDTIME ....
  if (ProfitTargetStage == 2) {
    StopExitContracts = DefEntryContracts - (Exit1Contracts + Exit2Contracts);
  }
  if (ProfitTargetStage == 1) {
    StopExitContracts = DefEntryContracts - Exit1Contracts;
  }
  if (ProfitTargetStage == 0) {
    StopExitContracts = DefEntryContracts;
  }
  if (vHour > vEndHour || (vHour == vEndHour && vMin >= vEndMin)) {
    //Close all OPEN Trades
    if (Strategy.isInTrade() == true) {
      if (Strategy.isShort() == true) {
        Strategy.doCover(
          "Close Short EOD",
          Strategy.MARKET,
          Strategy.NEXTBAR,
          StopExitContracts
        );
        ProfitTargetStage = 0;
        nStopStage = 0;
        nEntryBarCount = 0;
        EntryTargetPrice = 0;
        TradeType = 0;
      }
      if (Strategy.isLong() == true) {
        Strategy.doSell(
          "Close Long EOD",
          Strategy.MARKET,
          Strategy.NEXTBAR,
          StopExitContracts
        );
        ProfitTargetStage = 0;
        nStopStage = 0;
        nEntryBarCount = 0;
        EntryTargetPrice = 0;
        TradeType = 0;
      }
    }
  } //  END CLOSE OPEN TRADES

  //---------------------------------------------------
  //  Return the values...
  //  Uncomment the line below to return the "change" values...
  if (Stopsswitch == 1) {
    return new Array(signal, nStopPrice);
  } else {
    return new Array(signal);
  }
}
Graphics System Tips.
  • Use TEXT graphics for unique entry/exit triggers or for specific commentsyou wish to see on the chart.
  • Use SHAPE graphics for most common entry, stop, profit target and exitsignals.
  • Use IMAGE graphics for specific "conditional" or"reminder" actions within your code. For example, you might put a"smiley face" when you take profits on a trade.
  • Graphics functions should be placed just below (after) any strategy functions- as strategy functions generate trading actions, the graphics functions SHOWtrading actions.
  • Trend Lines are for more advanced users of eSignal as they require moredetailed programming knowledge.
  • Create color-coded schemes for all your trading systems - this help tostandardize on a set of graphics and colors.
  • Use the color.RGB() function to create custom colors and custom coloredbackgrounds.
  • Combine setBarBGColor with other graphic functions to a more dramatic visualeffect.