//+------------------------------------------------------------------+
//|                                                  FibOrdersEA.mq4 |
//|                                                            GM-LV |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "GM-LV"
#property link      ""
#property version   "1.00"
//#property strict

#define  WARNING 1
#define  ERROR 2
#define  INFO 3

#define  M_LOTS 1
#define  M_SL 2
#define  M_TP 3
#define  M_SL_TP 4

#define  ADD 1
#define  FIND 2
#define  CHANGE 3

string s = Symbol();
#define  SYMBOL s

//+------------------------------------------------------------------+
//| START SETTINGS                                                   |
//+------------------------------------------------------------------+
extern bool   AccBalance         = false;//Use account balance YES(true); NO(false).
extern bool   AccEquity          = false;//Use account equity YES(true); NO(false).    
extern double StartBalance       = 100;  //Used if AccBalance and AccEquity both are false.

extern double PercentToRisk      = 5;    //Ex: 2; 1.5; 0.5; 5 ... etc.
extern double RiskRewardRatio    = 3;    //Ex: 2; 1.5; 0.5; 5 ... etc.

extern double PipDistForOrder    = 0.1;  //Ex: 2; 1.5; 0.5; 5 ... etc. Hard pip set will be added to open price.  
extern double PipDistForStop     = 0.1;  //Ex: 2; 1.5; 0.5; 5 ... etc. Hard pip set will be added to stop price. 
extern double PipDistForProfit   = 0;    //Ex: 2; 1.5; 0.5; 5 ... etc. Hard pip set will be added to profit price.

extern bool   BreakEvenAtR_R     = false; //Break even action at set R/R level YES(true); NO(false).
extern double LockInAtR_R        = 1;    //R/R at which break even is triggered. Ex: 2; 1.5; 0.5; 5 ... etc.
extern double LockInPips         = 0.2;  //Pip and points to lock in at break even.
extern bool   PartCloseAtBE      = true; //Position part close action at break even level YES(true); NO(false).
extern double PartClosePercent   = 50;   //Position percentage to close at part close action. Ex: 25; 50; 46; 75 ... etc.

extern bool   ModifyNullSL       = true;  //if stop loss is null modify it accordingly to EA settings YES(true); NO(false).
extern double MinSLDistance      = 5.0;
extern bool   ModifyNullTP       = true;  //if take profit is null modify it accordingly to EA settings YES(true); NO(false).
extern bool   ManageOnlyEATrades = false; //if "true" EA will manage only trades placed by this EA

extern double FibLevelToUse_1    = 0.5;  //Fib. level for order Ex: 0.236; 0.382; 0.5; 0.618; 0.764; 1.0 etc.
extern double FibLevelToUse_2    = 0;    //Fib. level for stop Ex: 0.236; 0.382; 0.5; 0.618; 0.764; 1.0 etc.
extern string FibName            = "FibOrders";
extern color  FibColor           = clrBlack;
//double FibLevels[9] = {0.236, 0.382, 0.5, 0.618, 0.764, 1.0, 1.618, 2.618, 4.236}; //Default levels
double FibLevels[7] = {0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0}; //By 50%
//double FibLevels[7] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; //By 100%

extern bool   ShowInfo           = true;
extern color  InfoColor          = clrBlack;

extern bool   SoundOn            = true;

extern int    MagicNr            = 2468;

//+------------------------------------------------------------------+
//| END SETTINGS                                                     |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Math functions                                                   |
//+------------------------------------------------------------------+
double RoundDown(double doubleValue, double mold){   
   return mold * MathFloor(doubleValue / mold); 
}//RoundDown()

double RoundUp(double doubleValue, double mold){   
   return mold * MathCeil(doubleValue / mold); 
}//RoundUp()

