//+------------------------------------------------------------------+
//| The 7 Strategy EA
//|
//|    Generated by StrategyQuant EA Wizard version 1.1
//|    Generated at Wed Nov 14 07:55:00 GST 2012
//+------------------------------------------------------------------+
#property copyright "StrategyQuant.com"
#property link      "http://www.StrategyQuant.com"
#include <stdlib.mqh>
#define PATTERN_DOJI 1
#define PATTERN_HAMMER 2
#define PATTERN_SHOOTING_STAR 3
#define PATTERN_DARK_CLOUD 4
#define PATTERN_PIERCING_LINE 5
#define PATTERN_BEARISH_ENGULFING 6
#define PATTERN_BULLISH_ENGULFING 7


//+------------------------------------------------------------------+
// -- Variables
//+------------------------------------------------------------------+




//+------------------------------------------------------------------+
// -- Other Hidden Parameters
//+------------------------------------------------------------------+
bool writeInfoMessagesToLog = false;
int MaxSlippage = 3;
double gPointPow = 0;
double gPointCoef = 0;
int lastHistoryPosChecked = 0;
int lastHistoryPosCheckedNT = 0;
string currentTime = "";
string lastTime = "";
double brokerStopDifference = 0;
string sqLastPeriod;
bool sqIsBarOpen;

//+------------------------------------------------------------------+
// -- Functions
//+------------------------------------------------------------------+

int init() {
   Log("--------------------------------------------------------");
   Log("Starting the EA");

   double realDigits;
   if(Digits < 4) { realDigits = 2; } else { realDigits = 4; }

   gPointPow = MathPow(10, realDigits);
   gPointCoef = 1/gPointPow;

   Log("Broker Stop Difference: ",DoubleToStr(brokerStopDifference*gPointPow, 2));

   Log("--------------------------------------------------------");

   return(0);
}

//+------------------------------------------------------------------+

