'ExtUpperBuffer being set to 0.0 on new bar even though hard coded in If Else statement in OnCalc. Set to EMPTY_VALUE in Oninit
There are 2 buffers behaving the same way so to keep simple just mentioning ExtUpperBuffer and when I drop this onto the chart the datawindow/print values are as expected with the hard coded values im using for troubleshooting purposes. On a new bar the data window and print are showing 0.00 and 0.0 respectively, even though set to EMPTY_VALUE in the Oninit and either 420000 or 220000 in the OnCalc If Else statement. Trying to understand the HOW/WHY for this in MQL5. Thanks in advance.
//+------------------------------------------------------------------+
//| OBV & Fractal.mq5 |
//| Copyright 2021, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 3
//--- plot OBV
#property indicator_label1 "OBV"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrAqua
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
// Fractals
#property indicator_type2 DRAW_ARROW
#property indicator_type3 DRAW_ARROW
#property indicator_color2 clrGreen
#property indicator_color3 clrRed
#property indicator_label2 "Fractal Up"
#property indicator_label3 "Fractal Down"
//--- input parameters
input ENUM_APPLIED_VOLUME InpVolumeType=VOLUME_TICK; // Volumes
//--- indicator buffers
double OBVBuffer[];
double ExtUpperBuffer[]; // Up Fractal
double ExtLowerBuffer[]; // Down Fractal
//--- 10 pixels upper from high price for Fractals
int ExtArrowShift = -10;
//---OBV Handle
int obv_handle = INVALID_HANDLE;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
int size = ArraySize(OBVBuffer);
//--- indicator buffers mapping
SetIndexBuffer(0, OBVBuffer, INDICATOR_DATA);
SetIndexBuffer(1, ExtUpperBuffer, INDICATOR_DATA); // Up Fractal. Maps to #property indicator_type2
SetIndexBuffer(2, ExtLowerBuffer, INDICATOR_DATA); // Down Fractal. Maps to #property indicator_type3
//--- set indicator digits
IndicatorSetInteger(INDICATOR_DIGITS, 2);
// Taken from Fractals. //
//--- sets first bar from what index will be drawn
PlotIndexSetInteger(1,PLOT_ARROW,217);
PlotIndexSetInteger(2,PLOT_ARROW,218);
//--- arrow shifts when drawing
//PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,ExtArrowShift);
//PlotIndexSetInteger(2,PLOT_ARROW_SHIFT,-ExtArrowShift);
//--- sets drawing line empty value--
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---ArraySeries Setting
ArraySetAsSeries(OBVBuffer, true);
ArraySetAsSeries(ExtUpperBuffer, true);
ArraySetAsSeries(ExtLowerBuffer, true);
//---Create Indicator
obv_handle = iOBV(Symbol(), Period(), InpVolumeType);
//---Check if Indicator was Created
if(obv_handle == INVALID_HANDLE)
{
printf("Failed To Create OBV Indicator: [%d]", GetLastError());
return INIT_FAILED;
}
//---Set Indicator Name for Data WIndow
IndicatorSetString(INDICATOR_SHORTNAME, "OBV ");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---Array Set To Series True
ArraySetAsSeries(time, true);
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(tick_volume, true);
ArraySetAsSeries(volume, true);
ArraySetAsSeries(spread, true);
//---Refresh Indicators // From SMA v2 Framework, updated for OBV.
int calculatedBars = BarsCalculated(obv_handle);
//Check If Indicators are refreshed
if(calculatedBars < 2) // For SMA was using InpPeriod which was 14 for the SMA, OBV requires 2.
return prev_calculated;
//---Create Control Value to Stop recalculation of Closed candles
int limit;
if(prev_calculated <= 3){}
//limit = rates_total - (3); // These were taken from the SMA which uses an InpPeriod. Using 2 for OBV "input"
else
limit = rates_total - prev_calculated;
//---Assign Created Indicator Values to our Plotting Buffer
CopyBuffer(obv_handle, 0, 0, limit + 1, OBVBuffer);
//---End of OBV If statements etc.
// If statements from Fractals.
if(rates_total<5) // Could change this to be EMA input. Leaving 2 for now. // Fractals wants 5. Changing from 2 to 5.
return(prev_calculated);
if (rates_total==prev_calculated)
return (rates_total);
int start; // Variable from Fractals
//--- clean up arrays and sets start variable // Taken From Fractals Code
if(prev_calculated<7)
{
start=2;
ArrayInitialize(ExtUpperBuffer,EMPTY_VALUE);
ArrayInitialize(ExtLowerBuffer,EMPTY_VALUE);
}
else
start=rates_total - 5;
// Dropping in Fractals IF statements here //
//--- main cycle of calculations // Changing counter from i to j
// for(int j=start; j<rates_total-3 && !IsStopped(); j++)
int fractalUpCounter = 0;
int fractalDnCounter = 0;
// TODO: FIX Fractals going to 0 on the new bar.
for(int j = start; j < ((rates_total-prev_calculated)-3) && !IsStopped(); j++)
{
// if (OBVBuffer[j] == 0)
if (ExtLowerBuffer[j-1] == 0 || ExtUpperBuffer[j-1] == 0){
Print("I BROKE!!");
break;
}
//--- Lower Fractal
if(OBVBuffer[j]>OBVBuffer[j+1] && OBVBuffer[j]>OBVBuffer[j+2] && OBVBuffer[j]>=OBVBuffer[j-1] && OBVBuffer[j]>=OBVBuffer[j-2]){ // For OBV Div swap high[i] with ExtOBVBuffer[i]
if(OBVBuffer[j] != 0){
//ExtLowerBuffer[j] = OBVBuffer[j];
ExtLowerBuffer[j] = 421000;
//fractalDnCounter++;
}
//else{
// ExtLowerBuffer[j]=EMPTY_VALUE;
//}
}
else{
ExtLowerBuffer[j]=221000;
}
//--- Upper Fractal
if(OBVBuffer[j]<OBVBuffer[j+1] && OBVBuffer[j]<OBVBuffer[j+2] && OBVBuffer[j]<=OBVBuffer[j-1] && OBVBuffer[j]<=OBVBuffer[j-2]){
if(OBVBuffer[j] != 0){
//ExtUpperBuffer[j]=OBVBuffer[j];
ExtUpperBuffer[j] = 420000;
//fractalUpCounter++;
}
//else{
// ExtUpperBuffer[j]=EMPTY_VALUE;
//}
}
else{
ExtUpperBuffer[j]=220000;
}
//Print(" j: " + j + " OBVBuffer value: " + OBVBuffer[j] + " prev_calc: " + prev_calculated + " rates_total: " + rates_total);
//Print(" ExtUpperBuffer value: " + ExtUpperBuffer[j] + " ExtLowerBuffer value: " + ExtLowerBuffer[j]);
}
//Print("********* I AM DONE *************");
int length = sizeof(ExtUpperBuffer)/sizeof(ExtUpperBuffer[0]);
Print("ExtUpperBuffer: 0 " + ExtUpperBuffer[0] + " OBVBuffer: " + OBVBuffer[0]);
Print("ExtUpperBuffer: 1 " + ExtUpperBuffer[1] + " OBVBuffer: " + OBVBuffer[1]);
Print("ExtUpperBuffer: 2 " + ExtUpperBuffer[2] + " OBVBuffer: " + OBVBuffer[2]);
Print("ExtUpperBuffer: 3 " + ExtUpperBuffer[3] + " OBVBuffer: " + OBVBuffer[3]);
Print("ExtUpperBuffer: 4 " + ExtUpperBuffer[4] + " OBVBuffer: " + OBVBuffer[4]);
Print("ExtUpperBuffer: 5 " + ExtUpperBuffer[5] + " OBVBuffer: " + OBVBuffer[5]);
Print("ExtUpperBuffer: 6 " + ExtUpperBuffer[6] + " OBVBuffer: " + OBVBuffer[6]);
Print("ExtUpperBuffer: 7 " + ExtUpperBuffer[7] + " OBVBuffer: " + OBVBuffer[7]);
//Print("Start: " + start);
for (int i = 0; i < length; i++) {
//Print("OBVBuffer: " + OBVBuffer[i]);
}
/* for(int i = 0; i < length; i++){
Print("! ExtUpperBuffer: " + ExtUpperBuffer[i]);
}
int length2 = sizeof(ExtUpperBuffer)/sizeof(ExtUpperBuffer[0]);
for(int i = 0; i < length2; i++){
Print("! ExtLowerBuffer: " + ExtLowerBuffer[i]);
}
*/
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
Solution 1:[1]
A solution was provided in the MQL forums by Vladimir Karputov. Cheers to him taking the time. I still need to compare the two to see what was incorrect in my code but his solution works perfectly.
//+------------------------------------------------------------------+
//| Fractals On OBV.mq5 |
//| Copyright © 2022, Vladimir Karputov |
//| https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2022, Vladimir Karputov"
#property link "https://www.mql5.com/en/users/barabashkakvn"
#property version "1.00"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 3
//--- plot OOBV
#property indicator_label1 "OOBV"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDarkOrange
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- plot Fractal Up
#property indicator_label2 "Fractal Up"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrGray
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- plot Fractal Down
#property indicator_label3 "Fractal Down"
#property indicator_type3 DRAW_ARROW
#property indicator_color3 clrGray
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
//--- input parameters
input group "OBV"
input ENUM_APPLIED_VOLUME Inp_OBV_applied_volume = VOLUME_TICK; // OBV: volume type for calculation
//--- indicator buffers
double OBVBuffer[];
double Fractal_Up_Buffer[];
double Fractal_Down_Buffer[];
//---
int handle_iOBV; // variable for storing the handle of the iOBV indicator
int bars_calculated = 0; // we will keep the number of values in the On Balance Volume indicator
bool m_init_error = false; // error on InInit
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0,OBVBuffer,INDICATOR_DATA);
SetIndexBuffer(1,Fractal_Up_Buffer,INDICATOR_DATA);
SetIndexBuffer(2,Fractal_Down_Buffer,INDICATOR_DATA);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
PlotIndexSetInteger(1,PLOT_ARROW,217);
PlotIndexSetInteger(2,PLOT_ARROW,218);
//--- arrow shifts when drawing
PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,10);
PlotIndexSetInteger(2,PLOT_ARROW_SHIFT,-10);
//--- sets drawing line empty value
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//--- create handle of the iOBV indicator
handle_iOBV=iOBV(Symbol(),Period(),Inp_OBV_applied_volume);
//--- if the handle is not created
if(handle_iOBV==INVALID_HANDLE)
{
//--- tell about the failure and output the error code
PrintFormat("Failed to create handle of the iOBV indicator for the symbol %s/%s, error code %d",
Symbol(),
EnumToString(Period()),
GetLastError());
//--- the indicator is stopped early
m_init_error=true;
return(INIT_SUCCEEDED);
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---
if(m_init_error)
return(0);
if(rates_total<5)
return(0);
//--- number of values copied from the iOBV indicator
int values_to_copy;
//--- determine the number of values calculated in the indicator
int calculated=BarsCalculated(handle_iOBV);
if(calculated<=0)
{
PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError());
return(0);
}
//--- if it is the first start of calculation of the indicator or if the number of values in the iOBV indicator changed
//---or if it is necessary to calculated the indicator for two or more bars (it means something has changed in the price history)
if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1)
{
//--- if the iOBVBuffer array is greater than the number of values in the iOBV indicator for symbol/period, then we don't copy everything
//--- otherwise, we copy less than the size of indicator buffers
if(calculated>rates_total)
values_to_copy=rates_total;
else
values_to_copy=calculated;
}
else
{
//--- it means that it's not the first time of the indicator calculation, and since the last call of OnCalculate()
//--- for calculation not more than one bar is added
values_to_copy=(rates_total-prev_calculated)+1;
}
//--- fill the arrays with values of the iOBV indicator
//--- if FillArrayFromBuffer returns false, it means the information is nor ready yet, quit operation
if(!FillArrayFromBuffer(OBVBuffer,handle_iOBV,values_to_copy))
return(0);
//--- memorize the number of values in the On Balance Volume indicator
bars_calculated=calculated;
//--- Fractals
int start;
//--- clean up arrays
if(prev_calculated<7)
{
start=2;
ArrayInitialize(Fractal_Up_Buffer,EMPTY_VALUE);
ArrayInitialize(Fractal_Down_Buffer,EMPTY_VALUE);
}
else
start=rates_total-5;
//--- main cycle of calculations
for(int i=start; i<rates_total-3 && !IsStopped(); i++)
{
//--- Upper Fractal
if(OBVBuffer[i]>OBVBuffer[i+1] && OBVBuffer[i]>OBVBuffer[i+2] && OBVBuffer[i]>=OBVBuffer[i-1] && OBVBuffer[i]>=OBVBuffer[i-2])
Fractal_Up_Buffer[i]=OBVBuffer[i];
else
Fractal_Up_Buffer[i]=EMPTY_VALUE;
//--- Lower Fractal
if(OBVBuffer[i]<OBVBuffer[i+1] && OBVBuffer[i]<OBVBuffer[i+2] && OBVBuffer[i]<=OBVBuffer[i-1] && OBVBuffer[i]<=OBVBuffer[i-2])
Fractal_Down_Buffer[i]=OBVBuffer[i];
else
Fractal_Down_Buffer[i]=EMPTY_VALUE;
}
//---
for(int i=rates_total-3; i<rates_total; i++)
{
Fractal_Up_Buffer[i]=EMPTY_VALUE;
Fractal_Down_Buffer[i]=EMPTY_VALUE;
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| Filling indicator buffers from the iOBV indicator |
//+------------------------------------------------------------------+
bool FillArrayFromBuffer(double &obv_buffer[], // indicator buffer of OBV values
int ind_handle, // handle of the iOBV indicator
int amount // number of copied values
)
{
//--- reset error code
ResetLastError();
//--- fill a part of the iOBVBuffer array with values from the indicator buffer that has 0 index
if(CopyBuffer(ind_handle,0,0,amount,obv_buffer)<0)
{
//--- if the copying fails, tell the error code
PrintFormat("Failed to copy data from the iOBV indicator, error code %d",GetLastError());
//--- quit with zero result - it means that the indicator is considered as not calculated
return(false);
}
//--- everything is fine
return(true);
}
//+------------------------------------------------------------------+
//| Indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(handle_iOBV!=INVALID_HANDLE)
IndicatorRelease(handle_iOBV);
}
//+------------------------------------------------------------------+
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | TheJoshuamcgowan |