I was perplexed when my code did not produce the desired results. I spent quite a bit of time locating the problem and also learned some new things about formulas for calculating circular indexes that I felt were worth sharing with others.
To create a circular index for an array, you will often see simple code as follows:
vars: index(0), Size(12);
Index = Index + 1
if Index > Size then Index = 1;
Or this:
vars: index(0), Size(12);
Index = Index – 1;
if Index < 1 then Index = Size;
There are some situations, however, where you wish to calculate the circular index of a point many bars into the future, or many bars into the past.
My initial attempt at creating a more robust formula was:
CircularIndex = MOD(Index – 1, Size) + 1;
This seemed to work fine when tested in Excel, but when using it in EasyLanguage I was getting errors for referencing the Array out of bounds.
So, the first thing I learned about circular indexing is that the MOD function in Excel is NOT the same as the MOD function in EasyLanguage!
With positive offsets, the values are the same:
Excel | EasyLanguage |
MOD(1, 10) = 1 | MOD(1, 10) = 1 |
MOD(11, 10) = 1 | MOD(11, 10) = 1 |
Mod(21, 10) = 1 | MOD(21, 10) = 1 |
But with negative offsets, the values are different:
Excel | EasyLanguage |
MOD(-1, 10) = 9 | MOD(-1, 10) = -1 |
MOD(-11, 10) = 9 | MOD(-11, 10) = -11 |
Mod(-21, 10) = 9 | MOD(-21, 10) = -21 |
The EasyLanguage MOD function does not work for negative offsets. Therefore, it can not easily be used when backreferencing circular arrays with negative offsets since Arrays can only reference non-negative offsets:
e.g. A[0], A[1]…etc. but not A[-2]
Fortunately, I did find an EasyLanguage function that did work well:
CircularIndex = Index – Floor((Index – 1)/Size) * Size
My preference is to use circular indices that do not use the number 0. It is easier to debug code when, for example, calculated element 3 belongs in array[3] rather than in array[2]. This avoids the mental juggling of the offset required when also utilizing the element [0] to store data.
Secondly, the Array[0] element can often be used to hold “status” information about the array or its state of processing. When circular arrays are passed to functions for further calculations, having the “status” information in element Array[0] avoids having to create a separate status variable to pass this information.
The following simple example may be used to illustrate the CircularIndex function and the corresponding CircularIndexTest indicator, attached below.
A circular array of size 12 is set up and loaded with data starting with an index of 1 (BarNumber = 1):
BarNumber = 1: Array[1] = close;
BarNumber = 2: Array[2] = close;
….. …..
BarNumber = 12: Array[12] = close;
BarNumber = 13: Array[1] = close;
etc.
The answer is given by the formula:
CircularIndex | = | Index – floor((index – 1)/size) * size; |
= | 4092 – floor((4092 – 1)/12) * 12 | |
= | 4092 – 340 * 12 = 4092 – 4080 = 12 |
Suppose you are at the LastBarOnChart in the above case. The BarNumber is now 5027 and you need to know what is the correct circular index to use for a bar that is 1137 bars earlier. The answer is:
Index | = | 5027 – 1137 = 3890 |
CircularIndex | = | Index – floor((index – 1)/size) * size; |
= | 3890 – floor( (3890 – 1) / 12) * 12 | |
= | 3890 – 324 * 12 = 3890 – 3888 = 2 |
For example floor(-1/10) = -1
A test indicator CircularIndexTest is shown here calculating the circular index with Length = 12:

Fig. 1. CircularIndexTest Indicator demonstrating the function CircularIndex
Index = -15.00 Circular Index = 9.00 Index = -14.00 Circular Index = 10.00 Index = -13.00 Circular Index = 11.00 Index = -12.00 Circular Index = 12.00 Index = -11.00 Circular Index = 1.00 Index = -10.00 Circular Index = 2.00 Index = -9.00 Circular Index = 3.00 Index = -8.00 Circular Index = 4.00 Index = -7.00 Circular Index = 5.00 Index = -6.00 Circular Index = 6.00 Index = -5.00 Circular Index = 7.00 Index = -4.00 Circular Index = 8.00 Index = -3.00 Circular Index = 9.00 Index = -2.00 Circular Index = 10.00 Index = -1.00 Circular Index = 11.00 Index = 0.00 Circular Index = 12.00 Index = 1.00 Circular Index = 1.00 Index = 2.00 Circular Index = 2.00 Index = 3.00 Circular Index = 3.00 Index = 4.00 Circular Index = 4.00 Index = 5.00 Circular Index = 5.00 Index = 6.00 Circular Index = 6.00 Index = 7.00 Circular Index = 7.00 Index = 8.00 Circular Index = 8.00 Index = 9.00 Circular Index = 9.00 Index = 10.00 Circular Index = 10.00 Index = 11.00 Circular Index = 11.00 Index = 12.00 Circular Index = 12.00 Index = 13.00 Circular Index = 1.00 Index = 14.00 Circular Index = 2.00 Index = 15.00 Circular Index = 3.00 |
- Document the quirk about the MOD function behaving differently in Excel and EasyLanguage
- Show how the Floor function can be used in place of the MOD function to create a simpler formula for circular index calculations that works for offsets of ANY size, and in both the POSITIVE and NEGATIVE directions.
- Provide a function that can be called to calculate the circular index of an offset of any size in either postive or negative directions.
Downloads
Initially posted version: 08/31/09
Latest Update: 01/31/10
*.ELD files are compiled for TS 8.7
All ELD and code text files packaged here:
Users of earlier versions of TradeStation may compile the code
from the text files included in the above *.zip file.
The code may be visualized here: