// Scalping bot with Martingale strategy

// Directives
#property copyright "Scalper bot"
#property link      ""
#define buy -2
#define sell 2

extern string     General_Settings = "Configure General settings below";
extern int        magic = 12345;
extern double     range = 0;
extern string     Level_per_Lot = "Size of each level";
extern double     level_1 = 1.00;
extern double     level_2 = 2.00;
extern double     level_3 = 4.00;


extern string     Order_Settings = "Configure Order settings below";
extern double     tp_in_money_1 = 3.00;
extern double     tp_in_money_2 = 4.00;
extern double     tp_in_money_3 = 8.00;

extern string     BB_Settings = "Configure Bollinger Band settings below";
extern bool       use_bb = true;
extern int        bb_period = 20;
extern int        bb_deviation = 2;
extern int        bb_shift = 0;
extern string     Stoch_Settings = "Configure Stochastic settings below";
extern bool       use_stoch = true;
extern int        k = 5;
extern int        d = 3;
extern int        slowing = 3;
extern int        price_field = 0;
extern int        stoch_shift = 0;
extern int        lo_level = 30;
extern int        up_level = 70;
extern string     RSI_Settings="Configure RSI settings below";
extern bool       use_rsi = true;
extern int        rsi_period = 12;
extern int        rsi_shift = 0;
extern int        lower = 30;
extern int        upper = 70;

// Setup other variables
bool bot_inhibit = false;
int current_level = 0;
double current_loss;
int current_order_type;
double pt;
double minlot;
double stoplevel;
int precision=0;
int ticket=0;
double curr_trades_monetary;
//For the comment information
string comment_info;
string spread_comment;
string level_string;
string current_orders_string;
string point_comment;
string curr_order_comment;
string curr_loss_comment;
string range_calc_string;
string curr_trades_monetary_string;

/*------------------------------------------------------------------
 Bot initialization function                                  
------------------------------------------------------------------*/
int init()
  {
     // Print out some information on the market
     minlot = MarketInfo(Symbol(),MODE_MINLOT);
     stoplevel = MarketInfo(Symbol(),MODE_STOPLEVEL);
     Print("Digits for market = ", Digits);
     Print("Stoplevel for market = ", stoplevel);

     //Check the values
     if(level_1 < minlot){
      Print("Starting lot is too small.");
     }
     
     // Setup the precision for normalisation
     if(minlot == 0.01){
      precision = 2;
     }
     if(minlot == 0.1){
      precision = 1;
     }
      
     return(0);
  }

/*-----------------------------------------------------------------
  Bot deinitialization function                                
-----------------------------------------------------------------*/
int deinit()
  {
   return(0);
  }

