SimpleS&R-v1.3





//+------------------------------------------------------------------+
//|                                                   Simple S&R.mq4 |
//|                                        Copyright © 2008, LEGRUPO |
//|                                           http://www.legrupo.com |
//|                                                     Version: 1.1 |
//| History:                                                         |
//| 1.0 => Release version to the public                             |
//| 1.1 => fixes on this releases:                                   |
//|        1) StopLoss bug fixed;                                    |
//|        2) Now the EA close the open and pending orders on the    |
//|           end of the day, you just need to see when day ends     |
//|           on your broker. InterbankFX is GMT, so it is 0 on them |
//|        3) You don't need to manage the MagicNumber anymore       |
//| 1.3 => 10 Feb 2008 (Tinashe B Chipomho chipomho@xtra.co.nz       |
//|        Improved order handling routines, embedded the indicator  |
//|        making backtesting possible, close half of the position   |
//|        when the pivot point is reached.                          |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#include <WinUser32.mqh>
#include <stderror.mqh>
#include <stdlib.mqh>

#property copyright "Copyright © 2007, LEGRUPO Version 1.6"
#property link      "http://www.legrupo.com"

extern bool TimeSpecific = false;
extern int Slippage = 3;
extern double Lots = 0.2;
extern int ExpertID=1900;
extern int TakeProfitRange = 8;
extern int StopLoss = 100;
extern double FirstHalf = 0.1;

int MagicNumber = 10;
double Pivot = 0;

int CreateMagicNumber(){
   int SymbolCode  = 0;
   int PeriodCode  = 0;
   
   //---- Symbol Code
        if( StringSubstr(Symbol(),0,6) == "AUDCAD") { SymbolCode = 1000; }
   else if( StringSubstr(Symbol(),0,6) == "AUDJPY") { SymbolCode = 2000; }
   else if( StringSubstr(Symbol(),0,6) == "AUDNZD") { SymbolCode = 3000; }
   else if( StringSubstr(Symbol(),0,6) == "AUDUSD") { SymbolCode = 4000; }
   else if( StringSubstr(Symbol(),0,6) == "CHFJPY") { SymbolCode = 5000; }
   else if( StringSubstr(Symbol(),0,6) == "EURAUD") { SymbolCode = 6000; }
   else if( StringSubstr(Symbol(),0,6) == "EURCAD") { SymbolCode = 7000; }
   else if( StringSubstr(Symbol(),0,6) == "EURCHF") { SymbolCode = 8000; }
   else if( StringSubstr(Symbol(),0,6) == "EURGBP") { SymbolCode = 9000; }
   else if( StringSubstr(Symbol(),0,6) == "EURJPY") { SymbolCode = 1000; }
   else if( StringSubstr(Symbol(),0,6) == "EURUSD") { SymbolCode = 1100; }
   else if( StringSubstr(Symbol(),0,6) == "GBPCHF") { SymbolCode = 1200; }
   else if( StringSubstr(Symbol(),0,6) == "GBPJPY") { SymbolCode = 1300; }
   else if( StringSubstr(Symbol(),0,6) == "GBPUSD") { SymbolCode = 1400; }
   else if( StringSubstr(Symbol(),0,6) == "NZDJPY") { SymbolCode = 1500; }
   else if( StringSubstr(Symbol(),0,6) == "NZDUSD") { SymbolCode = 1600; }
   else if( StringSubstr(Symbol(),0,6) == "USDCAD") { SymbolCode = 1700; }
   else if( StringSubstr(Symbol(),0,6) == "USDCHF") { SymbolCode = 1800; }
   else if( StringSubstr(Symbol(),0,6) == "USDJPY") { SymbolCode = 1900; }
                     
   
   //---- Period Code
   if( TimeSpecific ){
     if( Period() == PERIOD_M1 )      { PeriodCode = 10; }
     else if( Period() == PERIOD_M5 ) { PeriodCode = 20; }
     else if( Period() == PERIOD_M15 ){ PeriodCode = 30; }
     else if( Period() == PERIOD_M30 ){ PeriodCode = 40; }
     else if( Period() == PERIOD_H1 ) { PeriodCode = 50; }
     else if( Period() == PERIOD_H4 ) { PeriodCode = 60; }
     else if( Period() == PERIOD_D1 ) { PeriodCode = 70; }
     else if( Period() == PERIOD_W1)  { PeriodCode = 80; }
     else if( Period() == PERIOD_MN1 ){ PeriodCode = 90; }
   }
   else
     PeriodCode = 0;
   //---- Calculate MagicNumber
   return(ExpertID+SymbolCode+PeriodCode);
}

