Mooo/CCI_EA_debug.mq5

427 lines
17 KiB
MQL5

2025-12-01 08:34:44 +00:00
//+------------------------------------------------------------------+
//| Expert Advisor: CCI Channel EA (مع Debug مفصل) |
//| Description: نفس الـ EA السابق مع إضافات Print debugging مفصّلة |
//| لتتبع قيم المؤشر، أسباب رفض/فتح الصفقات، وحساب حجم اللوت خطوةً بخطوة.|
//+------------------------------------------------------------------+
#property copyright "Generated by Copilot"
#property version "1.02"
#property strict
2025-12-01 08:30:23 +00:00
2025-12-01 08:34:44 +00:00
#include <Trade\Trade.mqh>
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());
}
}
//+------------------------------------------------------------------+