extern int initial_sl = 30;
extern int take_profit = 70;

extern int    BoxLength                  = 25;
int    BoxTimeFrame               = 0;
extern int    BoxRange                   = 20; // fixed box range, when AutoBoxRange is false
extern int    BoxBufferPips              = 10; // add this amount to the Box Yellow and Magenta lines
extern int    MinBarsClosedOutsideBO     = 1; // number of bars to close outside the BO levels to signal trades; 0 means "enter immediately on Breakout"
extern int    MaxBreakoutTradesPerBox    = 2; // maximum number of "trades" shown for each Box; 0 to ignore signals (no stats!), 999 or more to show+count all;
extern int    MaxProfitTradesPerBox      = 1;
extern bool   AutoBoxRange               = false;// when true, will use AutoBoxRangeDailyATRfactor*daily_ATR_value as the BoxRange value;
extern int    AutoBoxRangeDailyATRperiod = 30;
extern double AutoBoxRangeDailyATRfactor = 0.24;
extern int    DaysBack                   = 100; // calendar days back; 0=full history
extern double SL               = 1.000; // SL Factor, or fixed pips if greater than "TP_is_pips_above";

#define DECIMAL_CONVERSION 10
#define COMMENT_DIGITS 2
#define RETRYCOUNT    20
#define RETRYDELAY    200

bool all_sigs = false;

/***********EA HELPERs ************************/

#define LONG          1
#define SHORT         -1
#define C_TICKET         0
#define C_ROW_ID         1
#define C_SIG         2
#define C_DIR         3
#define C_OPRICE        4
#define C_OTIME         5
#define C_TP         6
#define C_SL         7
#define C_CMD         8
#define C_LOTS         9

extern int  magic_number =  99991;
double max_drawdown_percent = 30.0;
double max_lots=1;
string _sig_tag = "";
extern int _max_live_trades = 5;
extern double min_lots=0.01;

double margin_per_lot = 10000;
bool safe_mode_enabled = false;

bool     WriteScreenshots                    =  false;
datetime lastAlertTime;
int Slippage = 2;
int p5=0, p8=1, p13=2, p50=3, p100=4, p30=5, p300=6;

string display = "";

int decimalConv = 1;
bool BUY=false;
bool SELL=false;

int trail_amount = 0;
double initial_trail_step = 0;
double initial_trail_step_buffer  =0;
int signal_trade_mode = 0;
int save_paper_trades=1;
string signal_id="";

bool debug = false;
string comment = "";
string signal_config="";
int next_signal_config_time =0;
int next_db_ping_interval = 10;
double system_max_lots = 10;


bool init_previous_trades=true;

int last_counted_time=0;
string _sigs_data[] = {"ssoS1;0,30,30,sell,1,0,;","ssoB1;0,30,30,sell,1,0,;"};
string _signals[10];
string _signal_params[10][10];
string _trades[10][10];
int _account_id =0;
int paper_trade = -10;
int real_trade_mode = 1;
int minSLTPdstnc;

int init(){     
   for(int i=0; i< 10; i++){
      for(int j=0;j<10;j++){
         _trades[i][j] = 0;
      }
   }
   minSLTPdstnc = MarketInfo(Symbol(), MODE_STOPLEVEL);

   if (Digits == 3 || Digits == 5)   {      
      decimalConv =     DECIMAL_CONVERSION;
   }
   all_sigs = false;

   
   return(0);
   
}
int total_live_trades(){
   int live = OrdersTotal();
   return(live);
}

void handle_trade_sig(){
      double stop = Point* initial_sl * decimalConv;
      double tp = Point*take_profit*decimalConv;
      if( BUY && get_lots() > 0){
        open_trade(LONG, get_lots(), stop, tp, comment, signal_id, signal_trade_mode);
      }
      
      if( SELL && get_lots() > 0){    

         open_trade(SHORT, get_lots(), stop, tp, comment, signal_id, signal_trade_mode);              
      }
      BUY=false;SELL=false;

}

void string_split(string res, int split, string &values[]){
  int total_elements =0;   
   int last_comma =0;
   for(int k =0; k< StringLen(res); k++){
      int char =  StringGetChar(res, k);
      if(char == split){
         if(last_comma > 0){
            values[total_elements] = StringSubstr(res, last_comma+1, k - last_comma-1);
         }else{
            values[total_elements] = StringSubstr(res, last_comma, k - last_comma);
         }
         total_elements+=1;
         last_comma = k;
      }
   }     
}

bool Exit(int ticket, double volume, color clr)  {
    bool debug = true;
    int t = 0;
    int i, j, cmd;
    double prc, sl, tp, lots;
    string cmt;
    int dir;
    bool closed;
    
    if( OrderType() == OP_SELL){
      dir = SHORT;
    }else{
      dir = LONG;
    }

    if(debug){
      Print("Exit("+dir+","+DoubleToStr(volume,3)+","+t+")   ", ticket);
    }
    for (i=0; i<RETRYCOUNT; i++) {
        for (j=0; (j<50) && IsTradeContextBusy(); j++)
            Sleep(100);
        RefreshRates();

        if (dir == LONG) {
            prc = Bid;
        }
        if (dir == SHORT) {
            prc = Ask;
       }
       if(debug){
        Print("Exit: prc="+DoubleToStr(prc,Digits));
       }
       closed = OrderClose(ticket, volume, prc, Slippage, clr);

        if (closed) {
            if(debug){
               Print("Trade closed");
            }
            Screenshot("Exit");

            return (true);
        }
        if(debug){
         Print("Exit: error \'"+GetLastError()+"\' when exiting with "+DoubleToStr(volume,3)+" @"+DoubleToStr(prc,Digits));
        }
        Sleep(RETRYDELAY);
    }

    if(debug){
      Print("Exit: can\'t enter after "+RETRYCOUNT+" retries");
    }
    return (false);
}