double RoundToNearest(double doubleValue, double mold){   
   return mold * MathRound(doubleValue / mold); 
}//RoundToNearest()
//+------------------------------------------------------------------+
//| Expert info functions                                            |
//+------------------------------------------------------------------+
void InfoLabel(string name, int x, string text){
   ObjectCreate(0,name, OBJ_LABEL,0,0,0);
   ObjectSet     (name, OBJPROP_CORNER, 0);
   ObjectSet     (name, OBJPROP_XDISTANCE, x);
   ObjectSet     (name, OBJPROP_YDISTANCE, 5);
   ObjectSet     (name, OBJPROP_HIDDEN, true);
   ObjectSet     (name, OBJPROP_READONLY, true);
   ObjectSet     (name, OBJPROP_SELECTABLE, false);   
   ObjectSetText (name, text, 9, "Segoe UI Semibold", InfoColor);  
}//InfoLabel()

void InfoBox(){
   InfoLabel("Spread", 300, ("||  Spread: " + DoubleToStr(Spread(), Digits)));
   InfoLabel("Clock", 405, ("||  Next Bar in " + CandleTime()));
   ProfitOfOpenTrades();
}//InfoBox()

void ProfitOfOpenTrades(){
   double profit = 0;
   string info = "";
   
   for(int i = 1; i <= OrdersTotal(); i++){
      if(!OrderSelect(i - 1, SELECT_BY_POS))  continue;
      if(OrderSymbol()!= SYMBOL)              continue; 
      if(OrderType() == OP_BUY || OrderType() == OP_SELL){
         profit += (OrderProfit() + OrderCommission()); 
         info = StringFormat("Profit: %.2f", profit);
      }     
   }
    
   if(ShowInfo && info != "") 
      InfoLabel("Profit", 515, ("||  Running profit of  \"" + SYMBOL + "\": " + info)); 
   else ObjectDelete("Profit");
}//ProfitOfOpenTrades()

string CandleTime(){
   string minNull = "";
   string secNull = "";
   int    min = Time[0] + Period() * 60 - TimeCurrent();
   int    sec = min % 60;
   
   min = (min - sec) / 60;
   if (min < 10) minNull = "0";
   if (sec < 10) secNull = "0";
   
   return(minNull + DoubleToStr(min, 0) + ":" +  secNull + DoubleToStr(sec, 0));
}//CandleTime()

double PointValueCalculator(double lots = 0){
   double tickValue = MarketInfo(SYMBOL, MODE_TICKVALUE);
   double tickSize  = MarketInfo(SYMBOL, MODE_TICKSIZE);
   double point     = MarketInfo(SYMBOL, MODE_POINT);
   double stepSize = (lots == 0) ?  MarketInfo(SYMBOL, MODE_LOTSTEP) : lots;

   return((((tickValue * point * PFact()) / tickSize) * stepSize) / PFact());
}//PointValueCalculator()
//+------------------------------------------------------------------+
//| Expert message functions                                         |
//+------------------------------------------------------------------+
string LastMsg = "There isn't any messages.";
int LastMsgType = INFO;

void MsgBox(string msg, color clr){
   int y = (ShowInfo) ? 20 : 5;
   
   ObjectCreate ("MsgBox", OBJ_LABEL, 0, 0, 0);
   ObjectSet    ("MsgBox", OBJPROP_CORNER, 0);
   ObjectSet    ("MsgBox", OBJPROP_XDISTANCE, 300);
   ObjectSet    ("MsgBox", OBJPROP_YDISTANCE, y);
   ObjectSet    ("MsgBox", OBJPROP_HIDDEN, true);
   ObjectSet    ("MsgBox", OBJPROP_READONLY, true);
   ObjectSet    ("MsgBox", OBJPROP_SELECTABLE, false);
   ObjectSetText("MsgBox", "||  " + msg, 9, "Segoe UI Semibold", clr);
   
   ObjectSetString(0, "Message", OBJPROP_TEXT, "HideMsg");
}//MsgBox

