/*------------------------------------------------------------------------------------
   Name: xTDI Cross-EA.mq4
   Copyright ｩ2012, Xaphod, http://www.xaphod.com
   
   Description: TDI green/red cross EA for backtesting. 
                NOTE! Requires that Traders_Dynamic_Index.mq4 is installed
	          
   Change log: 
       2012-05-14. Xaphod, v1.0 
          - First Release 
-------------------------------------------------------------------------------------*/
#property copyright "Copyright ｩ 2012, Xaphod"
#property link      "http://www.xaphod.com"

// Win32 API
#import "Kernel32.dll"
  int CreateFileA(string lpFileName,int dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwCreationDisposition,int dwFlagsAndAttributes, int hTemplateFile);
  int CloseHandle(int hObject);
#import
#define OPEN_EXISTING 3
#define FILE_SHARE_READ 1
#define FILE_READ_DATA 1
#define FILE_ATTRIBUTE_NORMAL 128
#define INVALID_HANDLE_VALUE 0xFFFFFFFF


// Definitions
#define EA_NAME "xTDI Cross-EA"
#define EA_VERSION "1.0"
#define EA_TRADE_ID  20120513

#define TDI_INDI "Traders_Dynamic_Index"
#define STAT_IDLE 0     // Idle. waiting for setup bar
#define STAT_SETUP 1    // Setup bar active
#define STAT_STANDBY 2  // Waiting for entry. Setup bar closed.
#define STAT_TRADING 3  // Trade in progress

#define SIG_NO 0
#define SIG_UP 1
#define SIG_DN 2


//---- input parameters
extern string    Indi.Version= EA_VERSION;
extern string    RunTime.Settings="覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧";
extern string    RunTime.Enable="00:00";       // Enable trading after this time
extern string    RunTime.Disable="23:00";      // Disable trading after this time
extern string    Orter.Settings="覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧";
extern double    Order.LotSize=0.1;             // Lotsize
extern double    Order.SL=20;                   // Stoploss. Set to 0 to use no SL
extern double    Order.TP=40;                   // Take profit. Set to 0 to use no TP
extern double    Order.MoveToBE=20;             // Move to BE at profit level...
extern double    Order.BEOffset=2;              // Offset to add to BE position to account for the spread
extern double    Order.Slippage=5;              // Maximum Order slippage
extern int       Order.TradesPerDay=1;          // Nr of trades per day 
extern bool      Order.EnableBuy=True;          // Type of trades to take: 0=BUY/SELL, 1=BUY, 2=SELL
extern bool      Order.EnableSell=True;         // Type of trades to take: 0=BUY/SELL, 1=BUY, 2=SELL
extern bool      Order.TwoStep=True;            // Enter with TP/SL or add them after the position is opened for ECN brokers
extern string    TDI.Settings="覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧";
extern int       TDI.RSIPeriod=13;             // Period. Recomended values: 8-25
extern int       TDI.RSIPrice=0;               // 0=CLOSE, 1=OPEN, 2=HIGH, 3=LOW, 4=MEDIAN, 5=TYPICAL, 6=WEIGHTED
extern int       TDI.VolatilityBand=34;        // Recomended values: 20-40
extern int       TDI.RSIPriceLine=2;           // Period
extern int       TDI.RSIPriceType=0;           // 0=SMA, 1=EMA, 2=SSMA, 3=LWMA
extern int       TDI.TradeSignalLine=7;        // Period
extern int       TDI.TradeSignalType=0;        // 0=SMA, 1=EMA, 2=SSMA, 3=LWMA

double gdPipValue;
int giPipDigits;
int giStatus;
int giTicket;
int giOrderType;
double gdSL;
double gdTP;
double gdBELevel;
double gdBETrigger;
double gdTotalProfit;


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init() {
  giStatus=STAT_IDLE;
  SetPipDigits();
  Order.Slippage=Order.Slippage*MathPow(10,giPipDigits);
  ResetOrderVars();
  gdTotalProfit=0;
  RunTime.Enable=ValidateTime(RunTime.Enable);
  RunTime.Disable=ValidateTime(RunTime.Disable);
  if (!IndicatorExists(TDI_INDI+".ex4"))
    Alert(Symbol()+", "+TF2Str(Period())+", "+EA_NAME+": Error! "+TerminalPath()+"\\experts\\indicators\\"+TDI_INDI+".ex4 cannot be found.");
  return(0);
}


