Working with ACSIL Arrays and Understanding Looping


Introduction

This documentation page provides an explanation on how to work with the three most common arrays in the Sierra Chart Advanced Custom Study Interface.

It also discusses another important topic, the two methods of looping or iterating through all of the bars/columns in the chart. Looping through all of the bars/columns in the chart is necessary in order to fully calculate your study to produce a result that goes across the entire chart.

The two methods of looping are Automatic Looping and Manual Looping. These are exclusive of each other and you will never use both methods of looping in the same function. Otherwise, you would cause significant inefficiencies.

The preferred method is Automatic Looping.

Overview of
sc.BaseData[][]
sc.Subgraph[].Data[]
sc.Subgraph[].Arrays[][]

The three most common arrays you will work with are:

The sc.BaseData[][] arrays contain the data for the main price graph in the chart. The sc.BaseData[][] arrays are used as input data to your study.

The sc.Subgraph[].Data[] arrays, (shorthand notation: sc.Subgraph[][]), are for your studies displayable output and can be used to hold the results of background or intermediate calculations.

There are also the extra arrays, sc.Subgraph[].Arrays[][], that can be used to hold the results of background or intermediate calculations for a sc.Subgraph[].Data[] array that is graphed on the chart.

The next two sections provide examples on how to work with these arrays.

A good way to understand how to organize your study calculations and use the sc.Subgraph[] arrays to hold the results of those calculations is to ask yourself how would I do this if I were using one of the Sierra Chart Spreadsheet Studies. If your study would require 2 Spreadsheet columns, one for a background calculation and another for the final result to be graphed and visible, then you would use for example sc.Subgraph[0][sc.Index] (shorthand notation) for the final result to be graphed. Make sure sc.Subgraph[0].Name is set for the Subgraph. For the backgroud calculation you would use sc.Subgraph[0].Arrays[0][sc.Index].

Array Indexing and Sizes

The sc.BaseData[][] arrays have 2 indexing operators ([]). The second operator is for accessing the individual values within the specified chart Base Data array. The first element starts at 0, and the last element is sc.ArraySize -1. Examples: sc.BaseData[SC_LAST][0] , sc.BaseData[SC_LAST][sc.ArraySize-1]. The first element is the leftmost bar in the chart.

The sc.BaseDateTimeIn[] array has 1 index operator ([]). This operator is for accessing the individual SCDateTime variables within the sc.BaseDateTimeIn[] array. The first element starts at 0, and the last element is sc.ArraySize -1. Examples: sc.BaseDateTimeIn[0] , sc.BaseDateTimeIn[sc.ArraySize-1]. The first element is the Date-Time of the leftmost bar in the chart. This array always contains the starting time of the chart bars.

The sc.DateTimeOut[] array has 1 index operator ([]). This operator is for accessing the individual SCDateTime variables within the sc.DateTimeOut[] array. The first element starts at 0, and the last element is sc.OutArraySize -1. Examples: sc.DateTimeOut[0] , sc.DateTimeOut[sc.OutArraySize-1]. The first element is for the leftmost bar in the chart.

The sc.Subgraph[][] / sc.Subgraph[].Data[] arrays have 2 indexing operators ([]). sc.Subgraph[][] is a shorthand version of sc.Subgraph[].Data[]. The second operator is for accessing the individual values within the specified Subgraph array. The first element starts at 0, and the last element is sc.ArraySize -1. Examples: sc.Subgraph[0][0] , sc.Subgraph[0][sc.ArraySize-1]. If sc.IsCustomChart is set to 1, then the last element is equal to sc.Subgraph[0][sc.OutArraySize-1]. The first element is the leftmost column in the chart.

The sc.Subgraph[].Arrays[][] arrays have 3 indexing operators ([]). The third operator is for accessing the individual values within the specified Extra Array for the specified Subgraph. The first element starts at 0, and the last element is sc.ArraySize -1. Examples: sc.Subgraph[0].Arrays[0][0] , sc.Subgraph[0].Arrays[0][sc.ArraySize-1] . If sc.IsCustomChart is set to 1, then the last element is equal to sc.Subgraph[0].Arrays[0] [sc.OutArraySize-1]. The first element is for the leftmost column in the chart.

With all of the above arrays and in the case of Automatic Looping, you would access the element at the current index (the index at which your study function needs to perform calculations at) by using sc.Index with the second indexing operator. Example: sc.BaseData[SC_LAST][sc.Index]. This will be understood better when you review the Automatic Looping/Iterating section.

To get the size of an array, use the GetArraySize() member function. Example: sc.Subgraph[0].Data.GetArraySize(). This is particularly useful when you have accessed an array from another chart which has different array sizes compared to the chart where the arrays were gotten from.

Automatic Looping/Iterating