void Message(string msg, int msgType){
   LastMsg = "";
   switch(msgType){
      case INFO    :
         MsgBox(msg, clrDarkGreen);
         break;
      case WARNING :
         msg = StringConcatenate("WARNING: ", msg);
         MsgBox(msg, clrOrangeRed);
         break;
      case ERROR   :
         msg = StringConcatenate("ERROR: ", msg);
         MsgBox(msg, clrRed);
   }
   LastMsg = msg;
   LastMsgType = msgType;
}//Message()
//+------------------------------------------------------------------+
//| Fibonacci Retracement                                            |
//+------------------------------------------------------------------+
void FibCreate(){
   double   maxPrice = ChartGetDouble(0, CHART_PRICE_MAX);
   double   minPrice = ChartGetDouble(0, CHART_PRICE_MIN);
   datetime y_1 = iTime(0, 0, 0);
   datetime y_2 = iTime(0, 0, 20); 
   double   x_1 = maxPrice - ((maxPrice - minPrice) / 3);
   double   x_2 = minPrice + ((maxPrice - minPrice) / 3);
   string   label; 

   ObjectCreate    (0, FibName, OBJ_FIBO, 0, y_1, x_1, y_2, x_2);
   ObjectSetInteger(0, FibName, OBJPROP_SELECTABLE, true);
   ObjectSetInteger(0, FibName, OBJPROP_SELECTED, true);
   ObjectSetInteger(0, FibName, OBJPROP_HIDDEN, false);
   ObjectSetInteger(0, FibName, OBJPROP_ZORDER, 0);
   ObjectSetInteger(0, FibName, OBJPROP_LEVELS, 9);

   for(int i = 0; i < ArraySize(FibLevels); i++){
      label = "";
      if(FibLevels[i] == FibLevelToUse_1) label = "ACTIV  ";
      if(FibLevels[i] == FibLevelToUse_2) label = "ACTIV  ";
      ObjectSetDouble (0, FibName, OBJPROP_LEVELVALUE, i, FibLevels[i]);
      ObjectSetInteger(0, FibName, OBJPROP_LEVELCOLOR, i, FibColor);
      ObjectSetString (0, FibName, OBJPROP_LEVELTEXT, i, label + "(" + DoubleToString(100 * FibLevels[i], 1) + ")" + " - %$");
   }
}//FibCreate()

double GetFibLevel(double level){
   double fib_100 = ObjectGet(FibName, OBJPROP_PRICE1); //Fib 100.0% level
   double fib_0   = ObjectGet(FibName, OBJPROP_PRICE2); //Fib 0.0% level
   double fibDist = MathAbs(fib_100 - fib_0); 
   level = (fib_100 > fib_0) ? fib_0 + (fibDist * level) : fib_0 - (fibDist * level);
   return(NormalizePrice(level));
}//GetFibLevel()
//+------------------------------------------------------------------+
//| Buttons                                                          |
//+------------------------------------------------------------------+
void CreateButton(string name, string text, int x, int y, int width = 60, int height = 20){
   ObjectCreate    (0, name, OBJ_BUTTON, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
   ObjectSetInteger(0, name, OBJPROP_YSIZE, height);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 8);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clrBlack);
   ObjectSetInteger(0, name, OBJPROP_BACK, false);
   ObjectSetString (0, name, OBJPROP_TEXT, text);
}//CreateButton()

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam){
   if(id == CHARTEVENT_OBJECT_CLICK){
      if(sparam == "BtnControl"){BtnAction(sparam); BtnControlFunction();}
      if(sparam == "Fibornacci"){BtnAction(sparam); FibornacciBtnFunction();}
      if(sparam == "Message")   {BtnAction(sparam); MessageBtnFunction();}
      if(sparam == "BuyStop")   {BtnAction(sparam); OrderBtnFunction(OP_BUYSTOP);}
      if(sparam == "SellStop")  {BtnAction(sparam); OrderBtnFunction(OP_SELLSTOP);}
      if(sparam == "BuyLimit")  {BtnAction(sparam); OrderBtnFunction(OP_BUYLIMIT);}
      if(sparam == "SellLimit") {BtnAction(sparam); OrderBtnFunction(OP_SELLLIMIT);}
      if(sparam == "CloseAll")  {BtnAction(sparam); DeleteAllOrders();}
      if(sparam == "DeleteLast"){BtnAction(sparam); DeleteLastPendingOrder();}
   }
}//OnChartEvent()

