Navigation:Home > Content >

Ilan_Pyramid_v1[1].1.mq4

Time: 2011-05-28 | Download file:Ilan_Pyramid_v1[1].1.mq4

//+------------------------------------------------------------------+
//|                                            Ilan_Pyramid_v1.1.mq4 |
//|                                   Copyright © 2010, Tarakan Corp |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2010, Tarakan Corp"

#include   // тут функция вывода сообщения об ошибке ErrorDescription()

extern     double  IlanTakeProfit   = 10;       // TakeProfit для илана
extern     double  PyramidStopLoss  = 10;       // StopLoss для пирамиды

extern     double  IlanStep         = 30;       // размер шага открытия ордеров илана
extern     double  PyramidStep      = 30;       // размер шага открытия ордеров пирамиды

/*extern*/ bool    UseMartingale    = True;     // False - объем лота постоянен
                                                // True - объем лота каждого нового ордера увеличивается по экспоненте

extern     double  IlanLotExp       = 1.60;     // экспонента увеличения лотов илана
extern     double  PyramidLotExp    = 1.00;     // экспонента увеличения лотов пирамиды

// extern  double  IlanStartLot     = 0.01;     // начальный размер лота илана
// extern  double  PyramidStartLot  = 0.01;     // начальный размер лота пирамиды

// extern  bool    FixLot           = False;    // True - начальный лот всегда одинаковый
extern     int     LotStep          = 1000;     // шаг увеличения лота. сколько в депозите LotStep,
                                                // востолько увеличится LotSize. если депо 1000 то лот 0.01,
                                                // если станет 2000 то лот 0.02

extern     int     LotDecimal       = 2;        // 2 - микролоты 0.01; 1 - мини лоты 0.1; 0 - нормальные лоты 1.0

extern     int     MaxIlanTrades    = 10;       // максимальное количество открытых ордеров илана
extern     int     MaxPyramidTrades = 10;       // максимальное количество ордеров пирамиды

// extern  bool    UsePyramidTrail  = False; 
// extern  double  TrailStart       = 10;       // если прибыль по ордеру больше TrailStart, то срабатывает трал
// extern  double  TrailStop        = 10;       // новый StopLoss выставляется на TrailStop пунктов от текущей цены

extern     double  PercentLoss      = 50.00;    // сколько процентов депозита можно потерять прежде чем
                                                // советник принудительно закроет все ордеры

extern     int     MagicNumber      = 80808;    // магический номер

extern     bool    CheckPyramidOpen = True;     // True - проверяем ордеры пирамиды перед открытием
                                                // False - открываем без проверки

//===================================================================

double     CurrIlanAvgPrice = 0;
double     CurrIlanTP = 0;
double     CurrPyramidSL = 0;
double     Spread;
string     ExpertName = "Ilan Pyramid v1.1";
datetime   PrevTime = 0;
int        Slip = 3;
int        Total, cnt;
bool       SellTradeNow = False, BuyTradeNow = False;
bool       NewSellOrderPlaced = False, NewBuyOrderPlaced = False;

double     PercentProfit = 100.00; // когда советник заработает PercentProfit процентов
                                   // депозита, тогда он принудительно закроет все ордеры

int        BuyTrade = -1, SellTrade = -1;      //  0 - направление торгует как Илан
                                               //  1 - направление торгует как Пирамида
                                               // -1 - по направлению нет открытых ордеров

int        ErrorCode;

// массивы с тикетами открытых ордеров советника
int BuyOrders[];      // массив тикетов открытых ордеров buy
int SellOrders[];     // массив тикетов открытых ордеров sell

//===================================================================

int init()
  {
    return(0);
  }
  
//===================================================================

int deinit()
  {
    return(0);
  }
  
//===================================================================

int start()
  {
    // если потеряно PercentLoss (или больше) процентов депозита - закрываем все
    if (AccountEquity() <= AccountBalance() * (1 - PercentLoss / 100))
      {
        Print("Потеряно ", PercentLoss, "% депозита, принудительное закрытие всех ордеров");
        CloseAllOrders();
      }
    
    // если заработано PercentProfit (или больше) процентов депозита - закрываем все
    if (AccountEquity() >= AccountBalance() * (1 + PercentProfit / 100))
      {
        Print("Заработано ", PercentProfit, "% депозита, принудительное закрытие всех ордеров");
        CloseAllOrders();
      }
  
    //---------------------------------
  
    // тралим пирамиду
    // if (UsePyramidTrail)
    //   TrailingPyramid(TrailStart, TrailStop);
      
    //---------------------------------
  
    if (PrevTime == Time[0])
      return(0);      
      
    PrevTime = Time[0];
    
    //---------------------------------
    
    Spread = MarketInfo(Symbol(), MODE_SPREAD) * Point;
    
    RefreshOrders();  // пересчитаем все открытые ордеры
    RefreshTrades();  // обновим BuyTrade и SellTrade
    
    //---------------------------------
    
    // не пора ли открывать очередной ордер
    
    if (CheckBuyTrade()) BuyTradeNow = True;
    if (CheckSellTrade()) SellTradeNow = True;
      
    //---------------------------------------
    
    // будем ли открывать ордер пирамиды
    if (CheckPyramidOpen) CheckPyramid();
    
    //---------------------------------------
    
    // торгуем  
    
    if (SellTradeNow)
      {
        for (cnt = 0; cnt < 3; cnt++) // три попытки открыть ордер
          {
            if (OpenSellOrder())
              {
                NewSellOrderPlaced = True;  // новый ордер открыт
                SellTradeNow = False;
                break;
              }
            Sleep(2000);
          }
      }
    
    //-------
    
    if (BuyTradeNow)
      {
        for (cnt = 0; cnt < 3; cnt++) // три попытки открыть ордер
          {
            if (OpenBuyOrder())
              {
                NewBuyOrderPlaced = True;  // новый ордер открыт
                BuyTradeNow = False;
                break;
              }
            Sleep(2000);
          }
      }
    
    //-------------------------------
    
    // модифицируем ордеры (двигаем StopLoss и TakeProfit)
    
    if (NewBuyOrderPlaced)
      {
        ModifyBuyOrders();
        NewBuyOrderPlaced = False;
      }
      
    if (NewSellOrderPlaced)
      {
        ModifySellOrders();
        NewSellOrderPlaced = False;
      }
    
    //-------------------------------
    
    return(0);    
  }  // --- Exit start() function ---
  
  