/*----------------------------------------------------------------
  Bot tick function
----------------------------------------------------------------*/
int start()
  {
    if(bot_inhibit == false){
     // Temp stop the bot whilst it does its thing
     //bot_inhibit = true;

     /***********************************************************************************************************************************
      Find out how many orders are open for the current chart/bot, and also get the details of the last one, which should be the highest.
     ************************************************************************************************************************************/
     int type, no_orders;
     double curr_lot_size, op;
     int num_of_orders = 0;
     for(int i = 0; i < OrdersTotal(); i++)
     {
         if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == true){
            //Make sure they're for this symbol and bot
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic){
               // Grab the order details, should be left with the last.
               curr_lot_size = OrderLots();
               current_order_type = OrderType();
               op = OrderOpenPrice();
               // Increment the number of orders.
               num_of_orders++;
            }
         }
     }
    
     /*************************************************************************************************
      Work out our current level based on order quantity and lot size from above.
     **************************************************************************************************/
     if(OrdersTotal() == 0){
        current_level = 0;
     }

     /*************************************************************************************************
      Get the current P/L
     **************************************************************************************************/
     curr_trades_monetary = current_money();

     /*************************************************************************************************
      Get all the data for the graph display and join it together
     **************************************************************************************************/
     // Work out the current spread
     double spreadPips;
     if ((Digits == 4) || (Digits == 2)){
      spreadPips=NormalizeDouble((Ask-Bid)/Point,0);
      }
     if ((Digits == 5) || (Digits == 3)){
      spreadPips=NormalizeDouble((Ask-Bid)/Point,0);
      spreadPips/=10;
     }
     // Let's try and display our current out of range.  
     double out_of_range = 0;
     if(op>0){
        out_of_range = range_calc(current_order_type, op);
     }
     // Join all comments up and display for tick by tick info
     curr_trades_monetary_string = StringConcatenate("Current Monetary of open trades: ",curr_trades_monetary,"\n");
     curr_order_comment = StringConcatenate("Current Lot Size: ",curr_lot_size,"\n");
     spread_comment = StringConcatenate("Spread: ",spreadPips,"\n");
     point_comment = StringConcatenate("Point: ", Point,"\n");
     current_orders_string = StringConcatenate("Current Orders: ",num_of_orders,"\n");
     level_string = StringConcatenate("Current level: ",current_level,"\n");
     range_calc_string = StringConcatenate("Range Calc: ",out_of_range,"\n");
     comment_info = StringConcatenate(spread_comment, point_comment, current_orders_string, level_string, curr_order_comment,curr_trades_monetary_string, range_calc_string);
     Comment(comment_info);
     
     /*************************************************************************************************
      We should now know what level we're on, and take the appropriate action
     **************************************************************************************************/
     if(current_level == 0){
      // Execute code depending on level
      // We're on level 0, no open orders, so do the first one if signals are there.
        if(signal() == buy){
          //OrderSend(symbol,cmd,volume,price,slippage,stoploss,takeprofit,comment=NULL,magic,expiration=0,arrow_color)
          ticket=OrderSend(Symbol(),0,NormalizeDouble(level_1,2),Ask,3,0,0,"Level 1",magic,0,Blue);
          // Put us up to level 1
          current_level = 1;
        }
        if(signal() == sell){
          ticket=OrderSend(Symbol(),1,NormalizeDouble(level_1,2),Bid,3,0,0,"Level 1",magic,0,Red);
          // Put us up to level 1
          current_level = 1;
        }
        
      }
      
     /*************************************************************************************************
      Now are we on level 1?
     **************************************************************************************************/
     if(current_level == 1){
        // What's our range for this level?
        range = 6;
        // Ok so we're level 1, having done the first trade. First we need to check if we should take the money.
        if(curr_trades_monetary >= tp_in_money_1){
          closeall();
          closeall();
          closeall();
          current_level = 0;
        }
        // So we haven't made the money yet. Are we out of range? If yes, do the below
        else if(range_check(current_order_type, range, op) == true){
          //Close the order and open a new one
          closeall();
          closeall();
          closeall();
          if(signal() == buy){
          //OrderSend(symbol,cmd,volume,price,slippage,stoploss,takeprofit,comment=NULL,magic,expiration=0,arrow_color)
            ticket=OrderSend(Symbol(),0,level_2,Ask,3,0,0,"Level 2",magic,0,Blue);
            current_level = 2;
          }
          else if(signal() == sell){
            ticket=OrderSend(Symbol(),1,level_2,Bid,3,0,0,"Level 2",magic,0,Red);
            current_level = 2;
          }
          else{
            if(current_order_type == 0){
               ticket=OrderSend(Symbol(),current_order_type,level_2,Ask,3,0,0,"Level 2",magic,0,Red);
            }
            if(current_order_type == 1){
               ticket=OrderSend(Symbol(),current_order_type,level_2,Bid,3,0,0,"Level 2",magic,0,Red);
            }
            current_level = 2; // Go to level 2 for next tick
          }
        }
        else{
         //Do nothing because we haven't hit the take profit or max loss for this level
        }
     }
     
     
     /*************************************************************************************************
      Now are we on level 2?
     **************************************************************************************************/
     else if(current_level == 2){
        // What's our range for this level?
        range = 4;
        // Ok so we're level 2, having done the level 1 trade. First we need to check if we should take the money.
        if(curr_trades_monetary >= tp_in_money_2){
          closeall();
          current_level = 0;
        }
        // So we haven't made the money yet. Are we out of range? If yes, do the below
        else if(range_check(current_order_type, range, op) == true){
          //Close the order and open a new one
          closeall();
          closeall();
          closeall();
          if(signal() == buy){
          //OrderSend(symbol,cmd,volume,price,slippage,stoploss,takeprofit,comment=NULL,magic,expiration=0,arrow_color)
            ticket=OrderSend(Symbol(),0,level_3,Ask,3,0,0,"Level 3",magic,0,Blue);
            current_level = 3;
          }
          else if(signal() == sell){
            ticket=OrderSend(Symbol(),1,level_3,Bid,3,0,0,"Level 3",magic,0,Red);
            current_level = 3;
          }
          else{
            if(current_order_type == 0){
               ticket=OrderSend(Symbol(),current_order_type,level_2,Ask,3,0,0,"Level 3",magic,0,Red);
            }
            if(current_order_type == 1){
               ticket=OrderSend(Symbol(),current_order_type,level_2,Bid,3,0,0,"Level 3",magic,0,Red);
            }
            current_level = 3; // Go to level 3 for next tick
          }
        }
        else{
         //Do nothing because we haven't hit the take profit or max loss for this level
        }     
     }
          
     /*************************************************************************************************
      Now are we on level 3?
     **************************************************************************************************/
     else if(current_level == 3){
        // What's our range for this level?
        range = 3;
        // Ok so we're level 3, having done the level 2 trade. First we need to check if we should take the money.
        if(curr_trades_monetary >= tp_in_money_3){
          closeall();
          closeall();
          closeall();
          closeall();
          current_level = 0;
        }
        // So we haven't made the money yet. Are we out of range? If yes, do the below
        else if(range_check(current_order_type, range, op) == true){
          // We've hit our maximum loss on level 3 so close all.
          closeall();
          closeall();
          closeall();
        }
        else{
         //Do nothing because we haven't hit the take profit or max loss for this level
        }     
     }
     
        
    }//end of inhibit
     
    //re-enable bot
    bot_inhibit = false;
  }//end of tick function

