#property copyright "Copyright © 2008, Patrick Doucette"
#property link      "http://www.stochmonster.com"

extern int uniqueGridMagic = 1234;
extern double Lots = 0.1;
extern double GridSize = 120.0;
extern double GridSteps = 140.0;
extern double TakeProfit = 100.0;
extern double StopLoss = 0.0;
extern int trailStop = 0;
extern double UpdateInterval = 1.0;
extern bool wantLongs = TRUE;
extern bool wantShorts = TRUE;
extern bool wantBreakout = TRUE;
extern bool wantCounter = TRUE;
extern bool limitEMA = TRUE;
extern int EMAperiod = 123;
extern double GridMaxOpen = 11.0;
extern bool UseMACD = TRUE;
extern bool UseOsMA = TRUE;
extern bool CloseOpenPositions = TRUE;
extern bool doHouseKeeping = TRUE;
extern double keepOpenTimeLimit = 0.0;
extern int emaFast = 12;
extern int emaSlow = 26;
extern int signalPeriod = 9;
extern int timeFrame = 0;
extern int minFromPrice = 0;
extern int tradeForMinutes = 0;
extern int gridOffset = 1;
extern double longGridCenter = 0.0;
extern double shortGridCenter = 0.0;
extern double longGridLow = 0.0;
extern double longGridHigh = 0.0;
extern double shortGridLow = 0.0;
extern double shortGridHigh = 0.0;
extern double profitTarget = 15000.0;
extern bool suspendGrid = FALSE;
extern bool shutdownGrid = FALSE;
string gs_grid_280 = "Grid";
double gd_288 = 0.0;
double gd_296 = 0.0;
double gd_304 = 0.0;
double gd_312 = 0.0;
double gd_320 = 0.0;
bool gi_328 = FALSE;
int gi_332 = 0;
int gi_336 = 0;
bool gi_340 = TRUE;
bool gi_344 = FALSE;

int init() {
   string ls_0 = "2055.10.12";
   int li_8 = StrToTime(ls_0);
   /*if (TimeCurrent() >= li_8) {
      Alert("The trial version has been expired!");
      return (0);
   }*/
   gs_grid_280 = StringConcatenate("Grid-", Symbol(), "-", uniqueGridMagic);
   return (0);
}

int IsPosition(double ad_0, double ad_8, int ai_16) {
   int li_20;
   int li_24 = OrdersTotal();
   for (int li_28 = 0; li_28 < li_24; li_28++) {
      OrderSelect(li_28, SELECT_BY_POS);
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280) {
         li_20 = OrderType();
         if (MathAbs(OrderOpenPrice() - ad_0) < 0.9 * ad_8)
            if ((ai_16 && li_20 == OP_BUY || li_20 == OP_BUYLIMIT || li_20 == OP_BUYSTOP) || (!ai_16 && li_20 == OP_SELL || li_20 == OP_SELLLIMIT || li_20 == OP_SELLSTOP)) return (1);
      }
   }
   return (0);
}

void DeleteAfter(double ad_0) {
   bool li_8;
   int li_12 = OrdersTotal();
   for (int li_16 = li_12 - 1; li_16 >= 0; li_16--) OrderSelect(li_16, SELECT_BY_POS, MODE_TRADES);
   if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280) {
      if (MathAbs(iTime(Symbol(), PERIOD_M5, 0) - OrderOpenTime()) >= 60.0 * (60.0 * ad_0) && iTime(Symbol(), PERIOD_M5, 0) > 0) {
         li_8 = FALSE;
         if (OrderType() == OP_BUY) li_8 = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red);
         if (OrderType() == OP_SELL) li_8 = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red);
         if (OrderType() > OP_SELL) li_8 = OrderDelete(OrderTicket());
      }
   }
}

void CloseAllPendingOrders() {
   int li_0;
   int li_4 = OrdersTotal();
   for (int li_8 = li_4 - 1; li_8 >= 0; li_8--) {
      OrderSelect(li_8, SELECT_BY_POS);
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280)
         if (OrderType() > OP_SELL) li_0 = OrderDelete(OrderTicket());
   }
}