void BtnAction(string sparam){
   Sleep(70);
   ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
   if(SoundOn) PlaySound("Tick.wav");
}//BtnAction()

void BtnControlFunction(){
   if(ObjectGetString(0, "BtnControl", OBJPROP_TEXT) == "BtnON"){
      CreateButton("Fibornacci", FibornacciBtnState(), 10, 20);
      CreateButton("Message", MessageBtnState(), 73, 20);
      CreateButton("BuyStop", "Buy STOP", 10, 43);
      CreateButton("SellStop", "Sell STOP", 73, 43);
      CreateButton("BuyLimit", "Buy LIMIT", 10, 66);
      CreateButton("SellLimit", "Sell LIMIT", 73, 66); 
      CreateButton("CloseAll", "Close all oders", 10, 89, 123); 
      CreateButton("DeleteLast", "Delete last order", 10, 111, 123);
      
      ObjectSetString(0, "BtnControl", OBJPROP_TEXT, "BtnOFF");
   }
   else{
      ObjectDelete(0, "Fibornacci");
      ObjectDelete(0, "Message");
      ObjectDelete(0, "BuyStop");
      ObjectDelete(0, "SellStop");
      ObjectDelete(0, "BuyLimit");
      ObjectDelete(0, "SellLimit");
      ObjectDelete(0, "CloseAll");
      ObjectDelete(0, "DeleteLast");
      
      ObjectSetString(0, "BtnControl", OBJPROP_TEXT, "BtnON");
   }
}//BtnControlFunction()

void FibornacciBtnFunction(){
   if(ObjectFind(0, FibName) != 0){
      FibCreate(); 
      ObjectSetString(0, "Fibornacci", OBJPROP_TEXT, "FibOFF");
   }
   else if(ObjectFind(0, FibName) == 0){
      ObjectDelete(0, FibName); 
      ObjectSetString(0, "Fibornacci", OBJPROP_TEXT, "FibON");
   }
}//FibornacciBtnFunction()

string FibornacciBtnState(){
   string state = "FibON";
   if(ObjectFind(0, FibName) == 0) state = "FibOFF";
   return(state);
}//FibornacciBtnState()

void MessageBtnFunction(){
   if(ObjectFind(0, "MsgBox") != 0) Message(LastMsg, LastMsgType);
   else if(ObjectFind(0, "MsgBox") == 0){
      ObjectDelete(0, "MsgBox");
      ObjectSetString(0, "Message", OBJPROP_TEXT, "ShowMsg");
      if(ObjectFind(0, "ErrorDescription") == 0) ObjectDelete("ErrorDescription");
   } 
}//MessageBtnFunction()

string MessageBtnState(){
string state = "ShowMsg";
   if(ObjectFind(0, "MsgBox") == 0) state = "HideMsg";
   return(state);
}//MessageBtnState()