bool HasBuyOrder(double price){
  int total = OrdersTotal();
  double min = Slippage * Point;
  
  for(int i=0; i<total; i++){
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true){
      if (OrderSymbol()!=Symbol()) continue;
      if (OrderMagicNumber()!=MagicNumber)continue;
      if ((OrderType()==OP_BUY) || (OrderType()==OP_BUYLIMIT) || (OrderType()==OP_BUYSTOP)) {
        if ((OrderOpenPrice()-(Slippage*Point)<=price) && (OrderOpenPrice()+(Slippage*Point)>=price)){
          return (true);
        }
      }
    }
  }
  return (false);
}

bool HasSellOrder(double price){
  int total = OrdersTotal();
  double min = Slippage * Point;
  for(int i=0; i<total; i++){
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true){
      if (OrderSymbol()!=Symbol()) continue;
      //if (OrderMagicNumber()!=MagicNumber)continue;
      if ((OrderType()==OP_SELL) || (OrderType()==OP_SELLLIMIT) || (OrderType()==OP_SELLSTOP)) {
        if ((OrderOpenPrice()-min<=price) && (OrderOpenPrice()+min>=price)){
          return (true);
        }
      }
    }
  }
  return (false);
}


double GetLots(string name){
  //use this function to calculate the number of lots to use
  //if market conditions are favourable we might want to double
  //the lots.
  return (Lots);
}

string OrderType2String(int type){
  if (type==OP_BUY)
    return ("BUY");
  else if (type==OP_BUYLIMIT)
    return ("BUY LIMIT");
  else if (type==OP_BUYSTOP)
    return ("BUY STOP");
  else if (type==OP_SELL)
    return ("SELL");
  else if (type==OP_SELLLIMIT)
    return ("SELL LIMIT");
  else if (type==OP_SELLSTOP)
    return ("SELL STOP");
  return ("Unknown Order Type");  
}
/////////////////////////////////////////////////////////////////////////////////
// int _IsTradeAllowed( int MaxWaiting_sec = 30 )
//
// the function checks the trade context status. Return codes:
//  1 - trade context is free, trade allowed
//  0 - trade context was busy, but became free. Trade is allowed only after 
//      the market info has been refreshed.
// -1 - trade context is busy, waiting interrupted by the user (expert was removed from 
//      the chart, terminal was shut down, the chart period and/or symbol was changed, etc.)
// -2 - trade context is busy, the waiting limit is reached (MaxWaiting_sec). 
//      Possibly, the expert is not allowed to trade (checkbox "Allow live trading" 
//      in the expert settings).
//
// MaxWaiting_sec - time (in seconds) within which the function will wait 
// until the trade context is free (if it is busy). By default,30.
/////////////////////////////////////////////////////////////////////////////////
int _IsTradeAllowed(int MaxWaiting_sec = 30){
  
  if (IsTesting())
    return (1);
    
  // check whether the trade context is free
  if(!IsTradeAllowed()){
    int StartWaitingTime = GetTickCount();
    Print("Trade context is busy! Wait until it is free...");
    // infinite loop
    while(true){
      // if the expert was terminated by the user, stop operation
      if(IsStopped()){ 
        Print("The expert was terminated by the user!"); 
        return(-1); 
      }
      // if the waiting time exceeds the time specified in the 
      // MaxWaiting_sec variable, stop operation, as well
      if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000){
        Print("The waiting limit exceeded (" + MaxWaiting_sec + " ???.)!");
        return(-2);
      }
      
      // if the trade context has become free,
      if(IsTradeAllowed()){
        Print("Trade context has become free!");
        return(0);
      }
      // if no loop breaking condition has been met, "wait" for 0.1 
      // second and then restart checking            
      Sleep(100);
    }
  }
  else
   return(1);
}