When your study function uses automatic looping, then it is automaticaly called once for every bar or column in the chart when the study is initially calculated. If there are 100 bars in the chart, then it will be called 100 times when your study is initially calculated. After that, the study function is called as the latest bar is updated and new bars are added.

sc.Index is set to the index of the bar/column in the chart that your study function is being called for. This is a zero (0) based index. During normal chart updating, sc.Index will initially start at the sc.Index value of the last prior call to the study function. This will be the index of the last bar in the chart before any new bars have been added.

For information about when the study function is called during normal chart updating after the initial calculation of the study, refer to When the Study Function Is Called.

sc.CurrentIndex and sc.Index are the same. They are two different variables that are set to the same index value always. You can use either one. Normally the documentation will refer to sc.Index. sc.Index is equal to the elements in the sc.BaseData[][] arrays that need to be processed and/or the elements in the sc.Subgraph[][] arrays that need to be filled in. This will be more clear when you look at the code example below.

If you are creating a custom chart by setting sc.IsCustomChart to 1 (true), this is very unlikely, then sc.Index only refers to the elements in the sc.BaseData[][] arrays to process, assuming your custom chart function uses the sc.BaseData[][] arrays.

Automatic looping is activated by setting sc.AutoLoop = 1; in the code block at the top of your function for setting the defaults and configuration. When you create a new Advanced Custom Study file, the template function in that file, sets this variable to 1 (true). Therefore, by default, automatic looping is done for new functions. However, if sc.AutoLoop is not set, then its value will be zero and automatic looping will be off.

sc.Index initially starts at 0 and increments up to sc.ArraySize -1 when the study is fully recalculated. This happens when the chart is loaded or reloaded. Each time it increments, your study function is called again. There can be other cases for a full recalculation. For example, when you add or remove a study from a chart. Another case a full recalculation can occur is when you are using a custom chart such as the Renko Chart study or the Point and Figure Chart study and a new bar which was added by one of the studies is removed. In this case a full recalculation of the other studies is necessary. In this case sc.Index will start back at 0 and increment back up to the sc.ArraySize-1.

Here is an example of writing code that supports automatic looping:

/*============================================================================
This function demonstrates using sc.AutoLoop.
----------------------------------------------------------------------------*/
SCSFExport scsf_AutoLoopExample(SCStudyInterfaceRef sc)
{

    if (sc.SetDefaults)
    {

        // Set the configuration and defaults
        sc.GraphName = "Auto Loop Example";

        sc.StudyDescription = "This is an example of the new auto loop method for Advanced Custom Studies.";

        // Setting sc.AutoLoop to 1 (true) means looping is performed
        // automatically. This means that if there are 100 bars in your
        // chart, this function is called 100 times initially.
        sc.AutoLoop = 1; // true

        sc.Subgraph[0].Name = "Average";
        sc.Subgraph[1].Name = "Back Reference Example";

        sc.Subgraph[3].Name = "Current Low Price";
        return;
    }

    // Do data processing
    sc.SimpleMovAvg(sc.BaseData[SC_LAST], sc.Subgraph[0], sc.Index, 10);

    // The following line demonstrates referencing data one element back from
    // the current index.
    sc.Subgraph[1][sc.Index] = sc.BaseData[SC_LAST][sc.Index - 1];

    // The following line demonstrates referencing data at the current index.
    sc.Subgraph[3][sc.Index] = sc.BaseData[SC_LOW][sc.Index];
}
    

Manual Looping/Iterating

This section describes manual array element looping or iterating. The preferred method for you to use is Automatic Looping unless your study function does not require automatic looping or would work best without it. Manual looping is slightly more efficient, although it is more difficult. If improperly implemented by not using sc.UpdateStartIndex, then it can be much more inefficient. If sc.AutoLoop is set to zero (0), which is the default if it is not specified in your code block at the top of the study function for setting the defaults and configuration, then you need to use a for loop to iterate through all the sc.BaseData[][] and sc.Subgraph[][] data array elements. You must use the sc.UpdateStartIndex variable to determine what element Index to begin your for loop at. If you were to start your loop at position zero always, your study will be very inefficient. Instead use sc.UpdateStartIndex.

During normal chart updating and after the initial study calculation, refer to When the Study Function Is Called to know when the study function will be called.

When there is an event which will cause the study function to be called, it will be called at the Chart Update Interval set in Global Settings >> General Settings, and not more often. So it does not happen immediately upon, for example new market data received. It will be soon as the Chart Update Interval has elapsed and there is new data which causes an update.

The following is more information on sc.UpdateStartIndex and example code for manual looping:

More information about sc.UpdateStartIndex

sc.UpdateStartIndex is set by Sierra Chart to the index where your primary for loop will start looping from. This is the index in the sc.BaseData[][] arrays where updating has begun. This is the same index where updating should begin in the sc.Subgraph[][] arrays. If you are creating a custom chart, sc.IsCustomChart is set to true (this is very unlikely), then sc.UpdateStartIndex only refers to the sc.BaseData[][] element to process.

