یک قطعه کد و یادگاری ، شاید بدرد آینده ها خورد.

چهارشنبه ۱۴۰۳/۱۲/۰۸

این یک اکسپرت هست که برای 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); // خط چین





}