//+------------------------------------------------------------------+
//|                                               MACCIMO Trader v2  |
//|                             Copyright © 2009, Juan Cruz Baudino  |
//|                                                                  |
//| Please if you like the code and got some reward from this you    |
//| may don't mind to make a donation to the author.                 |
//| Paypal account: cacuscacus@gmail.com                             |
//| If you make some modifications please be kind to inform me       |
//| about this.                                                      |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2009, Juan Cruz Baudino."
#property link      "cacuscacus@gmail.com"
#include <stdlib.mqh>
#include <stderror.mqh>

extern string s1 = "====Basic settings====";
extern double Risk = 0.3;
extern double Lots = 0.01;
extern bool LotCalcOverBal = False;
extern double StopLoss = 100.0;
extern double TakeProfit = 45.0;
extern int Trailingstop = 5;
extern bool TickByTickTrailing = true;
extern bool RecoveryMode = true;
extern double RecoveryModeMulti = 2;
extern int SlipPage = 3;
extern int Magic = 4985;


extern string s2 = "====Time based filters====";
extern bool DayFilter = true;
extern int Day1 = 6;
extern int Day2 = 0;
extern int StartDayMonth = 1;
extern int StopDayMonth = 31;
extern bool HourFilter = False;
extern int GMTOffset = 3;
extern int Session1 = 1;
extern int Session2 = 0;
extern int Session3 = 0;
extern int Session1OpenHour = 0;
extern int Session1CloseHour = 0;
extern int Session2OpenHour = 0;
extern int Session2CloseHour = 0;
extern int Session3OpenHour = 0;
extern int Session3CloseHour = 0;


extern string s3 = "===Indicators logic and orders===";
extern int MaxOrders = 5;
extern int PipDifMin = 10;
extern double PerCCI1 = 14.0;
extern double CCIRange = 136.0;
extern double PerIMA1 = 80.0;
extern double PerIMA2 = 295.0;
extern double PerIMA3 = 588.0;
extern double IMATrendRate1 = 0.57;
extern double IMATrendRate2 = 0.13;
extern int PipsFromIMA2 = 1;
extern int PipsFromIMA = 12;
extern string s4 = "==== Extras ====";
extern string Comentario = "MACCIMO";
extern color ColorTXT = Red;
extern bool showInfo = False;
//..........................
extern string	Parameters              = "StochasticPerceptron";
extern string	Parameters_Stochastic   = "Stochastic";
extern int       Kperiod               = 5;
extern int       Dperiod               = 3;	
extern int       slowing               = 3;
extern string	Parameters_Perceptron   = "Perceptron";
extern int       shag                  = 0;
extern int       x1                    = 0;
extern int       x2                    = 0;
extern int       x3                    = 0;
extern int       x4                    = 0;
datetime GMT;
int time;
int bandTiempo = 0;
double maxdd,maxpercentdd; 
int banderaBalance=0;
bool BanderaRecover = true;
int SumaBeneficios = 0;
int cantidadOrdenesHistorial = 0;

double   myPoint;

int deinit() {
Print("MaxDD: ",maxdd);
Print("MaxPercDD: ",maxpercentdd);
return(0);
}
int init() {
   if (!IsTesting()) BanderaRecover = True;
   myPoint = SetPoint(Symbol());
// Following is all handled where needed by using myPoint
//   if (Digits == 5) {
//   StopLoss=StopLoss*10;
//   TakeProfit=TakeProfit*10;
//   SlipPage=SlipPage*10;
//   PipDifMin=PipDifMin*10;
//   IMATrendRate1=IMATrendRate1*10;
//   IMATrendRate2=IMATrendRate2*10;
//   PipsFromIMA=PipsFromIMA*10;
//   PipsFromIMA2=PipsFromIMA2*10;}
   return (0);
}

