//+------------------------------------------------------------------+
//|                                          Martingale-Mihalich.mq4 |
//|                                       Copyright © 2006, MихалbIч |
//|                            http://www.mihalich-trading.hotbox.ru |
//+------------------------------------------------------------------+

#property copyright "Copyright © МихалbIч, 18 марта, 2007"
#property link      "mihalich81@gmail.com"

/*
/////////////////////////
// Описание
/////////////////////////
Подробная информация в файле Martingale-Mihalich.doc
и в форуме 
*/

/////////////////////////
// Общие пользовательские переменные
/////////////////////////

extern string _1.                   = "Параметры системы Мартигейла";

extern double BuyLots               = 0.1;   // Количество лотов.

extern double SellLots              = 0.1;   // Количество лотов.

extern int    MartingaleStep        = 20;  // Пробел между уровнями Мартингейла.

extern int    BuyProfitPips         = 25;   // Профит (пунктов).

extern int    SellProfitPips        = 25;   // Профит (пунктов).

extern int    FixingMethod          = 1;   // Метод фиксации серии (1,2).

extern double Progression           = 1.5;   // Основная прогрессия.

extern double Progression_Filter    = 1.5;   // Прогрессия фильтра.

extern string _2.                   = "Параметры торговой системы";

extern bool   Fractal               = false;   // Торговая система Fractal.

extern int    Fractal_Timeframe     = 0;  // Таймфрейм ТС Fractal.

extern int    Fractal_Period        = 20;  // Количество баров для ТС Fractal.

extern string _3.                   = "Параметры фильтра";

extern bool   Filter_MA             = true;  // Фильтр входа по MA.

extern int    Filter_MA_Timeframe   = 0;  // Таймфрейм MA фильтра.

extern int    Filter_MA_Period      = 200;  // Период MA фильтра.

extern bool   Filter_RSI            = true;  // Фильтр входа по RSI.

extern int    Filter_RSI_Timeframe  = 0;  // Таймфрейм RSI фильтра.

extern int    Filter_RSI_Period     = 10;  // Период RSI фильтра.

extern string _4.                   = "Параметры MAGIC номеров";

extern int    Magic_Master          = 20070301; // 1-ый MAGIC номер.

extern int    Magic_Slave           = 20070302; // 2-ой MAGIC номер.

extern string _5.                   = "Параметры отладки";

extern bool   Comments              = false;  // Технические комментарии.

/////////////////////////
// Переменные
/////////////////////////

int i, NumBuys, NumSells;
double OpenBuyLots, OpenSellLots, OpenBuyProfit, OpenSellProfit, HighFractal, LowFractal, HighestBuy, LowestBuy, LowestSell, HighestSell, StartLowestBuy, StartHighestSell; 
double Filter_MA_Point, Filter_RSI_Point, BuyLevelMartingale, NextBuyLevelMartingale, SellLevelMartingale, NextSellLevelMartingale, ReqBuyLots, ReqSellLots, NextStartBuyLots, NextStartSellLots;
bool BuySignal, SellSignal, FilterBlockBuy, FilterBlockSell, EntryToBuy, EntryToSell, BlockBuy, BlockSell;
int    type_clr,err_clr;
double price_clr;
bool   result_clr;
double MaxDrawDown, MaxEquity;
double AccountStart;
string OrderCommentString, DateStart;

/////////////////////////
// Получение строки отчёта после тестирования
/////////////////////////
int init()
  {
   if (IsTesting() == true)
   {
    AccountStart=AccountEquity();
    DateStart=TimeToStr(TimeCurrent(),TIME_DATE);
   }   
  }