void OrderBtnFunction(int orderType){
   if(ObjectFind(0, FibName) != 0) Message("To trade set and adjust Fib accordingly.", ERROR);
   int res = ManageOrders(orderType);
   switch(res){
      case 0  : Message("To place an ORDER, adjust Fib accordingly.", WARNING);                      break;
      case 1  : Message(StringConcatenate("Order Send failed with error: ", GetLastError()), ERROR); break;
      case 2  : Message("Market conditions not met: order price too close to market price",  ERROR); break;
      default : Message(StringConcatenate("Order placed sucsesfully. Order ticket: #", res), INFO);
   }
}//OrderBtnFunction()
//+------------------------------------------------------------------+
//| Order Management functions                                       |
//+------------------------------------------------------------------+
int ManageOrders(int orderType){
   double fibTopPrice    = MathMax(GetFibLevel(FibLevelToUse_1), GetFibLevel(FibLevelToUse_2));
   double fibBottomPrice = MathMin(GetFibLevel(FibLevelToUse_1), GetFibLevel(FibLevelToUse_2));
   double openPrice;
   double stopPrice;
         
   switch(orderType){
      case OP_BUYLIMIT : 
         if(fibTopPrice < Ask && fibBottomPrice < Ask){
            openPrice = OpenPrice(fibTopPrice, OP_BUYLIMIT);
            stopPrice = StopPrice(fibBottomPrice, OP_BUYLIMIT);
         }
         else if(fibTopPrice > Ask && fibBottomPrice < Ask){
            openPrice = OpenPrice(fibBottomPrice, OP_BUYLIMIT);
            stopPrice = StopPrice(NormalizePrice(fibBottomPrice - (fibTopPrice - fibBottomPrice)), OP_BUYLIMIT);
         }
         else return(0); break;
      case OP_SELLLIMIT:
         if(fibTopPrice > Bid && fibBottomPrice > Bid){
            openPrice = OpenPrice(fibBottomPrice, OP_BUYLIMIT);
            stopPrice = StopPrice(fibTopPrice, OP_BUYLIMIT);
         }
         else if(fibTopPrice > Bid && fibBottomPrice < Bid){
            openPrice = OpenPrice(fibTopPrice, OP_BUYLIMIT);
            stopPrice = StopPrice(NormalizePrice(fibTopPrice + (fibTopPrice - fibBottomPrice)), OP_BUYLIMIT);
         }
         else return(0); break;
      case OP_BUYSTOP  :
         if(fibTopPrice > Ask){
            openPrice = OpenPrice(fibTopPrice, OP_BUYSTOP);
            stopPrice = StopPrice(fibBottomPrice, OP_BUYSTOP);
         }
         else return(0); break;
      case OP_SELLSTOP :
         if(fibBottomPrice < Bid){
            openPrice = OpenPrice(fibBottomPrice, OP_SELLSTOP);
            stopPrice = StopPrice(fibTopPrice, OP_SELLSTOP);  
         }
         else return(0); 
   }
   return(PlaceOrder(openPrice, stopPrice, orderType));
}//ManageOrders()

int PFact(){
   int pFact;
   if(Digits == 5 || Digits == 3) pFact = 10; 
   else if(Digits == 4 || Digits == 2) pFact = 1;
   return(pFact);
}//PFact()

double PipToDigits(double pip){
   double tickSize = MarketInfo(SYMBOL, MODE_TICKSIZE);
   return(NormalizePrice(pip * tickSize * PFact()));
}//PipToDigits()

double DigitsToPip(double dig){
   double tickSize = MarketInfo(SYMBOL, MODE_TICKSIZE);
   return(dig / tickSize / PFact());
}//DigitsToPip()

double DigitsToPoint(double dig){
   double point = MarketInfo(SYMBOL, MODE_POINT);
   return(dig / point);
}//DigitsToPoint()

double PointToDigits(double pts){
   double point = MarketInfo(SYMBOL, MODE_POINT);
   return(pts * point);
}//PointToDigit()

double Spread(){
   double tickSize = MarketInfo(SYMBOL, MODE_TICKSIZE);
   double spread = MarketInfo(Symbol(), MODE_SPREAD);
   spread = PipToDigits(spread / PFact());
   return(spread);
}//Spread()

int Slippage(){
   double tickSize = MarketInfo(SYMBOL, MODE_TICKSIZE);
   return(int( 2.0 * Spread() / tickSize));
}//Slippage()

double NormalizePrice(double price){
   double tickSize = MarketInfo(SYMBOL, MODE_TICKSIZE);
   return(RoundToNearest(price, tickSize));
}//NormalizePrice()

double NormalizeLots(double lots){
   double step = MarketInfo(SYMBOL, MODE_LOTSTEP);
   return(RoundUp(lots, step));
}//NormalizeLots()
 