Example

for (int Index = sc.UpdateStartIndex; Index < sc.ArraySize; ++Index)
{
    // fill in the first subgraph with the last values
    sc.Subgraph[0][Index] = sc.BaseData[SC_LAST][Index];
} 
            

The above loop will always fill in and update the necessary elements in the one output (Subgraph) array we are using (sc.Subgraph[0][]). If you are using manual looping, most studies will require a primary loop to iterate through the elements in the arrays.

This is a good example of the primary loop that you will need to use. You will begin at sc.UpdateStartIndex. You will loop from there up to, but not including, sc.ArraySize. You do not include sc.ArraySize because the arrays are zero-based, meaning the last element in the array is at the index sc.ArraySize - 1.

Example Code

/*============================================================================
This function demonstrates manual looping using a for loop.
----------------------------------------------------------------------------*/
SCSFExport scsf_ManualLoopExample(SCStudyInterfaceRef sc)
{

    if (sc.SetDefaults)
    {
        // Set the configuration and defaults
        sc.GraphName = "Manual Loop Example";

        sc.StudyDescription = "This is an example of using manual looping.";
        sc.AutoLoop = 0; // 0 is the default: there is no auto-looping

        sc.Subgraph[0].Name = "High Low Difference";
        sc.Subgraph[1].Name = "High - Low Average";

        sc.Subgraph[2].Name = "Back Reference Example";
        sc.Subgraph[3].Name = "Forward Reference Example";

        return;
    }
    
    // Do data processing
    for (int Index = sc.UpdateStartIndex; Index < sc.ArraySize; Index++)
    {    
        // Calculate the difference between the high and the low
        sc.Subgraph[0][Index] = sc.BaseData[SC_HIGH][Index] - sc.BaseData[SC_LOW][Index];

        // SimpleMovAvg will fill in the data element in sc.Subgraph[1] at index Index.
        sc.SimpleMovAvg(sc.Subgraph[0], sc.Subgraph[1], Index, 10);

        // Copy the previous last price (Index-1) to subgraph array number 3
        sc.Subgraph[2][Index] = sc.BaseData[SC_LAST][Index - 1];

        // Copy the next last price (Index+1) to subgraph array number 4
        sc.Subgraph[3][Index] = sc.BaseData[SC_LAST][Index + 1];
    }
}
        

When the Study Function Is Called

The study function (begins with scsf_ in CPP file) for a study added to a chart is first called when an instance of the study is added to the chart, a Chartbook is opened and a chart in that Chartbook contains an instance of the study, or a Study Collection is applied to a chart and an instance of the study is part of that Study Collection.

The study function will be called separately for each instance of the study.

There are at least two calls to the study function for the conditions described above. Once to set the defaults of the study. In this case sc.SetDefaults is set to 1. The second call is for the full calculation of the study.

During this second call into the study function, in the case of manual looping, the study function will be called 1 time with sc.UpdateStartIndex set to 0, and usually will be called a third time when the chart is immediately updated after. On this third call, sc.UpdateStartIndex is set to sc.ArraySize -1.

During this second group of calls into the study function, in the case of automatic looping, the study function will be called once for each bar in the chart. sc.Index starts at 0 and increments for each bar in the chart. Therefore, this is a series of calls which can be thousands or more times. For simplicity with describing this process, this is considered the second group of calls into the study function. This is considered the full calculation. After this full recalculation is complete, usually there will be a third call into this study function when the chart is immediately updated after. During this third call, sc.Index is set to sc.ArraySize -1.

The next time to study function will be called again with either manual or automatic looping, after the above described calls, is for one or more of the conditions given below. None of the conditions described below, cause an immediate call. They flag that the study function needs to be called, and the call occurs at the Chart Update Interval set in Global Settings >> General Settings.

  • There is new trade market data received
  • Historical downloaded data received
  • Bid and ask data received
  • Market depth data received
  • Fundamental data received
  • New orders or order updates for the symbol and trade account the chart is set to.
  • Trade Position updates for the symbol and trade account the chart is set to.
  • When records are read from the chart data file during a Replay of an Intraday chart
  • When using sc.UpdateAlways = 1

In these cases the study function will be called when the Chart Update Interval set in Global Settings >> General Settings elapses, and not more often. Therefore, it does not happen immediately upon, for example a new trade occurring for the symbol. It will be soon as the Chart Update Interval has elapsed and there is new data which causes an update for one of the given reasons.

During an accelerated Chart Replay, the Chart Update Interval is reduced internally to a shorter time.

It is possible to have a study function called immediately whenever a new trade occurs by setting sc.OnExternalDataImmediateStudyCall. This should be used with great caution and only for specialized purposes because it will cause high CPU usage and possible freezing of the user interface.


*Last modified Friday, 12th August, 2016.