#include <stdlib.mqh>
#include <stderror.mqh>
//+------------------------------------------------------------------+
//|                                          Puppeteer_v2.0_Auto.mq4 |
//|                        Copyright 2014, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property strict
extern double Lots                          = 0.1;
extern int    Slippage                      = 5;
extern double Percent_Risk                  = 20.0;
extern double Multipler                     = 1.667;
extern string _                             = "Values of the indicator for a basket of warrants_USD";
extern bool   Basket_of_warrants_USD        = true;
extern bool   Basket_of_warrants_USD_Martin = false;
extern int    Magic_usd                     = 11111;
extern string __                            = "Values of the indicator for a basket of warrants_GBP";
extern bool   Basket_of_warrants_GBP        = true;
extern bool   Basket_of_warrants_GBP_Martin = false;
extern int    Magic_gbp                     = 22222;
extern string ___                           = "Values of the indicator for a basket of warrants_JPY";
extern bool   Basket_of_warrants_JPY        = true;
extern bool   Basket_of_warrants_JPY_Martin = false;
extern int    Magic_jpy                     = 33333;
extern bool   Show_indi                     = true;

string Array_usd[] = {"EURUSD","GBPUSD","AUDUSD","NZDUSD"};
string array_usd[] = {"USDCAD","USDCHF","USDJPY"};
string Array_gbp[] = {"GBPAUD","GBPCAD","GBPCHF","GBPJPY","GBPNZD","GBPUSD"};
string array_gbp[] = {"EURGBP"};
string array_jpy[] = {"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"};

int Size_usd,size_usd,Size_gbp,size_gbp,SIZE_jpy,ticket,
retries,Total_USD,Total_GBP,Total_JPY,pairCount_USD,Nusr_usd,pairCount_GBP,Nusr_gbp,pairCount_JPY,Nusr_jpy;
double indi_usd,indi_gbp,indi_jpy,risk,oLots;
datetime timeprev;
string Gls_104 = "Puppeteer_v2.0_Auto";  
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
if(Digits == 5 || Digits == 3)
{
Slippage *= 10;
 }
//---
  Size_usd=ArraySize(Array_usd);
  size_usd=ArraySize(array_usd);
  Size_gbp=ArraySize(Array_gbp);
  size_gbp=ArraySize(array_gbp);
  SIZE_jpy = ArraySize(array_jpy);
  
  pairCount_USD=Size_usd+size_usd;
  pairCount_GBP=Size_gbp+size_gbp;
  pairCount_JPY=SIZE_jpy;
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  ObjectsDeleteAll();
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
  if(Show_indi == true)
  SHOW_INDICATOR();
  else
  ObjectsDeleteAll();
  risk=NormalizeDouble(AccountBalance()/100*Percent_Risk*Point,Digits);
   if(risk+OrderProfit() < 0) {Close_Orders();}
                  indi_usd = iCustom(Symbol(),PERIOD_D1,"Kuklovod_USD",7,0);
                  indi_gbp = iCustom(Symbol(),PERIOD_D1,"Kuklovod_GBP",7,0);
                  indi_jpy = iCustom(Symbol(),PERIOD_D1,"Kuklovod_JPY",7,0);
 Comment("\n Account Company: "+AccountCompany()+
 "\n Account № "+IntegerToString(AccountNumber())+
 "\n Account Name: "+AccountName()+
 "\n Indicator indications puppeteer_PERIOD_Daily_USD:  "+DoubleToString(indi_usd,2)+
 "\n Indicator indications puppeteer_PERIOD_Daily_GBP:  "+DoubleToString(indi_gbp,2)+
 "\n Indicator indications puppeteer_PERIOD_Daily_JPY:  "+DoubleToString(indi_jpy,2));
 bool plus_usd = false, minus_usd = false;
 bool plus_gbp = false, minus_gbp = false;
 bool plus_jpy = false, minus_jpy = false;
                  Total_USD = CountTrades_USD();
                  Total_GBP = CountTrades_GBP();
                  Total_JPY = CountTrades_JPY();
                    if(Time[0] == timeprev) return;
                    timeprev=Time[0];
                    oLots=Lots;
                    
    if(Basket_of_warrants_USD == true && Total_USD == 0)
    {
    if(timeprev && indi_usd >= 10 && indi_usd <= 35)     OpenPlus_USD();
     if(timeprev && indi_usd <= -10 && indi_usd >= -30)  OpenMinus_USD();
     }
     if(Basket_of_warrants_USD_Martin == true)
     {
     if(Total_USD == 0)
     {
      if(indi_usd >= 70 && indi_usd <= 75)    plus_usd  = true;
       if(indi_usd <= -70 && indi_usd >= -75) minus_usd = true;
        if(!plus_usd && !minus_usd) return;
         Nusr_usd = 0;
     }
     else
      {
   Nusr_usd = Total_USD/pairCount_USD;
   if (Nusr_usd > 3) return;
  } 
   oLots = Lots * MathPow(Multipler,Nusr_usd);
  if(plus_usd  == true && Uslovie_Plus_USD ())     OpenMinus_USD();
  if(minus_usd == true && Uslovie_Minus_USD())     OpenPlus_USD();
     }
     if(Total_USD > 0 && indi_usd >= 70 && indi_usd <= 90)   {Close_Orders_USD();} 
      if(Total_USD > 0 && indi_usd <= -70 && indi_usd >= -90) {Close_Orders_USD();}
       if(Total_USD > 0 && indi_usd >= 10 && indi_usd <= 12)   {Close_Orders_USD();} 
        if(Total_USD > 0 && indi_usd <= -10 && indi_usd >= -12) {Close_Orders_USD();}