//===================================================================

// возвращает размер лота для очередного ордера заданного направления
// в случае ошибки возвращает -1

double GetLotSize(int TradeType)
  {
    if (CountTrades(TradeType) == 0)
      return(StartLotSize());
    
    double Exponent = 1;
    double LotSize = FindLastLotSize(TradeType);
    
    if (IsIlan(TradeType))
      Exponent = IlanLotExp;
      
    if (IsPyramid(TradeType))
      Exponent = PyramidLotExp;
      
    //----------
    
    if (UseMartingale)
      LotSize = NormalizeDouble(LotSize * Exponent, LotDecimal);
        
    if (AccountFreeMarginCheck(Symbol(), TradeType, LotSize) <= 0)
      {
        Print("Ошибка! Для открытия ордера лотом ", DoubleToStr(LotSize, 2), " не хватает свободных средств");
        return(-1);
      }
      
    return(LotSize);
  }

//===================================================================

// возвращает количество открытых ордеров заданного направления
// если направление не задано возвращает общее количество открытых ордеров

int CountTrades(int TradeType = -1)
  {
    if (TradeType == OP_BUY)
      return(ArraySize(BuyOrders));
    
    if (TradeType == OP_SELL)
      return(ArraySize(SellOrders));
      
    return(ArraySize(BuyOrders) + ArraySize(SellOrders));
  }
  
//===================================================================

// возвращает прибыль по открытым ордерам заданного направления
// если направление не задано возвращает общую прибыль по открытым ордерам

/*double CalculateProfit(int TradeType = -1)
  {
    double Profit = 0;
    
    if (TradeType == OP_BUY || TradeType == -1)
      {
        for (cnt = 0; cnt < ArraySize(BuyOrders); cnt++)
          {
            OrderSelect(BuyOrders[cnt], SELECT_BY_TICKET);
            Profit = Profit + OrderProfit() + OrderCommission() + OrderSwap();
          }
      }
    
    if (TradeType == OP_SELL || TradeType == -1)
      {
        for (cnt = 0; cnt < ArraySize(SellOrders); cnt++)
          {
            OrderSelect(SellOrders[cnt], SELECT_BY_TICKET);
            Profit = Profit + OrderProfit() + OrderCommission() + OrderSwap();
          }
      }    
     
    return(Profit);
  }*/

//===================================================================

// закрывает все открытые ордеры

void CloseAllOrders()
  {
    for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--)
      {
        OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
        
        if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber)
          continue;
          
        if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
          {
            if (OrderType() == OP_BUY)
              OrderClose(OrderTicket(), OrderLots(), Bid, Slip, Lime);
              
            if (OrderType() == OP_SELL)
              OrderClose(OrderTicket(), OrderLots(), Ask, Slip, HotPink);
          }
          
        Sleep(2000);
      }
  }

//===================================================================

// пересчитывет все открытые ордеры и обновляет массивы BuyOrders[] и SellOrders[]

void RefreshOrders()
  {
    int Count;
    int Ticket, OldTicket;
    int FindTicket = 0, LastFindTicket;
    
    ArrayResize(BuyOrders, 0);
    ArrayResize(SellOrders, 0);
  
    while (True)
      {
        LastFindTicket = FindTicket;
        FindTicket = 0;
        OldTicket = 0;
      
        // ищем ордер с минимальным тикетом
        for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--)
          {
            OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
        
            if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber)
              continue;
          
            if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
              {
                if (OrderType() == OP_BUY || OrderType() == OP_SELL)
                  {
                    Ticket = OrderTicket();
                    if (Ticket < OldTicket || OldTicket == 0)
                      {
                        if (LastFindTicket != 0 && Ticket <= LastFindTicket)
                          continue;
                    
                        FindTicket = Ticket;
                        OldTicket = FindTicket;
                      }
                  }
              }
          }  // for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--)
          
        if (FindTicket == 0)
          {
            break;
          }
        else
          {
            OrderSelect(FindTicket, SELECT_BY_TICKET);
          
            if (OrderType() == OP_BUY)  // в BuyOrders[]
              {
                ArrayResize(BuyOrders, ArraySize(BuyOrders) + 1);
                BuyOrders[ArraySize(BuyOrders) - 1] = FindTicket;
              }
            else if (OrderType() == OP_SELL)  // в SellOrders[]
              {
                ArrayResize(SellOrders, ArraySize(SellOrders) + 1);
                SellOrders[ArraySize(SellOrders) - 1] = FindTicket;
              }
            
          }
      }  // while (True)
  }