int start() {

   SumaBeneficios = 0;
   if (BanderaRecover) {
      BanderaRecover = false;
      cantidadOrdenesHistorial = RecuperarOrdenes();
      banderaBalance = SumaBeneficios;
      Print("Ordenes en el historial: ", cantidadOrdenesHistorial, " beneficios: ", DoubleToStr(SumaBeneficios, 2));
   }
   
   while (Session1OpenHour<0) Session1OpenHour+=24;
   while (Session1OpenHour>24) Session1OpenHour-=24;
   if (Session1CloseHour<0) Session1CloseHour=Session1OpenHour-Session1CloseHour;
   while (Session1CloseHour>24) Session1CloseHour-=24;
   if (Session1CloseHour == 0) Session1CloseHour = 24;      
   
   while (Session2OpenHour<0) Session2OpenHour+=24;
   while (Session2OpenHour>24) Session2OpenHour-=24;
   if (Session2CloseHour<0) Session2CloseHour=Session2OpenHour-Session2CloseHour;
   while (Session2CloseHour>24) Session2CloseHour-=24;
   if (Session2CloseHour == 0) Session2CloseHour = 24;      
   
   while (Session3OpenHour<0) Session3OpenHour+=24;
   while (Session3OpenHour>24) Session3OpenHour-=24;
   if (Session3CloseHour<0) Session3CloseHour=Session3OpenHour-Session3CloseHour;
   while (Session3CloseHour>24) Session3CloseHour-=24;
   if (Session3CloseHour == 0) Session3CloseHour = 24;      
   GMT = TimeCurrent() - (GMTOffset * 3600); 
   time = GMT;    


if (TickByTickTrailing){
   //&&&&& TRAILING &&&&&&&&&&&&&&&&&&&&&&&&&      
   if(Trailingstop>0){Trailing();}
   //&&&&& TRAILING &&&&&&&&&&&&&&&&&&&&&&&&&    
  }
   
double OpenProfit = AccountEquity()-AccountBalance();
   
   if (OpenProfit<maxdd){ maxdd = OpenProfit;}
   if ((OpenProfit/AccountBalance()*100)<maxpercentdd)
   { maxpercentdd = (OpenProfit/AccountBalance()*100);}

  
   int ticket1;
   if (Time[0] == bandTiempo) return (0);
   bandTiempo = Time[0];
   double puntos = Point;
   bool Trading=true;
   if (TimeDay(TimeCurrent())==Day1 && DayFilter) Trading=false;
   if (TimeDay(TimeCurrent())==Day2 && DayFilter) Trading=false;
   
   if (!TickByTickTrailing){
   //&&&&& TRAILING &&&&&&&&&&&&&&&&&&&&&&&&&      
   if(Trailingstop>0){Trailing();}
   //&&&&& TRAILING &&&&&&&&&&&&&&&&&&&&&&&&&    
  }
   

   double Lots2=0;
   if (Risk>0){
   Lots=MMLots(Risk, AccountFreeMargin());
   if (LotCalcOverBal) Lots=MMLots(Risk, AccountBalance());
   Lots2=Lots;
   if (RecoveryMode){Lots=RecoveryLot(Lots);}
   }
//##############################################################################################
//##########CONTROLO LA PERDIDA MAXIMA Y EL PORCENTAJE DE PERDIDA###############################

   if (showInfo){
   ObjectCreate( "B/E", OBJ_LABEL,0,0,0,0,0,0);
   ObjectSet(    "B/E", OBJPROP_CORNER,3);
   ObjectSet(    "B/E", OBJPROP_XDISTANCE, 3);
   ObjectSet(    "B/E", OBJPROP_YDISTANCE, 30);
   ObjectSetText("B/E", "B/E: $"+DoubleToStr(NormalizeDouble(AccountBalance(),2),1)+"/"+DoubleToStr(NormalizeDouble(AccountEquity(),2),1),24,"Impact",ColorTXT);
   
   ObjectCreate( "MaxDD", OBJ_LABEL,0,0,0,0,0,0);
   ObjectSet(    "MaxDD", OBJPROP_CORNER,3);
   ObjectSet(    "MaxDD", OBJPROP_XDISTANCE, 3);
   ObjectSet(    "MaxDD", OBJPROP_YDISTANCE, 2);
   ObjectSetText("MaxDD", "RDD Máx: $"+DoubleToStr(NormalizeDouble(maxdd,2),1)+"/"+DoubleToStr(NormalizeDouble(maxpercentdd,2),1)+"%",24,"Impact",ColorTXT);
   }
   
   if (showInfo && Lots<Lots2 && RecoveryMode){
   ObjectCreate( "Recover", OBJ_LABEL,0,0,0,0,0,0);
   ObjectSet(    "Recover", OBJPROP_CORNER,1);
   ObjectSet(    "Recover", OBJPROP_XDISTANCE, 3);
   ObjectSet(    "Recover", OBJPROP_YDISTANCE, 2);
   ObjectSetText("Recover", "Recovery Mode Activated",24,"Impact",ColorTXT);
   }
   if (showInfo && (Lots>=Lots2 || !RecoveryMode) && ObjectFind("Recover")!=-1) ObjectDelete("Recover");
   
   
   if (HourFilter && showInfo){
   if (((IsTradeTime(1)!=1 || IsTradeTime(2)!=1 || IsTradeTime(3)!=1))) {
   
   ObjectCreate( "Notrade", OBJ_LABEL,0,0,0,0,0,0);
   ObjectSet(    "Notrade", OBJPROP_CORNER,0);
   ObjectSet(    "Notrade", OBJPROP_XDISTANCE, 15);
   ObjectSet(    "Notrade", OBJPROP_YDISTANCE, 2);
   ObjectSetText("Notrade", "No trading session, its "+TimeHour(TimeCurrent())+":"+TimeMinute(TimeCurrent()),24,"Impact",ColorTXT);
   }
   if (((IsTradeTime(1) || IsTradeTime(2) || IsTradeTime(3)))) ObjectDelete("Notrade");  
   //}
 }
//------------------------------------------------------------------------------------------------------
//======================================================================================================
   
   
    
   
   
   double CCI1 = iCCI(NULL, 0, PerCCI1, PRICE_CLOSE, 0);
   double CCI2 = iCCI(NULL, 0, PerCCI1, PRICE_CLOSE, 1);
   double IMA11 = iMA(NULL, 0, PerIMA1, 0, MODE_SMA, PRICE_MEDIAN, 0);
   double IMA12 = iMA(NULL, 0, PerIMA1, 0, MODE_SMA, PRICE_MEDIAN, 1);
   double IMA21 = iMA(NULL, 0, PerIMA2, 0, MODE_SMA, PRICE_MEDIAN, 0);
   double IMA22 = iMA(NULL, 0, PerIMA2, 0, MODE_SMA, PRICE_MEDIAN, 1);
   double IMA31 = iMA(NULL, 0, PerIMA3, 0, MODE_SMA, PRICE_MEDIAN, 0);
   double IMA32 = iMA(NULL, 0, PerIMA3, 0, MODE_SMA, PRICE_MEDIAN, 1);
   int OpenOrders = 0;
   double OrderOpenPrice1 = 0;
   for (int i = 0; i < OrdersTotal(); i++) {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         if (OrderMagicNumber() == Magic) {
            if (StringFind(OrderSymbol(), Symbol(), 0) != -1) {
               OpenOrders++;
               OrderOpenPrice1 = OrderOpenPrice();
               if (OrderType() == OP_BUY && CCI2 > CCIRange && CCI1 < CCI2 && Bid - IMA11 > PipsFromIMA * myPoint) {
                  waitForContext();
                  OrderClose(OrderTicket(), OrderLots(), NormalizeDouble(Bid,Digits), SlipPage, Violet);
                  return (0);
               }
               if (OrderType() == OP_SELL && CCI2 < (-CCIRange) && CCI1 > CCI2 && Ask - IMA11 < (-PipsFromIMA) * myPoint) {
                  waitForContext();
                  OrderClose(OrderTicket(), OrderLots(), NormalizeDouble(Ask,Digits), SlipPage, Violet);
                  return (0);
               }
            }
         }
      }
   }
   if (OpenOrders < MaxOrders && TimeDay(TimeCurrent())<StopDayMonth && TimeDay(TimeCurrent())>StartDayMonth && (!HourFilter || IsTradeTime(1) || IsTradeTime(2) || IsTradeTime(3))) {
      
      
      ticket1 = -10;
      if (perceptron()<0&&(IMA21 - IMA22 > IMATrendRate1 * myPoint && IMA31 - IMA32 > IMATrendRate2 * myPoint && IMA11 > IMA21 && CCI2 < (-CCIRange) && CCI1 > CCI2 && Ask - IMA11 < (-PipsFromIMA2) * myPoint &&
         OrderOpenPrice1 == 0.0 || Ask - OrderOpenPrice1 < (-PipDifMin) * myPoint && Trading))  {
         ticket1 = OpenTrade(OP_BUY, Lots,  StopLoss,  TakeProfit, Symbol() + " " + "MACCIMO BUY " + Comentario,  Magic);
         if (ticket1 > 0) Alert(Symbol() + "-" + "cacus: comprando");
      }
      if (perceptron()>0&&(IMA21 - IMA22 < (-IMATrendRate1) * myPoint && IMA31 - IMA32 < (-IMATrendRate2) * myPoint && IMA11 < IMA21 && CCI2 > CCIRange && CCI1 < CCI2 && Bid - IMA11 > PipsFromIMA2 * myPoint &&
         OrderOpenPrice1 == 0.0 || Bid - OrderOpenPrice1 > PipDifMin * myPoint && Trading)) {
         ticket1 = OpenTrade(OP_SELL, Lots, StopLoss , TakeProfit , Symbol() + " " + "MACCIMO SELL " + Comentario, Magic);
         if (ticket1 > 0) Alert(Symbol() + "-" + "cacus: vendiendo");
      }
   }
   
   return (0);
}