//=====================================================================================++
if(Basket_of_warrants_GBP == true && Total_GBP == 0)
    {
    if(timeprev && indi_gbp >= 10 && indi_gbp <= 30)     OpenPlus_GBP();
     if(timeprev && indi_gbp <= -10 && indi_gbp >= -30)  OpenMinus_GBP();
     }
     if(Basket_of_warrants_GBP_Martin == true)
     {
     if(Total_GBP == 0)
     {
      if(indi_gbp >= 70 && indi_gbp <= 75)    plus_gbp  = true;
       if(indi_gbp <= -70 && indi_gbp >= -75) minus_gbp = true;
        if(!plus_gbp && !minus_gbp) return;
         Nusr_gbp = 0;
        }
         else
      {
   Nusr_gbp = Total_GBP/pairCount_GBP;
   if (Nusr_gbp > 3) return;
  }
    oLots = Lots * MathPow(Multipler,Nusr_usd);
  if(plus_gbp  == true && Uslovie_Plus_GBP ())     OpenMinus_GBP();
  if(minus_gbp == true && Uslovie_Minus_GBP())     OpenPlus_GBP();
     }
     if(Total_USD > 0 && indi_gbp >= 70 && indi_gbp <= 90)   {Close_Orders_GBP();} 
      if(Total_USD > 0 && indi_gbp <= -70 && indi_gbp >= -90) {Close_Orders_GBP();}
       if(Total_USD > 0 && indi_gbp >= 10 && indi_gbp <= 12)   {Close_Orders_GBP();} 
        if(Total_USD > 0 && indi_gbp <= -10 && indi_gbp >= -12) {Close_Orders_GBP();}