//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit() {
   return(0);
}


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()  {
  datetime tEnableTime;
  datetime tDisableTime;
  static int iCurDay=0;
  static int iTradeCount=0;
  
  // Check that the pip value has been set
  if (gdPipValue==0) {
    SetPipDigits();
    Order.Slippage=Order.Slippage*MathPow(10,giPipDigits);
    return(0);
  }
  
  // Check Session time
  tEnableTime=StrToTime(TimeToStr(Time[0],TIME_DATE )+" "+RunTime.Enable);
  tDisableTime=StrToTime(TimeToStr(Time[0],TIME_DATE )+" "+RunTime.Disable);
  if (giStatus==STAT_IDLE && (Time[0]<tEnableTime || Time[0]>tDisableTime))
    return(0);
  
  // Check for new day
  if (Day()!=iCurDay) {
    iCurDay=Day();
    iTradeCount=0;
  }
  
  // Check nr of trades/day
  if (giStatus==STAT_IDLE && iTradeCount>=Order.TradesPerDay)
    return(0);    
  if (giStatus==STAT_IDLE && Order.TradesPerDay==0)
    return(0); 
  
  // State
  switch(giStatus) {
    // Check for signal if idle
    case STAT_IDLE:
      // Buy signal
      if (TDICrossSig(1)==SIG_UP && Order.EnableBuy) {      
        giTicket=OpenOrder(OP_BUY, Order.LotSize, Ask, Order.Slippage, Order.SL, Order.TP, Order.TwoStep);
        if (giTicket>0) {
          iTradeCount++;
          giStatus=STAT_TRADING;
          if(OrderSelect(giTicket,SELECT_BY_TICKET)) {
            if (Order.MoveToBE>0) {
              gdBELevel=NormalizeDouble(OrderOpenPrice()+Order.BEOffset*gdPipValue,Digits);
              gdBETrigger=NormalizeDouble(OrderOpenPrice()+Order.MoveToBE*gdPipValue,Digits);
              WriteMsg("Buy: Move to BE Trigger="+DoubleToStr(gdBETrigger,Digits)+", BE Level="+DoubleToStr(gdBELevel,Digits));
            }
            gdSL=OrderStopLoss();
            gdTP=OrderTakeProfit();
            giOrderType=OrderType();
          }
        }
      }
      // Sell signal
      if (TDICrossSig(1)==SIG_DN && Order.EnableSell) {
        giTicket=OpenOrder(OP_SELL, Order.LotSize, Bid, Order.Slippage, Order.SL, Order.TP, Order.TwoStep);
        if (giTicket>0) {
          iTradeCount++;
          giStatus=STAT_TRADING;
          if(OrderSelect(giTicket,SELECT_BY_TICKET)) {
            if (Order.MoveToBE>0) {
              gdBELevel=NormalizeDouble(OrderOpenPrice()-Order.BEOffset*gdPipValue,Digits);
              gdBETrigger=NormalizeDouble(OrderOpenPrice()-Order.MoveToBE*gdPipValue,Digits);
              WriteMsg("Sell: Move to BE Trigger="+DoubleToStr(gdBETrigger,Digits)+", BE Level="+DoubleToStr(gdBELevel,Digits));
            }
            gdSL=OrderStopLoss();
            gdTP=OrderTakeProfit();
            giOrderType=OrderType();
          }
        }
      }
    break;
    
    // Manage open trade
    case STAT_TRADING:
      // Check if SL/TP was hit
      if (giTicket>0) 
        CheckBE();
        if(OrderSelect(giTicket,SELECT_BY_TICKET))
          if (OrderCloseTime()!=0) { // Order Closed, Reset
            gdTotalProfit=gdTotalProfit+OrderProfit()+OrderSwap();
            WriteMsg("Ticket "+giTicket+" Closed. P/L="+DoubleToStr(OrderProfit(),2));            
            WriteMsg("Total Profit="+DoubleToStr(gdTotalProfit,2));
            ResetOrderVars();
            giStatus=STAT_IDLE;
          }  
    break;
  } //endswitch
   

  return(0);
}
//+------------------------------------------------------------------+