int start() {
   if(Bars<30) {
      if(writeInfoMessagesToLog) Print("NOT ENOUGH DATA: Less Bars than 30");
      return(0);
   }

   string currentPeriod = sqGetPeriodAsStr();
   if(currentPeriod == sqLastPeriod) {
      sqIsBarOpen = false;
   } else {
      sqLastPeriod = currentPeriod;
      sqIsBarOpen = true;
   }

   manageOrders();

   //--------------------------------------
   // Short Entry 
   if (((Close[1] < iOpen(NULL, PERIOD_D1, 1) && ((Open[1] > iMA(NULL, 0 , 5 , 0 , 1 , 2 , 1)) && ((Close[1] < iMA(NULL, 0 , 5 , 0 , 1 , 2 , 1)) && (Low[1] > iMA(NULL, 0 , 5 , 0 , 1 , 3 , 1)))))) {
      sqOpenOrder("NULL", OP_SELL, getOrderSize(11, OP_SELL ), getOrderPrice(11), "The7Short", 11);
   }
   //--------------------------------------
   // Long Entry 
   if (((Close[1] > iCloseD(NULL, PERIOD_D1, 1) && ((Open[1] < iMA(NULL, 0 , 5 , 0 , 1 , 3 , 1)) && ((Close[1] > iMA(NULL, 0 , 5 , 0 , 1 , 3 , 1)) && (High[1] < iMA(NULL, 0 , 5 , 0 , 1 , 2 , 1)))))) {
      sqOpenOrder("NULL", OP_BUY, getOrderSize(12, OP_BUY ), getOrderPrice(12), "The7Long", 12);
   }

   return(0);
}

//+------------------------------------------------------------------+

void manageOrders() {
   for(int i=0; i<OrdersTotal(); i++) {
      if (OrderSelect(i,SELECT_BY_POS)==true) {
         manageOrder(OrderMagicNumber());

         if(sqIsBarOpen) {
            manageOrderExpiration(OrderMagicNumber());
         }
      }
   }
}

//----------------------------------------------------------------------------

void manageOrder(int orderMagicNumber) {
   double tempValue = 0;
   double tempValue2 = 0;
   double newSL = 0;

   if(orderMagicNumber == 11) {
      if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
         // handle only active orders

         // Trailing Stop
         tempValue = getOrderTrailingStop(11, OrderType(), OrderOpenPrice());
         if(tempValue > 0) {
            if(OrderType() == OP_BUY) {
               newSL = tempValue;

               if (OrderStopLoss() < newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            } else { // OrderType() == OP_SELL
               newSL = tempValue;
               if (OrderStopLoss() > newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            }
         }

         // Move Stop Loss to Break Even
         tempValue = getOrderBreakEven(11, OrderType(), OrderOpenPrice());
         tempValue2 = getOrderBreakEvenAddPips(11);
         if(tempValue > 0) {
            if(OrderType() == OP_BUY) {
               newSL = OrderOpenPrice() + tempValue2;
               if (OrderOpenPrice() <= tempValue && OrderStopLoss() < newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            } else { // OrderType() == OP_SELL
               newSL = OrderOpenPrice() - tempValue2;
               if (OrderOpenPrice() >= tempValue && OrderStopLoss() > newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            }
         }

         // Exit After X Bars
         tempValue = getOrderExitAfterXBars(11);
         if(tempValue > 0) {
            if (sqGetOpenBarsForOrder(tempValue+10) >= tempValue) {
               sqClosePositionAtMarket(-1);
            }
         }
      }
   }

   if(orderMagicNumber == 12) {
      if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
         // handle only active orders

         // Trailing Stop
         tempValue = getOrderTrailingStop(12, OrderType(), OrderOpenPrice());
         if(tempValue > 0) {
            if(OrderType() == OP_BUY) {
               newSL = tempValue;

               if (OrderStopLoss() < newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            } else { // OrderType() == OP_SELL
               newSL = tempValue;
               if (OrderStopLoss() > newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            }
         }

         // Move Stop Loss to Break Even
         tempValue = getOrderBreakEven(12, OrderType(), OrderOpenPrice());
         tempValue2 = getOrderBreakEvenAddPips(12);
         if(tempValue > 0) {
            if(OrderType() == OP_BUY) {
               newSL = OrderOpenPrice() + tempValue2;
               if (OrderOpenPrice() <= tempValue && OrderStopLoss() < newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            } else { // OrderType() == OP_SELL
               newSL = OrderOpenPrice() - tempValue2;
               if (OrderOpenPrice() >= tempValue && OrderStopLoss() > newSL && !sqDoublesAreEqual(OrderStopLoss(), newSL)) {
                  OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
               }
            }
         }

         // Exit After X Bars
         tempValue = getOrderExitAfterXBars(12);
         if(tempValue > 0) {
            if (sqGetOpenBarsForOrder(tempValue+10) >= tempValue) {
               sqClosePositionAtMarket(-1);
            }
         }
      }
   }

}


//----------------------------------------------------------------------------

void manageOrderExpiration(int orderMagicNumber) {
   int tempValue = 0;
   int barsOpen = 0;

   if(orderMagicNumber == 11) {
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) {
         // handle only pending orders

         // Stop/Limit Order Expiration
         tempValue = getOrderExpiration(11);
         if(tempValue > 0) {
            barsOpen = sqGetOpenBarsForOrder(tempValue+10);
            if(barsOpen >= tempValue) {
               OrderDelete(OrderTicket());
            }
         }
      }
   }

   if(orderMagicNumber == 12) {
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) {
         // handle only pending orders

         // Stop/Limit Order Expiration
         tempValue = getOrderExpiration(12);
         if(tempValue > 0) {
            barsOpen = sqGetOpenBarsForOrder(tempValue+10);
            if(barsOpen >= tempValue) {
               OrderDelete(OrderTicket());
            }
         }
      }
   }

}

//----------------------------------------------------------------------------


double getOrderSize(int orderMagicNumber, int orderType) {
   double size = 0;
   if(orderMagicNumber == 11) {
      size = sqMMFixedRisk(orderMagicNumber, orderType);
   }

   if(orderMagicNumber == 12) {
      size = sqMMFixedRisk(orderMagicNumber, orderType);
   }


   return(size);
}

//----------------------------------------------------------------------------

double getOrderPrice(int orderMagicNumber) {
   double price = 0;

   if(orderMagicNumber == 11) {

      price = Bid;
   }
   if(orderMagicNumber == 12) {

      price = Ask;
   }

   return(NormalizeDouble(price, Digits));
}

//----------------------------------------------------------------------------

double getOrderStopLoss(int orderMagicNumber, int orderType, double price) {
   double value = 0;

   if(orderMagicNumber == 11) {
         value = High[2];

   }

   if(orderMagicNumber == 12) {
         value = Low[2];

   }


   return(NormalizeDouble(value, Digits));
}

//----------------------------------------------------------------------------

double getOrderProfitTarget(int orderMagicNumber, int orderType, double price) {
   double value = 0;

   if(orderMagicNumber == 11) {
      value = (( 20 * gPointCoef));
      if(value > 0) {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            value = price + value;
         } else {
            value = price - value;
         }
      }

   }

   if(orderMagicNumber == 12) {
      value = (( 20 * gPointCoef));
      if(value > 0) {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            value = price + value;
         } else {
            value = price - value;
         }
      }

   }


   return(NormalizeDouble(value, Digits));
}

//----------------------------------------------------------------------------

double getOrderExitAfterXBars(int orderMagicNumber) {
   double price = 0;

   if(orderMagicNumber == 11) {
      price = 0;
   }

   if(orderMagicNumber == 12) {
      price = 0;
   }


   return(NormalizeDouble(price, Digits));
}

//----------------------------------------------------------------------------

double getStopDifferencePrice(int orderMagicNumber) {
   double price = 0;

   if(orderMagicNumber == 11) {
      price = 0;
   }

   if(orderMagicNumber == 12) {
      price = 0;
   }


   return(NormalizeDouble(price, Digits));
}

//----------------------------------------------------------------------------

double getOrderTrailingStop(int orderMagicNumber, int orderType, double price) {
   double value = 0;

   if(orderMagicNumber == 11) {
      value = 0.5 * iATR(NULL, 0, 2 ,1);
      if(value > 0) {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            value = Bid - value;
         } else {
            value = Ask + value;
         }
      }

   }

   if(orderMagicNumber == 12) {
      value = 0.5 * iATR(NULL, 0, 2 ,1);
      if(value > 0) {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            value = Bid - value;
         } else {
            value = Ask + value;
         }
      }

   }


   return(NormalizeDouble(value, Digits));
}

//----------------------------------------------------------------------------

double getOrderBreakEven(int orderMagicNumber, int orderType, double price) {
   double value = 0;

   if(orderMagicNumber == 11) {
      value = ( 0 * gPointCoef);
      if(value > 0) {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            value = Bid - value;
         } else {
            value = Ask + value;
         }
      }

   }

   if(orderMagicNumber == 12) {
      value = ( 0 * gPointCoef);
      if(value > 0) {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            value = Bid - value;
         } else {
            value = Ask + value;
         }
      }

   }


   return(NormalizeDouble(value, Digits));
}