void ExitAll(int magic_num) {

   for (int i = OrdersTotal()-1; i >= 0; i--) {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      
      if(OrderMagicNumber() == magic_num ) {
         if (OrderType() == OP_BUY ) { Exit(OrderTicket(), OrderLots(), Blue); }
         if (OrderType() == OP_SELL ) { Exit( OrderTicket(), OrderLots(), Red); }
      }
   }
}
double max_account_equity = 0;
double get_lots(){
   if(max_account_equity < AccountEquity()){
      max_account_equity = AccountEquity();
   }    
   if(max_account_equity-AccountEquity() > 0 && (AccountEquity() / max_account_equity) < 1-(max_drawdown_percent/100)){
      return(0);
   }
   if(debug){
      Print("system_max_lots", system_max_lots, "min_lots", min_lots);
   }
   if(total_live_trades() >= _max_live_trades){
      return(0);
   }
return(min_lots);
   double Equity = AccountEquity ( ) /margin_per_lot;
   //double auto_scale_lots = NormalizeDouble(AccountEquity() / margin_per_lot, auto_scale_digits);
   //Print("AccountMaxLots" , account_max_lots, "AccountEquity:", AccountEquity (), "max_lots:", max_lots);

   if(system_max_lots > max_lots){
      return(max_lots);
   }else{
      return(system_max_lots);
   }
   
}
bool open_trade(int dir, double lots, double stop, double take, string comment, string sig, int trade_mode){
   if(trade_mode == real_trade_mode ){
      OpenTrade(dir, lots, stop, take, comment, sig, trade_mode);
   }else{
      open_paper_trade(dir, lots, stop, take, comment, sig, trade_mode);   
   }
}
bool open_paper_trade(int dir, double lots, double stop, double take, string comment, string sig, int trade_mode){
   int cmd;
   double prc, tp, sl;
   color clr;
   if (dir == LONG) 
   {

      cmd = OP_BUY;
      prc = Ask;
      clr = Green;
      tp = take + prc;
      sl = prc - stop;
   }
   if (dir == SHORT) 
   {
      cmd = OP_SELL;
      prc = Bid;
      clr = Pink;
      tp = prc - take;
      sl = prc + stop;
   }
   
   int row_id = TimeCurrent();

   _trades[trade_index(sig)][0] = 0;
   _trades[trade_index(sig)][1] = row_id;
   _trades[trade_index(sig)][2] = sig;
   _trades[trade_index(sig)][3] = dir;
   _trades[trade_index(sig)][4] = prc;
   _trades[trade_index(sig)][5] = TimeCurrent();
   _trades[trade_index(sig)][6] = tp;
   _trades[trade_index(sig)][7] = sl;
   _trades[trade_index(sig)][8] = cmd;
   _trades[trade_index(sig)][9] = lots;

}
bool open_real_trade(int dir, double lots, double stop, double take, string comment, string sig, int trade_mode)  
{
   int i, j, ticket, cmd;
   double prc, tp, sl, tp2, sl2;
   color clr;

   for (i=0; i<RETRYCOUNT; i++) 
   {
    // for (j=0; (j<50) && IsTradeContextBusy(); j++)
    //     Sleep(100);
     RefreshRates();

     if (dir == LONG) 
     {
         cmd = OP_BUY;
         prc = Ask;
         clr = Blue;
         tp = take + prc;
         sl = prc - stop;
         sl2 = sl;
         tp2=tp;
         //sl =0;
         //tp = 0;
     }
     if (dir == SHORT) 
     {
         cmd = OP_SELL;
         prc = Bid;
         clr = Red;
         tp = prc - take;
         sl = prc + stop;
         sl2 = sl;
         tp2=tp;
         //sl = 0;
         //tp = 0;
     }

     ticket = OrderSend(Symbol(), cmd, lots, prc, Slippage, sl, tp, comment, magic_number,0,clr);

     if (ticket > 0){
        //OrderModify( OrderTicket(), OrderOpenPrice(), stop, take, 0, Blue ) ;           
         OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES);
         Screenshot("OpenTrade_SLTP");
         int row_id = TimeCurrent();
 
         _trades[trade_index(sig)][0] = OrderTicket();
         _trades[trade_index(sig)][1] = row_id;
         _trades[trade_index(sig)][2] = sig;
         _trades[trade_index(sig)][3] = dir;
         _trades[trade_index(sig)][4] = OrderOpenPrice();
         _trades[trade_index(sig)][5] = OrderOpenTime();
         _trades[trade_index(sig)][6] = tp2;
         _trades[trade_index(sig)][7] = sl2;
         _trades[trade_index(sig)][8] = cmd;
         _trades[trade_index(sig)][9] = OrderLots();

         return (true);

     }   // end if (ticket != -1)
  
     //Print("OpenTrade: error \'"+ErrorDescription(GetLastError())+"\' when entering with "+DoubleToStr(lots,3)+" @"+DoubleToStr(prc,Digits));
     Sleep(RETRYDELAY);
  
   } // end for (i=0; i<RETRYCOUNT; i++) 

    //Print("OpenTrade: can\'t enter after "+RETRYCOUNT+" retries");
    return (false);
}
bool OpenTrade(int dir, double volume, double stop, double take, string sig, string comment, int t = 0)  
{
    int i, j, ticket, cmd;
    double prc, sl, tp, lots;
    double sl2, tp2;
    string cmt;
    color clr;

    //Print("OpenTrade("+dir+","+DoubleToStr(volume,3)+","+DoubleToStr(stop,Digits)+","+DoubleToStr(take,Digits)+","+t+")");

    lots = CheckLots(volume);
    

    for (i=0; i<RETRYCOUNT; i++) 
    {
        for (j=0; (j<50) && IsTradeContextBusy(); j++)
            Sleep(100);
        RefreshRates();

        if (dir == LONG) 
        {
            cmd = OP_BUY;
            prc = Ask;
            sl = stop;
            tp = take;
            tp2 = take + prc;
            sl2 = prc - stop;
           
         clr = Blue;
        }
        if (dir == SHORT) 
        {
            cmd = OP_SELL;
            prc = Bid;
            sl = stop;
            tp = take;
         tp2 = prc - take;
         sl2 = prc + stop;
            
         clr = Red;
        }
        //Print("OpenTrade: prc="+DoubleToStr(prc,Digits)+" sl="+DoubleToStr(sl,Digits)+" tp="+DoubleToStr(tp,Digits));

        cmt = comment;
        if (t > 0)
            cmt = comment + "|" + t;

        ticket = OrderSend(Symbol(), cmd, lots, prc, Slippage, 0, 0, cmt, magic_number,0,clr);
        if (ticket > 0){
            if( sl > 0 || tp > 0){
               Screenshot("OpenTrade");
               AssignSLTP(ticket, dir, stop, take);
            }else{ 
               Screenshot("OpenTrade_SLTP");
            }   // end if( sl > 0 || tp > 0)
           
            OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES);
            Screenshot("OpenTrade_SLTP");
            int row_id = TimeCurrent();
 
            _trades[trade_index(sig)][0] = OrderTicket();
            _trades[trade_index(sig)][1] = row_id;
            _trades[trade_index(sig)][2] = sig;
            _trades[trade_index(sig)][3] = dir;
            _trades[trade_index(sig)][4] = OrderOpenPrice();
            _trades[trade_index(sig)][5] = OrderOpenTime();
            _trades[trade_index(sig)][6] = tp2;
            _trades[trade_index(sig)][7] = sl2;
            _trades[trade_index(sig)][8] = cmd;
            _trades[trade_index(sig)][9] = OrderLots();

            return (true);

        }   // end if (ticket != -1)
        else if (ticket == -1)
        {// look for any open trades that are missing a stop loss and take profit
         if (FindTradesMissingSLTP(dir, stop, take, comment))
         {
             Screenshot("OpenTrade_SLTP");
             return( true );
         }
        }
        
        //Print("OpenTrade: error \'"+ErrorDescription(GetLastError())+"\' when entering with "+DoubleToStr(lots,3)+" @"+DoubleToStr(prc,Digits));
        Sleep(RETRYDELAY);
        
    } // end for (i=0; i<RETRYCOUNT; i++) 

    //Print("OpenTrade: can\'t enter after "+RETRYCOUNT+" retries");
    return (false);
}