//===================================================================

// возврвщает цуну уровня TakeProfit для заданной цены и заданного направления
// Price - текущая цена
// Profit - размер TakeProfit в пунктах

double GetTakeProfitPrice(double Price, int TradeType, double Profit)
  {
    double ResultPrice;
  
    double tp = Profit * Point;
    double MinStopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    
    if (tp < MinStopLevel)
      tp = MinStopLevel;
    
    if (TradeType == OP_BUY)
      ResultPrice = Price + tp;
      
    if (TradeType == OP_SELL)
      ResultPrice = Price - tp;
    
    return(ResultPrice);
  }

//===================================================================

// возврвщает цуну уровня StopLoss для заданной цены и заданного направления
// Price - текущая цена
// Stop - размер StopLoss в пунктах

double GetStopLossPrice(double Price, int TradeType, double Stop)
  {
    double ResultPrice;
  
    double sl = Stop * Point;
    double MinStopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    
    if (sl < MinStopLevel)
      sl = MinStopLevel;
    
    if (TradeType == OP_BUY)
      {
        ResultPrice = Price - sl;
        if (NormalizeDouble((Price - ResultPrice) - MinStopLevel, 8) == 0)
          ResultPrice = ResultPrice - Spread;
      }
      
    if (TradeType == OP_SELL)
      {
        ResultPrice = Price + sl;
        if (NormalizeDouble((ResultPrice - Price) - MinStopLevel, 8) == 0)
          ResultPrice = ResultPrice + Spread;
      }
    
    return(ResultPrice);
  }

//===================================================================

// открывает ордер buy по текущей рыночной цене, в случае удачи возвращает True
// если ордер не открыт возвращает False

bool OpenBuyOrder()
  {
    int Ticket;
    double LotSize;
    int Trades = ArraySize(BuyOrders);
  
    LotSize = GetLotSize(OP_BUY);
    
    if (IsIlan(OP_BUY))
      Print("Открываем Buy, илан, ордер ", Trades + 1, ", лот ", DoubleToStr(LotSize, 2),
                                                          ", цена ", DoubleToStr(Ask, Digits));
    if (IsPyramid(OP_BUY))
      Print("Открываем Buy, пирамида, ордер ", Trades + 1, ", лот ", DoubleToStr(LotSize, 2),
                                                          ", цена ", DoubleToStr(Ask, Digits));
    if (IsEmpty(OP_BUY))
      Print("Открываем Buy, ордер ", Trades + 1, ", лот ", DoubleToStr(LotSize, 2),
                                                          ", цена ", DoubleToStr(Ask, Digits));
            
    if (LotSize > 0)
      {
        RefreshRates();
        Ticket = OrderSend(Symbol(), OP_BUY, LotSize, NormalizeDouble(Ask, Digits),
                             Slip, 0, 0, ExpertName + " - " + (Trades + 1), MagicNumber, 0, Blue);
                                     
        if (Ticket < 0)
          {
            ErrorCode = GetLastError();
            Print("OrderSend Error ", ErrorCode, " - ", ErrorDescription(ErrorCode));
            return(False);
          }
        
        Print("Ордер ", Trades + 1, ", Buy - открыт, ticket #", Ticket);
        
        // добавим тикет ордера в конец массива        
        ArrayResize(BuyOrders, ArraySize(BuyOrders) + 1); 
        BuyOrders[ArraySize(BuyOrders) - 1] = Ticket;
      }
      
    return(True);
  }

//===================================================================

// открывает ордер sell по текущей рыночной цене, в случае удачи возвращает True
// если ордер не открыт возвращает False