//----------------------------------------------------------------------------

double getOrderBreakEvenAddPips(int orderMagicNumber) {
   double price = 0;

   if(orderMagicNumber == 11) {
      price = (1 * gPointCoef);
   }

   if(orderMagicNumber == 12) {
      price = (1 * gPointCoef);
   }


   return(NormalizeDouble(price, Digits));
}

//----------------------------------------------------------------------------

double getOrderExpiration(int orderMagicNumber) {
   double price = 0;

   if(orderMagicNumber == 11) {
      price = 0;
   }

   if(orderMagicNumber == 12) {
      price = 0;
   }


   return(NormalizeDouble(price, Digits));
}

//----------------------------------------------------------------------------

bool getReplaceStopLimitOrder(int orderMagicNumber) {
   bool value = false;

   if(orderMagicNumber == 11) {
      value = 0;
   }

   if(orderMagicNumber == 12) {
      value = 0;
   }


   return(value);
}


//+------------------------------------------------------------------+
//+ Global functions
//+------------------------------------------------------------------+

double sqConvertToRealPips(int value) {
   return(gPointCoef * value);
}

//----------------------------------------------------------------------------

datetime sqGetTime(int hour, int minute) {
   // StrToTime works only on a current date, for previous dates it should be used like this:
   // return(StrToTime(StringConcatenate(TimeToStr(Time[i], TIME_DATE), " 12:00"))));

   return(StrToTime(hour+ ":" + minute));
}

//----------------------------------------------------------------------------

