//+------------------------------------------------------------------+
#define g_strEAname "Generic EA" 
#define g_nSystemID    20070428 // chanege to current date
//|                                               Paul Hampton-Smith |
//+------------------------------------------------------------------+

// MarketInfo variables
int g_nDigits = 0;
double g_dblBid = 0.0;
double g_dblAsk = 0.0;
double g_dblPoint = 0.0;
double g_dblSwapLong = 0.0;		
double g_dblSwapShort = 0.0;

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// CODE SPECIFIC TO THIS EA BELOW THIS
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////


// external optimisable variables
extern int e_nStopLoss = 50;
extern int e_nTakeProfit = 50;
extern bool e_bTrailingStop = false;

// custom variables for this EA
extern int e_nPeriod = PERIOD_D1; // run the EA on this timeframe chart
extern int e_nMAperiod = 200;

// money management
extern double e_dblLots = 0.1;
extern bool e_bMoneyManagement = false;
extern int e_nStartCapital = 5000;
extern int e_nPercentOfMargin = 2;

// Indicator variables
double g_MA1 = 0.0;
double g_Close1 = 0.0;


bool LoadIndicatorValues()
{
	g_Close1 = Close[1];
	g_MA1 = iMA(Symbol(),0,e_nMAperiod,0,MODE_SMA,PRICE_CLOSE,1);

	// sanity check of values	
	if (g_Close1 == 0 || g_MA1 == 0)
	{
		Print("Error in LoadIndicatorValues() ",CommentLine());
		return(false);
	}
	else
	{
		return(true);
	}
}

bool BuyEntrySignal()
{
	return(
		g_Close1 > g_MA1 &&
		OpenOrders() == 0
		);
} 

bool SellEntrySignal()
{
	return(
		g_Close1 < g_MA1 &&
		OpenOrders() == 0
		);
} 

bool BuyExitSignal()
{
	return(
		g_Close1 < g_MA1
		);
} 
      
bool SellExitSignal()
{
	return(
		g_Close1 > g_MA1
		);
} 

string CommentLine()
{
	return("");
}


/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// GENERIC CODE BELOW THIS
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

#include <Stdlib.mqh>

int start()
{
	if (e_nPeriod != 0 && e_nPeriod != Period())
	{
		Alert("This EA should only run on a ",PeriodToStr(e_nPeriod)," chart");
		return(0);
	}

	if (!LoadMarketInfo()) return(0); // once we know g_strSymbol, load the current MarketInfo values
	if (!LoadIndicatorValues()) return(0); // create all the indicator values needed for entry and exit
	if (e_bTrailingStop) AdjustTrailingStops();
	ConditionalExit(); // exit if exit rules are met
	MoneyManagement(); // adjust lot size according to account balance and risk
	ConditionalEntry(); // enter if entry rules are met
	Comment(CommentLine()); // display info

   return(0);  
}

int OpenOrders()
{
	// counts total buy and sell open orders
   int nCount = 0;
   for ( int nPosition=0 ; nPosition<OrdersTotal() ; nPosition++ )
   {
      OrderSelect(nPosition, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol()==Symbol() &&
         ( OrderType() == OP_BUY || OrderType() == OP_SELL ) &&
         OrderMagicNumber() == g_nSystemID )
      {
         nCount++;
      }
   }
   return(nCount);
}

void ConditionalExit()
{
   for ( int nPosition=0 ; nPosition<OrdersTotal() ; nPosition++ )
   {
      OrderSelect(nPosition, SELECT_BY_POS, MODE_TRADES);
      if( OrderSymbol()==Symbol() && OrderMagicNumber()==g_nSystemID)
      {
      	switch (OrderType())
      	{
      	case OP_BUY:
	         if (BuyExitSignal()) 
            {
           		OrderClose(OrderTicket(),OrderLots(),g_dblBid,3,Violet);
					Print(ErrorDescription(GetLastError())); 
            }
            break;
      	case OP_SELL:
         	if (SellExitSignal())
           	{
					OrderClose(OrderTicket(),OrderLots(),g_dblAsk,3,Violet);
					Print(ErrorDescription(GetLastError())); 
            }
         }
      }
   }
}