int CreateOrder(int cmd, double price, double stoploss, double takeprofit, double lots, double expiration){
  int ticket = -1;
 
  if (!IsConnected()){
    Print("CreateOrder(): Not Connected.");
    return (-1);
  }
  
  if (IsStopped()){
    Print("CreateOrder(): Stopped.");
    return (-1);
  }

  
  // check whether trade context is free
  int TradeAllow = _IsTradeAllowed();
  if(TradeAllow < 0){ 
    return(-1); 
  }
    
  if(TradeAllow == 0){
    RefreshRates();
  }
 
  string comment = "SimpleFiboS&REA : ";
  Print("Opening "+OrderType2String(cmd) +" Order: Price["+price+"] StopLoss["+stoploss+"] TakeProfit["+takeprofit+"]");
  ticket = OrderSend(Symbol(), cmd, lots, price, Slippage, stoploss,
                     takeprofit, comment, MagicNumber, expiration);
  int err=GetLastError();
  if (err!=0){
    Print(""+OrderType2String(cmd) +" Failed to create Order: "+ err+" "+ ErrorDescription(err));
  }                  
                    
  return (ticket);
 
                      
}


/**
 * In this function place only buy orders.
 */
int PlaceSupportOrder(double price, double pivot, double lots, double stoploss, double takeprofit, datetime expiration){
  
  int ticket = -1;
  RefreshRates();
  double servers_min_stop = MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT);
  //if the price is within + or - Slippage*Point simply buy.
  if (  (((Slippage*Point) + Ask) >= price) && 
        (((Slippage*Point) - Ask) <= price) ){
    Print("Opening a buy order at market price.");
  }
   
  int cmd = OP_BUYLIMIT;
  //if the price is too close to the stoplevel there is 
  //nothing much we can do
  if (MathAbs(Ask-price) > servers_min_stop){
    if (Ask < price){
      cmd = OP_BUYSTOP;
    }
    //Print("SupportOrder: "+ OrderType2String(cmd)+" Price["+price+"] Pivot["+pivot+"] StopLoss["+stoploss+"] TakeProfit["+takeprofit+"] Expiration["+TimeToStr(expiration,TIME_DATE|TIME_MINUTES)+"]");
    ticket = CreateOrder(cmd, NormalizeDouble(price,Digits), NormalizeDouble(stoploss,Digits), NormalizeDouble(takeprofit,Digits), lots, expiration);
  }
  return (ticket);
}

/**
 * In this function place only buy orders.
 */
int PlaceResistanceOrder(double price, double pivot, double lots, double stoploss, double takeprofit, datetime expiration){
  
  int ticket = -1;
  RefreshRates();
  double servers_min_stop = MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT);
  //if the price is within + or - Slippage*Point simply buy.
  if (  (((Slippage*Point) + Bid) >= price) && 
        (((Slippage*Point) - Bid) <= price) ){
    Print("Opening a sell order at market price.");
  }
   
  int cmd = OP_SELLLIMIT;
  //if the price is too close to the stoplevel there is 
  //nothing much we can do
  if (MathAbs(Bid-price) > servers_min_stop){
    if (Bid > price){
      cmd = OP_SELLSTOP;
    }
    Print("ResistanceOrder: "+ OrderType2String(cmd)+" Price["+price+"] Pivot["+pivot+"] StopLoss["+stoploss+"] TakeProfit["+takeprofit+"] Expiration["+TimeToStr(expiration,TIME_DATE|TIME_MINUTES)+"]");
    ticket = CreateOrder(cmd, NormalizeDouble(price,Digits), NormalizeDouble(stoploss,Digits), NormalizeDouble(takeprofit,Digits), lots, expiration);
  }
  return (ticket);
}