double sqHeikenAshi(string symbol, int timeframe, string mode, int shift) {
   if(symbol == "NULL") {
      if(mode == "Open") {
         return(iCustom(NULL, 0, "Heiken Ashi", 0,0,0,0, 2, shift));
      }
      if(mode == "Close") {
         return(iCustom(NULL, 0, "Heiken Ashi", 0,0,0,0, 3, shift));
      }
      if(mode == "High") {
         return(MathMax(iCustom( NULL, 0, "Heiken Ashi", 0,0,0,0, 0, shift), iCustom( NULL, 0, "Heiken Ashi", 0,0,0,0, 1, shift)));
      }
      if(mode == "Low") {
         return(MathMin(iCustom( NULL, 0, "Heiken Ashi", 0,0,0,0, 0, shift), iCustom( NULL, 0, "Heiken Ashi", 0,0,0,0, 1, shift)));
      }

   } else {
      if(mode == "Open") {
         return(iCustom( symbol, timeframe, "Heiken Ashi", 0,0,0,0, 2, shift));
      }
      if(mode == "Close") {
         return(iCustom( symbol, timeframe, "Heiken Ashi", 0,0,0,0, 3, shift));
      }
      if(mode == "High") {
         return(MathMax(iCustom( symbol, timeframe, "Heiken Ashi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "Heiken Ashi", 0,0,0,0, 1, shift)));
      }
      if(mode == "Low") {
         return(MathMin(iCustom( symbol, timeframe, "Heiken Ashi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "Heiken Ashi", 0,0,0,0, 1, shift)));
      }
   }

   return(-1);
}


//+------------------------------------------------------------------+

double sqHighest(string symbol, int timeframe, int period, int shift) {
   double maxnum = -1000;
   double val;

   for(int i=shift; i<shift+period; i++) {
      if(symbol == "NULL") {
         val = iHigh(NULL, timeframe, i);
      } else {
         val = iHigh(symbol, timeframe, i);
      }

      if(val > maxnum) {
         maxnum = val;
      }
   }

   return(maxnum);
}

//+------------------------------------------------------------------+

double sqLowest(string symbol, int timeframe, int period, int shift) {
   double minnum = 1000;
   double val;

   for(int i=shift; i<shift+period; i++) {
      if(symbol == "NULL") {
         val = iLow(NULL, timeframe, i);
      } else {
         val = iLow(symbol, timeframe, i);
      }

      if(val < minnum) {
         minnum = val;
      }
   }

   return(minnum);
}

//+------------------------------------------------------------------+

double sqBiggestRange(string symbol, int timeframe, int period, int shift) {
   double maxnum = -1000;
   double range;

   for(int i=shift; i<shift+period; i++) {
      if(symbol == "NULL") {
         range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i);
      } else {
         range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i);
      }

      if(range > maxnum) {
         maxnum = range;
      }
   }

   return(maxnum);
}


//+------------------------------------------------------------------+

double sqSmallestRange(string symbol, int timeframe, int period, int shift) {
   double minnum = 1000;
   double range;

   for(int i=shift; i<shift+period; i++) {
      if(symbol == "NULL") {
         range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i);
      } else {
         range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i);
      }

      if(range < minnum) {
         minnum = range;
      }
   }

   return(minnum);
}

//+------------------------------------------------------------------+

double sqBarRange(string symbol, int timeframe, int shift) {
   if(symbol == "NULL") {
      return(iHigh(NULL, timeframe, shift) - iLow(NULL, timeframe, shift));
   } else {
      return(iHigh(symbol, timeframe, shift) - iLow(symbol, timeframe, shift));
   }
}

//+------------------------------------------------------------------+

double sqMinimum(double value1, double value2) {
   return(MathMin(value1, value2));
}

//+------------------------------------------------------------------+

double sqMaximum(double value1, double value2) {
   return(MathMax(value1, value2));
}

//+------------------------------------------------------------------+

void Log(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
   Print(TimeToStr(TimeCurrent()), " ", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}

//+------------------------------------------------------------------+

string sqGetPeriodAsStr() {
   string str = TimeToStr(Time[0], TIME_DATE);
   int period = Period();

   if(period == PERIOD_H4 || period == PERIOD_H1) {
      str = str + TimeHour(Time[0]);
   }
   if(period == PERIOD_M30 || period == PERIOD_M15 || period == PERIOD_M5 || period == PERIOD_M1) {
      str = str + " " + TimeToStr(Time[0], TIME_MINUTES);
   }

   return(str);
}

//+------------------------------------------------------------------+

bool sqDoublesAreEqual(double n1, double n2) {
   string s1 = DoubleToStr(n1, Digits);
   string s2 = DoubleToStr(n2, Digits);

   return (s1 == s2);
}

//+------------------------------------------------------------------+

int sqGetOpenBarsForOrder(int expBarsPeriod) {
   datetime opTime = OrderOpenTime();
   datetime currentTime = TimeCurrent();

   int numberOfBars = 0;
   for(int i=i; i<expBarsPeriod+10; i++) {
      if(opTime < Time[i]) {
         numberOfBars++;
      }
   }

   return(numberOfBars);
}

//----------------------------------------------------------------------------

void sqCloseOrder(int orderMagicNumber) {
   for(int i=0; i<OrdersTotal(); i++) {
      if (OrderSelect(i,SELECT_BY_POS)==true && OrderMagicNumber() == orderMagicNumber) {

         if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            sqClosePositionAtMarket(-1);
         } else {
            OrderDelete(OrderTicket());
         }
      }
   }
}

//----------------------------------------------------------------------------

void sqCloseOrderPartial(int orderMagicNumber, double size) {
   for(int i=0; i<OrdersTotal(); i++) {
      if (OrderSelect(i,SELECT_BY_POS)==true && OrderMagicNumber() == orderMagicNumber) {

         if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            sqClosePositionAtMarket(size);
         } else {
            OrderDelete(OrderTicket());
         }
      }
   }
}

//+------------------------------------------------------------------+

void sqClosePositionAtMarket(double size) {
   RefreshRates();
   double priceCP;

   if(OrderType() != OP_BUY && OrderType() != OP_SELL) {
     return(true);
   }

   if(OrderType() == OP_BUY) {
      priceCP = Bid;
   } else {
      priceCP = Ask;
   }

   if(size <= 0) {
      OrderClose(OrderTicket(), OrderLots(), priceCP, MaxSlippage);
   } else {
      OrderClose(OrderTicket(), size, priceCP, MaxSlippage);
   }
}

//+------------------------------------------------------------------+

int sqOpenOrder(string symbol, int orderType, double orderLots, double price, string comment, int orderMagicNumber) {
   int error, ticket;

   if(sqLiveOrderExists(orderMagicNumber)) {
      if(writeInfoMessagesToLog) Log("Order with magic number: ", orderMagicNumber, " already exists, cannot open another one!");
      return(0);
   }

   if(sqPendingOrderExists(orderMagicNumber)) {
      if(!getReplaceStopLimitOrder(orderMagicNumber)) {
         if(writeInfoMessagesToLog) Log("Pending Order with magic number: ", orderMagicNumber, " already exists, and replace is not allowed!");
         return(0);
      }

      // close pending order
      sqDeletePendingOrder(orderMagicNumber);
   }

   if(orderType == OP_BUYSTOP || orderType == OP_SELLSTOP) {
      double AskOrBid;
      if(orderType == OP_BUYSTOP) { AskOrBid = Ask; } else { AskOrBid = Bid; }

      // check if stop/limit price isn't too close
      if(NormalizeDouble(MathAbs(price - AskOrBid), Digits) <= NormalizeDouble(getStopDifferencePrice(orderMagicNumber)/gPointPow, Digits)) {
         //Log("stop/limit order is too close to actual price");
         return(0);
      }
   }

   if(symbol == "NULL") {
      ticket = OrderSend(Symbol(), orderType, orderLots, price, MaxSlippage, 0, 0, comment, orderMagicNumber);
   } else {
      ticket = OrderSend(symbol, orderType, orderLots, price, MaxSlippage, 0, 0, comment, orderMagicNumber);
   }
   if(ticket < 0) {
      // order failed, write error to log
      error = GetLastError();
      Log("Error opening order: ",error, " : ", ErrorDescription(error));
      return(-1);
   }

   OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES);
   Log("Order opened: ", OrderTicket(), " at price:", OrderOpenPrice());

   // set up stop loss and profit target
   // it has to be done separately to support ECN brokers

   double realSL = getOrderStopLoss(orderMagicNumber, orderType, price);
   double realPT = getOrderProfitTarget(orderMagicNumber, orderType, price);

   if(OrderModify(ticket, OrderOpenPrice(), realSL, realPT, 0, 0)) {
      Log("Order modified, StopLoss: ", OrderStopLoss(),", Profit Target: ", OrderTakeProfit());
   } else {
      Log("Error modifying order: ",error, " : ", ErrorDescription(error));
   }

   return(ticket);
}