int deinit()
  {
   Print("История ",DateStart,"-",TimeToStr(TimeCurrent(),TIME_DATE)," | Чистая прибыль=",AccountEquity()-AccountStart," | Максимальная просадка=",MathAbs(MaxDrawDown),
   " | Переменные: BuyLots=",BuyLots,"; SellLots=",SellLots,"; MartingaleStep=",MartingaleStep,
   "; BuyProfitPips=",BuyProfitPips,"; SellProfitPips=",SellProfitPips,"; FixingMethod=",FixingMethod,
   "; Progression=",Progression,"; Progression_Filter=",Progression_Filter,"; Fractal=",Fractal,
   "; Fractal_Timeframe=",Fractal_Timeframe,"; Fractal_Period=",Fractal_Period,
   "; Filter_MA=",Filter_MA,"; Filter_MA_Timeframe=",Filter_MA_Timeframe,"; Filter_MA_Period=",Filter_MA_Period,
   "; Filter_RSI=",Filter_RSI,"; Filter_RSI_Timeframe=",Filter_RSI_Timeframe,"; Filter_RSI_Period=",Filter_RSI_Period);
   return(0);
  }

int start()
  {

/////////////////////////
// Получение необходимой информации об открытых ордерах
/////////////////////////

   NumBuys          = 0;
   NumSells         = 0;
   OpenBuyLots      = 0;
   OpenSellLots     = 0;
   OpenBuyProfit    = 0;
   OpenSellProfit   = 0;
   HighestBuy       = 0;
   LowestBuy        = 10000;
   HighestSell      = 0;
   LowestSell       = 10000;
   StartLowestBuy   = 10000;
   StartHighestSell = 0;

   for(i = 0; i < OrdersTotal(); i++)
   {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
    if (OrderSymbol() == Symbol() && (OrderMagicNumber() == Magic_Slave || OrderMagicNumber() == Magic_Master))
    {
     if (OrderType() == OP_BUY)
     {
      NumBuys++;
      OpenBuyLots = OpenBuyLots + OrderLots();
      OpenBuyProfit = OpenBuyProfit + OrderProfit()-OrderSwap(); // своп учтён
      if (OrderOpenPrice() > HighestBuy) HighestBuy  = OrderOpenPrice();
      if (OrderOpenPrice() < LowestBuy) LowestBuy  = OrderOpenPrice();
     }
     if (OrderType() == OP_SELL)
     {     
      NumSells++;
      OpenSellLots = OpenSellLots + OrderLots();
      OpenSellProfit = OpenSellProfit + OrderProfit()-OrderSwap(); // своп учтён
      if (OrderOpenPrice() < LowestSell) LowestSell  = OrderOpenPrice();
      if (OrderOpenPrice() > HighestSell) HighestSell  = OrderOpenPrice();
     }
    }
    if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic_Master)
    {
     if (OrderType() == OP_BUY)
     {
      if (OrderOpenPrice() < StartLowestBuy) StartLowestBuy = OrderOpenPrice();
     }
     if (OrderType() == OP_SELL)
     {
      if (OrderOpenPrice() > StartHighestSell) StartHighestSell  = OrderOpenPrice();
     }
    }
   }

/////////////////////////
// Генерация сигналов Buy/Sell
/////////////////////////
   if (Fractal == false)
   {
    BuySignal         = true;
    SellSignal        = true;
   }
   else
   {
    BuySignal         = false;
    SellSignal        = false;
   }

   //начало кода генерации сигнала при пробое фрактала (ТС Fractal)
   if (BuySignal == false)
   {
    HighFractal = High[iHighest(NULL,Fractal_Timeframe,MODE_HIGH,Fractal_Period,1)]; //начало поиска "1", можно увеличить
    if (HighFractal < Open[0]) BuySignal=true; //уменьшение влияния ложных пробоев "Bid-5*Point"
   }
   
   if (SellSignal == false)
   {
    LowFractal = Low[iLowest(NULL,Fractal_Timeframe,MODE_HIGH,Fractal_Period,1)]; //начало поиска "1", можно увеличить
    if (LowFractal > Open[0]) SellSignal=true; //уменьшение влияния ложных пробоев "Bid+5*Point"
   }
   //конец кода генерации сигнала при пробое фрактала (ТС Fractal)

