Загрузка данных


//+------------------------------------------------------------------+
//|                                                  EA_Fibonacci.mq4|
//|                                                      AI Advisor  |
//|                                         https://metaquotes.net   |
//+------------------------------------------------------------------+
#property copyright "AI Advisor"
#property link      "https://metaquotes.net"
#property version   "1.08"
#property strict

//--- Входные параметры
input string   Group_Fibo     = "--- Настройки Фибоначчи ---";
input int      InpBarsCount   = 150;          // Количество баров для поиска экстремумов

input string   Group_Trading  = "--- Настройки торговли ---";
input bool     InpUseMM       = true;         // Включить расчет лота в % от депозита?
input double   InpLotPercent  = 1.0;          // Процент от депозита для первого ордера (61.8%)
input double   InpLotMain     = 0.01;         // Фиксированный лот (если InpUseMM = false)
input double   InpGridMultiplier = 1.0;       // Множитель лота для второго ордера (76.4%)
input int      InpMagic       = 123456;       // Магический номер
input double   InpProfitBuffer = 1.0;         // Подушка профита в валюте на каждые 0.01 лота

input string   Group_Visual   = "--- Настройки графики ---";
input color    InpLineColor   = clrDodgerBlue;// Цвет линий уровней
input int      InpLineStyle   = 3;            // Стиль линий (STYLE_DASHDOT)
input int      InpLineWidth   = 1;            // Толщина линий

//--- Глобальные переменные для отслеживания состояния
double lastPriceMax = 0;
double lastPriceMin = 0;
bool isCycleFinished = false; 

#define OBJ_PREFIX "EA_Fibo_"

//+------------------------------------------------------------------+
//| Функции инициализации и деинициализации                          |
//+------------------------------------------------------------------+
int OnInit() { return(INIT_SUCCEEDED); }
void OnDeinit(const int reason) { ObjectsDeleteAll(0, OBJ_PREFIX); Comment(""); }

//+------------------------------------------------------------------+
//| Вспомогательные функции (Лот и Отрисовка)                        |
//+------------------------------------------------------------------+
double CalculateLot(double percent)
{
   double freeMargin = AccountFreeMargin();
   double marginRequired = MarketInfo(Symbol(), MODE_MARGINREQUIRED);
   if(marginRequired <= 0) return(InpLotMain);
   double calculatedLot = (freeMargin * (percent / 100.0)) / marginRequired;
   double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   if(lotStep > 0) calculatedLot = MathFloor(calculatedLot / lotStep) * lotStep;
   return(calculatedLot);
}

double CheckLotBounds(double lot)
{
   double minLot = MarketInfo(Symbol(), MODE_MINLOT);
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   if(lot < minLot) lot = minLot;
   if(lot > maxLot) lot = maxLot;
   return(NormalizeDouble(lot, 2));
}

void DrawHLine(string name, double price)
{
   string objName = OBJ_PREFIX + name;
   if(ObjectFind(0, objName) >= 0) { ObjectMove(0, objName, 0, 0, price); return; }
   
   ObjectCreate(0, objName, OBJ_HLINE, 0, 0, price);
   ObjectSetInteger(0, objName, OBJPROP_COLOR, InpLineColor);
   ObjectSetInteger(0, objName, OBJPROP_WIDTH, InpLineWidth);
   ObjectSetInteger(0, objName, OBJPROP_STYLE, InpLineStyle);
   ObjectSetString(0, objName, OBJPROP_TEXT, name);
}

