Login Page - Create Account

Support Board


Date/Time: Mon, 14 Apr 2025 01:23:14 +0000



[Programming Help] - sc.GetStudyIDByIndex / sc.GetStudyIDByName always return 0

View Count: 185

[2025-04-10 20:16:18]
Richard Chinn - Posts: 33
The issue is: Both GetStudyIDByIndex and GetStudyIDByName return 0 instead of the actual study instance.

From the current documentation (not complete) I am assuming these functions may not be fully implemented yet,
but I don't know so I wanted to bring them to your attention.

Here is what is happening:

My control study is running on chart number 1.
I am attempting to add the ATR technical study S_ID 19 to chart number 2 (actually charts 2-8).
My code sets "studyNumber" via sc.AddStudyToChart (I'm adding more than one study to a chart in a loop).
I pass chartNumber and studyNumber in to sc.GetStudyIndexById (expecting a return value of the study instance) and I save it.

That's it, the value always comes back as 1 on chart 1, and 0 on all other charts.

So To Test and see if I would get any value other than zero:
I manually set the studyNumber (GetStudyIDByIndex parameter) to multiple S_ID numbers (In multiple test runs) with the same result --> 0
and I also tested using instance numbers of studies on my chart with the same result --> 0

Here is my code snippet for reference:


int studyNumber = sc.AddStudyToChart(addStudy); --> This IS ADDING the study to the chart correctly
LOG_DEBUG("studyNumber: " + Stringify(studyNumber)); --> Returned studyNumber as 19 (For ATR study, S_ID) -> Correct

int actualStudyNumber = sc.GetStudyIDByIndex(pChartNumber, studyNumber);
LOG_DEBUG("actualStudyNumber: " + Stringify(actualStudyNumber)); --> Returned actualStudyNumber as 0 -> Wrong?

//---------------------------------------------------------------
// THESE ARE MY TESTS TO VERIFY WHAT THE FUNCTIONS ARE RETURNING
//---------------------------------------------------------------
    
int testId = sc.GetStudyIDByIndex(pChartNumber, studyNumber);
LOG_DEBUG("testId: " + Stringify(testId)); --> Returns testId as 0 I ran different tests:
studyNumber = 1-10 (My Study Instances),
studyNumber = S_ID (Study S_ID numbers)

int testNameId = sc.GetStudyIDByName(pChartNumber, EnumName(pStudy).c_str(), true);
LOG_DEBUG("testNameId: " + Stringify(testNameId)); --> Returns testNameId as 0

NOTES:
1. The return value is always 0, consistently on Charts 2-8
2. sc.AddStudyToChart IS returning the right S_ID numbers
3. It doesn't matter if the study being added is the first instance or the 10th, the return values (from the 2 functions) are always 0
  
4. IF the study is being added to chart number 1, where my control study is running as the 1st instance on the chart:
- This line: int actualStudyNumber = sc.GetStudyIDByIndex(pChartNumber, studyNumber); --> Returns 1
- The line immediately following it: int testStudyId = sc.GetStudyIDByIndex(pChartNumber, studyNumber); --> Returns 0
These are the same call just being assigned to different variables so they should be the same value.

- Both of these are returning the wrong values because my control study occupies instance 1 on chart 1 (minimally we should expect a value of 2 if no other studies are on the chart) and
- testStudyId should be the same as actualStudyNumber.
[2025-04-11 09:00:29]
User431178 - Posts: 645

int studyNumber = sc.AddStudyToChart(addStudy);
int actualStudyNumber = sc.GetStudyIDByIndex(pChartNumber, studyNumber);

- sc.AddStudyToChart returns only 0 or 1 when I use it (not that it is important here).
- The use of sc.GetStudyIDByIndex is wrong, studyNumber argument should be 1 based index (based on position in study window list) - see docs ACSIL Interface Members - Functions: sc.GetStudyIDByIndex()
- The newly added study won't be avaiable until after it is added/calculated, which will be after your study function returns. In other words if you iterate through the indexes, starting at 1, your newly added study will not show up until the next time you call your study function.
[2025-04-11 11:50:43]
Richard Chinn - Posts: 33
Thanks for the response and I did think about that.

That's why in my tests I manually used not only the S_ID numbers which are being returned correctly by sc.AddChartToStudy, but I also manually substituted all of my study instance numbers (1-10) in the tests. These are the numbers that show in the top line of the screen and also to the left of the study name. I never got anything but 1 on chart 1 and 0 on charts 2-8.

Also sc.GetStudyIDByName always returns 0.

I tested both because to be honest what documentation was there was hard for me to understand. My clue in the documentation that the S_ID number might be the right parameter was that it returns a sc.StudyGraphInstanceId. If you look that up it says:

The StudyGraphInstanceID is a unique number assigned to each study on a chart. This identifier number is for the particular instance of your custom study which is applied to the chart. This ID number can be seen in the Chart Studies window on the right side of the study name in the Studies to Graph list.

Date Time Of Last Edit: 2025-04-11 11:54:16
[2025-04-11 12:21:07]
User431178 - Posts: 645
S_ID is not anything to do with sc.StudyGraphInstanceId

In the chart studies window, studies to graph box, you have:
- Index as the left most number
- ID (aka StudyGraphInstanceId) as the next (ID:#)
- Lastly, after the study name you have the S_ID number (that which you use in sc.AddStudy)


Anyway, as I said, the other study data is not available at the same time as you initially add the study in your function, therefore the testing you are doing is fundamentally flawed.

The code below works ok for me, each time it is run a new study is added, then on the next run that study is found using sc.GetStudyIDByIndex.



SCSFExport scsf_GetStudyInformation(SCStudyInterfaceRef sc)
{
  if (sc.SetDefaults)
  {
    sc.GraphName = "Study Information";
    sc.GraphRegion = 0;
    sc.AutoLoop = 0;
    sc.ValueFormat = VALUEFORMAT_INHERITED;
    sc.ScaleRangeType = SCALE_SAMEASREGION;
    sc.GlobalDisplayStudySubgraphsNameAndValue = 0;
    sc.DisplayStudyInputValues = 0;
    sc.HideDLLAndFunctionNames = 1;

    sc.Input[0].Name = "Chart Number";
    sc.Input[0].SetChartNumber(0);

    sc.Input[1].Name = "Study to Add Internal ID";
    sc.Input[1].SetInt(19); // ATR

    return;
  }

  if (sc.UpdateStartIndex != 0)
    return;

  const auto chartNumber = sc.Input[0].GetChartNumber();
  const auto identifier = sc.Input[1].GetInt();

  if (chartNumber == 0
    || identifier <= 0)
    return;

  auto addStudy = n_ACSIL::s_AddStudy{};

  addStudy.ChartNumber = chartNumber;
  addStudy.StudyID = identifier;

  const auto result = sc.AddStudyToChart(addStudy);

  if (result != 0)
    sc.AddMessageToLog(SCString().Format("Result = %d | Study with internal ID %d added to chart number %d"
                      , result
                      , identifier
                      , chartNumber), 0);

  auto studyIndex{ 1 };

  while (true)
  {
    const auto id = sc.GetStudyIDByIndex(chartNumber, studyIndex++);

    if (id <= 0)
      break;

    const auto studyName = sc.GetStudyNameFromChart(chartNumber, id);

    sc.AddMessageToLog(SCString().Format("Study ID: %d, Name: %s"
                      , id
                      , studyName.GetChars()), 0);
  }
}

[2025-04-12 14:56:04]
Richard Chinn - Posts: 33
Thanks for your help and the code but it didn't work for me as it was.
Just to make sure it isn't something on my machine I downloaded the current version of Sierra Chart onto a new machine.
I used the Analysis->New/Open Custom Study Files and copied the code in and saved it.
I had to add two lines at the top which are:
#include "sierrachart.h"
SCDLLName("StudyInformation");

I used Analysis->Build Custom Studies DLL and compiled the .dll

When it executes, I get no messages that anything is happening at all.
So this is how I understand the study after the SetDefaults block:

1. The first guard only allows this study to run on the very first index -> Not an issue
if (sc.UpdateStartIndex != 0)
return;


2. Assign the sc.Input values to chartNumber and identifier -> Also not an issue

3. The second guard is catching an issue.
The code can never get past this guard because of:
sc.Input[0].SetChartNumber(0); in the SetDefaults block, which is then assigned to chartNumber here:
const auto chartNumber = sc.Input[0].GetChartNumber(); So chartNumber is assigned zero.
When the guard checks it, it fails because chartNumber is zero:
if (chartNumber == 0 || identifier <= 0)
return;

4. All I had to do was change: sc.Input[0].SetChartNumber(0); TO sc.Input[0].SetChartNumber(1); to get the study to work.

The revised code returns the right values as you stated but:
- It takes two study execution cycles so the while(true) loop runs at least twice.
- The issue is not readily apparent without a counter.
If we add one more study and a counter the issue is easier to see.

I used the study you supplied and:
- Modified it to add an additional study.
- Added an execCounter to show how many times the study runs while sc.Index is zero. (3 times on my machine)
- Provided the log below, its short.

You can see in the study I manually add two studies to the chart before the while(true) loop.
That should mean all three studies are available to the while(true) loop each time the loop is entered.

On the first Study execution (execCounter == 1), the while(true) loop only displays the "Study Information" study (correct but should have displayed all 3)

On the second execution (execCounter == 2), the while(true) loop only displays the first and second study (As above, the values are correct but it should have displayed all 3)

It's not until the third execution (execCounter == 3) that all three studies are displayed and at this point, they are all displayed correctly.

In my personal study I assume the information is available once the studies are added, I don't perform multiple loops to obtain the information because according to the documentation, sc.AddStudyToChart returns the unique sc.StudyGraphInstanceID, which is exactly the value I am trying to get. I do this in my code:
const auto result = sc.AddStudyToChart(addStudy),
then use the "Result", expecting it to be correct.


If I understand what is happening correctly...
- The real issue is NOT: sc.GetStudyIDByIndex (which does show the correct values, proved in the while loop)
- The real issue is: The return value of sc.AddStudyToChart (I added two studies, ATR and EMA, so the "Result" should be 2 and 3 respectively because "Study Information" is 1, the first study instance on the chart)


You can see in the log output, that Result == 1 each time the study executes on every study, (this is where I think the issue is).
- The Results provided by sc.AddStudyToChart are not used in the while(true) loop.
- We are making the evaluation this way: const auto id = sc.GetStudyIDByIndex(chartNumber, studyIndex++);
- The while(true) loop is providing the correct values but only 1 study at a time.
- The loop has to execute (not iterate) three times to provide the correct values for all three studies.
- It is correctly displaying study values because we are not evaluating the return values of sc.AddStudyToChart.

LOG:
2025-04-12 12:51:14.036 | Loading DLL: C:\SierraChart\Data\GetStudyInformation.dll (GetStudyInformation_64.dll). Handle: 66000000
2025-04-12 12:51:22.876 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | EXECUTION COUNTER: sc.Index == 0 | execCounter == 1
2025-04-12 12:51:22.876 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | ATR: Result == 1 | Study with internal ID 19 added to chart number 1
2025-04-12 12:51:22.876 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | EMA: Result == 1 | Study with internal ID 27 added to chart number 1
2025-04-12 12:51:22.876 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | while(true): Study ID: 1, Name: Study Information
2025-04-12 12:51:22.912 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | EXECUTION COUNTER: sc.Index == 0 | execCounter == 2
2025-04-12 12:51:22.912 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | ATR: Result == 1 | Study with internal ID 19 added to chart number 1
2025-04-12 12:51:22.912 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | EMA: Result == 1 | Study with internal ID 27 added to chart number 1
2025-04-12 12:51:22.912 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | while(true): Study ID: 1, Name: Study Information
2025-04-12 12:51:22.912 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | while(true): Study ID: 2, Name: Average True Range
2025-04-12 12:51:22.917 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | EXECUTION COUNTER: sc.Index == 0 | execCounter == 3
2025-04-12 12:51:22.917 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | ATR: Result == 1 | Study with internal ID 19 added to chart number 1
2025-04-12 12:51:22.917 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | EMA: Result == 1 | Study with internal ID 27 added to chart number 1
2025-04-12 12:51:22.917 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | while(true): Study ID: 1, Name: Study Information
2025-04-12 12:51:22.917 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | while(true): Study ID: 2, Name: Average True Range
2025-04-12 12:51:22.917 | Chart: Replay 1.00X: ESM25-CME[M] 1 Min #1 | Study: Study Information | while(true): Study ID: 3, Name: Moving Average - Exponential

And Here is the revised study you sent me:

#include "sierrachart.h"

SCDLLName("StudyInformation");

SCSFExport scsf_GetStudyInformation(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Study Information";
sc.GraphRegion = 0;
sc.AutoLoop = 0;

sc.ValueFormat = VALUEFORMAT_INHERITED;
sc.ScaleRangeType = SCALE_SAMEASREGION;
sc.GlobalDisplayStudySubgraphsNameAndValue = 0;
sc.DisplayStudyInputValues = 0;
sc.HideDLLAndFunctionNames = 1;

sc.Input[0].Name = "Chart Number";
sc.Input[0].SetChartNumber(1); // REVISED FROM 0 TO 1

sc.Input[1].Name = "Study to Add Internal ID";
sc.Input[1].SetInt(19); // ATR

  sc.Input[2].Name = "Exponential Moving Avaerage";
  sc.Input[2].SetInt(27); // EMA

return;

}


if (sc.UpdateStartIndex != 0) {
return;
}

// Add an execution counter
//-------------------------
static int execCounter = 0; // This counts how many times the study executes while sc.Index == 0
sc.AddMessageToLog(SCString().Format("EXECUTION COUNTER: sc.Index == %d | execCounter == %d", sc.Index, ++execCounter), 0);

const auto chartNumber = sc.Input[0].GetChartNumber();

// Add an ATR study to the chart
//------------------------------
const auto atrIdentifier = sc.Input[1].GetInt();
auto atrStudy = n_ACSIL::s_AddStudy{};
atrStudy.ChartNumber = chartNumber;
atrStudy.StudyID = atrIdentifier;
const auto atrResult = sc.AddStudyToChart(atrStudy);

if(chartNumber == 0 || atrIdentifier <= 0)
   return;


if (atrResult != 0)

sc.AddMessageToLog(SCString().Format("ATR: Result == %d | Study with internal ID %d added to chart number %d"
, atrResult
, atrIdentifier
, chartNumber), 0);


// Add an EMA study to the chart
//------------------------------
const auto emaIdentifier = sc.Input[2].GetInt();
auto emaStudy = n_ACSIL::s_AddStudy{};
emaStudy.ChartNumber = chartNumber;
emaStudy.StudyID = emaIdentifier;
const auto emaResult = sc.AddStudyToChart(emaStudy);

if(chartNumber == 0 || emaIdentifier <= 0)
   return;


if (emaResult != 0)

sc.AddMessageToLog(SCString().Format("EMA: Result == %d | Study with internal ID %d added to chart number %d"
, emaResult
, emaIdentifier
, chartNumber), 0);


// Display Study Data In Loop
//---------------------------
auto studyIndex{ 1 };

while (true)
{

const auto id = sc.GetStudyIDByIndex(chartNumber, studyIndex++);

if (id <= 0)
break;

const auto studyName = sc.GetStudyNameFromChart(chartNumber, id);

sc.AddMessageToLog(SCString().Format("while(true): Study ID: %d, Name: %s"
, id
, studyName.GetChars()), 0);
}
}

[2025-04-12 15:11:41]
User431178 - Posts: 645

I had to add two lines at the top which are:
#include "sierrachart.h"
SCDLLName("StudyInformation");

Yes, sorry, I pasted it from a larger file that had those values set at the very top and forgot to include them for you here.


3. The second guard is catching an issue.
The code can never get past this guard because of:
sc.Input[0].SetChartNumber(0); in the SetDefaults block, which is then assigned to chartNumber here:
const auto chartNumber = sc.Input[0].GetChartNumber(); So chartNumber is assigned zero.
When the guard checks it, it fails because chartNumber is zero:
if (chartNumber == 0 || identifier <= 0)
return;

4. All I had to do was change: sc.Input[0].SetChartNumber(0); TO sc.Input[0].SetChartNumber(1); to get the study to work.

Fine, but you don't need to change that, the whole point is that you can set the chart number via the study settings interface.
The default value of 0 means that it doesn't do anything when you first add it to the chart (unless you change the input to the desired chart).





In my personal study I assume the information is available once the studies are added, I don't perform multiple loops to obtain the information because according to the documentation, sc.AddStudyToChart returns the unique sc.StudyGraphInstanceID, which is exactly the value I am trying to get. I do this in my code:
const auto result = sc.AddStudyToChart(addStudy),
then use the "Result", expecting it to be correct.

If I understand what is happening correctly...
- The real issue is NOT: sc.GetStudyIDByIndex (which does show the correct values, proved in the while loop)
- The real issue is: The return value of sc.AddStudyToChart (I added two studies, ATR and EMA, so the "Result" should be 2 and 3 respectively because "Study Information" is 1, the first study instance on the chart)

No

The return value of sc.AddStudyToChart is completely irrelevant (other than to indicate that it executed successfuly), I only included the "Result" variable so you could see it in the log.
Where exactly in the docs does it state that the sc.AddStudyToChart function returns the unique sc.StudyGraphInstanceID?

The problem is simply that the new studies are not available until the chart (or other chart) is calculated again, and this does not occur until after your study function returns.
It is wrong to assume that the information is immediately available, as it is not.
Date Time Of Last Edit: 2025-04-12 15:15:14
[2025-04-13 12:04:55]
Richard Chinn - Posts: 33
Hey, Thanks for digging in to this, I really appreciate it!

I do try to exhaust every possibility I can think of before ever considering contacting you guys.
I don't want to waste your time on something I should be able to resolve on my own!

This is the first time in a long time that I have been unable to figure something out.
You are right about the return value of sc.AddStudyToChart. With all the back and forth trying to figure out what exactly was happening I confused it with the sc.GetStudyIdByIndex return value. The documentation doesn't say what the return value is for sc.AddStudyToChart.

Now that I am clear on what is happening, I will restructure my code to handle it differently.
Thanks Again!
[2025-04-13 12:51:26]
User431178 - Posts: 645
I am not support, just another random user who'd run into the same problem in the past.
Hope you get your program worked out to you satisfaction.
[2025-04-13 18:02:12]
Richard Chinn - Posts: 33
Hey I appreciate it! I haven’t contacted support for more than 3 or 4 issues in 10 years because I respect their time and effort too much to ask them to figure out something for me that I should be able to do on my own! I’m glad you stepped in and helped me and I really do appreciate it more than you know!

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account