//+------------------------------------------------------------------+
//|                                                 Sidus3Phases.mq4 |
//|                                           Copyright © 2006, GP2X |
//|                              http://www.freewebs.com/sidusmethod |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, GP2X"
#property link      "http://www.freewebs.com/sidusmethod"

#define CommentOfOrders "Sidus3Phases_Order" //Anything as long as unique

#define DIRECTION_NONE  0
#define DIRECTION_UP    1
#define DIRECTION_DOWN  -1

#define PHASE_BAGOVINO  1
#define PHASE_SIDUS     2
#define PHASE_VEGAS     3

//Time filters, please use your server timezone
extern int StartTradingHour = 0;
extern int EndTradingHour = 23;

//Weekend time filters
extern bool TradeOnFriday = false;
extern int FridayStartHour = 19;
extern int FridayEndHour = 23;
extern bool TradeOnSunday = false;
extern int SundayStartHour = 20;
extern int SundayEndHour = 23;

extern int Slippage = 3;
extern double Lots = 0.5;           //Lots should be greater than FirstTPLots+Second+Third+Fourth
extern double FirstTPLots = 0.1;
extern double SecondTPLots = 0.1;
extern double ThirdTPLots = 0.1;
extern double FourthTPLots = 0.1;

extern int StopLoss = 60;
extern int BAGOVINOTakeProfit = 40; //PHASE_BAGOVINO TP
extern int SIDUSTakeProfit = 80; //PHASE_SIDUS TP
extern int VEGASTakeProfit = 377; //PHASE_VEGAS TP



//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   static int phaseNumber = PHASE_BAGOVINO;
   int magicNumber = MagicfromSymbol();

   int M30EMADirection = getM30EMADirection();
   int M30RSIDirection = getStepRSIDirection();
   int direction = directionToEnter(M30EMADirection, M30RSIDirection);
   int H1TunnelDirection = getH1TunnelDirection();
   

   int existingOrders = 0;
   for (int i = 0; i < OrdersTotal(); i ++) {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if ((OrderSymbol()==Symbol()) && (OrderMagicNumber()==magicNumber) && (OrderComment()==CommentOfOrders)) {
         int orderType = OrderType();
         double remainedLots = OrderLots();
         double newStopLoss = OrderStopLoss();
         double newTakeProfit = OrderTakeProfit();
         existingOrders++;
         switch (orderType) {
            case OP_BUY:
               if (phaseNumber==PHASE_BAGOVINO) {
                  if (enterPhaseSidus(DIRECTION_UP)) {
                     phaseNumber = PHASE_SIDUS;
                     newTakeProfit = OrderOpenPrice() + Point*SIDUSTakeProfit;
                     newStopLoss = Ask - Point*StopLoss;
                  }
                  else if (H1TunnelDirection==DIRECTION_DOWN) {
                     OrderClose(OrderTicket(), remainedLots, Bid, Slippage, MediumSeaGreen);
                     existingOrders--;
                  }
               }
               else if (phaseNumber==PHASE_SIDUS) {
                  if (enterPhaseVegas(DIRECTION_UP)) {
                     phaseNumber = PHASE_VEGAS;
                     newTakeProfit = OrderOpenPrice() + Point*VEGASTakeProfit;
                     newStopLoss = Ask - Point*StopLoss;
                  }
                  else if (H1TunnelDirection==DIRECTION_DOWN) {
                     OrderClose(OrderTicket(), remainedLots, Bid, Slippage, MediumSeaGreen);
                     existingOrders--;
                  }
               }
               else if (phaseNumber==PHASE_VEGAS) {
                  if (H1TunnelDirection==DIRECTION_DOWN) {
                     OrderClose(OrderTicket(), remainedLots, Bid, Slippage, MediumSeaGreen);
                     existingOrders--;
                  }
                  else
                     newStopLoss = vegasTakeProfit(DIRECTION_UP, remainedLots);
               }
            break;
            case OP_SELL:
               if (phaseNumber==PHASE_BAGOVINO) {
                  if (enterPhaseSidus(DIRECTION_DOWN)) {
                     phaseNumber = PHASE_SIDUS;
                     newTakeProfit = OrderOpenPrice() - Point*SIDUSTakeProfit;
                     newStopLoss = Bid + Point*StopLoss;                     
                  }
                  else if (H1TunnelDirection==DIRECTION_UP) {
                     OrderClose(OrderTicket(), remainedLots, Ask, Slippage, DarkOrange);
                     existingOrders--;
                  }
               }
               else if (phaseNumber==PHASE_SIDUS) {
                  if (enterPhaseVegas(DIRECTION_DOWN)) {
                     phaseNumber = PHASE_VEGAS;
                     newTakeProfit = OrderOpenPrice() - Point*VEGASTakeProfit;                     
                     newStopLoss = Bid + Point*StopLoss;                     
                  }
                  else if (H1TunnelDirection==DIRECTION_UP) {
                     OrderClose(OrderTicket(), remainedLots, Ask, Slippage, DarkOrange);
                     existingOrders--;
                  }
               }
               else if (phaseNumber==PHASE_VEGAS) {
                  if (H1TunnelDirection==DIRECTION_UP) {
                     OrderClose(OrderTicket(), remainedLots, Ask, Slippage, DarkOrange);
                     existingOrders--;
                  }
                  else
                     newStopLoss = vegasTakeProfit(DIRECTION_DOWN, remainedLots);
               }
            break;
         }
         if ((existingOrders>0) && ((newStopLoss!=OrderStopLoss()) || (newTakeProfit!=OrderTakeProfit())))
            OrderModify(OrderTicket(),0,newStopLoss,newTakeProfit,0);
      }
   }
   if (existingOrders==0) {
      phaseNumber = PHASE_BAGOVINO;
      if (timeFilter()) {
         int ticket=1;
         if (direction==DIRECTION_UP) {
            ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, Ask-Point*StopLoss , Ask+Point*BAGOVINOTakeProfit, CommentOfOrders , magicNumber, 0, DodgerBlue);
         }
         else if (direction==DIRECTION_DOWN) {
            ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, Bid+Point*StopLoss, Bid-Point*BAGOVINOTakeProfit, CommentOfOrders, magicNumber, 0, DeepPink);
         }
      }
   }
   return(0);
  }
