//+------------------------------------------------------------------+
//|                                            EACenterOfGravity.mq4 |
//|                                                            v0.11 |
//|                                           http://www.edlogic.com |
//+------------------------------------------------------------------+
#property copyright "test 1 2 3"
#property link      "link 1 2 3"
#define COGMAGIC  706706706

extern int stopLoss = 450;
extern int breakEvenSteps = 77;
extern double maxLots = 0.10;
extern int riskPercent = 3;
extern int activateExitStrategyAtPips = -150;
extern int takeProfit = 350;
extern int maxOrders = 3;
extern double trailStopLoss = 22;

double Lots;
int Nmbr_Bars = 180;
double cogCenter[3],cogHigh1[3],cogHigh2[3],cogHigh3[3],cogLow3[3],cogLow2[3],cogLow1[3];
double HighOrders[3], LowOrders[3], lastHighCOG[3], lastLowCOG[3];
double bid, ask, point, cogOrderTicket, cogHighLowSpan, cogHigh3High2Span, cogHigh2High1Span;
double cogLow3Low2Span, cogLow2Low1Span, cogHigh1Center, cogLow3Center;
int digits, spread, minStopLevel;
bool runOnce = false, defeatPeriodCheck = false, defeatTrendDirectionCheck = false, testing = false;

double   balance              =  0.00;
double   equity               =  0.00;
double   marginFree           =  0.00;
double   marginUsed           =  0.00;
double   marginUsedPercent    =  0.00;
double   marginUsablePercent  =  0.00;
double   profitLossPercentage =  0.00;

int start() {
   
  if(Bars<100 || IsTradeAllowed()==false)
    return;
  
  if (testing)
  {
    defeatPeriodCheck = true;
    defeatTrendDirectionCheck = true;
  }  

   getMarketInfo(Symbol());
   updateMoneyManager();
   checkIfHighLowOrdersClosed();
   GravityCenter2();
   setLastCOGvalues();
   calcSpans();
   ManageCurrentOrders();
   CheckToOpenOrders();

   return(0);
}

void checkIfHighLowOrdersClosed()
{
  for (int idx = 0; idx < 3; idx++)
  {
    checkHighOrderClosed(idx);
    checkLowOrderClosed(idx);
  }
}

void checkHighOrderClosed(int idx)
{
  if (HighOrders[idx] >= 0)
  {
    if (checkIfOrderClosed(HighOrders[idx]))
      HighOrders[idx] = -255;
  }
}
 
void checkLowOrderClosed(int idx)
{
  if (LowOrders[idx] >= 0)
  {
    if (checkIfOrderClosed(LowOrders[idx]))
      LowOrders[idx] = -255;
  }
}

bool checkIfOrderClosed(double orderNumber)
{
  int totalOrders = OrdersTotal();
  int    orderTicket;
  
  for(int idx = totalOrders - 1; idx >= 0; idx--)
	{
		if (OrderSelect(idx, SELECT_BY_POS, MODE_TRADES) && (OrderMagicNumber() == COGMAGIC || OrderSymbol() == Symbol()))
		{
			orderTicket = OrderTicket();
		
		  if (orderNumber == orderTicket)
		    return (false); // order is not closed
		}
		else { Print( "Error when order select ", GetLastError()); Sleep(1); }
	}
  
	//Alert("returning true because order not found ordernumber = ", orderNumber);
	return (true);
}