//-----------------------------------------------------------------------------
// function: TDICrossSig()
// Description: TDI red/green crossover signal
//-----------------------------------------------------------------------------
int TDICrossSig(int i) {
  double dRSIPriceLine0,dRSIPriceLine1;
  double dTradeSignalLine0,dTradeSignalLine1;
  
  dRSIPriceLine0=iCustom(NULL,0,TDI_INDI,TDI.RSIPeriod,TDI.RSIPrice,TDI.VolatilityBand,TDI.RSIPriceLine,
                        TDI.RSIPriceType,TDI.TradeSignalLine,TDI.TradeSignalType,4,i);     // Green line
  dRSIPriceLine1=iCustom(NULL,0,TDI_INDI,TDI.RSIPeriod,TDI.RSIPrice,TDI.VolatilityBand,TDI.RSIPriceLine,
                        TDI.RSIPriceType,TDI.TradeSignalLine,TDI.TradeSignalType,4,i+1); 
  dTradeSignalLine0=iCustom(NULL,0,TDI_INDI,TDI.RSIPeriod,TDI.RSIPrice,TDI.VolatilityBand,TDI.RSIPriceLine,
                           TDI.RSIPriceType,TDI.TradeSignalLine,TDI.TradeSignalType,5,i);  // Red line
  dTradeSignalLine1=iCustom(NULL,0,TDI_INDI,TDI.RSIPeriod,TDI.RSIPrice,TDI.VolatilityBand,TDI.RSIPriceLine,
                           TDI.RSIPriceType,TDI.TradeSignalLine,TDI.TradeSignalType,5,i+1); 
        
  if (dRSIPriceLine0>dTradeSignalLine0 && dRSIPriceLine1<dTradeSignalLine1)
    return(SIG_UP);
  else if (dRSIPriceLine0<dTradeSignalLine0 && dRSIPriceLine1>dTradeSignalLine1)
    return(SIG_DN);
  else
    return(SIG_NO);
}


//-----------------------------------------------------------------------------
// function: ResetOrderVars()
// Description: Reset Order variables
//-----------------------------------------------------------------------------
void ResetOrderVars() {
  giOrderType=-1;
  giTicket=-1;
  gdSL=0;
  gdTP=0;  
  gdBELevel=0;
  gdBETrigger=0;
  return(0);
}


//-----------------------------------------------------------------------------
// function: CheckTP()
// Description: Check if TP has been hit
//-----------------------------------------------------------------------------
int CheckBE() {
  if (Order.MoveToBE>0 && gdBELevel>0) {
    if (giOrderType==OP_BUY && Bid>=gdBETrigger)
      MoveToBE();
    if (giOrderType==OP_SELL && Ask<=gdBETrigger)
      MoveToBE();
  }
}


//-----------------------------------------------------------------------------
// function: MoveToBE()
// Description: 
//-----------------------------------------------------------------------------
int MoveToBE() {
  int iErr;
  
  if (OrderSelect(giTicket,SELECT_BY_TICKET)) {    
    WaitForTradeContext();
    if (OrderModify(giTicket,OrderOpenPrice(),gdBELevel,OrderTakeProfit(),0)) {
       OrderSelect(giTicket,SELECT_BY_TICKET);
       WriteMsg("Ticket "+giTicket+" modified"+", OP="+DoubleToStr(OrderOpenPrice(),Digits)+", SL="+DoubleToStr(OrderStopLoss(),Digits)+
           ", TP="+DoubleToStr(OrderTakeProfit(),Digits));
       gdSL=OrderStopLoss();  
       gdTP=OrderTakeProfit();
       gdBELevel=0;
    }  
  }
  else {
    iErr=GetLastError();
    WriteMsg("Ticket "+giTicket+" failed order modify. Error: "+Err2Str(iErr)+". OP="+DoubleToStr(OrderOpenPrice(),Digits)+
            ", SL="+DoubleToStr(gdBELevel,Digits)+", TP="+DoubleToStr(OrderTakeProfit(),Digits));
  }  
  return; 
}