//-----------------------------------------------------------------------------------+
// This routine calculates a Take Profit price and checks it against the minimum stop 
//  loss take profit distance returned by MarketInfo() for the currency pair.
//-----------------------------------------------------------------------------------+
double GetTakeProfit(int dir, double openPrc, double take)
{
   double tp = 0;


   // Calculate Take Profit Price.
   //-----------------------------
   
   if (dir == LONG)
   {
      tp = openPrc + take;
      
      RefreshRates();
      
      if ((tp - Bid) < minSLTPdstnc*Point)
      {
         tp = Bid + minSLTPdstnc*Point;
         if (lastAlertTime != Time[0])
         {
            //Print("Min. Stop Loss Take Profit distance = ", minSLTPdstnc);
            Alert("GetTakeProfit() - Specified TP is TOO CLOSE to current price!\nMinimum allowed TP distance for this currency of (",tp,") used instead");
            lastAlertTime = Time[0];
         }
      }
   }
   else if (dir == SHORT)
   {
      tp = openPrc - take;
      
      RefreshRates();
      
      if ((Ask - tp) < minSLTPdstnc*Point)
      {
         tp = Ask - minSLTPdstnc*Point;
         if (lastAlertTime != Time[0])
         {
            //Print("Min. Stop Loss Take Profit distance = ", minSLTPdstnc);
            Alert("GetTakeProfit() - Specified TP is TOO CLOSE to current price!\nMinimum allowed TP distance for this currency of (",tp,") used instead");
            lastAlertTime = Time[0];
         }
      }
   }
   
   return(tp);
}

//-----------------------------------------------------------------------------------+
// This routine calculates a Stop Loss price and checks it against the minimum stop 
//  loss take profit distance returned by MarketInfo() for the currency pair.
//-----------------------------------------------------------------------------------+
double GetStopLoss(int dir, double openPrc, double stop)
{
   double sl = 0;


   // Calculate Take Profit Price.
   //-----------------------------
   
   if (dir == LONG)
   {
      sl = openPrc - stop;
      
      RefreshRates();
      
      if ((Bid - sl) < minSLTPdstnc*Point)
      {
         sl = Bid - minSLTPdstnc*Point;
         if (lastAlertTime != Time[0])
         {
            //Print("Min. Stop Loss Take Profit distance = ", minSLTPdstnc);
            Alert("GetStopLoss() - Specified SL is TOO CLOSE to current price!\nMinimum allowed SL/TP distance for this currency of (",sl,") used instead");
            lastAlertTime = Time[0];
         }
      }
   }
   else if (dir == SHORT)
   {
      sl = openPrc + stop;
      
      RefreshRates();
      
      if ((sl - Ask) < minSLTPdstnc*Point)
      {
         sl = Ask + minSLTPdstnc*Point;
         if (lastAlertTime != Time[0])
         {
            //Print("Min. Stop Loss Take Profit distance = ", minSLTPdstnc);
            Alert("GetStopLoss() - Specified SL is TOO CLOSE to current price!\nMinimum allowed SL/TP distance for this currency of (",sl,") used instead");
            lastAlertTime = Time[0];
         }
      }
   }
   
   return(sl);
}