int PartiallyClose(int type,int ticket, double openprice, double takeprofit){
  int TradeAllow = _IsTradeAllowed();
  
  double closeprice = 0.0;
    
  Print("Moving to break even and partially closing position ");          
  Print("  TradeAllow["+TradeAllow+"] ticket["+ ticket+"] openprice["+openprice+"] takeprofit["+takeprofit+"] type["+type+"] ");          
  if (TradeAllow >= 0){

    if(TradeAllow == 0)
      RefreshRates();
      
    if (OrderModify(ticket,openprice,openprice,takeprofit,0)!=true)
      Print(OrderType2String(type)+"  Failed to modify to break even: "+ ErrorDescription(GetLastError()));
              
    TradeAllow = _IsTradeAllowed();
    if (TradeAllow==0)
      RefreshRates();

    if (type==OP_BUY)
      closeprice=Bid;
    else if (type==OP_SELL)            
      closeprice=Ask;
      
    Print(" After modify trade allow "+ TradeAllow);          
    Print(OrderType2String(type)+"  : Closing first lot, Ticket["+ticket+"] FirstLots["+FirstHalf+"] Ask["+Ask+"] Bid["+Bid+"] ClosePrice["+closeprice+"]"); 
    
    if (OrderClose(ticket,FirstHalf,closeprice,Slippage)!=true)
      Print(OrderType2String(type)+" Failed to partially close an open order: "+ ErrorDescription(GetLastError()));

     return (0);              
  }  
  return (-1);
}

int TrackOrders(){
  int i=0, ticket=-1;
  int total = OrdersTotal();
  
  int modify = -1;
  double pivot = Pivot;//NormalizeDouble(ObjectGet("PIVOT", OBJPROP_PRICE1), Digits);
  double servers_min_stop = MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT);
  
  for(i=(total-1);i>=0; i--){
    
    //if we cant select an order ignore it.
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)!=true)
      continue;

    //if its not our order just leave it.
    if (OrderMagicNumber()!=MagicNumber)
     continue;
      
    //dont be nosy and manipulate other people's orders.
    if (OrderSymbol()!=Symbol())
      continue;

    //orders not yet filled leave them as well.
    if ((OrderType()!=OP_SELL)&&(OrderType()!= OP_BUY))
      continue;
      
    //not doing anything to orders that are not yet profitable
    //let the stoploss take care of it.
    //TODO: This might be not be acceptable in certain market conditions.
    if (OrderProfit()<=0)
      continue;
      
    ticket = OrderTicket();     
    
    if (OrderType()==OP_SELL){
      //sell order
      if (MathAbs(OrderOpenPrice()-pivot)>=servers_min_stop){
        if (pivot>=Ask){
          //we have gone past the pivot point,
          if (((OrderStopLoss()>OrderOpenPrice())|| (OrderStopLoss()==0)) && (FirstHalf>0)) {
            //the stop loss is still untouched, close the first half and move the 
            //stop loss to break even.
            modify = PartiallyClose(OrderType(),OrderTicket(),OrderOpenPrice(),OrderTakeProfit());
          }
        }
      }
      
    }
    else if (OrderType()==OP_BUY){
      //buy Order
      if (MathAbs(OrderOpenPrice()-pivot)>=servers_min_stop){
        if (pivot<=Bid){
          if (((OrderStopLoss()<OrderOpenPrice())|| (OrderStopLoss()==0) ) && (FirstHalf>0)){
            //the stop loss is still untouched, close the first half and move the stop loss to break
            //even.
            modify = PartiallyClose(OrderType(),OrderTicket(),OrderOpenPrice(),OrderTakeProfit());
          }
        }
      }
      
    }
    
    //TrailingStop(OrderType(),OrderTicket(), OrderOpenPrice(), OrderTakeProfit(), OrderStopLoss());
  }  
  
}

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init(){
  MagicNumber = CreateMagicNumber();
  return(0);
}

