Tutorial - RTL

What follows is a basic tutorial on RTL. The tutorial will focus primarily on RTL syntax and how to write formulas.

The Basics

RTL is written using Tokens to access data elements. Some simple Token examples are:

  • CL (Closing Price of a Bar)
  • OP (Opening Price of a Bar)
  • HI (High Price of a Bar)
  • LO (Low Price of a Bar)
  • VO (Volume of a Bar)

Tokens are combined in the RTL Editor Window to build expressions. Let's begin by opening the RTL Editor Window by going to File → New → RTL Object or use the Windows shortcut ALT-R or macOS shortcut command-R.

RTL Editor

  1. Chooses the Type of RTL Object you'd like to Create or Open. Use the dropdown to view existing RTL objects of the "Type" chosen.
  2. Favorites Button. When pressed, refines the list of tokens to show only your favorites as defined in Setup → Configuration → RTLFavoriteTokens. Add your own personal semicolon separated list of Favorites to this Configuration Variable to see them appear in the RTL Editor Window (i.e. CL;MPD;MA;).
  3. Lists the available Tokens along with a dropdown at the top to Filter by certain types of Tokens. For a more detailed description of each Token, see the Tokens Tab on this page.
  4. Lists the Tokens being used in the current RTL Object.
  5. Lists Function Tokens (more on Function Tokens later).
  6. Shortcuts to insert operators available in the RTL Language.
  7. Syntax Window to build your RTL expressions.
  8. Check your expressions for errors or Export a definition of the current RTL Object to share with other users.
  9. Save your work or use the "Send To" button to use the RTL Expression in a Chart or QuotePage.
Create your first RTL Object

First, open a chart by going to File → New → Chart. Then let's open the RTL Editor and choose Custom Indicator from available radio buttons(1) at the top of the RTL Editor window. In the syntax Window(5), type the token CL. Then press "Save As" and name this Technical Indicator "Closing_Price." Next, press Send To → Chart-Custom Indicator. You have just built your first RTL Object.

To edit the Indicator, double click on it in the chart. This will open the Custom Indicator Preferences Window which will allow you to change various aspects of the Indicators display.

Accessing Previous Bar Data with Qualifiers

Any Token in Investor/RT can be qualified with a number to access data from prior bars by adding a period and a number to the token. Consider the following examples:

  • CL.1 (Access the Previous Bars closing price)
  • (CL + CL.1)/2 (Compute the Average of the Previous and Current Closing prices)
  • (CL + CL.1 + CL.2)/3 (Compute the Average of the last three Closing Prices)

Arithmetic & Grouping Expressions with Parenthesis

This aspect of RTL is fairly straightforward. RTL supports the following arithmetic operators(the operator used is in parenthesis):

  • Addition(+)
  • Subtraction(-)
  • Multiplication(*)
  • Division(/)
  • Modulo(%)
  • Exponentiation(^)
Grouping Expressions with Parenthesis

When using arithmetic or compound expressions in RTL, it is often necessary to use parentheses in order to instruct the program which expression should be evaluated first. Investor/RT utilizes basic Operator precedence or evaluated together. As a good example, let's look at the following arithmetic expression:

(2 * VO) / (HI - LO)

But placing the parentheses around the two expressions, we've instructed the program to first multiple the volume by 2, then subtract the low from the high, and then take the quotient of the two results. If we had instead omitted the parentheses and instead used the following expression:

2 * VO / HI - LO

Then expression would be evaluated as follows, first multiplying the volume by two, then dividing the result by the high, and THEN subtracting the low from that result. This obviously would have effected a very different outcome. The order in which Investor/RT evaluates any given expression can be seen by simply clicking on the "Check" button at the bottom of the RTL window.

Boolean vs. Numerical Results

First, let's discuss the difference between a boolean result and a numerical results. Scans and signals have boolean (true/false) results while custom indicators have arithmetic results. For instance, a signal might tell the user if price is above a moving average:

CL > MA

Note: CL and MA are tokens in the RTL language. CL is a shortcut for CLOSE, the closing price of each bar. MA is the moving average indicator token. The attributes of the moving average (the type of average and the period of the average) are not written in the formula itself. Instead Investor/RT prompts separately for those setups, keeping the RTL formula simple and easy to setup.