/*--------------------------------------------------------------------------------------------------
 FUNCTION
 Check if we're out of the range in pips, return TRUE if our range has been exceeded on current bet
---------------------------------------------------------------------------------------------------*/
bool range_check(int current_order_type, double range, double opening_price){
  if(current_order_type == 0){
    // It's a buy order we're looking at, so check against the Bid.
    if(Bid<=opening_price-range){
      return(true);
    }
    else{
      return(false);
    }
  }
  if(current_order_type == 1){
    // It's a sell order, so check against the Ask
    if(Ask>=opening_price+range){
      return(true);
    }
    else{
      return(false);
    }
  }
}

/*--------------------------------------------------------------------
 FUNCTION
 Work out our current out of range
--------------------------------------------------------------------*/
double range_calc(int current_order_type, double opening_price){
  double temp_1;
  if(current_order_type == 0){     
     temp_1 = Bid-opening_price;
  }
  if(current_order_type == 1){
     
     temp_1 = Ask+opening_price;
  }
  return(temp_1);
}

/*--------------------------------------------------------------------
 FUNCTION
 Show the profit/loss total of current trades on this bot/chart
--------------------------------------------------------------------*/
double current_money()
{
  int i;
  double profit=0;
  // Get total profit from all open orders that this bot has made.
  for(i=0; i<OrdersTotal(); i++)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
    if(OrderSymbol()==Symbol() && OrderMagicNumber() == magic){
     profit = profit + OrderProfit();
    }
  }
  return(profit);

}

/*--------------------------------------------------------------------
 FUNCTION
 Generate signals from the data for trading.
--------------------------------------------------------------------*/
int signal()
{
  double upBB=iBands(Symbol(),0,bb_period,bb_deviation,0,PRICE_CLOSE,MODE_UPPER,bb_shift);
  double loBB=iBands(Symbol(),0,bb_period,bb_deviation,0,PRICE_CLOSE,MODE_LOWER,bb_shift);
  double stoch=iStochastic(Symbol(),0,k,d,slowing,MODE_SMA,price_field,MODE_SIGNAL,stoch_shift);
  double rsi=iRSI(Symbol(),0,rsi_period,PRICE_CLOSE,rsi_shift);
  if(use_bb && use_stoch && use_rsi)
  {
     if(High[bb_shift]>upBB && stoch>up_level && rsi>upper) return(sell);
     if(Low[bb_shift]<loBB && stoch<lo_level && rsi<lower) return(buy);
  }
  if(use_bb && use_stoch && !use_rsi)
  {
     if(High[bb_shift]>upBB && stoch>up_level) return(sell);
     if(Low[bb_shift]<loBB && stoch<lo_level) return(buy);
  }
  if(use_bb && !use_stoch && !use_rsi)
  {
     if(High[bb_shift]>upBB) return(sell);
     if(Low[bb_shift]<loBB) return(buy);
  }
  if(!use_bb && use_stoch && use_rsi)
  {
     if(stoch>up_level && rsi>upper) return(sell);
     if(stoch<lo_level && rsi<lower) return(buy);
  }
  if(!use_bb && use_stoch && !use_rsi)
  {
     if(stoch>up_level) return(sell);
     if(stoch<lo_level) return(buy);
  }
  if(use_bb && !use_stoch && use_rsi)
  {
     if(High[bb_shift]>upBB && rsi>upper) return(sell);
     if(Low[bb_shift]<loBB && rsi<lower) return(buy);
  }
  if(!use_bb && !use_stoch && use_rsi)
  {
     if(rsi>upper) return(sell);
     if(rsi<lower) return(buy);
  }
  return(0);
}

/*--------------------------------------------------------------------
 FUNCTION
 Close all trades instantly.
--------------------------------------------------------------------*/
void closeall()
{
   bot_inhibit = true;
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if(OrderSymbol()!=Symbol() || OrderMagicNumber()!=magic){
        continue;
      }

      if(OrderType()>1){
        OrderDelete(OrderTicket());
      }
      else
      {
        if(OrderType()==0){
         OrderClose(OrderTicket(),OrderLots(),Bid,3,CLR_NONE);
        }
        else{
         OrderClose(OrderTicket(),OrderLots(),Ask,3,CLR_NONE);
        }
      
      }
   } 
  bot_inhibit = false;
}