void ManageCurrentOrders()
{
  int result, error, totalOrders = OrdersTotal(), orderType, orderTakeProfit;
  bool stopLossChanged = false, takeProfitChanged = false;
  double orderStopLoss, orderOpenPrice;
  string orderSymbol;
  
  Sleep(1);
  
  for(int cnt = totalOrders - 1; cnt >= 0; cnt--)
  {
    Sleep(1);

    if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES) && (OrderMagicNumber() == COGMAGIC || OrderSymbol() == Symbol()))
    { 
      orderType = OrderType();
			orderSymbol = OrderSymbol();
			orderStopLoss = OrderStopLoss();
			orderTakeProfit = OrderTakeProfit();
			//orderTicket = OrderTicket();
			//orderLots = OrderLots();
			orderOpenPrice = OrderOpenPrice();
      stopLossChanged = false;
      takeProfitChanged = false;
      getMarketInfo(OrderSymbol());
      
      if (orderType == OP_BUY || orderType == OP_SELL)
      { //Alert("ordertype is buy or sell = ", ordertype); Sleep(1000);
        if (trailStopLoss > 0)
        {
          if (OrderType() == OP_BUY)
          {
            //orderTakeprofit = (OrderTakeProfit() - OrderOpenPrice() ) * (1 / point);
            //Alert ("orderTakeprofit = ", orderTakeprofit); Sleep(5000);
            //if (currProfit > Ask - percentStartTrailStop * takeProfit * Point)
              if (trailStopLoss * point < bid - orderOpenPrice)
              { //Alert ("trailStopLoss point bid oderopenprice - trailStopLoss * point - bid - orderOpenPrice = ",
                //trailStopLoss, ", ", DoubleToStr(point, 5), ", ",  DoubleToStr(bid, 5), ", ", DoubleToStr(orderOpenPrice, 5), ", ", DoubleToStr(trailstoploss * point, 5), ", ",  DoubleToStr(bid - orderopenprice, 5));
                if (bid - trailStopLoss * point > orderStopLoss)
                {
                  stopLossChanged = true;
                  //orderStopLoss = trailStopLoss;
                }
              }
          }
          else
          {
            //orderTakeProfit = (OrderOpenPrice() - OrderTakeProfit() ) * (1 / point);
            //Alert ("orderTakeProfit = ", orderTakeProfit); Sleep(5000);
            //if (currProfit > Bid + percentStartTrailStop * takeProfit * Point)
              if (trailStopLoss * point < orderOpenPrice - ask)
              {
                if (ask + trailStopLoss * point < orderStopLoss)
                {
                  stopLossChanged = true;
                  //orderstoploss = trailstoploss;
                }
              }
          }
      
          if (stopLossChanged || takeProfitChanged)
            modifyStopLoss(trailStopLoss, takeProfit, orderType, ask, bid, point);  
        } 
      }
    }
  }
  
	return (error);
}


int modifyStopLoss(double newstoploss, double newtakeprofit,
  int ordertype, double orderask, double orderbid, double point)
{
  double stop_loss, take_profit;
  bool   result = false, spreadmatters = false;
  int    error;
	
	//Alert("setting stoploss begin - newstoploss, newtakeprofit, ordertype, orderask, orderbid = ", newstoploss, ", ", newtakeprofit, ", ", ordertype, ", ", orderask, ", ", orderbid); Sleep(1000);
	
	if(ordertype == OP_BUY || ordertype == OP_SELL)
	{
	  //if (ordertype == OP_BUY || ordertype == OP_SELL)
	    //spreadmatters = newstoploss < spread + 10;
	  //else
	    spreadmatters = true;
	    
    //while (!result && spreadmatters)
    {
      Sleep(1);
      //Alert("orderopenprice = ", OrderOpenPrice());
      if (ordertype == OP_BUY) 
      {
        stop_loss = orderask - newstoploss * point;  
        take_profit = orderask + newtakeprofit * point;
      }
      else            
      {
        stop_loss = orderbid + newstoploss * point; 
        take_profit = orderbid - newtakeprofit * point;
      }
	
      result = OrderModify(OrderTicket(), 0, stop_loss, take_profit, 0, CLR_NONE); Sleep(1); 

      if (result != TRUE)
      {
        //error = GetLastError(); Print("stoploss Error description - number - spread - newstoploss= ", ErrorDescription(error), ", ", error, ", ", spread, ", ", newstoploss );
        //newstoploss++;
      }
    }
	}
	
  return(0);
}


void CheckToOpenOrders()  
{
  if (OrdersTotal() < maxOrders)
  {
    for (int idx = 0; idx < 3; idx++)
    {
      if (Period() == PERIOD_M5 || defeatPeriodCheck)
      {
        if (cogCenter[2] > cogCenter[1] || defeatTrendDirectionCheck)
          checkToOpenHighOrder(idx);
        
        if (cogCenter[2] < cogCenter[1] || defeatTrendDirectionCheck)
          checkToOpenLowOrder(idx);
      }
    }
  }
}  

void checkToOpenHighOrder(int idx)
{
  getMarketInfo(Symbol());
  cogOrderTicket = -255;
  
  if (HighOrders[idx] == -255)
  {
    if (bid > lastHighCOG[idx])
    {
      openSellOrder(Symbol());
    
      if (cogOrderTicket >= 0)
        HighOrders[idx] = cogOrderTicket;
      
      Alert("sell bid idx lastHighCOG[idx] cogCenter[2] cogCenter[1] cogOrderTicket = ", bid, ", ", idx, ", ", lastHighCOG[idx], ", ", cogCenter[2], ", ", cogCenter[1], ", ", cogOrderTicket);
    }
  }
}