//----------------------------------------------------------------+
// routine makes RETRYCOUNT attempts to "modify" the Stop Loss and 
//  Take Profit for the specified ticket/order
//----------------------------------------------------------------+

bool AssignSLTP(int tkt, int dir, double stop, double take)
{
   int ix, ix2;
   double tp = take;
   double sl = stop;
   bool modified = false;
   

   // Select specified ticket.
   OrderSelect(tkt, SELECT_BY_TICKET, MODE_TRADES);

   // Make several attempts   

   ix = 0;
   while(!modified && ix < RETRYCOUNT)   
   {
      for (ix2 = 0; (ix2 < 50) && IsTradeContextBusy(); ix2++)
         Sleep(100);
      RefreshRates();
      
      if(dir == LONG)   // LONG order
      {
         // set take profit
         if( tp != 0 ) 
            tp = GetTakeProfit(dir, OrderOpenPrice(), take);
	      else 
	         tp = 0;
	      
	      // set stop loss	     
         if( sl != 0 ) 
            sl = GetStopLoss(dir, OrderOpenPrice(), stop);
	      else 
	         sl = 0;

         // attempt to set stop loss and take profit
         if ( OrderModify(tkt, 0, sl, tp, 0) ) 
         {
            //Print("OpenTrade: SL/TP are set LONG");
            Screenshot("OpenTrade_SLTP");
            modified = true;
         }
         else
         {
            //Print("OpenTrade: error \'"+ErrorDescription(GetLastError())+"\' when setting SL/TP");
            Sleep(RETRYDELAY);
         }
      }
      
      else if( dir == SHORT )    // SHORT order
      {
         // set take profit
         if( tp != 0 ) 
            tp = GetTakeProfit(dir, OrderOpenPrice(), take);
	      else 
	         tp = 0;
	      
	      // set stop loss	     
         if( sl != 0 ) 
            sl = GetStopLoss(dir, OrderOpenPrice(), stop);
	      else 
	         sl = 0;

         // attempt to set stop loss and take profit
         if ( OrderModify(tkt, 0, sl,tp, 0) ) 
         {
            //Print("OpenTrade: SL/TP are set SHORT");
            Screenshot("OpenTrade_SLTP");
            modified = true;
         }                
         else
         {
            //Print("OpenTrade: error \'"+ErrorDescription(GetLastError())+"\' when setting SL/TP");
            Sleep(RETRYDELAY);
         }
      }
      
      ix++;    // increment loop counter

   }  // end while(!modified && ix < RETRYCOUNT)   
   
   return(modified);
}

//--------------------------------------------------------------+
// routine checks for open trades placed by the EA this time bar 
//  that have Stop Loss and Take Profit values of zero.  It then
//  reattempts to assign the stop loss or take profit.  If 
//  successful it returns true, otherwise false.
//--------------------------------------------------------------+

bool FindTradesMissingSLTP(int dir, double stop, double take, string comment)
{
   bool result = true;
   
   
   for (int ix = OrdersTotal()-1; ix >= 0; ix--) 
   {
      OrderSelect(ix, SELECT_BY_POS, MODE_TRADES);
      
      // look for one of the EAs trades
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number && OrderComment() == comment) 
      {
         // if the trade has neither stop loss or take profit attempt to assign one
         if (OrderStopLoss() <= 0 && OrderTakeProfit() <= 0)
            if (!AssignSLTP(OrderTicket(), dir, stop, take))
               result = false;   // record whether AssignSLTP ever fails
      }
      
   }  // end for (int ix = OrdersTotal()-1; ix >= 0; ix--)
   
   // return result of our attempt
   return (result);
}

double CheckLots(double lots)
{
    double lot, lotmin, lotmax, lotstep, margin;
    
    lotmin = MarketInfo(Symbol(), MODE_MINLOT);
    lotmax = MarketInfo(Symbol(), MODE_MAXLOT);
    lotstep = MarketInfo(Symbol(), MODE_LOTSTEP);
    margin = MarketInfo(Symbol(), MODE_MARGINREQUIRED);

    if (lots*margin > AccountFreeMargin())
        lots = AccountFreeMargin() / margin;

    lot = MathFloor(lots/lotstep + 0.5) * lotstep;

    if (lot < lotmin)
        lot = lotmin;
    if (lot > lotmax)
        lot = lotmax;

    return (lot);
}