bool OpenSellOrder()
  {
    int Ticket;
    double LotSize;
    int Trades = ArraySize(SellOrders);
  
    LotSize = GetLotSize(OP_SELL);
    
    if (IsIlan(OP_SELL))
      Print("Открываем Sell, илан, ордер ", Trades + 1, ", лот ", DoubleToStr(LotSize, 2),
                                                            ", цена ", DoubleToStr(Bid, Digits));
    if (IsPyramid(OP_SELL))
      Print("Открываем Sell, пирамида, ордер ", Trades + 1, ", лот ", DoubleToStr(LotSize, 2),
                                                            ", цена ", DoubleToStr(Bid, Digits));
    if (IsEmpty(OP_SELL))
      Print("Открываем Sell, ордер ", Trades + 1, ", лот ", DoubleToStr(LotSize, 2),
                                                            ", цена ", DoubleToStr(Bid, Digits));
            
    if (LotSize > 0)
      {
        RefreshRates();
        Ticket = OrderSend(Symbol(), OP_SELL, LotSize, NormalizeDouble(Bid, Digits),
                             Slip, 0, 0, ExpertName + " - " + (Trades + 1), MagicNumber, 0, Red);
                                     
        if (Ticket < 0)
          {
            ErrorCode = GetLastError();
            Print("OrderSend Error ", ErrorCode, " - ", ErrorDescription(ErrorCode));
            return(False);
          }
        
        Print("Ордер ", Trades + 1, ", Sell - открыт, ticket #", Ticket);
        
        // добавим тикет ордера в конец массива
        ArrayResize(SellOrders, ArraySize(SellOrders) + 1); 
        SellOrders[ArraySize(SellOrders) - 1] = Ticket;
      }
      
    return(True);
  }

//===================================================================

// модифицирует ордеры заданного направления
// Price - новый уровень StopLoss или TakeProfit
// для направления, торгующего как илан, модифицирует TakeProfit
// для направления, торгующего как пирамида, модифицирует StopLoss

void ModifyOrders(int TradeType, double Price)
  {
    double NewStopLoss;
    double NewTakeProfit;
    int Orders[];
    
    if (TradeType == OP_BUY)
      {
        ArrayResize(Orders, ArraySize(BuyOrders));
        ArrayCopy(Orders, BuyOrders);
      }
    else if (TradeType == OP_SELL)
      {
        ArrayResize(Orders, ArraySize(SellOrders));
        ArrayCopy(Orders, SellOrders);
      }
  
    // модифицируем все ордеры массива Orders[]
    for (cnt = 0; cnt < ArraySize(Orders); cnt++)
      {
        OrderSelect(Orders[cnt], SELECT_BY_TICKET);
          
        if (IsIlan(TradeType)) // для илана двигаем TakeProfit
          {
            NewTakeProfit = NormalizeDouble(Price, Digits);
            NewStopLoss = OrderStopLoss();
          }
        
        if (IsPyramid(TradeType)) // для пирамиды двигаем StopLoss
          {
            NewTakeProfit = OrderTakeProfit();
            NewStopLoss = /*OrderStopLoss()*/NormalizeDouble(Price, Digits);
            
            /*if (TradeType == OP_BUY)
              {
                // если стопа нет совсем или новый стоп выше старого
                if (OrderStopLoss() == 0 || (OrderStopLoss() != 0 && Price > OrderStopLoss()))
                  NewStopLoss = NormalizeDouble(Price, Digits);
              }
            else if (TradeType == OP_SELL)
              {
                // если стопа нет совсем или новый стоп ниже старого
                if (OrderStopLoss() == 0 || (OrderStopLoss() != 0 && Price < OrderStopLoss()))
                  NewStopLoss = NormalizeDouble(Price, Digits);
              }*/
          }
          
        if (NewStopLoss != OrderStopLoss() || NewTakeProfit != OrderTakeProfit())
          {
            if (!OrderModify(OrderTicket(), OrderOpenPrice(), NewStopLoss, NewTakeProfit, 0, Yellow))
              {
                ErrorCode = GetLastError();
                Print("Order #", OrderTicket(), " - OrderModify Error ",
                                 ErrorCode, " - ", ErrorDescription(ErrorCode));
              }
            Sleep(2000);  
          }
      }  // for (cnt = 0; cnt < ArraySize(Orders); cnt++)
  }

//===================================================================

// модифицирует все ордеры направления buy

void ModifyBuyOrders()
  {
    if (IsIlan(OP_BUY)) // если buy торгует как илан
      {
        CurrIlanAvgPrice = GetAveragePrice(OP_BUY);
        CurrIlanTP = GetTakeProfitPrice(CurrIlanAvgPrice, OP_BUY, IlanTakeProfit);  // новый TakeProfit
        
        Print("Модифицируем ордеры Buy, илан, новый TakeProfit ", DoubleToStr(CurrIlanTP, Digits));   
        ModifyOrders(OP_BUY, CurrIlanTP);
        
        if (IsPyramid(OP_SELL) && PyramidStopLoss == 0)
          {
            Print("Модифицируем ордеры Sell, пирамида, новый StopLoss ", DoubleToStr(CurrIlanTP + Spread, Digits));
            ModifyOrders(OP_SELL, CurrIlanTP + Spread);
          }
      }
    
    //-----------
          
    if (IsPyramid(OP_BUY)) // если buy торгует как пирамида
      {
        if (PyramidStopLoss == 0)  // если StopLoss пирамиды равен TakeProfit илана
          {
            // если у илана еще нет TakeProfit - вычислим его
            if (IsIlan(OP_SELL) && CurrIlanAvgPrice == 0 && CurrIlanTP == 0)
              {
                CurrIlanAvgPrice = GetAveragePrice(OP_SELL);
                CurrIlanTP = GetTakeProfitPrice(CurrIlanAvgPrice, OP_SELL, IlanTakeProfit);
              }
          
            if (CurrIlanTP == 0) // если еще нет илана
              CurrPyramidSL = GetStopLossPrice(FindLastBuyPrice(), OP_BUY, IlanTakeProfit);
            else
              CurrPyramidSL = CurrIlanTP - Spread;
          }
        else // если у пирамиды свой StopLoss
          {
            CurrPyramidSL = GetStopLossPrice(FindLastBuyPrice(), OP_BUY, PyramidStopLoss);
          }
        
        Print("Модифицируем ордеры Buy, пирамида, новый StopLoss ", DoubleToStr(CurrPyramidSL, Digits));
        ModifyOrders(OP_BUY, CurrPyramidSL);
      }  // if (IsPyramid(OP_BUY))
  }