//+------------------------------------------------------------------+

int MagicfromSymbol() { //Copied From Firebird 
   int MagicNumber=0;  
   for (int i=0; i<5; i++) {  
      MagicNumber=MagicNumber*3+StringGetChar(Symbol(),i);  
   }  
   MagicNumber=MagicNumber*3+Period();  
   return(MagicNumber);  
}  

int getM30EMADirection() {
   double fast0=iMA(NULL,PERIOD_M30,5,0,MODE_EMA,PRICE_CLOSE,0);
   double fast1=iMA(NULL,PERIOD_M30,5,0,MODE_EMA,PRICE_CLOSE,1);
   double slow0=iMA(NULL,PERIOD_M30,12,0,MODE_EMA,PRICE_CLOSE,0);
   double slow1=iMA(NULL,PERIOD_M30,12,0,MODE_EMA,PRICE_CLOSE,1);
   return(getCrossDirection(fast0, fast1, slow0, slow1));
}

int getCrossDirection(double fast0, double fast1, double slow0, double slow1) {
   int crossDirection = DIRECTION_NONE;
   if ((fast0>slow0) && (fast1<slow1)) crossDirection = DIRECTION_UP;
   else if ((fast0<slow0) && (fast1>slow1)) crossDirection = DIRECTION_DOWN;
   return(crossDirection);
}
/*
int getM30RSIDirection() {
   int RSIDirection = DIRECTION_NONE;
   double RSI0 = iRSI(NULL, 0, 21, PRICE_CLOSE, 0);
   double RSI1 = iRSI(NULL, 0, 21, PRICE_CLOSE, 1);
   if ((RSI1<=50) && (RSI0>50)) RSIDirection = DIRECTION_UP;
   if ((RSI1>=50) && (RSI0<50)) RSIDirection = DIRECTION_DOWN;
   return(RSIDirection);
}*/

