Support Board
Date/Time: Thu, 03 Jul 2025 20:20:47 +0000
Post From: Jma custom study for Sierra Chart
[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]; } |