void ClosePendingOrdersAndPositions() {
   bool li_0;
   int li_4 = OrdersTotal();
   for (int li_8 = li_4 - 1; li_8 >= 0; li_8--) {
      OrderSelect(li_8, SELECT_BY_POS);
      li_0 = FALSE;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280) {
         if (OrderType() == OP_BUY) li_0 = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red);
         if (OrderType() == OP_SELL) li_0 = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red);
         if (OrderType() > OP_SELL) li_0 = OrderDelete(OrderTicket());
      }
   }
}

void CloseOrdersfromEMA(double ad_0) {
   int li_8;
   bool li_12;
   int li_16 = OrdersTotal();
   for (int li_20 = li_16 - 1; li_20 >= 0; li_20--) {
      OrderSelect(li_20, SELECT_BY_POS);
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280) {
         li_8 = OrderType();
         li_12 = FALSE;
         if (li_8 == OP_BUYLIMIT && OrderOpenPrice() <= ad_0) li_12 = OrderDelete(OrderTicket());
         if (li_8 == OP_BUYSTOP && OrderOpenPrice() <= ad_0) li_12 = OrderDelete(OrderTicket());
         if (li_8 == OP_SELLLIMIT && OrderOpenPrice() >= ad_0) li_12 = OrderDelete(OrderTicket());
         if (li_8 == OP_SELLSTOP && OrderOpenPrice() >= ad_0) li_12 = OrderDelete(OrderTicket());
      }
   }
}

int openPositions() {
   int li_0;
   int li_4 = 0;
   int li_8 = OrdersTotal();
   for (int li_12 = li_8 - 1; li_12 >= 0; li_12--) {
      OrderSelect(li_12, SELECT_BY_POS);
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280) {
         li_0 = OrderType();
         if (li_0 == OP_BUY) li_4++;
         if (li_0 == OP_SELL) li_4++;
      }
   }
   return (li_4);
}

void TestForProfit(int ai_0, double ad_4, int ai_12, int ai_16) {
   int li_20;
   int li_24;
   if (ad_4 > 0.0) {
      gd_304 = 0;
      if (ai_16 == 1) {
         li_20 = OrdersHistoryTotal();
         for (int li_28 = 0; li_28 < li_20; li_28++) {
            OrderSelect(li_28, SELECT_BY_POS, MODE_HISTORY);
            if (OrderSymbol() == Symbol() && OrderMagicNumber() == ai_0) gd_304 += OrderProfit();
         }
      } else gd_320 = 0;
      gd_312 = 0;
      if (ai_12 == 1) {
         li_20 = OrdersTotal();
         gi_332 = 0;
         gi_336 = 0;
         for (li_28 = 0; li_28 < li_20; li_28++) {
            OrderSelect(li_28, SELECT_BY_POS);
            if (OrderSymbol() == Symbol() && OrderMagicNumber() == ai_0) {
               gd_312 += OrderProfit();
               li_24 = OrderType();
               if (li_24 == OP_BUY) gi_332++;
               if (li_24 == OP_SELL) gi_336++;
            }
         }
      }
      if (gd_304 + gd_312 >= ad_4 + gd_320) {
         Print("Closing grid due to profit target");
         ClosePendingOrdersAndPositions();
         gd_320 = gd_320 + gd_304 + gd_312;
         gi_328 = TRUE;
         if (gi_344 == TRUE) gi_340 = FALSE;
      }
   }
}

void TrailIt(int ai_0) {
   if (ai_0 >= 5) {
      for (int li_4 = 0; li_4 < OrdersTotal(); li_4++) {
         OrderSelect(li_4, SELECT_BY_POS, MODE_TRADES);
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == uniqueGridMagic || OrderComment() == gs_grid_280) {
            if (OrderType() == OP_BUY) {
               if (Bid - OrderOpenPrice() <= ai_0 * MarketInfo(OrderSymbol(), MODE_POINT)) continue;
               if (OrderStopLoss() >= Bid - ai_0 * MarketInfo(OrderSymbol(), MODE_POINT)) continue;
               OrderModify(OrderTicket(), OrderOpenPrice(), Bid - ai_0 * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(), 255);
               continue;
            }
            if (OrderType() == OP_SELL) {
               if (OrderOpenPrice() - Ask > ai_0 * MarketInfo(OrderSymbol(), MODE_POINT))
                  if (OrderStopLoss() > Ask + ai_0 * MarketInfo(OrderSymbol(), MODE_POINT) || OrderStopLoss() == 0.0) OrderModify(OrderTicket(), OrderOpenPrice(), Ask + ai_0 * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(), 255);
            }
         }
      }
   }
}