double MaxCapitalPerTrade(){
   if(AccBalance) StartBalance = AccountBalance();
   else if(AccEquity) StartBalance = AccountEquity();
   else if(StartBalance < 0) Message("Trade balance settings are incorrect.", ERROR); 
   return(StartBalance * PercentToRisk / 100.0);
}//MaxCapitalPerTrade()

double Lots(double risk){ 
   double lot;
   double minLot    = MarketInfo(SYMBOL, MODE_MINLOT);
   double maxLot    = MarketInfo(SYMBOL, MODE_MAXLOT);
   double tickValue = MarketInfo(SYMBOL, MODE_TICKVALUE);
      
   lot = MaxCapitalPerTrade() / DigitsToPoint(risk) * tickValue;
                
   if(lot < minLot) lot = minLot;
   if(lot > maxLot) lot = maxLot;       
   return(NormalizeLots(lot));
}//Lots()

double OpenPrice(double priceLevel, int orderType){
   double price;
   double pipDist = PipToDigits(PipDistForOrder);

   switch(orderType){
      case OP_BUYLIMIT :  price = priceLevel + Spread() - pipDist;   break;
      case OP_SELLLIMIT:  price = priceLevel - pipDist;              break;
      case OP_BUYSTOP  :  price = priceLevel + Spread() + pipDist;   break;
      case OP_SELLSTOP :  price = priceLevel - pipDist;             
   }   
   return(NormalizePrice(price));
}//OpenPrice()

double StopPrice(double priceLevel, int orderType){
   double price;
   double pipDist = PipToDigits(PipDistForStop);
   
   if(orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP)        price = priceLevel - pipDist;
   else if(orderType == OP_SELLLIMIT || orderType == OP_SELLSTOP) price = priceLevel + Spread() + pipDist;
   return(NormalizePrice(price));
}//StopPrice()

double ProfitPrice(double openPrice, double stopPrice, int orderType){
   double price;
   double pipDist    = PipToDigits(PipDistForProfit);
   double profitDist = PipToDigits(DigitsToPip(openPrice - stopPrice) * RiskRewardRatio);

   if(orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP)        price = openPrice + pipDist + profitDist;
   else if(orderType == OP_SELLLIMIT || orderType == OP_SELLSTOP) price = openPrice - pipDist - profitDist;
   return(NormalizePrice(price));
}//ProfitPrice()

int PlaceOrder(double open, double stop, int type){
   int ticket; 
   int expiration = TimeCurrent() + PERIOD_D1 * 60;
   double lot     = Lots(MathAbs(open - stop));
   double close   = ProfitPrice(open, stop, type);
 
   if(StopLevelCheck(open, stop, close, type)){
      ResetLastError();
      ticket = OrderSend(SYMBOL, type, lot, open, Slippage(), 0, 0, "", MagicNr, expiration, CLR_NONE);
      
      if(ticket < 0) return(1);
      RefreshRates();
      if(!OrderSelect(ticket, SELECT_BY_TICKET)) return(ticket);
      ModifyTrade(M_SL_TP, stop, close);
      return(ticket);
   }
   return(2);
}//PlaceOrder()

bool StopLevelCheck(double open, double stop, double profit, int orderType){
   bool res = true;
   double stopLevel   = MarketInfo(SYMBOL, MODE_STOPLEVEL);
   double marketPrice = (orderType == OP_BUYSTOP || 
                         orderType == OP_BUYLIMIT) ? Ask : Bid;
                         
   if(MathAbs(marketPrice - open) >= stopLevel  || 
      MathAbs(open - stop) >= stopLevel         || 
      MathAbs(profit - open) >= stopLevel) res = false;   
   return(res);
}//StopLevelCheck
//+------------------------------------------------------------------+
//| Ticket Pool functions                                            |
//+------------------------------------------------------------------+
string TicketPool = "";//to store order tickets;