int IsTradeTime(int Session) {
   if (Session == 1 && Session1==1){
   if (Session1OpenHour < Session1CloseHour && TimeHour(time) < Session1OpenHour || TimeHour(time) >= Session1CloseHour) return (0);
   if (Session1OpenHour > Session1CloseHour && (TimeHour(time) < Session1OpenHour && TimeHour(time) >= Session1CloseHour)) return (0);
   if (Session1CloseHour == 0) Session1CloseHour = 24;
   if (TimeHour(time) == Session1CloseHour - 1 && TimeMinute(time) >= 55) return (0);
   return (1);
   }
   if (Session == 2 && Session2==1){
   if (Session2OpenHour < Session2CloseHour && TimeHour(time) < Session2OpenHour || TimeHour(time) >= Session2CloseHour) return (0);
   if (Session2OpenHour > Session2CloseHour && (TimeHour(time) < Session2OpenHour && TimeHour(time) >= Session2CloseHour)) return (0);
   if (Session2CloseHour == 0) Session2CloseHour = 24;
   if (TimeHour(time) == Session2CloseHour - 1 && TimeMinute(time) >= 55) return (0);
   return (1);
   }
   if (Session == 3 && Session3==1){
   if (Session3OpenHour < Session3CloseHour && TimeHour(time) < Session3OpenHour || TimeHour(time) >= Session3CloseHour) return (0);
   if (Session3OpenHour > Session3CloseHour && (TimeHour(time) < Session3OpenHour && TimeHour(time) >= Session3CloseHour)) return (0);
   if (Session3CloseHour == 0) Session3CloseHour = 24;
   if (TimeHour(time) == Session3CloseHour - 1 && TimeMinute(time) >= 55) return (0);
   return (1);
   }
   
}

