Plotting Directly From Within Strategies

When a strategy is using a custom indicator or custom function to calculate values for limit and stop orders, it is often desirable to plot the custom indicator on the same chart used by the strategy. This allows the user to verify that trades are occurring at the appropriate levels, since the trade signals generated by the strategy can be compared to the indicator values on the chart.

Here is an example of a reversion to the mean trading strategy that has a custom RibbonsPlotter indicator plotting a linear regression center line and deviation ribbons spaced ATR multiples away from the center line.

Fig. 1. Custom Indicator Inserted Into Strategy Chart.

To make the values of the RibbonPlotter indicator available to the strategy, one could duplicate the custom indicator code within the strategy. However, code duplication creates additional work when modifying and improving the code as changes have to be made in two places. Debugging code in two places and ensuring that both copies of the code are generating the same values increases the programming work required.

This duplication of code can be avoided by packaging the custom indicator code into a function that can then be called by both the indicator and the strategy. This simplifies updates to the custom code in that it only has to be modified at a single location, within the function code module.

To ensure that the custom indicator and strategy are referencing the same custom function values, both the indicator input parameters and the strategy input parameters must be maintained in sync by the user. Some custom indicators involve entering many parameters. It is tedious for the user to continually have to check the input parameters of both the indicator and the strategy to verify that they are the same. Having to do so leaves the trading system vulnerable to inadvertent errors if the input parameters become out of sync.

Each time the strategy is optimized and the optimal input parameters values are adopted by the strategy, the indicator input parameters must be updated by the user to match these. This requires opening the strategy formatting window to see what the optimized parameters are, then opening the indicator formatting window and copying all of these values into the corresponding input variables, and finally, closing both formatting windows.

Life would be so much simpler if the strategy could plot the custom indicator directly from within the strategy code. If that were possible, it would also ensure the each time the strategy were optimized, the optimized values of the input parameters would be correctly plotted superimposed on the trading signals on the chart. This makes it much easier to visually verify that the trades were being made at appropriate price levels.

Unfortunately, Plot[n] statements cannot be used from within a strategy. It may only be used within an indicator. Therefore, an alternate method of generating plots from within a strategy is needed. Fortunately, trend lines CAN be drawn from within a strategy providing a solution to the dilemma.

The TLPlot function, described below, reproduces the functionality of the Plot[n] statement creating a series of trend line segments to produce the plot. Such trend line plots can be formatted as solid, dotted and or various dashed lines in any color specified by the user.

Since the plotting is being done from within the strategy, the need for the user to keep indicator input parameters and strategy input parameters in sync is eliminated. Each time the strategy is optimized, the new optimized input parameters are automatically plotted correctly without further user intervention.

This next chart shows plotting directly from the strategy, using the TLPlot function:

Fig. 2. BuyLimit, SellLimit, BuyStop and SellStop values being plotted directly from strategy using TLPlot.

A second benefit arises from plotting from within the strategy. You will notice that the second screen shot above differs somewhat from the first screen shot, which used a custom indicator to perform plotting. When plotting from within the strategy, instead of plotting the custom function values, you can plot the BuyLimit, SellLimit, BuyStop and SellStop order values assigned to these function values. The benefit is that you not only see the function values, to confirm they are accurate, but you also see the strategy logic manipulating the BuyLimit, SellLimit, BuyStop and SellStop levels.

For example, when a trade is taken in the long direction, a protective stop is automatically placed a certain ATR multiple below the BuyLimit entry value. This value must be held constant during the trade, rather than continue to recalculate with each bar, as the custom indicator in the first screen above is doing. Notice that outer cyan lines representing the stop loss levels are held constant once a long or short position is taken (yellow arrows). When the trade closes, either by stopping out, or by reaching a profit target the out cyan stop loss levels once again resumes the values of the displacement function.

Therefore, the additional benefit of being able to plot from within the strategy is not only to see that the Buy/Sell values are correct and that trades are actually occurring at these values, but one can also see that the logic of the strategy has been programmed correctly. It would not be possible to see if the strategy was holding the stop loss constant during a trade if the stop loss value could not be plotted directly from the strategy. TLPlot allows this to happen, greatly reducing the debugging time spent on developing strategy logic.

Summary of Advantages of Plotting From Strategies

  1. Eliminates need for corresponding indicators to be placed on chart.
  2. Ensures input values for custom functions using in strategy decisions are the same values used for plotting the custom functions.
  3. Automatically updates the plotted custom function when new input values are adopted by the strategy after optimization.
  4. Allows the strategy logic as well as the custom function values to be verified by observation on the chart rather than extensive testing and debugging.

Function TLPlot

This function is called using the following syntax:

value1 = _TLPlot ( PlotNr, Price, Length, Offset, Style, Color, Size );

This is similar to the plot statement syntax:

Plot(n) [Offset] (Price, "PlotName", Color, default, Width );

The TLPlot function can also programmatically set the line style to solid, dotted or one of three dashed formats, making it somewhat more versatile than the Plot[n] statement, whose line style can only be changed by manually formatting the indicator.

TLPlot input parameters are defined as follows:

Plot number, similar to the number of the plot statement, Plot[n].

Plot number, similar to the number of the plot statement, Plot[n].
Price Value of function to be plotted.
Length Number of bars for which a plot is desired, counting from the right most edge of the chart.

If a user wishes only to see the function in the visible bars of the chart, a Length equal to the maximum number of bars visible in the chart is selected.

If the user wishes to be able to review the historical bars outside of the visible bars in the chart, then Length can be increased to go back in history as far as desired. For example, on a daily chart, to review 5 years of data, the Length can be set to 252 x 5, as there are approximately 252 trading days in each year.

Offset Number of bars Price is shifted to the right.
Style Plot line style. The choices are:

Tool_Solid, Tool_Dotted, Tool_Dashed, Tool_Dashed2, and Tool_Dashed3.


Plot color.
Size Width of plot line.

Typical Usage in MACrossOver Strategy















Optimizing(GetAppInfo(aiOptimizing) = 1),;


MA1 = Average(Price, Length1);

MA2 = Average(Price, Length2);



if MA1 crosses above MA2 then Buy Next Bar at Market;

if MA1 crosses below MA2 then SellShort Next Bar at Market;


{ plot only when NOT optimizing }

if Optimizing = false then begin

value1 = _TLPlot(1, MA1, PlotLength, PriceOffset, 0, TLStyle, TLColor1, TLSize);

value1 = _TLPlot(2, MA2, PlotLength, PriceOffset, 0, TLStyle, TLColor2, TLSize);



Fig. 3. MACrossOver Strategy showing moving averages plotted direction from strategy.

In the MACrossOver strategy code above, note that a PriceOffset = 1 is used to synchronize the cross of the moving averages with the actual trade entries, since orders are of the type Buy/Sell NEXT bar at ..... That is, the trigger to make the trade normally occurs one bar before the actual trade. By using PriceOffset = 1, the moving average cross-over lines up with the same bar of the trade entry, making it easier to follow the logic of the strategy and verify that it was programmed correctly.

Also note that the plotting is bypassed if the strategy is optimizing.



Initial posted version: 10/03/09

Latest Update: 03/15/17

*.ELD files are compiled for TS 9.5

All ELD and code text files packaged here:


The code may be visualized here:

Function TLPlot

A version generously contributed by David Pedersen (dpf16 on TS Forum) using vectors rather than arrays:

Function TLPlotVec

How to call this function from your strategy:

Sample Strategy Code to Call Function


Bookmark and Share