int getH1TunnelDirection() { // 18/28 EMA tunnel on H1
   double tunnelFast0 = iMA(NULL,PERIOD_H1,18,0,MODE_EMA,PRICE_CLOSE,0);
   double tunnelFast1 = iMA(NULL,PERIOD_H1,18,0,MODE_EMA,PRICE_CLOSE,1);
   double tunnelSlow0 = iMA(NULL,PERIOD_H1,28,0,MODE_EMA,PRICE_CLOSE,0);
   double tunnelSlow1 = iMA(NULL,PERIOD_H1,28,0,MODE_EMA,PRICE_CLOSE,1);
   return (getCrossDirection(tunnelFast0, tunnelFast1, tunnelSlow0, tunnelSlow1));
}

bool enterPhaseSidus(int direction) {
   bool result = false;
   double tunnelFast0 = iMA(NULL,PERIOD_H1,18,0,MODE_EMA,PRICE_CLOSE,0);
   double tunnelFast1 = iMA(NULL,PERIOD_H1,18,0,MODE_EMA,PRICE_CLOSE,1);
   double tunnelSlow0 = iMA(NULL,PERIOD_H1,28,0,MODE_EMA,PRICE_CLOSE,0);
   double tunnelSlow1 = iMA(NULL,PERIOD_H1,28,0,MODE_EMA,PRICE_CLOSE,1);
   int tunnelDirection = getCrossDirection(tunnelFast0, tunnelFast1, tunnelSlow0, tunnelSlow1);
   if (tunnelDirection==direction) {
      double wmaFast = iMA(NULL,60,5,0,MODE_LWMA,PRICE_CLOSE,0);
      double wmaSlow = iMA(NULL,60,8,0,MODE_LWMA,PRICE_CLOSE,0);
      if ((tunnelDirection==DIRECTION_UP) && (wmaFast>=wmaSlow) && (wmaSlow>=tunnelFast0))
         result = true;
      if ((tunnelDirection==DIRECTION_DOWN) && (wmaFast<=wmaSlow) && (wmaSlow<=tunnelFast0))
         result = false;
   }
   return(result);
}

bool enterPhaseVegas(int direction) {
   bool result = false;
   double vegasFast=iMA(NULL,60,144,0,1,PRICE_CLOSE,0);
   double vegasSlow=iMA(NULL,60,169,0,1,PRICE_CLOSE,0);
   if (direction==DIRECTION_UP) {
      result = Bid>MathMax(vegasFast, vegasSlow);
   }
   else if (direction==DIRECTION_DOWN) {
      result = Ask<MathMin(vegasFast, vegasSlow);
   }
   return (result);
}