//+------------------------------------------------------------------+

// модифицирует все ордеры направления sell

void ModifySellOrders()
  {
    if (IsIlan(OP_SELL)) // если sell торгует как илан
      {
        CurrIlanAvgPrice = GetAveragePrice(OP_SELL);
        CurrIlanTP = GetTakeProfitPrice(CurrIlanAvgPrice, OP_SELL, IlanTakeProfit);  // новый TakeProfit
        
        Print("Модифицируем ордеры Sell, илан, новый TakeProfit ", DoubleToStr(CurrIlanTP, Digits));
        ModifyOrders(OP_SELL, CurrIlanTP);
        
        if (IsPyramid(OP_BUY) && PyramidStopLoss == 0)
          {
            Print("Модифицируем ордеры Buy, пирамида, новый StopLoss ", DoubleToStr(CurrIlanTP - Spread, Digits));
            ModifyOrders(OP_BUY, CurrIlanTP - Spread);
          }
      }
    
    //-----------
          
    if (IsPyramid(OP_SELL)) // если sell торгует как пирамида
      {
        if (PyramidStopLoss == 0)  // если StopLoss пирамиды равен TakeProfit илана
          {
            // если у илана еще нет TakeProfit - вычислим его
            if (IsIlan(OP_BUY) && CurrIlanAvgPrice == 0 && CurrIlanTP == 0)
              {
                CurrIlanAvgPrice = GetAveragePrice(OP_BUY);
                CurrIlanTP = GetTakeProfitPrice(CurrIlanAvgPrice, OP_BUY, IlanTakeProfit);
              }
          
            if (CurrIlanTP == 0) // если еще нет илана
              CurrPyramidSL = GetStopLossPrice(FindLastSellPrice(), OP_SELL, IlanTakeProfit);
            else
              CurrPyramidSL = CurrIlanTP + Spread;
          }
        else // если у пирамиды свой StopLoss
          {
            CurrPyramidSL = GetStopLossPrice(FindLastSellPrice(), OP_SELL, PyramidStopLoss);
          }
        
        Print("Модифицируем ордеры Sell, пирамида, новый StopLoss ", DoubleToStr(CurrPyramidSL, Digits));
        ModifyOrders(OP_SELL, CurrPyramidSL);
      }  // if (IsPyramid(OP_SELL))
  }

//===================================================================

// проверяет, не пора ли открывать ордер buy

bool CheckBuyTrade()
  {
    int Step;
    int MaxTrades;
    double LastBuyPrice;
    bool CheckResult = False;
  
    if (IsIlan(OP_BUY)) MaxTrades = MaxIlanTrades;
    if (IsPyramid(OP_BUY)) MaxTrades = MaxPyramidTrades;
    
    //-------
      
    LastBuyPrice = FindLastBuyPrice();
    
    if (CountTrades(OP_BUY) > 0 && CountTrades(OP_BUY) < MaxTrades)
      {
        if (IsIlan(OP_BUY) && LastBuyPrice - Ask >= IlanStep * Point) // цена идет вниз
          CheckResult = True;
          
        if (IsPyramid(OP_BUY) && Ask - LastBuyPrice >= PyramidStep * Point) // цена идет вверх
          CheckResult = True;
      }
        
    //--------
        
    if (IsEmpty(OP_BUY)) // buy пока не определился
      {
        if (CountTrades(OP_BUY) == 0)
          {
            CheckResult = True;
          }
        else
          {
            // если цена ушла вверх, то buy будет пирамидой
            if ((Ask - LastBuyPrice >= PyramidStep * Point))
              {
                BuyTrade = 1; // buy - пирамида
                Print("Buy - пирамида");
                CheckResult = True;
              }
          
            // если цена ушла вниз, то buy будет иланом
            if ((LastBuyPrice - Ask >= IlanStep * Point))
              {
                BuyTrade = 0;  // buy - илан
                Print("Buy - илан");
                CheckResult = True;
              }
          }
      }  // if (IsEmpty(OP_BUY)
      
    return(CheckResult);
  }

//===================================================================

// проверяет, не пора ли открывать ордер sell