//=====================================================================================++
if(Basket_of_warrants_JPY == true && Total_JPY == 0)
    {
    if(timeprev && indi_jpy >= 10 && indi_jpy <= 30)     OpenPlus_JPY();
     if(timeprev && indi_jpy <= -10 && indi_jpy >= -30)  OpenMinus_JPY();
     }
     if(Basket_of_warrants_JPY_Martin == true)
     {
    if(Total_JPY == 0)
    {
     if(indi_jpy >= 70 && indi_jpy <= 75)    plus_jpy  = true;
       if(indi_jpy <= -70 && indi_jpy >= -75) minus_jpy = true;
        if(!plus_jpy && !minus_jpy) return;
         Nusr_jpy = 0;
        }
         else
      {
   Nusr_jpy = Total_JPY/pairCount_JPY;
   if (Nusr_jpy > 3) return;
  }
    oLots = Lots * MathPow(Multipler,Nusr_usd);
  if(plus_jpy  == true && Uslovie_Plus_GBP ())     OpenMinus_JPY();
  if(minus_jpy == true && Uslovie_Minus_GBP())     OpenPlus_JPY();
     }
     if(Total_JPY > 0 && indi_jpy >= 70 && indi_jpy <= 90)   {Close_Orders_JPY();} 
      if(Total_JPY > 0 && indi_jpy <= -70 && indi_jpy >= -90) {Close_Orders_JPY();}
       if(Total_JPY > 0 && indi_jpy >= 10 && indi_jpy <= 12)   {Close_Orders_JPY();} 
        if(Total_JPY > 0 && indi_jpy <= -10 && indi_jpy >= -12) {Close_Orders_JPY();}
        
//---
}
//---------Функция показания индикатора для усреднения--------+
bool Uslovie_Minus_JPY()
{
   bool res = false;
   if(Nusr_jpy == 0)  res = true;
   if(Nusr_jpy == 1 && indi_jpy <= -80 && indi_jpy >= -85) res = true;
   if(Nusr_jpy == 2 && indi_jpy <= -90 && indi_jpy >= -95) res = true;
return(res);
}
//---------Функция показания индикатора для усреднения--------+
bool Uslovie_Plus_JPY()
{
   bool res = false;
   if(Nusr_jpy == 0)  res = true;
   if(Nusr_jpy == 1 && indi_jpy >= 80  && indi_jpy <= 85)  res = true;
   if(Nusr_jpy == 2 && indi_jpy >= 90  && indi_jpy <= 95)  res = true;
return(res);
}
//---------Функция показания индикатора для усреднения--------+
bool Uslovie_Minus_GBP()
{
   bool res = false;
   if(Nusr_gbp == 0)  res = true;
   if(Nusr_gbp == 1 && indi_gbp <= -80 && indi_gbp >= -85) res = true;
   if(Nusr_gbp == 2 && indi_gbp <= -90 && indi_gbp >= -95) res = true;
return(res);
}
//---------Функция показания индикатора для усреднения--------+
bool Uslovie_Plus_GBP()
{
   bool res = false;
   if(Nusr_usd == 0)  res = true;
   if(Nusr_usd == 1 && indi_usd >= 80  && indi_usd <= 85)  res = true;
   if(Nusr_usd == 2 && indi_usd >= 90  && indi_usd <= 95)  res = true;
return(res);
}
//---------Функция показания индикатора для усреднения--------+
bool Uslovie_Minus_USD()
{
   bool res = false;
   if(Nusr_usd == 0)  res = true;
   if(Nusr_usd == 1 && indi_usd <= -80 && indi_usd >= -85) res = true;
   if(Nusr_usd == 2 && indi_usd <= -90 && indi_usd >= -95) res = true;
return(res);
}
//---------Функция показания индикатора для усреднения--------+
bool Uslovie_Plus_USD()
{
   bool res = false;
   if(Nusr_usd == 0)  res = true;
   if(Nusr_usd == 1 && indi_usd >= 80  && indi_usd <= 85)  res = true;
   if(Nusr_usd == 2 && indi_usd >= 90  && indi_usd <= 95)  res = true;
return(res);
}
//----------------------------------------------------------++
void OpenMinus_JPY()
{
  int i;
for(i=SIZE_jpy-1; i>=0; i --)
{
ticket = OrderSendReliable(array_jpy[i],OP_BUY,oLots,Ask,Slippage,0,0,"Puppeteer_JPY ",Magic_jpy,0,clrGreen);
 }
}
//----------------------------------------------------------++
void OpenPlus_JPY()
{
  int i;
for(i=SIZE_jpy-1; i>=0; i --)
{
ticket = OrderSendReliable(array_jpy[i],OP_SELL,oLots,Bid,Slippage,0,0,"Puppeteer_JPY ",Magic_jpy,0,clrRed);
 }
}
//-------------------Функция закрытия ордеров USD--------------------+
void Close_Orders_JPY()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderMagicNumber() == Magic_jpy)
{
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
{
if(OrderType() == OP_BUY)  if(OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrYellow)) Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
if(OrderType() == OP_SELL) if(OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrYellow)) Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
    }
   }
  }
 }
}
//-------------------Функция закрытия ордеров USD--------------------+
void Close_Orders_GBP()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderMagicNumber() == Magic_gbp)
{
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
{
if(OrderType() == OP_BUY)  if(OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrYellow)) Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
if(OrderType() == OP_SELL) if(OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrYellow)) Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
    }
   }
  }
 }
}
//----------------------------------------------------------++
void OpenMinus_GBP()
{
  int i,a;
for(i=Size_gbp-1; i>=0; i --)
{
ticket = OrderSendReliable(Array_gbp[i],OP_SELL,oLots,Bid,Slippage,0,0,"Puppeteer_GBP ",Magic_gbp,0,clrRed);
}
for(a=size_gbp-1; a >= 0; a--)
{
ticket = OrderSendReliable(array_gbp[a],OP_BUY,oLots,Ask,Slippage,0,0,"Puppeteer_GBP ",Magic_gbp,0,clrGreen);
 }
}