//+------------------------------------------------------------------+

int sqGetMarketPosition() {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;

      if(OrderType() == OP_BUY) {
         return(1);
      }
      if(OrderType() == OP_SELL) {
         return(-1);
      }
   }

   return(0);
}

//+------------------------------------------------------------------+

double sqGetOpenPrice(int orderMagicNumber) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderMagicNumber() == orderMagicNumber) {
         return(OrderOpenPrice());
      }
   }

   return(0);
}

//+------------------------------------------------------------------+

double sqGetOrderStopLoss(int orderMagicNumber) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderMagicNumber() == orderMagicNumber) {
         return(OrderStopLoss());
      }
   }

   return(0);
}

//+------------------------------------------------------------------+

double sqGetOrderProfitTarget(int orderMagicNumber) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderMagicNumber() == orderMagicNumber) {
         return(OrderTakeProfit());
      }
   }

   return(0);
}

//+------------------------------------------------------------------+

void sqDeletePendingOrder(int orderMagicNumber) {
   for(int i=0; i<OrdersTotal(); i++) {
      if (OrderSelect(i,SELECT_BY_POS)==true) {
         if(OrderMagicNumber() != orderMagicNumber) continue;

         OrderDelete(OrderTicket());
         return;
      }
   }
}

//+------------------------------------------------------------------+