On each bar, that condition is either true or false. Internally, true is represented by 1 and false is represented by 0 (zero). Again, all signals and scans have boolean results. An arithmetic result is a number, computed for each bar based on the formula. All custom indicators have numerical results. For example, the following custom indicator computes the volume of each bar divided by the range of a bar:

VO / (HI - LO)

Note: The expression could also be written VOLUME / (HIGH - LOW). The difference between the high and low of any bar is so commonly used that it has a token of its own, HLR, the high low range of the bar. Thus this particular formula could be written more succinctly as simply VO / HLR.

The result of this custom indicator might be 12.26 on one bar, 1.12 on the next, and 321.12 on the next.

Tokens or Elements

Tokens are the basic elements used to build RTL expressions. In this tutorial, we will primarily focus on the two most common tokens: Historical Data Tokens and Technical Indicator Tokens. Historical Data Tokens provide access to the raw bar data including OP (open), HI (high), LO (low), CL (close) and VO (volume). These tokens are historical in that they have a unique value historically for each bar (instead of just a single current value). Technical Indicator Tokens are also historical, and provide the user access to any of the 160+ technical indicators within Investor/RT. In the express CL > MA, we make use of both an Historical Data Token (CL) and a Technical Indicator Token (MA). For a list of tokens and token types, see RTL Tokens

Comparative operators

Comparative operators are commonly used in boolean expressions to compare two numerical values, and include the following:

Comparative operators are commonly used in boolean expressions to compare two numerical values, and include the following:

In the boolean expression mentioned earlier, CL > MA, would read "the closing price of the bar is greater than the moving average value of the bar". Similarly, the expression MA <= HI reads "the moving average value of the bar is below or equal to the high price of the bar".

Qualifiers

Technical Indicator Tokens and Historical Data Tokens (see above) can be qualified with a number to access data from prior bars. This can be best illustrated with an example. Consider the following boolean expression which might be used within a signal:

CL.1 < MA.2

This expression reads "the closing price of the prior bars is less than the moving average value two bars prior". The period is optional when qualifying. This expression could have also been written as CL1 < MA2. The use of periods just makes the expression more legible.

Compound Operators: AND and OR

Multiple boolean expression can be combined using the compound operators AND and OR. Consider an example where you want to locate the bars where price moved above a moving average. In order for this to take place, two things must occur: then closing price of the current bar must be greater than the current moving average, AND the closing price of the previous bar must have been equal to or less than the moving average of the previous bar. These two conditions would be joined with the AND operator to produce:

CL > MA AND CL.1 <= MA.1

Notice the presence of the AND operator forces both conditions to be true in order for the overall result to be true. If either condition is false (or if both are false), the result is false. Let's consider another situation where we are looking for price to be making a higher high OR a lower low. This could be expressed with: HI > HI.1 OR LO <> HI.1 AND LO < LO.1 We would not get a true result unless we made both a higher high and a lower low on the same bar.

Arithmetic Operators

This aspect of RTL is fairly straightforward. RTL supports the following arithmetic operators:

The last two operators will rarely be used and not discussed in this basic tutorial. The following custom indicator expression demonstrates the use of arithmetic in RTL:

(2 * VO) / (HI - LO)

This expression involves three arithmetic operators and divides twice the volume (2 * VO) by the high/low range of the bar (HI - LO). Notice the use of parentheses in this expression to ensure that the arithmetic operators are processed in the order desired by the user. Parenthesis will be covered in more detail in the following section.

Parentheses - Grouping Expressions

When using arithmetic or compound expressions in RTL, it is often necessary to use parentheses in order to instruct the program which expression should be evaluated first or evaluated together. As a good example, let's look at the arithmetic expression we just considered:

(2 * VO) / (HI - LO)

But placing the parentheses around the two expressions, we've instructed the program to first multiple the volume by 2, then subtract the low from the high, and then take the quotient of the two results. If we had instead omitted the parentheses and instead used the following expression:

2 * VO / HI - LO

Then expression would be evaluated as follows, first multiplying the volume by two, then dividing the result by the high, and THEN subtracting the low from that result. This obviously would have effected a very different outcome. The order in which Investor/RT evaluates any given expression can be seen by simply clicking on the "Check" button at the bottom of the RTL window.

Another example that underscores the importance of using parentheses, this time with a boolean expression:

