//+------------------------------------------------------------------+
//|                                         smTMMS RR-Calculator_vX
//+------------------------------------------------------------------+
#property copyright "Copyright 08.08.2019, SwingMan"

#property strict
#property indicator_chart_window
//---
enum ENUM_ACCOUNT_MODE
  {
   Cash_Amount,
   Account_Balance,
   Account_Equity,
   Account_Margin_Free
  };
//--- input parameters
//+------------------------------------------------------------------+
input bool           Enable_MoneyManagement=true;
//input ENUM_ACCOUNT_MODE Account_Mode=Cash_Amount;
input ENUM_ACCOUNT_MODE Account_Mode=Account_Balance;
input double          Risc_Percent   =2.0;
input double          Trading_Capital=1000;
input double          Fixed_LotSize  =0.01;
//--- input parameters of the Fibo 
input string ___Fibo_Retracements="--------------------------------------------";
input bool             Show_Comments=true;
input int              Payoff_Levels=4;
input int              ExpandingBarsToRight=10;
input int              Sensitivity_BidLine=5;
input color            FiboLine_Color  =clrOrange;
input ENUM_LINE_STYLE  FiboLine_Style  =STYLE_SOLID;
input int              FiboLine_Width  =3;
//
input color            FiboLevels_Color=clrDarkOrange;
input ENUM_LINE_STYLE  FiboLevels_Style=STYLE_DOT;
input int              FiboLevels_Width=1;
//
input color            FiboText_Color   =clrDarkOrange;
input string           FiboText_Font    ="Arial";
input int              FiboText_FontSize=8;
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Set number of levels and their parameters                        | 
//+------------------------------------------------------------------+ 
int             levelsM;          // number of level lines 
double          valuesM[];         // values of level lines 
color           colorsM[];         // color of level lines 
ENUM_LINE_STYLE stylesM[];         // style of level lines 
int             widthsM[];         // width of level lines 
long            chart_IDM=0;        // chart's ID 
string          nameM="FiboTrendLevels_"; // object name 

string CR="\n";

//--- variables
datetime time1M,time2M;
double price1M,price2M;
bool bFiboWasChanged;
//---

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   ObjectDelete(chart_IDM,nameM);

   levelsM=20;

   ArrayResize(valuesM,levelsM);
   ArrayResize(colorsM,levelsM);
   ArrayResize(stylesM,levelsM);
   ArrayResize(widthsM,levelsM);

   for(int i=0;i<levelsM;i++)
     {
      colorsM[i]=clrYellow;
      stylesM[i]=STYLE_DOT;
      widthsM[i]=1;
     }

//--- level values
   valuesM[0]=0;
   valuesM[1]=0.5;
   valuesM[2]=1;
   for(int i=3;i<levelsM;i++)
     {
      valuesM[i]=i-1;
     }

//--- indicator buffers mapping

//---
   if(Show_Comments==true)
      Comment(CR,WindowExpertName(),CR,"===================");
//---

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(chart_IDM,nameM);
   if(Show_Comments==true)
      Comment("");
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//=========================================================
//--- create fibo levels
   if(ObjectFind(nameM)==-1)
     {
      Get_FiboCreate_Values(time1M,price1M,time2M,price2M);
      Set_FiboRetracement(time1M,price1M,time2M,price2M);
     }

