Vizion-Trading-EA/Experts/profitmoney.mq5
2026-02-19 23:19:25 -06:00

783 lines
No EOL
49 KiB
MQL5

//+------------------------------------------------------------------+
//| QuarterTheory_FIXED_V11.mq5 |
//| MA 50 IS CRITICAL + Continuous Level Break/Retest |
//| MA 7 Crosses + MA 50 Confirmation = Gold Standard |
//+------------------------------------------------------------------+
#property copyright "Fixed System - MA 50 Critical + Break/Retest"
#property version "11.00"
#property strict
#include <Trade/Trade.mqh>
CTrade Trade;
//================ INPUT PARAMETERS ==================//
input group "=== GENERAL ==="
input int MagicNumber = 456789;
input double Risk_Per_Trade = 1.5;
input int Max_Simultaneous_Trades = 6;
input group "=== MOVING AVERAGES ==="
input int MA_1 = 7; // Fast trigger
input int MA_2 = 14;
input int MA_3 = 21;
input int MA_4 = 50; // CRITICAL MA!
input int MA_5 = 140;
input int MA_6 = 230;
input int MA_7 = 500;
input int MA_8 = 1000;
input int MA_9 = 1100;
input int MA_10 = 1300;
input group "=== MA 50 RULES (CRITICAL!) ==="
input bool MA50_Must_Confirm = true; // MA 50 must align
input bool MA50_Is_Major_Level = true; // MA 50 = support/resistance
input bool Enter_On_MA50_Touch = true; // Enter when price touches MA 50
input int MA50_Touch_Buffer = 20; // Buffer for MA 50 touch
input group "=== LEVEL BREAK & RETEST ==="
input bool Enter_On_Level_Break = true; // Enter on level break
input bool Enter_On_Level_Retest = true; // Enter on retest
input int Lookback_Bars = 200;
input int Level_Buffer_Points = 40;
input bool Mark_Levels_Continuously = true; // Keep updating levels
input int Level_Update_Minutes = 15; // Update every 15 min
input group "=== RISK MANAGEMENT ==="
input int Initial_SL_Points = 250;
input int BreakEven_Points = 80;
input bool Trail_To_MA50 = true; // Trail SL to MA 50
input group "=== TAKE PROFIT ==="
input double Close_At_MA6_Percent = 15.0; // MA 230
input double Close_At_MA7_Percent = 25.0; // MA 500
input double Close_At_MA8_Percent = 25.0; // MA 1000
input double Close_At_MA9_Percent = 20.0; // MA 1100
// 15% runner
input group "=== DAILY LIMITS ==="
input double Max_Daily_Loss_Percent = 4.0;
input double Max_Daily_Profit_Percent = 20.0;
input int Max_Trades_Per_Day = 25;
//================ GLOBALS ==================//
double PriceLevels[];
string LevelTypes[];
double LevelPrevPrices[]; // Track if price broke level
int TotalLevels = 0;
int MA_Handles[10];
double MA_Current[10];
double MA_Previous[10];
struct Position
{
ulong ticket;
double entry;
double original_lot;
bool is_buy;
bool tp_ma6_hit;
bool tp_ma7_hit;
bool tp_ma8_hit;
bool tp_ma9_hit;
};
Position OpenPositions[];
double DailyStart = 0;
int TodayTrades = 0;
datetime LastDay = 0;
datetime LastLevelUpdate = 0;
//+------------------------------------------------------------------+
int OnInit()
{
Print("========================================");
Print("FIXED v11.0 - MA 50 CRITICAL");
Print("Break & Retest System");
Print("========================================");
Trade.SetExpertMagicNumber(MagicNumber);
Trade.SetDeviationInPoints(50);
int periods[10] = {MA_1, MA_2, MA_3, MA_4, MA_5, MA_6, MA_7, MA_8, MA_9, MA_10};
for(int i=0; i<10; i++)
{
MA_Handles[i] = iMA(_Symbol, PERIOD_CURRENT, periods[i], 0, MODE_EMA, PRICE_CLOSE);
if(MA_Handles[i] == INVALID_HANDLE)
{
Print("ERROR: Failed to create MA ", periods[i]);
return INIT_FAILED;
}
}
Print("MA 50 (index 3) is CRITICAL confirmation");
CalculateAndMarkLevels();
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
LastLevelUpdate = TimeCurrent();
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
for(int i=0; i<10; i++)
if(MA_Handles[i] != INVALID_HANDLE)
IndicatorRelease(MA_Handles[i]);
ObjectsDeleteAll(0, "Level_");
ObjectsDeleteAll(0, "Arrow_");
ObjectsDeleteAll(0, "MA50_");
Print("EA Stopped");
}
//+------------------------------------------------------------------+
//| CALCULATE AND MARK LEVELS CONTINUOUSLY
//+------------------------------------------------------------------+
void CalculateAndMarkLevels()
{
// Clear old data
ArrayResize(PriceLevels, 0);
ArrayResize(LevelTypes, 0);
ArrayResize(LevelPrevPrices, 0);
TotalLevels = 0;
// Find ATH/ATL
double high = iHigh(_Symbol, PERIOD_CURRENT, 0);
double low = iLow(_Symbol, PERIOD_CURRENT, 0);
for(int i=1; i<=Lookback_Bars; i++)
{
double h = iHigh(_Symbol, PERIOD_CURRENT, i);
double l = iLow(_Symbol, PERIOD_CURRENT, i);
if(h > high) high = h;
if(l < low) low = l;
}
double range = high - low;
// Add levels
AddLevel(low, "FIB_0.0", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.236, "FIB_0.236", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.382, "FIB_0.382", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.5, "FIB_0.5", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.618, "FIB_0.618", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.786, "FIB_0.786", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(high, "FIB_1.0", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(high + range * 0.618, "FIB_1.618", iClose(_Symbol, PERIOD_CURRENT, 1));
// Quarters
AddLevel(low + range * 0.25, "QUARTER_0.25", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.75, "QUARTER_0.75", iClose(_Symbol, PERIOD_CURRENT, 1));
// Eighths
AddLevel(low + range * 0.125, "EIGHTH_0.125", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.375, "EIGHTH_0.375", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.625, "EIGHTH_0.625", iClose(_Symbol, PERIOD_CURRENT, 1));
AddLevel(low + range * 0.875, "EIGHTH_0.875", iClose(_Symbol, PERIOD_CURRENT, 1));
Print("Levels marked: ", TotalLevels, " | Range: ", (int)(range/_Point), " points");
DrawLevels();
}
//+------------------------------------------------------------------+
void AddLevel(double price, string type, double prev_price)
{
int size = ArraySize(PriceLevels);
ArrayResize(PriceLevels, size + 1);
ArrayResize(LevelTypes, size + 1);
ArrayResize(LevelPrevPrices, size + 1);
PriceLevels[size] = price;
LevelTypes[size] = type;
LevelPrevPrices[size] = prev_price;
TotalLevels++;
}
//+------------------------------------------------------------------+
void DrawLevels()
{
ObjectsDeleteAll(0, "Level_");
for(int i=0; i<TotalLevels; i++)
{
string name = "Level_" + IntegerToString(i);
color clr = clrGray;
int width = 1;
if(StringFind(LevelTypes[i], "FIB_0.5") >= 0 ||
StringFind(LevelTypes[i], "FIB_0.618") >= 0)
{
clr = clrYellow;
width = 2;
}
else if(StringFind(LevelTypes[i], "FIB") >= 0)
{
clr = clrDodgerBlue;
width = 1;
}
else if(StringFind(LevelTypes[i], "QUARTER") >= 0)
{
clr = clrLime;
width = 1;
}
ObjectCreate(0, name, OBJ_HLINE, 0, 0, PriceLevels[i]);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
ObjectSetInteger(0, name, OBJPROP_BACK, true);
ObjectSetString(0, name, OBJPROP_TEXT, LevelTypes[i]);
}
// Draw MA 50 as special level
UpdateMAs();
string ma50_name = "MA50_Line";
ObjectCreate(0, ma50_name, OBJ_HLINE, 0, 0, MA_Current[3]);
ObjectSetInteger(0, ma50_name, OBJPROP_COLOR, clrOrange);
ObjectSetInteger(0, ma50_name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, ma50_name, OBJPROP_WIDTH, 2);
ObjectSetString(0, ma50_name, OBJPROP_TEXT, "MA 50 - CRITICAL");
}
//+------------------------------------------------------------------+
void UpdateMAs()
{
for(int i=0; i<10; i++)
{
double curr[1], prev[1];
if(CopyBuffer(MA_Handles[i], 0, 0, 1, curr) > 0)
MA_Current[i] = curr[0];
else
MA_Current[i] = 0;
if(CopyBuffer(MA_Handles[i], 0, 1, 1, prev) > 0)
MA_Previous[i] = prev[0];
else
MA_Previous[i] = 0;
}
}
//+------------------------------------------------------------------+
//| CHECK MA 50 CONFIRMATION
//+------------------------------------------------------------------+
bool MA50_Confirms_Direction(bool check_bullish)
{
if(!MA50_Must_Confirm) return true;
// MA 50 must be aligned with direction
if(check_bullish)
{
// For bullish: MA 7 should be above MA 50
return MA_Current[0] > MA_Current[3];
}
else
{
// For bearish: MA 7 should be below MA 50
return MA_Current[0] < MA_Current[3];
}
}
//+------------------------------------------------------------------+
//| CHECK IF PRICE TOUCHING MA 50
//+------------------------------------------------------------------+
bool IsPriceTouchingMA50(double price, bool &bullish_touch, bool &bearish_touch)
{
double buffer = MA50_Touch_Buffer * _Point;
double ma50 = MA_Current[3];
bullish_touch = false;
bearish_touch = false;
if(MathAbs(price - ma50) <= buffer)
{
// Check if approaching from below (bullish) or above (bearish)
double prev_price = iClose(_Symbol, PERIOD_CURRENT, 1);
if(prev_price < ma50 && price >= ma50 - buffer)
bullish_touch = true;
else if(prev_price > ma50 && price <= ma50 + buffer)
bearish_touch = true;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| DETECT LEVEL BREAK
//+------------------------------------------------------------------+
bool DetectLevelBreak(double current_price, double prev_price, bool &bullish_break, bool &bearish_break, int &level_index)
{
bullish_break = false;
bearish_break = false;
level_index = -1;
for(int i=0; i<TotalLevels; i++)
{
double level = PriceLevels[i];
// Bullish break: previous below, current above
if(prev_price < level && current_price > level)
{
bullish_break = true;
level_index = i;
LevelPrevPrices[i] = current_price; // Update
Print("LEVEL BREAK UP: ", LevelTypes[i], " @ ", level);
return true;
}
// Bearish break: previous above, current below
if(prev_price > level && current_price < level)
{
bearish_break = true;
level_index = i;
LevelPrevPrices[i] = current_price; // Update
Print("LEVEL BREAK DOWN: ", LevelTypes[i], " @ ", level);
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| DETECT LEVEL RETEST
//+------------------------------------------------------------------+
bool DetectLevelRetest(double current_price, bool &bullish_retest, bool &bearish_retest, int &level_index)
{
bullish_retest = false;
bearish_retest = false;
level_index = -1;
double buffer = Level_Buffer_Points * _Point;
for(int i=0; i<TotalLevels; i++)
{
double level = PriceLevels[i];
double prev_level_price = LevelPrevPrices[i];
// Bullish retest: price broke above, now retesting from above
if(prev_level_price > level + buffer &&
current_price <= level + buffer &&
current_price >= level - buffer)
{
bullish_retest = true;
level_index = i;
Print("LEVEL RETEST (Bull): ", LevelTypes[i], " @ ", level);
return true;
}
// Bearish retest: price broke below, now retesting from below
if(prev_level_price < level - buffer &&
current_price >= level - buffer &&
current_price <= level + buffer)
{
bearish_retest = true;
level_index = i;
Print("LEVEL RETEST (Bear): ", LevelTypes[i], " @ ", level);
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| CHECK MA 7 CROSSES
//+------------------------------------------------------------------+
bool MA7_Crossed_Up()
{
// Check if MA 7 recently crossed above any MA
for(int i=1; i<5; i++) // Check 14, 21, 50, 140
{
if(MA_Previous[0] <= MA_Previous[i] && MA_Current[0] > MA_Current[i])
{
Print("MA 7 crossed UP through MA ", GetMAPeriod(i));
return true;
}
}
return false;
}
bool MA7_Crossed_Down()
{
// Check if MA 7 recently crossed below any MA
for(int i=1; i<5; i++) // Check 14, 21, 50, 140
{
if(MA_Previous[0] >= MA_Previous[i] && MA_Current[0] < MA_Current[i])
{
Print("MA 7 crossed DOWN through MA ", GetMAPeriod(i));
return true;
}
}
return false;
}
int GetMAPeriod(int index)
{
int periods[10] = {MA_1, MA_2, MA_3, MA_4, MA_5, MA_6, MA_7, MA_8, MA_9, MA_10};
if(index >= 0 && index < 10)
return periods[index];
return 0;
}
//+------------------------------------------------------------------+
double GetLotSize(int sl_points)
{
double risk = AccountInfoDouble(ACCOUNT_BALANCE) * Risk_Per_Trade / 100.0;
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double lot = risk / ((sl_points * _Point / tickSize) * tickValue);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lot = MathMax(lot, minLot);
lot = MathMin(lot, maxLot);
lot = NormalizeDouble(lot / step, 0) * step;
return lot;
}
//+------------------------------------------------------------------+
bool CheckLimits()
{
MqlDateTime dt;
TimeCurrent(dt);
dt.hour = 0; dt.min = 0; dt.sec = 0;
datetime today = StructToTime(dt);
if(today != LastDay)
{
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
TodayTrades = 0;
LastDay = today;
}
if(TodayTrades >= Max_Trades_Per_Day) return false;
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double pl = ((balance - DailyStart) / DailyStart) * 100.0;
if(pl <= -Max_Daily_Loss_Percent || pl >= Max_Daily_Profit_Percent)
return false;
return true;
}
//+------------------------------------------------------------------+
void OpenTrade(bool buy, double price, string reason)
{
double lot = GetLotSize(Initial_SL_Points);
if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
double sl = buy ? price - Initial_SL_Points * _Point : price + Initial_SL_Points * _Point;
bool result = false;
if(buy)
result = Trade.Buy(lot, _Symbol, price, sl, 0, reason);
else
result = Trade.Sell(lot, _Symbol, price, sl, 0, reason);
if(result)
{
TodayTrades++;
ulong ticket = Trade.ResultOrder();
int size = ArraySize(OpenPositions);
ArrayResize(OpenPositions, size + 1);
OpenPositions[size].ticket = ticket;
OpenPositions[size].entry = price;
OpenPositions[size].original_lot = lot;
OpenPositions[size].is_buy = buy;
OpenPositions[size].tp_ma6_hit = false;
OpenPositions[size].tp_ma7_hit = false;
OpenPositions[size].tp_ma8_hit = false;
OpenPositions[size].tp_ma9_hit = false;
Print("========== TRADE ", TodayTrades, " ==========");
Print(buy ? "BUY" : "SELL", " @ ", price);
Print("Reason: ", reason);
Print("MA 50: ", MA_Current[3]);
Print("===================================");
// Draw arrow
string arrow_name = "Arrow_" + IntegerToString(ticket);
ObjectCreate(0, arrow_name, OBJ_ARROW, 0, TimeCurrent(), price);
ObjectSetInteger(0, arrow_name, OBJPROP_COLOR, buy ? clrLime : clrRed);
ObjectSetInteger(0, arrow_name, OBJPROP_ARROWCODE, buy ? 233 : 234);
ObjectSetInteger(0, arrow_name, OBJPROP_WIDTH, 3);
}
}
//+------------------------------------------------------------------+
void ManagePositions()
{
UpdateMAs();
for(int i=PositionsTotal()-1; i>=0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
int idx = -1;
for(int j=0; j<ArraySize(OpenPositions); j++)
{
if(OpenPositions[j].ticket == ticket)
{
idx = j;
break;
}
}
if(idx == -1) continue;
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
bool is_buy = OpenPositions[idx].is_buy;
double current = is_buy ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double profit_points = is_buy ? (current - entry) / _Point
: (entry - current) / _Point;
// Breakeven
if(profit_points >= BreakEven_Points)
{
if((is_buy && sl < entry) || (!is_buy && sl > entry))
{
Trade.PositionModify(ticket, entry, 0);
}
}
// Trail to MA 50
if(Trail_To_MA50 && profit_points >= 100)
{
double ma50 = MA_Current[3];
if(is_buy && ma50 > sl + 20 * _Point)
{
Trade.PositionModify(ticket, ma50, 0);
Print("SL → MA 50: ", ma50);
}
else if(!is_buy && ma50 < sl - 20 * _Point)
{
Trade.PositionModify(ticket, ma50, 0);
Print("SL → MA 50: ", ma50);
}
}
double lot = PositionGetDouble(POSITION_VOLUME);
// Partial TPs
if(!OpenPositions[idx].tp_ma6_hit)
{
bool hit = is_buy ? (current >= MA_Current[5]) : (current <= MA_Current[5]);
if(hit)
{
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Close_At_MA6_Percent / 100.0, 2);
if(close_size > 0 && close_size <= lot)
{
Trade.PositionClosePartial(ticket, close_size);
OpenPositions[idx].tp_ma6_hit = true;
Print("TP: MA 230");
}
}
}
if(!OpenPositions[idx].tp_ma7_hit)
{
bool hit = is_buy ? (current >= MA_Current[6]) : (current <= MA_Current[6]);
if(hit)
{
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Close_At_MA7_Percent / 100.0, 2);
if(close_size > 0 && close_size <= lot)
{
Trade.PositionClosePartial(ticket, close_size);
OpenPositions[idx].tp_ma7_hit = true;
Print("TP: MA 500");
}
}
}
if(!OpenPositions[idx].tp_ma8_hit)
{
bool hit = is_buy ? (current >= MA_Current[7]) : (current <= MA_Current[7]);
if(hit)
{
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Close_At_MA8_Percent / 100.0, 2);
if(close_size > 0 && close_size <= lot)
{
Trade.PositionClosePartial(ticket, close_size);
OpenPositions[idx].tp_ma8_hit = true;
Print("TP: MA 1000");
}
}
}
if(!OpenPositions[idx].tp_ma9_hit)
{
bool hit = is_buy ? (current >= MA_Current[8]) : (current <= MA_Current[8]);
if(hit)
{
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Close_At_MA9_Percent / 100.0, 2);
if(close_size > 0 && close_size <= lot)
{
Trade.PositionClosePartial(ticket, close_size);
OpenPositions[idx].tp_ma9_hit = true;
Print("TP: MA 1100");
}
}
}
}
}
//+------------------------------------------------------------------+
void OnTick()
{
// Update levels continuously
if(Mark_Levels_Continuously)
{
if(TimeCurrent() - LastLevelUpdate > Level_Update_Minutes * 60)
{
CalculateAndMarkLevels();
LastLevelUpdate = TimeCurrent();
}
}
ManagePositions();
if(!CheckLimits()) return;
int open = 0;
for(int i=0; i<PositionsTotal(); i++)
{
if(PositionGetTicket(i) == 0) continue;
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
open++;
}
if(open >= Max_Simultaneous_Trades) return;
UpdateMAs();
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double current = (bid + ask) / 2;
double previous = iClose(_Symbol, PERIOD_CURRENT, 1);
// Check MA 7 crosses
bool ma7_up = MA7_Crossed_Up();
bool ma7_down = MA7_Crossed_Down();
// Check MA 50 confirmation
bool ma50_bull = MA50_Confirms_Direction(true);
bool ma50_bear = MA50_Confirms_Direction(false);
// Check MA 50 touch
bool bull_ma50_touch = false;
bool bear_ma50_touch = false;
if(Enter_On_MA50_Touch)
IsPriceTouchingMA50(current, bull_ma50_touch, bear_ma50_touch);
// Check level breaks
bool bull_break = false;
bool bear_break = false;
int break_level_idx = -1;
if(Enter_On_Level_Break)
DetectLevelBreak(current, previous, bull_break, bear_break, break_level_idx);
// Check level retests
bool bull_retest = false;
bool bear_retest = false;
int retest_level_idx = -1;
if(Enter_On_Level_Retest)
DetectLevelRetest(current, bull_retest, bear_retest, retest_level_idx);
// === BUY SIGNALS ===
bool buy_signal = false;
string buy_reason = "";
// 1. MA 7 crossed up + MA 50 confirms
if(ma7_up && ma50_bull)
{
buy_signal = true;
buy_reason = "MA 7 Cross Up + MA 50 Confirms";
}
// 2. Level break + MA 50 confirms
if(bull_break && ma50_bull && break_level_idx >= 0)
{
buy_signal = true;
buy_reason = "Level Break: " + LevelTypes[break_level_idx];
}
// 3. Level retest + MA 50 confirms
if(bull_retest && ma50_bull && retest_level_idx >= 0)
{
buy_signal = true;
buy_reason = "Level Retest: " + LevelTypes[retest_level_idx];
}
// 4. MA 50 touch + MA 7 above MA 50
if(bull_ma50_touch && ma50_bull)
{
buy_signal = true;
buy_reason = "MA 50 Touch (CRITICAL!)";
}
// === SELL SIGNALS ===
bool sell_signal = false;
string sell_reason = "";
// 1. MA 7 crossed down + MA 50 confirms
if(ma7_down && ma50_bear)
{
sell_signal = true;
sell_reason = "MA 7 Cross Down + MA 50 Confirms";
}
// 2. Level break + MA 50 confirms
if(bear_break && ma50_bear && break_level_idx >= 0)
{
sell_signal = true;
sell_reason = "Level Break: " + LevelTypes[break_level_idx];
}
// 3. Level retest + MA 50 confirms
if(bear_retest && ma50_bear && retest_level_idx >= 0)
{
sell_signal = true;
sell_reason = "Level Retest: " + LevelTypes[retest_level_idx];
}
// 4. MA 50 touch + MA 7 below MA 50
if(bear_ma50_touch && ma50_bear)
{
sell_signal = true;
sell_reason = "MA 50 Touch (CRITICAL!)";
}
// EXECUTE
if(buy_signal)
{
OpenTrade(true, ask, buy_reason);
}
if(sell_signal)
{
OpenTrade(false, bid, sell_reason);
}
}
//+------------------------------------------------------------------+