Navigation:Home > Content >

CCI_Cross_Grid_v1.5_Build_765.mq4

Time: 2014-12-15 | Download file:CCI_Cross_Grid_v1.5_Build_765.mq4

#include 
#include  
#property copyright "Copyright © 2011, www.lifesdream.org"
#property link "http://www.lifesdream.org"
#property strict
// ------------------------------------------------------------------------------------------------
// EXTERN VARS
// ------------------------------------------------------------------------------------------------
extern int magic = 79205;
// Configuration
extern string EAName = "CCI Cross Grid v1.5";
extern string CommonSettings = "---------------------------------------------";
extern int user_slippage = 2; 
extern int grid_size = 35;
extern double profit_lock = 0.60;
extern int profit_mode = 1;
extern string MoneyManagementSettings = "---------------------------------------------";
// Money Management
extern double min_lots = 0.01;
extern double min_lots_increment = 0.1;
extern double account_risk = 100.0;
// Indicator
extern string IndicatorSettings = "---------------------------------------------";
extern int cci_period = 60;
extern int cci_cross_level = 100;
extern int shift = 0;

// ------------------------------------------------------------------------------------------------
// GLOBAL VARS
// ------------------------------------------------------------------------------------------------
string key = "CCI Cross Grid v1.5";
// Ticket
int buy_tickets[50];
int sell_tickets[50];
// Lots
double buy_lots[50];
double sell_lots[50];
// Current Profit
double buy_profit[50];
double sell_profit[50];
// Open Price
double buy_price[50];
double sell_price[50];
// Indicator
double cci1=0, cci2=0;
// Number of orders
int buys = 0;
int sells = 0;
double total_buy_profit=0,total_sell_profit=0;
double total_buy_lots=0, total_sell_lots=0;
double buy_max_profit=0, buy_close_profit=0;
double sell_max_profit=0, sell_close_profit=0;
int slippage=0;
// OrderReliable
int retry_attempts = 10; 
double sleep_time = 4.0;
double sleep_maximum	= 25.0;  // in seconds
string OrderReliable_Fname = "OrderReliable fname unset";
static int _OR_err = 0;
string OrderReliableVersion = "V1_1_1"; 
bool   errororder = true;
// ------------------------------------------------------------------------------------------------
// START
// ------------------------------------------------------------------------------------------------
int start()
{  
  double point = MarketInfo(Symbol(), MODE_POINT);
  double dd=0;
  
  if (MarketInfo(Symbol(),MODE_DIGITS)==4 || MarketInfo(Symbol(),MODE_DIGITS)==2)
  {
    slippage = user_slippage;
  }
  else if (MarketInfo(Symbol(),MODE_DIGITS)==5 || MarketInfo(Symbol(),MODE_DIGITS)==3)
  {
    slippage = 10*user_slippage;
  }
  
  if(IsTradeAllowed() == false) 
  {
    Comment("Copyright © 2011, www.lifesdream.org\nTrade not allowed.");
    return(0);  
  }
  
  // Updating current status
  InitVars();
  UpdateVars();
  SortByLots();
  ShowData();
  ShowLines();
  
  Robot();
  
  return(0);
}

// ------------------------------------------------------------------------------------------------
// INIT VARS
// ------------------------------------------------------------------------------------------------
void InitVars()
{
  // Reset number of buy/sell orders
  buys=0;
  sells=0;
  // Reset arrays
  for(int i=0; i<50; i++)
  {
    buy_tickets[i] = 0;
    buy_lots[i] = 0;
    buy_profit[i] = 0;
    buy_price[i] = 0;
    sell_tickets[i] = 0;
    sell_lots[i] = 0;
    sell_profit[i] = 0;
    sell_price[i] = 0;    
  }
}

// ------------------------------------------------------------------------------------------------
// BUY RESET AFTER CLOSE
// ------------------------------------------------------------------------------------------------
void BuyResetAfterClose()
{
   buy_max_profit=0;
   buy_close_profit=0;  
   ObjectDelete("line_buy");
   ObjectDelete("line_buy_ts");
}

// ------------------------------------------------------------------------------------------------
// SELL RESET AFTER CLOSE
// ------------------------------------------------------------------------------------------------
void SellResetAfterClose()
{
   sell_max_profit=0;
   sell_close_profit=0;   
   ObjectDelete("line_sell");
   ObjectDelete("line_sell_ts");
}