//----------------------------------------------------------++
void OpenPlus_GBP()
{
  int i,a;
for(i=Size_gbp-1; i>=0; i --)
{
ticket = OrderSendReliable(Array_gbp[i],OP_BUY,oLots,Ask,Slippage,0,0,"Puppeteer_GBP ",Magic_gbp,0,clrGreen);
}
for(a=size_gbp-1; a >= 0; a--)
{
ticket = OrderSendReliable(array_gbp[a],OP_SELL,oLots,Bid,Slippage,0,0,"Puppeteer_GBP ",Magic_gbp,0,clrRed);
 }
}
//-------------------Функция закрытия ордеров USD--------------------+
void Close_Orders_USD()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderMagicNumber() == Magic_usd)
{
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
{
if(OrderType() == OP_BUY)  if(OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrYellow)) Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
if(OrderType() == OP_SELL) if(OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrYellow)) Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
    }
   }
  }
 }
}
//-------------------Функция закрытия ордеров USD--------------------+
void Close_Orders()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
{
if(OrderType() == OP_BUY)  if(OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrYellow))Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
if(OrderType() == OP_SELL) if(OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrYellow))Print("Ордер закрыт успешно ! "+OrderSymbol());Alert("Ошибка закрытия № "+IntegerToString(GetLastError())+"  ордера по символу "+OrderSymbol());
    
   }
  }
 }
}
//----------------------------------------------------------++
void OpenMinus_USD()
{
  int i,a;
for(i=Size_usd-1; i>=0; i --)
{
ticket = OrderSendReliable(Array_usd[i],OP_BUY,oLots,Ask,Slippage,0,0,"Puppeteer_USD ",Magic_usd,0,clrGreen);
}
for(a=size_usd-1; a >= 0; a--)
{
ticket = OrderSendReliable(array_usd[a],OP_SELL,oLots,Bid,Slippage,0,0,"Puppeteer_USD ",Magic_usd,0,clrRed);
 }
}

//----------------------------------------------------------++
void OpenPlus_USD()
{
  int i,a;
for(i=Size_usd-1; i>=0; i --)
{
ticket = OrderSendReliable(Array_usd[i],OP_SELL,oLots,Bid,Slippage,0,0,"Puppeteer_USD ",Magic_usd,0,clrRed);
}
for(a=size_usd-1; a >= 0; a--)
{
ticket = OrderSendReliable(array_usd[a],OP_BUY,oLots,Ask,Slippage,0,0,"Puppeteer_USD ",Magic_usd,0,clrGreen);
 }
}

//+------------------------------------------------------------------+
int CountTrades_JPY()
{
   int count = 0;
   for(int i=OrdersTotal()-1; i >= 0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderMagicNumber() == Magic_jpy)     count++;
 }
 return(count);
}
  //+------------------------------------------------------------------+