void init_signals(){

   int mysql=0;
   int signal_count = 0;
   for(int k=0;k<1;k++){
      int numOfRows = ArraySize(_sigs_data);
      for (int j=0;j<numOfRows;j++) { 

         string row = _sigs_data[j];
         string values[10];   
//         row = StringSubstr(row, StringFind(row, ";;;;")+4);
         string_split(row, ';', values);
         _signals[signal_count] = values[0];

         string params[10];
         string_split(values[1],',', params);
         Print(signal_count, "row=", row);
         //Print(signal_count, "params[5]=", params[5]);         
         for(int i =0; i< 10; i++){
            _signal_params[signal_count][i] = params[i];
       
         }
   
         if(_signals[signal_count] == "test_sigadfasdf" ){
            Print(signal_count, "row", row);
            Print("sig", values[0], ":", signal_count, "params mode=", params[1], "   copied", _signal_params[signal_count][1]);
            Print("sig", values[0], ":", signal_count, "params mode=", params[2], "   copied", _signal_params[signal_count][2]);
         }      
         signal_count +=1;
      }
    } 
/*

    if(init_previous_trades == true){
      total_orders = OrdersTotal();
      for(int i=1; i < 20 && i < total_orders; i++){
         OrderSelect(total_orders-i, SELECT_BY_POS, MODE_TRADES);
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number){
            int row_id = -1;
 
            _trades[trade_index(sig)][0] = OrderTicket();
            _trades[trade_index(sig)][1] = row_id;
            _trades[trade_index(sig)][2] = sig;
            _trades[trade_index(sig)][3] = dir;
            _trades[trade_index(sig)][4] = OrderOpenPrice();
            _trades[trade_index(sig)][5] = OrderOpenTime();
            _trades[trade_index(sig)][6] = OrderTakeProfit();
            _trades[trade_index(sig)][7] = OrderStopLoss();
            _trades[trade_index(sig)][8] = OrderType();
            _trades[trade_index(sig)][9] = OrderLots();
          }
      }
      init_previous_trades = false;
   }
    if(init_previous_trades == true){
      for( k=0; k< signal_count; k++){
         string sig = _signals[k] ;
         query=StringConcatenate("SELECT CONCAT(';;;;', id, ';', ticket, ',', id, ',', sig, ',', d, ',', op, ',', ot, ',', tp, ',', sl, ',', md, ',', l, ',;') FROM trades WHERE ct = 0 AND sig = '", sig, "' ORDER BY id DESC LIMIT 1;  ");
         mysql_query(mysql,query); 
         result = mysql_store_result(mysql); 
         numOfRows = mysql_num_rows(result); 
         if(numOfRows > 0){
            for (j=0;j<numOfRows;j++) { 
               row = mysql_fetch_row(result);
               string values2[10];   
               row = StringSubstr(row, StringFind(row, ";;;;")+4);
               //Print("rowInit ", row);
               string_split(row, ';', values2);
               string params2[10];
               string_split(values2[1],',', params2);

               for(i=0; i< 10; i++){
                  _trades[trade_index(sig)][i] = params2[i];
                  //Print("aaa", _trades[trade_index(sig)][i] );
               }
             }
            mysql_free_result(result);
         }
      }
      init_previous_trades = false;
    }
*/    
}

void set_signal_config(string signal_name, bool set_trade){
   int size = ArraySize(_signals);
      
   for(int i =0; i< size; i++){
      //Print("sigs count=", i, " ", _signals[i], ":", signal_name);
      if(StringLen(_signals[i]) > 2 && _signals[i] == signal_name){
         signal_id = signal_name;
         signal_trade_mode = StrToDouble(_signal_params[i][0]);
                  
         save_paper_trades = StrToInteger(_signal_params[i][4]);
         
//         trail_amount = StrToDouble(_signal_params[i][3]);
//         initial_trail_step = StrToDouble(_signal_params[i][4]);
//         initial_trail_step_buffer =StrToDouble(_signal_params[i][5]);

   
         if(set_trade){
            Print("setsignalconfig initial_sl:", _signal_params[i][1], " tp:", _signal_params[i][2], " sig:", _signals[i], " index:", i);
            if( _signal_params[i][3] == "sell"){
               SELL = true; 
            }else if( _signal_params[i][3] == "buy"){
              BUY = true; 
            }            
         }
         comment = signal_name;  
          
      }
   }   
}
void Screenshot(string moment_name)
{
    if ( WriteScreenshots )
        WindowScreenShot(WindowExpertName()+"_"+Symbol()+"_M"+Period()+"_"+
                         Year()+"-"+two_digits(Month())+"-"+two_digits(Day())+"_"+
                         two_digits(Hour())+"-"+two_digits(Minute())+"-"+two_digits(Seconds())+"_"+
                         moment_name+".gif", 1024, 768);
}

string two_digits(int i)
{
    if (i < 10)
        return ("0"+i);
    else
        return (""+i);
}
int trade_index(string sig){
   int size = ArraySize(_signals);
   for(int i =0; i<size;  i++){
      if(_signals[i] == sig){
         
         return(i);
      }
   }
  
}

void  get_signal(string sig, string &params[]){
   
   int size = ArraySize(_signals);
   for(int i =0; i<size;  i++){
      if(_signals[i] == sig){
         for(int j=0; j< 10; j++){
            params[j] = _signal_params[i][j];
         }
         break;
      }
   }
}