// ------------------------------------------------------------------------------------------------
// UPDATE VARS
// ------------------------------------------------------------------------------------------------
void UpdateVars()
{
  int aux_buys=0, aux_sells=0;
  double aux_total_buy_profit=0, aux_total_sell_profit=0;
  double aux_total_buy_lots=0, aux_total_sell_lots=0;
  
  // We are going to introduce data from opened orders in arrays  
  for(int i=0; i0 && buy_lots[j]>0)
      {
        // at least 2 orders
        if (buy_lots[j]0 && sell_lots[j]>0)
      {
        // at least 2 orders
        if (sell_lots[j]user_slippage) point=point*10;
  
  if (buys>=1)
  { 
    if (profit_mode==1) aux_tp_buy = CalculateTP(buy_lots[0]);
    if (profit_mode==2) aux_tp_buy = (CalculateTP(total_buy_lots)/buys);
  }  
  
  if (sells>=1)
  {
    if (profit_mode==1) aux_tp_sell = CalculateTP(sell_lots[0]);
    if (profit_mode==2) aux_tp_sell = (CalculateTP(total_sell_lots)/sells);
  }
  
  if (buys>=1)
  {
    buy_pip = CalculatePipValue(buy_lots[0]);    
    for (i=0;i<50;i++) buy_v[i] = 0;  
    
    for (i=0;i0)
    {
      buy_tar = buy_close_profit/(buy_pip/point);
      buy_tar = buy_tar + buy_b;
      buy_tar = buy_tar/buy_a;
      HorizontalLine(buy_tar,"line_buy_ts",DodgerBlue,STYLE_DASH,1);
    }
  }
  
  if (sells>=1)
  {
    sell_pip = CalculatePipValue(sell_lots[0]);    
    for (i=0;i<50;i++) sell_v[i] = 0;  
    
    for (i=0;i0)
    {
      sell_tar = -1*(sell_close_profit/(sell_pip/point));
      sell_tar = sell_tar + sell_b;
      sell_tar = sell_tar/sell_a;
      HorizontalLine(sell_tar,"line_sell_ts",Tomato,STYLE_DASH,1);
    }
  }

}

// ------------------------------------------------------------------------------------------------
// SHOW DATA
// ------------------------------------------------------------------------------------------------
void ShowData()
{
  string txt;
  double aux_tp_buy=0, aux_tp_sell=0;
  
  if (buys>=1)
  { 
    if (profit_mode==1) aux_tp_buy = CalculateTP(buy_lots[0]);
    if (profit_mode==2) aux_tp_buy = (CalculateTP(total_buy_lots)/buys);
  }  
  
  if (sells>=1)
  {
    if (profit_mode==1) aux_tp_sell = CalculateTP(sell_lots[0]);
    if (profit_mode==2) aux_tp_sell = (CalculateTP(total_sell_lots)/sells);
  }
        
  txt = "\nCopyright © 2011, www.lifesdream.org" +
        "\nCCI Cross Grid v1.5 is running." +
        "\n" +
        "\nSETTINGS: " + 
        "\nGrid size: " + IntegerToString(grid_size,Digits) +
        "\nProfit locked: " + DoubleToStr(100*profit_lock,2) + "%" +
        "\nMinimum lots: " + DoubleToStr(min_lots,2) +
        "\nAccount risk: " + DoubleToStr(account_risk,0) + "%" +
        "\nCCI period: " + DoubleToStr(cci_period,0) +
        "\nCCI cross level: " + DoubleToStr(cci_cross_level,0) +
        "\nCCI shift: " + DoubleToStr(shift,0) +
        
        "\n" +
        "\nBUY ORDERS" +
        "\nNumber of orders: " + IntegerToString(buys,Digits) +
        "\nTotal lots: " + DoubleToStr(total_buy_lots,2) +         
        "\nCurrent profit: " + DoubleToStr(total_buy_profit,2) + 
        "\nProfit goal: $" + DoubleToStr(aux_tp_buy,2) + 
        "\nMaximum profit reached: $" + DoubleToStr(buy_max_profit,2) + 
        "\nProfit locked: $" + DoubleToStr(buy_close_profit,2) + 
        
        "\n" +
        "\nSELL ORDERS" +
        "\nNumber of orders: " + IntegerToString(sells,Digits) +
        "\nTotal lots: " + DoubleToStr(total_sell_lots,2) +   
        "\nCurrent profit: " + DoubleToStr(total_sell_profit,2) +       
        "\nProfit goal: $" + DoubleToStr(aux_tp_sell,2) + 
        "\nMaximum profit reached: $" + DoubleToStr(sell_max_profit,2) + 
        "\nProfit locked: $" + DoubleToStr(sell_close_profit,2);
  
  Comment(txt);
}


// ------------------------------------------------------------------------------------------------
// WRITE
// ------------------------------------------------------------------------------------------------
void Write(string name, string s, int x, int y, string font, int size, color c)
{
  if (ObjectFind(name)!=-1)
  {
    ObjectSetText(name,s,size,font,c);
  }
  else
  {
    ObjectCreate(name,OBJ_LABEL,0,0,0);
    ObjectSetText(name,s,size,font,c);
    ObjectSet(name,OBJPROP_XDISTANCE, x);
    ObjectSet(name,OBJPROP_YDISTANCE, y);
  }
}

// ------------------------------------------------------------------------------------------------
// HORIZONTAL LINE
// ------------------------------------------------------------------------------------------------
void HorizontalLine(double value, string name, color c, int style, int thickness) 
{
  if(ObjectFind(name) == -1)
  {
    ObjectCreate(name, OBJ_HLINE, 0, Time[0], value);
    
    ObjectSet(name, OBJPROP_STYLE, style);             
    ObjectSet(name, OBJPROP_COLOR, c);
    ObjectSet(name,OBJPROP_WIDTH,thickness);
  }
  else
  {
    ObjectSet(name,OBJPROP_PRICE1,value);
    ObjectSet(name, OBJPROP_STYLE, style);             
    ObjectSet(name, OBJPROP_COLOR, c);
    ObjectSet(name,OBJPROP_WIDTH,thickness);
  }  
}

// ------------------------------------------------------------------------------------------------
// CALCULATE STARTING VOLUME
// ------------------------------------------------------------------------------------------------
double CalculateStartingVolume()
{ 
  double aux; 
 
  aux=min_lots;

  if (aux>MarketInfo(Symbol(),MODE_MAXLOT))
    aux=MarketInfo(Symbol(),MODE_MAXLOT);
      
  if (aux=1)
  {
    decimals=0;
  }  
  else
  {
    decimals=0;
    aux=volume;
    while (aux<1)
    {
      decimals = decimals + 1;
      aux = aux * 10;
    }
  }
  
  return(decimals);
}
// ------------------------------------------------------------------------------------------------
// MARTINGALE VOLUME
// ------------------------------------------------------------------------------------------------
double MartingaleVolume(double losses)
{ 
  double aux, grid_value, multiplier; 
  
  grid_value = CalculateTP(min_lots); // minimum grid value
  multiplier = MathFloor(MathAbs(losses/grid_value));
  
  aux = NormalizeDouble(multiplier*min_lots_increment,(int)CalculateDecimals(min_lots_increment));
  
  if (aux < min_lots) aux = min_lots;
    
  if (aux>MarketInfo(Symbol(),MODE_MAXLOT))
    aux=MarketInfo(Symbol(),MODE_MAXLOT);
      
  if (auxAccountEquity())
  {
    // Closing buy orders
    for (i=0; i<=buys-1; i++) 
    {
      cerrada=OrderCloseReliable(buy_tickets[i],buy_lots[i],MarketInfo(Symbol(),MODE_BID),slippage,Blue);
    }
    // Closing sell orders
    for (i=0; i<=sells-1; i++) 
    {
      cerrada=OrderCloseReliable(sell_tickets[i],sell_lots[i],MarketInfo(Symbol(),MODE_ASK),slippage,Red);
    }
    BuyResetAfterClose();
    SellResetAfterClose();
  }  
  
  // **************************************************
  // BUYS==0
  // **************************************************
  if (buys==0)
  {
    if (cci1>-1*cci_cross_level && cci2<-1*cci_cross_level) 
      ticket = OrderSendReliable(Symbol(),OP_BUY,CalculateStartingVolume(),MarketInfo(Symbol(),MODE_ASK),slippage,0,0,key,magic,0,Blue);      
  }  

  // **************************************************
  // BUYS>=1
  // **************************************************  
  if (buys>=1)
  {
    // CASE 1 >>> We reach Stop Loss (grid size)    
    if (total_buy_profit < CalculateSL(total_buy_lots))
    {
      if (buys<50 && cci1>-1*cci_cross_level && cci2<-1*cci_cross_level) 
      {
        ticket = OrderSendReliable(Symbol(),OP_BUY,MartingaleVolume(total_buy_profit),MarketInfo(Symbol(),MODE_ASK),slippage,0,0,key,magic,0,Blue); 
      }
    } 
    
    // CASE 2.1 >>> We reach Take Profit so we activate profit lock
    if (buy_max_profit==0 && profit_mode==1 && total_buy_profit > CalculateTP(buy_lots[0]))
    {
      buy_max_profit = total_buy_profit;
      buy_close_profit = profit_lock*buy_max_profit;
    }
    if (buy_max_profit==0 && profit_mode==2 && total_buy_profit > (CalculateTP(total_buy_lots)/buys))
    {
      buy_max_profit = total_buy_profit;
      buy_close_profit = profit_lock*buy_max_profit;
    }
    
    // CASE 2.2 >>> Profit locked is updated in real time
    if (buy_max_profit>0)
    {
      if (total_buy_profit>buy_max_profit)
      {      
        buy_max_profit = total_buy_profit;
        buy_close_profit = profit_lock*total_buy_profit; 
      }
    }   
    
    // CASE 2.3 >>> If profit falls below profit locked we close all orders
    if (buy_max_profit>0 && buy_close_profit>0 && buy_max_profit>buy_close_profit && total_buy_profit1)
  
  // **************************************************
  // SELLS==0
  // **************************************************
  if (sells==0)
  {
    if (cci1cci_cross_level) 
      ticket = OrderSendReliable(Symbol(),OP_SELL,CalculateStartingVolume(),MarketInfo(Symbol(),MODE_BID),slippage,0,0,key,magic,0,Red);   
  }  
  
  // **************************************************
  // SELLS>=1
  // **************************************************  
  if (sells>=1)
  {
    // CASE 1 >>> We reach Stop Loss (grid size)   
    if (total_sell_profit < CalculateSL(total_sell_lots))
    {
      if (sells<50 && cci1cci_cross_level)
      {
        ticket = OrderSendReliable(Symbol(),OP_SELL,MartingaleVolume(total_sell_profit),MarketInfo(Symbol(),MODE_BID),slippage,0,0,key,magic,0,Red); 
      }
    } 
    
    // CASE 2.1 >>> We reach Take Profit so we activate profit lock
    if (sell_max_profit==0 && profit_mode==1 && total_sell_profit > CalculateTP(sell_lots[0]))
    {
      sell_max_profit = total_sell_profit;
      sell_close_profit = profit_lock*sell_max_profit;
    }
    if (sell_max_profit==0 && profit_mode==2 && total_sell_profit > (CalculateTP(total_sell_lots)/sells))
    {
      sell_max_profit = total_sell_profit;
      sell_close_profit = profit_lock*sell_max_profit;
    }
    
    // CASE 2.2 >>> Profit locked is updated in real time
    if (sell_max_profit>0)
    {
      if (total_sell_profit>sell_max_profit)
      {      
        sell_max_profit = total_sell_profit;
        sell_close_profit = profit_lock*sell_max_profit;
      }
    }   
    
    // CASE 2.3 >>> If profit falls below profit locked we close all orders
    if (sell_max_profit>0 && sell_close_profit>0 && sell_max_profit>sell_close_profit && total_sell_profit1)  
  
  
    
}


//=============================================================================
//							 OrderSendReliable()
//
//	This is intended to be a drop-in replacement for OrderSend() which, 
//	one hopes, is more resistant to various forms of errors prevalent 
//	with MetaTrader.
//			  
//	RETURN VALUE: 
//
//	Ticket number or -1 under some error conditions.  Check
// final error returned by Metatrader with OrderReliableLastErr().
// This will reset the value from GetLastError(), so in that sense it cannot
// be a total drop-in replacement due to Metatrader flaw. 
//
//	FEATURES:
//
//		 * Re-trying under some error conditions, sleeping a random 
//		   time defined by an exponential probability distribution.
//
//		 * Automatic normalization of Digits
//
//		 * Automatically makes sure that stop levels are more than
//		   the minimum stop distance, as given by the server. If they
//		   are too close, they are adjusted.
//
//		 * Automatically converts stop orders to market orders 
//		   when the stop orders are rejected by the server for 
//		   being to close to market.  NOTE: This intentionally
//       applies only to OP_BUYSTOP and OP_SELLSTOP, 
//       OP_BUYLIMIT and OP_SELLLIMIT are not converted to market
//       orders and so for prices which are too close to current
//       this function is likely to loop a few times and return
//       with the "invalid stops" error message. 
//       Note, the commentary in previous versions erroneously said
//       that limit orders would be converted.  Note also
//       that entering a BUYSTOP or SELLSTOP new order is distinct
//       from setting a stoploss on an outstanding order; use
//       OrderModifyReliable() for that. 
//
//		 * Displays various error messages on the log for debugging.
//
//
//	Matt Kennel, 2006-05-28 and following
//
//=============================================================================
int OrderSendReliable(string symbol, int cmd, double volume, double price,
					  int lslippage, double stoploss, double takeprofit,
					  string comment, int lmagic, datetime expiration = 0, 
					  color arrow_color = CLR_NONE) 
{

	// ------------------------------------------------
	// Check basic conditions see if trade is possible. 
	// ------------------------------------------------
	OrderReliable_Fname = "OrderSendReliable";
	OrderReliablePrint(" attempted " + OrderReliable_CommandString(cmd) + " " + DoubleToString(volume,Digits) + 
						" lots @" + DoubleToString(price,Digits) + " sl:" + DoubleToString(stoploss,Digits) + " tp:" + DoubleToString(takeprofit,Digits)); 
						
	//if (!IsConnected()) 
	//{
	//	OrderReliablePrint("error: IsConnected() == false");
	//	_OR_err = ERR_NO_CONNECTION; 
	//	return(-1);
	//}
	
	if (IsStopped()) 
	{
		OrderReliablePrint("error: IsStopped() == true");
		_OR_err = ERR_COMMON_ERROR; 
		return(-1);
	}
	
	int cnt = 0;
	while(!IsTradeAllowed() && cnt < retry_attempts) 
	{
		OrderReliable_SleepRandomTime(sleep_time, sleep_maximum); 
		cnt++;
	}
	
	if (!IsTradeAllowed()) 
	{
		OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries.");
		_OR_err = ERR_TRADE_CONTEXT_BUSY; 

		return(-1);  
	}

	// Normalize all price / stoploss / takeprofit to the proper # of digits.
	int digits = (int)MarketInfo(symbol, MODE_DIGITS);
	if (digits > 0) 
	{
		price = NormalizeDouble(price, digits);
		stoploss = NormalizeDouble(stoploss, digits);
		takeprofit = NormalizeDouble(takeprofit, digits); 
	}
	
	if (stoploss != 0) 
		OrderReliable_EnsureValidStop(symbol, price, stoploss); 

	int err = GetLastError(); // clear the global variable.  
	err = 0; 
	_OR_err = 0; 
	bool exit_loop = false;
	bool limit_to_market = false; 
	
	// limit/stop order. 
	int ticket=-1;

	if ((cmd == OP_BUYSTOP) || (cmd == OP_SELLSTOP) || (cmd == OP_BUYLIMIT) || (cmd == OP_SELLLIMIT)) 
	{
		cnt = 0;
		while (!exit_loop) 
		{
			if (IsTradeAllowed()) 
			{
				ticket = OrderSend(symbol, cmd, volume, price, lslippage, stoploss, 
									takeprofit, comment, lmagic, expiration, arrow_color);
				err = GetLastError();
				_OR_err = err; 
			} 
			else 
			{
				cnt++;
			} 

         double servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * MarketInfo(symbol, MODE_POINT); 
			switch (err) 
			{
				case ERR_NO_ERROR:
					exit_loop = true;
					break;
				
				// retryable errors
				case ERR_SERVER_BUSY:
				case ERR_NO_CONNECTION:
				case ERR_INVALID_PRICE:
				case ERR_OFF_QUOTES:
				case ERR_BROKER_BUSY:
				case ERR_TRADE_CONTEXT_BUSY: 
					cnt++; 
					break;
					
				case ERR_PRICE_CHANGED:
				case ERR_REQUOTE:
					RefreshRates();
					continue;	// we can apparently retry immediately according to MT docs.
					
				case ERR_INVALID_STOPS:
					if (cmd == OP_BUYSTOP) 
					{
						// If we are too close to put in a limit/stop order so go to market.
						if (MathAbs(MarketInfo(symbol,MODE_ASK) - price) <= servers_min_stop)	
							limit_to_market = true; 
							
					} 
					else if (cmd == OP_SELLSTOP) 
					{
						// If we are too close to put in a limit/stop order so go to market.
						if (MathAbs(MarketInfo(symbol,MODE_BID) - price) <= servers_min_stop)
							limit_to_market = true; 
					}
					exit_loop = true; 
					break; 
					
				default:
					// an apparently serious error.
					exit_loop = true;
					break; 
					
			}  // end switch 

			if (cnt > retry_attempts) 
				exit_loop = true; 
			 	
			if (exit_loop) 
			{
				if (err != ERR_NO_ERROR) 
				{
					OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); 
				}
				if (cnt > retry_attempts) 
				{
					OrderReliablePrint("retry attempts maxed at " + IntegerToString(retry_attempts,Digits)); 
				}
			}
			 
			if (!exit_loop) 
			{
				OrderReliablePrint("retryable error (" + IntegerToString(cnt,Digits) + "/" + IntegerToString(retry_attempts,Digits) + 
									"): " + OrderReliableErrTxt(err)); 
				OrderReliable_SleepRandomTime(sleep_time, sleep_maximum); 
				RefreshRates(); 
			}
		}
		 
		// We have now exited from loop. 
		if (err == ERR_NO_ERROR) 
		{
			OrderReliablePrint("apparently successful OP_BUYSTOP or OP_SELLSTOP order placed, details follow.");
			errororder = OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); 
			OrderPrint(); 
			return(ticket); // SUCCESS! 
		} 
		if (!limit_to_market) 
		{
			OrderReliablePrint("failed to execute stop or limit order after " + IntegerToString(cnt,Digits) + " retries");
			OrderReliablePrint("failed trade: " + OrderReliable_CommandString(cmd) + " " + symbol + 
								"@" + DoubleToString(price,Digits) + " tp@" + DoubleToString(takeprofit,Digits) + " sl@" + DoubleToString(stoploss,Digits)); 
			OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); 
			return(-1); 
		}
	}  // end	  
  
	if (limit_to_market) 
	{
		OrderReliablePrint("going from limit order to market order because market is too close.");
		if ((cmd == OP_BUYSTOP) || (cmd == OP_BUYLIMIT)) 
		{
			cmd = OP_BUY;
			price = MarketInfo(symbol,MODE_ASK);
		} 
		else if ((cmd == OP_SELLSTOP) || (cmd == OP_SELLLIMIT)) 
		{
			cmd = OP_SELL;
			price = MarketInfo(symbol,MODE_BID);
		}	
	}
	
	// we now have a market order.
	err = GetLastError(); // so we clear the global variable.  
	err = 0; 
	_OR_err = 0; 
	ticket = -1;

	if ((cmd == OP_BUY) || (cmd == OP_SELL)) 
	{
		cnt = 0;
		while (!exit_loop) 
		{
			if (IsTradeAllowed()) 
			{
				ticket = OrderSend(symbol, cmd, volume, price, lslippage, 
									stoploss, takeprofit, comment, lmagic, 
									expiration, arrow_color);
				err = GetLastError();
				_OR_err = err; 
			} 
			else 
			{
				cnt++;
			} 
			switch (err) 
			{
				case ERR_NO_ERROR:
					exit_loop = true;
					break;
					
				case ERR_SERVER_BUSY:
				case ERR_NO_CONNECTION:
				case ERR_INVALID_PRICE:
				case ERR_OFF_QUOTES:
				case ERR_BROKER_BUSY:
				case ERR_TRADE_CONTEXT_BUSY: 
					cnt++; // a retryable error
					break;
					
				case ERR_PRICE_CHANGED:
				case ERR_REQUOTE:
					RefreshRates();
					continue; // we can apparently retry immediately according to MT docs.
					
				default:
					// an apparently serious, unretryable error.
					exit_loop = true;
					break; 
					
			}  // end switch 

			if (cnt > retry_attempts) 
			 	exit_loop = true; 
			 	
			if (!exit_loop) 
			{
				OrderReliablePrint("retryable error (" + IntegerToString(cnt,Digits) + "/" + 
									IntegerToString(retry_attempts,Digits) + "): " + OrderReliableErrTxt(err)); 
				OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); 
				RefreshRates(); 
			}
			
			if (exit_loop) 
			{
				if (err != ERR_NO_ERROR) 
				{
					OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); 
				}
				if (cnt > retry_attempts) 
				{
					OrderReliablePrint("retry attempts maxed at " + IntegerToString(retry_attempts,Digits)); 
				}
			}
		}
		
		// we have now exited from loop. 
		if (err == ERR_NO_ERROR) 
		{
			OrderReliablePrint("apparently successful OP_BUY or OP_SELL order placed, details follow.");
			errororder = OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); 
			OrderPrint(); 
			return(ticket); // SUCCESS! 
		} 
		OrderReliablePrint("failed to execute OP_BUY/OP_SELL, after " + IntegerToString(cnt,Digits) + " retries");
		OrderReliablePrint("failed trade: " + OrderReliable_CommandString(cmd) + " " + symbol + 
							"@" + DoubleToString(price,Digits) + " tp@" + DoubleToString(takeprofit,Digits) + " sl@" + DoubleToString(stoploss,Digits)); 
		OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); 
		return(-1); 
	}
  return(0);
}
	
