//+------------------------------------------------------------------+
//|                                               tradefunctions.mq4 |
//|                                                       Cam Ballew |
/* A collection of well-used functions                              */
// errorchecking
// NewBar
// CountOpens
// ManageStops
// close_trade
// close_pending
// GetMagic
// GetPeriod
// PitBullBuy
// PitBullSell
//+------------------------------------------------------------------+
#include <stdlib.mqh>
#property copyright "Cam Ballew"
#property library 
//+------------------------------------------------------------------+/
void errorchecking(int err)
{
   switch (err)
   {
         case 4:           //ERR_SERVER_BUSY
            Sleep(1000);
            RefreshRates();
         case 6:           //ERR_NO_CONNECTION
            Sleep(1000);
            RefreshRates();
         case 128:         //ERR_TRADE_TIMEOUT
            Sleep(1000);
            RefreshRates();
         case 129:         //ERR_INVALID_PRICE
            Sleep(1000);
            RefreshRates();
         case 130:         //ERR_INVALID_STOPS
            Sleep(1000);
            RefreshRates();
         case 131:         //ERR_INVALID_TRADE_VOLUME
            Sleep(1000);
            RefreshRates();
         case 132:         //RR_MARKET_CLOSED
            Sleep(1000);
            RefreshRates();
         case 133:         //ERR_TRADE_DISABLED
            Sleep(1000);
            RefreshRates();
         case 134:         //ERR_NOT_ENOUGH_MONEY
            Sleep(1000);
            RefreshRates();
         case 135:         //ERR_PRICE_CHANGED
            Sleep(1000);
            RefreshRates();
         case 136:         //ERR_OFF_QUOTES
            Sleep(1000);
            RefreshRates();
         case 137:         //ERR_BROKER_BUSY
            Sleep(1000);
            RefreshRates();
         case 138:         //ERR_REQUOTE
            Sleep(1000);
            RefreshRates();
         case 139:         //ERR_ORDER_LOCKED
            Sleep(1000);
            RefreshRates();
         case 140:         //ERR_LONG_POSITIONS_ONLY_ALLOWED
            Sleep(1000);
            RefreshRates();
         case 141:         //ERR_TOO_MANY_REQUESTS
            Sleep(1000);
            RefreshRates();
         case 142:         //??
            Sleep(1000);
            RefreshRates();
         case 143:         //??
            Sleep(1000);
            RefreshRates();
         case 144:         //??
            Sleep(1000);
            RefreshRates();
         case 145:         //ERR_TRADE_MODIFY_DENIED
            Sleep(1000);
            RefreshRates();
         case 146:         //ERR_TRADE_CONTEXT_BUSY
            Sleep(1000);
            RefreshRates();
         case 147:         //ERR_TRADE_EXPIRATION_DENIED
            Sleep(1000);
            RefreshRates();
         case 148:         //ERR_TRADE_TOO_MANY_ORDERS
            Sleep(1000);
            RefreshRates();
         case 149:         //ERR_TRADE_HEDGE_PROHIBITED
            Sleep(1000);
            RefreshRates();
         case 150:         //ERR_TRADE_PROHIBITED_BY_FIFO
            Sleep(1000);
            RefreshRates();
   } 
   return;  
}
//+------------------------------------------------------------------+
bool NewBar()
{
   static datetime dt = 0;
   if (Time[0] != dt)//open time of the current bar
   {
      dt = Time[0];
      return(true);
   }
   return(false);
}
//***** Count open orders ****************************************************************
int CountOpenOrders(int PairNumber,int openorders,int buys,int sells,int ticket, int type)
{   
   openorders=0;buys=0;sells=0;
   for(int cnt=0;cnt<OrdersTotal();cnt++)   
   {
     OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
	  if ((OrderSymbol()==Symbol() && (OrderMagicNumber()==PairNumber)) 
	     && (OrderType()==OP_BUY || OrderType()==OP_SELL))
	  {  ticket = OrderTicket();
	     type = OrderType();
	     if(OrderType()==OP_BUY) buys++; else sells++;
	  	  openorders++;
	  }
   } //Print(" open: ",open.orders," buys: ",buys," sells: ",sells);
   return(PairNumber+openorders+buys+sells+ticket+type);
}