bool handle_current_trade(string sig){
   bool live_trade = false;
   double price = 0;
   double open_price;
   string trade_info[10];   

   if(StrToInteger(_trades[trade_index(sig)][0]) <= 0 && StrToInteger(_trades[trade_index(sig)][1]) <= 0){
      return(false);
   }

   int close_time = 0;
   RefreshRates();
   if(StrToInteger(_trades[trade_index(sig)][8]) == OP_BUY){
      price = Ask;
   }else{
      price = Bid;
   }
   string query ="";
   double profit =0;

   int profit_loss = -1;
   double profitPips, increments, sl_init;
   double distToStop;
   double diff;
   double currentProfit, currSL;
   double init_step = (initial_trail_step + initial_trail_step_buffer)*decimalConv*Point;   
   double sl_trail;

   double trail = NormalizeDouble(Point * trail_amount * decimalConv, Digits);
   if( StrToInteger(_trades[trade_index(sig)][C_CMD]) == OP_SELL){
      currentProfit = StrToDouble(_trades[trade_index(sig)][C_OPRICE]) - Ask;
      currSL =  StrToDouble(_trades[trade_index(sig)][C_SL]) - StrToDouble(_trades[trade_index(sig)][C_OPRICE]);            
      sl_init = NormalizeDouble(StrToDouble(_trades[trade_index(sig)][C_OPRICE]) -  (initial_trail_step*decimalConv*Point), Digits);
      distToStop = StrToDouble(_trades[trade_index(sig)][C_SL]) - Ask;
      sl_trail = NormalizeDouble(Ask + trail, Digits);

   }else{
      currentProfit = Bid - StrToDouble(_trades[trade_index(sig)][C_OPRICE]);
      currSL = StrToDouble(_trades[trade_index(sig)][C_OPRICE]) - StrToDouble(_trades[trade_index(sig)][C_SL]);
      sl_init = NormalizeDouble(StrToDouble(_trades[trade_index(sig)][C_OPRICE]) +  (initial_trail_step*decimalConv*Point), Digits);
      distToStop = Bid - StrToDouble(_trades[trade_index(sig)][C_SL]);
      sl_trail = NormalizeDouble(Bid - trail, Digits);            
   }
   diff = distToStop - trail;
   double sl_amount = initial_sl*decimalConv*Point;
   double tp_amount = take_profit*decimalConv*Point;
   if(currentProfit < 0 && MathAbs(currentProfit) >  sl_amount){

      //Print("SL Close:" , currentProfit, " sl:", DoubleToStr(sl_amount, 5), " initial_sl:", initial_sl);
      close_time = TimeCurrent();
   
   }else if( currentProfit > take_profit *decimalConv*Point ){
      //Print("TP Close:" , currentProfit, " tp:", DoubleToStr(tp_amount, 5) , " tp:", take_profit);
      close_time = TimeCurrent();
      profit_loss = 1;
   }   
   bool order_closed = false;
   if(_trades[trade_index(sig)][C_TICKET] != "0" && OrderSelect(StrToInteger(_trades[trade_index(sig)][C_TICKET]),SELECT_BY_TICKET)
      && OrderCloseTime() > 0){   
     //Print("aaa ", OrderSelect(StrToInteger(_trades[trade_index(sig)][C_TICKET]),SELECT_BY_TICKET), " ", OrderCloseTime(), "   ", _trades[trade_index(sig)][C_TICKET]);
      close_time = OrderCloseTime();
      order_closed = true;
   }
   if(_trades[trade_index(sig)][C_TICKET] != "0"){   
      double swap = OrderSwap();
      price = OrderClosePrice();
      profit = OrderProfit();
      if(profit > 0){
         profit_loss =1;
      }
   }else{
      profit = MathAbs(StrToDouble(_trades[trade_index(sig)][C_OPRICE]) - price) /(MarketInfo(Symbol(),MODE_POINT) *decimalConv);      
      profit = profit * profit_loss;

   }

   if(close_time > 0){
      if(_trades[trade_index(sig)][C_TICKET] != "0" && !order_closed){
         Exit(OrderTicket(), OrderLots(), Blue);
      }
      _trades[trade_index(sig)][0] = 0;
      _trades[trade_index(sig)][1] = 0;
      _trades[trade_index(sig)][2] = "";
      _trades[trade_index(sig)][3] = "";
      _trades[trade_index(sig)][4] = "";
      _trades[trade_index(sig)][5] = "";
      return(false);  

   }
      

   return(true);             
   
}