//=============================================================================
//							 OrderSendReliableMKT()
//
//	This is intended to be an alternative for OrderSendReliable() which
// will update market-orders in the retry loop with the current Bid or Ask.
// Hence with market orders there is a greater likelihood that the trade will
// be executed versus OrderSendReliable(), and a greater likelihood it will
// be executed at a price worse than the entry price due to price movement. 
//			  
//	RETURN VALUE: 
//
//	Ticket number or -1 under some error conditions.  Check
// final error returned by Metatrader with OrderReliableLastErr().
// This will reset the value from GetLastError(), so in that sense it cannot
// be a total drop-in replacement due to Metatrader flaw. 
//
//	FEATURES:
//
//     * Most features of OrderSendReliable() but for market orders only. 
//       Command must be OP_BUY or OP_SELL, and specify Bid or Ask at
//       the time of the call.
//
//     * If price moves in an unfavorable direction during the loop,
//       e.g. from requotes, then the slippage variable it uses in 
//       the real attempt to the server will be decremented from the passed
//       value by that amount, down to a minimum of zero.   If the current
//       price is too far from the entry value minus slippage then it
//       will not attempt an order, and it will signal, manually,
//       an ERR_INVALID_PRICE (displayed to log as usual) and will continue
//       to loop the usual number of times. 
//
//		 * Displays various error messages on the log for debugging.
//
//
//	Matt Kennel, 2006-08-16
//
//=============================================================================
int OrderSendReliableMKT(string symbol, int cmd, double volume, double price,
					  int lslippage, double stoploss, double takeprofit,
					  string comment, int lmagic, datetime expiration = 0, 
					  color arrow_color = CLR_NONE) 
{

	// ------------------------------------------------
	// Check basic conditions see if trade is possible. 
	// ------------------------------------------------
	OrderReliable_Fname = "OrderSendReliableMKT";
	OrderReliablePrint(" attempted " + OrderReliable_CommandString(cmd) + " " + DoubleToString(volume,Digits) + 
						" lots @" + DoubleToString(price,Digits) + " sl:" + DoubleToString(stoploss,Digits) + " tp:" + DoubleToString(takeprofit,Digits)); 

   if ((cmd != OP_BUY) && (cmd != OP_SELL)) {
      OrderReliablePrint("Improper non market-order command passed.  Nothing done.");
      _OR_err = ERR_MALFUNCTIONAL_TRADE; 
      return(-1);
   }

	//if (!IsConnected()) 
	//{
	//	OrderReliablePrint("error: IsConnected() == false");
	//	_OR_err = ERR_NO_CONNECTION; 
	//	return(-1);
	//}
	
	if (IsStopped()) 
	{
		OrderReliablePrint("error: IsStopped() == true");
		_OR_err = ERR_COMMON_ERROR; 
		return(-1);
	}
	
	int cnt = 0;
	while(!IsTradeAllowed() && cnt < retry_attempts) 
	{
		OrderReliable_SleepRandomTime(sleep_time, sleep_maximum); 
		cnt++;
	}
	
	if (!IsTradeAllowed()) 
	{
		OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries.");
		_OR_err = ERR_TRADE_CONTEXT_BUSY; 

		return(-1);  
	}

	// Normalize all price / stoploss / takeprofit to the proper # of digits.
	int digits = (int)MarketInfo(symbol, MODE_DIGITS);
	if (digits > 0) 
	{
		price = NormalizeDouble(price, digits);
		stoploss = NormalizeDouble(stoploss, digits);
		takeprofit = NormalizeDouble(takeprofit, digits); 
	}
	
	if (stoploss != 0) 
		OrderReliable_EnsureValidStop(symbol, price, stoploss); 

	int err = GetLastError(); // clear the global variable.  
	err = 0; 
	_OR_err = 0; 
	bool exit_loop = false;
	
	// limit/stop order. 
	int ticket=-1;

	// we now have a market order.
	err = GetLastError(); // so we clear the global variable.  
	err = 0; 
	_OR_err = 0; 
	ticket = -1;

	if ((cmd == OP_BUY) || (cmd == OP_SELL)) 
	{
		cnt = 0;
		while (!exit_loop) 
		{
			if (IsTradeAllowed()) 
			{
            double pnow = price;
            int slippagenow = lslippage;
            if (cmd == OP_BUY) {
            	// modification by Paul Hampton-Smith to replace RefreshRates()
               pnow = NormalizeDouble(MarketInfo(symbol,MODE_ASK),(int)MarketInfo(symbol,MODE_DIGITS)); // we are buying at Ask
               if (pnow > price) {
                  slippagenow = lslippage - (int)((pnow-price)/MarketInfo(symbol,MODE_POINT)); 
               }
            } else if (cmd == OP_SELL) {
            	// modification by Paul Hampton-Smith to replace RefreshRates()
               pnow = NormalizeDouble(MarketInfo(symbol,MODE_BID),(int)MarketInfo(symbol,MODE_DIGITS)); // we are buying at Ask
               if (pnow < price) {
                  // moved in an unfavorable direction
                  slippagenow = lslippage - (int)((price-pnow)/MarketInfo(symbol,MODE_POINT));
               }
            }
            if (slippagenow > lslippage) slippagenow = lslippage; 
            if (slippagenow >= 0) {
            
				   ticket = OrderSend(symbol, cmd, volume, pnow, slippagenow, 
									stoploss, takeprofit, comment, lmagic, 
									expiration, arrow_color);
			   	err = GetLastError();
			   	_OR_err = err; 
			  } else {
			      // too far away, manually signal ERR_INVALID_PRICE, which
			      // will result in a sleep and a retry. 
			      err = ERR_INVALID_PRICE;
			      _OR_err = err; 
			  }
			} 
			else 
			{
				cnt++;
			} 
			switch (err) 
			{
				case ERR_NO_ERROR:
					exit_loop = true;
					break;
					
				case ERR_SERVER_BUSY:
				case ERR_NO_CONNECTION:
				case ERR_INVALID_PRICE:
				case ERR_OFF_QUOTES:
				case ERR_BROKER_BUSY:
				case ERR_TRADE_CONTEXT_BUSY: 
					cnt++; // a retryable error
					break;
					
				case ERR_PRICE_CHANGED:
				case ERR_REQUOTE:
					// Paul Hampton-Smith removed RefreshRates() here and used MarketInfo() above instead
					continue; // we can apparently retry immediately according to MT docs.
					
				default:
					// an apparently serious, unretryable error.
					exit_loop = true;
					break; 
					
			}  // end switch 

			if (cnt > retry_attempts) 
			 	exit_loop = true; 
			 	
			if (!exit_loop) 
			{
				OrderReliablePrint("retryable error (" + IntegerToString(cnt,Digits) + "/" + 
									IntegerToString(retry_attempts,Digits) + "): " + OrderReliableErrTxt(err)); 
				OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); 
			}
			
			if (exit_loop) 
			{
				if (err != ERR_NO_ERROR) 
				{
					OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); 
				}
				if (cnt > retry_attempts) 
				{
					OrderReliablePrint("retry attempts maxed at " + IntegerToString(retry_attempts,Digits)); 
				}
			}
		}
		
		// we have now exited from loop. 
		if (err == ERR_NO_ERROR) 
		{
			OrderReliablePrint("apparently successful OP_BUY or OP_SELL order placed, details follow.");
			errororder = OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); 
			OrderPrint(); 
			return(ticket); // SUCCESS! 
		} 
		OrderReliablePrint("failed to execute OP_BUY/OP_SELL, after " + IntegerToString(cnt,Digits) + " retries");
		OrderReliablePrint("failed trade: " + OrderReliable_CommandString(cmd) + " " + symbol + 
							"@" + DoubleToString(price,Digits) + " tp@" + DoubleToString(takeprofit,Digits) + " sl@" + DoubleToString(stoploss,Digits)); 
		OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); 
		return(-1); 
	}
   return(0);
}
		
	
//=============================================================================
//							 OrderModifyReliable()
//
//	This is intended to be a drop-in replacement for OrderModify() which, 
//	one hopes, is more resistant to various forms of errors prevalent 
//	with MetaTrader.
//			  
//	RETURN VALUE: 
//
//		TRUE if successful, FALSE otherwise
//
//
//	FEATURES:
//
//		 * Re-trying under some error conditions, sleeping a random 
//		   time defined by an exponential probability distribution.
//
//		 * Displays various error messages on the log for debugging.
//
//
//	Matt Kennel, 	2006-05-28
//
//=============================================================================
bool OrderModifyReliable(int ticket, double price, double stoploss, 
						 double takeprofit, datetime expiration, 
						 color arrow_color = CLR_NONE) 
{
	string symbol = OrderSymbol();
	OrderReliable_Fname = "OrderModifyReliable";

	OrderReliablePrint(" attempted modify of #" + IntegerToString(ticket,Digits) + " price:" + DoubleToString(price,Digits) + 
						" sl:" + DoubleToString(stoploss,Digits) + " tp:" + DoubleToString(takeprofit,Digits)); 

	//if (!IsConnected()) 
	//{
	//	OrderReliablePrint("error: IsConnected() == false");
	//	_OR_err = ERR_NO_CONNECTION; 
	//	return(false);
	//}
	
	if (IsStopped()) 
	{
		OrderReliablePrint("error: IsStopped() == true");
		return(false);
	}
	
	int cnt = 0;
	while(!IsTradeAllowed() && cnt < retry_attempts) 
	{
		OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); 
		cnt++;
	}
	if (!IsTradeAllowed()) 
	{
		OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries.");
		_OR_err = ERR_TRADE_CONTEXT_BUSY; 
		return(false);  
	}


	
	if (false) {
		 // This section is 'nulled out', because
		 // it would have to involve an 'OrderSelect()' to obtain
		 // the symbol string, and that would change the global context of the
		 // existing OrderSelect, and hence would not be a drop-in replacement
		 // for OrderModify().
		 //
		 // See OrderModifyReliableSymbol() where the user passes in the Symbol 
		 // manually.
		 
		 errororder = OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
		 //string symbol = OrderSymbol();
		 int digits = (int)MarketInfo(symbol,MODE_DIGITS);
		 if (digits > 0) {
			 price = NormalizeDouble(price,digits);
			 stoploss = NormalizeDouble(stoploss,digits);
			 takeprofit = NormalizeDouble(takeprofit,digits); 
		 }
		 if (stoploss != 0) OrderReliable_EnsureValidStop(symbol,price,stoploss); 
	}



	int err = GetLastError(); // so we clear the global variable.  
	err = 0; 
	_OR_err = 0; 
	bool exit_loop = false;
	cnt = 0;
	bool result = false;
	
	while (!exit_loop) 
	{
		if (IsTradeAllowed()) 
		{
			result = OrderModify(ticket, price, stoploss, 
								 takeprofit, expiration, arrow_color);
			err = GetLastError();
			_OR_err = err; 
		} 
		else 
			cnt++;

		if (result == true) 
			exit_loop = true;

		switch (err) 
		{
			case ERR_NO_ERROR:
				exit_loop = true;
				break;
				
			case ERR_NO_RESULT:
				// modification without changing a parameter. 
				// if you get this then you may want to change the code.
				exit_loop = true;
				break;
				
			case ERR_SERVER_BUSY:
			case ERR_NO_CONNECTION:
			case ERR_INVALID_PRICE:
			case ERR_OFF_QUOTES:
			case ERR_BROKER_BUSY:
			case ERR_TRADE_CONTEXT_BUSY: 
			case ERR_TRADE_TIMEOUT:		// for modify this is a retryable error, I hope. 
				cnt++; 	// a retryable error
				break;
				
			case ERR_PRICE_CHANGED:
			case ERR_REQUOTE:
				RefreshRates();
				continue; 	// we can apparently retry immediately according to MT docs.
				
			default:
				// an apparently serious, unretryable error.
				exit_loop = true;
				break; 
				
		}  // end switch 

		if (cnt > retry_attempts) 
			exit_loop = true; 
			
		if (!exit_loop) 
		{
			OrderReliablePrint("retryable error (" + IntegerToString(cnt,Digits) + "/" + IntegerToString(retry_attempts,Digits) + 
								"): "  +  OrderReliableErrTxt(err)); 
			OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); 
			RefreshRates(); 
		}
		
		if (exit_loop) 
		{
			if ((err != ERR_NO_ERROR) && (err != ERR_NO_RESULT)) 
				OrderReliablePrint("non-retryable error: "  + OrderReliableErrTxt(err)); 

			if (cnt > retry_attempts) 
				OrderReliablePrint("retry attempts maxed at " + IntegerToString(retry_attempts,Digits)); 
		}
	}  
	
	// we have now exited from loop. 
	if ((result == true) || (err == ERR_NO_ERROR)) 
	{
		OrderReliablePrint("apparently successful modification order, updated trade details follow.");
		errororder = OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); 
		OrderPrint(); 
		return(true); // SUCCESS! 
	} 
	
	if (err == ERR_NO_RESULT) 
	{
		OrderReliablePrint("Server reported modify order did not actually change parameters.");
		OrderReliablePrint("redundant modification: "  + IntegerToString(ticket,Digits) + " " + symbol + 
							"@" + DoubleToString(price,Digits) + " tp@" + DoubleToString(takeprofit,Digits) + " sl@" + DoubleToString(stoploss,Digits)); 
		OrderReliablePrint("Suggest modifying code logic to avoid."); 
		return(true);
	}
	
	OrderReliablePrint("failed to execute modify after " + IntegerToString(cnt,Digits) + " retries");
	OrderReliablePrint("failed modification: "  + IntegerToString(ticket,Digits) + " " + symbol + 
						"@" + DoubleToString(price,Digits) + " tp@" + DoubleToString(takeprofit,Digits) + " sl@" + DoubleToString(stoploss,Digits)); 
	OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); 
	
	return(false);  
}
 
 
//=============================================================================
//
//						OrderModifyReliableSymbol()
//
//	This has the same calling sequence as OrderModify() except that the 
//	user must provide the symbol.
//
//	This function will then be able to ensure proper normalization and 
//	stop levels.
//
//=============================================================================
bool OrderModifyReliableSymbol(string symbol, int ticket, double price, 
							   double stoploss, double takeprofit, 
							   datetime expiration, color arrow_color = CLR_NONE) 
{
	int digits = (int)MarketInfo(symbol, MODE_DIGITS);
	
	if (digits > 0) 
	{
		price = NormalizeDouble(price, digits);
		stoploss = NormalizeDouble(stoploss, digits);
		takeprofit = NormalizeDouble(takeprofit, digits); 
	}
	
	if (stoploss != 0) 
		OrderReliable_EnsureValidStop(symbol, price, stoploss); 
		
	return(OrderModifyReliable(ticket, price, stoploss, 
								takeprofit, expiration, arrow_color)); 
	
}
 
 
//=============================================================================
//							 OrderCloseReliable()
//
//	This is intended to be a drop-in replacement for OrderClose() which, 
//	one hopes, is more resistant to various forms of errors prevalent 
//	with MetaTrader.
//			  
//	RETURN VALUE: 
//
//		TRUE if successful, FALSE otherwise
//
//
//	FEATURES:
//
//		 * Re-trying under some error conditions, sleeping a random 
//		   time defined by an exponential probability distribution.
//
//		 * Displays various error messages on the log for debugging.
//
//
//	Derk Wehler, ashwoods155@yahoo.com  	2006-07-19
//
//=============================================================================
bool OrderCloseReliable(int ticket, double lots, double price, 
						int lslippage, color arrow_color = CLR_NONE) 
{
	int nOrderType;
	string strSymbol;
	OrderReliable_Fname = "OrderCloseReliable";
	
	OrderReliablePrint(" attempted close of #" + IntegerToString(ticket,Digits) + " price:" + DoubleToString(price,Digits) + 
						" lots:" + DoubleToString(lots,Digits) + " lslippage:" + IntegerToString(lslippage,Digits)); 

// collect details of order so that we can use GetMarketInfo later if needed
	if (!OrderSelect(ticket,SELECT_BY_TICKET))
	{
		_OR_err = GetLastError();		
		OrderReliablePrint("error: " + ErrorDescription(_OR_err));
		return(false);
	}
	else
	{
		nOrderType = OrderType();
		strSymbol = OrderSymbol();
	}

	if (nOrderType != OP_BUY && nOrderType != OP_SELL)
	{
		_OR_err = ERR_INVALID_TICKET;
		OrderReliablePrint("error: trying to close ticket #" + IntegerToString(ticket,Digits) + ", which is " + OrderReliable_CommandString(nOrderType) + ", not OP_BUY or OP_SELL");
		return(false);
	}

	//if (!IsConnected()) 
	//{
	//	OrderReliablePrint("error: IsConnected() == false");
	//	_OR_err = ERR_NO_CONNECTION; 
	//	return(false);
	//}
	
	if (IsStopped()) 
	{
		OrderReliablePrint("error: IsStopped() == true");
		return(false);
	}

	
	int cnt = 0;
/*	
	Commented out by Paul Hampton-Smith due to a bug in MT4 that sometimes incorrectly returns IsTradeAllowed() = false
	while(!IsTradeAllowed() && cnt < retry_attempts) 
	{
		OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); 
		cnt++;
	}
	if (!IsTradeAllowed()) 
	{
		OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries.");
		_OR_err = ERR_TRADE_CONTEXT_BUSY; 
		return(false);  
	}
*/

	int err = GetLastError(); // so we clear the global variable.  
	err = 0; 
	_OR_err = 0; 
	bool exit_loop = false;
	cnt = 0;
	bool result = false;
	
	while (!exit_loop) 
	{
		if (IsTradeAllowed()) 
		{
			result = OrderClose(ticket, lots, price, lslippage, arrow_color);
			err = GetLastError();
			_OR_err = err; 
		} 
		else 
			cnt++;

		if (result == true) 
			exit_loop = true;

		switch (err) 
		{
			case ERR_NO_ERROR:
				exit_loop = true;
				break;
				
			case ERR_SERVER_BUSY:
			case ERR_NO_CONNECTION:
			case ERR_INVALID_PRICE:
			case ERR_OFF_QUOTES:
			case ERR_BROKER_BUSY:
			case ERR_TRADE_CONTEXT_BUSY: 
			case ERR_TRADE_TIMEOUT:		// for modify this is a retryable error, I hope. 
				cnt++; 	// a retryable error
				break;
				
			case ERR_PRICE_CHANGED:
			case ERR_REQUOTE:
				continue; 	// we can apparently retry immediately according to MT docs.
				
			default:
				// an apparently serious, unretryable error.
				exit_loop = true;
				break; 
				
		}  // end switch 

		if (cnt > retry_attempts) 
			exit_loop = true; 
			
		if (!exit_loop) 
		{
			OrderReliablePrint("retryable error (" + IntegerToString(cnt,Digits) + "/" + IntegerToString(retry_attempts,Digits) + 
								"): "  +  OrderReliableErrTxt(err)); 
			OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); 
			// Added by Paul Hampton-Smith to ensure that price is updated for each retry
			if (nOrderType == OP_BUY)  price = NormalizeDouble(MarketInfo(strSymbol,MODE_BID),(int)MarketInfo(strSymbol,MODE_DIGITS));
			if (nOrderType == OP_SELL) price = NormalizeDouble(MarketInfo(strSymbol,MODE_ASK),(int)MarketInfo(strSymbol,MODE_DIGITS));
		}
		
		if (exit_loop) 
		{
			if ((err != ERR_NO_ERROR) && (err != ERR_NO_RESULT)) 
				OrderReliablePrint("non-retryable error: "  + OrderReliableErrTxt(err)); 

			if (cnt > retry_attempts) 
				OrderReliablePrint("retry attempts maxed at " + IntegerToString(retry_attempts,Digits)); 
		}
	}  
	
	// we have now exited from loop. 
	if ((result == true) || (err == ERR_NO_ERROR)) 
	{
		OrderReliablePrint("apparently successful close order, updated trade details follow.");
		errororder = OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); 
		OrderPrint(); 
		return(true); // SUCCESS! 
	} 
	
	OrderReliablePrint("failed to execute close after " + IntegerToString(cnt,Digits) + " retries");
	OrderReliablePrint("failed close: Ticket #" + IntegerToString(ticket,Digits) + ", Price: " + 
						DoubleToString(price,Digits) + ", Slippage: " + IntegerToString(slippage,Digits)); 
	OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); 
	
	return(false);  
}
 
 