/////////////////////////
// Фильтрация сигналов Buy/Sell
/////////////////////////
   EntryToBuy        = false;
   EntryToSell       = false;

   if (Filter_MA == true)
   {
    Filter_MA_Point = NormalizeDouble(iMA(NULL,Filter_MA_Timeframe,Filter_MA_Period,0,MODE_SMMA,PRICE_CLOSE,1),4);
   }
   if (Filter_RSI == true)
   {
    Filter_RSI_Point = NormalizeDouble(iRSI(NULL,Filter_RSI_Timeframe,Filter_RSI_Period,PRICE_CLOSE,0),0);
   }

   //вход только в покупку
   if ((Filter_MA == true && Filter_RSI == true && Bid > Filter_MA_Point && Filter_RSI_Point < 30) ||
       (Filter_MA == true && Filter_RSI == false && Bid > Filter_MA_Point) ||
       (Filter_MA == false && Filter_RSI == true && Filter_RSI_Point < 30))
   {
    if (FilterBlockBuy == true &&
        NumBuys > 0 &&
        LowestBuy != 10000 &&
       (LowestBuy-Bid)/Point > MartingaleStep &&
       (StartLowestBuy > Bid && StartLowestBuy-MartingaleStep*Point >= Bid)) // ограничение повторений
    {
     EntryToBuy=true;
    }
    FilterBlockSell=true;
    FilterBlockBuy=false;
   }
   else FilterBlockBuy=true;

   //вход только в продажу
   if ((Filter_MA == true && Filter_RSI == true && Bid < Filter_MA_Point && Filter_RSI_Point > 70) ||
       (Filter_MA == true && Filter_RSI == false && Bid < Filter_MA_Point) ||
       (Filter_MA == false && Filter_RSI == true && Filter_RSI_Point > 70))
   {
    if (FilterBlockSell == true &&
        NumSells > 0 &&
        HighestSell > 0 &&
       (Bid-HighestSell)/Point > MartingaleStep &&
        StartHighestSell+MartingaleStep*Point <= Bid) // ограничение повторений
    {
     EntryToSell=true;
    }
    FilterBlockBuy=true;
    FilterBlockSell=false;
   }
   else FilterBlockSell=true;

   //вход без фильтров
   if (Filter_MA == false && Filter_RSI == false)
   {
    if (FilterBlockBuy == true &&
        NumBuys > 0 &&
        LowestBuy != 10000 &&
       (LowestBuy-Bid)/Point > MartingaleStep &&
       (StartLowestBuy > Bid && StartLowestBuy-MartingaleStep*Point >= Bid)) // ограничение повторений
    {
     EntryToBuy=true;
    }
    FilterBlockBuy=false;
   
    if (FilterBlockSell == true &&
        NumSells > 0 &&
        HighestSell > 0 &&
       (Bid-HighestSell)/Point > MartingaleStep &&
        StartHighestSell+MartingaleStep*Point <= Bid) // ограничение повторений
    {
     EntryToSell=true;
    }
    FilterBlockSell=false;
   }

/////////////////////////
// Определение комментария для открываемых ордеров
/////////////////////////
   if (Period() == 1) OrderCommentString="M1 - ";
   if (Period() == 5) OrderCommentString="M5 - ";
   if (Period() == 15) OrderCommentString="M15 - ";
   if (Period() == 30) OrderCommentString="M30 - ";
   if (Period() == 60) OrderCommentString="H1 - ";
   if (Period() == 240) OrderCommentString="H4 - ";
   if (Period() == 1440) OrderCommentString="D1 - ";
   if (Period() == 10080) OrderCommentString="W1 - ";
   if (Period() == 43200) OrderCommentString="MN1 - ";