bool handle_trade_step_profits(string sig){
   bool live_trade = false;
   double price = 0;
   double open_price;
   string trade_info[10];   

   if(StrToInteger(_trades[trade_index(sig)][0]) <= 0 && StrToInteger(_trades[trade_index(sig)][1]) <= 0){
      return(false);
   }

   int close_time = 0;
   RefreshRates();
   if(StrToInteger(_trades[trade_index(sig)][8]) == OP_BUY){
      price = Ask;
   }else{
      price = Bid;
   }
   string query ="";
   double profit =0;

   int profit_loss = -1;
   double profitPips, increments, sl_init;
   double distToStop;
   double diff;
   double currentProfit, currSL;
   double init_step = (initial_trail_step + initial_trail_step_buffer)*decimalConv*Point;   
   double sl_trail;

   double trail = NormalizeDouble(Point * trail_amount * decimalConv, Digits);
   if( StrToInteger(_trades[trade_index(sig)][C_CMD]) == OP_SELL){
      currentProfit = StrToDouble(_trades[trade_index(sig)][C_OPRICE]) - Ask;
      currSL =  StrToDouble(_trades[trade_index(sig)][C_SL]) - StrToDouble(_trades[trade_index(sig)][C_OPRICE]);            
      sl_init = NormalizeDouble(StrToDouble(_trades[trade_index(sig)][C_OPRICE]) -  (initial_trail_step*decimalConv*Point), Digits);
      distToStop = StrToDouble(_trades[trade_index(sig)][C_SL]) - Ask;
      sl_trail = NormalizeDouble(Ask + trail, Digits);

   }else{
      currentProfit = Bid - StrToDouble(_trades[trade_index(sig)][C_OPRICE]);
      currSL = StrToDouble(_trades[trade_index(sig)][C_OPRICE]) - StrToDouble(_trades[trade_index(sig)][C_SL]);
      sl_init = NormalizeDouble(StrToDouble(_trades[trade_index(sig)][C_OPRICE]) +  (initial_trail_step*decimalConv*Point), Digits);
      distToStop = Bid - StrToDouble(_trades[trade_index(sig)][C_SL]);
      sl_trail = NormalizeDouble(Bid - trail, Digits);            
   }
   diff = distToStop - trail;
   double sl_amount = initial_sl*decimalConv*Point;
   double tp_amount = take_profit*decimalConv*Point;
   if(currentProfit < 0 && MathAbs(currentProfit) >  sl_amount){

      //Print("SL Close:" , currentProfit, " sl:", DoubleToStr(sl_amount, 5), " initial_sl:", initial_sl);
      close_time = TimeCurrent();
   
   }else if( currentProfit > take_profit *decimalConv*Point ){
      //Print("TP Close:" , currentProfit, " tp:", DoubleToStr(tp_amount, 5) , " tp:", take_profit);
      close_time = TimeCurrent();
      profit_loss = 1;
   }   
   bool order_closed = false;
   if(_trades[trade_index(sig)][C_TICKET] != "0" && OrderSelect(StrToInteger(_trades[trade_index(sig)][C_TICKET]),SELECT_BY_TICKET)
      && OrderCloseTime() > 0){   
     //Print("aaa ", OrderSelect(StrToInteger(_trades[trade_index(sig)][C_TICKET]),SELECT_BY_TICKET), " ", OrderCloseTime(), "   ", _trades[trade_index(sig)][C_TICKET]);
      close_time = OrderCloseTime();
      order_closed = true;
   }
   if(_trades[trade_index(sig)][C_TICKET] != "0"){   
      double swap = OrderSwap();
      price = OrderClosePrice();
      profit = OrderProfit();
      if(profit > 0){
         profit_loss =1;
      }
   }else{
      profit = MathAbs(StrToDouble(_trades[trade_index(sig)][C_OPRICE]) - price) /(MarketInfo(Symbol(),MODE_POINT) *decimalConv);      
      profit = profit * profit_loss;

   }

   if(close_time > 0){
      if(_trades[trade_index(sig)][C_TICKET] != "0" && !order_closed){
         Exit(OrderTicket(), OrderLots(), Blue);
      }
      _trades[trade_index(sig)][0] = 0;
      _trades[trade_index(sig)][1] = 0;
      _trades[trade_index(sig)][2] = "";
      _trades[trade_index(sig)][3] = "";
      _trades[trade_index(sig)][4] = "";
      _trades[trade_index(sig)][5] = "";
      return(false);  

   }
      

   return(true);             
   
}
void init_open_trades(string sig){
   int total_orders = OrdersTotal();
   for(int i=1; i < 20 && i < total_orders; i++){
      OrderSelect(total_orders-i, SELECT_BY_POS, MODE_TRADES);
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number){
         int row_id = -1;
         int dir;
         if(OrderType() == OP_BUY){
            dir = LONG;
         }else{
            dir = SHORT;
         }
         _trades[trade_index(sig)][0] = OrderTicket();
         _trades[trade_index(sig)][1] = row_id;
         _trades[trade_index(sig)][2] = sig;
         _trades[trade_index(sig)][3] = dir;
         _trades[trade_index(sig)][4] = OrderOpenPrice();
         _trades[trade_index(sig)][5] = OrderOpenTime();
         _trades[trade_index(sig)][6] = OrderTakeProfit();
         _trades[trade_index(sig)][7] = OrderStopLoss();
         _trades[trade_index(sig)][8] = OrderType();
         _trades[trade_index(sig)][9] = OrderLots();
       }
   }

}
/***********EA HELPERs ************************/

/***********STAIR STEP HELPERS ************************/

bool VHandsEnabled = true;
bool   ShowTPLevels     = false; // false will hide the TP levels
bool   ShowTPLevelsOnLastBoxOnly = false; // to limit the TP levels to the last Box only
double TP1              = 0.618;
double TP2              = 1.382;
double TP3              = 2.618;
double TP4              = 4.236;
double TP5              = 5.854;
double TP6              = 7.472;
double TP7              = 9.090;
double TP8              = 11.708;
double TP9              = 14.326;
color  TPLevelColor     = Gray;
double TP_is_pips_above = 20; // any TP input above this value is considered as a FIXED PIP value, below is a FACTOR of the box size (including bufferpips);