bool Tickets(string ticket, int action){
   bool res = false;
   switch(action){
      case ADD    : res = StringAdd(TicketPool, ":" + ticket + ":");
         break;
      case FIND   : res = (StringFind(TicketPool, ":" + ticket + ":") < 0) ? false : true;
         break;
      case CHANGE : res = (StringReplace(TicketPool, ":" + ticket + ":", ":" + ticket + "C:") < 0) ? false : true;
   }
   return(res);
}//Tickets

void TicketsRefresh(){
   string temp = "";
   string ticket;
   for(int i = 1; i <= OrdersTotal(); i++){
      if(CheckOpenTrades(i - 1)) continue;
      ticket = (string)OrderTicket();
      if(Tickets(ticket, FIND)){
         if(Tickets((ticket + "C"), FIND)) temp = StringAdd(temp, (":" + ticket + "C:"));
         else temp = StringAdd(temp, (":" + ticket + ":"));
      }
      else temp = StringAdd(temp, (":" + ticket + ":"));
   }
   TicketPool = temp;
}//TicketsRefresh()
//+------------------------------------------------------------------+
//| Trade Management functions                                       |
//+------------------------------------------------------------------+
int CheckAllOrders(int i){//Order is preselected;
   if(!OrderSelect(i, SELECT_BY_POS))                     return(true);
   if(OrderSymbol()!= SYMBOL)                             return(true); 
   if(ManageOnlyEATrades && OrderMagicNumber()!= MagicNr) return(true); 
   return(false);
}//CheckAllOrders()

int CheckOpenTrades(int i){//Order is preselected;  
   if(CheckAllOrders(i)) return(true);
   if(OrderType() > 2)   return(true); 
   return(false);
}//CheckOpenTrades()

int GetLastOrder(bool test = false){//Order is preselected; ... for openTrades-false; for pendingOrders-true
   datetime time   = 0;
   int      ticket = -1;
   
   for(int i = 1; i <= OrdersTotal(); i++){ 
      if(CheckOpenTrades(i - 1) == test) continue;
      if(time < OrderOpenTime()){
         time = OrderOpenTime();
         ticket = OrderTicket();
      }
   }
   return(ticket);
}//GetLastPending()

double PriceToUse(){//Order is preselected;
   double price = (OrderType() == OP_BUY) ? Bid : Ask;
   return(price);
}//PriceToUse()

int DFact(){//Order is preselected;
   int dirctionFact = (OrderType() == OP_BUY) ? 1 : -1;
   return(dirctionFact);
}//Direction()

bool R_RStatus(){//Order is preselected;
   double assignedRisk = DigitsToPip(MathAbs(OrderOpenPrice() - OrderStopLoss())) * LockInAtR_R;
   double rrStatus     = DigitsToPip(MathAbs(OrderOpenPrice() - PriceToUse()));
   return(rrStatus > assignedRisk);
}//R_RStatus()

double ModifyLots(){//Order is preselected;
   return(NormalizeLots((PartClosePercent / 100) * OrderLots()));
}//ModifyLots()

double BreakEvenPrice(){//Order is preselected;
   return(OrderOpenPrice() + (PipToDigits(LockInPips) * DFact()));
}//BreakEvenPrice()

double StopPriceToModify(){//Order is preselected;
   double stopDist = PointToDigits(MaxCapitalPerTrade() / PointValueCalculator(OrderLots()));
   stopDist = (stopDist < PipToDigits(MinSLDistance)) ? (PipToDigits(MinSLDistance)* DFact()) : (stopDist * DFact());
   return(OrderOpenPrice() - stopDist);
}//StopPriceToModify()

double ProfitPriceToModify(){//Order is preselected;
   double stopPrice      = (OrderStopLoss() == 0) ? StopPriceToModify() : OrderStopLoss();
   double takeProfitDist = MathAbs(OrderOpenPrice() - stopPrice) * RiskRewardRatio;
   return(OrderOpenPrice() + (takeProfitDist * DFact()));
}//ProfitPriceToModify()