void Trailing() {

      double Ask1 = GetAsk() + Trailingstop * myPoint;
      double Bid1 = GetBid() - Trailingstop * myPoint;
      if (OrdersTotal() > 0) {
         for (int i = 0; i < OrdersTotal(); i++) {
            OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
            if (OrderType() == OP_SELL && OrderSymbol() == Symbol() && OrderMagicNumber() == Magic) {
               if (GetAsk() < OrderOpenPrice() - Trailingstop * myPoint && Ask1 < OrderStopLoss()) {
                  waitForContext();
                  OrderModify(OrderTicket(), OrderOpenPrice(), Ask1, OrderTakeProfit(), 0, Green);
                  return (0);
               }
            }
            if (OrderType() == OP_BUY && OrderSymbol() == Symbol() && OrderMagicNumber() == Magic) {
               if (GetBid() > OrderOpenPrice() + Trailingstop * myPoint && Bid1 > OrderStopLoss()) {
                  waitForContext();
                  OrderModify(OrderTicket(), OrderOpenPrice(), Bid1, OrderTakeProfit(), 0, Green);
                  return (0);
               }
            }
         }
      }}
  
double GetBid() {
   return (NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits));
}

double GetAsk() {
   return (NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits));
}      




double SetPoint(string mySymbol)
{
   double mPoint, myDigits;
   
   myDigits = MarketInfo (mySymbol, MODE_DIGITS);
   if (myDigits < 4) mPoint = 0.01; else mPoint = 0.0001;   
   return(mPoint);
}

