Login Page - Create Account

Support Board


Date/Time: Sun, 28 Apr 2024 19:51:06 +0000



[Programming Help] - Calculation based on subgraph values

View Count: 1491

[2017-06-24 03:36:55]
Neo - Posts: 198
Do you have any examples of how I can process a calculation based only on subgraph values, so it's either independent of base data, or ignores zero values?
imageMA subgraph exp.png / V - Attached On 2017-06-24 03:36:28 UTC - Size: 13.98 KB - 248 views
[2017-06-26 07:37:47]
Sierra Chart Engineering - Posts: 104368
Refer to:

ACSIL Programming Concepts: Using or Referencing Study/Indicator Data in an ACSIL Function
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, *change* to the Teton service:
Sierra Chart Teton Futures Order Routing
[2017-06-27 06:39:47]
Neo - Posts: 198
From the documentation you linked to I created a Moving Average study that calculates on subgraph values > 0 and ignores 0 values.

It does what I want, but has serious performance issues. I have tried to implement manual looping but can't seem to gain any performance improvement.

Any comments towards improving performance would be much appreciated.

// Test
#include "sierrachart.h"

SCDLLName("MA>Zero")

SCSFExport scsf_MovingAverageSimple(SCStudyInterfaceRef sc)
{
  SCSubgraphRef Avg = sc.Subgraph[0];

  SCInputRef InputStudy1 = sc.Input[0];
  SCInputRef Study1Subgraph = sc.Input[1];
  SCInputRef StudySubgraph1 = sc.Input[2];  
  SCInputRef Length = sc.Input[3];
  
  if (sc.SetDefaults)
  {
    sc.GraphName = "Moving Average - Zero";

    sc.GraphRegion = 0;
    sc.ValueFormat = 2;

    Avg.Name = "Avg";
    Avg.DrawStyle = DRAWSTYLE_LINE;
    Avg.PrimaryColor = RGB(0, 255, 0);
    Avg.LineWidth = 1;
    Avg.DrawZeros = true;

    Length.Name = "Length";
    Length.SetInt(4);
    Length.SetIntLimits(1, MAX_STUDY_LENGTH);
    
    InputStudy1.SetStudyID(0);
  
    Study1Subgraph.SetSubgraphIndex(0);

    StudySubgraph1.Name = "Study Subgraph Reference";
    StudySubgraph1.SetStudySubgraphValues(0,0);

    sc.FreeDLL = 1;

    return;
  }
  
  SCFloatArray Study1Array;
  sc.GetStudyArrayUsingID(StudySubgraph1.GetStudyID(), StudySubgraph1.GetSubgraphIndex(), Study1Array);

  int len = Length.GetInt();
  
  for (int Index = len - 1; Index < sc.ArraySize; Index++)
  {
    if (Study1Array[Index] <= 0.0f)
      continue;
  
    int count = 0;
    float summ = 0.0f;

    int i = Index;
    while(count < len)
    {
      float data = Study1Array[i];
      if (data > 0.0f)
      {
        summ += data;
        count ++;

      }
      i--;
    }
    
    if (count>0)
    {
      Avg[Index] = summ / count;
    }
    else
    {
      Avg[Index] = 0.0f;
    }
  }    
}

[2017-06-27 20:03:27]
mkata - Posts: 103
Neo,
Why not just use the built in function?

sc.MovingAverage(sc.BaseDataIn[SC_LAST], sc.Subgraph[0], MOVAVGTYPE_SIMPLE_SKIP_ZEROS, 20);
[2017-06-28 01:39:02]
Neo - Posts: 198
mkata,

Do you mean something like this-

#include "sierrachart.h"

SCDLLName("MivingAvgBigSmall")