void ManageTrades(){
   for(int i = 1; i <= OrdersTotal(); i++){
      if(CheckOpenTrades(i - 1)) continue;
      if(OrderStopLoss() == 0 && ModifyNullSL)        ModifyTrade(M_SL, StopPriceToModify());
      else if(OrderTakeProfit() == 0 && ModifyNullTP) ModifyTrade(M_TP, ProfitPriceToModify());
       
      if(BreakEvenAtR_R && R_RStatus() && ((OrderStopLoss() - OrderOpenPrice() * DFact()) < 0)) 
           ModifyTrade(M_SL, BreakEvenPrice());
      if(PartCloseAtBE && R_RStatus()){
           TicketsRefresh();
           string ticket = (string)OrderTicket();
           if(!Tickets((ticket + "C"), FIND)){
              ModifyTrade(M_LOTS, ModifyLots()); 
              Tickets(ticket, CHANGE);
           }
      }   
   }
}//ManageTrades()

bool ModifyTrade(int modifyCase, double modifyValue, double modifyValue2 = 0){//Order is preselected;
   bool res;
   switch(modifyCase){
      case M_LOTS : res = OrderClose(OrderTicket(), modifyValue, PriceToUse(), Slippage(), CLR_NONE);                                break;
      case M_SL   : res = OrderModify(OrderTicket(), OrderOpenPrice(), modifyValue, OrderTakeProfit(), OrderExpiration(), CLR_NONE); break;
      case M_TP   : res = OrderModify(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), modifyValue, OrderExpiration(), CLR_NONE);   break;
      case M_SL_TP: res = OrderModify(OrderTicket(), OrderOpenPrice(), modifyValue, modifyValue2, OrderExpiration(), CLR_NONE);      
   }
  // Comment((string)res);
   return(res);
}//ModifyTrade()

void DeleteLastPendingOrder(){
   ResetLastError();
   if(!OrderDelete(GetLastOrder(true))){
      Message(StringConcatenate("Order delete failed with error: #", GetLastError()), ERROR);
   }
   else Message("Last order deleted sucsesfully.", INFO); 
}//DeleteLastPendingOrder()

void DeleteAllOrders(){
   bool res;
   int err;
   for(int i = 1; i <= OrdersTotal(); i++){
      if(CheckAllOrders(i - 1)) continue;
      ResetLastError();
      if(OrderType() <= 2)
         res = OrderClose(OrderTicket(), OrderLots(), PriceToUse(), Slippage(), CLR_NONE);
      else res = OrderDelete(OrderTicket());
           
      if(res == true) Message("Order closed sucsesfully.", INFO);
      err = GetLastError();
      if(err > 0){
         Message(StringConcatenate("Order close failed with error: ", err), ERROR);
         Sleep(500);
         RefreshRates();
         i--;
      }  
   }
   if(res == true) Message("All orders closed sucsesfully.", INFO);   
}//DeleteAllOrders()
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
void init(){  
   deinit();
   //Comment("");
   CreateButton("BtnControl", "BtnON", 230, 2, 60, 20);
}//init()
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit(){
   ObjectDelete("MsgBox");
   ObjectDelete("Spread");
   ObjectDelete("Clock");
   ObjectDelete("Profit");
   ObjectSetString(0, "BottonControl", OBJPROP_TEXT, "BtnOFF");
   BtnControlFunction();
   ObjectDelete("BtnControl");
   ObjectDelete(FibName);
   return (0);
}//deinit()

//+------------------------------------------------------------------+
//| Expert program start function                                    |
//+------------------------------------------------------------------+
int start(){
   if(FibLevelToUse_1 == FibLevelToUse_2)       {Message("Fibonacci Retracement settings is incorrect.", ERROR); return(0);}
   if(PercentToRisk == 0 || PercentToRisk > 100){Message("To trade adjust risk percentage accordingly.", ERROR); return(0);}
   if(RiskRewardRatio == 0)                     {Message("Risk/Reward ratio is null: adjust accordingly.", ERROR); return(0);}
   
   if(ShowInfo) InfoBox(); //Comment(StringConcatenate("Risk: ", t));
   ManageTrades();
   return(0);
}//start()
