Login Page - Create Account

Support Board


Date/Time: Thu, 03 Jul 2025 18:22:06 +0000



Jma custom study for Sierra Chart

View Count: 110

[2025-06-15 17:21:03]
User520975 - Posts: 6
Could you add this to your custom studies?

#include "sierrachart.h"

SCDLLName("Jurik Moving Average (JMA)")

SCStudyInterfaceRef g_ChartInterface; // Global reference to access chart data

SCFloatArrayRef JMA = sc.Subgraph[0]; // Main JMA line
SCFloatArrayRef UpperBand = sc.Subgraph[1]; // Upper volatility band
SCFloatArrayRef LowerBand = sc.Subgraph[2]; // Lower volatility band
SCFloatArrayRef VoltyArray = sc.PersistVars->Floats[0]; // Persistent array for volatility (size 11)
SCFloatArrayRef VSum = sc.PersistVars->Floats[11]; // Persistent vSum
SCFloatArrayRef AvgVolty = sc.PersistVars->Floats[12]; // Persistent avgVolty
SCFloatArrayRef Det0 = sc.PersistVars->Floats[13]; // Persistent det0
SCFloatArrayRef Det1 = sc.PersistVars->Floats[14]; // Persistent det1
SCFloatArrayRef MA1 = sc.PersistVars->Floats[15]; // Persistent ma1
SCFloatArrayRef PrevJMA = sc.PersistVars->Floats[16]; // Persistent previous JMA

SCInputRef Period = sc.Input[0];
SCInputRef Phase = sc.Input[1];
SCInputRef Factor = sc.Input[2];
SCInputRef Source = sc.Input[3];

SCSubgraphRef JMA_Subgraph = sc.Subgraph[0];
SCSubgraphRef UpperBand_Subgraph = sc.Subgraph[1];
SCSubgraphRef LowerBand_Subgraph = sc.Subgraph[2];

void InitializeVoltyArray(SCStudyInterfaceRef sc, int index)
{
for (int i = 0; i < 11; i++)
VoltyArray[index * 11 + i] = 0.0f;
}