//=============================================================================
//=============================================================================
//								Utility Functions
//=============================================================================
//=============================================================================



int OrderReliableLastErr() 
{
	return (_OR_err); 
}


string OrderReliableErrTxt(int err) 
{
	return ("" + IntegerToString(err,Digits) + ":" + ErrorDescription(err)); 
}


void OrderReliablePrint(string s) 
{
	// Print to log prepended with stuff;
	if (!(IsTesting() || IsOptimization())) Print(OrderReliable_Fname + " " + OrderReliableVersion + ":" + s);
}


string OrderReliable_CommandString(int cmd) 
{
	if (cmd == OP_BUY) 
		return("OP_BUY");

	if (cmd == OP_SELL) 
		return("OP_SELL");

	if (cmd == OP_BUYSTOP) 
		return("OP_BUYSTOP");

	if (cmd == OP_SELLSTOP) 
		return("OP_SELLSTOP");

	if (cmd == OP_BUYLIMIT) 
		return("OP_BUYLIMIT");

	if (cmd == OP_SELLLIMIT) 
		return("OP_SELLLIMIT");

	return("(CMD==" + IntegerToString(cmd,Digits) + ")"); 
}


//=============================================================================
//
//						 OrderReliable_EnsureValidStop()
//
// 	Adjust stop loss so that it is legal.
//
//	Matt Kennel 
//
//=============================================================================
void OrderReliable_EnsureValidStop(string symbol, double price, double& sl) 
{
	// Return if no S/L
	if (sl == 0) 
		return;
	
	double servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * MarketInfo(symbol, MODE_POINT); 
	
	if (MathAbs(price - sl) <= servers_min_stop) 
	{
		// we have to adjust the stop.
		if (price > sl)
			sl = price - servers_min_stop;	// we are long
			
		else if (price < sl)
			sl = price + servers_min_stop;	// we are short
			
		else
			OrderReliablePrint("EnsureValidStop: error, passed in price == sl, cannot adjust"); 
			
		sl = NormalizeDouble(sl, (int)MarketInfo(symbol, MODE_DIGITS)); 
	}
}


//=============================================================================
//
//						 OrderReliable_SleepRandomTime()
//
//	This sleeps a random amount of time defined by an exponential 
//	probability distribution. The mean time, in Seconds is given 
//	in 'mean_time'.
//
//	This is the back-off strategy used by Ethernet.  This will 
//	quantize in tenths of seconds, so don't call this with a too 
//	small a number.  This returns immediately if we are backtesting
//	and does not sleep.
//
//	Matt Kennel mbkennelfx@gmail.com.
//
//=============================================================================
void OrderReliable_SleepRandomTime(double mean_time, double max_time) 
{
	if (IsTesting()) 
		return; 	// return immediately if backtesting.

	double tenths = MathCeil(mean_time / 0.1);
	if (tenths <= 0) 
		return; 
	 
	int maxtenths = (int)MathRound(max_time/0.1); 
	double p = 1.0 - 1.0 / tenths; 
	  
	Sleep(100); 	// one tenth of a second PREVIOUS VERSIONS WERE STUPID HERE. 
	
	for(int i=0; i < maxtenths; i++)  
	{
		if (MathRand() > p*32768) 
			break; 
			
		// MathRand() returns in 0..32767
		Sleep(100); 
	}
}  

Recommend