bool sqLiveOrderExists(int orderMagicNumber) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderMagicNumber() != orderMagicNumber) continue;
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;

      return(true);
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqPendingOrderExists(int orderMagicNumber) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderMagicNumber() != orderMagicNumber) continue;
      if(OrderType() == OP_BUY || OrderType() == OP_SELL) continue;

      return(true);
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqIsCandlePattern(int shift, int pattern) {
   if(pattern == PATTERN_DOJI) return(sqCandlePatternDoji(shift));
   if(pattern == PATTERN_HAMMER) return(sqCandlePatternHammer(shift));
   if(pattern == PATTERN_SHOOTING_STAR) return(sqCandlePatternShootingStar(shift));
   if(pattern == PATTERN_DARK_CLOUD) return(sqCandlePatternDarkCloudCover(shift));
   if(pattern == PATTERN_PIERCING_LINE) return(sqCandlePatternPiercingLine(shift));
   if(pattern == PATTERN_BEARISH_ENGULFING) return(sqCandlePatternBearishEngulfing(shift));
   if(pattern == PATTERN_BULLISH_ENGULFING) return(sqCandlePatternBullishEngulfing(shift));

   return(false);
}

bool sqCandlePatternDoji(int shift) {
   if(MathAbs(Open[shift] - Close[shift])*gPointPow < 0.6) {
      return(true);
   }
   return(false);
}

//+------------------------------------------------------------------+