bool CheckSellTrade()
  {
    int Step;
    int MaxTrades;
    double LastSellPrice;
    bool CheckResult = False;
  
    if (IsIlan(OP_SELL)) MaxTrades = MaxIlanTrades;
    if (IsPyramid(OP_SELL)) MaxTrades = MaxPyramidTrades;
    
    //-------
      
    LastSellPrice = FindLastSellPrice();
    
    if (CountTrades(OP_SELL) > 0 && CountTrades(OP_SELL) < MaxTrades)
      {
        if (IsIlan(OP_SELL) && Bid - LastSellPrice >= IlanStep * Point) // цена идет вверх
          CheckResult = True;
          
        if (IsPyramid(OP_SELL) && LastSellPrice - Bid >= PyramidStep * Point) // цена идет вниз
          CheckResult = True;
      }
        
    //--------
        
    if (IsEmpty(OP_SELL)) // sell пока не определился
      {
        if (CountTrades(OP_SELL) == 0)
          {
            CheckResult = True;
          }
        else
          {
            // если цена ушла вверх, то sell будет иланом
            if ((Bid - LastSellPrice >= IlanStep * Point))
              {
                SellTrade = 0; // sell - илан
                Print("Sell - илан");
                CheckResult = True;
              }
          
            // если цена ушла вниз, то sell будет пирамидой
            if ((LastSellPrice - Bid >= PyramidStep * Point))
              {
                SellTrade = 1; // sell - пирамида
                Print("Sell - пирамида");
                CheckResult = True;
              }
          }
      }  // if (IsEmpty(OP_SELL)
      
    return(CheckResult);
  }

//===================================================================

// возвращает усредненную цену открытия всех ордеров заданного направления

double GetAveragePrice(int TradeType)
  {
    double ResultPrice = 0;
    double Count = 0;
    int Orders[];
        
    if (TradeType == OP_BUY)
      {
        ArrayResize(Orders, ArraySize(BuyOrders));
        ArrayCopy(Orders, BuyOrders);
      }
    else if (TradeType == OP_SELL)
      {
        ArrayResize(Orders, ArraySize(SellOrders));
        ArrayCopy(Orders, SellOrders);
      }
    
    for (cnt = 0; cnt < ArraySize(Orders); cnt++)
      {
        OrderSelect(Orders[cnt], SELECT_BY_TICKET);
    
        ResultPrice = ResultPrice + OrderOpenPrice() * OrderLots();
        Count = Count + OrderLots();
      }
      
    if (ArraySize(Orders) > 0)
      ResultPrice = NormalizeDouble(ResultPrice / Count, Digits);
    
    return(ResultPrice);
  }

//===================================================================

// проверяет, торгует ли заданное направление как илан

bool IsIlan(int TradeType)
  {
    if ((TradeType == OP_BUY && BuyTrade == 0) || (TradeType == OP_SELL && SellTrade == 0))
      return(True);
    else
      return(False);
  }

//===================================================================

// проверяет, торгует ли заданное направление как пирамида

bool IsPyramid(int TradeType)
  {
    if ((TradeType == OP_BUY && BuyTrade == 1) || (TradeType == OP_SELL && SellTrade == 1))
      return(True);
    else
      return(False);
  }

//===================================================================

// возвращает True если заданное направление не илан и не пирамида

bool IsEmpty(int TradeType)
  {
    if ((TradeType == OP_BUY && BuyTrade == -1) || (TradeType == OP_SELL && SellTrade == -1))
      return(True);
    else
      return(False);
  }

//===================================================================

// проверяет и обновляет BuyTrade и SellTrade

void RefreshTrades()
  {
    if (CountTrades(OP_BUY) == 0)
      {
        if (IsIlan(OP_BUY))
          {
            CurrIlanTP = 0;
            CurrIlanAvgPrice = 0;
          }
        if (IsPyramid(OP_BUY))
          {
            CurrPyramidSL = 0;
          }
          
        BuyTrade = -1;
      }
    
    //-------
    
    if (CountTrades(OP_SELL) == 0)
      {
        if (IsIlan(OP_SELL))
          {
            CurrIlanTP = 0;
            CurrIlanAvgPrice = 0;
          }
        if (IsPyramid(OP_SELL))
          {
            CurrPyramidSL = 0;
          }
          
        SellTrade = -1;
      }
  }

//===================================================================

// тралит пирамиду