int ConditionalEntry()
{
	// defaults
	int nSlippage = 3;
	color clrBuy = Green;
	color clrSell = Red;

	double dblStopLoss = 0.0, dblTakeProfit = 0.0;
	int nTicket;

	if (BuyEntrySignal())
	{
		if (e_nStopLoss > 0) dblStopLoss = NormalizeDouble(g_dblAsk-e_nStopLoss*g_dblPoint,g_nDigits);
		if (e_nTakeProfit > 0) dblTakeProfit = NormalizeDouble(g_dblBid+e_nTakeProfit*g_dblPoint,g_nDigits);
		nTicket = OrderSend(Symbol(),OP_BUY,e_dblLots,g_dblAsk,nSlippage,dblStopLoss,dblTakeProfit,g_strEAname,g_nSystemID,0,clrBuy);
		Print(ErrorDescription(GetLastError())); 
		return(nTicket);
	}
	
	if (SellEntrySignal())
	{
		if (e_nStopLoss > 0) dblStopLoss = NormalizeDouble(g_dblBid+e_nStopLoss*g_dblPoint,g_nDigits);
		if (e_nTakeProfit > 0) dblTakeProfit = NormalizeDouble(g_dblAsk-e_nTakeProfit*g_dblPoint,g_nDigits);
		nTicket = OrderSend(Symbol(),OP_SELL,e_dblLots,g_dblBid,nSlippage,dblStopLoss,dblTakeProfit,g_strEAname,g_nSystemID,0,clrSell);
		Print(ErrorDescription(GetLastError())); 
		return(nTicket);
	}
	return(-1); // no entry signal
}


bool LoadMarketInfo()
{
	g_nDigits = Digits;		
	g_dblBid = NormalizeDouble(Bid,g_nDigits);		
	g_dblAsk = NormalizeDouble(Ask,g_nDigits);		
	g_dblPoint = NormalizeDouble(Point,g_nDigits);		
	g_dblSwapLong = MarketInfo(Symbol(),MODE_SWAPLONG);		
	g_dblSwapShort = MarketInfo(Symbol(),MODE_SWAPSHORT);
	
	// sanity check
	if (g_nDigits == 0 || g_dblBid == 0 || g_dblAsk == 0 || g_dblPoint == 0)
	{
		Print("Error in LoadMarketInfo()");
		return(false);
	}
	else
	{
		return(true);
	}
}


void MoneyManagement()
{
	if (e_bMoneyManagement)
	{
  		e_dblLots = NormalizeDouble((e_nPercentOfMargin/100.0)*(AccountFreeMargin()-e_nStartCapital)*AccountLeverage()/MarketInfo(Symbol(),MODE_LOTSIZE),1);
		// if using 100% (!!!!), reduce slightly to ensure under limit
   	if (e_nPercentOfMargin == 100) e_dblLots -= 0.1;
	}
	// if !e_bMoneyManagement, no change to e_dblLots

	// minimum lots is 0.1
   e_dblLots = MathMax(e_dblLots,0.1);
}

string PeriodToStr(int nPeriod)
{
	switch(nPeriod)
	{
	case PERIOD_M1: return("1 Minute");
	case PERIOD_M5: return("5 Minute");
	case PERIOD_M15: return("15 Minute");
	case PERIOD_M30: return("30 Minute");
	case PERIOD_H1: return("1 Hour");
	case PERIOD_H4: return("4 Hour");
	case PERIOD_D1: return("Daily");
	case PERIOD_W1: return("Weekly");
	case PERIOD_MN1: return("Monthly");
	default: return("Unknown period");
	}
}	

void AdjustTrailingStops()
{
   for ( int nPosition=0 ; nPosition<OrdersTotal() ; nPosition++ )
   {
      OrderSelect(nPosition, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol()==Symbol() && OrderMagicNumber() == g_nSystemID)
      {
      	double dblNewStop = 0.0;
      	switch(OrderType())
      	{
      	case OP_BUY:
      		dblNewStop = NormalizeDouble(g_dblBid-e_nStopLoss*g_dblPoint,g_nDigits);
      		if (dblNewStop > OrderStopLoss())
         	{
            	OrderModify(OrderTicket(),OrderOpenPrice(),dblNewStop,OrderTakeProfit(),0,Green);
         	}
         	break;
         case OP_SELL:
      		dblNewStop = NormalizeDouble(g_dblAsk+e_nStopLoss*g_dblPoint,g_nDigits);
      		if (dblNewStop < OrderStopLoss())
	         {
   	         OrderModify(OrderTicket(),OrderOpenPrice(),dblNewStop,OrderTakeProfit(),0,Red);
      	   }
      	}
      } 
   }
}