bool sqCandlePatternHammer(int shift) {
   double H = High[shift];
   double L = Low[shift];
   double L1 = Low[shift+1];
   double L2 = Low[shift+2];
   double L3 = Low[shift+3];

   double O = Open[shift];
   double C = Close[shift];
   double CL = H-L;

   double BodyLow, BodyHigh;
   double Candle_WickBody_Percent = 0.9;
   double CandleLength = 12;

   if (O > C) {
      BodyHigh = O;
      BodyLow = C;
   } else {
      BodyHigh = C;
      BodyLow = O;
   }

   double LW = BodyLow-L;
   double UW = H-BodyHigh;
   double BLa = MathAbs(O-C);
   double BL90 = BLa*Candle_WickBody_Percent;

   double pipValue = gPointCoef;

   if ((L<=L1)&&(L<L2)&&(L<L3))  {
      if (((LW/2)>UW)&&(LW>BL90)&&(CL>=(CandleLength*pipValue))&&(O!=C)&&((LW/3)<=UW)&&((LW/4)<=UW)/*&&(H<H1)&&(H<H2)*/)  {
         return(true);
      }
      if (((LW/3)>UW)&&(LW>BL90)&&(CL>=(CandleLength*pipValue))&&(O!=C)&&((LW/4)<=UW)/*&&(H<H1)&&(H<H2)*/)  {
         return(true);
      }
      if (((LW/4)>UW)&&(LW>BL90)&&(CL>=(CandleLength*pipValue))&&(O!=C)/*&&(H<H1)&&(H<H2)*/)  {
         return(true);
      }
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqCandlePatternPiercingLine(int shift) {
   double L = Low[shift];
   double H = High[shift];

   double O = Open[shift];
   double O1 = Open[shift+1];
   double C = Close[shift];
   double C1 = Close[shift+1];
   double CL = H-L;

   double CO_HL;
   if((H - L) != 0) {
      CO_HL = (C-O)/(H-L);
   } else {
      CO_HL = 0;
   }

   double Piercing_Line_Ratio = 0.5;
   double Piercing_Candle_Length = 10;

   if ((C1<O1)&&(((O1+C1)/2)<C)&&(O<C) && (CO_HL>Piercing_Line_Ratio)&&(CL>=(Piercing_Candle_Length*gPointCoef))) {
      return(true);
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqCandlePatternShootingStar(int shift) {
   double L = Low[shift];
   double H = High[shift];
   double H1 = High[shift+1];
   double H2 = High[shift+2];
   double H3 = High[shift+3];

   double O = Open[shift];
   double C = Close[shift];
   double CL = H-L;

   double BodyLow, BodyHigh;
   double Candle_WickBody_Percent = 0.9;
   double CandleLength = 12;

   if (O > C) {
      BodyHigh = O;
      BodyLow = C;
   } else {
      BodyHigh = C;
      BodyLow = O;
   }

   double LW = BodyLow-L;
   double UW = H-BodyHigh;
   double BLa = MathAbs(O-C);
   double BL90 = BLa*Candle_WickBody_Percent;

   double pipValue = gPointCoef;

   if ((H>=H1)&&(H>H2)&&(H>H3))  {
      if (((UW/2)>LW)&&(UW>(2*BL90))&&(CL>=(CandleLength*pipValue))&&(O!=C)&&((UW/3)<=LW)&&((UW/4)<=LW)/*&&(L>L1)&&(L>L2)*/)  {
         return(true);
      }
      if (((UW/3)>LW)&&(UW>(2*BL90))&&(CL>=(CandleLength*pipValue))&&(O!=C)&&((UW/4)<=LW)/*&&(L>L1)&&(L>L2)*/)  {
         return(true);
      }
      if (((UW/4)>LW)&&(UW>(2*BL90))&&(CL>=(CandleLength*pipValue))&&(O!=C)/*&&(L>L1)&&(L>L2)*/)  {
         return(true);
      }
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqCandlePatternBearishEngulfing(int shift) {
   double O = Open[shift];
   double O1 = Open[shift+1];
   double C = Close[shift];
   double C1 = Close[shift+1];

   if ((C1>O1)&&(O>C)&&(O>=C1)&&(O1>=C)&&((O-C)>(C1-O1))) {
      return(true);
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqCandlePatternBullishEngulfing(int shift) {
   double O = Open[shift];
   double O1 = Open[shift+1];
   double C = Close[shift];
   double C1 = Close[shift+1];

   if ((O1>C1)&&(C>O)&&(C>=O1)&&(C1>=O)&&((C-O)>(O1-C1))) {
      return(true);
   }

   return(false);
}

//+------------------------------------------------------------------+

bool sqCandlePatternDarkCloudCover(int shift) {
   double L = Low[shift];
   double H = High[shift];

   double O = Open[shift];
   double O1 = Open[shift+1];
   double C = Close[shift];
   double C1 = Close[shift+1];
   double CL = H-L;

   double OC_HL;
   if((H - L) != 0) {
      OC_HL = (O-C)/(H-L);
   } else {
      OC_HL = 0;
   }

   double Piercing_Line_Ratio = 0.5;
   double Piercing_Candle_Length = 10;

   if ((C1>O1)&&(((C1+O1)/2)>C)&&(O>C)&&(C>O1)&&(OC_HL>Piercing_Line_Ratio)&&((CL>=Piercing_Candle_Length*gPointCoef))) {
      return(true);
   }

   return(false);
}

//+------------------------------------------------------------------+

double sqGetOpenPLInPips(int orderMagicNumber) {
   double pl = 0;

   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
      if(orderMagicNumber != 0 && OrderMagicNumber() != orderMagicNumber) continue;

      if(OrderType() == OP_BUY) {
         pl += Bid - OrderOpenPrice();
      } else {
         pl += OrderOpenPrice() - Ask;
      }
   }

   return(pl*gPointPow);
}

//+------------------------------------------------------------------+

double sqGetOpenPLInMoney(int orderMagicNumber) {
   double pl = 0;

   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
      if(orderMagicNumber != 0 && OrderMagicNumber() != orderMagicNumber) continue;

      pl += OrderProfit();
   }

   return(pl*gPointPow);
}

//+------------------------------------------------------------------+

double sqGetCurrentPositionSize(int orderMagicNumber) {
   double lots = 0;

   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
      if(orderMagicNumber != 0 && OrderMagicNumber() != orderMagicNumber) continue;

      lots += OrderLots();
   }

   return(lots);
}

//+------------------------------------------------------------------+

void sqMoveSLTo(int orderMagicNumber, double newSL) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;

      if(OrderMagicNumber() == orderMagicNumber) {
         OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
      }
   }
}

//+------------------------------------------------------------------+

void sqMovePTTo(int orderMagicNumber, double newPT) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;

      if(OrderMagicNumber() == orderMagicNumber) {
         OrderModify(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), newPT, 0);
      }
   }
}

