Files
Coding for Dummies 9003b29674 Indicator Collection
Indicator Collection
2024-08-27 23:35:50 +07:00

705 lines
54 KiB
Plaintext

//+------------------------------------------------------------------+
//| MACD.mq4 |
//| Copyright © 2005, David W. Thomas |
//| mailto:davidwt@usa.net |
//+------------------------------------------------------------------+
// This is the correct computation and display of MACD.
#property copyright "Copyright © 2005, David W. Thomas"
#property link "mailto:davidwt@usa.net"
#property description "MACD True"
#property strict
//---
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots 3
//--- macd & signal lines
#property indicator_color1 clrBlue
#property indicator_color2 clrRed
//--- macd histogram
#property indicator_color3 clrForestGreen,clrFireBrick
#property indicator_width3 2
//--- input parameters
input string str2zs = "================================================"; //---
input string str5sj = "==== MACD Settings ===="; //---
input string str2el = "================================================"; //---
input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;
input int FastMAPeriod = 12;
input int SlowMAPeriod = 26;
input int SignalMAPeriod = 9;
input ENUM_MA_METHOD MAMethod = MODE_EMA;
input ENUM_APPLIED_PRICE AppliedPrice = PRICE_CLOSE;
//--- signal line
input string str6as = "================================================"; //---
input string str3yf = "==== Arrows & Alerts For Signal Line Cross ===="; //---
input string str7kp = "================================================"; //---
input bool ShowSignalLineCrossArrows = true;
input bool SendSignalLineCrossAlert = false;
input bool SendSignalLineCrossText = false;
input double SignalLineGap = 3.5; //gap needed to trigger alert, 0=off
input color BullishSignalLineCrossArrowColor = clrGreen;
input int BullishSignalLineCrossArrowCode = 233;
input int BullishSignalLineCrossArrowWidth = 2;
input color BearishSignalLineCrossArrowColor = clrRed;
input int BearishSignalLineCrossArrowCode = 234;
input int BearishSignalLineCrossArrowWidth = 2;
//--- zero line
input string str6st = "================================================"; //---
input string str3yk = "==== Arrows & Alerts For Zero Line Cross ===="; //---
input string str7im = "================================================"; //---
input bool ShowZeroLineCrossArrows = true;
input bool SendZeroLineCrossAlert = false;
input bool SendZeroLineCrossText = false;
input double ZeroLineGap = 2.5; //gap needed to trigger alert, 0=off
input color BullishZeroLineCrossArrowColor = clrGreen;
input int BullishZeroLineCrossArrowCode = 139;
input int BullishZeroLineCrossArrowWidth = 2;
input color BearishZeroLineCrossArrowColor = clrRed;
input int BearishZeroLineCrossArrowCode = 139;
input int BearishZeroLineCrossArrowWidth = 2;
//--- arrow spacing
input string str6dv = "================================================"; //---
input string str3hf = "==== Arrow Spacing ===="; //---
input string str7hp = "================================================"; //---
input int ATRPeriodArrows = 20;
input double ATRMultiplierArrows = 1.25;
////////////////////////////////////////////////////////////////////////////////////////
double ArrowSpacing;
string ObjDel="_macdta"; // unique to this indicator
double ATR[];
////////////////////////////////////////////////////////////////////////////////////////
//--- buffers
double MACDLineBuffer[];
double SignalLineBuffer[];
double HistogramHighBuffer[];
double HistogramLowBuffer[];
double HistogramColorBuffer[];
//--- MA handles
int handleFastMa;
int handleSlowMa;
int handleATR;
//--- variables
double alpha = 0;
double alpha_1 = 0;
bool isBullishSignalLineCrossActive=false;
bool isBearishSignalLineCrossActive=false;
bool isBullishZeroLineCrossActive=false;
bool isBearishZeroLineCrossActive=false;
double fastMA[], slowMA[];
bool arrowsWereDrawnInHistory=false;
/////////////////////////////////////////////////////////////////////////////////////////////
//Calculating the factor needed to turn pip values into their correct points value to accommodate different Digit size.
//Thanks to Lifesys for providing this code. Coders, you need to briefly turn off Wrap and turn on a mono-spaced font to view this properly and see how easy it is to make changes.
string pipFactor[] = {"JPY","XAG","SILVER","BRENT","WTI","XAU","GOLD","SP500","S&P","UK100","WS30","DAX30","DJ30","NAS100","CAC400"};
double pipFactors[] = { 100, 100, 100, 100, 100, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1};
double factor;//For pips/points stuff. Set up in int init()
/////////////////////////////////////////////////////////////////////////////////////////////
//Time frame arrays
string TFstr[] = {"Current","M1","M2","M3","M4","M5","M6","M10","M12","M15",
"M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN1"};
ENUM_TIMEFRAMES TFenum[] = {PERIOD_CURRENT,PERIOD_M1,PERIOD_M2,PERIOD_M3,PERIOD_M4,PERIOD_M5,PERIOD_M6,
PERIOD_M10,PERIOD_M12,PERIOD_M15,PERIOD_M20,PERIOD_M30,PERIOD_H1,PERIOD_H2,
PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1,PERIOD_W1,PERIOD_MN1};
int TFint[] = {0,1,2,3,4,5,6,10,12,15,20,30,16385,16386,16387,16388,16390,16392,16396,16408,32769,49153};
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- name for DataWindow and indicator subwindow label
IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
string short_name=StringFormat("MACD(%s/%s, %d, %d, %d)",_Symbol,TFEnumToStr(TimeFrame),
FastMAPeriod,SlowMAPeriod,SignalMAPeriod);
IndicatorSetString(INDICATOR_SHORTNAME,short_name);
//--- macd line
SetIndexBuffer(0,MACDLineBuffer,INDICATOR_DATA);
PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,SlowMAPeriod);
PlotIndexSetString(0,PLOT_LABEL,"MACD Line");
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
//--- signal line
SetIndexBuffer(1,SignalLineBuffer,INDICATOR_DATA);
PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(1,PLOT_LINE_STYLE,STYLE_DOT);
PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,SlowMAPeriod+SignalMAPeriod);
PlotIndexSetString(1,PLOT_LABEL,"Signal Line");
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
//--- Histogram
SetIndexBuffer(2,HistogramHighBuffer,INDICATOR_DATA);
PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_COLOR_HISTOGRAM2);
PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,SlowMAPeriod+SignalMAPeriod);
PlotIndexSetString(2,PLOT_LABEL,"MACD Histogram");
//--- Histogram color
SetIndexBuffer(3,HistogramLowBuffer,INDICATOR_DATA);
SetIndexBuffer(4,HistogramColorBuffer,INDICATOR_COLOR_INDEX);
//--- get MA handles
handleFastMa=iMA(_Symbol,TimeFrame,FastMAPeriod,0,MAMethod,AppliedPrice);
//--- if the handle is not created
if(handleFastMa==INVALID_HANDLE)
{
//--- tell about the failure and output the error code
PrintFormat("Failed to create handle of the iMA Fast indicator for the symbol %s/%s, error code %d",
_Symbol,
EnumToString(_Period),
GetLastError());
//--- the indicator is stopped early
return(INIT_FAILED);
}
handleSlowMa=iMA(_Symbol,TimeFrame,SlowMAPeriod,0,MAMethod,AppliedPrice);
//--- if the handle is not created
if(handleSlowMa==INVALID_HANDLE)
{
//--- tell about the failure and output the error code
PrintFormat("Failed to create handle of the iMA Slow indicator for the symbol %s/%s, error code %d",
_Symbol,
EnumToString(_Period),
GetLastError());
//--- the indicator is stopped early
return(INIT_FAILED);
}
//--- ATR handle
handleATR = iATR(_Symbol,_Period,ATRPeriodArrows);
//--- if the handle is not created
if(handleATR==INVALID_HANDLE)
{
//--- tell about the failure and output the error code
PrintFormat("Failed to create handle of the ATR indicator for the symbol %s/%s, error code %d",
_Symbol,
EnumToString(_Period),
GetLastError());
//--- the indicator is stopped early
return(INIT_FAILED);
}
//---
alpha = 2.0 / (SignalMAPeriod + 1.0);
alpha_1 = 1.0 - alpha;
//--- pips factor
factor = PFactor(_Symbol);
//--- initialization done
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| custom deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Delete objects when indicator is removed from chart
//--- Add "+ObjDel" to end of object's name
//--- ObjDel --> unique indicator identifier
DeleteChartObjects(ObjDel);
if(handleFastMa!=INVALID_HANDLE)
IndicatorRelease(handleFastMa);
if(handleSlowMa!=INVALID_HANDLE)
IndicatorRelease(handleSlowMa);
if(handleATR!=INVALID_HANDLE)
IndicatorRelease(handleATR);
//--- clear comment
Comment("");
//---
}
//+------------------------------------------------------------------+
//| 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[])
{
//--- local variables
int limit=0;
bool isNewBar = IsNewBar();
//--- array set as series
ArraySetAsSeries(time,true);
ArraySetAsSeries(open,true);
ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);
ArraySetAsSeries(close,true);
ArraySetAsSeries(MACDLineBuffer,true);
ArraySetAsSeries(SignalLineBuffer,true);
ArraySetAsSeries(HistogramHighBuffer,true);
ArraySetAsSeries(HistogramLowBuffer,true);
ArraySetAsSeries(HistogramColorBuffer,true);
//--- must wait for OnCalculate() before working with MTF handles
//--- https://www.mql5.com/en/forum/168437
if (!arrowsWereDrawnInHistory && prev_calculated>0)
{
int calculated=BarsCalculated(handleFastMa);
if(calculated<=0)
{
Print("Not all data of handleFastMa is calculated (",calculated,"bars ). Error",GetLastError());
return(0);
}
calculated=BarsCalculated(handleSlowMa);
if(calculated<=0)
{
Print("Not all data of handleSlowMa is calculated (",calculated,"bars ). Error",GetLastError());
return(0);
}
}
//--- check for possible errors
if (prev_calculated<0) return(-1);
//--- starting index (limit) for bars recalculation loop
if(prev_calculated==0)// checking the first call
limit=rates_total-4-MathMax(ATRPeriodArrows,SlowMAPeriod); // starting index first call
else
limit=rates_total-prev_calculated; // starting index
//--- draw arrows in history
if (!arrowsWereDrawnInHistory && prev_calculated>0)
{
for(int i=rates_total-4-MathMax(ATRPeriodArrows,SlowMAPeriod); i>=0; i--)
{
CalculateMACD(i);
DrawArrowsAndSendAlerts(i, time, open, close, high, low, false);
}
// set flag
arrowsWereDrawnInHistory = true;
}
//--- draw arrows and send alerts
if (arrowsWereDrawnInHistory)
{
for(int i=limit; i>=0; i--)
{
CalculateMACD(i);
if (isNewBar)
DrawArrowsAndSendAlerts(i+1, time, open, close, high, low, true);
}
}
//---
return(rates_total);
}
//+------------------------------------------------------------------+
//| CalculateMACD() |
//+------------------------------------------------------------------+
void CalculateMACD(int i)
{
//--- bar shift
int bar = iBarShift(_Symbol,TimeFrame,iTime(_Symbol,_Period,i));
if (bar < 0) bar = 0;
//iMA(_Symbol,TimeFrame,FastMAPeriod,0,MODE_EMA,PRICE_CLOSE,bar)
//iMA(_Symbol,TimeFrame,SlowMAPeriod,0,MODE_EMA,PRICE_CLOSE,bar)
FillArrayFromBuffer(handleFastMa,0,bar,1,fastMA,true,"iMA Fast");
FillArrayFromBuffer(handleSlowMa,0,bar,1,slowMA,true,"iMA Slow");
//--- MACD Line
MACDLineBuffer[i] = fastMA[0] - slowMA[0];
//--- Signal Line
SignalLineBuffer[i] = alpha*MACDLineBuffer[i] + alpha_1*SignalLineBuffer[i+1];
//--- Histogram
double hist = MACDLineBuffer[i] - SignalLineBuffer[i];
if (hist >= 0)
{
HistogramHighBuffer[i] = hist;
HistogramLowBuffer[i] = 0;
HistogramColorBuffer[i] = 0;
}
if (hist < 0)
{
HistogramHighBuffer[i] = 0;
HistogramLowBuffer[i] = hist;
HistogramColorBuffer[i] = 1;
}
}
//+------------------------------------------------------------------+
//| DrawArrowsAndSendAlerts() |
//+------------------------------------------------------------------+
void DrawArrowsAndSendAlerts(int i,
const datetime &myTime[],
const double &myOpen[],
const double &myClose[],
const double &myHigh[],
const double &myLow[],
bool isNewBar)
{
//--- ATR arrow spacing
FillArrayFromBuffer(handleATR,0,i,1,ATR,true,"ATR");
ArrowSpacing = ATR[0] * ATRMultiplierArrows;
//--- signal line cross
bool isBullishSignalLineCross = false;
bool isBearishSignalLineCross = false;
//isBullishSignalLineCross = (MACDLineBuffer[i+1] <= SignalLineBuffer[i+1] && MACDLineBuffer[i] > SignalLineBuffer[i]);
//isBearishSignalLineCross = (MACDLineBuffer[i+1] >= SignalLineBuffer[i+1] && MACDLineBuffer[i] < SignalLineBuffer[i]);
//--- reset bullish 'active' flag
//if (MACDLineBuffer[i+1] >= SignalLineBuffer[i+1] && MACDLineBuffer[i] < SignalLineBuffer[i])
//isBullishSignalLineCrossActive = false;
//--- reset bearish 'active' flag
//if (MACDLineBuffer[i+1] <= SignalLineBuffer[i+1] && MACDLineBuffer[i] > SignalLineBuffer[i])
//isBearishSignalLineCrossActive = false;
//--- bullish cross
if (MACDLineBuffer[i] > SignalLineBuffer[i]+SignalLineGap/factor && !isBullishSignalLineCrossActive)
{
isBullishSignalLineCross = true;
isBullishSignalLineCrossActive = true;
isBearishSignalLineCrossActive = false;
}
//--- bearish cross
if (MACDLineBuffer[i] < SignalLineBuffer[i]-SignalLineGap/factor && !isBearishSignalLineCrossActive)
{
isBearishSignalLineCross = true;
isBearishSignalLineCrossActive = true;
isBullishSignalLineCrossActive = false;
}
//--- bullish arrow and alert
if (isBullishSignalLineCross)
{
// send alert
if (SendSignalLineCrossAlert && isNewBar)
{
string str = "Bullish Signal Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
SendAlert(str,SendSignalLineCrossAlert,SendSignalLineCrossText);
}
// draw arrow
if (ShowSignalLineCrossArrows)
{
string str = "Bullish_Signal_Line_Cross_Arrow";
drawArrow(i, myLow[i], myHigh[i], myTime[i], true, ArrowSpacing, BullishSignalLineCrossArrowColor, BullishSignalLineCrossArrowCode, BullishSignalLineCrossArrowWidth, str);
}
}
//--- bearish arrow and alert
if (isBearishSignalLineCross)
{
// send alert
if (SendSignalLineCrossAlert && isNewBar)
{
string str = "Bearish Signal Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
SendAlert(str,SendSignalLineCrossAlert,SendSignalLineCrossText);
}
// draw arrow
if (ShowSignalLineCrossArrows)
{
string str = "Bearish_Signal_Line_Cross_Arrow";
drawArrow(i, myLow[i], myHigh[i], myTime[i], false, ArrowSpacing, BearishSignalLineCrossArrowColor, BearishSignalLineCrossArrowCode, BearishSignalLineCrossArrowWidth, str);
}
}
//
//
//
//--- zero line cross
bool isBullishZeroLineCross = false;
bool isBearishZeroLineCross = false;
//isBullishZeroLineCross = (MACDLineBuffer[i+1] <= 0 && MACDLineBuffer[i] > 0);
//isBearishZeroLineCross = (MACDLineBuffer[i+1] >= 0 && MACDLineBuffer[i] < 0);
//--- bullish cross
if (MACDLineBuffer[i] > ZeroLineGap/factor && !isBullishZeroLineCrossActive)
{
isBullishZeroLineCross = true;
isBullishZeroLineCrossActive = true;
isBearishZeroLineCrossActive = false;
}
//--- bearish cross
if (MACDLineBuffer[i] < -ZeroLineGap/factor && !isBearishZeroLineCrossActive)
{
isBearishZeroLineCross = true;
isBearishZeroLineCrossActive = true;
isBullishZeroLineCrossActive = false;
}
//--- bullish arrow and alert
if (isBullishZeroLineCross)
{
// send alert
if (SendZeroLineCrossAlert && isNewBar)
{
string str = "Bullish Zero Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
SendAlert(str,SendZeroLineCrossAlert,SendZeroLineCrossText);
}
// draw arrow
if (ShowZeroLineCrossArrows)
{
string str = "Bullish_Zero_Line_Cross_Arrow";
drawArrow(i, myLow[i], myHigh[i], myTime[i], true, ArrowSpacing, BullishZeroLineCrossArrowColor, BullishZeroLineCrossArrowCode, BullishZeroLineCrossArrowWidth, str);
}
}
//--- bearish arrow and alert
if (isBearishZeroLineCross)
{
// send alert
if (SendZeroLineCrossAlert && isNewBar)
{
string str = "Bearish Zero Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
SendAlert(str,SendZeroLineCrossAlert,SendZeroLineCrossText);
}
// draw arrow
if (ShowZeroLineCrossArrows)
{
string str = "Bearish_Zero_Line_Cross_Arrow";
drawArrow(i, myLow[i], myHigh[i], myTime[i], false, ArrowSpacing, BearishZeroLineCrossArrowColor, BearishZeroLineCrossArrowCode, BearishZeroLineCrossArrowWidth, str);
}
}
}
//+------------------------------------------------------------------+
//| drawArrow() |
//+------------------------------------------------------------------+
void drawArrow(int i,
double myLow,
double myHigh,
datetime myTime,
bool upArrow,
double arrowSpacing,
color myColor,
int myArrowCode,
int myWidth,
string myName)
{
string name = myName+"_"+TimeToString(myTime)+ObjDel;
ObjectCreate(0,name,OBJ_ARROW,0,0,0,0,0);
ObjectSetInteger(0,name,OBJPROP_ARROWCODE,myArrowCode);
ObjectSetInteger(0,name,OBJPROP_COLOR,myColor);
ObjectSetInteger(0,name,OBJPROP_WIDTH,myWidth);
ObjectSetInteger(0,name,OBJPROP_TIME,myTime);
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
if (upArrow)
ObjectSetDouble(0,name,OBJPROP_PRICE,myLow-arrowSpacing);
else
ObjectSetDouble(0,name,OBJPROP_PRICE,myHigh+arrowSpacing);
}
//+------------------------------------------------------------------+
// IsNewBar() |
//+------------------------------------------------------------------+
bool IsNewBar()
{
static datetime lastTime;
bool isNewBar = (iTime(_Symbol,_Period,0) != lastTime);
lastTime = iTime(_Symbol,_Period,0);
return(isNewBar);
}
//+------------------------------------------------------------------+
// StringUpper(string str) |
//+------------------------------------------------------------------+
// Converts any lowercase characters in a string to uppercase
// Usage: string x=StringUpper("The Quick Brown Fox") returns x = "THE QUICK BROWN FOX"
string StringUpper(string str)
{
string outstr = "";
string lower = "abcdefghijklmnopqrstuvwxyz";
string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(int i=0; i<StringLen(str); i++) {
int t1 = StringFind(lower,StringSubstr(str,i,1),0);
if (t1 >=0)
outstr = outstr + StringSubstr(upper,t1,1);
else
outstr = outstr + StringSubstr(str,i,1);
}
return(outstr);
} //End StringUpper(string str)
//+------------------------------------------------------------------+
//| StrToTF() |
//+------------------------------------------------------------------+
int StrToTF(string tfs)
{
StringToUpper(tfs);
for(int i=ArraySize(TFenum)-1; i>=0; i--)
if(tfs==TFstr[i])
return(TFenum[i]);
return(_Period);
}
//+------------------------------------------------------------------+
//| TFToStr() |
//+------------------------------------------------------------------+
string TFToStr(int tf)
{
for(int i=ArraySize(TFint)-1; i>=0; i--)
if(tf==TFint[i])
return(TFstr[i]);
return("Current");
}
//+------------------------------------------------------------------+
//| TFEnumToStr() |
//+------------------------------------------------------------------+
string TFEnumToStr(ENUM_TIMEFRAMES tf)
{
string str="Current";
for (int i=ArraySize(TFenum)-1; i>=0; i--)
if (tf==TFenum[i])
str=TFstr[i];
if (str=="Current")
str=TFToStr(_Period);
return(str);
}
//+------------------------------------------------------------------+
//| TFCurrentToEnum() |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES TFCurrentToEnum(ENUM_TIMEFRAMES tf)
{
if(tf == PERIOD_CURRENT)
{
int period=_Period;
for(int i=ArraySize(TFint)-1; i>=0; i--)
if(period==TFint[i])
return(TFenum[i]);
}
return(tf);
}
//+------------------------------------------------------------------+
//| SendAlert() |
//+------------------------------------------------------------------+
void SendAlert(string sMsg, bool popAlert, bool textMsg)
{
if(popAlert)
Alert(sMsg);
if(textMsg)
SendNotification(sMsg);
}
//+------------------------------------------------------------------+
//| Pip Factor |
//+------------------------------------------------------------------+
double PFactor(string symbol)
{
//This code supplied by Lifesys. Many thanks Paul - we all owe you.
//Gary was trying to make me see this, but I could not understand his explanation.
//Paul used Janet and John words.
for ( int i = ArraySize(pipFactor)-1; i >=0; i-- )
if (StringFind(symbol,pipFactor[i],0) != -1)
return (pipFactors[i]);
return(10000);
}//End double PFactor(string pair)
//+------------------------------------------------------------------+
//| CloseEnough() |
//+------------------------------------------------------------------+
bool CloseEnough(double num1, double num2)
{
/*
This function addresses the problem of the way in which mql4 compares doubles. It often messes up the 8th
decimal point.
For example, if A = 1.5 and B = 1.5, then these numbers are clearly equal. Unseen by the coder, mql4 may
actually be giving B the value of 1.50000001, and so the variable are not equal, even though they are.
This nice little quirk explains some of the problems I have endured in the past when comparing doubles. This
is common to a lot of program languages, so watch out for it if you program elsewhere.
Gary (garyfritz) offered this solution, so our thanks to him.
*/
if (num1 == 0 && num2 == 0) return(true); //0==0
if (MathAbs(num1 - num2) / (MathAbs(num1) + MathAbs(num2)) < 0.00000001) return(true);
//Doubles are unequal
return(false);
}//End bool CloseEnough(double num1, double num2)
//+------------------------------------------------------------------+
//| DeleteChartObjects() |
//+------------------------------------------------------------------+
void DeleteChartObjects(string str)
{
// Delete objects when indicator is removed from chart
// Add "+ObjDel" to end of object's name
// ObjDel --> unique indicator identifier
for(int i=ObjectsTotal(0)-1; i>=0; i--)
{
string name=ObjectName(0,i);
if(StringFind(name, str, 0) != -1)
{
ObjectDelete(0,name);
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool FillArrayFromBuffer(int ind_handle, // handle of the indicator
int ind_buff, // indicator buffer number
int start, // start
int count, // number of copied values
double &arr[], // array for indicator values
bool as_series, // index elements as series
string ind_name) // name of indicator
{
//--- set as series
if(as_series) ArraySetAsSeries(arr, true);
//--- reset error code
ResetLastError();
//--- fill a part of the iMABuffer array with values from the indicator buffer that has 0 index
if(CopyBuffer(ind_handle,ind_buff,start,count,arr)<0)
{
//--- if the copying fails, tell the error code
PrintFormat("Failed to copy data from the "+ind_name+" indicator, error code %d",_LastError);
//--- quit with zero result - it means that the indicator is considered as not calculated
return(false);
}
//--- everything is fine
return(true);
}
//+------------------------------------------------------------------+