//-----------------------------------------------------------------------------
// function: OpenNewPosition()
// Description: Open a new BUY or SELL position based on the signal 
//-----------------------------------------------------------------------------
int OpenOrder(int iOrderType, double dLotSize, double dOpenPrice, int iSlippage, double dSL, double dTP, bool bTwoStep, int iMagicNr=0, string sComment="") {
  double dOrderSL=0;
  double dOrderTP=0;
  int iErr;
  int iTicket=0;
  string sOrderType;
  
  dOpenPrice=NormalizeDouble(dOpenPrice,Digits);
  sOrderType=OrderType2Str(iOrderType);
  if (bTwoStep) {
    dOrderSL=0;
    dOrderTP=0;
  }
  else {
    if (iOrderType==OP_BUY || iOrderType==OP_BUYLIMIT || iOrderType==OP_BUYSTOP) { 
      dOrderSL=NormalizeDouble(dOpenPrice-dSL*gdPipValue,Digits);
      dOrderTP=NormalizeDouble(dOpenPrice+dTP*gdPipValue,Digits);
    } 
    else {
      dOrderSL=NormalizeDouble(dOpenPrice+dSL*gdPipValue,Digits);
      dOrderTP=NormalizeDouble(dOpenPrice-dTP*gdPipValue,Digits);
    }
  }
  
  WriteMsg("Opening "+sOrderType+" At Price: "+DoubleToStr(dOpenPrice,Digits));
  WaitForTradeContext();
  iTicket=OrderSend(Symbol(),iOrderType,dLotSize,dOpenPrice,iSlippage,dOrderSL,dOrderTP,sComment,iMagicNr,0,Green);
  if(iTicket>0) {
    if(OrderSelect(iTicket,SELECT_BY_TICKET,MODE_TRADES)) { 
      WriteMsg(sOrderType+" opened. Ticket="+iTicket+", OP="+DoubleToStr(OrderOpenPrice(),Digits)+", Lots="+DoubleToStr(OrderLots(),2)+
                ", SL="+DoubleToStr(OrderStopLoss(),Digits)+", TP="+DoubleToStr(OrderTakeProfit(),Digits));
      if (bTwoStep && (dSL>0 || dTP>0)) {
        if (iOrderType==OP_BUY || iOrderType==OP_BUYLIMIT || iOrderType==OP_BUYSTOP) { 
          if (dSL>0) dOrderSL=NormalizeDouble(OrderOpenPrice()-dSL*gdPipValue,Digits);
          if (dTP>0) dOrderTP=NormalizeDouble(OrderOpenPrice()+dTP*gdPipValue,Digits);
        }
        else {
          if (dSL>0) dOrderSL=NormalizeDouble(OrderOpenPrice()+dSL*gdPipValue,Digits);
          if (dTP>0) dOrderTP=NormalizeDouble(OrderOpenPrice()-dTP*gdPipValue,Digits);
        }
        
        //OrderSelect(iTicket,SELECT_BY_TICKET);
        WriteMsg(sOrderType+" modify SL:"+DoubleToStr(dOrderSL,Digits)+", TP: "+DoubleToStr(dOrderTP,Digits));
        WaitForTradeContext();
        if (OrderModify(iTicket,OrderOpenPrice(),dOrderSL,dOrderTP,0)) {
          OrderSelect(iTicket,SELECT_BY_TICKET);
          WriteMsg(sOrderType+" modified"+", OP="+DoubleToStr(OrderOpenPrice(),Digits)+", SL="+DoubleToStr(OrderStopLoss(),Digits)+
             ", TP="+DoubleToStr(OrderTakeProfit(),Digits));
          gdSL=OrderStopLoss();  
          gdTP=OrderTakeProfit();
        }     
        else {
          OrderSelect(iTicket,SELECT_BY_TICKET); 
          iErr=GetLastError();
          WriteMsg("Failed "+sOrderType+" modify. "+Err2Str(iErr)+". OP="+DoubleToStr(OrderOpenPrice(),Digits)+", SL="
                     +DoubleToStr(dOrderSL,Digits)+", TP="+DoubleToStr(dOrderTP,Digits));
        }     
      }
    }
    else {
      iErr=GetLastError();        
      WriteMsg("Failed "+sOrderType+" open. "+Err2Str(iErr)+". No Ticket received, OP="+DoubleToStr(OrderOpenPrice(),Digits)+
                ", Lots="+DoubleToStr(OrderLots(),2));
    }
  }
  else {   
    iErr=GetLastError();
    WriteMsg("Failed "+sOrderType+" open. "+Err2Str(iErr)+", OP="+DoubleToStr(dOpenPrice,Digits)+", Lots="+DoubleToStr(dLotSize,2)+
             ", SL="+DoubleToStr(dOrderSL,Digits)+", TP="+DoubleToStr(dOrderTP,Digits));
  }
  return(iTicket);
}


//-----------------------------------------------------------------------------
// function: OrderType2Str()
// Description: 
//-----------------------------------------------------------------------------
string OrderType2Str(int iOrderType) {
  switch (iOrderType) {
   case OP_BUY:
     return("Buy");
     break;
   case OP_SELL:
     return("Sell");
     break; 
   case OP_BUYSTOP:
     return("Buy Stop");
     break;   
   case OP_SELLSTOP:
     return("Sell Stop");
     break;  
   case OP_BUYLIMIT:
     return("Buy Limit");
     break;  
   case OP_SELLLIMIT:
     return("Sell Limit");
     break;  
  }
  return("Unknown Order Type: "+iOrderType);   
}


//-----------------------------------------------------------------------------
// function: WaitForTradeContext()
// Description: Wait for TradeContext to be released
//-----------------------------------------------------------------------------
int WaitForTradeContext(int iTimeOut=120) {
  datetime dStartTime;
  
  // Don't bother with the TradeContextBusy if in test mode 
  if(IsTesting()) 
    return(1);
     
  if(!IsTradeContextBusy()) 
    return(0);
  else
    Comment("Trade Context Busy. Waiting....");
    
  // Wait for tradeflag to be released or timeout.
  dStartTime=GetTickCount(); // Reset timeout timer
  while(true) {
    if(!IsTradeContextBusy()) 
      return(0);
    // Exit if EA is stopped
    if (IsStopped()==true) 
      return(-1);    
    // Exit on time out
    if ((GetTickCount()-dStartTime)>(iTimeOut*1000) )
      return(-3);    
    Sleep(50);    
  } // endwhile
}


//-----------------------------------------------------------------------------
// function: SetPipDigits()
// Description: Set the number of digits for the pip value
//-----------------------------------------------------------------------------
void SetPipDigits() {
  int iaPipMult[]={1,10,1,10,1,10,100};
  gdPipValue = Point * iaPipMult[Digits];
  giPipDigits=MathLog(iaPipMult[Digits])/MathLog(10);
}


//-----------------------------------------------------------------------------
// function: ValidateTime()
// Description: Return a valid time format (ex. 08:30) or an error.
//-----------------------------------------------------------------------------
string ValidateTime(string sTime) {  
  if (StringLen(sTime)==1) return("0"+sTime+":00");
  if (StringLen(sTime)==2) return(sTime+":00");
  if (StringLen(sTime)==4 && StringSubstr(sTime, 1, 1)==":")  return("0"+sTime);
  if (StringLen(sTime)==4) return(StringSubstr(sTime, 0, 2)+":"+StringSubstr(sTime, 2, 2));
  if (StringLen(sTime)==5 && StringSubstr(sTime, 2, 1)==":") return(sTime);
  if (StringLen(sTime)==5 && StringSubstr(sTime, 2, 1)==".") return(StringSubstr(sTime, 0, 2)+":"+StringSubstr(sTime, 3, 2));
  // Error warning 
  Alert(Symbol()," Error: Invalid Time Format in input parameters! ",sTime); 
  return(sTime);
}


//-----------------------------------------------------------------------------
// function: IndicatorExists()
// Description: Check if an indicator exists
//-----------------------------------------------------------------------------
bool IndicatorExists(string sIndicatorName) {
  int hFile;
  string sFile;
    
  // Exit if dlls are disabled
  if (!IsDllsAllowed())
    return(True);
  
  // Try to open indicator 
  sFile=TerminalPath()+"\\experts\\indicators\\"+sIndicatorName;
  hFile=CreateFileA(sFile,FILE_READ_DATA,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);  
  if (hFile==INVALID_HANDLE_VALUE) {
    return(False);    
  }
  else {
    CloseHandle(hFile);
    return(True);
  }
  return(False);
}


//-----------------------------------------------------------------------------
// function: TF2Str()
// Description: Convert time-frame to a string
//-----------------------------------------------------------------------------
string TF2Str(int iPeriod) {
  switch(iPeriod) {
    case PERIOD_M1: return("M1");
    case PERIOD_M5: return("M5");
    case PERIOD_M15: return("M15");
    case PERIOD_M30: return("M30");
    case PERIOD_H1: return("H1");
    case PERIOD_H4: return("H4");
    case PERIOD_D1: return("D1");
    case PERIOD_W1: return("W1");
    case PERIOD_MN1: return("MN1");
    default: return("M"+iPeriod);
  }
}


//-----------------------------------------------------------------------------
// function: WriteMsg()
// Description:
//-----------------------------------------------------------------------------
int WriteMsg(string sMsg, int iWithTime=1, bool bClear=False) {
  static string sMsgList[10];
  static int iLine=0;
  int i;
  string sPrint, sTime;
  if (bClear) {
    for (i=0;i<10;i++)
      sMsgList[i]="";
    iLine=0;
  }
  if (bClear && sMsg=="") {
    Comment("");
    return(iLine);
  }
  if (iLine>=10) 
    iLine=10;
  else   
    iLine++;
  for (i=iLine-1;i>0;i--)
    sMsgList[i]=sMsgList[i-1];
  if ( (iWithTime & CLR_NONE)==1 && sMsg!="")
    sTime=TimeToStr(Time[0],TIME_MINUTES)+" ";
  else if ( (iWithTime & CLR_NONE)==2  && sMsg!="")
    sTime=TimeToStr(Time[0],TIME_DATE|TIME_MINUTES)+" ";
  else
    sTime="";
  sPrint="\n";
  sMsgList[0]=sMsg;
  for (i=0;i<iLine;i++)
    sPrint=sPrint+sTime+sMsgList[i]+"\n";
  Comment(sPrint);
  return(iLine);
}