//+------------------------------------------------------------------+
void ManageStops_MA(double stop.level,int PairNumber)
{
   bool   result=false;
   int    error;
   double stop;
      for(int j = 0;j <= OrdersTotal()-1;j++)
      {
         if(OrderSelect(j,SELECT_BY_POS,MODE_TRADES))
         {
            if(OrderType()==OP_BUY&&OrderSymbol()==Symbol()&& OrderMagicNumber()==PairNumber)
              {
               stop = stop.level;//SetStops("buy",stop.period);
               //Print(" Orderstop ",OrderStopLoss()," buystop ",stop);
               if(OrderStopLoss()<stop)
                 result=OrderModify(OrderTicket(),OrderOpenPrice(),stop,OrderTakeProfit(),CLR_NONE);
                 if(result!=TRUE) { error=GetLastError();if(error!=0) Print("Error ModifyBuyOrder(",error,"): ",ErrorDescription(error));}
              }
            if(OrderType()==OP_SELL&&OrderSymbol()==Symbol()&& OrderMagicNumber()==PairNumber)
              {
               stop =  stop.level;//SetStops("sell",stop.period);
               //Print(" Orderstop ",OrderStopLoss()," sellstop ",stop);
               if(OrderStopLoss()>stop)
                 result=OrderModify(OrderTicket(),OrderOpenPrice(),stop,OrderTakeProfit(),CLR_NONE);
                 if(result!=TRUE) { error=GetLastError();if(error!=0) Print("Error ModifySellOrder(",error,"): ",ErrorDescription(error));}
              }
         }
       }
   return;
}
//+------------------------------------------------------------------+
//| script "close all open orders"     |
//+------------------------------------------------------------------+
void close_trade(int ID)
  {
//----
   for (int cnt = OrdersTotal()-1; cnt >= 0; cnt--)
      {
      if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)) continue;
      if(OrderSymbol()!=Symbol()) continue;
      if(OrderMagicNumber()!=ID) continue;
      if ((OrderType() == OP_BUY || OrderType() == OP_SELL))
        {
        //---- close each market order
        close();
        }
      int type   = OrderType();
      bool result = false;   
      switch(type)
      {
        //Close opened long positions
        case OP_BUY       : result=true;break;
        //Close opened short positions
        case OP_SELL      : result=true;break;
        //Close pending orders
        case OP_BUYLIMIT  : result = OrderDelete( OrderTicket() );break;
        case OP_BUYSTOP   : result = OrderDelete( OrderTicket() );break;
        case OP_SELLLIMIT : result = OrderDelete( OrderTicket() );break;
        case OP_SELLSTOP  : result = OrderDelete( OrderTicket() );break;
      }
      if(result == false)
      {  Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() );
         Sleep(3000);
      }  

      }
//----
   SendMail("Closed", "all trades closed.");

   return;
  }
//+------------------------------------------------------------------+
int close()
  {
   bool   result;
   double price;
   int    cmd,error;
//----
   if(OrderSelect(0,SELECT_BY_POS,MODE_TRADES))
     {
      cmd=OrderType();
      //---- first order is buy or sell
      if(cmd==OP_BUY || cmd==OP_SELL)
        {
         while(true)
           {
               if(cmd==OP_BUY) price=MarketInfo(OrderSymbol(),MODE_BID);
               else            price=MarketInfo(OrderSymbol(),MODE_ASK);
            //Print(" # ",OrderTicket()," type ",cmd," price ",price);
            result=OrderClose(OrderTicket(),OrderLots(),price,3,Gold);
            if(result!=TRUE) { error=GetLastError(); errorchecking(error);
            if(error!=0) Print("LastError = ",error); }
            else break;
           }
        }
     }
   else Print( "Error when order select ", GetLastError());
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| script "close all pending orders"     |
//+------------------------------------------------------------------+
void close_pending(int ID)
{
  int total = OrdersTotal();
  for(int i=total-1;i>=0;i--)
  {
    OrderSelect(i, SELECT_BY_POS);
    int type   = OrderType();

    bool result = false;
    
    switch(type)
    {
      //Close opened long positions
      case OP_BUY       : result=true;break;
      //Close opened short positions
      case OP_SELL      : result=true;break;
      //Close pending orders
      case OP_BUYLIMIT  : result = OrderDelete( OrderTicket() );break;
      case OP_BUYSTOP   : result = OrderDelete( OrderTicket() );break;
      case OP_SELLLIMIT : result = OrderDelete( OrderTicket() );break;
      case OP_SELLSTOP  : result = OrderDelete( OrderTicket() );break;
    }
    
    if(result == false)
    {
      Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() );
      Sleep(3000);
    }  
  }
   return;
}
int GetMagic(string sym)
{  int magic.num;

   magic.num = GetPairID(sym);
   magic.num = magic.num + 100;

return(magic.num);
}

int GetPairID(string sym)
{  string pair.name[26];
   int pairID;
   //ArrayInitialize(pair.name,"");
   pair.name[0] =  "AUDCADm";
   pair.name[1] =  "AUDCHFm";
   pair.name[2] =  "AUDJPYm";
   pair.name[3] =  "AUDNZDm";
   pair.name[4] =  "AUDUSDm";
   pair.name[5] =  "CADJPYm";
   pair.name[6] =  "CHFJPYm";
   pair.name[7] =  "EURAUDm";
   pair.name[8] =  "EURCADm";
   pair.name[9] =  "EURCHFm";
   pair.name[10]=  "EURGBPm";
   pair.name[11]=  "EURJPYm";
   pair.name[12]=  "EURNZDm";
   pair.name[13]=  "EURUSDm";
   pair.name[14]=  "GBPAUDm";
   pair.name[15]=  "GBPCADm";
   pair.name[16]=  "GBPCHFm";
   pair.name[17]=  "GBPJPYm";
   pair.name[18]=  "GBPNZDm";
   pair.name[19]=  "GBPUSDm";
   pair.name[20]=  "NZDCHFm";
   pair.name[21]=  "NZDJPYm";
   pair.name[22]=  "NZDUSDm";
   pair.name[23]=  "USDCADm";
   pair.name[24]=  "USDCHFm";
   pair.name[25]=  "USDJPYm";
   
   for(int i = 0;i<ArraySize(pair.name);i++)
   {  if(pair.name[i] == sym) {pairID = i;break;}
   }
   return(pairID);
}