//--- redraw the chart and wait for 1 second 
   ChartRedraw();
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Check_FiboChanged(datetime &time1X,double &price1X,datetime &time2X,double &price2X)
  {
   datetime time1,time2;
   double price1,price2;
   string objClicked=nameM;

   time1=(datetime)ObjectGet(objClicked,OBJPROP_TIME2);
   time2=(datetime)ObjectGet(objClicked,OBJPROP_TIME1);

   price1=ObjectGetDouble(chart_IDM,objClicked,OBJPROP_PRICE2);
   price2=ObjectGetDouble(chart_IDM,objClicked,OBJPROP_PRICE1);

   datetime tempTime=0;
   double   tempPrice=0;
   if(time1!=time1X || time2!=time2X || price1!=price1X || price2!=price2X)
     {
      if(time1<time2)
        {
         tempTime=time1;
         time1=time2;
         time2=tempTime;

         tempPrice=price1;
         price1=price2;
         price2=tempPrice;
        }
      time1X=time1;
      time2X=time2;
      price1X=price1;
      price2X=price2;
      return(true);
     }
   else
      return (false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Set_FiboRetracement(datetime time1,double price1,datetime time2,double price2)
  {
   string obName;
   ObjectsDeleteAll(0,nameM);
   int localTrend=0;
   string sOrder="";
   bool bSelectable;

//=========================================================
//-- 1. Fibo Line   ---------------------------------------
   obName=nameM;

   bSelectable=true;
   Draw_TrendLine(obName,time1,price1,time2,price2,
                  FiboLine_Color,FiboLine_Style,FiboLine_Width,bSelectable,true); // selectable,selected

   double currPrice=Close[0];
   double offset   =Sensitivity_BidLine*Point;
//=========================================================
//-- 2. Fibo Levels ---------------------------------------
//--- extend the lines at right
   if(time1>time2)
      time1=time1+ExpandingBarsToRight*Period()*60;
   else
      time2=time2+ExpandingBarsToRight*Period()*60;

   double diffPrice=MathAbs(price1-price2);

   double entryPrice=price1;
   double stopPrice=0,levelPrice=0;

//short ----------------------------------------- SELL
   if(price1<price2)
     {
      localTrend=-1;
      if(price1>currPrice+offset)
         sOrder="SELL LIMIT";
      else
      if(price1<currPrice-offset)
         sOrder="SELL STOP";
      else
         sOrder="SELL MARKET";
      stopPrice=entryPrice+diffPrice;
     }
   else
//long ------------------------------------------ BUY
   if(price1>price2) 
     {
      localTrend=1;
      if(price1>currPrice+offset)
         sOrder="BUY STOP";
      else
      if(price1<currPrice-offset)
         sOrder="BUY LIMIT";
      else
         sOrder="BUY MARKET";
      stopPrice=entryPrice-diffPrice;
     }

   int numLevels=Payoff_Levels+3;

   bSelectable=false;
   for(int i=0;i<numLevels;i++)
     {
      obName=nameM+"Level"+(string)i;
      //short
      if(localTrend<0)
         levelPrice=stopPrice-diffPrice*valuesM[i];
      else
      //long
      if(localTrend>0)
         levelPrice=stopPrice+diffPrice*valuesM[i];

      //--- set StopLoss line as selectable and selected
      //if(i==0) bSelectable=true; else bSelectable=false;

      Draw_TrendLine(obName,time1,levelPrice,time2,levelPrice,
                     FiboLevels_Color,FiboLevels_Style,FiboLevels_Width,bSelectable,bSelectable); // selectable,selected
     }

//=========================================================
//-- 3. Fibo Percents Text --------------------------------
   double diffPoints=MathAbs(price1-price2)/Point;
   double lotSize=Get_LotSize(Symbol(),Fixed_LotSize,Risc_Percent,diffPoints);
   double tickValue=MarketInfo(Symbol(),MODE_TICKVALUE);
   string sValue=DoubleToString(lotSize*diffPoints*tickValue,2)+" "+AccountCurrency();

   string sText;
   for(int i=0;i<numLevels;i++)
     {
      obName=nameM+"Percent"+(string)i;
      //short
      if(localTrend<0)
         levelPrice=stopPrice-diffPrice*valuesM[i];
      else
      //long
      if(localTrend>0)
         levelPrice=stopPrice+diffPrice*valuesM[i];

      switch(i)
        {
         case 0: sText="(Stop Loss= "+DoubleToString(diffPoints,0)+" points)  "+DoubleToString(levelPrice,Digits); break;
         case 1: sText="(1/2  Risk of "+DoubleToString(Risc_Percent,2)+"%)  "+DoubleToString(levelPrice,Digits); break;
         case 2: sText="( "+sOrder+"= "+DoubleToString(lotSize,2)+" lots)  "+DoubleToString(levelPrice,Digits); break;
         //case 2: sText="( ENTRY= "+DoubleToString(lotSize,2)+" lots)  "+DoubleToString(levelPrice,Digits); break;
         case 3: sText="("+(string)(i-2)+" R=  "+sValue+")  "+DoubleToString(levelPrice,Digits); break;
         default: sText="("+(string)(i-2)+" R)  "+DoubleToString(levelPrice,Digits); break;
        }

      Draw_Text(obName,sText,time1,levelPrice,
                FiboText_Color,FiboText_Font,FiboText_FontSize);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Get_FiboCreate_Values(datetime &tBar1,double &pBar1,datetime &tBar2,double &pBar2)
  {
//--- ENTRY price -------------------------------   
   tBar1=Time[0];
   pBar1=Open[0];

//--- STOP LOSS price ---------------------------
//--- trend = slope bar 0/3
   double slope=iMA(Symbol(),Period(),3,0,MODE_SMA,PRICE_MEDIAN,0)-
                iMA(Symbol(),Period(),3,0,MODE_SMA,PRICE_MEDIAN,3);

   int iBar1=0,iBar2=0;

//--- short
//--- pivot is the HIGH
   if(slope<0)
     {
      for(int i=2;i<20;i++)
        {
         if(High[i+1]<High[i] && High[i-1]<High[i])
           {
            tBar2=Time[i];
            pBar2=High[i];
            break;
           }
        }
     }
   else
//--- long   
//--- pivot is the LOW
   if(slope>0)
     {
      for(int i=2;i<20;i++)
        {
         if(Low[i+1]>Low[i] && Low[i-1]>Low[i])
           {
            tBar2=Time[i];
            pBar2=Low[i];
            break;
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // Event ID 
                  const long& lparam,   // Parameter of type long event 
                  const double& dparam, // Parameter of type double event 
                  const string& sparam  // Parameter of type string events 
                  )
  {
   //int iLevel=2;

   //string sValue;
   string objClicked;

   bFiboWasChanged=false;

   if(id==CHARTEVENT_OBJECT_CLICK || id==CHARTEVENT_OBJECT_DRAG)
     {
      if(sparam=="" || sparam=="0") return;
      if(StringFind(sparam,nameM,0)>=0)
        {

         objClicked=sparam;
         bFiboWasChanged=true;

         if(Check_FiboChanged(time1M,price1M,time2M,price2M)==true)
            Set_FiboRetracement(time1M,price1M,time2M,price2M);
        }
     }
   else
     {
      return;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Get_LotSize(string sSymbol,double dFixedLots,double dPercent,double dStopPoints)
  {
   double lotSize;

   if(Enable_MoneyManagement==false)
     {
      return(dFixedLots);
     }

//--- lots calculation
   double tickValue=MarketInfo(sSymbol,MODE_TICKVALUE);

   double dMoneyLimit=0;
   switch(Account_Mode)
     {
      case Cash_Amount:         dMoneyLimit=Trading_Capital; break;
      case Account_Balance:      dMoneyLimit=AccountInfoDouble(ACCOUNT_BALANCE); break;
      case Account_Equity:       dMoneyLimit=AccountInfoDouble(ACCOUNT_EQUITY); break;
      case Account_Margin_Free:  dMoneyLimit=AccountInfoDouble(ACCOUNT_MARGIN_FREE); break;
     }
   dMoneyLimit=dMoneyLimit*(dPercent/100.0);

   lotSize=(dMoneyLimit/dStopPoints)/tickValue;
   lotSize=NormalizeDouble(lotSize,2);

//--- check permitted amount of lots   
   lotSize=MathMax(lotSize,MarketInfo(sSymbol,MODE_MINLOT));
   lotSize=MathMin(lotSize,MarketInfo(sSymbol,MODE_MAXLOT));

   return(lotSize);
  }
//                ***************************************  
//                      DRAW OBJECTS
//                ***************************************
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Draw_TrendLine(string objX,datetime dTime1,double dPrice1,
                    datetime dTime2,double dPrice2,
                    color dColor,int iStyle,int iWidth,bool bSelectable,bool bSelected)
  {
   if(ObjectFind(0,objX)>=0) return;

   ObjectCreate(objX,OBJ_TREND,0,dTime1,dPrice1,dTime2,dPrice2);
   ObjectSet(objX,OBJPROP_COLOR,dColor);
   ObjectSet(objX,OBJPROP_STYLE,iStyle);
   ObjectSet(objX,OBJPROP_WIDTH,iWidth);
   ObjectSet(objX,OBJPROP_RAY,false);
   ObjectSet(objX,OBJPROP_BACK,true);
   ObjectSet(objX,OBJPROP_SELECTABLE,bSelectable);
   ObjectSet(objX,OBJPROP_SELECTED,bSelected);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Draw_Text(string objX,string text,datetime time,double price,
               color dColor,string font,int font_size)
  {
   ObjectDelete(objX);

   ObjectCreate(objX,OBJ_TEXT,0,time,price);
   ObjectSetString(0,objX,OBJPROP_TEXT,text);
   ObjectSetString(0,objX,OBJPROP_FONT,font);
   ObjectSet(objX,OBJPROP_FONTSIZE,font_size);
   ObjectSet(objX,OBJPROP_COLOR,dColor);
   ObjectSet(objX,OBJPROP_BACK,false);
   ObjectSet(objX,OBJPROP_ANCHOR,ANCHOR_LOWER);
   ObjectSet(objX,OBJPROP_ALIGN,ALIGN_RIGHT);
  }
//+------------------------------------------------------------------+