int OpenTrade(int signal, double mLots, double StopLoss, double TakeProfit, string msg, int MagicNumber)
{  
  int ticket, err;
  double TPprice,STprice;
  
   RefreshRates();
   
   if (signal==OP_BUY) 
   {
   double Ask1=NormalizeDouble(Ask,Digits);
     waitForContext();
     ticket=OrderSend(Symbol(),OP_BUY,mLots,Ask1,SlipPage,0,0,msg,MagicNumber,0,Green);
      if (ticket > 0)
      {
           if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) ) 
           {
           if (StopLoss != 0 || TakeProfit != 0)
	        {
            TPprice = 0;
            if (TakeProfit > 0)
            {
              TPprice = Ask + TakeProfit * myPoint;
		        TPprice = ValidTakeProfit(OP_BUY,Ask, TPprice);
		      }
            STprice = 0;
            if (StopLoss > 0)
            {
              STprice = Ask - StopLoss * myPoint;
		        STprice = ValidStopLoss(OP_BUY,Bid, STprice);
		      }   
 // Normalize stoploss / takeprofit to the proper # of digits.
            if (Digits > 0) 
            {
              STprice = NormalizeDouble( STprice, Digits);
              TPprice = NormalizeDouble( TPprice, Digits); 
            }
            waitForContext();
		      OrderModify(ticket, OrderOpenPrice(), STprice, TPprice, 0, LightGreen);
		     }
		   
		   }
         
      }
   } 
   else if (signal==OP_SELL) 
   {
   double Bid1=NormalizeDouble(Bid,Digits);
      waitForContext();
      ticket=OrderSend(Symbol(),OP_SELL,mLots,Bid1,SlipPage,0,0,msg,MagicNumber,0,Red);
      if (ticket > 0)
      {
         if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) ) 
         {
           if (StopLoss != 0 || TakeProfit != 0)
	        {
            TPprice = 0;
            if (TakeProfit > 0)
            {
              TPprice=Bid - TakeProfit * myPoint;
		        TPprice = ValidTakeProfit(OP_SELL,Bid, TPprice); 
		        
            }
            STprice = 0;
            if (StopLoss > 0)
            {
              STprice = Bid + StopLoss * myPoint;
		        STprice = ValidStopLoss(OP_SELL,Ask, STprice); 
		      }  
 // Normalize stoploss / takeprofit to the proper # of digits.
            if (Digits > 0) 
            {
              STprice = NormalizeDouble( STprice, Digits);
              TPprice = NormalizeDouble( TPprice, Digits); 
            }
            waitForContext();
		      OrderModify(ticket, OrderOpenPrice(), STprice, TPprice, 0, LightGreen);
		     }
         }
       }
   }
      
   if(ticket<0)
   {
      err = GetLastError();
      Print("Error opening SELL order : ",err, " ", ErrorDescription(err));
   }
   return(ticket);
}

