//+------------------------------------------------------------------+
//|                                    PowerSM SemiMartingale-EA.mq4 |
//|             Copyright © 2007, Scott Merritt, mer071898@mchsi.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Scott Merritt, modified by Primer"
#property link      "mer071898@mchsi.com, https://login.mql5.com/ru/users/primer"
#include <stdlib.mqh>

#define acct 0 //if not 0 then will work only on this account number
#define expireD 1
#define expireM 1
#define expireY 2013
string   Expire_Message = "Your trial period is over! Please contact Scott Merritt at mer071898@mchsi.com regarding an updated version, Thank you."; 

extern int expertId = 183547;
extern int TakeProfit=100;
extern int StopLoss=100;
extern int BreakevenStop = 300;

extern bool TimeEntry=false;
extern string StartTime="7:00";
extern string StopTime="17:00";
extern bool PriceEntry=false;
extern double Price=1.5500;
extern bool FirstPosBuy=true;

extern double StartLots=0.01;
extern double LotExponent=2.00;
extern bool SameDirectInProfit=false;
extern bool SameDirectInLoss=true;
extern bool RestartNewCycle = true;

extern int    slippage=3;   	//slippage for market order processing
extern int    OrderTriesNumber=10; //to repeat sending orders when you receive an error or requote

extern string    EAName="PowerSM"; 

bool buysig,sellsig,cycleended;
int tries,long,short,co,plen,lord,mord,lpos;
double Lot,lots[],tlot,lop,lcp,lsl,ltp;

double lbid = -1;

int counter = 0;

int init() 
{
   int      steps, dg;
   double   minlot,
            maxlot,
            temp;
   
   maxlot = MarketInfo(Symbol(),MODE_MAXLOT);
   minlot = MarketInfo(Symbol(),MODE_MINLOT);
   steps = maxlot / minlot;

   if(minlot < 0.1) dg = 2; else dg = 1;
   if(StartLots < minlot) StartLots = minlot;
   if(LotExponent<=0){Print("LotExponent error! It must be > 0"); return(-1);}
   
   ArrayResize(lots,1);
   lots[0] = StartLots;
   //Print("lots: ",DoubleToStr(lots[0],2));
   for(int i=2; i<=steps; i++){
      ArrayResize(lots,i);
      if(lots[i-2] * LotExponent < maxlot){
         lots[i-1] = lots[i-2] * LotExponent;
         //Print("lots: ",DoubleToStr(lots[i-1],2));
         }
      else{ 
         lots[i-1] = maxlot; 
         //Print("lots: ",DoubleToStr(lots[i-1],2));         
         break;
         }
      }
   int msize = ArraySize(lots);
   while(msize-1 >= 0){
      NormalizeDouble(lots[msize],dg);
      msize--;
      }
}

void start()  {
   if (Year()*10000+Month()*100+Day()>=expireY*10000+expireM*100+expireD) {
      Alert("Expire_Message");
      double d1;
      d1=2/d1;
      return(-1);
   }
   if (acct!=0 && AccountNumber()!=acct) {
      Alert("EA will not work on this account number");
      double d;
      d=2/d;
      return(-1);
   }
   //---- check for history and trading
   if(Bars<100 || IsTradeAllowed()==false) return;
   
   if (lbid == -1) lbid = Bid;

   co=CalculateCurrentOrders();
   if (co > 0) counter = 1;
      
   CheckForSignals();
   CheckForOpen();  
   DoBreakEven(BreakevenStop,0);
   
   lbid = Bid;
}


int CalculateCurrentOrders() {
   int ord; string c;
//----
   for(int i=0;i<OrdersTotal();i++) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==expertId) {
         ord++;
         if (OrderType()==OP_BUY) {
            mord=1;
            if (OrderClosePrice()-OrderOpenPrice()>BreakevenStop*Point) tlot=MathAbs(tlot); else tlot=-MathAbs(tlot);
         }
         if (OrderType()==OP_SELL) {
            mord=-1;
            if (-OrderClosePrice()+OrderOpenPrice()>BreakevenStop*Point) tlot=MathAbs(tlot); else tlot=-MathAbs(tlot);
         }
         c=StringSubstr(OrderComment(),0,StringFind(OrderComment(),"_",0));
         lpos=StrToInteger(c);
         return(ord);
      }
   }
//---- return orders volume
   return(ord);
}

double GetLastTrade() 
{
   int ord; lord=0;
   string c;
//----
   for(int i=OrdersHistoryTotal()-1;i>=0;i--) 
   {
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==expertId) 
      {
         if (OrderType()==OP_BUY) lord=1;
         if (OrderType()==OP_SELL) lord=-1;
         c=StringSubstr(OrderComment(),0,StringFind(OrderComment(),"_",0));
         lpos=StrToInteger(c);
         
         lop = NormalizeDouble(OrderOpenPrice(), Digits);
         lcp = NormalizeDouble(OrderClosePrice(), Digits);
         lsl = NormalizeDouble(OrderStopLoss(), Digits);
         ltp = NormalizeDouble(OrderTakeProfit(), Digits);
         
         if (OrderProfit()>0) 
          return(OrderLots()); 
         else 
          return(-OrderLots());
      }
   }
   return(0);
}

