//+------------------------------------------------------------------+ //| Expert Advisor: CCI Channel EA (مع Debug مفصل) | //| Description: نفس الـ EA السابق مع إضافات Print debugging مفصّلة | //| لتتبع قيم المؤشر، أسباب رفض/فتح الصفقات، وحساب حجم اللوت خطوةً بخطوة.| //+------------------------------------------------------------------+ #property copyright "Generated by Copilot" #property version "1.02" #property strict #include input int InpCCIPeriod = 20; // فترة مؤشر CCI input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_TYPICAL; // نوع السعر المستخدم لمؤشر CCI input double InpUpperLevel = 100.0; // مستوى التشبع الشرائي (Overbought) input double InpLowerLevel = -100.0; // مستوى التشبع البيعي (Oversold) input double InpFixedLot = 0.01; // حجم اللوت الثابت (إذا لم تستخدم مخاطرة نسبة) input bool InpUseRiskPercent = false; // هل استخدام نسبة مخاطرة لحساب اللوت؟ input double InpRiskPercent = 1.0; // نسبة المخاطرة من الرصيد لكل صفقة (إن اخترت استخدام النسبة) input int InpStopLossPoints = 200; // وقف الخسارة (نقطة) مثال: 200 input int InpTakeProfitPoints= 400; // جني الأرباح (نقطة) input int InpMaxSpreadPoints = 50; // أقصى سبريد (بـ Points) مسموح به لفتح الصفقات input ulong InpMagicNumber = 20251201; // رقم سحري للتعرف على الصفقات input bool InpAllowBuy = true; // تمكين الصفقات الشرائية input bool InpAllowSell = true; // تمكين الصفقات البيعية input bool InpCloseOppositeOnSignal = false; // إغلاق الصفقة المعاكسة عند وجود إشارة (false = لا تغلق) input bool InpEnableTrailing = false; // تفعيل التريلينج ستوب input int InpTrailingStart = 200; // تريلينج يبدأ بعد (نقطة) input int InpTrailingStep = 50; // خطوة التريلينج (نقطة) /* ---------- إعدادات ساعات التداول ---------- */ input bool InpEnableTimeFilter = false; // تفعيل فلترة الساعات input bool InpTradeSunday = false; input bool InpTradeMonday = true; input bool InpTradeTuesday = true; input bool InpTradeWednesday = true; input bool InpTradeThursday = true; input bool InpTradeFriday = true; input bool InpTradeSaturday = false; input int InpTradeStartHour = 8; input int InpTradeStartMinute = 0; input int InpTradeEndHour = 17; input int InpTradeEndMinute = 0; /* ------------------------------------------- */ /* ---------- Debugging toggle ---------- */ input bool InpEnableDebug = true; // تفعيل/تعطيل الطباعة التفصيلية في Journal /* ------------------------------------- */ CTrade trade; int cci_handle = INVALID_HANDLE; datetime last_bar_time = 0; //+------------------------------------------------------------------+ //| Normalize lot to broker limits | //+------------------------------------------------------------------+ double NormalizeLot(double lot) { double min_lot=0, max_lot=0, step=0; if(!SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN, min_lot)) min_lot = 0.01; if(!SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX, max_lot)) max_lot = 100.0; if(!SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP, step)) step = 0.01; if(step <= 0) step = 0.01; double steps = MathRound(lot/step); double res = steps * step; if(res < min_lot) res = min_lot; if(res > max_lot) res = max_lot; double final = MathRound(res/step)*step; if(InpEnableDebug) PrintFormat("NormalizeLot: requested=%.8f -> normalized=%.8f (min=%.8f max=%.8f step=%.8f)", lot, final, min_lot, max_lot, step); return(final); } //+------------------------------------------------------------------+ //| تحقق من إذا الوقت الحالي داخل نافذة التداول المسموح بها | //+------------------------------------------------------------------+ bool IsTradingAllowed() { if(!InpEnableTimeFilter) return true; datetime now = TimeCurrent(); int dow = TimeDayOfWeek(now); // 0=Sunday .. 6=Saturday bool allowedDays[7]; allowedDays[0] = InpTradeSunday; allowedDays[1] = InpTradeMonday; allowedDays[2] = InpTradeTuesday; allowedDays[3] = InpTradeWednesday; allowedDays[4] = InpTradeThursday; allowedDays[5] = InpTradeFriday; allowedDays[6] = InpTradeSaturday; if(!allowedDays[dow]) { if(InpEnableDebug) PrintFormat("IsTradingAllowed: current day (%d) is not allowed", dow); return false; } int curHour = TimeHour(now); int curMin = TimeMinute(now); int curTotal = curHour*60 + curMin; int startTotal = InpTradeStartHour*60 + InpTradeStartMinute; int endTotal = InpTradeEndHour*60 + InpTradeEndMinute; if(startTotal <= endTotal) { if(curTotal < startTotal || curTotal > endTotal) { if(InpEnableDebug) PrintFormat("IsTradingAllowed: outside time window (%02d:%02d not in %02d:%02d - %02d:%02d)", curHour, curMin, InpTradeStartHour, InpTradeStartMinute, InpTradeEndHour, InpTradeEndMinute); return false; } } else { if(curTotal < startTotal && curTotal > endTotal) { if(InpEnableDebug) PrintFormat("IsTradingAllowed: outside overnight window (%02d:%02d)", curHour, curMin); return false; } } return true; } //+------------------------------------------------------------------+ //| Initialize | //+------------------------------------------------------------------+ int OnInit() { cci_handle = iCCI(Symbol(), Period(), InpCCIPeriod, InpAppliedPrice); if(cci_handle == INVALID_HANDLE) { Print("خطأ: تعذّر إنشاء مؤشر CCI"); return(INIT_FAILED); } last_bar_time = 0; if(InpEnableDebug) { PrintFormat("OnInit: Symbol=%s Period=%s InpCCIPeriod=%d InpUpper=%.2f InpLower=%.2f TimeFilter=%s", Symbol(), EnumToString(Period()), InpCCIPeriod, InpUpperLevel, InpLowerLevel, InpEnableTimeFilter ? "ON":"OFF"); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Deinit | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(cci_handle != INVALID_HANDLE) { IndicatorRelease(cci_handle); cci_handle = INVALID_HANDLE; } if(InpEnableDebug) PrintFormat("OnDeinit: reason=%d", reason); } //+------------------------------------------------------------------+ //| Main tick | //+------------------------------------------------------------------+ void OnTick() { datetime current_closed_time = (datetime) iTime(Symbol(), Period(), 1); if(current_closed_time == 0) return; if(current_closed_time == last_bar_time) return; last_bar_time = current_closed_time; // Print basic tick/time info if(InpEnableDebug) PrintFormat("OnTick: new closed bar at %s", TimeToString(current_closed_time, TIME_DATE|TIME_MINUTES)); if(!IsTradingAllowed()) { if(InpEnableDebug) Print("خارج نافذة التداول المسموح بها - لا يتم فتح صفقات حاليا."); return; } double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT); if(point <= 0) { if(InpEnableDebug) Print("OnTick: invalid point value"); return; } double spread_points = MathRound((ask - bid)/point); if(InpEnableDebug) PrintFormat("Market: ask=%.5f bid=%.5f spread_points=%.0f", ask, bid, spread_points); if(spread_points > InpMaxSpreadPoints) { if(InpEnableDebug) PrintFormat("تجاوز السبريد الحد المسموح به: %d > %d", (int)spread_points, InpMaxSpreadPoints); return; } double cci_buf[2]; int copied = CopyBuffer(cci_handle, 0, 1, 2, cci_buf); // array[0]=value@1, array[1]=value@2 if(copied != 2) { Print("تعذر نسخ قيم CCI"); return; } double cci_current = cci_buf[0]; double cci_previous= cci_buf[1]; if(InpEnableDebug) PrintFormat("CCI: previous=%.4f current=%.4f (upper=%.2f lower=%.2f)", cci_previous, cci_current, InpUpperLevel, InpLowerLevel); bool buy_signal = false; bool sell_signal = false; if(InpAllowBuy) { if(cci_previous <= InpLowerLevel && cci_current > InpLowerLevel) buy_signal = true; } if(InpAllowSell) { if(cci_previous >= InpUpperLevel && cci_current < InpUpperLevel) sell_signal = true; } if(InpEnableDebug) PrintFormat("Signals: buy=%s sell=%s", buy_signal ? "YES":"no", sell_signal ? "YES":"no"); if(!buy_signal && !sell_signal) return; bool hasPosition = PositionSelect(Symbol()); ulong pos_type = POSITION_TYPE_BUY; double pos_volume = 0.0; if(hasPosition) { pos_type = (ulong) PositionGetInteger(POSITION_TYPE); pos_volume = PositionGetDouble(POSITION_VOLUME); } if(InpEnableDebug) PrintFormat("Position: has=%s type=%d volume=%.2f", hasPosition ? "YES":"no", (int)pos_type, pos_volume); if(buy_signal) { if(hasPosition && pos_type == POSITION_TYPE_BUY) { if(InpEnableDebug) Print("مركز شراء موجود بالفعل، تجاهل إشارة الشراء."); } else { if(hasPosition && pos_type == POSITION_TYPE_SELL && InpCloseOppositeOnSignal) { if(!ClosePositionByType(POSITION_TYPE_SELL)) Print("تعذر إغلاق الصفقة المعاكسة قبل فتح شراء."); } if(!hasPosition || (hasPosition && pos_type != POSITION_TYPE_BUY)) OpenOrder(true, ask, bid, cci_previous, cci_current, spread_points); } } if(sell_signal) { if(hasPosition && pos_type == POSITION_TYPE_SELL) { if(InpEnableDebug) Print("مركز بيعي موجود بالفعل، تجاهل إشارة البيع."); } else { if(hasPosition && pos_type == POSITION_TYPE_BUY && InpCloseOppositeOnSignal) { if(!ClosePositionByType(POSITION_TYPE_BUY)) Print("تعذر إغلاق الصفقة المعاكسة قبل فتح بيع."); } if(!hasPosition || (hasPosition && pos_type != POSITION_TYPE_SELL)) OpenOrder(false, ask, bid, cci_previous, cci_current, spread_points); } } OnTick_ManageTrailing(); // إدارة التريلينج بعد أي قرار } //+------------------------------------------------------------------+ //| فتح أمر شراء/بيع (مع Debug) | //+------------------------------------------------------------------+ void OpenOrder(bool isBuy, double ask, double bid, double cci_prev, double cci_curr, double spread_points) { double sl_price=0, tp_price=0; double price = isBuy ? ask : bid; double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT); if(InpStopLossPoints > 0) { if(isBuy) sl_price = NormalizeDouble(price - InpStopLossPoints * point, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)); else sl_price = NormalizeDouble(price + InpStopLossPoints * point, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)); } if(InpTakeProfitPoints > 0) { if(isBuy) tp_price = NormalizeDouble(price + InpTakeProfitPoints * point, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)); else tp_price = NormalizeDouble(price - InpTakeProfitPoints * point, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)); } double lot = InpFixedLot; double before_norm_lot = lot; double tick_value = 0.0; double account_balance = AccountInfoDouble(ACCOUNT_BALANCE); double risk_amount = 0.0; double loss_per_lot = 0.0; if(InpUseRiskPercent && InpStopLossPoints > 0) { tick_value = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE); if(tick_value <= 0) tick_value = 0.0; risk_amount = account_balance * InpRiskPercent / 100.0; loss_per_lot = InpStopLossPoints * point * tick_value; if(loss_per_lot > 0) lot = risk_amount / loss_per_lot; else lot = InpFixedLot; if(InpEnableDebug) { PrintFormat("Lot calc (risk): balance=%.2f risk%%=%.2f risk_amount=%.2f tick_value=%.8f loss_per_lot=%.8f lot_before_norm=%.8f", account_balance, InpRiskPercent, risk_amount, tick_value, loss_per_lot, lot); } lot = NormalizeLot(lot); } else { lot = NormalizeLot(lot); if(InpEnableDebug) PrintFormat("Lot calc (fixed): requested=%.8f normalized=%.8f", before_norm_lot, lot); } if(lot <= 0) { Print("حجم اللوت غير صالح: ", DoubleToString(lot,8)); return; } trade.SetExpertMagicNumber(InpMagicNumber); trade.SetDeviationInPoints( (int) MathMax(10, InpMaxSpreadPoints) ); if(InpEnableDebug) { PrintFormat("Attempting to open %s: price=%.5f SL=%.5f TP=%.5f lot=%.8f spread_points=%.0f CCI_prev=%.4f CCI_cur=%.4f", isBuy ? "BUY":"SELL", price, sl_price, tp_price, lot, spread_points, cci_prev, cci_curr); } bool result=false; if(isBuy) result = trade.Buy(lot, Symbol(), price, sl_price, tp_price, "CCI_EA_debug"); else result = trade.Sell(lot, Symbol(), price, sl_price, tp_price, "CCI_EA_debug"); int retcode = trade.ResultRetcode(); string comment = trade.ResultComment(); ulong order_ticket = trade.ResultOrder(); if(result) PrintFormat("تم فتح %s بنجاح على %s حجم %.8f SL=%.5f TP=%.5f ticket=%I64u retcode=%d comment=%s", isBuy ? "شراء" : "بيع", Symbol(), lot, sl_price, tp_price, order_ticket, retcode, comment); else PrintFormat("فشل فتح %s: retcode=%d comment=%s", isBuy ? "شراء" : "بيع", retcode, comment); } //+------------------------------------------------------------------+ //| إغلاق الصفقة حسب النوع | //+------------------------------------------------------------------+ bool ClosePositionByType(ulong pos_type) { if(!PositionSelect(Symbol())) { if(InpEnableDebug) Print("ClosePositionByType: no position selected"); return false; } if(PositionGetInteger(POSITION_TYPE) != pos_type) { if(InpEnableDebug) Print("ClosePositionByType: position type mismatch"); return false; } double volume = PositionGetDouble(POSITION_VOLUME); if(volume <= 0) { if(InpEnableDebug) Print("ClosePositionByType: zero volume"); return false; } if(InpEnableDebug) PrintFormat("Closing opposite position type=%d volume=%.2f", (int)pos_type, volume); if(trade.PositionClose(Symbol())) { PrintFormat("تم إغلاق المركز المعاكس (نوع=%d) بنجاح. retcode=%d comment=%s", pos_type, trade.ResultRetcode(), trade.ResultComment()); return true; } else { PrintFormat("فشل إغلاق المركز المعاكس: retcode=%d comment=%s", trade.ResultRetcode(), trade.ResultComment()); return false; } } //+------------------------------------------------------------------+ //| إدارة التريلينج ستوب | //+------------------------------------------------------------------+ void OnTick_ManageTrailing() { if(!InpEnableTrailing) return; if(!PositionSelect(Symbol())) return; ulong ptype = (ulong)PositionGetInteger(POSITION_TYPE); double open_price = PositionGetDouble(POSITION_PRICE_OPEN); double volume = PositionGetDouble(POSITION_VOLUME); double current_profit_points = 0; double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT); double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); if(ptype == POSITION_TYPE_BUY) current_profit_points = (bid - open_price) / point; else current_profit_points = (open_price - ask) / point; if(InpEnableDebug) PrintFormat("Trailing: ptype=%d open=%.5f current profit points=%.1f", (int)ptype, open_price, current_profit_points); if(current_profit_points >= InpTrailingStart) { double new_sl; if(ptype == POSITION_TYPE_BUY) { new_sl = NormalizeDouble(bid - InpTrailingStep * point, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)); } else { new_sl = NormalizeDouble(ask + InpTrailingStep * point, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)); } bool mod = trade.PositionModify(Symbol(), new_sl, PositionGetDouble(POSITION_TP)); if(InpEnableDebug) PrintFormat("Trailing: modify SL to %.5f result=%s retcode=%d comment=%s", new_sl, mod ? "OK":"FAIL", trade.ResultRetcode(), trade.ResultComment()); } } //+------------------------------------------------------------------+