این یک اکسپرت هست که برای mql4 نوشته شده
//+------------------------------------------------------------------+
//| MACDivergenceSimple.mq4 |
//| Copyright 2023, HDNSOFT Ltd. |
//| https://www.hdnsoft.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, HDNSOFT Ltd."
#property link "https://www.hdnsoft.com"
#property version "1.00"
#property strict// تنظیمات ورودی
input int MACD_FastEMA = 60;
input int MACD_SlowEMA = 130;
input int MACD_SignalSMA = 45;
input int FontSize = 10; // اندازه فونت تایمر
input color FontColor = clrDarkOrange; // رنگ فونت تایمر
input string FontName = "Tahoma"; // نام فونت تایمرdatetime lastTime = 0; // زمان آخرین کندل
// آرایههای ذخیرهسازی
double macdPositiveValues[];
double macdNegativeValues[];
int positiveBarNumbers[];
int negativeBarNumbers[];
datetime positiveDates[];
datetime negativeDates[];//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// حذف تمامی آبجکتهایی که حاوی عبارت "MACDivergence" هستند
DeleteObjectsWithNamePart("MACDivergence");
lastTime = iTime(NULL, 0, 0); // زمان اولین کندل
// تنظیم تایمر برای هر ثانیه
EventSetTimer(1);
DrawHourlyLines();
// اجرای تحلیل و ذخیرهسازی مقادیر
AnalyzeAndStoreValues();
// رسم فلشها بر اساس مقادیر آرایهها
DrawArrowsFromArrays();
CompareAndDrawTrendLines();return(INIT_SUCCEEDED);
}//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
// توقف تایمر
EventKillTimer();
// Remove all vertical lines with "first-Line" in the name when the expert advisor is removed
for (int i = ObjectsTotal() - 1; i >= 0; i--)
{
string objName = ObjectName(i);
if (StringFind(objName, "first-Line") != -1)
{
ObjectDelete(objName);
}
}
}//+------------------------------------------------------------------+
//| Delete objects containing a specific name part |
//+------------------------------------------------------------------+
void DeleteObjectsWithNamePart(string namePart) {
int totalObjects = ObjectsTotal();
for (int i = totalObjects - 1; i >= 0; i--) {
string name = ObjectName(i);
if (StringFind(name, namePart) >= 0) {
ObjectDelete(name);
}
}
}//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer() {
datetime currentTime = iTime(NULL, 0, 0);// بررسی بسته شدن کندل جدید
if (currentTime != lastTime) {
lastTime = currentTime;// حذف آبجکتهای قبلی
DeleteObjectsWithNamePart("MACDivergence");
// رسم خطوط یک ساعته
DrawHourlyLines();
// اجرای تحلیل و ذخیرهسازی مقادیر
AnalyzeAndStoreValues();
// رسم فلشها بر اساس مقادیر آرایهها
DrawArrowsFromArrays();
CompareAndDrawTrendLines();
}// نمایش شمارنده معکوس
ShowCountdownTimer();
}//+------------------------------------------------------------------+
//| Analyze MACD phases and store values |
//+------------------------------------------------------------------+
void AnalyzeAndStoreValues() {
int bars = iBars(NULL, 0);
ArrayResize(macdPositiveValues, 0);
ArrayResize(macdNegativeValues, 0);
ArrayResize(positiveBarNumbers, 0);
ArrayResize(negativeBarNumbers, 0);
ArrayResize(positiveDates, 0);
ArrayResize(negativeDates, 0);bool isPositive = false;
double maxMACD = -DBL_MAX;
double minMACD = DBL_MAX;
int maxIndex = -1;
int minIndex = -1;for (int i = bars - 1; i >= 0; i--) {
double macdValue = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, i);
double signalValue = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_SIGNAL, i);if (signalValue > 0) {
if (!isPositive) {
if (minIndex != -1) {
// ذخیره مقادیر مکدی منفی
ArrayResize(macdNegativeValues, ArraySize(macdNegativeValues) + 1);
ArrayResize(negativeBarNumbers, ArraySize(negativeBarNumbers) + 1);
ArrayResize(negativeDates, ArraySize(negativeDates) + 1);
macdNegativeValues[ArraySize(macdNegativeValues) - 1] = minMACD;
negativeBarNumbers[ArraySize(negativeBarNumbers) - 1] = minIndex;
negativeDates[ArraySize(negativeDates) - 1] = Time[minIndex];
}
isPositive = true;
maxMACD = macdValue;
maxIndex = i;
} else if (macdValue > maxMACD) {
maxMACD = macdValue;
maxIndex = i;
}
} else {
if (isPositive) {
if (maxIndex != -1) {
// ذخیره مقادیر مکدی مثبت
ArrayResize(macdPositiveValues, ArraySize(macdPositiveValues) + 1);
ArrayResize(positiveBarNumbers, ArraySize(positiveBarNumbers) + 1);
ArrayResize(positiveDates, ArraySize(positiveDates) + 1);
macdPositiveValues[ArraySize(macdPositiveValues) - 1] = maxMACD;
positiveBarNumbers[ArraySize(positiveBarNumbers) - 1] = maxIndex;
positiveDates[ArraySize(positiveDates) - 1] = Time[maxIndex];
}
isPositive = false;
minMACD = macdValue;
minIndex = i;
} else if (macdValue < minMACD) {
minMACD = macdValue;
minIndex = i;
}
}
}
}//+------------------------------------------------------------------+
//| Show countdown timer |
//+------------------------------------------------------------------+
void ShowCountdownTimer() {
datetime currentTime = TimeCurrent();
datetime candleCloseTime = iTime(NULL, 0, 0) + PeriodSeconds();
int secondsRemaining = (int)(candleCloseTime - currentTime);string text;
if (secondsRemaining < 60) {
text = " " + IntegerToString(secondsRemaining) + "s";
} else if (secondsRemaining < 3600) {
int minutes = secondsRemaining / 60;
int seconds = secondsRemaining % 60;
text = " " + IntegerToString(minutes) + "m " + IntegerToString(seconds) + "s";
} else if (secondsRemaining < 86400) {
int hours = secondsRemaining / 3600;
int minutes = (secondsRemaining % 3600) / 60;
int seconds = secondsRemaining % 60;
text = " " + IntegerToString(hours) + ":" + IntegerToString(minutes) + ":" + IntegerToString(seconds);
} else {
int days = secondsRemaining / 86400;
int hours = (secondsRemaining % 86400) / 3600;
int minutes = (secondsRemaining % 3600) / 60;
int seconds = secondsRemaining % 60;
text = " ⏰ " + IntegerToString(days) + "d " + IntegerToString(hours) + ":" + IntegerToString(minutes) + ":" + IntegerToString(seconds);
}string name = "MACDivergence_CountdownTimer";
double askPrice = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits);
// تغییر مکان تایمر به دو کندل جلوتر
double offsetPrice = askPrice;
datetime futureTime = iTime(NULL, 0, 0) + 2 * PeriodSeconds();bool created = ObjectCreate(0, name, OBJ_TEXT, 0, futureTime, offsetPrice);
if (created) {
ObjectSetInteger(0, name, OBJPROP_COLOR, FontColor);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetString(0, name, OBJPROP_FONT, FontName);
} else {
ObjectSetString(0, name, OBJPROP_TEXT, text); // بروزرسانی متن تایمر در صورت ایجاد قبلی
ObjectMove(0, name, 0, futureTime, offsetPrice); // بروزرسانی مکان تایمر در صورت ایجاد قبلی
}
}
//+------------------------------------------------------------------+
//| Draw arrows based on array values |
//+------------------------------------------------------------------+
void DrawArrowsFromArrays() {
// رسم فلشها برای مقادیر مثبت مکدی
for (int i = 0; i < ArraySize(macdPositiveValues); i++) {
DrawArrowOnChart(positiveBarNumbers[i], true, 1); // درج فلش سبز در پنجره مکدی
DrawArrowOnChart(positiveBarNumbers[i], true, 0); // درج فلش سبز در پنجره چارت
}// رسم فلشها برای مقادیر منفی مکدی
for (int i = 0; i < ArraySize(macdNegativeValues); i++) {
DrawArrowOnChart(negativeBarNumbers[i], false, 1); // درج فلش قرمز در پنجره مکدی
DrawArrowOnChart(negativeBarNumbers[i], false, 0); // درج فلش قرمز در پنجره چارت
}
}
//+------------------------------------------------------------------+
//| Draw arrow on chart at specified bar |
//+------------------------------------------------------------------+
void DrawArrowOnChart(int barNumber, bool isUp, int window) {
string name = "MACDivergence_Arrow_" + IntegerToString(barNumber) + (window == 1 ? "_MACD" : "_Chart");
double arrowPrice;
double priceRange = WindowPriceMax() - WindowPriceMin();
double offsetUpChart = priceRange * 0.03; // تنظیم فاصله برای فلشهای رو به بالا در چارت
double offsetDownChart = priceRange * 0.01; // تنظیم فاصله برای فلشهای رو به پایین در چارت
double offsetUpMACD = priceRange * 0.015; // تنظیم فاصله برای فلشهای رو به بالا در مکدی
double offsetDownMACD = priceRange * 0.005; // تنظیم فاصله برای فلشهای رو به پایین در مکدیif (window == 1) {
arrowPrice = isUp ? iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, barNumber) + offsetUpMACD
: iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, barNumber) - offsetDownMACD;
} else {
if (isUp) {
arrowPrice = High[barNumber] + offsetUpChart; // فلش سبز برای high کندل
} else {
arrowPrice = Low[barNumber] - offsetDownChart; // فلش قرمز برای low کندل
}
}bool created = ObjectCreate(0, name, OBJ_TEXT, window, Time[barNumber], arrowPrice);
if (created) {
ObjectSetInteger(0, name, OBJPROP_COLOR, isUp ? clrDeepSkyBlue : clrDeepPink);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, name, OBJPROP_TEXT, isUp ? "▲" : "▼");
}
}
//+------------------------------------------------------------------+
//| Compare MACD values and draw trend lines |
//+------------------------------------------------------------------+
void CompareAndDrawTrendLines() {
// مقایسه و رسم ترند لاینها برای مقادیر مثبت مکدی
for (int i = 0; i < ArraySize(macdPositiveValues) - 1; i++) {
if (macdPositiveValues[i] > macdPositiveValues[i + 1] && High[positiveBarNumbers[i]] < High[positiveBarNumbers[i + 1]]) {
// رسم ترند لاین بین مقادیر high کندل
DrawTrendLine(positiveBarNumbers[i], positiveBarNumbers[i + 1], 1);// رسم ترند لاین بین مقادیر مثبت مکدی بر اساس عدد کندل
DrawPositiveMACDTrendLine(positiveBarNumbers[i], positiveBarNumbers[i + 1]);
}
}// مقایسه و رسم ترند لاینها برای مقادیر منفی مکدی
for (int i = 0; i < ArraySize(macdNegativeValues) - 1; i++) {
if (macdNegativeValues[i] < macdNegativeValues[i + 1] && Low[negativeBarNumbers[i]] > Low[negativeBarNumbers[i + 1]]) {
// رسم ترند لاین بین مقادیر low کندل
DrawTrendLine(negativeBarNumbers[i], negativeBarNumbers[i + 1], -1);// رسم ترند لاین بین مقادیر منفی مکدی بر اساس عدد کندل
DrawNegativeMACDTrendLine(negativeBarNumbers[i], negativeBarNumbers[i + 1]);
}
}
}//+------------------------------------------------------------------+
//| Draw positive MACD trend line between two bars based on candle numbers |
//+------------------------------------------------------------------+
void DrawPositiveMACDTrendLine(int barNumber1, int barNumber2) {
string name = "MACDivergence_PositiveMACDTrendLine_" + IntegerToString(barNumber1) + "_to_" + IntegerToString(barNumber2);
double price1 = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, barNumber1);
double price2 = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, barNumber2);bool created = ObjectCreate(0, name, OBJ_TREND, 1, Time[barNumber1], price1, Time[barNumber2], price2);
if (created) {
ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkGreen); // تنظیم رنگ به سبز تیره
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, name, OBJPROP_RAY, false); // خارج کردن خط ترند از حالت Ray
}
}//+------------------------------------------------------------------+
//| Draw negative MACD trend line between two bars based on candle numbers |
//+------------------------------------------------------------------+
void DrawNegativeMACDTrendLine(int barNumber1, int barNumber2) {
string name = "MACDivergence_NegativeMACDTrendLine_" + IntegerToString(barNumber1) + "_to_" + IntegerToString(barNumber2);
double price1 = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, barNumber1);
double price2 = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, barNumber2);bool created = ObjectCreate(0, name, OBJ_TREND, 1, Time[barNumber1], price1, Time[barNumber2], price2);
if (created) {
ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkRed); // تنظیم رنگ به قرمز تیره برای ترند لاینهای منفی مکدی
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, name, OBJPROP_RAY, false); // خارج کردن خط ترند از حالت Ray
}
}//+------------------------------------------------------------------+
//| Draw trend line between two bars on chart only |
//+------------------------------------------------------------------+
void DrawTrendLine(int barNumber1, int barNumber2 ,int type) {
string name = "MACDivergence_TrendLine_" + IntegerToString(barNumber1) + "_to_" + IntegerToString(barNumber2) + "_Chart";
double price1 = Low[barNumber1];
double price2 = Low[barNumber2];
color clr = clrDeepPink;
if(type > 0 )
{
price1 = High[barNumber1];
price2 = High[barNumber2];
clr = clrSkyBlue;
}bool created = ObjectCreate(0, name, OBJ_TREND, 0, Time[barNumber1], price1, Time[barNumber2], price2);
if (created) {
ObjectSetInteger(0, name, OBJPROP_COLOR, clr); // تنظیم رنگ به سبز تیره
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, name, OBJPROP_RAY, false); // خارج کردن خط ترند از حالت Ray
}
}void DrawHourlyLines() {
int bars = iBars(NULL, 0);
for (int i = bars - 1; i >= 0; i--) {
datetime time = Time[i];
int minute = TimeMinute(time);
int hh = TimeHour(time);
if ( minute == 0) { // هر 60 دقیقه
string lineName = "MACDivergence_HHLine_" + IntegerToString(i);
if (!ObjectCreate(0, lineName, OBJ_VLINE, 0, time, 0)) {
Print("Failed to create line: ", lineName);
continue;
}
ObjectSetInteger(0, lineName, OBJPROP_COLOR, C'0,153,204');
ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, lineName, OBJPROP_STYLE, STYLE_DASH); // خط چین
}
if (minute % 30 == 0 && minute > 0) { // هر 30 دقیقه
string lineName = "MACDivergence_VLine_" + IntegerToString(i);
if (!ObjectCreate(0, lineName, OBJ_VLINE, 0, time, 0)) {
Print("Failed to create line: ", lineName);
continue;
}
ObjectSetInteger(0, lineName, OBJPROP_COLOR, C'157,86,0');
ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, lineName, OBJPROP_STYLE, STYLE_DASH); // خط چین
}
if (minute % 30 == 0) {// پیدا کردن بالاترین یا پایینترین میله مکدی بر اساس فاز مکدی
double maxMACD = -DBL_MAX;
double minMACD = DBL_MAX;
int maxBar = -1;
int minBar = -1;for (int j = i; j > i - 30 && j >= 0; j--) { // بررسی 30 کندل قبلی
double macdValue = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_MAIN, j);
double signalValue = iMACD(NULL, 0, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE, MODE_SIGNAL, j);if (macdValue >= 0) { // فاز مثبت - به دنبال حداکثر
if (macdValue > maxMACD) {
maxMACD = macdValue;
maxBar = j;
}
} else { // فاز منفی - به دنبال حداقل
if (macdValue < minMACD) {
minMACD = macdValue;
minBar = j;
}
}
}// رسم فلشها
if (maxBar != -1) {
// فلش رو به بالا
DrawArrowOnChart(maxBar, true, 1);
DrawArrowOnChart(maxBar, true, 0);
}
if (minBar != -1) {
// فلش رو به پایین
DrawArrowOnChart(minBar, false, 1);
DrawArrowOnChart(minBar, false, 0);
}
}
}
// تغییر رنگ کندلها
ChartSetInteger(NULL, CHART_COLOR_CANDLE_BULL, clrGreen);
ChartSetInteger(NULL, CHART_COLOR_CHART_UP, clrAqua);
ChartSetInteger(NULL, CHART_COLOR_CANDLE_BEAR, C'132,0,72');
ChartSetInteger(NULL, CHART_COLOR_CHART_DOWN, clrDeepPink);
//رسم خط چین رو به جلو
datetime time = Time[0];
int hour = TimeHour(time);
int minute = TimeMinute(time);
// بررسی اینکه آیا دقیقه کمتر از 30 هست یا بیشتر
if (minute < 30) {
minute = 30; // تنظیم به نیم ساعت
} else {
minute = 0; // تنظیم به ساعت بعد
hour = (hour + 1) % 24; // افزایش ساعت و بررسی عبور از 23 به 0
}
// تبدیل به datetime
datetime roundedTime = StrToTime(TimeToString(time, TIME_DATE) + " " + IntegerToString(hour) + ":" + (minute < 10 ? "0" : "") + IntegerToString(minute));string lineName = "MACDivergence_VLine_Temps" + IntegerToString(0);
ObjectDelete(NULL,"MACDivergence_VLine_Temps" + IntegerToString(0));
ObjectCreate(0, lineName, OBJ_VLINE, 0, roundedTime, 0);
ObjectSetInteger(0, lineName, OBJPROP_COLOR, clrGold);
ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, lineName, OBJPROP_STYLE, STYLE_DASH); // خط چین
}