double ValidStopLoss(int type, double price, double SL)
{

   double newSL, temp;
   
   if (SL < 0.1) return(SL);
   
   temp = MarketInfo(Symbol(), MODE_STOPLEVEL) * myPoint;
   newSL = SL;
   if (type == OP_BUY)
   {
		 if((price - SL) < temp) newSL = price - temp;
   }
   if (type == OP_SELL)
   {
       if((SL-price) < temp)  newSL = price + temp;  
   }
   newSL = NormalizeDouble(newSL,Digits);   

   return(newSL);   
}

double ValidTakeProfit(int type, double price, double TP)
{

   double newTP, temp;
   
   temp = MarketInfo(Symbol(), MODE_STOPLEVEL) * myPoint;
   newTP = TP;
   if (type == OP_BUY)
   {
		 if((TP - price) < temp) newTP = price + temp;
   }
   if (type == OP_SELL)
   {
       if((price - TP) < temp)  newTP = price - temp;  
   }
   newTP = NormalizeDouble(newTP,Digits);   

   return(newTP);   
}

int RecuperarOrdenes() {
   int contador = 0;
   for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) {
      if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) {
         if (OrderMagicNumber() != Magic || OrderSymbol()!=Symbol()) continue;
         ContarBalance(OrderProfit());
         contador++;
      }
   }
   return (contador);
}

void ContarBalance(double aux1) {
   SumaBeneficios += aux1;
}

double RecoveryLot(double PreLot) {
   RecuperarOrdenes();
   if (banderaBalance < SumaBeneficios) banderaBalance = SumaBeneficios;
   if (banderaBalance > SumaBeneficios) return (NormalizeLots(RecoveryModeMulti * PreLot));
   return (PreLot);
}

double NormalizeLots(double PreLot) {
   double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   double MinLot = MarketInfo(Symbol(), MODE_MINLOT);
   double MaxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double valor = MathCeil(PreLot / LotStep) * LotStep;
   if (valor < MinLot) {
      valor = MinLot;
   }
   if (valor > MaxLot) {
      valor = MaxLot;
   }
   return (valor);
}
double MMLots(double risk, double margin) {
   return(NormalizeLots(risk * margin / MarketInfo(Symbol(), MODE_MARGINREQUIRED) / (AccountLeverage() / 10.0)));
}

int waitForContext() {
   for (int contador = 0; IsTradeContextBusy() && contador < 20; contador++) Sleep(15);
   if (contador >= 20) Print("El contexto de trading estuvo ocupado por mas de ", DoubleToStr(15 * contador / 1000, 2), " segundos");
   else
      if (contador > 0) Print("El contexto de trading estuvo ocupado por ", DoubleToStr(15 * contador / 1000, 2), " segundos");
   return (contador);
}
//..............................................................................
double perceptron()
  
   {
    int i=0;     
         double w1 = x1 - 100;
         double w2 = x2 - 100;
         double w3 = x3 - 100;
         double w4 = x4 - 100;

         double a1 = iStochastic(NULL,0,Kperiod	,Dperiod	,slowing,MODE_SMA,0,MODE_MAIN,i)-50;
         double a2 = iStochastic(NULL,0,Kperiod ,Dperiod	,slowing,MODE_SMA,0,MODE_MAIN,i+shag)-50; 
         double a3 = iStochastic(NULL,0,Kperiod ,Dperiod	,slowing,MODE_SMA,0,MODE_MAIN,i+shag*2)-50; 
         double a4 = iStochastic(NULL,0,Kperiod ,Dperiod	,slowing,MODE_SMA,0,MODE_MAIN,i+shag*3)-50;
     
         return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);
    }
    