SCSFExport scsf_MovingAverageBigSmall(SCStudyInterfaceRef sc)
{
  SCSubgraphRef Avg = sc.Subgraph[0];

  SCInputRef InputStudy1 = sc.Input[0];
  SCInputRef Study1Subgraph = sc.Input[1];
  SCInputRef StudySubgraph1 = sc.Input[2];  
  SCInputRef Length = sc.Input[3];
  if (sc.SetDefaults)
  {
    sc.GraphName = "Moving Average - Big and Small";

    sc.ValueFormat = 2;
    sc.AutoLoop = 1;

    Avg.Name = "Avg";
    Avg.DrawStyle = DRAWSTYLE_LINE;
    Avg.PrimaryColor = RGB(0, 255, 0);
    Avg.LineWidth = 1;
    Avg.DrawZeros = true;

    InputStudy1.SetStudyID(0);
    Study1Subgraph.SetSubgraphIndex(0);
    StudySubgraph1.Name = "Study Subgraph Reference(Big)";
    StudySubgraph1.SetStudySubgraphValues(0,0);

    Length.Name = "Length";
    Length.SetInt(4);
    Length.SetIntLimits(1, MAX_STUDY_LENGTH);
    
    sc.FreeDLL = 1;
    return;
  }
  
  SCFloatArray Study1Array;
  sc.GetStudyArrayUsingID(StudySubgraph1.GetStudyID(), StudySubgraph1.GetSubgraphIndex(), Study1Array);
  
  sc.MovingAverage(Study1Array,Avg,MOVAVGTYPE_SIMPLE_SKIP_ZEROS,Length.GetInt());
}

From my understanding SC don't have a built in function for what I require, so it requires a custom implementation

MOVAVGTYPE_SIMPLE_SKIP_ZEROS looks to skip zero values and replace them with the last value

eg MOVAVGTYPE_SIMPLE_SKIP_ZEROS, based on length 2, subgraph values: 10[],0[-1],5[-2] = 10
eg My Moving Average, based on length 2, subgrpah values: 10[],0[-1],5[-2]= 7.5


I could be wrong here in my undersatnding, So I stand to be corrected.
[2017-06-28 22:27:58]
mkata - Posts: 103
Yep you're right. I didn't pay close enough attention to the code. I was thinking that it completely skipped over the zeros but it does in fact replace them with the last value.
[2017-06-28 22:45:30]
Sierra Chart Engineering - Posts: 104368

MOVAVGTYPE_SIMPLE_SKIP_ZEROS looks to skip zero values and replace them with the last value

. I didn't pay close enough attention to the code. I was thinking that it completely skipped over the zeros but it does in fact replace them with the last value.
How do both of you come to this conclusion? This is not what MOVAVGTYPE_SIMPLE_SKIP_ZEROS actually does. And can be easily verified by looking at the provided code. The mathematical formula is also given here:
https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=353#Moving_Average_-_Simple_Skip_Zeros
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, *change* to the Teton service:
Sierra Chart Teton Futures Order Routing
Date Time Of Last Edit: 2017-06-28 22:51:53
[2017-06-28 23:45:47]
mkata - Posts: 103
Perhaps I should have said the zero value is included rather than replaced.

For example, with a 4-element array of 3,0,0,6 and a 2-period moving average the MOVAVGTYPE_SIMPLE_SKIP_ZEROS will return a value of 6.
However Neo was looking to skip the zero's and return a value of 4.5.
imageCLG6 1 Min #1 2017-06-28 19_39_46.783.png / V - Attached On 2017-06-28 23:42:05 UTC - Size: 43.47 KB - 241 views
[2017-06-29 00:52:32]
Neo - Posts: 198
Perhaps I should have said the zero value is included rather than replaced.

Sorry, I mislead you here! I hadn't look at the formula, I'd just had a quick look at the study on a 2-period length and it appeared to be replacing zero values with the last value. You probably made the same observation. Either way, it doesn't work with what I'm trying to implement. Thanks for your efforts anyway.
[2017-06-29 01:01:34]
Sierra Chart Engineering - Posts: 104368
OK we understand what you are looking for, we think.

How the study works according to the documentation is demonstrated here:
http://www.sierrachart.com/image.php?Image=1498695661172.png


This chart shows six test values.10, 0, 0, 0, 0 5. You can see result from the Moving Average Skip Zeros with a Length of 6 is 7.5.