//+------------------------------------------------------------------+
//| Основной рабочий модуль советника                                |
//+------------------------------------------------------------------+
void OnTick()
{
   RefreshRates();

   int bars = Bars(Symbol(), Period());
   int searchBars = (bars < InpBarsCount) ? bars : InpBarsCount;
   if(searchBars <= 0) return;

   int maxBarIdx = iHighest(Symbol(), Period(), MODE_HIGH, searchBars, 1);
   int minBarIdx = iLowest(Symbol(), Period(), MODE_LOW, searchBars, 1);
   if(maxBarIdx < 0 || minBarIdx < 0) return;

   double priceMax = NormalizeDouble(iHigh(Symbol(), Period(), maxBarIdx), Digits);
   double priceMin = NormalizeDouble(iLow(Symbol(), Period(), minBarIdx), Digits);
   
   datetime timeMax = iTime(Symbol(), Period(), maxBarIdx);
   datetime timeMin = iTime(Symbol(), Period(), minBarIdx);

   bool isBullish = (timeMax > timeMin); 

   if(priceMax != lastPriceMax || priceMin != lastPriceMin)
   {
      lastPriceMax = priceMax;
      lastPriceMin = priceMin;
      isCycleFinished = false; 
   }

   double height = priceMax - priceMin;
   double f50_Price  = NormalizeDouble(isBullish ? (priceMax - height * 0.500) : (priceMin + height * 0.500), Digits);
   double f618_Price = NormalizeDouble(isBullish ? (priceMax - height * 0.618) : (priceMin + height * 0.618), Digits);
   double f764_Price = NormalizeDouble(isBullish ? (priceMax - height * 0.764) : (priceMin + height * 0.764), Digits);
   double f100_Price = isBullish ? priceMin : priceMax; 

   DrawHLine("50.0", f50_Price);
   DrawHLine("61.8 (Вход)", f618_Price);
   DrawHLine("76.4 (Доливка)", f764_Price);
   DrawHLine("100.0 (Стоп)", f100_Price);

   int totalOrders = 0;
   int mainOrderTicket = -1;
   int mainType = -1;

   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol() != Symbol() || OrderMagicNumber() != InpMagic) continue;
      
      totalOrders++;
      if(mainOrderTicket == -1) 
      {
         mainOrderTicket = OrderTicket();
         mainType = OrderType();
      }
   }

   double tradeLotMain = InpUseMM ? CalculateLot(InpLotPercent) : InpLotMain;
   double tradeLotGrid = NormalizeDouble(tradeLotMain * InpGridMultiplier, 2);

   tradeLotMain = CheckLotBounds(tradeLotMain);
   tradeLotGrid = CheckLotBounds(tradeLotGrid);

   string textStatus = isCycleFinished ? "Ожидание новой сетки" : "Поиск входа";
   if(totalOrders == 1) textStatus = "Один ордер в рынке";
   if(totalOrders == 2) textStatus = "Два ордера в рынке. Поиск БУ.";

   Comment("=== СТАТУС EA FIBONACCI ===\n",
           "Направление: ", (isBullish ? "ВВЕРХ (BUY)" : "ВНИЗ (SELL)"), "\n",
           "Статус: ", textStatus, "\n",
           "Лот: ", DoubleToString(tradeLotMain, 2), "\n",
           "-------------------------------------\n",
           "50.0% (TP): ", DoubleToString(f50_Price, Digits), "\n",
           "61.8% (Вход): ", DoubleToString(f618_Price, Digits), "\n",
           "76.4% (Grid): ", DoubleToString(f764_Price, Digits), "\n",
           "100.0% (SL): ", DoubleToString(f100_Price, Digits));

   if(isCycleFinished) return;

   double AskPrice = MarketInfo(Symbol(), MODE_ASK);
   double BidPrice = MarketInfo(Symbol(), MODE_BID);
   bool actionResult = false; 

   // --- СЛУЧАЙ А: Нет открытых ордеров ---
   if(totalOrders == 0)
   {
      if(isBullish && BidPrice <= f618_Price && BidPrice > f764_Price)
         if(OrderSend(Symbol(), OP_BUY, tradeLotMain, AskPrice, 3, 0, 0, "Fibo BUY Main", InpMagic, 0, clrGreen) < 0) Print("Ошибка BUY: ", GetLastError());
         
      if(!isBullish && AskPrice >= f618_Price && AskPrice < f764_Price)
         if(OrderSend(Symbol(), OP_SELL, tradeLotMain, BidPrice, 3, 0, 0, "Fibo SELL Main", InpMagic, 0, clrRed) < 0) Print("Ошибка SELL: ", GetLastError());
   }
   
   // --- СЛУЧАЙ Б: Открыт ОДИН ордер ---
   if(totalOrders == 1 && OrderSelect(mainOrderTicket, SELECT_BY_TICKET))
   {
      if(mainType == OP_BUY)
      {
         if(BidPrice >= f50_Price) { actionResult = OrderClose(OrderTicket(), OrderLots(), BidPrice, 3, CLR_NONE); if(actionResult) isCycleFinished = true; return; }
         if(BidPrice <= f100_Price) { actionResult = OrderClose(OrderTicket(), OrderLots(), BidPrice, 3, CLR_NONE); if(actionResult) isCycleFinished = true; return; }
         if(BidPrice <= f764_Price) if(OrderSend(Symbol(), OP_BUY, tradeLotGrid, AskPrice, 3, 0, 0, "Fibo BUY Grid", InpMagic, 0, clrGreen) < 0) Print("Ошибка Grid BUY: ", GetLastError());
      }
      if(mainType == OP_SELL)
      {
         if(AskPrice <= f50_Price) { actionResult = OrderClose(OrderTicket(), OrderLots(), AskPrice, 3, CLR_NONE); if(actionResult) isCycleFinished = true; return; }
         if(AskPrice >= f100_Price) { actionResult = OrderClose(OrderTicket(), OrderLots(), AskPrice, 3, CLR_NONE); if(actionResult) isCycleFinished = true; return; }
         if(AskPrice >= f764_Price) if(OrderSend(Symbol(), OP_SELL, tradeLotGrid, BidPrice, 3, 0, 0, "Fibo SELL Grid", InpMagic, 0, clrRed) < 0) Print("Ошибка Grid SELL: ", GetLastError());
      }
   }
   
   // --- СЛУЧАЙ В: Открыты ОБА ордера (Безубыток с денежной подушкой) ---
   if(totalOrders == 2)
   {
      double totalProfit = 0;
      double totalGridLots = 0; 
      
      for(int i = OrdersTotal() - 1; i >= 0; i--)
      {
         if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
         if(OrderSymbol() != Symbol() || OrderMagicNumber() != InpMagic) continue;
         
         totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
         totalGridLots += OrderLots(); 
      }
      
      double requiredProfit = (totalGridLots / 0.01) * InpProfitBuffer;
      
      if(totalProfit >= requiredProfit)
      {
         for(int k = OrdersTotal() - 1; k >= 0; k--)
         {
            if(!OrderSelect(k, SELECT_BY_POS, MODE_TRADES)) continue;
            if(OrderSymbol() != Symbol() || OrderMagicNumber() != InpMagic) continue;
            
            double closePrice = (OrderType() == OP_BUY) ? BidPrice : AskPrice;
            actionResult = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, CLR_NONE);
            if(!actionResult) Print("Ошибка закрытия БУ для билета ", OrderTicket(), ": ", GetLastError());
         }
         isCycleFinished = true; 
      }
   }
}