//+------------------------------------------------------------------+
int GetPeriod(int period,int dir)
{
   switch(period)
   {   case 10080:
         int shorter = 1440;
         int shortest = 240;
         break;
       case 1440:
         int longer = 10080;
         int longest = 10080;
         shorter = 240;
         shortest = 60;
         break;
       case 240:
         longer = 1440;
         longest = 10080;
         shorter = 60;
         shortest = 30;
         break;
       case 60:
         longer = 240;
         longest = 1440;
         shorter = 30;
         shortest = 15;
         break;
       case 30:
         longer = 60;
         longest = 240;
         shorter = 15;
         shortest = 5;
         break;
       case 15:
         longer = 30;
         longest = 60;
         shorter = 5;
         shortest = 1;
       case 5:
         longer = 15;
         longest = 30;
         shorter = 1;
         shortest = 1;
       case 1:
         longer = 5;
         longest = 15;
         break;
       default: break;
   }  
   if(dir == 1) return(longer);
   if(dir == 2) return(longest);else return(shorter);
}
//+------------------------------------------------------------------+

void PitBullBuy(double Lot,double entry)
  {

   OrderSend("AUDJPYm",OP_BUY, Lot, MarketInfo("AUDJPYm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("NZDJPYm",OP_BUY, Lot, MarketInfo("NZDJPYm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("GBPJPYm",OP_BUY, Lot, MarketInfo("GBPJPYm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("EURJPYm",OP_BUY, Lot, MarketInfo("EURJPYm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("USDJPYm",OP_BUY, Lot, MarketInfo("USDJPYm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);

   OrderSend("EURUSDm",OP_BUY, Lot, MarketInfo("EURUSDm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("NZDUSDm",OP_BUY, Lot, MarketInfo("NZDUSDm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("GBPUSDm",OP_BUY, Lot, MarketInfo("GBPUSDm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("EURGBPm",OP_BUY, Lot, MarketInfo("EURGBPm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("AUDUSDm",OP_BUY, Lot, MarketInfo("AUDUSDm",MODE_ASK), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
    
   return(0);
  }
//+----------------------------------------------------------------------------------------------------+

void PitBullSell(double Lot,double entry)
  {

   OrderSend("AUDJPYm",OP_SELL, Lot, MarketInfo("AUDJPYm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("NZDJPYm",OP_SELL, Lot, MarketInfo("NZDJPYm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("GBPJPYm",OP_SELL, Lot, MarketInfo("GBPJPYm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("EURJPYm",OP_SELL, Lot, MarketInfo("EURJPYm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("USDJPYm",OP_SELL, Lot, MarketInfo("USDJPYm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);

   OrderSend("EURUSDm",OP_SELL, Lot, MarketInfo("EURUSDm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("NZDUSDm",OP_SELL, Lot, MarketInfo("NZDUSDm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("GBPUSDm",OP_SELL, Lot, MarketInfo("GBPUSDm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("EURGBPm",OP_SELL, Lot, MarketInfo("EURGBPm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
   OrderSend("AUDUSDm",OP_SELL, Lot, MarketInfo("AUDUSDm",MODE_BID), 2, NULL, NULL, "@ "+DoubleToStr(entry,4), 0, 0, CLR_NONE);
    
   return(0);
  }
//+----------------------------------------------------------------------------------------------------+

double GetLots(string type, double stop, double risk)
{
   double stopvalue, riskdollars,stop_pipsperlot,maxlots=50;
   double digits = MarketInfo(Symbol(),MODE_DIGITS);
   
   if(digits>=4 && type=="buy") stopvalue=MathAbs(stop-Ask)*10000;
   if(digits>=4 && type=="sell") stopvalue=MathAbs(Bid-stop)*10000;
   if(digits<=3 && type=="buy") stopvalue=MathAbs(stop-Ask)*100;
   if(digits<=3 && type=="sell") stopvalue=MathAbs(Bid-stop)*100;

   riskdollars = NormalizeDouble(AccountBalance() * risk / 100,2);
   stop_pipsperlot = stopvalue * MarketInfo( Symbol(), MODE_TICKVALUE)*10;
   double Lots = NormalizeDouble((riskdollars/*number.of.orders*/) / stop_pipsperlot,2);// order size is function of risk, & size of stop
   //Print(" risk: ",riskdollars," stopValue: ",stopvalue);
   if(Lots >= maxlots) Lots = maxlots;
return(Lots);
}

//+------------------------------------------------------------------+
int Modify(int ticket,double stop, double target)
  {
   bool   result;
   double stop_loss,point;
   int    cmd,total,error;

      result=OrderModify(ticket,0,stop,target,0,CLR_NONE);
      if(result!=TRUE) { error=GetLastError(); Print("LastError = ",error); }
      else error=0;

   return(result);
  }