It sounds like what you want, is to extend the length of the average, and skip over zero values and find nonzero values in order to meet the necessary Length.
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, *change* to the Teton service:
Sierra Chart Teton Futures Order Routing
Date Time Of Last Edit: 2017-06-29 01:02:51
[2017-06-29 02:03:03]
Neo - Posts: 198
Using that example, I want the result of 7.5, with a length of 2.

Is that how you understand it?
Date Time Of Last Edit: 2017-06-29 02:07:14
[2017-06-29 02:36:06]
Neo - Posts: 198
@Sierra Chart Engineering
-Don't waste your time trying to implement this for me, if that is what you were planning to do. Although I'd be very interested in seeing how you would do it, I now have a version with significant performance improvements. Any comments regarding further improvement would be appreciated.

// Test
#include "sierrachart.h"

SCDLLName("MaGreaterThanZerov5")

SCSFExport scsf_MovingAverageSimple(SCStudyInterfaceRef sc)
{
  SCSubgraphRef Avg = sc.Subgraph[0];

  SCInputRef InputStudy1 = sc.Input[0];
  SCInputRef Study1Subgraph = sc.Input[1];
  SCInputRef StudySubgraph1 = sc.Input[2];  
  SCInputRef Length = sc.Input[3];
  
  if (sc.SetDefaults)
  {
    sc.GraphName = "MaGreaterThanZerov5";

    sc.GraphRegion = 0;
    sc.ValueFormat = 2;

    Avg.Name = "Avg";
    Avg.DrawStyle = DRAWSTYLE_LINE;
    Avg.PrimaryColor = RGB(0, 255, 0);
    Avg.LineWidth = 1;
    Avg.DrawZeros = true;

    Length.Name = "Length";
    Length.SetInt(4);
    Length.SetIntLimits(1, MAX_STUDY_LENGTH);
    
    InputStudy1.SetStudyID(0);
  
    Study1Subgraph.SetSubgraphIndex(0);

    StudySubgraph1.Name = "Study Subgraph Reference";
    StudySubgraph1.SetStudySubgraphValues(0,0);

    sc.FreeDLL = 1;

    return;
  }
  
  SCFloatArray Study1Array;
  sc.GetStudyArrayUsingID(StudySubgraph1.GetStudyID(), StudySubgraph1.GetSubgraphIndex(), Study1Array);

  int len = Length.GetInt();
  float* temp = new float[len];

  int Index;
  for (Index = len - 1; Index < sc.ArraySize; Index++)
  {
    if (Study1Array[Index] <= 0.0f)
    {
      Avg[Index] = 0.0f;
      continue;
    }
    
    int count = 0;
    float summ = 0.0f;

    int i = Index;
    while(count < len && i >= 0)
    {
      float data = Study1Array[i];
      if (data > 0.0f)
      {
        temp[count] = data;
        summ += data;
        count ++;

      }
      i--;
    }
      
    if (count == len)
    {
      Avg[Index] = summ / count;
      break;
    }
    else
    {
      Avg[Index] = 0.0f;
    }  
  }

  for (int k = Index + 1; k < sc.ArraySize; k++)
  {
    if (Study1Array[k] <= 0.0f)
    {
      Avg[k] = 0.0f;
      continue;
    }
      
    float summ = 0.0f;
    for (int i = 0; i < len - 1; i ++)
    {
      summ += temp[i];
    }
    summ += Study1Array[k];
    Avg[k] = summ / len;

    for (int i = len - 1; i >= 1; i --)
    {
      temp[i] = temp[i - 1];
    }
    temp[0] = Study1Array[k];
  }
}

Date Time Of Last Edit: 2017-06-29 02:45:46
[2017-06-29 03:09:43]
Sierra Chart Engineering - Posts: 104368
This is extremely inefficient:

for (Index = len - 1; Index < sc.ArraySize; Index++)

It needs to be:

for (Index = sc.UpdateStartIndex; Index < sc.ArraySize; Index++)
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, *change* to the Teton service:
Sierra Chart Teton Futures Order Routing

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

Login

Login Page - Create Account