//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit(){
  return(0);
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start(){

  double rates[1][6],yesterday_close,yesterday_high,yesterday_low;
  ArrayCopyRates(rates, Symbol(), PERIOD_D1);
  
  
  if(DayOfWeek() == 1){
    if(TimeDayOfWeek(iTime(Symbol(),PERIOD_D1,1)) == 5){
      yesterday_close = rates[1][4];
      yesterday_high = rates[1][3];
      yesterday_low = rates[1][2];
    }
    else{
      for(int d = 5;d>=0;d--){
        if(TimeDayOfWeek(iTime(Symbol(),PERIOD_D1,d)) == 5){
          yesterday_close = rates[d][4];
          yesterday_high = rates[d][3];
          yesterday_low = rates[d][2];
        }
      }  
    }
  }
  else{
    yesterday_close = rates[1][4];
    yesterday_high = rates[1][3];
    yesterday_low = rates[1][2];
  }
  
  
  double R = yesterday_high - yesterday_low;//range
  double pivot = NormalizeDouble((yesterday_high + yesterday_low + yesterday_close)/3,Digits);// Standard Pivot
  Pivot=NormalizeDouble(pivot,Digits);
  double r3 = NormalizeDouble(pivot + (R * 1.000),Digits);
  double r2 = NormalizeDouble(pivot + (R * 0.618),Digits);
  double r1 = NormalizeDouble(pivot + (R * 0.382),Digits);
  double s1 = NormalizeDouble(pivot - (R * 0.382),Digits);
  double s2 = NormalizeDouble(pivot - (R * 0.618),Digits);
  double s3 = NormalizeDouble(pivot - (R * 1.000),Digits);
  
  
  
   double servers_min_stop = MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT);
  
   //well just use 1min before the end of day.
   //this is the expiration for our pending orders.
   datetime TimeToEndOfDay = StrToTime("23:59");
   
   double takeprofit = 0;
   int ticket = -1; //default ticket number.
   double stoploss = StopLoss * Point; //default stop loss level.
   //
   
   
   //well just no order placing in the last minute of the day.
   if (TimeToStr(TimeCurrent(),TIME_DATE|TIME_MINUTES)!=TimeToStr(TimeToEndOfDay,TIME_DATE|TIME_MINUTES)){
     //check if we have orders at various fibo points, if not we need to open 
     //the orders.      
     //start by opening orders from s3,r3 then move to s2,r2 then move to s1,r1 
     
     if ( HasSellOrder(r3)!= true) {
       //open a sell order at r3 
       takeprofit = s1+MathMin(TakeProfitRange*Point, servers_min_stop);
       stoploss = r3+MathMax(StopLoss * Point,servers_min_stop);
       ticket = PlaceResistanceOrder(r3,pivot, GetLots("r3"), stoploss, takeprofit ,TimeToEndOfDay);
     }
   
     if ( HasSellOrder(r2)!= true) {
       //open a sell order at r2 
       takeprofit = s1+MathMin(TakeProfitRange*Point, servers_min_stop);
       stoploss = r3+MathMax(StopLoss * Point,servers_min_stop);
       ticket = PlaceResistanceOrder(r2,pivot, GetLots("r2"), stoploss, takeprofit ,TimeToEndOfDay);
     }

     if ( HasSellOrder(r1)!= true) {
       //open a sell order at r1 
       takeprofit = s1+MathMin(TakeProfitRange*Point, servers_min_stop);
       stoploss = r3+MathMax(StopLoss * Point,servers_min_stop);
       ticket = PlaceResistanceOrder(r1,pivot, GetLots("r1"), stoploss, takeprofit ,TimeToEndOfDay);
     }
     
     if ( HasBuyOrder(s3)!= true) {
       //open a buy order at s3 
       takeprofit = r1-MathMax(TakeProfitRange*Point, servers_min_stop);
       stoploss = s3-MathMax(StopLoss * Point,servers_min_stop);
       ticket = PlaceSupportOrder(s3,pivot, GetLots("s3"), stoploss, takeprofit ,TimeToEndOfDay);
     }
     
     if ( HasBuyOrder(s2)!= true) {
       //open a buy order at s2 
       takeprofit = r1-MathMax(TakeProfitRange*Point, servers_min_stop);
       stoploss = s2-MathMax(StopLoss * Point,servers_min_stop);
       ticket = PlaceSupportOrder(s2,pivot, GetLots("s2"), stoploss, takeprofit ,TimeToEndOfDay);
     }

     if ( HasBuyOrder(s1)!= true) {
       //open a sell order at s1 
       takeprofit = r1-MathMax(TakeProfitRange*Point, servers_min_stop);
       stoploss = s1-MathMax(StopLoss * Point,servers_min_stop);
       ticket = PlaceSupportOrder(s1,pivot, GetLots("s1"), stoploss, takeprofit ,TimeToEndOfDay);
     }
     
  }
  
  TrackOrders();
  
  return(0);
}
//+------------------------------------------------------------------+



Sample





Analysis



Market Information Used:



Indicator Curves created:


Indicators Used:



Custom Indicators Used:

Order Management characteristics:
Checks for the total of open orders

It can change open orders parameters, due to possible stepping strategy
It Closes Orders by itself

Other Features: