//+------------------------------------------------------------------+
//|                                                     NoLossEA.mq4 |
//|                                                  Hartono Setiono |
//|                                      mailto:hartono@mitrakom.com |
//+------------------------------------------------------------------+

// Version 1.0 - May 27th, 2007
// The first and final version of No Loss EA
// This EA was designed for GBP/USD only on 1 hour chart
// It needs historical data for GBP/JPY and USD/JPY to be exist
// otherwise it won't work
// This EA a long with NoLoss indicator is created just for ***FUN***
// DON'T EVER use this EA to trade Live !!!!

#property copyright "HS"
#property link      ""

//---- input parameters
extern bool     AccountIsIBFXmini=false;
extern double   Lots=0.1;
extern double   MaximumRisk=0.03;
extern double   DecreaseFactor=300;
extern double   MinLot=0.01;
extern int      Slippage=3;
extern double   TrailingStop=30;
double          StartBalance,StartEquity;
extern bool     UseHourTrade = false;
extern int      FromHourTrade = 6;
extern int      ToHourTrade = 18;

//---- global variables
int             dir=0;
int             openorders=0;
int             cnt;
string          pair;
int             MagicNumber;

int            bsflag=0;
int            bstarget=0;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   if (Symbol() == "AUDCADm" || Symbol() == "AUDCAD") { MagicNumber = 427101; }
   if (Symbol() == "AUDJPYm" || Symbol() == "AUDJPY") { MagicNumber = 427102; }
   if (Symbol() == "AUDNZDm" || Symbol() == "AUDNZD") { MagicNumber = 427103; }
   if (Symbol() == "AUDUSDm" || Symbol() == "AUDUSD") { MagicNumber = 427104; }
   if (Symbol() == "CHFJPYm" || Symbol() == "CHFJPY") { MagicNumber = 427105; }
   if (Symbol() == "EURAUDm" || Symbol() == "EURAUD") { MagicNumber = 427106; }
   if (Symbol() == "EURCADm" || Symbol() == "EURCAD") { MagicNumber = 427107; }
   if (Symbol() == "EURCHFm" || Symbol() == "EURCHF") { MagicNumber = 427108; }
   if (Symbol() == "EURGBPm" || Symbol() == "EURGBP") { MagicNumber = 427109; }
   if (Symbol() == "EURJPYm" || Symbol() == "EURJPY") { MagicNumber = 427110; }
   if (Symbol() == "EURUSDm" || Symbol() == "EURUSD") { MagicNumber = 427111; }
   if (Symbol() == "GBPCHFm" || Symbol() == "GBPCHF") { MagicNumber = 427112; }
   if (Symbol() == "GBPJPYm" || Symbol() == "GBPJPY") { MagicNumber = 427113; }
   if (Symbol() == "GBPUSDm" || Symbol() == "GBPUSD") { MagicNumber = 427114; }
   if (Symbol() == "NZDJPYm" || Symbol() == "NZDJPY") { MagicNumber = 427115; }
   if (Symbol() == "NZDUSDm" || Symbol() == "NZDUSD") { MagicNumber = 427116; }
   if (Symbol() == "USDCHFm" || Symbol() == "USDCHF") { MagicNumber = 427117; }
   if (Symbol() == "USDJPYm" || Symbol() == "USDJPY") { MagicNumber = 427118; }
   if (Symbol() == "USDCADm" || Symbol() == "USDCAD") { MagicNumber = 427119; }
   if (MagicNumber == 0) { MagicNumber = 427199; }
   
   pair = Symbol();
   
   return(0);
  } 

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

//+------------------------------------------------------------------+
//| Calculate open positions                                         |
//+------------------------------------------------------------------+
int GetCurrentOrders()
  {
  //---- calc open OrderSelect
   openorders=0;
   dir=0;
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
      {
        openorders+=1;
        if(OrderType()==OP_BUY) dir=1;
        if(OrderType()==OP_SELL) dir=-1;
      }  
   }
}
//+-------------------End Calculate open positions-------------------+
//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double LotsOptimized()
  {
   double lot=Lots;
   int    orders=HistoryTotal();     // history orders total
   int    losses=0;                  // number of losses orders without a break
//---- select lot size
   lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/500.0,1);
//---- calculate number of losses orders without a break
   if(DecreaseFactor>0)
     {
      for(int i=orders-1;i>=0;i--)
        {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; }
         if(OrderSymbol()!=Symbol() || OrderMagicNumber()!=MagicNumber || OrderType()>OP_SELL) continue;
         //----
         if(OrderProfit()>0) break;
         if(OrderProfit()<0) losses++;
        }
      if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//---- return lot size
   if(lot>999) lot=999;
   if(lot<MinLot) lot=MinLot;
   return(lot);
  }
//+-------------------End Calculate optimal lot size-----------------+
//+------------------------------------------------------------------+
//| Close Open Position                                              |
//+------------------------------------------------------------------+
int CloseTrade()
  { 
  for(int i=0;i<OrdersTotal();i++)
    {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)        break;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
      {
        if(OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3,Yellow);
        if(OrderType()==OP_SELL) OrderClose(OrderTicket(),OrderLots(),Ask,3,Yellow);
      }  
   }
}
//+----------------------End Close Open Position---------------------+
//+------------------------------------------------------------------+
//| Open Trade Position                                              |
//+------------------------------------------------------------------+
int OpenTrade()
  {
   int vLots=LotsOptimized();
   if (bsflag==1) OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,Slippage,0,Ask+bstarget*Point,"NoLoss",MagicNumber,0,Green);
   
   if (bsflag==2) OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,Slippage,0,Ask-bstarget*Point,"NoLoss",MagicNumber,0,Red);
}
//+----------------------End Open Trade Position---------------------+
//+------------------------------------------------------------------+
//| Buy/Sell Indicator                                               |
//+------------------------------------------------------------------+
int CalcBSI()
  {
  //---- calc current indicators
 
  //double val1=iCustom("GBPJPY",0,"NoLoss",0,0,0);
  //double val2=iCustom("GBPJPY",0,"NoLoss",0,1,0);
  //double val3=iCustom("USDJPY",0,"NoLoss",0,0,0);
  //double val4=iCustom("USDJPY",0,"NoLoss",0,1,0);
  
  double val1=iOpen("GBPJPY",0,0);
  double val2=iClose("GBPJPY",0,0);
  double val3=iOpen("USDJPY",0,0);
  double val4=iClose("USDJPY",0,0);
  
  double nval1=xDiv(val1,val2);
  double nval2=xDiv(val3,val4);
  
  if(nval1>nval2)
  {
    bsflag=2;
    bstarget=(nval1-nval2)*10000;
  } else
  if(nval1<nval2)
  {
    bsflag=1;
    bstarget=(nval2-nval1)*10000;
  }
  else
  {
    bsflag=0;
    bstarget=0;
  }

  if(bstarget<10)
  {
    bsflag=0;
    bstarget=0;
  }
}
//+-----------------------End Buy/Sell Indicator---------------------+
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
 {
 
 if (Period()<PERIOD_H1) { Alert("Only on H1 or larger!"); return(0); } // For use only on H4 --- NO ERROR if activated
 
  for(cnt=0;cnt<OrdersTotal();cnt++)
     {
      OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
      if(OrderType()<=OP_SELL &&   // check for opened position 
         OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)  // check for symbol and magic number
        {
         if(OrderType()==OP_BUY)   // long position is opened
           {
          
            // check for trailing stop
            if(TrailingStop>0)  
              {                 
               if(Bid-OrderOpenPrice()>Point*TrailingStop)
                 {
                  if(OrderStopLoss()<Bid-Point*TrailingStop)
                    {
                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                     return(0);
                    }
                 }
              }
           }
         else // go to short position
           {
            
            // check for trailing stop
            if(TrailingStop>0)  
              {                 
               if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                 {
                  if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                    {
                     OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                     return(0);
                    }
                 }
              }
           }
        }
     }
//+--------------------End TrailingStop & BreakEven------------------+
if (UseHourTrade)
   {
   if (!((Hour() >= FromHourTrade) && (Hour() <= ToHourTrade)))
      {
      Comment("Non-Trading Hours!");
      return(0);
      }
   }

  GetCurrentOrders();
  CalcBSI();
  Comment("\nStart Balance= ",StartBalance,",","Start Equity= ",StartEquity,
		   "\nBalance: ",AccountBalance(),","," Equity: ",AccountEquity(),","," TotalProfit: ",AccountProfit(),
         "\nBSFlag: ",bsflag,"\nbstarget: ",bstarget);
   
  //---- exit trades
  if (openorders!=0) {
     if ((bsflag==1) && (dir<0)) CloseTrade();
     if ((bsflag==2) && (dir>0)) CloseTrade();
  }   
  //---- open trades
  else 
  {
   if (bsflag != 0 && bstarget>20) OpenTrade();
  }   
}
//+---------------------End Expert Start Function--------------------+

double xDiv(double a, double b)
{
  if(b==0) return(b); else return(a/b);
}