/////////////////////////
// Открытие первого стартового ордера
/////////////////////////
   if (BuySignal == true && FilterBlockBuy == false && NumBuys == 0)
      {
       OrderSend(Symbol(),OP_BUY,BuyLots,Ask,3,0,0,OrderCommentString+Magic_Master,Magic_Master,0,Blue);
       NumBuys++;
      }

   if (SellSignal == true && FilterBlockSell == false && NumSells == 0)
      {
       OrderSend(Symbol(),OP_SELL,SellLots,Bid,3,0,0,OrderCommentString+Magic_Master,Magic_Master,0,Red);
       NumSells++;
      }

/////////////////////////
// Определение уровня Мартингейла и необходимого количества лотов
/////////////////////////

   BuyLevelMartingale      = 0;
   NextBuyLevelMartingale  = 0;
   ReqBuyLots              = 0;
   SellLevelMartingale     = 0;
   ReqSellLots             = 0;
   NextSellLevelMartingale = 0;

   if (HighestBuy > Bid && NumBuys > 0)
   {
    BuyLevelMartingale = (HighestBuy - Bid) / Point / MartingaleStep; // уровень Мартингейла
    NextBuyLevelMartingale = (StartLowestBuy - Bid) / Point / MartingaleStep; // добавочный уровень Мартингейла
    ReqBuyLots = NormalizeDouble((MathPow(Progression,NextBuyLevelMartingale)*2-1)*BuyLots,1); // расчёт лотов (всего)
   }

   if (LowestSell < Bid && NumSells > 0)
   {
    SellLevelMartingale = (Bid - LowestSell) / Point / MartingaleStep; // общий уровень Мартингейла
    NextSellLevelMartingale = (Bid - StartHighestSell) / Point / MartingaleStep; // добавочный уровень Мартингейла
    ReqSellLots = NormalizeDouble((MathPow(Progression,NextSellLevelMartingale)*2-1)*SellLots,1); // расчёт лотов (всего)
   }
   
   NextStartBuyLots = NormalizeDouble(MathAbs(OpenBuyProfit)/MartingaleStep/10*(Progression_Filter-1),1);// Деление на 10 обязательно для мини-форекса.
   NextStartSellLots = NormalizeDouble(MathAbs(OpenSellProfit)/MartingaleStep/10*(Progression_Filter-1),1);// Деление на 10 обязательно для мини-форекса.

/////////////////////////
// Открытие добавочных стартовых ордеров (после отключения фильтра
/////////////////////////
   if (EntryToBuy == true && NextStartBuyLots >= MarketInfo(Symbol(),MODE_MINLOT))
      {
       OrderSend(Symbol(),OP_BUY,NextStartBuyLots,Ask,3,0,0,OrderCommentString+Magic_Master,Magic_Master,0,LightSkyBlue);
      }

   if (EntryToSell == true && NextStartSellLots >= MarketInfo(Symbol(),MODE_MINLOT))
      {
       OrderSend(Symbol(),OP_SELL,NextStartSellLots,Bid,3,0,0,OrderCommentString+Magic_Master,Magic_Master,0,Pink);
      }

/////////////////////////
// Открытие ордеров
/////////////////////////

   if (ReqBuyLots > OpenBuyLots && NumBuys > 0 && FilterBlockBuy == false && EntryToBuy == false && ReqBuyLots-OpenBuyLots >= MarketInfo(Symbol(),MODE_MINLOT))
      {
       OrderSend(Symbol(),OP_BUY,ReqBuyLots-OpenBuyLots,Ask,3,0,0,OrderCommentString+Magic_Slave,Magic_Slave,0,DodgerBlue);
       NumBuys++;
      }

   if (ReqSellLots > OpenSellLots && NumSells > 0 && FilterBlockSell == false && EntryToSell == false && ReqSellLots-OpenSellLots >= MarketInfo(Symbol(),MODE_MINLOT))
      {
       OrderSend(Symbol(),OP_SELL,ReqSellLots-OpenSellLots,Bid,3,0,0,OrderCommentString+Magic_Slave,Magic_Slave,0,Tomato);
       NumSells++;
      }