(CL > MA AND CL.1 < MA.1) OR (CL < MA AND Cl.1 >= MA.1)

This expression will look for the closing price crossing the moving average in either direction (either crossing above, or crossing below). Notice the two ANDed expressions are grouped and processed first, with their results being ORed together for the final result. If the parentheses had been omitted as follows:

CL > MA AND CL.1 < MA.1 OR CL < MA AND Cl.1 >= MA.1

Then Investor/RT would have evaluated the expression in the following manner:

(CL > MA AND (CL.1 < MA.1 OR (CL < MA AND Cl.1 >= MA.1) ) )

And resulting in quite a different outcome. It is not always necessary to use parenthesis, however, it is important to use the "Check" button to ensure Investor/RT is evaluating your expression in the desired order. It never hurts to use extra parentheses even when not completely necessary as it will not slow down the calculation of the expression.

Indicator Names, Syntax, and Preferences

Each indicator has a token that represents that indicator in the RTL language. For example, the token for the Moving Average Indicator is MA. To create a custom indicator that simply computed the MA, simply type in the syntax:

MA

and then click the "Save" button. When the Save button is clicked, Investor/RT will recognize that MA has not yet been added to the list at the upper left, and that it's preferences (type, period, etc) have not yet been specified. The Moving Average preference window will automatically appear, allowing the user to enter the Moving Average period, type, etc. Once the user provides these settings and clicks "OK", another box will popup asking for the name of the Custom Indicator. Each RTL object, including custom indicators, must be identified with a unique name. At this point, the MA preferences can still be edited by double-clicking on the token name (MA) in the list on the upper right of the custom indicator window.

Same Indicator Token - Multiple Instances

If you need to use the same indicator in your syntax multiple times, but with different settings, simply append an underscore followed by a letter to differentiate the tokens. For instance, you might want to take the difference between a 13 period moving average and a 26 period moving average. Simply type in the syntax:

MA - MA_B

and then when you save the RTL object, you will be asked for the settings for MA (13 period) and then the preferences for MA_B (26 period). You are not restricted to using single letters, MA_TWENTYSIX would have worked equally well as MA_B, but you cannot end your token with a number as that will be interpreted as a qualifier (see qualifier section above).

Indicator of an Indicator

RTL allows uses to use the following syntax to perform a moving average on the CCI values:

MA(CCI)

In this instance, the moving average will operate on the CCI results as opposed to the "Price" that is specified in the moving average preferences. This same format can be used to with any two or more technical indicator tokens.

MA(MA_B(MA_C) ) ) - MA_B(MA_C)

Multi-Line Expressions (Backtesting Only)

RTL expressions can generally be completed on a single line, as you've seen in the examples shared to this point in the tutorial. However, in certain situations, and most commonly in backtesting, there is a need to have multiple lines within a single RTL expression. Take for example the signal below: IF (POS = 1) THEN (SET(V#2, HI)); IF (HI > V#2) THEN (SET(V#2, HI); HI = V#2;

