//+------------------------------------------------------------------+ //| Gold_Scalping_Balanced.mq5 | //| Copyright 2025, Manus System | //| | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Manus System" #property link "" #property version "1.01" #property strict //+------------------------------------------------------------------+ /* تم تضمين صورة الخلفية (gold_scalping_bg.bmp) مباشرة داخل كود الإكسبيرت باستخدام موارد MQL5 (Resources). هذا يعني أنك لست بحاجة لوضع ملف الصورة بشكل منفصل في مجلد MQL5/Files بعد الآن لكي تعمل اللوحة. **هام جداً لعملية الترجمة (Compilation):** لكي يتم تضمين الصورة بنجاح عند ترجمة الكود (تحويل .mq5 إلى .ex5)، يجب أن يكون ملف الصورة `gold_scalping_bg.bmp` موجوداً داخل مجلد فرعي باسم `Files` في نفس المكان الذي يوجد به ملف الكود `.mq5`. مثال لهيكلية المجلدات عند الترجمة: MyExperts/ ├── Gold_Scalping_Balanced.mq5 (ملف الكود هذا) └── Files/ └── gold_scalping_bg.bmp (ملف الصورة) بعد الترجمة الناجحة، يمكنك نقل ملف .ex5 الناتج إلى مجلد Experts الخاص بالمنصة، ولن تحتاج لنقل ملف الصورة معه. يمكنك التحكم في: - ShowBackgroundImage: تفعيل/إلغاء عرض الصورة (input parameter) - BackgroundOpacity: مستوى الشفافية (input parameter, 0-100) ملاحظات: - إذا لم يتم العثور على الصورة أثناء الترجمة، ستظهر رسالة خطأ ولن يتم تضمينها. - تم تحسين ألوان النصوص تلقائياً للظهور بوضوح على الصورة. */ // تضمين مكتبة التداول #include // إعدادات المؤشرات input int MACD_Fast = 12; // فترة MACD السريعة input int MACD_Slow = 26; // فترة MACD البطيئة input int MACD_Signal = 9; // فترة إشارة MACD input int SMA_Period = 50; // فترة المتوسط المتحرك البسيط input int RSI_Period = 14; // فترة مؤشر RSI input int RSI_OverBought = 70; // مستوى التشبع الشرائي input int RSI_OverSold = 30; // مستوى التشبع البيعي input int ATR_Period = 14; // فترة مؤشر ATR // إعدادات التداول input string ExpertName = "Gold Scalping Balanced"; // اسم الإكسبيرت (يظهر في التعليقات) input int MagicNumber = 123456; // الرقم السحري للإكسبيرت input double LotSize = 0.01; // حجم العقد input double RiskPercent = 2.0; // نسبة المخاطرة من الحساب (%) input int TakeProfit = 500; // جني الأرباح (بالنقاط) input int StopLoss = 300; // وقف الخسارة (بالنقاط) input bool UseATRStopLoss = true; // استخدام ATR لوقف الخسارة input double ATRMultiplier = 2.0; // مضاعف ATR لوقف الخسارة input int MaxSpread = 30; // الحد الأقصى للسبريد (بالنقاط) input int MaxDailyTrades = 5; // الحد الأقصى لعدد الصفقات اليومية input int MinutesBetweenTrades = 60; // الوقت بين الصفقات (بالدقائق) input bool UseTrailingStop = true; // استخدام وقف الخسارة المتحرك input int TrailingStart = 200; // بدء وقف الخسارة المتحرك (بالنقاط) input int TrailingStep = 50; // خطوة وقف الخسارة المتحرك (بالنقاط) // إعدادات الباك تيست المحسنة input group "=== إعدادات الباك تيست ===" input bool UseBacktestSpread = true; // استخدام سبريد مخصص للباك تيست input int BacktestSpreadPoints = 30; // السبريد المخصص للباك تيست (بالنقاط) input int BacktestSlippage = 3; // الانزلاق المخصص للباك تيست (بالنقاط) input bool ShowBacktestInfo = true; // عرض معلومات الباك تيست في اللوحة // إعدادات الوقت input group "=== إعدادات التوقيت ===" input bool TradeOnlyDuringOptimalHours = true; // التداول فقط خلال الساعات المثالية input int StartHour = 8; // ساعة بدء التداول (بتوقيت المنصة) input int EndHour = 17; // ساعة إنهاء التداول (بتوقيت المنصة) input bool AvoidNews = true; // تجنب التداول خلال الأخبار // إعدادات الفلاتر المتقدمة input group "=== الفلاتر المتقدمة ===" input bool UseMultiTimeframeFilter = true; // استخدام فلتر الأطر الزمنية المتعددة input bool UseVolatilityFilter = true; // استخدام فلتر التقلبات input double MinATRValue = 8.0; // الحد الأدنى لقيمة ATR للتداول input bool UseTrendFilter = true; // استخدام فلتر الاتجاه input int TrendSMA_Period = 200; // فترة المتوسط المتحرك للاتجاه input bool UseCandlePatterns = true; // استخدام أنماط الشموع اليابانية // إعدادات لوحة المعلومات input group "=== إعدادات اللوحة ===" input bool ShowDashboard = true; // عرض لوحة النتائج input int DashboardCorner = 4; // زاوية اللوحة (0=أعلى يسار، 1=أعلى يمين، 2=أسفل يسار، 3=أسفل يمين) input int DashboardXOffset = 20; // المسافة الأفقية من الحافة input int DashboardYOffset = 30; // المسافة العمودية من الحافة input bool ShowBackgroundImage = true; // عرض صورة الخلفية // input string BackgroundImagePath = "gold_scalping_bg.bmp"; // مسار صورة الخلفية (ضع الصورة في مجلد MQL5/Files) input int BackgroundOpacity = 30; // شفافية الخلفية (0-100) // متغيرات عامة int macdHandle; // مؤشر MACD int smaHandle; // مؤشر المتوسط المتحرك البسيط int rsiHandle; // مؤشر القوة النسبية int atrHandle; // مؤشر ATR int trendSMAHandle; // مؤشر المتوسط المتحرك للاتجاه int dailyTradeCount = 0; // عدد الصفقات اليومية datetime lastTradeTime = 0; // وقت آخر صفقة CTrade trade; // كائن التداول // متغيرات الباك تيست bool isBacktesting = false; // هل يعمل الإكسبرت في وضع الباك تيست double appliedSpread = 0; // السبريد المطبق حالياً // متغيرات لوحة النتائج double dailyProfit = 0.0; // الربح اليومي double weeklyProfit = 0.0; // الربح الأسبوعي double monthlyProfit = 0.0; // الربح الشهري double totalProfit = 0.0; // إجمالي الربح int totalTrades = 0; // إجمالي الصفقات int winTrades = 0; // الصفقات الرابحة int lossTrades = 0; // الصفقات الخاسرة double winRate = 0.0; // معدل النجاح datetime startOfDay = 0; // بداية اليوم datetime startOfWeek = 0; // بداية الأسبوع datetime startOfMonth = 0; // بداية الشهر //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // التحقق من وضع الباك تيست isBacktesting = MQLInfoInteger(MQL_TESTER); // حساب السبريد المطبق if(isBacktesting && UseBacktestSpread) { appliedSpread = BacktestSpreadPoints * SymbolInfoDouble(_Symbol, SYMBOL_POINT); Print("=== وضع الباك تيست مُفعل ==="); Print("السبريد المطبق: ", BacktestSpreadPoints, " نقطة"); Print("الانزلاق المطبق: ", BacktestSlippage, " نقطة"); } else { appliedSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * SymbolInfoDouble(_Symbol, SYMBOL_POINT); if(!isBacktesting) Print("=== وضع التداول المباشر ==="); } // تهيئة المؤشرات macdHandle = iMACD(_Symbol, PERIOD_M5, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); smaHandle = iMA(_Symbol, PERIOD_M5, SMA_Period, 0, MODE_SMA, PRICE_CLOSE); rsiHandle = iRSI(_Symbol, PERIOD_M5, RSI_Period, PRICE_CLOSE); atrHandle = iATR(_Symbol, PERIOD_M5, ATR_Period); if(UseTrendFilter) trendSMAHandle = iMA(_Symbol, PERIOD_H1, TrendSMA_Period, 0, MODE_SMA, PRICE_CLOSE); // التحقق من صحة المؤشرات if(macdHandle == INVALID_HANDLE || smaHandle == INVALID_HANDLE || rsiHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE || (UseTrendFilter && trendSMAHandle == INVALID_HANDLE)) { Print("فشل في إنشاء المؤشرات!"); return(INIT_FAILED); } // إعداد كائن التداول trade.SetExpertMagicNumber(MagicNumber); // إعداد الانزلاق للباك تيست if(isBacktesting && UseBacktestSpread) { trade.SetDeviationInPoints(BacktestSlippage); } // تهيئة متغيرات الوقت InitializeDateVariables(); // إنشاء لوحة النتائج if(ShowDashboard) CreateDashboard(); // إعداد التنبيهات Print("=== تم تهيئة ", ExpertName, " ==="); Print("الرقم السحري: ", MagicNumber); Print("الإعدادات: حجم العقد = ", LotSize, ", جني الأرباح = ", TakeProfit, ", وقف الخسارة = ", StopLoss); // تنبيه حول صورة الخلفية if(ShowBackgroundImage) { Print("لعرض صورة الخلفية، ضع الصورة في المسار التالي:"); Print("يجب أن تكون الصورة بصيغة BMP وبأبعاد مناسبة (مثل 270x310 بكسل)"); Print("شفافية الخلفية الحالية: ", BackgroundOpacity, "%"); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // حذف جميع الكائنات المرسومة if(ShowDashboard) DeleteDashboard(); // تحرير موارد المؤشرات IndicatorRelease(macdHandle); IndicatorRelease(smaHandle); IndicatorRelease(rsiHandle); IndicatorRelease(atrHandle); if(UseTrendFilter) IndicatorRelease(trendSMAHandle); Print("=== تم إيقاف ", ExpertName, " ==="); } //+------------------------------------------------------------------+ //| الحصول على السعر المُعدل للباك تيست | //+------------------------------------------------------------------+ double GetAdjustedBuyPrice() { double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(isBacktesting && UseBacktestSpread) { // إضافة نصف السبريد المخصص لسعر الشراء askPrice += appliedSpread / 2; } return askPrice; } //+------------------------------------------------------------------+ //| الحصول على السعر المُعدل للبيع للباك تيست | //+------------------------------------------------------------------+ double GetAdjustedSellPrice() { double bidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(isBacktesting && UseBacktestSpread) { // طرح نصف السبريد المخصص لسعر البيع bidPrice -= appliedSpread / 2; } return bidPrice; } //+------------------------------------------------------------------+ //| حساب السبريد الفعلي | //+------------------------------------------------------------------+ double GetEffectiveSpread() { if(isBacktesting && UseBacktestSpread) { return BacktestSpreadPoints; } else { return SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // التحقق من يوم جديد if(IsNewDay()) { dailyTradeCount = 0; InitializeDateVariables(); Print("يوم جديد تم اكتشافه، إعادة تعيين عدد الصفقات اليومية"); } // تحديث الإحصائيات UpdateStatistics(); // تحديث لوحة النتائج if(ShowDashboard) UpdateDashboard(); // إدارة الصفقات المفتوحة (وقف الخسارة المتحرك) if(UseTrailingStop) ManageTrailingStop(); // التحقق من شروط التداول الأساسية if(!IsTradeAllowed()) { return; } // الحصول على قيم المؤشرات double macdMain = 0, macdSignal = 0; GetMACDValues(macdMain, macdSignal); double smaValue = GetSMAValue(); double rsiValue = GetRSIValue(); double atrValue = GetATRValue(); // الحصول على الأسعار المُعدلة للباك تيست double askPrice = GetAdjustedBuyPrice(); double bidPrice = GetAdjustedSellPrice(); // التحقق من فلتر الاتجاه إذا كان مفعلاً bool trendFilterPassed = true; if(UseTrendFilter) { double trendSMAValue = GetTrendSMAValue(); // تخفيف شرط فلتر الاتجاه - نسمح بالتداول في كلا الاتجاهين trendFilterPassed = true; // دائماً يمرر الفلتر } // التحقق من فلتر التقلبات إذا كان مفعلاً bool volatilityFilterPassed = true; if(UseVolatilityFilter) { volatilityFilterPassed = (atrValue >= MinATRValue); } // التحقق من فلتر الأطر الزمنية المتعددة إذا كان مفعلاً bool multiTimeframeFilterPassed = true; if(UseMultiTimeframeFilter) { multiTimeframeFilterPassed = CheckMultiTimeframeFilter(); } // التحقق من إشارات الشراء if(IsBuySignal(macdMain, macdSignal, smaValue, rsiValue, askPrice) && trendFilterPassed && volatilityFilterPassed && multiTimeframeFilterPassed) { Print("تم اكتشاف إشارة شراء!"); ExecuteBuyOrder(askPrice, StopLoss, TakeProfit, atrValue); return; } // التحقق من إشارات البيع if(IsSellSignal(macdMain, macdSignal, smaValue, rsiValue, bidPrice) && trendFilterPassed && volatilityFilterPassed && multiTimeframeFilterPassed) { Print("تم اكتشاف إشارة بيع!"); ExecuteSellOrder(bidPrice, StopLoss, TakeProfit, atrValue); return; } } //+------------------------------------------------------------------+ //| التحقق من إشارة الشراء | //+------------------------------------------------------------------+ bool IsBuySignal(double macdMain, double macdSignal, double smaValue, double rsiValue, double price) { // شروط مخففة للشراء bool macdCondition = (macdMain > macdSignal); // تم إزالة شرط MACD > 0 bool smaCondition = (price > smaValue); bool rsiCondition = (rsiValue > RSI_OverSold); // تم تخفيف شرط RSI // تحقق من نمط الشموع اليابانية إذا كان مفعلاً bool candlePattern = true; if(UseCandlePatterns) candlePattern = CheckBullishCandlePattern(); return macdCondition && smaCondition && rsiCondition && candlePattern; } //+------------------------------------------------------------------+ //| التحقق من إشارة البيع | //+------------------------------------------------------------------+ bool IsSellSignal(double macdMain, double macdSignal, double smaValue, double rsiValue, double price) { // شروط مخففة للبيع bool macdCondition = (macdMain < macdSignal); // تم إزالة شرط MACD < 0 bool smaCondition = (price < smaValue); bool rsiCondition = (rsiValue < RSI_OverBought); // تم تخفيف شرط RSI // تحقق من نمط الشموع اليابانية إذا كان مفعلاً bool candlePattern = true; if(UseCandlePatterns) candlePattern = CheckBearishCandlePattern(); return macdCondition && smaCondition && rsiCondition && candlePattern; } //+------------------------------------------------------------------+ //| تنفيذ أمر شراء | //+------------------------------------------------------------------+ void ExecuteBuyOrder(double price, int stopLoss, int takeProfit, double atrValue) { // حساب حجم العقد بناءً على نسبة المخاطرة إذا كان مطلوباً double finalLotSize = LotSize; if(RiskPercent > 0) { double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = accountBalance * RiskPercent / 100; double pointValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); if(UseATRStopLoss) finalLotSize = NormalizeDouble(riskAmount / (ATRMultiplier * atrValue * pointValue), 2); else finalLotSize = NormalizeDouble(riskAmount / (stopLoss * pointValue), 2); // التأكد من أن حجم العقد ضمن الحدود المسموح بها double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); finalLotSize = MathMax(minLot, MathMin(maxLot, finalLotSize)); } // تحويل النقاط إلى قيم سعرية للذهب double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double sl, tp; if(UseATRStopLoss) sl = price - ATRMultiplier * atrValue; else sl = price - stopLoss * point; tp = price + takeProfit * point; // في حالة الباك تيست، إضافة تكلفة السبريد إلى السعر if(isBacktesting && UseBacktestSpread) { Print("باك تيست - السعر الأصلي: ", SymbolInfoDouble(_Symbol, SYMBOL_ASK), " السعر المُعدل: ", price, " (سبريد إضافي: ", BacktestSpreadPoints, " نقطة)"); } Print("محاولة فتح صفقة شراء - السعر: ", price, " SL: ", sl, " TP: ", tp, " حجم العقد: ", finalLotSize); // إنشاء تعليق الصفقة مع اسم الإكسبيرت وحالة الباك تيست string comment = ExpertName + " - Buy"; if(isBacktesting) comment += " [BT:" + IntegerToString(BacktestSpreadPoints) + "sp]"; // فتح صفقة شراء if(trade.Buy(finalLotSize, _Symbol, price, sl, tp, comment)) { Print("تم إرسال أمر الشراء بنجاح! الصفقة #", trade.ResultOrder()); Print("كود النتيجة: ", trade.ResultRetcode(), ", الوصف: ", trade.ResultRetcodeDescription()); dailyTradeCount++; lastTradeTime = TimeCurrent(); } else { Print("فشل في إرسال أمر الشراء. كود الخطأ: ", trade.ResultRetcode()); Print("وصف الخطأ: ", trade.ResultRetcodeDescription()); } } //+------------------------------------------------------------------+ //| تنفيذ أمر بيع (مُصحح) | //+------------------------------------------------------------------+ void ExecuteSellOrder(double price, int stopLoss, int takeProfit, double atrValue) { // حساب حجم العقد بناءً على نسبة المخاطرة إذا كان مطلوباً double finalLotSize = LotSize; if(RiskPercent > 0) { double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = accountBalance * RiskPercent / 100; double pointValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); if(UseATRStopLoss) finalLotSize = NormalizeDouble(riskAmount / (ATRMultiplier * atrValue * pointValue), 2); else finalLotSize = NormalizeDouble(riskAmount / (stopLoss * pointValue), 2); // التأكد من أن حجم العقد ضمن الحدود المسموح بها double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); finalLotSize = MathMax(minLot, MathMin(maxLot, finalLotSize)); } // تحويل النقاط إلى قيم سعرية للذهب double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double sl, tp; // التصحيح: للبيع - وقف الخسارة أعلى السعر، جني الأرباح أسفل السعر if(UseATRStopLoss) sl = price + ATRMultiplier * atrValue; // وقف الخسارة أعلى سعر البيع else sl = price + stopLoss * point; // وقف الخسارة أعلى سعر البيع tp = price - takeProfit * point; // جني الأرباح أسفل سعر البيع // في حالة الباك تيست، إضافة تكلفة السبريد if(isBacktesting && UseBacktestSpread) { Print("باك تيست - السعر الأصلي: ", SymbolInfoDouble(_Symbol, SYMBOL_BID), " السعر المُعدل: ", price, " (سبريد إضافي: ", BacktestSpreadPoints, " نقطة)"); } Print("محاولة فتح صفقة بيع - السعر: ", price, " SL: ", sl, " TP: ", tp, " حجم العقد: ", finalLotSize); // إنشاء تعليق الصفقة مع اسم الإكسبيرت وحالة الباك تيست string comment = ExpertName + " - Sell"; if(isBacktesting) comment += " [BT:" + IntegerToString(BacktestSpreadPoints) + "sp]"; // فتح صفقة بيع if(trade.Sell(finalLotSize, _Symbol, price, sl, tp, comment)) { Print("تم إرسال أمر البيع بنجاح! الصفقة #", trade.ResultOrder()); Print("كود النتيجة: ", trade.ResultRetcode(), ", الوصف: ", trade.ResultRetcodeDescription()); dailyTradeCount++; lastTradeTime = TimeCurrent(); } else { Print("فشل في إرسال أمر البيع. كود الخطأ: ", trade.ResultRetcode()); Print("وصف الخطأ: ", trade.ResultRetcodeDescription()); } } //+------------------------------------------------------------------+ //| إدارة وقف الخسارة المتحرك | //+------------------------------------------------------------------+ void ManageTrailingStop() { if(!UseTrailingStop) return; for(int i = 0; i < PositionsTotal(); i++) { if(PositionSelectByTicket(PositionGetTicket(i))) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber) { double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentSL = PositionGetDouble(POSITION_SL); double currentTP = PositionGetDouble(POSITION_TP); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double newSL = 0; // حساب وقف الخسارة المتحرك للشراء if(positionType == POSITION_TYPE_BUY) { // التحقق مما إذا كان السعر قد تحرك بما فيه الكفاية لتفعيل وقف الخسارة المتحرك if(currentPrice - positionOpenPrice > TrailingStart * point) { // حساب وقف الخسارة الجديد newSL = currentPrice - TrailingStep * point; // التحقق مما إذا كان وقف الخسارة الجديد أعلى من الحالي if(newSL > currentSL) { // تحديث وقف الخسارة if(trade.PositionModify(PositionGetTicket(i), newSL, currentTP)) { Print("تم تحديث وقف الخسارة المتحرك للصفقة #", PositionGetTicket(i), " إلى ", newSL); } } } } // حساب وقف الخسارة المتحرك للبيع else if(positionType == POSITION_TYPE_SELL) { // التحقق مما إذا كان السعر قد تحرك بما فيه الكفاية لتفعيل وقف الخسارة المتحرك if(positionOpenPrice - currentPrice > TrailingStart * point) { // حساب وقف الخسارة الجديد newSL = currentPrice + TrailingStep * point; // التحقق مما إذا كان وقف الخسارة الجديد أقل من الحالي (أو إذا كان وقف الخسارة الحالي = 0) if(newSL < currentSL || currentSL == 0) { // تحديث وقف الخسارة if(trade.PositionModify(PositionGetTicket(i), newSL, currentTP)) { Print("تم تحديث وقف الخسارة المتحرك للصفقة #", PositionGetTicket(i), " إلى ", newSL); } } } } } } } } //+------------------------------------------------------------------+ //| الحصول على قيم مؤشر MACD | //+------------------------------------------------------------------+ void GetMACDValues(double &macdMain, double &macdSignal) { double macdBuffer[]; double signalBuffer[]; ArraySetAsSeries(macdBuffer, true); ArraySetAsSeries(signalBuffer, true); // التأكد من نسخ البيانات بشكل صحيح int copied1 = CopyBuffer(macdHandle, 0, 0, 3, macdBuffer); int copied2 = CopyBuffer(macdHandle, 1, 0, 3, signalBuffer); if(copied1 <= 0 || copied2 <= 0) { Print("فشل في نسخ بيانات MACD. الخطأ: ", GetLastError()); macdMain = 0; macdSignal = 0; return; } macdMain = macdBuffer[0]; macdSignal = signalBuffer[0]; } //+------------------------------------------------------------------+ //| الحصول على قيمة المتوسط المتحرك البسيط | //+------------------------------------------------------------------+ double GetSMAValue() { double smaBuffer[]; ArraySetAsSeries(smaBuffer, true); // التأكد من نسخ البيانات بشكل صحيح int copied = CopyBuffer(smaHandle, 0, 0, 3, smaBuffer); if(copied <= 0) { Print("فشل في نسخ بيانات SMA. الخطأ: ", GetLastError()); return SymbolInfoDouble(_Symbol, SYMBOL_BID); // استخدام السعر الحالي في حالة الفشل } return smaBuffer[0]; } //+------------------------------------------------------------------+ //| الحصول على قيمة مؤشر RSI | //+------------------------------------------------------------------+ double GetRSIValue() { double rsiBuffer[]; ArraySetAsSeries(rsiBuffer, true); // التأكد من نسخ البيانات بشكل صحيح int copied = CopyBuffer(rsiHandle, 0, 0, 3, rsiBuffer); if(copied <= 0) { Print("فشل في نسخ بيانات RSI. الخطأ: ", GetLastError()); return 50.0; // قيمة محايدة في حالة الفشل } return rsiBuffer[0]; } //+------------------------------------------------------------------+ //| الحصول على قيمة مؤشر ATR | //+------------------------------------------------------------------+ double GetATRValue() { double atrBuffer[]; ArraySetAsSeries(atrBuffer, true); // التأكد من نسخ البيانات بشكل صحيح int copied = CopyBuffer(atrHandle, 0, 0, 3, atrBuffer); if(copied <= 0) { Print("فشل في نسخ بيانات ATR. الخطأ: ", GetLastError()); return 0.001; // قيمة صغيرة في حالة الفشل } return atrBuffer[0]; } //+------------------------------------------------------------------+ //| الحصول على قيمة المتوسط المتحرك للاتجاه | //+------------------------------------------------------------------+ double GetTrendSMAValue() { if(!UseTrendFilter) return 0; double trendSMABuffer[]; ArraySetAsSeries(trendSMABuffer, true); // التأكد من نسخ البيانات بشكل صحيح int copied = CopyBuffer(trendSMAHandle, 0, 0, 3, trendSMABuffer); if(copied <= 0) { Print("فشل في نسخ بيانات Trend SMA. الخطأ: ", GetLastError()); return SymbolInfoDouble(_Symbol, SYMBOL_BID); // استخدام السعر الحالي في حالة الفشل } return trendSMABuffer[0]; } //+------------------------------------------------------------------+ //| التحقق من فلتر الأطر الزمنية المتعددة | //+------------------------------------------------------------------+ bool CheckMultiTimeframeFilter() { // تم تبسيط فلتر الأطر الزمنية المتعددة // التحقق من اتجاه MACD على الإطار الزمني H1 فقط int macdH1Handle = iMACD(_Symbol, PERIOD_H1, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); if(macdH1Handle == INVALID_HANDLE) return true; // في حالة الفشل، نعتبر الفلتر مجتازاً double macdH1Main[], macdH1Signal[]; ArraySetAsSeries(macdH1Main, true); ArraySetAsSeries(macdH1Signal, true); if(CopyBuffer(macdH1Handle, 0, 0, 3, macdH1Main) <= 0 || CopyBuffer(macdH1Handle, 1, 0, 3, macdH1Signal) <= 0) { IndicatorRelease(macdH1Handle); return true; // في حالة الفشل، نعتبر الفلتر مجتازاً } bool h1Bullish = (macdH1Main[0] > macdH1Signal[0]); // تحرير موارد المؤشرات IndicatorRelease(macdH1Handle); // نسمح بالتداول في كلا الاتجاهين return true; } //+------------------------------------------------------------------+ //| التحقق من نمط الشموع اليابانية الصاعد | //+------------------------------------------------------------------+ bool CheckBullishCandlePattern() { // الحصول على بيانات الشموع MqlRates rates[]; ArraySetAsSeries(rates, true); if(CopyRates(_Symbol, PERIOD_M5, 0, 3, rates) <= 0) return false; // التحقق من نمط الابتلاع الصاعد bool bullishEngulfing = (rates[1].close < rates[1].open) && // شمعة هابطة سابقة (rates[0].close > rates[0].open) && // شمعة صاعدة حالية (rates[0].open < rates[1].close) && // فتح الشمعة الحالية أقل من إغلاق السابقة (rates[0].close > rates[1].open); // إغلاق الشمعة الحالية أعلى من فتح السابقة // التحقق من نمط المطرقة double bodySize = MathAbs(rates[0].close - rates[0].open); double lowerWick = MathMin(rates[0].open, rates[0].close) - rates[0].low; double upperWick = rates[0].high - MathMax(rates[0].open, rates[0].close); bool hammer = (lowerWick > 2 * bodySize) && (upperWick < 0.2 * bodySize) && (rates[0].close > rates[0].open); // تم تبسيط الشرط - نقبل أي شمعة صاعدة bool bullishCandle = (rates[0].close > rates[0].open); return bullishEngulfing || hammer || bullishCandle; } //+------------------------------------------------------------------+ //| التحقق من نمط الشموع اليابانية الهابط | //+------------------------------------------------------------------+ bool CheckBearishCandlePattern() { // الحصول على بيانات الشموع MqlRates rates[]; ArraySetAsSeries(rates, true); if(CopyRates(_Symbol, PERIOD_M5, 0, 3, rates) <= 0) return false; // التحقق من نمط الابتلاع الهابط bool bearishEngulfing = (rates[1].close > rates[1].open) && // شمعة صاعدة سابقة (rates[0].close < rates[0].open) && // شمعة هابطة حالية (rates[0].open > rates[1].close) && // فتح الشمعة الحالية أعلى من إغلاق السابقة (rates[0].close < rates[1].open); // إغلاق الشمعة الحالية أقل من فتح السابقة // التحقق من نمط النجمة الساقطة double bodySize = MathAbs(rates[0].close - rates[0].open); double upperWick = rates[0].high - MathMax(rates[0].open, rates[0].close); double lowerWick = MathMin(rates[0].open, rates[0].close) - rates[0].low; bool shootingStar = (upperWick > 2 * bodySize) && (lowerWick < 0.2 * bodySize) && (rates[0].close < rates[0].open); // تم تبسيط الشرط - نقبل أي شمعة هابطة bool bearishCandle = (rates[0].close < rates[0].open); return bearishEngulfing || shootingStar || bearishCandle; } //+------------------------------------------------------------------+ //| التحقق من السماح بالتداول | //+------------------------------------------------------------------+ bool IsTradeAllowed() { // التحقق من الحد الأقصى للصفقات اليومية if(dailyTradeCount >= MaxDailyTrades) { return false; } // التحقق من السبريد (استخدام السبريد الفعلي) double currentSpread = GetEffectiveSpread(); if(currentSpread > MaxSpread) { return false; } // التحقق من الوقت المنقضي منذ آخر صفقة if(TimeCurrent() - lastTradeTime < MinutesBetweenTrades * 60) { return false; } // التحقق من ساعات التداول المثلى if(TradeOnlyDuringOptimalHours) { datetime currentTime = TimeCurrent(); MqlDateTime timeStruct; TimeToStruct(currentTime, timeStruct); if(timeStruct.hour < StartHour || timeStruct.hour >= EndHour) { // خارج ساعات التداول المثلى return false; } } // التحقق من الأخبار (يمكن تنفيذه باستخدام مكتبة خارجية أو خدمة أخبار) if(AvoidNews && IsNewsTime()) { return false; } return true; } //+------------------------------------------------------------------+ //| التحقق من وقت الأخبار | //+------------------------------------------------------------------+ bool IsNewsTime() { // هذه الدالة تحتاج إلى تنفيذ خاص بناءً على مصدر بيانات الأخبار // يمكن استخدام مكتبة خارجية أو خدمة أخبار // للتبسيط، نفترض أنه لا توجد أخبار حالياً return false; } //+------------------------------------------------------------------+ //| التحقق من يوم جديد | //+------------------------------------------------------------------+ bool IsNewDay() { static datetime lastDay = 0; datetime currentTime = TimeCurrent(); MqlDateTime timeStruct; TimeToStruct(currentTime, timeStruct); // إنشاء تاريخ اليوم فقط (بدون وقت) datetime currentDay = StringToTime(StringFormat("%04d.%02d.%02d", timeStruct.year, timeStruct.mon, timeStruct.day)); if(currentDay > lastDay) { lastDay = currentDay; return true; } return false; } //+------------------------------------------------------------------+ //| تهيئة متغيرات التاريخ | //+------------------------------------------------------------------+ void InitializeDateVariables() { datetime currentTime = TimeCurrent(); MqlDateTime timeStruct; TimeToStruct(currentTime, timeStruct); // بداية اليوم timeStruct.hour = 0; timeStruct.min = 0; timeStruct.sec = 0; startOfDay = StructToTime(timeStruct); // بداية الأسبوع (الأحد) int daysSinceWeekStart = timeStruct.day_of_week; startOfWeek = startOfDay - (daysSinceWeekStart * 24 * 3600); // بداية الشهر timeStruct.day = 1; startOfMonth = StructToTime(timeStruct); } //+------------------------------------------------------------------+ //| تحديث الإحصائيات | //+------------------------------------------------------------------+ void UpdateStatistics() { dailyProfit = 0.0; weeklyProfit = 0.0; monthlyProfit = 0.0; totalProfit = 0.0; totalTrades = 0; winTrades = 0; lossTrades = 0; // مراجعة جميع الصفقات في تاريخ الحساب if(HistorySelect(0, TimeCurrent())) { int totalDeals = HistoryDealsTotal(); for(int i = 0; i < totalDeals; i++) { ulong dealTicket = HistoryDealGetTicket(i); if(dealTicket > 0) { string dealSymbol = HistoryDealGetString(dealTicket, DEAL_SYMBOL); long dealMagic = HistoryDealGetInteger(dealTicket, DEAL_MAGIC); long dealType = HistoryDealGetInteger(dealTicket, DEAL_TYPE); datetime dealTime = (datetime)HistoryDealGetInteger(dealTicket, DEAL_TIME); double dealProfit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT); double dealSwap = HistoryDealGetDouble(dealTicket, DEAL_SWAP); double dealCommission = HistoryDealGetDouble(dealTicket, DEAL_COMMISSION); // التحقق من أن الصفقة تخص رمزنا ورقمنا السحري if(dealSymbol == _Symbol && dealMagic == MagicNumber) { // حساب الربح الإجمالي double totalDealProfit = dealProfit + dealSwap + dealCommission; // إضافة إلى الربح الإجمالي totalProfit += totalDealProfit; // التحقق من النوع (إغلاق صفقة فقط) if(dealType == DEAL_TYPE_BUY || dealType == DEAL_TYPE_SELL) { totalTrades++; if(totalDealProfit > 0) winTrades++; else if(totalDealProfit < 0) lossTrades++; // حساب الأرباح حسب الفترة الزمنية if(dealTime >= startOfDay) dailyProfit += totalDealProfit; if(dealTime >= startOfWeek) weeklyProfit += totalDealProfit; if(dealTime >= startOfMonth) monthlyProfit += totalDealProfit; } } } } } // حساب معدل النجاح if(totalTrades > 0) winRate = (double)winTrades / totalTrades * 100.0; else winRate = 0.0; } // ===== دوال لوحة المعلومات ===== //+------------------------------------------------------------------+ //| تحديث أبعاد اللوحة للعناصر الجديدة | //+------------------------------------------------------------------+ void CreateDashboard() { // حذف اللوحة السابقة إن وجدت DeleteDashboard(); // إنشاء صورة الخلفية إذا كانت مفعلة if(ShowBackgroundImage) { CreateBackgroundImage(); CreateImageOverlay(); CreateImageFrame(); } // إنشاء الخلفية الرئيسية مع زيادة الارتفاع للعناصر الجديدة if(!ObjectCreate(0, "Dashboard_Background", OBJ_RECTANGLE_LABEL, 0, 0, 0)) { Print("فشل في إنشاء خلفية اللوحة"); return; } // إعداد خصائص الخلفية مع شفافية وارتفاع أكبر ObjectSetInteger(0, "Dashboard_Background", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_XDISTANCE, DashboardXOffset); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_YDISTANCE, DashboardYOffset); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_XSIZE, 280); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_YSIZE, 420); // زيادة الارتفاع للعناصر الجديدة ObjectSetInteger(0, "Dashboard_Background", OBJPROP_COLOR, clrBlack); // إضافة شفافية للخلفية لإظهار صورة الخلفية color bgColor = ShowBackgroundImage ? C'10,10,10' : C'20,20,20'; ObjectSetInteger(0, "Dashboard_Background", OBJPROP_BGCOLOR, bgColor); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_WIDTH, 2); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_SELECTED, false); ObjectSetInteger(0, "Dashboard_Background", OBJPROP_HIDDEN, true); // إنشاء الحدود الذهبية CreateDashboardBorder(); // إنشاء العنوان CreateDashboardTitle(); // إنشاء عناصر البيانات CreateDashboardElements(); } //+------------------------------------------------------------------+ //| إنشاء صورة الخلفية | //+------------------------------------------------------------------+ void CreateBackgroundImage() { // إنشاء كائن الصورة if(!ObjectCreate(0, "Dashboard_Background_Image", OBJ_BITMAP_LABEL, 0, 0, 0)) { Print("تحذير: فشل في إنشاء صورة الخلفية. تأكد من وجود الصورة في مجلد MQL5/Files"); return; } // إعداد خصائص الصورة ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_XDISTANCE, DashboardXOffset + 5); ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_YDISTANCE, DashboardYOffset + 5); // تحديد مسار الصورة ObjectSetString(0, "Dashboard_Background_Image", OBJPROP_BMPFILE, "gold_scalping_bg.bmp"); // Use local file // إعدادات إضافية للصورة ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_XSIZE, 270); ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_YSIZE, 350); // زيادة الارتفاع ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_BACK, true); // في الخلفية ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_SELECTED, false); ObjectSetInteger(0, "Dashboard_Background_Image", OBJPROP_HIDDEN, true); // Print("تم إنشاء صورة الخلفية بنجاح: ", BackgroundImagePath); // Removed as BackgroundImagePath is no longer used } //+------------------------------------------------------------------+ //| إنشاء طبقة شفافية فوق الصورة | //+------------------------------------------------------------------+ void CreateImageOverlay() { // إنشاء طبقة شفافية فوق الصورة لتحسين وضوح النص if(!ObjectCreate(0, "Dashboard_Image_Overlay", OBJ_RECTANGLE_LABEL, 0, 0, 0)) return; ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_XDISTANCE, DashboardXOffset + 5); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_YDISTANCE, DashboardYOffset + 5); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_XSIZE, 270); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_YSIZE, 350); // زيادة الارتفاع // حساب لون الطبقة بناءً على مستوى الشفافية int alphaValue = 255 - (BackgroundOpacity * 255 / 100); color overlayColor = ColorToARGB(clrBlack, alphaValue); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_BGCOLOR, overlayColor); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Image_Overlay", OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| تحويل اللون مع الشفافية | //+------------------------------------------------------------------+ color ColorToARGB(color clr, int alpha) { int r = (clr >> 16) & 0xFF; int g = (clr >> 8) & 0xFF; int b = clr & 0xFF; return (alpha << 24) | (r << 16) | (g << 8) | b; } //+------------------------------------------------------------------+ //| إنشاء إطار مزخرف حول صورة الخلفية | //+------------------------------------------------------------------+ void CreateImageFrame() { if(!ShowBackgroundImage) return; // إطار داخلي ذهبي رفيع ObjectCreate(0, "Dashboard_Image_Frame_Inner", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_XDISTANCE, DashboardXOffset + 3); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_YDISTANCE, DashboardYOffset + 3); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_XSIZE, 274); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_YSIZE, 354); // زيادة الارتفاع ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_COLOR, clrGold); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_BGCOLOR, clrNONE); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_WIDTH, 1); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Image_Frame_Inner", OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| إنشاء الحدود الذهبية | //+------------------------------------------------------------------+ void CreateDashboardBorder() { // الحد العلوي ObjectCreate(0, "Dashboard_Border_Top", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_XDISTANCE, DashboardXOffset); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_YDISTANCE, DashboardYOffset); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_XSIZE, 280); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_YSIZE, 3); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_BGCOLOR, clrGold); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Border_Top", OBJPROP_HIDDEN, true); // الحد السفلي ObjectCreate(0, "Dashboard_Border_Bottom", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_XDISTANCE, DashboardXOffset); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_YDISTANCE, DashboardYOffset + 417); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_XSIZE, 280); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_YSIZE, 3); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_BGCOLOR, clrGold); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Border_Bottom", OBJPROP_HIDDEN, true); // الحد الأيسر ObjectCreate(0, "Dashboard_Border_Left", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_XDISTANCE, DashboardXOffset); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_YDISTANCE, DashboardYOffset); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_XSIZE, 3); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_YSIZE, 420); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_BGCOLOR, clrGold); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Border_Left", OBJPROP_HIDDEN, true); // الحد الأيمن ObjectCreate(0, "Dashboard_Border_Right", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_XDISTANCE, DashboardXOffset + 277); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_YDISTANCE, DashboardYOffset); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_XSIZE, 3); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_YSIZE, 420); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_BGCOLOR, clrGold); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Border_Right", OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| إنشاء عنوان اللوحة | //+------------------------------------------------------------------+ void CreateDashboardTitle() { // خلفية العنوان - أكثر شفافية إذا كانت الصورة مفعلة ObjectCreate(0, "Dashboard_Title_BG", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_XDISTANCE, DashboardXOffset + 3); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_YDISTANCE, DashboardYOffset + 3); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_XSIZE, 274); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_YSIZE, 35); // تقليل كثافة خلفية العنوان إذا كانت الصورة مفعلة color titleBgColor = ShowBackgroundImage ? C'20,15,5' : C'40,30,10'; ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_BGCOLOR, titleBgColor); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Title_BG", OBJPROP_HIDDEN, true); // نص العنوان - عرض اسم الإكسبيرت مع حالة الباك تيست string titleText = "⚡ " + ExpertName + " ⚡"; if(isBacktesting && ShowBacktestInfo) titleText += " [BT]"; ObjectCreate(0, "Dashboard_Title", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_XDISTANCE, DashboardXOffset + 140); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_YDISTANCE, DashboardYOffset + 12); ObjectSetString(0, "Dashboard_Title", OBJPROP_TEXT, titleText); ObjectSetString(0, "Dashboard_Title", OBJPROP_FONT, "Arial Black"); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_FONTSIZE, ShowBackgroundImage ? 15 : 14); // حجم أكبر مع الصورة ObjectSetInteger(0, "Dashboard_Title", OBJPROP_COLOR, clrGold); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Title", OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| إنشاء عناصر البيانات - الحل النهائي للمحاذاة | //+------------------------------------------------------------------+ void CreateDashboardElements() { int yPos = DashboardYOffset + 50; int lineHeight = 20; int labelX = DashboardXOffset + 15; // موضع التسميات int valueX = DashboardXOffset + 265; // تقليل أكثر بكثير // الوقت والتوقيت CreateDashboardLabel("Server_Time_Label", "🕐 Server Time:", yPos, clrLightGray, labelX); CreateDashboardValue("Server_Time_Value", "00:00:00", yPos, clrCyan, valueX); yPos += lineHeight; CreateDashboardLabel("Timeframe_Label", "📊 Timeframe:", yPos, clrLightGray, labelX); CreateDashboardValue("Timeframe_Value", GetCurrentTimeframeName(), yPos, clrAqua, valueX); yPos += lineHeight; CreateDashboardLabel("Candle_Timer_Label", "⏰ Next Candle:", yPos, clrLightGray, labelX); CreateDashboardValue("Candle_Timer_Value", "00:00", yPos, clrYellow, valueX); yPos += lineHeight + 5; // خط فاصل CreateDashboardSeparator(yPos); yPos += 15; // الأرباح CreateDashboardLabel("Daily_Profit_Label", "📅 Daily Profit:", yPos, clrLightGray, labelX); CreateDashboardValue("Daily_Profit_Value", "$0.00", yPos, clrLime, valueX); yPos += lineHeight; CreateDashboardLabel("Weekly_Profit_Label", "📊 Weekly Profit:", yPos, clrLightGray, labelX); CreateDashboardValue("Weekly_Profit_Value", "$0.00", yPos, clrLime, valueX); yPos += lineHeight; CreateDashboardLabel("Monthly_Profit_Label", "📈 Monthly Profit:", yPos, clrLightGray, labelX); CreateDashboardValue("Monthly_Profit_Value", "$0.00", yPos, clrLime, valueX); yPos += lineHeight; CreateDashboardLabel("Total_Profit_Label", "💰 Total Profit:", yPos, clrLightGray, labelX); CreateDashboardValue("Total_Profit_Value", "$0.00", yPos, clrGold, valueX); yPos += lineHeight + 5; // خط فاصل CreateDashboardSeparator(yPos); yPos += 15; // الصفقات CreateDashboardLabel("Total_Trades_Label", "🔢 Total Trades:", yPos, clrLightGray, labelX); CreateDashboardValue("Total_Trades_Value", "0", yPos, clrWhite, valueX); yPos += lineHeight; CreateDashboardLabel("Win_Trades_Label", "✅ Win Trades:", yPos, clrLightGray, labelX); CreateDashboardValue("Win_Trades_Value", "0", yPos, clrLime, valueX); yPos += lineHeight; CreateDashboardLabel("Loss_Trades_Label", "❌ Loss Trades:", yPos, clrLightGray, labelX); CreateDashboardValue("Loss_Trades_Value", "0", yPos, clrRed, valueX); yPos += lineHeight; CreateDashboardLabel("Win_Rate_Label", "📊 Win Rate:", yPos, clrLightGray, labelX); CreateDashboardValue("Win_Rate_Value", "0%", yPos, clrGold, valueX); yPos += lineHeight + 5; // خط فاصل CreateDashboardSeparator(yPos); yPos += 15; // معلومات السوق CreateDashboardLabel("Spread_Label", "📡 Spread:", yPos, clrLightGray, labelX); CreateDashboardValue("Spread_Value", "0", yPos, clrAqua, valueX); yPos += lineHeight; CreateDashboardLabel("Daily_Trades_Label", "📅 Today Trades:", yPos, clrLightGray, labelX); CreateDashboardValue("Daily_Trades_Value", "0", yPos, clrWhite, valueX); yPos += lineHeight; CreateDashboardLabel("Account_Balance_Label", "💳 Balance:", yPos, clrLightGray, labelX); CreateDashboardValue("Account_Balance_Value", "$0.00", yPos, clrYellow, valueX); yPos += lineHeight; CreateDashboardLabel("Magic_Number_Label", "🔮 Magic:", yPos, clrLightGray, labelX); CreateDashboardValue("Magic_Number_Value", IntegerToString(MagicNumber), yPos, clrCyan, valueX); yPos += lineHeight; // معلومات الباك تيست (إذا كانت مفعلة) if(isBacktesting && ShowBacktestInfo) { yPos += 5; CreateDashboardSeparator(yPos); yPos += 15; CreateDashboardLabel("Backtest_Mode_Label", "🔬 Backtest Mode:", yPos, clrLightGray, labelX); CreateDashboardValue("Backtest_Mode_Value", "ACTIVE", yPos, clrOrange, valueX); yPos += lineHeight; if(UseBacktestSpread) { CreateDashboardLabel("BT_Spread_Label", "📊 BT Spread:", yPos, clrLightGray, labelX); CreateDashboardValue("BT_Spread_Value", IntegerToString(BacktestSpreadPoints) + "pts", yPos, clrYellow, valueX); yPos += lineHeight; CreateDashboardLabel("BT_Slippage_Label", "⚡ BT Slippage:", yPos, clrLightGray, labelX); CreateDashboardValue("BT_Slippage_Value", IntegerToString(BacktestSlippage) + "pts", yPos, clrMagenta, valueX); } } } //+------------------------------------------------------------------+ //| إنشاء تسمية مُحسنة | //+------------------------------------------------------------------+ void CreateDashboardLabel(string name, string text, int yPos, color clr, int xPos) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xPos); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yPos); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetString(0, name, OBJPROP_FONT, "Tahoma"); // خط مضغوط ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10); // حجم أكبر قليلاً color textColor = ShowBackgroundImage ? clrWhite : clr; ObjectSetInteger(0, name, OBJPROP_COLOR, textColor); ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT); ObjectSetInteger(0, name, OBJPROP_BACK, false); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| إنشاء قيمة مع أقصى ضمان عدم الخروج | //+------------------------------------------------------------------+ void CreateDashboardValue(string name, string text, int yPos, color clr, int xPos) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xPos); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yPos); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetString(0, name, OBJPROP_FONT, "Tahoma"); // خط أكثر ضغطاً ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10); // حجم أكبر قليلاً color valueColor = ShowBackgroundImage ? clr : clr; if(ShowBackgroundImage && clr == clrLightGray) valueColor = clrWhite; ObjectSetInteger(0, name, OBJPROP_COLOR, valueColor); ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT); ObjectSetInteger(0, name, OBJPROP_BACK, false); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| إنشاء خط فاصل | //+------------------------------------------------------------------+ void CreateDashboardSeparator(int yPos) { ObjectCreate(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_CORNER, DashboardCorner); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_XDISTANCE, DashboardXOffset + 15); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_YDISTANCE, yPos); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_XSIZE, 250); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_YSIZE, 1); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_BGCOLOR, C'100,100,100'); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_BACK, false); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "Dashboard_Separator_" + IntegerToString(yPos), OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| تحديث لوحة النتائج المُحسنة | //+------------------------------------------------------------------+ void UpdateDashboard() { // تحديث الوقت والتوقيت ObjectSetString(0, "Server_Time_Value", OBJPROP_TEXT, GetServerTime()); ObjectSetString(0, "Timeframe_Value", OBJPROP_TEXT, GetCurrentTimeframeName()); ObjectSetString(0, "Candle_Timer_Value", OBJPROP_TEXT, GetCandleTimeRemaining()); // تلوين عداد الشمعة حسب الوقت المتبقي string timeRemaining = GetCandleTimeRemaining(); string timeParts[]; int splitResult = StringSplit(timeRemaining, ':', timeParts); if(splitResult >= 2) { int minutes = (int)StringToInteger(timeParts[0]); int seconds = (int)StringToInteger(timeParts[1]); int totalSeconds = minutes * 60 + seconds; // تلوين حسب الوقت المتبقي if(totalSeconds <= 30) ObjectSetInteger(0, "Candle_Timer_Value", OBJPROP_COLOR, clrRed); else if(totalSeconds <= 60) ObjectSetInteger(0, "Candle_Timer_Value", OBJPROP_COLOR, clrOrange); else ObjectSetInteger(0, "Candle_Timer_Value", OBJPROP_COLOR, clrYellow); } // تحديث الأرباح ObjectSetString(0, "Daily_Profit_Value", OBJPROP_TEXT, "$" + DoubleToString(dailyProfit, 2)); ObjectSetString(0, "Weekly_Profit_Value", OBJPROP_TEXT, "$" + DoubleToString(weeklyProfit, 2)); ObjectSetString(0, "Monthly_Profit_Value", OBJPROP_TEXT, "$" + DoubleToString(monthlyProfit, 2)); ObjectSetString(0, "Total_Profit_Value", OBJPROP_TEXT, "$" + DoubleToString(totalProfit, 2)); // تحديث ألوان الأرباح ObjectSetInteger(0, "Daily_Profit_Value", OBJPROP_COLOR, dailyProfit >= 0 ? clrLime : clrRed); ObjectSetInteger(0, "Weekly_Profit_Value", OBJPROP_COLOR, weeklyProfit >= 0 ? clrLime : clrRed); ObjectSetInteger(0, "Monthly_Profit_Value", OBJPROP_COLOR, monthlyProfit >= 0 ? clrLime : clrRed); ObjectSetInteger(0, "Total_Profit_Value", OBJPROP_COLOR, totalProfit >= 0 ? clrGold : clrRed); // تحديث الصفقات ObjectSetString(0, "Total_Trades_Value", OBJPROP_TEXT, IntegerToString(totalTrades)); ObjectSetString(0, "Win_Trades_Value", OBJPROP_TEXT, IntegerToString(winTrades)); ObjectSetString(0, "Loss_Trades_Value", OBJPROP_TEXT, IntegerToString(lossTrades)); ObjectSetString(0, "Win_Rate_Value", OBJPROP_TEXT, DoubleToString(winRate, 1) + "%"); // تحديث معلومات السوق double currentSpread = GetEffectiveSpread(); ObjectSetString(0, "Spread_Value", OBJPROP_TEXT, DoubleToString(currentSpread, 0)); // إضافة تمييز بصري لسبريد الباك تيست if(isBacktesting && UseBacktestSpread) ObjectSetString(0, "Spread_Value", OBJPROP_TEXT, DoubleToString(currentSpread, 0) + " [BT]"); ObjectSetString(0, "Daily_Trades_Value", OBJPROP_TEXT, IntegerToString(dailyTradeCount)); double balance = AccountInfoDouble(ACCOUNT_BALANCE); ObjectSetString(0, "Account_Balance_Value", OBJPROP_TEXT, "$" + DoubleToString(balance, 2)); // تلوين السبريد if(currentSpread <= MaxSpread / 2) ObjectSetInteger(0, "Spread_Value", OBJPROP_COLOR, clrLime); else if(currentSpread <= MaxSpread) ObjectSetInteger(0, "Spread_Value", OBJPROP_COLOR, clrYellow); else ObjectSetInteger(0, "Spread_Value", OBJPROP_COLOR, clrRed); } //+------------------------------------------------------------------+ //| حذف لوحة النتائج المُحسنة (إضافة العناصر الجديدة للحذف) | //+------------------------------------------------------------------+ void DeleteDashboard() { // حذف صورة الخلفية والطبقة الشفافة والإطار ObjectDelete(0, "Dashboard_Background_Image"); ObjectDelete(0, "Dashboard_Image_Overlay"); ObjectDelete(0, "Dashboard_Image_Frame_Inner"); // حذف جميع الكائنات المتعلقة باللوحة ObjectDelete(0, "Dashboard_Background"); ObjectDelete(0, "Dashboard_Border_Top"); ObjectDelete(0, "Dashboard_Border_Bottom"); ObjectDelete(0, "Dashboard_Border_Left"); ObjectDelete(0, "Dashboard_Border_Right"); ObjectDelete(0, "Dashboard_Title_BG"); ObjectDelete(0, "Dashboard_Title"); // حذف عناصر الوقت والتوقيت الجديدة ObjectDelete(0, "Server_Time_Label"); ObjectDelete(0, "Server_Time_Value"); ObjectDelete(0, "Timeframe_Label"); ObjectDelete(0, "Timeframe_Value"); ObjectDelete(0, "Candle_Timer_Label"); ObjectDelete(0, "Candle_Timer_Value"); // حذف التسميات والقيم ObjectDelete(0, "Daily_Profit_Label"); ObjectDelete(0, "Daily_Profit_Value"); ObjectDelete(0, "Weekly_Profit_Label"); ObjectDelete(0, "Weekly_Profit_Value"); ObjectDelete(0, "Monthly_Profit_Label"); ObjectDelete(0, "Monthly_Profit_Value"); ObjectDelete(0, "Total_Profit_Label"); ObjectDelete(0, "Total_Profit_Value"); ObjectDelete(0, "Total_Trades_Label"); ObjectDelete(0, "Total_Trades_Value"); ObjectDelete(0, "Win_Trades_Label"); ObjectDelete(0, "Win_Trades_Value"); ObjectDelete(0, "Loss_Trades_Label"); ObjectDelete(0, "Loss_Trades_Value"); ObjectDelete(0, "Win_Rate_Label"); ObjectDelete(0, "Win_Rate_Value"); ObjectDelete(0, "Spread_Label"); ObjectDelete(0, "Spread_Value"); ObjectDelete(0, "Daily_Trades_Label"); ObjectDelete(0, "Daily_Trades_Value"); ObjectDelete(0, "Account_Balance_Label"); ObjectDelete(0, "Account_Balance_Value"); ObjectDelete(0, "Magic_Number_Label"); ObjectDelete(0, "Magic_Number_Value"); // حذف عناصر الباك تيست ObjectDelete(0, "Backtest_Mode_Label"); ObjectDelete(0, "Backtest_Mode_Value"); ObjectDelete(0, "BT_Spread_Label"); ObjectDelete(0, "BT_Spread_Value"); ObjectDelete(0, "BT_Slippage_Label"); ObjectDelete(0, "BT_Slippage_Value"); // حذف الخطوط الفاصلة for(int i = 0; i < 25; i++) { ObjectDelete(0, "Dashboard_Separator_" + IntegerToString(DashboardYOffset + 50 + (i * 25))); ObjectDelete(0, "Dashboard_Separator_" + IntegerToString(DashboardYOffset + 115 + (i * 25))); ObjectDelete(0, "Dashboard_Separator_" + IntegerToString(DashboardYOffset + 200 + (i * 25))); ObjectDelete(0, "Dashboard_Separator_" + IntegerToString(DashboardYOffset + 285 + (i * 25))); ObjectDelete(0, "Dashboard_Separator_" + IntegerToString(DashboardYOffset + 320 + (i * 25))); } } //+------------------------------------------------------------------+ //| حساب الوقت المتبقي لانتهاء الشمعة الحالية (ديناميكي) | //+------------------------------------------------------------------+ string GetCandleTimeRemaining() { datetime currentTime = TimeCurrent(); ENUM_TIMEFRAMES currentTimeframe = Period(); // الحصول على وقت بداية الشمعة الحالية datetime currentCandleTime = iTime(_Symbol, currentTimeframe, 0); // حساب مدة الإطار الزمني بالثواني int timeframeDuration = PeriodSeconds(currentTimeframe); // حساب وقت انتهاء الشمعة datetime candleEndTime = currentCandleTime + timeframeDuration; // حساب الوقت المتبقي بالثواني int remainingSeconds = (int)(candleEndTime - currentTime); // التأكد من أن الوقت المتبقي ليس سالباً if(remainingSeconds < 0) remainingSeconds = 0; // تحويل الثواني إلى تنسيق مناسب int minutes = remainingSeconds / 60; int seconds = remainingSeconds % 60; return StringFormat("%02d:%02d", minutes, seconds); } //+------------------------------------------------------------------+ //| الحصول على الوقت الحالي للسيرفر مُنسق | //+------------------------------------------------------------------+ string GetServerTime() { datetime serverTime = TimeCurrent(); MqlDateTime timeStruct; TimeToStruct(serverTime, timeStruct); return StringFormat("%02d:%02d:%02d", timeStruct.hour, timeStruct.min, timeStruct.sec); } //+------------------------------------------------------------------+ //| الحصول على اسم الإطار الزمني الحالي | //+------------------------------------------------------------------+ string GetCurrentTimeframeName() { ENUM_TIMEFRAMES tf = Period(); switch(tf) { case PERIOD_M1: return "M1"; case PERIOD_M2: return "M2"; case PERIOD_M3: return "M3"; case PERIOD_M4: return "M4"; case PERIOD_M5: return "M5"; case PERIOD_M6: return "M6"; case PERIOD_M10: return "M10"; case PERIOD_M12: return "M12"; case PERIOD_M15: return "M15"; case PERIOD_M20: return "M20"; case PERIOD_M30: return "M30"; case PERIOD_H1: return "H1"; case PERIOD_H2: return "H2"; case PERIOD_H3: return "H3"; case PERIOD_H4: return "H4"; case PERIOD_H6: return "H6"; case PERIOD_H8: return "H8"; case PERIOD_H12: return "H12"; case PERIOD_D1: return "D1"; case PERIOD_W1: return "W1"; case PERIOD_MN1: return "MN1"; default: return "Unknown"; } } //+------------------------------------------------------------------+