int last_bar = 0;
int bar_index=0;
int curr_box;
int curr_trade_count=0;
// VHandsEnabled, BoxLength, BoxTimeFrame, BoxRange, AutoBoxRange, AutoBoxRangeDailyATRperiod, AutoBoxRangeDailyATRfactor, BoxBufferPips, DaysBack, MinBarsClosedOutsideBO, MaxBreakoutTradesPerBox, ShowTPLevels, ShowTPLevelsOnLastBoxOnly, TP1, TP2, TP3, TP4, TP5, TP6, TP7, TP8, TP9, TPLevelColor, TP_is_pips_above, SignalAlert, CreateStatisticsFile, BuySignalArrowCode, BuySignalArrowColor, BuySignalArrowWidth, SellSignalArrowCode, SellSignalArrowColor, SellSignalArrowWidth, BreakoutBoxFontSize, BreakoutBoxColor, BreakoutBoxContColor, BreakoutBoxContFullColored, BreakoutPriceColor, BreakoutPriceWidth, ShowDisplayPanel, StatsColor, StatsBGColor, StatsCorner, BoxVerticalLineDelimiter, BoxVerticalLineColor, SwingLabelsFontSize, SwingLabelsColor, Fonts, debug, 
int start()
{
   debug = false;
   BUY=false;
   SELL=false;
   
   //signal_trade_mode = 0;//real_trade_mode;
   //max_drawdown_percent = 50;
   system_max_lots=100;
   if(all_sigs == false){
      _sigs_data[0] = "ssoS1;1,;";
      _sigs_data[1] = "ssoB1;1,;";
      signal_trade_mode = 1;
      _sig_tag = "sso";
      _account_id = AccountNumber();

      init_signals();
      all_sigs = true;
      init_open_trades("ssoS1");
      init_open_trades("ssoB1");
   } 

   string buy_sig= StringConcatenate("ssoB", 1);
   string sell_sig = StringConcatenate("ssoS", 1);
   //Print(handle_current_trade(buy_sig), " handle2:", handle_current_trade(sell_sig));
   if(handle_trade_step_profits(buy_sig) || handle_trade_step_profits(sell_sig)){
      return;
   }

   if(last_bar >= iTime(Symbol(), Period(), bar_index)){
      return(false);
   }
   if(trade_curr_box()){
      if(sso_buy()){
         signal_id = buy_sig;
         comment = buy_sig;  
         BUY=true;
         handle_trade_sig();
         curr_trade_count++;
      }else if(sso_sell()){
         signal_id = sell_sig;
         comment = sell_sig;  
         SELL=true;
         handle_trade_sig();
         curr_trade_count++;
      
      }
   }
   last_bar = iTime(Symbol(), 0, bar_index);
}
bool trade_curr_box(){
   int total_orders = OrdersHistoryTotal();
   int total_orders_for_box = 0;
   int last_order_profit = 0;
   int box_starting_buffer = 7;
   int curr_box_starting_time = iCustom(NULL, 0, "sqDynamicBreakoutBox",
            VHandsEnabled, BoxLength, BoxTimeFrame, BoxRange, AutoBoxRange, AutoBoxRangeDailyATRperiod, AutoBoxRangeDailyATRfactor, 
            BoxBufferPips, DaysBack, MinBarsClosedOutsideBO, MaxBreakoutTradesPerBox, ShowTPLevels, ShowTPLevelsOnLastBoxOnly, 
            TP1, TP2, TP3, TP4, TP5, TP6, TP7, TP8, TP9, TPLevelColor, TP_is_pips_above, SL, 
            box_starting_buffer
             ,bar_index);
   curr_box = curr_box_starting_time;

   for(int i=1; i < 20 && i < total_orders; i++){
      OrderSelect(total_orders-i, SELECT_BY_POS, MODE_HISTORY);
/*
      if(curr_box != EMPTY_VALUE || true){
         Print("bbbb curr_box=", curr_box, " OrderId=", OrderTicket(), " Profit=", OrderProfit(), 
            " OrderOpenTime=", OrderOpenTime(),
            OrderSymbol(), ":", Symbol(), " ", OrderMagicNumber(), ":", magic_number);
      }
*/
      if(OrderOpenTime() > curr_box) {
         if( OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number){
            total_orders_for_box += 1;
            //Print("mmmmmmm curr_box=", curr_box, " OrderId=", OrderTicket(), " Profit=", OrderProfit());
            if(OrderProfit() > 0){
               last_order_profit+=1; 
            }
         }
//         Print("ccccc curr_box=", curr_box, " OrderId=", OrderTicket(), " Profit=", OrderProfit(), " OrderOpenTime=", OrderOpenTime(), " total_orders_for_box=" , total_orders_for_box);

      }else{
         break;
      }
   }
   if(total_orders_for_box >= MaxBreakoutTradesPerBox){
      return(false);
   }
   
   if(last_order_profit >=MaxProfitTradesPerBox){
      return(false);
   }
   
   return(true);
}
bool sso_sell(){
   int bars_closed=0;  
   int buy_singal_buffer = 4;
   int sell_singal_buffer = 5;
   int sig_count_col = 7;   
 
   double sell_signal = iCustom(NULL, 0, "sqDynamicBreakoutBox",
            VHandsEnabled, BoxLength, BoxTimeFrame, BoxRange, AutoBoxRange, AutoBoxRangeDailyATRperiod, AutoBoxRangeDailyATRfactor, 
            BoxBufferPips, DaysBack, MinBarsClosedOutsideBO, MaxBreakoutTradesPerBox, ShowTPLevels, ShowTPLevelsOnLastBoxOnly, 
            TP1, TP2, TP3, TP4, TP5, TP6, TP7, TP8, TP9, TPLevelColor, TP_is_pips_above, SL, 
             sell_singal_buffer
             ,bar_index);
   if(sell_signal != EMPTY_VALUE){
      Print( " sell_signal:", sell_signal);
      return(true);
   }  
   return(false);

}  

bool sso_buy(){   
   int bars_closed=0;  
   int buy_singal_buffer = 4;
   int sell_singal_buffer = 5;
   int sig_count_col = 7;   
   double buy_signal = iCustom(NULL, 0, "sqDynamicBreakoutBox",
            VHandsEnabled, BoxLength, BoxTimeFrame, BoxRange, AutoBoxRange, AutoBoxRangeDailyATRperiod, AutoBoxRangeDailyATRfactor, 
            BoxBufferPips, DaysBack, MinBarsClosedOutsideBO, MaxBreakoutTradesPerBox, ShowTPLevels, ShowTPLevelsOnLastBoxOnly, 
            TP1, TP2, TP3, TP4, TP5, TP6, TP7, TP8, TP9, TPLevelColor, TP_is_pips_above, SL, 
             buy_singal_buffer
             ,bar_index);

      
   if(buy_signal != EMPTY_VALUE){
      Print("buy_signal:" , buy_signal);
      return(true);
   }  

   return(false);
 
}  

/***********STAIR STEP HELPERS ************************/