First, notice that each line ends with a semi-colon. After typing the semi-colon, simply hit the enter key to move to the next line. For each bar, the expression will be evaluated one line at a time, starting with the top line. The net result of the expression will be the result of the last line. Any lines prior to the last line are generally used for maintaining values of user variables (V#), stops, targets, etc.

Let's look at the example above line by line. The POS token represents the Position Indicator, which in this example, is setup with "Bars from start of session" (in the indicator preferences). Therefore, the first line reads "if this bar is the first bar of the session, then set V#2 to the high of that first bar. This line will only have an effect on the first bar of each session, initializing V#2 to the high of that bar. The second line reads "if the high of this bar is greater than V#2, then set V#2 to the high of this bar". This allows us to keep track of the high of the session with V#2. Notice the last line is simply "HI = V#2", so the signal will be true on bars we're making a new high, and false otherwise.

Again, this multi-line method is commonly used in backtesting for two reasons. It's very convenient to be able to do multiple lines of user variable and stop/target maintenance within a single expression. Secondly (and this is very important), backtests run through the data sequentially, from the oldest bar first, to the most recent bar last. This allows the syntax above using the Position Indicator to work properly. However, for signals or custom indicators added directly to charts, the data is evaluated the reverse order, with the most recent bar being computed first. Therefore, you would not get the results you expected if you added the signal above directly to a chart as a signal marker.

For those interested in backtesting, please view the video series Trading Systems and Backtesting. You'll find examples like this and many more.

Efficiency

Efficiency is an important consideration when adding various RTL objects to charts in Investor/RT. The Efficiency Tutorial does a good job of covering this topic. It's highly recommend that anyone using RTL watch the Running an Efficient Investor/RT at the top of that tutorial. It provides instructions on how to check the time and frequency of calculations of indicators in charts, and how to quickly identify any potential problems in this area that can result in data running behind (lagging). Additionally, anyone using the MPD (Mixed Periodicity Indicator) video should visit the Mixed Periodicity Data indicator page and pay special attention to the short video Using MPD Efficiently. If you don't have time to review these videos at this time, make a note to return in the future after you've added a number of RTL objects to your charts and watch the videos.

Sessions and Periodicity in RTL

When you create a signal or custom indicator with RTL you can apply that RTL object to any chart, of any symbol, of any periodicity, and set to any session. There are a few exceptions, but generally that is the case. It's important to keep in mind that changing something like the session will often change the values of your indicator in a chart, and that goes for normal indicators as well as custom indicators and signals. For example, consider a 20 period simple moving average on a 5-minute chart. If the chart is set to session 2 (day session), then the MA values of the first 19 bars of that session will be quite different than the MA values of the same bars on a chart set to session 31 (GLOBEX/overnight session). That's because on the day session chart, the 20 period look-back considers bars from the end of the previous session, while the GLOBEX session chart is simple considering bars earlier in it's session. Similarly, the overnight VWAP will be different than the day session VWAP. The overnight Value Area high and low (provide by the TPO Indicator) will be quite different than the Value Area of a chart set to the day session.

Bars Loaded

In the lower corner of the RTL window, you'll see a listbox where the user can specify a number of "Bars". This controls the number of bars that are considered when recalculating the RTL Object (custom indicator or signal) within a chart. In other words, if a custom indicator was setup with a value of "Bars: 100", then each time the custom indicator was calculated in a chart, it would send the last 100 bars through the calculation routine in order to recalculate the dynamic value of the current bar. This is a setting that users generally do not need to be concerned with. The default for this setting is "Automatic" which instructs Investor/RT to best determine the most efficient (minimal) number of bars needed based on the tokens involved in the syntax and their preferences. However, there is no way to accurately determine this value for certain indicators such as Signal Statistics. In those cases, it might be required for the user to specify a reasonable value based on the syntax. There is also an option for "Bars: All" which will force each calculation to consider all bars in the chart each time it recalculates the current value. This bars setting can be especially helpful for what we refer to as "cumulative" indicators.

RTL Objects Embedded within Technical Indicators

RTL Objects embedded within Technical Indicators The following indicators are built upon RTL objects. Each of these indicators has an option within it's preferences to specify a signal, a custom indicator, or both.

  • Signal Marker - Signal Markers are built upon a signal and plot markers on bars whenever the signal is true. The user can provide the color, style, size, and position of the marker. The Markers can be labelled with the bars price, time, or even with any custom indicators value on that bar.
  • Custom Indicator - There are technically two "custom indicator" windows. The setup window where the syntax is formed, and the preference window which holds the settings to how the indicator is displayed in the chart. The preference window is similar to the preference window of any indicator, and provides options on how the custom indicator is drawn in the chart (line, histogram, colors, etc) as well as some other options. This video provides more details on adding signals or custom indicators to charts.
  • Color Markers - Color Markers, like Signal Markers, are built upon a signal (or custom indicators) and plot markers on bars whenever the signal is true. Color Markers provide some nice flexibility with how the markers are drawn, allowing customized color, position, shape, size, and offset from the top or bottom. Color Markers can easily be stacked in a pane to provide a quick look at many conditions in one place.
  • Paint Bars - Paint Bars allow the user to paint the bar, or the background of the bar, based on a signal or custom indicator result. As with any of the indicators in this list, multiple Paint Bars can be added to the same chart, allowing the user to colors bars with many different colors based on a number of different signals or custom indicators.
  • Signal Statistics - The Signal Statistics indicator allows for statistical calculations on signals, including summation, consecutive signals, frequency, bars since last signal, change since last signal, and more. SSTAT allows the user to select any existing signal, and any custom statistical result to calculate on that scan/signal. Click here for the full list of statistics available.
  • Mixed Periodicity Data
  • Horizontal Reference Line
  • Trading System Indicator

Key Indicators in RTL / Examples

Most indicators in Investor/RT calculate their results based on input of the price and volume data of each bar. Certain indicators are unique as they relate to RTL and the type of information and data which their results provide. These indicators make it possible to use a single token to accomplish a task that might take dozens of lines of code in other languages or systems. We're going to look at some of these indicators below and provide examples of each one.

Signal Statistics (SSTAT) Example MORE

Requirements: One user wanted to plot the high reached between two specific times during the trading session. Specifically, this user wanted to plot the high reached between 14:20 and 14:50 on a 1-min or 5-min chart, and to plot it historically.

Solution:This can be achieved with a combination of Signal Statistics (SSTAT), the REF function, and the TIME token. The syntax of the custom indicator follows:

REF(SSTAT_Begin, SSTAT_End)

This statement reads "reference the SSTAT_Begin value x bars back, where x gets it's value from SSTAT_End. SSTAT_End gives us the number of bars back of the 14:50 bar. This is achieved by setting up SSTAT_End with "bars since last signal" using a signal (created and saved separately) with syntax:

TIME = 1450

This signal is true only on the bar that ends at 14:50. Furthermore, the SSTAT_Begin token is setup with "Highest Price Since Signal" and "Price: High" and is built upon the following signal:

TIME = 1420

Again, this signal is created and saved separately. By referencing that value on the 14:50 bar, we get the high from 14:20 to 14:50 using our original custom indicator above. This implementation will work between any two times, just change the times in the two respective signals appropriately.

Two important notes on this custom indicator. First, there is no need to recalculate this indicator frequently. Setting up the indicator to recalculate every 1 minute should be quite sufficient for this moderately inefficient indicator. In addition, within the custom indicator syntax window, specify a value of "Bars: 1000". This will ensure that the custom indicator is considering a sufficient number of bars when recalculating within the chart. When the SSTAT token is involved, it is difficult for Investor/RT to automatically compute how many bars need to be loaded.

More Examples

Divergence

Between Indicator and Price, or Between Two Indicators Requirements: Find the lowest RSI value over the past 20 bars (or any user-specified number of bars). What was that low value? What's the highest RSI value since that low? What was the low price of the instrument on the bar where the RSI made it's low? What's the highest high price of the instrument since the RSI made that low?

We'll look at each of these four requirements independently. Different users have different definitions of "divergence", but armed with the information and expressions below, users should be able to formulate their own divergence signals and indicators. This logic will work for divergence with any indicator. Just substitute the desired indicator token in place of the RSI token in each of the expressions below. In addition, this logic can be used to find divergence not only between price and an indicator, but also between any two indicators. This will be discussed below.

What was that low value?

This one is pretty straightforward using the MIN operator: MIN(RSI, 20)

which reads "the minimum RSI value over the past 20 bars". For each bar, this includes that bar AND the previous 19 bars (NOT the previous 20 bars).

What's the highest RSI value since that low?

This one is a bit more complicated, but the syntax is actually quite simple: MAX(RSI, STAT(RSI) + 1)

The key is how STAT (Statistics Indicator) is setup. It should be setup as "Minimum Low for the last 20 Bars" (substitute your required period in place of 20) and with "Resulting Value" of "Bars Since the Minimum Value". Setting up STAT in this fashion, and operating it on RSI in this manner, STAT(RSI), gives us the number of bars back that RSI reached it's low over the past 20 bars. We need to add 1 to this result in order to include the current bar and the low-RSI bar. Therefore, the complete expression will return the maximum RSI value since the low RSI was created, which is exactly what we wanted. The expression would read "Maximum RSI value since the RSI made it's low, including the current bar and the bar which made the RSI low".

What was the low price of the instrument on the bar where the RSI made it's low?

Building off what we just explained: REF(LO, STAT(RSI) + 1)

This reads "reference the low price on the bar where the lowest RSI occurred over the previous 20 bars". You can substitute LO with CL or OP if you need the closing or opening price of the instrument on the bar that created the low RSI value. And if you're looking for divergence between two indicators, you can substitute LO with the token for the respective indicator, such as CCI.

What's the highest high price of the instrument since the RSI made that low?

Again, building upon the logic we've already discussed: MAX(HI, STAT(RSI) + 1)

Which reads "maximum high price achieved since the lowest RSI occurred over the previous 20 bars". Again, if you're looking for divergence between two indicators, just substitute HI with the your respective indicator token, such as CCI.

How can we access the maximum/minimum value between two events/signals? For example, how we would access the highest high from the point the CCI turned negative until it turned back positive? First, we need to create two signals. The first will find when the CCI turns negative: CCI < 0 AND CCI.1 >= 0

(reads: The CCI of the current bar is less than zero and the CCI of the previous bar was greater than or equal to zero). And save this signal with a name like CCI_NEG. Now, create another signal: CCI > 0 AND CCI.1 <= 0

(reads: The CCI of the current bar is greater than zero and the CCI of the previous bar was less than or equal to zero). and save this signal with a name like CCI_POS. Now, use the following syntax to access the highest high between the two events. REF(MAX(HI, SSTAT_NEG), SSTAT_POS)

Where SSTAT_NEG is setup as "bars since last signal" referencing signal CCI_NEG, and SSTAT_POS is setup as "bars since last signal" referencing signal CCI_POS. This syntax is very flexible, to find the lowest price between the two events, just change the MAX to MIN. The token HI can be replaced by any price or indicator. So to access the lowest CCI value between these two signals, just change syntax to: REF(MIN(CCI, SSTAT_NEG), SSTAT_POS)

To change the starting signal/event, simply change the underlying signal of SSTAT_NEG. To change the ending signal/event, change the underlying signal of SSTAT_POS.

Swing High / Swing Low Prices and Retracement Levels

Requirements: Identify the Swing High and Swing Low with a signal. Plot the price of the last Swing High/Low. Plot retracement levels between the last Swing High and Low.

In these examples, we're defining a Swing High as a bar which has a higher high than the two bars preceding it and following it.

How do we write a signal that will identify Swing Highs and Lows? We'll use the Fractals indicator to help identify these bars. They syntax for the Swing High signal would simply be: FRACU = 1

With FRACU setup with "Bars Involved: 5". Let's call this signal "SwingHighBar". The FRACU token will give us a 1 on Up Fractals and a 0 otherwise. With FRACU setup for 5 bars, it will identify the Swing Highs involving 5 bars (including itself, the 2 bars before it and 2 bars after it).

Similarly, the Swing Low would be identified with: FRACD = 1

Again, with FRACD being setup with "Bars Involved: 5". Let's call this signal "SwingLowBar". FRACD identifies the down fractals or the bars whose low is lower than the 2 bars before and 2 bar after it.

If your definition of a Swing High involves 1 or 3 bars before and after (instead of the 2 assumed above), simply adjusting the settings in the Fractal indicator accordingly in the signals.

How would we plot the price of the last Swing High or Swing Low? To plot the price of the last Swing High, the following custom indicator would be used: SSTAT

Where SSTAT is setup with "Signal: SwingHighBar" (from above) and "Result: Price At Last Signal" and "Price: High". The price of the last swing low would be identified using the same syntax, but this time, SSTAT would be setup with "Signal: SwingLowBar" (from above), "Result: Price At Last Signal", and "Price: Low".

How would we plot the retracement levels between the last Swing High and Swing Low? To plot the 50% retracement, use the following custom indicator: SSTAT_LO + (SSTAT_HI - SSTAT_LO) * 0.50

Where SSTAT_LO is setup to access the price of last Swing Low as described immediately above, and SSTAT_HI is setup to access the price of the last Swing High. To plot the 61.8 and 38.2 retracement levels as well: SSTAT_LO + (SSTAT_HI - SSTAT_LO) * 0.382

and... SSTAT_LO + (SSTAT_HI - SSTAT_LO) * 0.618

Users may consider a much easier alternative to the multiple custom indicators above: the Zig Zag Indicator setup with "Draw Fib Levels" checked. This will automatically draw fib retracement levels between key high/low Zig Zag pivots. That method would not only easier, but also more efficient. However, it would use pivots based on price movement and not necessarily identify Swing Highs and Swing Lows.