/*void TrailingPyramid(int Start, int Stop)
  {
    int Profit;
    int Trade;
    double OldStopLoss;
    double NewStopLoss;
    int Orders[];
    
    if (Stop == 0) return;
    if (!IsPyramid(OP_BUY) && !IsPyramid(OP_SELL)) return;
        
    if (IsPyramid(OP_BUY))
      {
        ArrayResize(Orders, ArraySize(BuyOrders));
        ArrayCopy(Orders, BuyOrders);
      }
    else if (IsPyramid(OP_SELL))
      {
        ArrayResize(Orders, ArraySize(SellOrders));
        ArrayCopy(Orders, SellOrders);
      }
      
    for (cnt = 0; cnt < ArraySize(Orders); cnt++)
      {
        OrderSelect(Orders[cnt], SELECT_BY_TICKET);
        
        if (OrderType() == OP_BUY)
          {
            Profit = NormalizeDouble((Bid - OrderOpenPrice()) / Point, 0);  // прибыль в пунктах
            if (Profit < Start)
              continue;
            OldStopLoss = OrderStopLoss();
            NewStopLoss = Bid - (Stop * Point);
            if (OldStopLoss == 0 || (OldStopLoss != 0 && NewStopLoss > OldStopLoss))
              if (!OrderModify(OrderTicket(), OrderOpenPrice(), NewStopLoss, OrderTakeProfit(), 0))
                {
                  ErrorCode = GetLastError();
                  Print("Order #", OrderTicket(), " - OrderModify Error ",
                                   ErrorCode, " - ", ErrorDescription(ErrorCode));
                }
            Sleep(1500);
          }  // if (OrderType() == OP_BUY)
              
        if (OrderType() == OP_SELL)
          {
            Profit = NormalizeDouble((OrderOpenPrice() - Ask) / Point, 0);  // прибыль в пунктах
            if (Profit < Start)
              continue;
            OldStopLoss = OrderStopLoss();
            NewStopLoss = Ask + (Stop * Point);
            if (OldStopLoss == 0 || (OldStopLoss != 0 && NewStopLoss < OldStopLoss))
              if (!OrderModify(OrderTicket(), OrderOpenPrice(), NewStopLoss, OrderTakeProfit(), 0))
                {
                  ErrorCode = GetLastError();
                  Print("Order #", OrderTicket(), " - OrderModify Error ",
                                   ErrorCode, " - ", ErrorDescription(ErrorCode));
                }
            Sleep(1500);
          }  // if (OrderType() == OP_SELL)
        
      }  // for (cnt = 0; cnt < ArraySize(Orders); cnt++)
  }*/
  
//===================================================================

void CheckPyramid()
  {
    // проверим, надо ли открывать ордер пирамиды
    // если после открытия ордера пирамида закроется по стопу в минус,
    // то ордер не открываем, но стоп пирамиды двигаем как будто ордер был открыт
    
    double OldPyramidSL = CurrPyramidSL;
    double NewPyramidSL;
    
    if (SellTradeNow && IsPyramid(OP_SELL))
      {
        if (!CheckPyramidProfit(OP_SELL)) // будет минус
          {
            Print("Пирамида - пропускаем открытие ордера Sell");
          
            // ордер не открываем, но стоп двигаем
            if (PyramidStopLoss != 0)
              {
                RefreshRates();
                NewPyramidSL = GetStopLossPrice(Bid, OP_SELL, PyramidStopLoss);
                
                // если старого стопа нет или новый стоп ниже старого
                if ((OldPyramidSL == 0) || (OldPyramidSL != 0 && NewPyramidSL < OldPyramidSL))
                  {
                    CurrPyramidSL = NewPyramidSL;
                    Print("Модифицируем ордеры Sell, пирамида, новый StopLoss ", DoubleToStr(CurrPyramidSL, Digits));
                    ModifyOrders(OP_SELL, CurrPyramidSL);
                  }
              }
              
            SellTradeNow = False;  // ордер не открываем
          }
      }
    
    //------------------
      
    if (BuyTradeNow && IsPyramid(OP_BUY))
      {
        if (!CheckPyramidProfit(OP_BUY)) // будет минус
          {
            Print("Пирамида - пропускаем открытие ордера Buy");
          
            // ордер не открываем, но стоп двигаем
            if (PyramidStopLoss != 0)
              {
                RefreshRates();
                NewPyramidSL = GetStopLossPrice(Ask, OP_BUY, PyramidStopLoss);
                
                // если старого стопа нет или новый стоп выше старого
                if ((OldPyramidSL == 0) || (OldPyramidSL != 0 && NewPyramidSL > OldPyramidSL))
                  {
                    CurrPyramidSL = NewPyramidSL;
                    Print("Модифицируем ордеры Buy, пирамида, новый StopLoss ", DoubleToStr(CurrPyramidSL, Digits));
                    ModifyOrders(OP_BUY, CurrPyramidSL);
                  }
              }
              
            BuyTradeNow = False;  // ордер не открываем
          }
      }
  }

//===================================================================

// проверяет, закроется ли пирамида в плюс, если после открытия ордера сработает стоп
// возвращает True если будет плюс, False если будет минус