double vegasTakeProfit(int direction, double remainedLots) {
   double vegasFast=iMA(NULL,60,144,0,1,PRICE_CLOSE,0);
   double vegasSlow=iMA(NULL,60,169,0,1,PRICE_CLOSE,0);
   double vegasMedian = (vegasFast+vegasSlow)/2;
   double newStopLoss = OrderStopLoss();
   if (direction==DIRECTION_UP) {
      double Up55 = 55* Point + vegasMedian;
      double Up89 = 89* Point + vegasMedian;
      double Up144 = 144* Point + vegasMedian;
      double Up233 = 233* Point + vegasMedian;
      if ((Bid>=Up55) && (remainedLots>=Lots)) {
         OrderClose(OrderTicket(), FirstTPLots, Bid, Slippage, MediumSeaGreen);
         newStopLoss = OrderOpenPrice();
      }
      if ((Bid>=Up89) && (remainedLots>=(Lots-FirstTPLots))) {
         OrderClose(OrderTicket(), SecondTPLots, Bid, Slippage, MediumSeaGreen);
         newStopLoss = Up55;
      }
      if ((Bid>=Up144) && (remainedLots>=(Lots-FirstTPLots-SecondTPLots))) {
         OrderClose(OrderTicket(), ThirdTPLots, Bid, Slippage, MediumSeaGreen);
         newStopLoss = Up89;
      }
      if ((Bid>=Up233) && (remainedLots>=(Lots-FirstTPLots-SecondTPLots-ThirdTPLots))) {
         OrderClose(OrderTicket(), FourthTPLots, Bid, Slippage, MediumSeaGreen);
         newStopLoss = Up144;
      }
   }
   else if (direction==DIRECTION_DOWN) {
      double Down55 = vegasMedian - 55* Point;
      double Down89 = vegasMedian - 89* Point;
      double Down144 = vegasMedian - 144* Point;
      double Down233 = vegasMedian - 233* Point;
      if ((Ask<=Down55) && (remainedLots>=Lots)) {
         OrderClose(OrderTicket(), FirstTPLots, Ask, Slippage, MediumSeaGreen);
         newStopLoss = OrderOpenPrice();
      }
      if ((Ask<=Down89) && (remainedLots>=(Lots-FirstTPLots))) {
         OrderClose(OrderTicket(), SecondTPLots, Ask, Slippage, MediumSeaGreen);
         newStopLoss = Down55;
      }
      if ((Ask<=Down144) && (remainedLots>=(Lots-FirstTPLots-SecondTPLots))) {
         OrderClose(OrderTicket(), ThirdTPLots, Ask, Slippage, MediumSeaGreen);
         newStopLoss = Down89;
      }
      if ((Ask<=Down233) && (remainedLots>=(Lots-FirstTPLots-SecondTPLots-ThirdTPLots))) {
         OrderClose(OrderTicket(), FourthTPLots, Ask, Slippage, MediumSeaGreen);
         newStopLoss = Down144;
      }
   }
   return (newStopLoss);
}

bool timeFilter() {
   bool result = false;
	int startHour;
	int endHour;
   switch(DayOfWeek()) {
      case 0:
         result = TradeOnSunday;
         startHour = SundayStartHour;
         endHour = SundayEndHour;
         break;
      case 5:
         result = TradeOnFriday;
         startHour = FridayStartHour;
         endHour = FridayEndHour;
         break;
      default:
         result = true;
         startHour = StartTradingHour;
         endHour = EndTradingHour;
      }
   if (result) {
	  int currentHour = Hour();
     result = (currentHour>=startHour) && (currentHour<=endHour);
   }
   return (result);
}

int directionToEnter(int EMACrossDirection, int RSICrossDirection) { //5 EMA, 12 EMA and RSI21 on M30
   static int pendingCross = DIRECTION_NONE;
   static int pendingRSI = DIRECTION_NONE;
   int direction = DIRECTION_NONE;
   if (EMACrossDirection!=DIRECTION_NONE) pendingCross = EMACrossDirection;
   if (RSICrossDirection!=DIRECTION_NONE) pendingRSI = RSICrossDirection;
   
   if ((pendingCross!=DIRECTION_NONE) && (pendingRSI!=DIRECTION_NONE)) {
      if (pendingCross==pendingRSI) direction = pendingCross; //Wait for both crossed
      //Clear pending signals
      pendingCross = DIRECTION_NONE;
      pendingRSI = DIRECTION_NONE;
   }
   return(direction);
}

int getStepRSIDirection() {
   int direction = DIRECTION_NONE;
   double periodRSI = iCustom(NULL, 0, "StepRSI_v2", 14, 5, 15, 0, 0);
   double stepFast = iCustom(NULL, 0, "StepRSI_v2", 14, 5, 15, 1, 0);
   double stepSlow = iCustom(NULL, 0, "StepRSI_v2", 14, 5, 15, 2, 0);
   if ((periodRSI>stepSlow) && (stepFast>stepSlow)) direction=DIRECTION_UP;
   if ((periodRSI<stepSlow) && (stepFast<stepSlow)) direction=DIRECTION_DOWN;
   return (direction);
}