int start() {
   int li_0;
   int li_4;
   int li_8;
   bool li_12;
   double ld_16;
   double ld_24;
   double ld_32;
   double ld_40;
   double ld_48;
   bool li_56;
   double ld_60;
   double ld_68;
   double ld_76;
   int li_84;
   double ld_88;
   if (TakeProfit <= 0.0) TakeProfit = GridSize;
   bool li_96 = wantLongs;
   bool li_100 = wantShorts;
   if (suspendGrid == TRUE) CloseAllPendingOrders();
   if (shutdownGrid == TRUE) {
      ClosePendingOrdersAndPositions();
      return (0);
   }
   if (gi_328 == TRUE) {
      ClosePendingOrdersAndPositions();
      if (gi_344 == TRUE) gi_340 = FALSE;
   }
   if (gi_340 == FALSE) return (0);
   if (MathAbs(TimeCurrent() - gd_288) > 60.0 * UpdateInterval) {
      if (profitTarget > 0.0) TestForProfit(uniqueGridMagic, profitTarget, 1, 0);
      gd_288 = TimeCurrent();
      ld_16 = MarketInfo(Symbol(), MODE_POINT);
      ld_24 = (Ask + ld_16 * GridSize / 2.0) / ld_16 / GridSize;
      li_0 = ld_24;
      li_0 = li_0 * GridSize;
      ld_24 = li_0 * ld_16 - GridSize * GridSteps / 2.0 * ld_16;
      ld_48 = iMA(NULL, 0, EMAperiod, 0, MODE_EMA, PRICE_CLOSE, 0);
      li_56 = FALSE;
      if (GridMaxOpen > 0.0) {
         li_56 = openPositions();
         if (li_56 >= GridMaxOpen) CloseAllPendingOrders();
      }
      if (limitEMA)
         if (doHouseKeeping) CloseOrdersfromEMA(ld_48);
      if (keepOpenTimeLimit > 0.0) DeleteAfter(keepOpenTimeLimit);
      if (trailStop > 0) TrailIt(trailStop);
      if (UseMACD || UseOsMA) {
         if (UseMACD) {
            ld_60 = iMACD(NULL, timeFrame, emaFast, emaSlow, signalPeriod, PRICE_CLOSE, MODE_MAIN, 0);
            ld_68 = iMACD(NULL, timeFrame, emaFast, emaSlow, signalPeriod, PRICE_CLOSE, MODE_MAIN, 1);
            ld_76 = iMACD(NULL, timeFrame, emaFast, emaSlow, signalPeriod, PRICE_CLOSE, MODE_MAIN, 2);
         }
         if (UseOsMA) {
            ld_60 = iOsMA(NULL, timeFrame, emaFast, emaSlow, signalPeriod, PRICE_CLOSE, 0);
            ld_68 = iOsMA(NULL, timeFrame, emaFast, emaSlow, signalPeriod, PRICE_CLOSE, 1);
            ld_76 = iOsMA(NULL, timeFrame, emaFast, emaSlow, signalPeriod, PRICE_CLOSE, 2);
         }
         if (ld_60 > 0.0 && ld_68 > 0.0 && ld_76 < 0.0) {
            CloseAllPendingOrders();
            if (CloseOpenPositions == TRUE) ClosePendingOrdersAndPositions();
         }
         if (ld_60 < 0.0 && ld_68 < 0.0 && ld_76 > 0.0) {
            CloseAllPendingOrders();
            if (CloseOpenPositions == TRUE) ClosePendingOrdersAndPositions();
         }
         li_96 = FALSE;
         li_100 = FALSE;
         if (ld_60 > 0.0 && ld_68 > 0.0 && ld_76 > 0.0 && wantLongs == TRUE) li_96 = TRUE;
         if (ld_60 < 0.0 && ld_68 < 0.0 && ld_76 < 0.0 && wantShorts == TRUE) li_100 = TRUE;
      }
      li_84 = GridSteps;
      if (GridMaxOpen > 0.0 && li_56 >= GridMaxOpen) li_84 = 0;
      if (suspendGrid == TRUE) return (0);
      Print("Trigs ", ld_60, "  ", ld_68, "  ", ld_76, "  ", li_96, "  ", li_100, "  ", li_84, " ema ", ld_48, " price ", Bid);
      for (int li_104 = 0; li_104 < li_84; li_104++) {
         ld_24 = (Ask + ld_16 * GridSize / 2.0) / ld_16 / GridSize;
         li_0 = ld_24;
         li_0 = li_0 * GridSize;
         ld_24 = li_0 * ld_16 - GridSize * GridSteps / 2.0 * ld_16;
         ld_32 = ld_24 + li_104 * ld_16 * GridSize + gridOffset * ld_16;
         if (li_96 && !limitEMA || ld_32 > ld_48) {
            if (longGridCenter > ld_16) {
               ld_40 = GridSteps / 2.0;
               li_0 = ld_40;
               ld_24 = longGridCenter - li_0 * GridSize * ld_16;
            } else {
               ld_24 = (Ask + ld_16 * GridSize / 2.0) / ld_16 / GridSize;
               li_0 = ld_24;
               li_0 = li_0 * GridSize;
               ld_24 = li_0 * ld_16 - GridSize * GridSteps / 2.0 * ld_16;
            }
            ld_32 = ld_24 + li_104 * ld_16 * GridSize + gridOffset * ld_16;
            li_12 = TRUE;
            if (ld_32 < longGridLow) li_12 = FALSE;
            if (ld_32 > longGridHigh && longGridHigh > ld_16) li_12 = FALSE;
            if (IsPosition(ld_32, ld_16 * GridSize, 1) == 0 && li_12 == TRUE) {
               ld_88 = 0;
               if (StopLoss > 0.0) ld_88 = ld_32 - ld_16 * StopLoss;
               if (ld_32 > Ask) li_8 = 4;
               else li_8 = 2;
               if ((ld_32 > Ask + minFromPrice * Point && wantBreakout) || (ld_32 <= Ask - minFromPrice * Point && wantCounter)) li_4 = OrderSend(Symbol(), li_8, Lots, ld_32, 0, ld_88, ld_32 + ld_16 * TakeProfit, gs_grid_280, uniqueGridMagic, 0, Green);
            }
         }
         if (li_100 && !limitEMA || ld_32 < ld_48) {
            if (shortGridCenter > ld_16) {
               ld_40 = GridSteps / 2.0;
               li_0 = ld_40;
               ld_24 = shortGridCenter - li_0 * GridSize * ld_16;
            } else {
               ld_24 = (Ask + ld_16 * GridSize / 2.0) / ld_16 / GridSize;
               li_0 = ld_24;
               li_0 = li_0 * GridSize;
               ld_24 = li_0 * ld_16 - GridSize * GridSteps / 2.0 * ld_16;
            }
            ld_32 = ld_24 + li_104 * ld_16 * GridSize + gridOffset * ld_16;
            li_12 = TRUE;
            if (ld_32 < shortGridLow) li_12 = FALSE;
            if (ld_32 > shortGridHigh && shortGridHigh > ld_16) li_12 = FALSE;
            if (IsPosition(ld_32, ld_16 * GridSize, 0) == 0 && li_12 == TRUE) {
               ld_88 = 0;
               if (StopLoss > 0.0) ld_88 = ld_32 + ld_16 * StopLoss;
               if (ld_32 > Bid) li_8 = 3;
               else li_8 = 5;
               if ((ld_32 < Bid - minFromPrice * Point && wantBreakout) || (ld_32 >= Bid + minFromPrice * Point && wantCounter)) li_4 = OrderSend(Symbol(), li_8, Lots, ld_32, 0, ld_88, ld_32 - ld_16 * TakeProfit, gs_grid_280, uniqueGridMagic, 0, Red);
            }
         }
      }
   }
   return (0);
}