int CountTrades_GBP()
{
   int count = 0;
   for(int i=OrdersTotal()-1; i >= 0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderMagicNumber() == Magic_gbp)     count++;
 }
 return(count);
}
//+------------------------------------------------------------------+
int CountTrades_USD()
{
   int count = 0;
   for(int i=OrdersTotal()-1; i >= 0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderMagicNumber() == Magic_usd)     count++;
 }
 return(count);
}//----------------Функция оброботки ошибок---------------------------+
int OrderSendReliable(string asymbol, int cmd, double volume, double aprice,
                 int slippage, double stoploss, double takeprofit,
                 string acomment, int magic, datetime expiration = 0, 
                 color arrow_color = CLR_NONE) 
{
   int err = GetLastError(); 
   err = 0; 
   bool exit_loop = false;
   bool limit_to_market = false; 

   err = GetLastError(); 
   err = 0; 
   ticket = -1;

   if ((cmd == OP_BUY) || (cmd == OP_SELL)) 
   {
      int cnt = 0;
      while (!exit_loop) 
      {
         if (IsTradeAllowed()) 
         {
       
      // Comment(asymbol,"\n",cmd,"\n",volume,"\n",aprice,"\n",slippage,"\n",stoploss,"\n",takeprofit,"\n",acomment,"\n",magic);
       
            ticket = OrderSend(asymbol, cmd, volume, aprice, slippage, 
                           stoploss, takeprofit, acomment, magic, 
                           expiration, arrow_color);
            err = GetLastError();
         } 
         else 
        {
           cnt++;
        } 
         switch (err) 
         {
            case ERR_NO_ERROR:
               exit_loop = true;
               break;
               
            case ERR_SERVER_BUSY:
            case ERR_NO_CONNECTION:
            case ERR_INVALID_PRICE:
            case ERR_OFF_QUOTES:
            case ERR_BROKER_BUSY:
            case ERR_TRADE_CONTEXT_BUSY: 
               cnt++;
               break;
               
            case ERR_PRICE_CHANGED:
            case ERR_REQUOTE:
               RefreshRates();
               continue; 
               
            default:
               exit_loop = true;
               break; 
               
         }  // end switch 

         if (cnt > retries) 
             exit_loop = true; 
             
         if (!exit_loop) 
         {
            Sleep(1000); 
            RefreshRates(); 
         }
         
         if (exit_loop) 
         {
            if (err != ERR_NO_ERROR) 
            {
               Alert("Ошибка : " + IntegerToString(err)); 
            }
         }
      }
      
      if (err == ERR_NO_ERROR) 
      {
         if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) 
         return(ticket);
      } 
      Alert("Ошибка открытия ордера после " + IntegerToString(cnt) + " попыток."+" по символу "+OrderSymbol());
      Alert("Ошибка : " + IntegerToString(err)); 
      return(-1); 
   }
   return(-1);
}
//+------------------------------------------------------------------+
void SHOW_INDICATOR() {
   string name_0 = Gls_104 + "L_1";
   if (ObjectFind(name_0) == -1) {
      ObjectCreate(name_0, OBJ_LABEL, 0, 0, 0);
      ObjectSet(name_0, OBJPROP_CORNER, 0);
      ObjectSet(name_0, OBJPROP_XDISTANCE, 270);
      ObjectSet(name_0, OBJPROP_YDISTANCE, 5);
   }
   ObjectSetText(name_0, "Puppeteer Auto System. v.2.0", 28, "Arial", clrYellow);
  
   name_0 = Gls_104 + "L_3";
   if (ObjectFind(name_0) == -1) {
      ObjectCreate(name_0, OBJ_LABEL, 0, 0, 0);
      ObjectSet(name_0, OBJPROP_CORNER, 0);
      ObjectSet(name_0, OBJPROP_XDISTANCE, 290);
      ObjectSet(name_0, OBJPROP_YDISTANCE, 45);
   }
   ObjectSetText(name_0, "Skype: denis77515.  e-mail: denis77515@gmail.com", 14, "Arial", clrRed);
   }