bool IsEntryTime()
{
  datetime tm0 = TimeCurrent();
  datetime tm1 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + StartTime);
  datetime tm2 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + StopTime);

  bool isTm = false; 
  if (tm1 <= tm2) 
    isTm = isTm || (tm1 <= tm0 && tm0 < tm2);
  else
    isTm = isTm || (tm1 <= tm0 || tm0 < tm2);
  
  return (isTm);
}

void CheckForSignals() 
{
  buysig = false;
  sellsig = false;
      
	if (co > 0) return;

  if (TimeEntry)
  {
    bool cond = IsEntryTime();
    if (!cond) return;
  }

  if (PriceEntry)
  { 
    cond = ((Bid >= Price && lbid < Price) || (Bid <= Price && lbid > Price));
    if (!cond) return;
  }
	
	double lastlot = GetLastTrade();
	if (lastlot >= 0)
	{
	  if (counter > 0)
	  {
	    if (!RestartNewCycle) return;
	  }
	
    if(counter > 0){
      if(lord>0)
         if(SameDirectInProfit)  buysig = true;
         else                    sellsig = true;
      else if(lord < 0)
         if(SameDirectInProfit)  sellsig = true;
         else                    buysig = true;    
      }
    else{ 
      if (FirstPosBuy)  buysig = true; 
      else                 sellsig = true;
      }
      
    lpos = 0;
    Lot = lots[0];
	}

	else
	{
    lpos++;

    int BE = 0;
    if (lord > 0 && lcp == lop+BE*Point) lpos--;
    if (lord < 0 && lcp == lop-BE*Point) lpos--;

    Lot = lots[lpos];
    if (lord > 0) 
      if(SameDirectInLoss) buysig = true;
      else                 sellsig = true;
    else if (lord < 0) 
      if(SameDirectInLoss) sellsig = true;
      else                 buysig = true;
  }
}

void CheckForOpen() {
   int    res,tr,TP;
   //---- sell conditions
   if(sellsig && co==0)  {
	   Print("sell open ",Lot," ",lpos);
      res = OpenAtMarket(OP_SELL,Lot,TakeProfit,lpos);
	   if (res>0) { tlot=Lot; }
      return;
   }
   //---- buy conditions
   if(buysig && co==0)  {
	   Print("buy open ",Lot," ",lpos);
      res = OpenAtMarket(OP_BUY,Lot,TakeProfit,lpos);
	   if (res>0) { tlot=Lot; }
      return;
   }
}
  
int OpenAtMarket(int mode,double lot,int TP,int pos) {
   int    res,tr,col;
   double openprice,sl,tp;
   tries=0;
   while (res<=0 && tries<OrderTriesNumber) {
      tr=0; while (tr<5 && !IsTradeAllowed()) { tr++; Sleep(2000); }
      RefreshRates();
      if (mode==OP_SELL) {
         openprice=Bid; 
         if (StopLoss>0) sl=openprice+StopLoss*Point;
         if (TP>0) tp=openprice-TP*Point;
         col=Red;
      } else {
         openprice=Ask;
         if (StopLoss>0) sl=openprice-StopLoss*Point;
         if (TP>0) tp=openprice+TP*Point;
         col=Blue;
      }
      res=OrderSend(Symbol(),mode,lot,openprice,slippage,sl,tp,pos+"_"+EAName+"_"+expertId,expertId,0,col);
      tries++;
   }
   Print("market order:: ",Symbol(),"  ",mode,"  ",lot,"  ",openprice,"  ",sl,"  ",tp,"  ",pos+"_"+EAName+"_"+expertId);
   if (res<=0) Print("error opening order : ",ErrorDescription(GetLastError()));
   return(res);
}


void DoBreakEven(int BP, int BE) {
   bool bres;
   for (int i = 0; i < OrdersTotal(); i++) {
      if ( !OrderSelect (i, SELECT_BY_POS) )  continue;
      if ( OrderSymbol() != Symbol() || OrderMagicNumber() != expertId )  continue;
      if ( OrderType() == OP_BUY ) {
         if (Bid<OrderOpenPrice()+BP*Point) continue;
         if ( OrderOpenPrice()+BE*Point-OrderStopLoss()>Point/10) {
               //Print(BP,"  ",BE," bestop");
               bres=OrderModify (OrderTicket(), OrderOpenPrice(), OrderOpenPrice()+BE*Point, OrderTakeProfit(), 0, Black);
				   if (!bres) Print("Error Modifying BE BUY order : ",ErrorDescription(GetLastError()));
         }
      }

      if ( OrderType() == OP_SELL ) {
         if (Ask>OrderOpenPrice()-BP*Point) continue;
         if ( OrderStopLoss()-(OrderOpenPrice()-BE*Point)>Point/10) {
               //Print(BP,"  ",BE," bestop");
               bres=OrderModify (OrderTicket(), OrderOpenPrice(), OrderOpenPrice()-BE*Point, OrderTakeProfit(), 0, Gold);
				   if (!bres) Print("Error Modifying BE SELL order : ",ErrorDescription(GetLastError()));
         }
      }
   }
   return;
}

/*
int FindPos(double ls) {
   for (int i=0; i<plen; i++) {
      if (NormalizeDouble(MathAbs(lots[i]-ls),3)<0.001) return(i);
   }
   return(-1);
}
*/