bool CheckPyramidProfit(int TradeType)
  {
    double PyramidProfit = 0;
    
    double CurrPrice;         // текущая рыночная цена, по которой должен открыться ордер
    double PyramidLot;        // объем ордера пирамиды, каким он будет если мы откроем ордер
    double PyramidStop;       // StopLoss пирамиды, каким он будет если мы откроем ордер
    
    int Correct = (Digits - 4) / 10; // поправка, если после запятой пять цифр
    if (Correct == 0) Correct = 1;
    
    int Orders[];
    
    if (TradeType == OP_BUY)
      {
        ArrayResize(Orders, ArraySize(BuyOrders));
        ArrayCopy(Orders, BuyOrders);
      }
    else if (TradeType == OP_SELL)
      {
        ArrayResize(Orders, ArraySize(SellOrders));
        ArrayCopy(Orders, SellOrders);
      }
    
    RefreshRates();
    
    //------
    
    // цена, по которой должен открыться ордер
    if (TradeType == OP_BUY)
      CurrPrice = Ask;
    else if (TradeType == OP_SELL)
      CurrPrice = Bid;
    
    //------
    
    // лот, которым должен открыться ордер 
    PyramidLot = GetLotSize(TradeType);
    
    //------
    
    // уровень стопа после открытия ордера
    if (PyramidStopLoss != 0)
      {
        PyramidStop = GetStopLossPrice(CurrPrice, TradeType, PyramidStopLoss);
      }
    else
      {
        if (CurrIlanTP == 0) // если еще нет илана
          {
            PyramidStop = GetStopLossPrice(CurrPrice, TradeType, IlanTakeProfit);
          }
        else
          {
            if (TradeType == OP_BUY)
              PyramidStop = CurrIlanTP - Spread;
            else if (TradeType == OP_SELL)
              PyramidStop = CurrIlanTP + Spread;
          }
      }
    
    //------
    
    // сначала считаем будущую прибыль последнего (еще не открытого) ордера
    if (TradeType == OP_BUY)
      PyramidProfit = (PyramidStop - CurrPrice) / Point * Correct * PyramidLot * 10;
    else if (TradeType == OP_SELL)
      PyramidProfit = (CurrPrice - PyramidStop) / Point * Correct * PyramidLot * 10;
    
    //------
      
    // теперь будущую прибыль по всем остальным ордерам пирамиды
    for (cnt = 0; cnt < ArraySize(Orders); cnt++)
      {
        OrderSelect(Orders[cnt], SELECT_BY_TICKET);
        
        if (TradeType == OP_BUY)
          PyramidProfit = PyramidProfit + (PyramidStop - OrderOpenPrice()) * Correct / Point * OrderLots() * 10;
        else if (TradeType == OP_SELL)
          PyramidProfit = PyramidProfit + (OrderOpenPrice() - PyramidStop) * Correct / Point * OrderLots() * 10;
      }
    
    //------
      
    if (PyramidProfit > 0)
      return(True);
    else
      return(False);
  }

//===================================================================

// возвращает цену открытия последнего ордера buy
// в случае ошибки возвращает -1

double FindLastBuyPrice()
  {
    if (OrderSelect(FindLastTicket(OP_BUY), SELECT_BY_TICKET) > 0)
      return(OrderOpenPrice());
    else
      return(-1);
  }
  
//===================================================================

// возвращает цену открытия последнего ордера sell
// в случае ошибки возвращает -1

double FindLastSellPrice()
  {
    if (OrderSelect(FindLastTicket(OP_SELL), SELECT_BY_TICKET) > 0)
      return(OrderOpenPrice());
    else
      return(-1);
  }
  
//===================================================================

// возвращает размер лота последнего открытого ордера заданного направления
// в случае ошибки возвращает -1

double FindLastLotSize(int TradeType)
  {
    if (OrderSelect(FindLastTicket(TradeType), SELECT_BY_TICKET) > 0)
      return(OrderLots());
    else
      return(-1);
  }

//===================================================================

// возвращает тикет последнего открытого ордера заданного направления
// если направление не задано возвращает тикет самого последнего ордера
// если тикет не найден возвращает -1

int FindLastTicket(int TradeType = -1)
  {
    int FindTicket = -1;
    
    if (TradeType == OP_BUY)
      {
        if (ArraySize(BuyOrders) == 0)
          return(-1);
        else
          return(BuyOrders[ArraySize(BuyOrders) - 1]);
      }
    
    if (TradeType == OP_SELL)
      {
        if (ArraySize(SellOrders) == 0)
          return(-1);
        else
          return(SellOrders[ArraySize(SellOrders) - 1]);
      }
    
    // TradeType == -1
  
    if (ArraySize(BuyOrders) != 0)
      FindTicket = BuyOrders[ArraySize(BuyOrders) - 1];
    
    if (ArraySize(SellOrders) != 0)
      if (SellOrders[ArraySize(SellOrders) - 1] > FindTicket)
        FindTicket = SellOrders[ArraySize(SellOrders) - 1];
    
    return(FindTicket);
  }

//===================================================================

// возвращает стартовый размер лота для текущего размера депозита

double StartLotSize()
  {
    double ResultLot;
    double k;
    
    double LotStepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
    double MinLotSize = MarketInfo(Symbol(), MODE_MINLOT);
    double MaxLotSize = MarketInfo(Symbol(), MODE_MAXLOT);

    if (MinLotSize == 0) MinLotSize = 0.01;
    if (MaxLotSize == 0) MaxLotSize = 100;

    if (LotStepSize > 0)
      k = 1 / LotStepSize;
    else
      k = 1 / MinLotSize;
      
    ResultLot = MathFloor((AccountBalance() / LotStep / 100) * k) / k; 
    
    if (ResultLot < MinLotSize) ResultLot = MinLotSize;
    if (ResultLot > MaxLotSize) ResultLot = MaxLotSize;

    return(ResultLot);
  }

//===================================================================



//===================================================================

Recommend