/////////////////////////
// Закрытие ордеров
/////////////////////////

   if ((FixingMethod == 2 && OpenBuyProfit > BuyProfitPips*OpenBuyLots*10) || // Умножение на 10 обязательно для мини-форекса.
       (FixingMethod == 1 && LowestBuy+BuyProfitPips*Point < Bid))
   {
    for(i=OrdersTotal()-1;i>=0;i--)
    {
     if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
     {
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic_Slave || OrderMagicNumber() == Magic_Master)
      {
       type_clr=OrderType();
       if(type_clr==OP_BUY)
       {
        while(true)
        {
         if(type_clr==OP_BUY) price_clr=MarketInfo(OrderSymbol(),MODE_BID);
         result_clr=OrderClose(OrderTicket(),OrderLots(),price_clr,3,Gold);
         if(result_clr!=true) {err_clr=GetLastError(); Print("LastError = ",err_clr);}
         else err_clr=0;
         if(err_clr==135) RefreshRates();
         else break;
        }
       }
      }
     }
    }     
   }

   if ((FixingMethod == 2 && OpenSellProfit > SellProfitPips*OpenSellLots*10) || // Умножение на 10 обязательно для мини-форекса.
       (FixingMethod == 1 && HighestSell-SellProfitPips*Point > Bid))
   {
    for(i=OrdersTotal()-1;i>=0;i--)
    {
     if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
     {
      if (OrderSymbol() == Symbol() && (OrderMagicNumber() == Magic_Slave || OrderMagicNumber() == Magic_Master))
      {
       type_clr=OrderType();
       if(type_clr==OP_SELL)
       {
        while(true)
        {
         if(type_clr==OP_SELL) price_clr=MarketInfo(OrderSymbol(),MODE_ASK);
         result_clr=OrderClose(OrderTicket(),OrderLots(),price_clr,3,Gold);
         if(result_clr!=true) {err_clr=GetLastError(); Print("LastError = ",err_clr);}
         else err_clr=0;
         if(err_clr==135) RefreshRates();
         else break;
        }
       }
      }
     }
    }
   }

/////////////////////////
// Технические комментарии
/////////////////////////
   if (MaxEquity < AccountEquity()) { MaxEquity = AccountEquity(); }
   if (MaxDrawDown > (AccountEquity()-MaxEquity)) { MaxDrawDown = AccountEquity()-MaxEquity; }
   if (Comments == true)
   {
    Comment("\nHighFractal = ",HighFractal,", LowFractal = ",LowFractal,", BuySignal = ",BuySignal,", SellSignal = ",SellSignal,
            "\nNumBuys = ",NumBuys,", NumSells = ",NumSells,", OpenBuyLots = ",OpenBuyLots,", OpenSellLots = ",OpenSellLots,", OpenBuyProfit = ",OpenBuyProfit,", OpenSellProfit = ",OpenSellProfit,
            "\nHighestBuy = ",HighestBuy,", LowestBuy = ",LowestBuy,", HighestSell = ",HighestSell,", LowestSell = ",LowestSell, ", StartLowestBuy = ",StartLowestBuy,", StartHighestSell = ",StartHighestSell,
            "\nFilter_RSI_Point = ",Filter_RSI_Point,
            "\nBuyLevelMartingale = ",BuyLevelMartingale,", NextBuyLevelMartingale = ",NextBuyLevelMartingale,",ReqBuyLots = ",ReqBuyLots,", SellLevelMartingale = ",SellLevelMartingale,", NextSellLevelMartingale = ",NextSellLevelMartingale,",ReqSellLots = ",ReqSellLots,
            "\nNextStartBuyLots = ",NextStartBuyLots,", NextStartSellLots = ",NextStartSellLots,", EntryToBuy = ",EntryToBuy,", EntryToSell = ",EntryToSell,", FilterBlockBuy = ",FilterBlockBuy,", FilterBlockSell = ",FilterBlockSell,
            "\nMaxDrawDown = ",MaxDrawDown);
   }
   return(0);
  }