SCSFExport scsf_JurikMovingAverage(SCStudyInterfaceRef sc)
{
g_ChartInterface = sc; // Store chart interface for global access

if (sc.SetDefaults)
{
sc.GraphName = "Jurik Moving Average (JMA)";
sc.GraphRegion = 0;
sc.AutoLoop = 1;

// Subgraphs
JMA_Subgraph.Name = "JMA";
JMA_Subgraph.DrawStyle = DRAWSTYLE_LINE;
JMA_Subgraph.PrimaryColor = RGB(255, 255, 0); // Yellow
JMA_Subgraph.LineWidth = 2;

UpperBand_Subgraph.Name = "Jurik Upper Band";
UpperBand_Subgraph.DrawStyle = DRAWSTYLE_LINE;
UpperBand_Subgraph.PrimaryColor = RGB(128, 128, 128); // Gray
UpperBand_Subgraph.LineWidth = 1;

LowerBand_Subgraph.Name = "Jurik Lower Band";
LowerBand_Subgraph.DrawStyle = DRAWSTYLE_LINE;
LowerBand_Subgraph.PrimaryColor = RGB(128, 128, 128); // Gray
LowerBand_Subgraph.LineWidth = 1;

// Inputs
Period.Name = "Period";
Period.SetInt(14);
Period.SetIntLimits(1, MAX_STUDY_LENGTH);

Phase.Name = "Phase";
Phase.SetInt(0);
Phase.SetIntLimits(-100, 100);

Factor.Name = "Power";
Factor.SetFloat(0.45f);
Factor.SetFloatLimits(0.1f, 1.0f);

Source.Name = "Source";
Source.SetInputDataIndex(SC_LAST);

// Allocate persistent storage for VoltyArray (11 elements per bar)
sc.PersistVars->AllocateFloatArray(17); // 11 for VoltyArray, 1 each for vSum, avgVolty, det0, det1, ma1, prevJMA

sc.AddFillAreaToGraph(UpperBand_Subgraph, LowerBand_Subgraph, RGB(128, 128, 128), 70, "Jurik Volatility Zone");

return;
}

// Get input values
int period = Period.GetInt();
float phase = Phase.GetInt();
float factor = Factor.GetFloat();
SCFloatArray source = sc.BaseData[Source.GetInputDataIndex()];

// Pre-calculate constants
float phase_value = min(max((phase * 0.01f) + 1.5f, 0.5f), 2.5f);
float beta = factor * (period - 1) / ((factor * (period - 1)) + 2);
float len1 = max((log(sqrt(0.5f * (period - 1))) / log(2.0f)) + 2.0f, 0.0f);
float pow1 = max(len1 - 2.0f, 0.5f);
float len2 = sqrt(0.5f * (period - 1)) * len1;
float pow1Reciprocal = 1.0f / pow1;
float avgVoltyAlpha = 2.0f / (max(4.0f * period, 65) + 1.0f);
float div = 1.0f / (10.0f + 10.0f * (min(max(period - 10, 0), 100) / 100.0f));

int index = sc.Index;

// Initialize persistent variables at the first bar
if (index == 0)
{
UpperBand[index] = source[index];
LowerBand[index] = source[index];
MA1[index] = source[index];
JMA[index] = source[index];
VSum[index] = 0.0f;
Det0[index] = 0.0f;
Det1[index] = 0.0f;
AvgVolty[index] = 0.0f;
PrevJMA[index] = source[index];
InitializeVoltyArray(sc, index);
}
else
{
// Copy previous values
UpperBand[index] = UpperBand[index - 1];
LowerBand[index] = LowerBand[index - 1];
MA1[index] = MA1[index - 1];
JMA[index] = JMA[index - 1];
VSum[index] = VSum[index - 1];
Det0[index] = Det0[index - 1];
Det1[index] = Det1[index - 1];
AvgVolty[index] = AvgVolty[index - 1];
PrevJMA[index] = JMA[index - 1];

// Copy VoltyArray from previous bar
for (int i = 0; i < 11; i++)
VoltyArray[index * 11 + i] = VoltyArray[(index - 1) * 11 + i];
}

// Calculate volatility
float del1 = source[index] - UpperBand[index];
float del2 = source[index] - LowerBand[index];
float volty = (fabs(del1) == fabs(del2)) ? 0.0f : max(fabs(del1), fabs(del2));

// Update VoltyArray (circular buffer)
for (int i = 10; i > 0; i--)
VoltyArray[index * 11 + i] = VoltyArray[index * 11 + (i - 1)];
VoltyArray[index * 11 + 0] = volty;

// Calculate vSum
VSum[index] = VSum[index] + (volty - VoltyArray[index * 11 + 10]) * div;

// Calculate avgVolty
if (index == 0)
AvgVolty[index] = VSum[index];
else
AvgVolty[index] = AvgVolty[index - 1] + avgVoltyAlpha * (VSum[index] - AvgVolty[index - 1]);

// Calculate relative volatility
float rvolty = min(max(AvgVolty[index] > 0 ? volty / AvgVolty[index] : 1.0f, 1.0f), pow(len1, pow1Reciprocal));

// Calculate adaptive parameters
float pow2 = pow(rvolty, pow1);
float Kv = pow(len2 / (len2 + 1), sqrt(pow2));

// Update volatility bands
UpperBand[index] = (del1 > 0) ? source[index] : source[index] - Kv * del1;
LowerBand[index] = (del2 < 0) ? source[index] : source[index] - Kv * del2;

// Calculate dynamic factor alpha
float alpha = pow(beta, pow2);
float alphaSquared = alpha * alpha;
float oneMinusAlpha = 1.0f - alpha;
float oneMinusAlphaSquared = oneMinusAlpha * oneMinusAlpha;

// 1st stage - preliminary smoothing by adaptive EMA
MA1[index] = source[index] + (alpha * (MA1[index - 1] - source[index]));

// 2nd stage - preliminary smoothing by Kalman filter
Det0[index] = (source[index] - MA1[index]) * (1 - beta) + beta * Det0[index - 1];
float ma2 = MA1[index] + (phase_value * Det0[index]);

// 3rd stage - final smoothing by unique Jurik adaptive filter
Det1[index] = ((ma2 - PrevJMA[index]) * oneMinusAlphaSquared) + (alphaSquared * Det1[index - 1]);
JMA[index] = PrevJMA[index] + Det1[index];

// Update PrevJMA for next iteration
PrevJMA[index] = JMA[index];
}
[2025-06-17 19:12:48]
Sierra_Chart Engineering - Posts: 20064
Yes we will do that.
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, use the Teton service:
Sierra Chart Teton Futures Order Routing
[2025-06-17 19:58:16]
Sierra_Chart Engineering - Posts: 20064
We had a look at this, and we cannot include this study because it is using global variables. There must be no global variables at all. All variables must be within the study function itself.

Example:
SCStudyInterfaceRef g_ChartInterface;
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, use 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