//-----------------------------------------------------------------------------
// function: Err2Str()
// Description: 
//-----------------------------------------------------------------------------
string Err2Str(int iErr) {
  switch (iErr) {
    //errors returned from trade server
    case    0:  return("Error 0: No Error");        
    case    1:  return("Error 1: No Result");        
    case    2:  return("Error 2: Common Error");        
    case    3:  return("Error 3: Invalid Trade Parameters");        
    case    4:  return("Error 4: Server Busy");        
    case    5:  return("Error 5: Old Version");        
    case    6:  return("Error 6: No Connection");        
    case    7:  return("Error 7: Not Enough Rights");        
    case    8:  return("Error 8: Too Frequent Requests");        
    case    9:  return("Error 9: Malfunctional Trade");        
    case   64:  return("Error 64: Account Disabled");        
    case   65:  return("Error 65: Invalid Account");        
    case  128:  return("Error 128: Trade Timeout");        
    case  129:  return("Error 129: Invalid Price");        
    case  130:  return("Error 130: Invalid Stops");        
    case  131:  return("Error 131: Invalid Trade Volume");        
    case  132:  return("Error 132: Market Closed");        
    case  133:  return("Error 133: Trade Disabled");        
    case  134:  return("Error 134: Not Enough Money");        
    case  135:  return("Error 135: Price Changed");        
    case  136:  return("Error 136: Off Quotes");        
    case  137:  return("Error 137: Broker Busy");        
    case  138:  return("Error 138: Requote");        
    case  139:  return("Error 139: Order Locked");        
    case  140:  return("Error 140: Long Positions Only Allowed");        
    case  141:  return("Error 141: Too Many Requests");        
    case  145:  return("Error 145: Trade Modify Denied");        
    case  146:  return("Error 146: Trade Context Busy");        
    case  147:  return("Error 147: Trade Expiration Denied");        
    case  148:  return("Error 148: Trade Too Many Orders");        
    case  149:  return("Error 149: Trade Hedge Prohibited");        
    case  150:  return("Error 150: Trade Prohibited By Fifo");        
    //mql4 run time errors
    case 4000:  return("Error 4000: No MQL Error");        
    case 4001:  return("Error 4001: Wrong Function Pointer");        
    case 4002:  return("Error 4002: Array Index Out Of Range");        
    case 4003:  return("Error 4003: No Memory For Call Stack");        
    case 4004:  return("Error 4004: Recursive Stack Overflow");        
    case 4005:  return("Error 4005: Not Enough Stack For Param");        
    case 4006:  return("Error 4006: No Memory For Param String");        
    case 4007:  return("Error 4007: No Memory For Temp String");        
    case 4008:  return("Error 4008: Not Initialized String");        
    case 4009:  return("Error 4009: Not Initialized Arraystring");        
    case 4010:  return("Error 4010: No Memory For Arraystring");        
    case 4011:  return("Error 4011: Too Long String");        
    case 4012:  return("Error 4012: Remainder From Zero Divide");        
    case 4013:  return("Error 4013: Zero Divide");        
    case 4014:  return("Error 4014: Unknown Command");        
    case 4015:  return("Error 4015: Wrong Jump");        
    case 4016:  return("Error 4016: Not Initialized Array");        
    case 4017:  return("Error 4017: Dll Calls Not Allowed");        
    case 4018:  return("Error 4018: Cannot Load Library");        
    case 4019:  return("Error 4019: Cannot Call Function");        
    case 4020:  return("Error 4020: External Calls Not Allowed");        
    case 4021:  return("Error 4021: No Memory For Returned Str");        
    case 4022:  return("Error 4022: System Busy");        
    case 4050:  return("Error 4050: Invalid Function Paramscnt");        
    case 4051:  return("Error 4051: Invalid Function Paramvalue");        
    case 4052:  return("Error 4052: String Function Internal");        
    case 4053:  return("Error 4053: Some Array Error");        
    case 4054:  return("Error 4054: Incorrect Seriesarray Using");        
    case 4055:  return("Error 4055: Custom Indicator Error");        
    case 4056:  return("Error 4056: Incompatible Arrays");        
    case 4057:  return("Error 4057: Global Variables Processing");        
    case 4058:  return("Error 4058: Global Variable Not Found");        
    case 4059:  return("Error 4059: Func Not Allowed In Testing");        
    case 4060:  return("Error 4060: Function Not Confirmed");        
    case 4061:  return("Error 4061: Send Mail Error");        
    case 4062:  return("Error 4062: String Parameter Expected");        
    case 4063:  return("Error 4063: Integer Parameter Expected");        
    case 4064:  return("Error 4064: Double Parameter Expected");        
    case 4065:  return("Error 4065: Array As Parameter Expected");        
    case 4066:  return("Error 4066: History Will Updated");        
    case 4067:  return("Error 4067: Trade Error");        
    case 4099:  return("Error 4099: End Of File");        
    case 4100:  return("Error 4100: Some File Error");        
    case 4101:  return("Error 4101: Wrong File Name");        
    case 4102:  return("Error 4102: Too Many Opened Files");        
    case 4103:  return("Error 4103: Cannot Open File");        
    case 4104:  return("Error 4104: Incompatible Fileaccess");        
    case 4105:  return("Error 4105: No Order Selected");        
    case 4106:  return("Error 4106: Unknown Symbol");        
    case 4107:  return("Error 4107: Invalid Price Param");        
    case 4108:  return("Error 4108: Invalid Ticket");        
    case 4109:  return("Error 4109: Trade Not Allowed");        
    case 4110:  return("Error 4110: Longs Not Allowed");        
    case 4111:  return("Error 4111: Shorts Not Allowed");        
    case 4200:  return("Error 4200: Object Already Exists");        
    case 4201:  return("Error 4201: Unknown Object Property");        
    case 4202:  return("Error 4202: Object Does Not Exist");        
    case 4203:  return("Error 4203: Unknown Object Type");        
    case 4204:  return("Error 4204: No Object Name");        
    case 4205:  return("Error 4205: Object Coordinates Error");        
    case 4206:  return("Error 4206: No Specified Subwindow");        
    case 4207:  return("Error 4207: Some Object Error");
    default: return("Error "+iErr+": Unknown Error");
  }
}





