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 ( ) ) ;
}
}
//+------------------------------------------------------------------+