void checkToOpenLowOrder(int idx)
{
  getMarketInfo(Symbol());
  cogOrderTicket = -255;
  
  if (LowOrders[idx] == -255)
  {
    if (ask < lastLowCOG[idx])
    {
      openBuyOrder(Symbol());
    
      if (cogOrderTicket >= 0)
        LowOrders[idx] = cogOrderTicket;
    
      Alert("buy ask idx lastLowCOG[idx] cogCenter[2] cogCenter[1] cogOrderTicket = ", ask, ", ", idx, ", ", lastLowCOG[idx], ", ", cogCenter[2], ", ", cogCenter[1], ", ", cogOrderTicket);
    }
  }
}



bool openBuyOrder(string symbol)
{
  int buyOrderTicket = -1;
  
  while (buyOrderTicket < 0) // < 0 && OrdersTotal() < currmaxorders)
  {
    getMarketInfo(symbol);
    buyOrderTicket = OrderSend(symbol, OP_BUY, 0.10, ask, 3, 0, 0, "buyit", COGMAGIC, 0, CLR_NONE);
		
		if (buyOrderTicket < 0)
		{
			int error = GetLastError();
			// Print("buy Error = ", symbol, " ", ErrorDescription(error));
			
			if (error != 135) { return(buyOrderTicket >= 0); }
    }
  }

  if (buyOrderTicket >= 0) // && OrdersTotal() < currmaxorders)
  {  
    //lastopenedorder = "buy";	
	  setstoploss(stopLoss, takeProfit, OP_BUY, buyOrderTicket); 
	  cogOrderTicket = buyOrderTicket;
	}
	
	return(buyOrderTicket < 0); // && OrdersTotal() < currmaxorders);
}

bool openSellOrder(string symbol)
{
  int sellOrderTicket = -1;
  
  while (sellOrderTicket < 0) // < 0 && OrdersTotal() < currmaxorders)
  {
    getMarketInfo(symbol);
    sellOrderTicket = OrderSend(symbol, OP_SELL, 0.10, bid, 3, 0, 0, "sellit", COGMAGIC, 0, CLR_NONE);
		
		if (sellOrderTicket < 0)
		{
			int error = GetLastError();
			//Print("sell Error = ", symbol, " ", ErrorDescription(error));
			
			if (error != 135) { return(sellOrderTicket >= 0); }
    }
  }

  if (sellOrderTicket >= 0) // && OrdersTotal() < currmaxorders)
  {  
    //lastopenedorder = "sell";	
	  setstoploss(stopLoss, takeProfit, OP_SELL, sellOrderTicket);
	  cogOrderTicket = sellOrderTicket;
	}

	return(sellOrderTicket < 0); // && OrdersTotal() < currmaxorders);
}

int setstoploss(double newstoploss, double newtakeprofit, int ordertype, int orderticket)
{
  double stop_loss, take_profit;
  bool   result = false;
  int    error;

	//Print ("start stoploss - symbol newstoploss newtakeprofit bid ask = ", symbol, " ", newstoploss, " ", newtakeprofit, " ", bid, " ", ask);

  if (orderticket > -1)
  {
    if(ordertype == OP_BUY || ordertype == OP_SELL)
    {
      while (result == false)
      {
        if (ordertype == OP_BUY) 
        {
          stop_loss = ask - newstoploss * point;  
          take_profit = ask + newtakeprofit * point;
        }
        else            
        {
          stop_loss = bid + newstoploss * point; 
          take_profit = bid - newtakeprofit * point;
        }

        result = OrderModify(orderticket, OrderOpenPrice(), stop_loss, take_profit, 0, CLR_NONE); Sleep(1); 

        if (result != TRUE)
        {
          // error = GetLastError(); Print("ticket descrip errnum spread newstoploss newtakeprofit bid ask stop_loss take_profit minstoplevel = ", orderticket, " ", ErrorDescription(error), " ", error, " ", spread, " ", newstoploss, " ", newtakeprofit, " ", bid, " ", ask, " ", stop_loss, " ", take_profit, " ", minStopLevel);
          return(0);
        }
      }
    }
  }
  else
    Print ("stoploss ticket bad < 0 = ", orderticket);
  	
  return(0);
}