//+------------------------------------------------------------------+


int sqGetBarsSinceEntry(int orderMagicNumber) {
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;

      if(OrderMagicNumber() == orderMagicNumber) {
         return (sqGetOpenBarsForOrder(1000));
      }
   }

   return(0);
}

//+------------------------------------------------------------------+

int sqGetOrdersOpenedToday(int direction, string includePending) {
   string todayTime = TimeToStr( TimeCurrent(), TIME_DATE);
   int tradesOpenedToday = 0;

   for(int i=0;i<OrdersHistoryTotal();i++) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {

         if(direction == 1) {
            if(OrderType() == OP_SELL || OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP) {
               // skip short orders
               continue;
            }
         } else if(direction == -1) {
            if(OrderType() == OP_BUY || OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP) {
               // skip long orders
               continue;
            }
         }

         if(includePending == "false") {
            if(OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP || OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP) {
               // skip pending orders
               continue;
            }
         }

         if(TimeToStr( OrderOpenTime(), TIME_DATE) == todayTime) {
            tradesOpenedToday++;
         }
      }
   }

   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;

      if(direction == 1) {
         if(OrderType() == OP_SELL || OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP) {
            // skip short orders
            continue;
         }
      } else if(direction == -1) {
         if(OrderType() == OP_BUY || OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP) {
            // skip long orders
            continue;
         }
      }

      if(includePending == "false") {
         if(OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP || OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP) {
            // skip pending orders
            continue;
         }
      }

      if(TimeToStr( OrderOpenTime(), TIME_DATE) == todayTime) {
         tradesOpenedToday++;
      }
   }

   return(tradesOpenedToday);
}


//+------------------------------------------------------------------+
//+ Money Management functions
//+------------------------------------------------------------------+

double sqMMGetOrderStopLossDistance(int orderMagicNumber, int orderType) {
   double openPrice = getOrderPrice(orderMagicNumber);
   double slSize = getOrderStopLoss(orderMagicNumber, orderType, openPrice);

   if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
      return(openPrice - slSize);
   } else {
      return(slSize - openPrice);
   }
}


double sqMMFixedRisk(int orderMagicNumber, int orderType) 
{
   double slSize = sqMMGetOrderStopLossDistance(orderMagicNumber, orderType) * gPointPow;
   if(slSize <= 0) 
   {
      return(0.01);
   }

   double _riskInPercent = 2.0;
   double _lotsDecimals = 2.0;
   double _maximumLots = 5.0;

   if(_riskInPercent < 0 ) 
   {
      Log("Incorrect RiskInPercent size, it must be above 0");
      return(0);
   }
   double riskPerTrade = (AccountBalance() *  (_riskInPercent / 100.0));
   if(slSize <= 0) 
   {
      Log("Incorrect StopLossPips size, it must be above 0");
      return(0);
   }

   Log("SL: ", slSize, ", AccBal: ", AccountBalance(),", Tickval: ", MarketInfo(Symbol(), MODE_TICKVALUE),", Point: ", MarketInfo(Symbol(), MODE_POINT));

   double lotMM1 = NormalizeDouble(riskPerTrade / (slSize * 10.0), _lotsDecimals);
   double lotMM;
   double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   if(MathMod(lotMM*100, lotStep*100) > 0) 
   {
      lotMM = lotMM1 - MathMod(lotMM1, lotStep);
   } else 
   {
      lotMM = lotMM1;
   }

   lotMM = NormalizeDouble( lotMM, _lotsDecimals);

   if(MarketInfo(Symbol(), MODE_LOTSIZE)==10000.0) lotMM=lotMM*10.0 ;
   lotMM=NormalizeDouble(lotMM,_lotsDecimals);

   double Smallest_Lot = MarketInfo(Symbol(), MODE_MINLOT);
   double Largest_Lot = MarketInfo(Symbol(), MODE_MAXLOT);

   if (lotMM < Smallest_Lot) lotMM = Smallest_Lot;
   if (lotMM > Largest_Lot) lotMM = Largest_Lot;

   if(lotMM > _maximumLots) {
      lotMM = _maximumLots;
   }

   return (lotMM);
}

