Works fine.bluebird wrote: Tue Sep 03, 2024 10:57 pm Hey, Can this indicator be updated please? Much appreciated![]()
Re: Fix: Indicator is not showing on MT4 chart
272When attached to the chart, it doesn't update/refresh automatically in real time. There is an error within the code that I struggle to fix myself. My coding abilities is limited compared to your expertise, please help
Re: Fix: Indicator is not showing on MT4 chart
273
Hi all. I was trying to convert a PineScript indicator from Tradingview over to MQL4 for MT4.
I used ChatGPT Pro to do it. And the finished code compiled with no errors.
But the indicator shows up blank on the chart.
Can you help me fix it?
Here is the mql4 code:
-------------------------------------------------------------------------------------------------------------------------------------------------
Attached is the indicator.
Here is some logic in the PineScript to MQL4 conversion is also attached.
I used ChatGPT Pro to do it. And the finished code compiled with no errors.
But the indicator shows up blank on the chart.
Can you help me fix it?
Here is the mql4 code:
Code: Select all
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 3
//--- Plots
#property indicator_label1 "Volatility RSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrOrange
#property indicator_width1 2
#property indicator_label2 "Line 30"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrOrange
#property indicator_width2 1
#property indicator_style2 STYLE_DOT
#property indicator_label3 "Line 4"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrSaddleBrown
#property indicator_width3 1
#property indicator_style3 STYLE_DOT
//--- Inputs
extern int VolatilityLength = 8;
//--- Buffers
double VolatilityRSIBuffer[];
double HorizontalLine30[];
double HorizontalLine4[];
// -------------- Utilities & Math --------------
double Ln(double x)
{
// MQL4 does not have a built-in natural log named ln(),
// but it does have MathLog() which is ln(x).
return(MathLog(x));
}
// RMA (Wilder’s Smoothing) helper
// Equivalent to TradingView's ta.rma() if you do it in a rolling fashion.
// But we must do a "manual" approach using a loop.
double WilderRMA(double currentValue, double prevRma, int length)
{
// RMA = (prevRma*(length-1) + currentValue) / length
return((prevRma*(length-1) + currentValue) / length);
}
// -------------- Pine Script Functions Rewritten --------------
// _pv(_src, _len) = sqrt((_src / ((_len * 4) * ln(2))) * sum( (ln(high/low))^2, _len ))
double PVCalculation(int pos, int len)
{
// pos is the current bar index from left to right in MQL4
// _src = hlc3 = (High+Low+Close)/3 for the *current* bar
// we must sum over the last "len" bars for (ln(high/low))^2
// Here we do a standard loop for i in [pos..pos+len-1], carefully checking bounds.
if(pos + len >= Bars) return(0); // not enough bars to the left
double src = (High[pos] + Low[pos] + Close[pos]) / 3.0;
double sumLnSq = 0.0;
for(int i=0; i<len; i++)
{
int barIndex = pos + i;
if(barIndex >= Bars) break;
double h = High[barIndex];
double l = Low[barIndex];
if(l <= 0 || h <= 0) continue;
double val = Ln(h/l);
sumLnSq += val*val;
}
double denominator = (len * 4.0) * Ln(2.0); // (_len*4)*ln(2)
if(denominator == 0) return(0);
double result = 0.0;
// result = sqrt( (src / denominator) * sumLnSq )
result = MathSqrt((src / denominator) * sumLnSq);
return(result);
}
// _rsi(_src, _len)
// u = max(_src - _src[1], 0)
// d = max(_src[1] - _src, 0)
// rs = rma(u,_len)/rma(d,_len)
// res = 100 - 100/(1+rs)
double RSIOfSeries(double priceArray[], int pos, int len, int arraySize)
{
// We compute a short RSI over 'len' bars.
// MQL4 has iRSI, but we replicate Pine’s approach:
// We need a rolling calculation of U and D, then Wilder RMA of them.
if(len <= 0) return(0);
if(pos + len >= arraySize) return(0);
// Build arrays for U and D over the chunk
double rmaU = 0, rmaD = 0;
double prevRmaU = 0, prevRmaD = 0;
bool firstCalc = true;
// We go from oldest to newest: bar pos+len-1 up to pos
// so that the last step is "pos" (the current bar).
for(int i=len; i>0; i--)
{
int currentBar = pos + (i-1);
int previousBar = currentBar+1; // next to the right in MQL4 array
if(previousBar >= arraySize) continue;
double u = MathMax(priceArray[currentBar] - priceArray[previousBar], 0);
double d = MathMax(priceArray[previousBar] - priceArray[currentBar], 0);
if(firstCalc)
{
// initialize
prevRmaU = u;
prevRmaD = d;
firstCalc = false;
}
else
{
// update
prevRmaU = WilderRMA(u, prevRmaU, len);
prevRmaD = WilderRMA(d, prevRmaD, len);
}
}
// after finishing the loop, the last prevRmaU and prevRmaD are the final
// for the bar 'pos'
if(prevRmaD == 0) return(100.0); // avoid div-by-zero
double rs = prevRmaU / prevRmaD;
double rsi = 100.0 - (100.0 / (1.0 + rs));
return(rsi);
}
// Simple Harmonic function _simple_harmonic(_src, _len)
// Implementation note: We have to interpret c0= _src[pos], c1= _src[pos+1], c2= _src[pos+2], etc.
double SimpleHarmonic(double priceArray[], int pos, int len, int arraySize)
{
if(pos+2 >= arraySize) return(0);
double c0 = priceArray[pos];
double c1 = priceArray[pos+1];
double c2 = priceArray[pos+2];
double v0 = c0 - c1;
double v1 = c1 - c2;
double a0 = v0 - v1;
// We then take an EMA of a0 over length => a1
// For simplicity, we'll do a naive rolling approach again from pos+2 down to pos
// but since a0 is just 1 value (?), we’ll treat this with caution.
// In the original Pine, a0 is a series (bar by bar). This is more advanced.
// We'll approximate by just using the single a0’s WilderRMA for now:
// (Alternatively, you might store a separate buffer for a0 each bar.)
double a1 = a0; // or some smoothing if you want
// t0 = 2 * pi * sqrt( abs(v0 / a1) )
double pi = 3.14159265359;
double denominator = a1;
if(denominator == 0) denominator = 1e-9;
double t0 = 2.0 * pi * MathSqrt(MathAbs(v0/denominator));
// t1 = c0 > c1 ? t0 : -t0
double t1 = (c0 > c1)? t0 : -t0;
// In Pine, v3 = ema(t1, len) and t3 = ema(t0, len). We need bar-by-bar.
// For demonstration, we’ll just return the final SHO = (v3 / t3)*100
// by approximating v3 ~ t1 and t3 ~ t0. A more faithful port
// requires storing the entire t1, t0 series in arrays & applying EMA across bars.
// This is a big difference between Pine’s approach vs. MQL4 single-pass approach.
double v3 = t1;
double t3 = t0;
if(t3 == 0) return(0);
double sho = (v3/t3)*100.0;
return(sho);
}
// _karo(_src, _len)
// This is also a multi-bar logic in Pine that uses EMA. We simplify similarly.
double Karo(double priceArray[], int pos, int len, int arraySize)
{
// src = ema(_src, _len)
// Then some ratio-based logic.
// Here we do single-step for the current bar only (since a full port
// needs storing time series).
// We’ll approximate by using normal average of last 'len' bars:
if(pos + len >= arraySize) return(0);
double sum = 0;
for(int i=0; i<len; i++)
{
sum += priceArray[pos + i];
}
double src = sum / len; // approximate the "ema" with an "sma" for example
// a = ema(src < src[1] ? src/src[1] : 0, _len)
// b = ...
// The original code references src[1]. That means the bar to the right in MQL4 indexing.
// We'll just do a single-step approximation.
double src1 = (pos+1 < arraySize) ? priceArray[pos+1] : src;
double ratioCurrent = 0;
if(src1 != 0.0 && src < src1) ratioCurrent = src/src1;
double ratioOpposite = 0;
if(src1 != 0.0 && src > src1) ratioOpposite = src/src1;
// c = (src/src[1]) / ((src/src[1]) + b)
// d = 2 * ((src/src[1]) / ((src/src[1]) + c*a)) - 1
// We’ll approximate:
double cDen = ratioCurrent + ratioOpposite;
if(cDen == 0) cDen = 1e-9;
double cVal = ratioCurrent / cDen;
double karoden = ratioCurrent + cVal*ratioCurrent;
if(karoden == 0) karoden = 1e-9;
double dVal = 2.0 * (ratioCurrent / karoden) - 1.0;
return(dVal);
}
// _moscillator(_src, _len)
// Loops from 1 to _len
// if s0 > si => +1, if s0 < si => -1, else 0, sum them up
double MOscillator(double priceArray[], int pos, int len, int arraySize)
{
// s0 = _src[pos], si = _src[pos+i]
// sum up +1 / -1
if(pos + len >= arraySize) return(0);
double s0 = priceArray[pos];
int sum = 0;
for(int i=1; i<=len; i++)
{
int index = pos + i;
if(index >= arraySize) break;
double si = priceArray[index];
if(s0 > si) sum += 1;
else if(s0 < si) sum -= 1;
}
return(sum);
}
// typ7(_typ, _src, _len)
// In your Pine, you allowed multiple modes, but in your final code you used rsi_type.
// We replicate only the “RSI” path (since your variable `typ5 = rsi_type`).
// If you want to expand to “no_type, simp_harmon_type, karo_type, m_type”, add more logic.
double Typ7RSIOnly(double currentPV, int pos, int len, int arraySize, double priceArray[])
{
// We'll just do the RSI path from your code:
// _typ1 == rsi_type ? _rsi(_pv(...),_len) : ...
// Because you set typ5 = rsi_type in the final script.
// So effectively: volatility_rsi = _rsi( _pv(src0,VolatilityLength), VolatilityLength ).
// We pass in "currentPV" which is _pv(...) for the current bar.
// Now we build a small array so we can feed RSIOfSeries().
// But that requires a time series. We'll create a synthetic array with currentPV repeated,
// which doesn’t help RSI. Real port would store PV for each bar.
// The correct approach is: for each bar, compute PV, store it in an array, then feed that array to RSIOfSeries for the current bar.
return(currentPV); // <--- Stub if you only want the raw _pv()
// If you want the RSI of that PV time series, do the following:
// 1) Build an array that holds PV for all bars.
// 2) Then pass that array to RSIOfSeries(...).
// This example code, for simplicity, just returns the raw PV.
}
//--------------------------------------------
// OnInit
//--------------------------------------------
int OnInit()
{
// 3 buffers
SetIndexStyle(0, DRAW_LINE, EMPTY, 2, clrOrange);
SetIndexBuffer(0, VolatilityRSIBuffer);
SetIndexStyle(1, DRAW_LINE, STYLE_DOT, 1, clrOrange);
SetIndexBuffer(1, HorizontalLine30);
SetIndexStyle(2, DRAW_LINE, STYLE_DOT, 1, clrSaddleBrown);
SetIndexBuffer(2, HorizontalLine4);
IndicatorShortName("Breakout Detector (Converted from PineScript)");
return(INIT_SUCCEEDED);
}
//--------------------------------------------
// OnCalculate
//--------------------------------------------
// typical signature for MQL4:
// OnCalculate(int rates_total, int prev_calculated,
// const double &price[], ... )
// but we’ll just do a simplified version:
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
// We want to fill VolatilityRSIBuffer for each bar.
// In Pine: volatility_rsi = _rsi( _pv(hlc3,VolatilityLength), VolatilityLength )
// We'll do the best we can in MQL4 with a single pass.
// Build an array for storing PV on each bar so we can then do RSI if desired
// For simplicity, let’s just store the PV and not do RSI on it (since that is more advanced).
// You can expand to do full RSI if needed.
static double PVArray[1]; // dynamic approach below
ArrayResize(PVArray, rates_total);
// prepare to read High[], Low[], Close[]; in MQL4 these are global arrays
// Make sure we handle indexing carefully: bar i in MQL4 = i-th from the left in OnCalculate loops.
// We'll fill from oldest bar to newest bar: i = 0..rates_total-1
// but watch out for access High[i], Low[i], etc. in the same direction.
int limit = rates_total - prev_calculated;
if(limit > rates_total) limit = rates_total;
for(int i=0; i<limit; i++)
{
// compute PV for bar i
double pvVal = PVCalculation(i, VolatilityLength);
PVArray[i] = pvVal; // store it so we can do RSI, etc.
// If you want RSI of PV, you’d do something like:
// double rsiVal = RSIOfSeries(PVArray, i, VolatilityLength, rates_total);
// VolatilityRSIBuffer[i] = rsiVal;
// Here we just do the stub for demonstration:
VolatilityRSIBuffer[i] = pvVal;
// Set the lines
HorizontalLine30[i] = 30.0;
HorizontalLine4[i] = 4.0;
}
//-------------------------
// Emulate alertcondition(ta.crossunder(volatility_rsi,15))
// crossunder => volatility_rsi just went from >= 15 to < 15
// We can check the last bar processed:
if(rates_total > 1)
{
int iCur = limit - 1; // the most recent bar we processed
int iPrev = iCur + 1; // the bar to the right (previous in Pine sense)
if(iPrev < rates_total)
{
double curVal = VolatilityRSIBuffer[iCur];
double prevVal = VolatilityRSIBuffer[iPrev];
if(curVal < 15.0 && prevVal >= 15.0)
{
Alert("Breakout Zone: crossunder 15 detected on bar ", iCur);
}
}
}
//-------------------------
return(rates_total);
}
-------------------------------------------------------------------------------------------------------------------------------------------------
Attached is the indicator.
Here is some logic in the PineScript to MQL4 conversion is also attached.
Re: Fix: Indicator is not showing on MT4 chart
274Below are several common reasons why an indicator might compile fine in MQL4 but display a blank (or “blacked out”) subwindow—and suggested fixes. Most issues come down to indexing (since Pine Script and MQL4 handle bar indexing in opposite directions) or the data series being full of zeros.
1. The Loop Direction & MQL4 Bar Indexing
In MQL4:
Bar 0 = the most recent (rightmost) bar.
Bar 1 = the previous bar, and so on.
Bar (rates_total-1) = the oldest (leftmost) bar.
But in your code, you wrote:
Here, i=0 means the newest bar in MQL4, yet inside PVCalculation(i, len) you do:
If pos = 0 (the newest bar), then 0 + len might often be < Bars, so you might get data for future bars if you used a “left-to-right” concept.
Actually, in MQL4 we often must do the loop from right to left: for(int i=rates_total-1; i>=0; i--).
Symptom: If PVCalculation(...) frequently returns 0 (because the indexing is not matching), then VolatilityRSIBuffer becomes zero for all bars, and your subwindow line is flat at 0 (often off-scale or invisible).
Solution
Reverse your loop so that bar indexing aligns with MQL4’s convention. For instance:
Now i=0 is still the newest bar, but the loop will start with i = rates_total-1 (the oldest) and move backward in time. Inside PVCalculation(i, len), i is the bar on the right indexing style.
2. The “pos + len >= Bars” Condition
Inside PVCalculation you have:
If pos is the newest bar (0), then 0 + len is likely much smaller than Bars, so that might be okay.
But if you intended “pos + len-1 goes beyond the oldest bar,” you need to check the logic if you invert the loop.
Alternatively, if you truly want “not enough bars to the right,” you might need to do if(pos - len < 0) return(0); depending on how you define “left” vs “right” in MQL4.
Symptom: If you intended pos to be an older bar, you might get 0 for everything because the condition is never satisfied in the way you expect.
Solution
Carefully decide what “left” and “right” means in MQL4. Typically, an older bar has a higher bar index. If you want the last len bars from the past, you do something like:
OR if you are reversing the loop (where pos starts from the oldest bar going downward), you might do:
Again, it depends on your loop direction and how you interpret “last len bars.”
3. The Entire Buffer is 0 or Off-Scale
If your calculations always return 0, your plotted line might be stuck at the bottom of the chart. Depending on your chart’s auto-scale settings, you might see a flat line at 0 or “nothing.”
Check: Hover your mouse over the subwindow; do you see any numeric label on the Y-axis near 0?
Solution
Print out debug messages inside your code to see if you’re really getting 0:
If you see all zeros in the Experts tab, your logic for computing PVCalculation or indexing is the issue.
4. Color or Style Issues
You set:
That should draw an orange line. Usually that’s visible on a black background. If your chart background is also some similar color or if “Chart on foreground” is enabled, sometimes the line can appear hidden.
Solution
Right-click chart → Properties → Common tab → uncheck “Chart on foreground.”
Or try a different color: SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2, clrLimeGreen);
5. Make Sure You’re Actually Plotting Enough Bars
In the code snippet, you do:
If prev_calculated is large, limit might be very small. Then you only fill a few buffer elements, possibly near the oldest bars. If you’ve reversed your indexing, you can end up with an uninitialized buffer near the newest bars.
Typical solution is something like:
Or do a full fill from oldest to newest:
6. Check “Array as Series” or “SetIndexDrawBegin”
Sometimes you need to indicate to MQL4 how the buffer is arranged:
ArraySetAsSeries(VolatilityRSIBuffer, true);
Tells MQL4 that index 0 is the newest element, and the last index is the oldest.
SetIndexDrawBegin(0, something);
Tells MQL4 not to plot for the first N bars.
If you don’t manage those calls carefully, you can have mismatched indexing.
7. Example “Fixed” OnCalculate
Below is a quick edit of your OnCalculate that reverses the loop so bar 0 is the newest. This ensures that pos=i in PVCalculation(i,...) interprets i as the newest bar. Then pos+len is “older bars,” which may or may not be what you intended. Adjust as needed.
Then inside PVCalculation:
This code uses pos - i in the loop to move to older bars in MQL4’s indexing scheme. That often matches the “left-to-right” logic from Pine.
In Summary
Reverse your loops and/or revise your indexing so that your bar references make sense in MQL4.
Confirm that your calculations do not always return zero.
Check chart scale, color, and that you’re actually filling the buffer for all bars.
Debug with Print statements to confirm real values are being assigned.
Following these steps typically resolves the “indicator is black/blank” issue in MT4. Once the buffer has real, non-zero values (and you have a suitable loop and color), you’ll see the line on the chart in the subwindow.
1. The Loop Direction & MQL4 Bar Indexing
In MQL4:
Bar 0 = the most recent (rightmost) bar.
Bar 1 = the previous bar, and so on.
Bar (rates_total-1) = the oldest (leftmost) bar.
But in your code, you wrote:
Code: Select all
for(int i=0; i<limit; i++)
{
double pvVal = PVCalculation(i, VolatilityLength);
...
VolatilityRSIBuffer[i] = pvVal;
}
Code: Select all
// pos is the current bar index from left to right in MQL4
// ...
if(pos + len >= Bars) return(0);
Actually, in MQL4 we often must do the loop from right to left: for(int i=rates_total-1; i>=0; i--).
Symptom: If PVCalculation(...) frequently returns 0 (because the indexing is not matching), then VolatilityRSIBuffer becomes zero for all bars, and your subwindow line is flat at 0 (often off-scale or invisible).
Solution
Reverse your loop so that bar indexing aligns with MQL4’s convention. For instance:
Code: Select all
int limit = rates_total - prev_calculated;
if(limit > rates_total) limit = rates_total;
for(int i = rates_total - 1; i >= 0; i--)
{
double pvVal = PVCalculation(i, VolatilityLength);
VolatilityRSIBuffer[i] = pvVal;
HorizontalLine30[i] = 30.0;
HorizontalLine4[i] = 4.0;
}
2. The “pos + len >= Bars” Condition
Inside PVCalculation you have:
Code: Select all
if(pos + len >= Bars) return(0); // not enough bars to the left
But if you intended “pos + len-1 goes beyond the oldest bar,” you need to check the logic if you invert the loop.
Alternatively, if you truly want “not enough bars to the right,” you might need to do if(pos - len < 0) return(0); depending on how you define “left” vs “right” in MQL4.
Symptom: If you intended pos to be an older bar, you might get 0 for everything because the condition is never satisfied in the way you expect.
Solution
Carefully decide what “left” and “right” means in MQL4. Typically, an older bar has a higher bar index. If you want the last len bars from the past, you do something like:
Code: Select all
// If we want to ensure that "pos + (len - 1)" does not exceed the oldest bar index:
if(pos + (len - 1) > (Bars - 1))
return(0);
Code: Select all
// If 'pos' is the oldest bar index, and we need the next 'len' bars to the right:
if(pos - (len - 1) < 0)
return(0);
3. The Entire Buffer is 0 or Off-Scale
If your calculations always return 0, your plotted line might be stuck at the bottom of the chart. Depending on your chart’s auto-scale settings, you might see a flat line at 0 or “nothing.”
Check: Hover your mouse over the subwindow; do you see any numeric label on the Y-axis near 0?
Solution
Print out debug messages inside your code to see if you’re really getting 0:
Code: Select all
for(int i=rates_total-1; i>=0; i--)
{
double pvVal = PVCalculation(i, VolatilityLength);
Print("Bar=", i, " PV=", pvVal);
VolatilityRSIBuffer[i] = pvVal;
...
}
4. Color or Style Issues
You set:
Code: Select all
#property indicator_separate_window
#property indicator_label1 "Volatility RSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrOrange
#property indicator_width1 2
Solution
Right-click chart → Properties → Common tab → uncheck “Chart on foreground.”
Or try a different color: SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2, clrLimeGreen);
5. Make Sure You’re Actually Plotting Enough Bars
In the code snippet, you do:
Code: Select all
int limit = rates_total - prev_calculated;
if(limit > rates_total) limit = rates_total;
for(int i=0; i<limit; i++)
{
...
}
Typical solution is something like:
Code: Select all
int start = prev_calculated;
if(start < 1) start = 0;
for(int i = start; i < rates_total; i++)
{
...
}
Code: Select all
for(int i = rates_total-1; i >= 0; i--)
{
...
}
Sometimes you need to indicate to MQL4 how the buffer is arranged:
ArraySetAsSeries(VolatilityRSIBuffer, true);
Tells MQL4 that index 0 is the newest element, and the last index is the oldest.
SetIndexDrawBegin(0, something);
Tells MQL4 not to plot for the first N bars.
If you don’t manage those calls carefully, you can have mismatched indexing.
7. Example “Fixed” OnCalculate
Below is a quick edit of your OnCalculate that reverses the loop so bar 0 is the newest. This ensures that pos=i in PVCalculation(i,...) interprets i as the newest bar. Then pos+len is “older bars,” which may or may not be what you intended. Adjust as needed.
Code: Select all
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
int limit = rates_total - prev_calculated;
if(limit > rates_total) limit = rates_total;
// We'll process from the oldest bar to the newest bar:
// i = rates_total-1 (oldest) down to 0 (newest)
for(int i = rates_total - 1; i >= 0; i--)
{
double pvVal = PVCalculation(i, VolatilityLength);
VolatilityRSIBuffer[i] = pvVal;
HorizontalLine30[i] = 30.0;
HorizontalLine4[i] = 4.0;
}
return(rates_total);
}
Code: Select all
double PVCalculation(int pos, int len)
{
// If pos is an older bar index, pos+len might be an even older bar index
// But in MQL4, a bigger index = older bar. So you might want "pos - len" instead.
// Adjust your condition. For example:
if(pos - (len - 1) < 0) return(0); // means not enough older bars to do the sum
double src = (High[pos] + Low[pos] + Close[pos]) / 3.0;
double sumLnSq = 0.0;
for(int i=0; i<len; i++)
{
int barIndex = pos - i;
if(barIndex < 0) break;
double h = High[barIndex];
double l = Low[barIndex];
if(l <= 0.0 || h <= 0.0) continue;
double val = MathLog(h / l);
sumLnSq += val * val;
}
double denominator = (len * 4.0) * MathLog(2.0);
if(denominator == 0) return(0);
double result = MathSqrt((src / denominator) * sumLnSq);
return(result);
}
In Summary
Reverse your loops and/or revise your indexing so that your bar references make sense in MQL4.
Confirm that your calculations do not always return zero.
Check chart scale, color, and that you’re actually filling the buffer for all bars.
Debug with Print statements to confirm real values are being assigned.
Following these steps typically resolves the “indicator is black/blank” issue in MT4. Once the buffer has real, non-zero values (and you have a suitable loop and color), you’ll see the line on the chart in the subwindow.
Re: Fix: Indicator is not showing on MT4 chart
275Could you please give me the name or link of the indicator in Tradeview?RACER-X wrote: Fri Dec 27, 2024 9:44 pm Hi all. I was trying to convert a PineScript indicator from Tradingview over to MQL4 for MT4.
I used ChatGPT Pro to do it. And the finished code compiled with no errors.
But the indicator shows up blank on the chart.
Can you help me fix it?
Here is the mql4 code:
Code: Select all
#property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 3 //--- Plots #property indicator_label1 "Volatility RSI" #property indicator_type1 DRAW_LINE #property indicator_color1 clrOrange #property indicator_width1 2 #property indicator_label2 "Line 30" #property indicator_type2 DRAW_LINE #property indicator_color2 clrOrange #property indicator_width2 1 #property indicator_style2 STYLE_DOT #property indicator_label3 "Line 4" #property indicator_type3 DRAW_LINE #property indicator_color3 clrSaddleBrown #property indicator_width3 1 #property indicator_style3 STYLE_DOT //--- Inputs extern int VolatilityLength = 8; //--- Buffers double VolatilityRSIBuffer[]; double HorizontalLine30[]; double HorizontalLine4[]; // -------------- Utilities & Math -------------- double Ln(double x) { // MQL4 does not have a built-in natural log named ln(), // but it does have MathLog() which is ln(x). return(MathLog(x)); } // RMA (Wilder’s Smoothing) helper // Equivalent to TradingView's ta.rma() if you do it in a rolling fashion. // But we must do a "manual" approach using a loop. double WilderRMA(double currentValue, double prevRma, int length) { // RMA = (prevRma*(length-1) + currentValue) / length return((prevRma*(length-1) + currentValue) / length); } // -------------- Pine Script Functions Rewritten -------------- // _pv(_src, _len) = sqrt((_src / ((_len * 4) * ln(2))) * sum( (ln(high/low))^2, _len )) double PVCalculation(int pos, int len) { // pos is the current bar index from left to right in MQL4 // _src = hlc3 = (High+Low+Close)/3 for the *current* bar // we must sum over the last "len" bars for (ln(high/low))^2 // Here we do a standard loop for i in [pos..pos+len-1], carefully checking bounds. if(pos + len >= Bars) return(0); // not enough bars to the left double src = (High[pos] + Low[pos] + Close[pos]) / 3.0; double sumLnSq = 0.0; for(int i=0; i<len; i++) { int barIndex = pos + i; if(barIndex >= Bars) break; double h = High[barIndex]; double l = Low[barIndex]; if(l <= 0 || h <= 0) continue; double val = Ln(h/l); sumLnSq += val*val; } double denominator = (len * 4.0) * Ln(2.0); // (_len*4)*ln(2) if(denominator == 0) return(0); double result = 0.0; // result = sqrt( (src / denominator) * sumLnSq ) result = MathSqrt((src / denominator) * sumLnSq); return(result); } // _rsi(_src, _len) // u = max(_src - _src[1], 0) // d = max(_src[1] - _src, 0) // rs = rma(u,_len)/rma(d,_len) // res = 100 - 100/(1+rs) double RSIOfSeries(double priceArray[], int pos, int len, int arraySize) { // We compute a short RSI over 'len' bars. // MQL4 has iRSI, but we replicate Pine’s approach: // We need a rolling calculation of U and D, then Wilder RMA of them. if(len <= 0) return(0); if(pos + len >= arraySize) return(0); // Build arrays for U and D over the chunk double rmaU = 0, rmaD = 0; double prevRmaU = 0, prevRmaD = 0; bool firstCalc = true; // We go from oldest to newest: bar pos+len-1 up to pos // so that the last step is "pos" (the current bar). for(int i=len; i>0; i--) { int currentBar = pos + (i-1); int previousBar = currentBar+1; // next to the right in MQL4 array if(previousBar >= arraySize) continue; double u = MathMax(priceArray[currentBar] - priceArray[previousBar], 0); double d = MathMax(priceArray[previousBar] - priceArray[currentBar], 0); if(firstCalc) { // initialize prevRmaU = u; prevRmaD = d; firstCalc = false; } else { // update prevRmaU = WilderRMA(u, prevRmaU, len); prevRmaD = WilderRMA(d, prevRmaD, len); } } // after finishing the loop, the last prevRmaU and prevRmaD are the final // for the bar 'pos' if(prevRmaD == 0) return(100.0); // avoid div-by-zero double rs = prevRmaU / prevRmaD; double rsi = 100.0 - (100.0 / (1.0 + rs)); return(rsi); } // Simple Harmonic function _simple_harmonic(_src, _len) // Implementation note: We have to interpret c0= _src[pos], c1= _src[pos+1], c2= _src[pos+2], etc. double SimpleHarmonic(double priceArray[], int pos, int len, int arraySize) { if(pos+2 >= arraySize) return(0); double c0 = priceArray[pos]; double c1 = priceArray[pos+1]; double c2 = priceArray[pos+2]; double v0 = c0 - c1; double v1 = c1 - c2; double a0 = v0 - v1; // We then take an EMA of a0 over length => a1 // For simplicity, we'll do a naive rolling approach again from pos+2 down to pos // but since a0 is just 1 value (?), we’ll treat this with caution. // In the original Pine, a0 is a series (bar by bar). This is more advanced. // We'll approximate by just using the single a0’s WilderRMA for now: // (Alternatively, you might store a separate buffer for a0 each bar.) double a1 = a0; // or some smoothing if you want // t0 = 2 * pi * sqrt( abs(v0 / a1) ) double pi = 3.14159265359; double denominator = a1; if(denominator == 0) denominator = 1e-9; double t0 = 2.0 * pi * MathSqrt(MathAbs(v0/denominator)); // t1 = c0 > c1 ? t0 : -t0 double t1 = (c0 > c1)? t0 : -t0; // In Pine, v3 = ema(t1, len) and t3 = ema(t0, len). We need bar-by-bar. // For demonstration, we’ll just return the final SHO = (v3 / t3)*100 // by approximating v3 ~ t1 and t3 ~ t0. A more faithful port // requires storing the entire t1, t0 series in arrays & applying EMA across bars. // This is a big difference between Pine’s approach vs. MQL4 single-pass approach. double v3 = t1; double t3 = t0; if(t3 == 0) return(0); double sho = (v3/t3)*100.0; return(sho); } // _karo(_src, _len) // This is also a multi-bar logic in Pine that uses EMA. We simplify similarly. double Karo(double priceArray[], int pos, int len, int arraySize) { // src = ema(_src, _len) // Then some ratio-based logic. // Here we do single-step for the current bar only (since a full port // needs storing time series). // We’ll approximate by using normal average of last 'len' bars: if(pos + len >= arraySize) return(0); double sum = 0; for(int i=0; i<len; i++) { sum += priceArray[pos + i]; } double src = sum / len; // approximate the "ema" with an "sma" for example // a = ema(src < src[1] ? src/src[1] : 0, _len) // b = ... // The original code references src[1]. That means the bar to the right in MQL4 indexing. // We'll just do a single-step approximation. double src1 = (pos+1 < arraySize) ? priceArray[pos+1] : src; double ratioCurrent = 0; if(src1 != 0.0 && src < src1) ratioCurrent = src/src1; double ratioOpposite = 0; if(src1 != 0.0 && src > src1) ratioOpposite = src/src1; // c = (src/src[1]) / ((src/src[1]) + b) // d = 2 * ((src/src[1]) / ((src/src[1]) + c*a)) - 1 // We’ll approximate: double cDen = ratioCurrent + ratioOpposite; if(cDen == 0) cDen = 1e-9; double cVal = ratioCurrent / cDen; double karoden = ratioCurrent + cVal*ratioCurrent; if(karoden == 0) karoden = 1e-9; double dVal = 2.0 * (ratioCurrent / karoden) - 1.0; return(dVal); } // _moscillator(_src, _len) // Loops from 1 to _len // if s0 > si => +1, if s0 < si => -1, else 0, sum them up double MOscillator(double priceArray[], int pos, int len, int arraySize) { // s0 = _src[pos], si = _src[pos+i] // sum up +1 / -1 if(pos + len >= arraySize) return(0); double s0 = priceArray[pos]; int sum = 0; for(int i=1; i<=len; i++) { int index = pos + i; if(index >= arraySize) break; double si = priceArray[index]; if(s0 > si) sum += 1; else if(s0 < si) sum -= 1; } return(sum); } // typ7(_typ, _src, _len) // In your Pine, you allowed multiple modes, but in your final code you used rsi_type. // We replicate only the “RSI” path (since your variable `typ5 = rsi_type`). // If you want to expand to “no_type, simp_harmon_type, karo_type, m_type”, add more logic. double Typ7RSIOnly(double currentPV, int pos, int len, int arraySize, double priceArray[]) { // We'll just do the RSI path from your code: // _typ1 == rsi_type ? _rsi(_pv(...),_len) : ... // Because you set typ5 = rsi_type in the final script. // So effectively: volatility_rsi = _rsi( _pv(src0,VolatilityLength), VolatilityLength ). // We pass in "currentPV" which is _pv(...) for the current bar. // Now we build a small array so we can feed RSIOfSeries(). // But that requires a time series. We'll create a synthetic array with currentPV repeated, // which doesn’t help RSI. Real port would store PV for each bar. // The correct approach is: for each bar, compute PV, store it in an array, then feed that array to RSIOfSeries for the current bar. return(currentPV); // <--- Stub if you only want the raw _pv() // If you want the RSI of that PV time series, do the following: // 1) Build an array that holds PV for all bars. // 2) Then pass that array to RSIOfSeries(...). // This example code, for simplicity, just returns the raw PV. } //-------------------------------------------- // OnInit //-------------------------------------------- int OnInit() { // 3 buffers SetIndexStyle(0, DRAW_LINE, EMPTY, 2, clrOrange); SetIndexBuffer(0, VolatilityRSIBuffer); SetIndexStyle(1, DRAW_LINE, STYLE_DOT, 1, clrOrange); SetIndexBuffer(1, HorizontalLine30); SetIndexStyle(2, DRAW_LINE, STYLE_DOT, 1, clrSaddleBrown); SetIndexBuffer(2, HorizontalLine4); IndicatorShortName("Breakout Detector (Converted from PineScript)"); return(INIT_SUCCEEDED); } //-------------------------------------------- // OnCalculate //-------------------------------------------- // typical signature for MQL4: // OnCalculate(int rates_total, int prev_calculated, // const double &price[], ... ) // but we’ll just do a simplified version: int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { // We want to fill VolatilityRSIBuffer for each bar. // In Pine: volatility_rsi = _rsi( _pv(hlc3,VolatilityLength), VolatilityLength ) // We'll do the best we can in MQL4 with a single pass. // Build an array for storing PV on each bar so we can then do RSI if desired // For simplicity, let’s just store the PV and not do RSI on it (since that is more advanced). // You can expand to do full RSI if needed. static double PVArray[1]; // dynamic approach below ArrayResize(PVArray, rates_total); // prepare to read High[], Low[], Close[]; in MQL4 these are global arrays // Make sure we handle indexing carefully: bar i in MQL4 = i-th from the left in OnCalculate loops. // We'll fill from oldest bar to newest bar: i = 0..rates_total-1 // but watch out for access High[i], Low[i], etc. in the same direction. int limit = rates_total - prev_calculated; if(limit > rates_total) limit = rates_total; for(int i=0; i<limit; i++) { // compute PV for bar i double pvVal = PVCalculation(i, VolatilityLength); PVArray[i] = pvVal; // store it so we can do RSI, etc. // If you want RSI of PV, you’d do something like: // double rsiVal = RSIOfSeries(PVArray, i, VolatilityLength, rates_total); // VolatilityRSIBuffer[i] = rsiVal; // Here we just do the stub for demonstration: VolatilityRSIBuffer[i] = pvVal; // Set the lines HorizontalLine30[i] = 30.0; HorizontalLine4[i] = 4.0; } //------------------------- // Emulate alertcondition(ta.crossunder(volatility_rsi,15)) // crossunder => volatility_rsi just went from >= 15 to < 15 // We can check the last bar processed: if(rates_total > 1) { int iCur = limit - 1; // the most recent bar we processed int iPrev = iCur + 1; // the bar to the right (previous in Pine sense) if(iPrev < rates_total) { double curVal = VolatilityRSIBuffer[iCur]; double prevVal = VolatilityRSIBuffer[iPrev]; if(curVal < 15.0 && prevVal >= 15.0) { Alert("Breakout Zone: crossunder 15 detected on bar ", iCur); } } } //------------------------- return(rates_total); }
-------------------------------------------------------------------------------------------------------------------------------------------------
Attached is the indicator.
Here is some logic in the PineScript to MQL4 conversion is also attached.
Re: Fix: Indicator is not showing on MT4 chart
276I don't have the link. The name is Breakout Detector.mrtools wrote: Fri Dec 27, 2024 11:56 pm Could you please give me the name or link of the indicator in Tradeview?
Here is the Tradingview Pinescript code.
Code: Select all
//@version=5
tag0 = "TC Breakout Detector"
indicator("Breakout Detector")
pi = 3.14159265359
src0 = hlc3
volatility_length = input(8,title="Volatility Length")
no_type = "Standard"
simp_harmon_type = "Simple Harmonic"
rsi_type = "RSI"
karo_type = "Karobein"
m_type = "M-Oscillator"
typ5 = rsi_type
_pv(_src, _len) =>
math.sqrt((_src / ((_len * 4) * math.log(2))) * math.sum(math.pow(math.log(high / low), 2), _len))
_rma(_src, _len) =>
ta.sma(_src, _len * 3) + ta.sma(_src, _len * 2) - ta.sma(_src, _len)
_rsi(_src, _len) =>
u = math.max(_src - _src[1], 0)
d = math.max(_src[1] - _src, 0)
rs = ta.rma(u, _len) / ta.rma(d, _len)
res = 100 - 100 / (1 + rs)
res
_simple_harmonic(_src, _len) =>
c0 = _src
c1 = c0[1]
c2 = c0[2]
v0 = c0 - c1
v1 = c1 - c2
a0 = v0 - v1
a1 = ta.ema(a0, _len)
t0 = 2 * pi * (math.sqrt(math.abs(v0 / a1)))
t1 = c0 > c1 ? t0 : t0 * -1
v3 = ta.ema(t1, _len)
t3 = ta.ema(t0, _len)
sho = (v3 / t3) * 100
_karo(_src, _len) =>
src = ta.ema(_src, _len)
a = ta.ema(src < src[1] ? src / src[1] : 0, _len)
b = ta.ema(src > src[1] ? src / src[1] : 0, _len)
c = (src / src[1]) / (src / src[1] + b)
d = 2 * ((src / src[1]) / (src / src[1] + c * a)) - 1
_moscillator(_src, _len) =>
tt_c = 0
for i = 1 to _len
s0 = _src[0]
si = _src[i]
t_c = s0 > si ? 1 :s0 < si ? -1 : 0
tt_c := tt_c + t_c
tt_c
tt_c
typ7(_typ1, _src, _len) =>
_typ1 == no_type ? _pv(src0, volatility_length) :
_typ1 == rsi_type ? _rsi(_pv(src0, volatility_length), _len) :
_typ1 == simp_harmon_type ? _simple_harmonic(_pv(src0, volatility_length), _len) :
_typ1 == karo_type ? _karo(_pv(src0, volatility_length), _len) :
_typ1 == m_type ? ta.ema(ta.ema(_moscillator(_pv(src0, volatility_length), _len), 5), 3) : na
cond0 = typ5
cond1 = cond0 == no_type ? src0 : _pv(src0, volatility_length)
cond2 = cond0 == no_type ? volatility_length : volatility_length
volatility_rsi = typ7(cond0, cond1, cond2)
plot(volatility_rsi, tag0, #f5ab0c, 1, style=plot.style_line,transp=5)
h1=hline(30, color=#f5ab0c21, linestyle=hline.style_solid, linewidth=2)
h2=hline(4, color=#806732, linestyle=hline.style_solid, linewidth=2)
fill(h1, h2, color = color.new(#ff9900, 85))
makelabel(x, y, msg, col=color.white)=>
var label _la = label.new(x, y, msg, color=#00000000, style=label.style_label_left)
label.set_xy(_la, x, y)
label.set_text(_la, msg)
label.set_textcolor(_la, col)
_la
bc = 16
makelabel(bar_index+10, bc, 'Breakout Zone ↑↓')
alertcondition(ta.crossunder(volatility_rsi,15), title='Breakout Zone', message='Breakout Zone')
If you load this code in the PineScript editor it works with no issues.
Regards
X
Re: Fix: Indicator is not showing on MT4 chart
279That is an early interpolated version of Awesome (interpolation was called ratio) we have a lot of newer Awesome using interpolation mtf in the forum now.
Re: Fix: Indicator is not showing on MT4 chart
280Hello all
I am trying to share this template both here and with some friends locally, with no good results. The biggest problem probably has more to do with operator error than anything else. I've never had trouble like this sharing in the past. A couple of members on xard's board graciously posted a fix, but the results when I shared with a couple of local friends were the same. The navigator shows the indicators in a folder and can be dragged to chart, all with default settings that need configured. I wouldn't consider myself tech savvy, but I can navigate and usually find a solution to whatever it is. Any help would be greatly appreciated. my screen shared results
this shared template changes the chart from the Dow to Gold, that's a new one...fyi,this particular share going from 50" to Microsoft tablet
I am trying to share this template both here and with some friends locally, with no good results. The biggest problem probably has more to do with operator error than anything else. I've never had trouble like this sharing in the past. A couple of members on xard's board graciously posted a fix, but the results when I shared with a couple of local friends were the same. The navigator shows the indicators in a folder and can be dragged to chart, all with default settings that need configured. I wouldn't consider myself tech savvy, but I can navigate and usually find a solution to whatever it is. Any help would be greatly appreciated. my screen shared results
this shared template changes the chart from the Dow to Gold, that's a new one...fyi,this particular share going from 50" to Microsoft tablet