void GravityCenter2()
{
  //int Nmbr_Bars = 3;
  int Order = 3;
  double Ecart = 1.61803399;

  double gda_120[20][20],gda_124[20],gda_128[20],gda_132[20];
  int gi_136,gi_140,gi_144,gi_148,gi_152,gi_156,gi_160;
  double gd_164,gd_172,gd_180,gd_188,gd_196;
  datetime l_time_0 = 0;

  gi_152 = Order + 1;
  gda_124[1] = Nmbr_Bars + 1;
  for (gi_160 = 1; gi_160 <= gi_152 << 1 - 2; gi_160++) {
    gd_164 = 0;
    for (gi_156 = 0; gi_156 <= Nmbr_Bars; gi_156++) gd_164 += MathPow(gi_156, gi_160);
    gda_124[gi_160 + 1] = gd_164;
  }
  for (gi_160 = 1; gi_160 <= gi_152; gi_160++) {
    gd_164 = 0;
    for (gi_156 = 0; gi_156 <= Nmbr_Bars; gi_156++) {
       if (gi_160 == 1) gd_164 += (High[gi_156] + Low[gi_156]) / 2.0;
       else gd_164 += (High[gi_156] + Low[gi_156]) / 2.0 * MathPow(gi_156, gi_160 - 1);
    }
    gda_128[gi_160] = gd_164;
  }
  for (gi_140 = 1; gi_140 <= gi_152; gi_140++) {
    for (gi_136 = 1; gi_136 <= gi_152; gi_136++) {
       gi_144 = gi_136 + gi_140 - 1;
       gda_120[gi_136][gi_140] = gda_124[gi_144];
    }
  }
  for (gi_144 = 1; gi_144 <= gi_152 - 1; gi_144++) {
    gi_148 = 0;
    gd_188 = 0;
    for (gi_136 = gi_144; gi_136 <= gi_152; gi_136++) {
       if (MathAbs(gda_120[gi_136][gi_144]) > gd_188) {
          gd_188 = MathAbs(gda_120[gi_136][gi_144]);
          gi_148 = gi_136;
       }
    }
    if (gi_148 == 0) return (0);
    if (gi_148 != gi_144) {
       for (gi_140 = 1; gi_140 <= gi_152; gi_140++) {
          gd_196 = gda_120[gi_144][gi_140];
          gda_120[gi_144][gi_140] = gda_120[gi_148][gi_140];
          gda_120[gi_148][gi_140] = gd_196;
       }
       gd_196 = gda_128[gi_144];
       gda_128[gi_144] = gda_128[gi_148];
       gda_128[gi_148] = gd_196;
    }
    for (gi_136 = gi_144 + 1; gi_136 <= gi_152; gi_136++) {
       gd_180 = gda_120[gi_136][gi_144] / gda_120[gi_144][gi_144];
       for (gi_140 = 1; gi_140 <= gi_152; gi_140++) {
          if (gi_140 == gi_144) gda_120[gi_136][gi_140] = 0;
          else gda_120[gi_136][gi_140] = gda_120[gi_136][gi_140] - gd_180 * gda_120[gi_144][gi_140];
       }
       gda_128[gi_136] = gda_128[gi_136] - gd_180 * gda_128[gi_144];
    }
  }
  gda_132[gi_152] = gda_128[gi_152] / gda_120[gi_152][gi_152];
  for (gi_136 = gi_152 - 1; gi_136 >= 1; gi_136--) {
    gd_196 = 0;
    for (gi_140 = 1; gi_140 <= gi_152 - gi_136; gi_140++) {
       gd_196 += (gda_120[gi_136][gi_136 + gi_140]) * (gda_132[gi_136 + gi_140]);
       gda_132[gi_136] = 1 / gda_120[gi_136][gi_136] * (gda_128[gi_136] - gd_196);
    }
  }
  for (gi_156 = 0; gi_156 <= Nmbr_Bars; gi_156++) {
    gd_164 = 0;
    for (gi_144 = 1; gi_144 <= Order; gi_144++) gd_164 += (gda_132[gi_144 + 1]) * MathPow(gi_156, gi_144);
    cogCenter[gi_156] = gda_132[1] + gd_164;
  }
  gd_172 = iStdDev(NULL, 0, Nmbr_Bars, 0, MODE_SMA, PRICE_HIGH, 0) * Ecart;
  for (gi_156 = 0; gi_156 <= Nmbr_Bars; gi_156++) {
    cogHigh3[gi_156] = cogCenter[gi_156] + gd_172;
    cogHigh2[gi_156] = cogCenter[gi_156] + (cogHigh3[gi_156] - cogCenter[gi_156]) / 1.382;
    cogHigh1[gi_156] = cogCenter[gi_156] + (cogHigh2[gi_156] - cogCenter[gi_156]) / 1.618;
    cogLow1[gi_156] = cogCenter[gi_156] - gd_172;
    cogLow2[gi_156] = cogCenter[gi_156] - (cogCenter[gi_156] - cogLow1[gi_156]) / 1.382;
    cogLow3[gi_156] = cogCenter[gi_156] - (cogCenter[gi_156] - cogLow2[gi_156]) / 1.618;
  }
} 

void setLastCOGvalues()
{
  lastHighCOG[0] = cogHigh1[1];
  lastHighCOG[1] = cogHigh2[1];
  lastHighCOG[2] = cogHigh3[1];
  lastLowCOG[0] = cogLow1[1];
  lastLowCOG[1] = cogLow2[1];
  lastLowCOG[2] = cogLow3[1];
}

void calcSpans()
{
  cogHighLowSpan = lastHighCOG[2] - lastLowCOG[0];
  cogHigh3High2Span = lastHighCOG[2] - lastHighCOG[1];
  cogHigh2High1Span = lastHighCOG[1] - lastHighCOG[0];
  cogLow3Low2Span = lastLowCOG[2] - lastLowCOG[1];
  cogLow2Low1Span = lastLowCOG[1] - lastLowCOG[0];
  cogHigh1Center = cogHigh1[1] - cogCenter[1];
  cogLow3Center = cogCenter[1] - cogLow3[1];
  
  if (!runOnce)
  {
    Print("gc bid cogHigh3[1] cogHigh2[1] cogHigh1[1] cogCenter[2] cogCenter[1] = ", bid, ", ", cogHigh3[1], ", ", cogHigh2[1], ", ", cogHigh1[1], ", ", cogCenter[2], ", ", cogCenter[1]);
    Print("gc ask cogLow3[1] cogLow2[1] cogLow1[1] cogCenter[2] cogCenter[1] = ", ask, ", ", cogLow3[1], ", ", cogLow2[1], ", ", cogLow1[1], ", ", cogCenter[2], ", ", cogCenter[1]);
    Print("price cogHighLowSpan, cogHigh3High2Span, cogHigh2High1Span, cogLow3Low2Span, cogLow2Low1Span, cogHigh1Center, cogLow3Center = ", cogHighLowSpan, ", ", cogHigh3High2Span, ", ", cogHigh2High1Span, ", ", cogLow3Low2Span, ", ", cogLow2Low1Span, ", ", cogHigh1Center, ", ", cogLow3Center);
    Print("pips cogHighLowSpan, cogHigh3High2Span, cogHigh2High1Span, cogLow3Low2Span, cogLow2Low1Span, cogHigh1Center, cogLow3Center = ", cogHighLowSpan / point, ", ", cogHigh3High2Span / point, ", ", cogHigh2High1Span / point, ", ", cogLow3Low2Span / point, ", ", cogLow2Low1Span / point, ", ", cogHigh1Center / point, ", ", cogLow3Center / point);
    runOnce = true;
  }
}

void getMarketInfo(string symbol)
{
  RefreshRates();
  //bid = MarketInfo(symbol, MODE_BID);
  //ask = MarketInfo(symbol, MODE_ASK);
  //point = MarketInfo(symbol, MODE_POINT);
  //Alert ("point = ", point); Sleep(5000); return (0);
  digits = MarketInfo(symbol, MODE_DIGITS);
  spread = MarketInfo(symbol, MODE_SPREAD);
  minStopLevel = MarketInfo(symbol, MODE_STOPLEVEL);
  //Alert("min stop level = ", minstoplevel); Sleep(1000);
  //Alert("spread = ", spread); return (0); Sleep(1000);
  bid = NormalizeDouble(MarketInfo(symbol, MODE_BID), digits);
  ask = NormalizeDouble(MarketInfo(symbol, MODE_ASK), digits);
  point = NormalizeDouble(MarketInfo(symbol, MODE_POINT), digits);
  //Alert("bid ask point = ", bid, ", ", ask, ", ", point); Sleep(10000);
}  
  
/**
 * Recalculates current free, used margin and other values
 */
double updateMoneyManager()
{
   balance = AccountBalance();
   equity = AccountEquity();
   
   marginFree = AccountFreeMargin();
   marginUsed = equity - marginFree;
   
   marginUsedPercent = marginUsed / equity * 100;
   marginUsablePercent = marginFree / equity * 100;
   
   profitLossPercentage = AccountProfit() / balance * 100;
}  