
//+------------------------------------------------------------------+
//|                                   Camarilla Trader.mq4           |
//| Original concept picked up here                                  |
//| https://www.forexfactory.com/showthread.php?p=9811015#post9811015|
//| With this copywrite                                              |
//| Copyright © 2005 FAB4x, Alejandro Galindo & KillerKhan           |
//|     http://yousky.free.fr Copyright © 2006, Yousky Soft          |
//|                                                                  |
//| This is a complette re-write in 2017                             |
//+------------------------------------------------------------------+
//
#property copyright   "https://www.forexfactory.com/lukeb"
#property link        " "
#property description "Re-written to handle errors, complile strict "
#property description "with built-in Camarilla calculaion and display"
#property description "by https://www.forexfactory.com/lukeb"
#property version     "1.07"
#property strict
#include <stdlib.mqh>
enum ENUM_PRICE_POINTS {PRICE_POINT_0, PRICE_POINT_1};
enum ENUM_LOTS_MODE {FIXED_LOTS, PCT_FREE_MARGIN};
//+------------------------------------------------------------------+
//| Common External variables                                        |
//+------------------------------------------------------------------+
extern ENUM_TIMEFRAMES CamarillaTF = PERIOD_D1;
extern int               MAGIC_NUM = 16384;
extern ENUM_LOTS_MODE LOTS_MODE = PCT_FREE_MARGIN;
extern double           riskPct = 3;
extern double         FixedLots = 0.02;
//+------------------------------------------------------------------+
//| External variables                                               |
//+------------------------------------------------------------------+
extern double StartHour   = 0;
extern double StartMinute = 30;
extern double EndHour   = 21;
extern double EndMinute = 55;
//========================
string msg = "";
ENUM_TIMEFRAMES workCamarillaTF;
const int WINDOW_ZERO = 0;
bool orderingTime = false;
//========================
enum ENUM_ORDER_IDX         {BUY_ORDER,      SELL_ORDER,     BUY_STOP,        SELL_STOP,   endOrderIdx};
string orderTypeNames[]   = {"BUY_PRMPT",    "SELL_PRMPT",   "BSTOP_PRMPT",   "SSTOP_PRMPT"};
string orderTypeCntName[] = {"BUY_CNT",      "SELL_CNT",     "BSTOP_CNT",     "SSTOP_CNT"  };
string ticketObjName[]    = {"BUY_TKT",      "SELL_TKT",     "BSTOP_TKT",     "SSTOP_TKT"  };
int ticketCnts[endOrderIdx];
int ticketNums[endOrderIdx];
int orderXpos[endOrderIdx];
enum ENUM_ORDER_YPOS        {ORDR_PROMPT_ROW, ORDER_CNT_ROW, ORDER_TKT_ROW, endOrderRows};
int orderYpos[endOrderRows];
//========================
enum ENUM_CAMARILLA_IDX         { H1_IDX,       L1_IDX,       H2_IDX,       L2_IDX,       H3_IDX,       L3_IDX,       H4_IDX,       L4_IDX,   endCamarillaIdx};
string camarillaPrompNames[]  = {"H1_PRMPT",    "L1_PRMPT",   "H2_PRMPT",   "L2_PRMPT",   "H3_PRMPT",   "L3_PRMPT",   "H4_PRMPT",   "L4_PRMPT"};
string camarillaValName[]     = {"H1_VAL",      "L1_VAL",     "H2_VAL",     "L2_VAL",     "H3_VAL",     "L3_VAL",     "H4_VAL",     "L4_VAL"  };
double camarillaVals[endCamarillaIdx];
int camarillaXpos[endCamarillaIdx];
enum ENUM_CAM_YPOS           {CAM_PROMPT_ROW, CAM_VALS_ROW, endCamRows};
int camarillaYpos[endCamRows];
//--------------------------
string camarillaLineNames[]  = {"H1_LINE",     "L1_LINE",    "H2_LINE",    "L2_LINE",    "H3_LINE",    "L3_LINE",    "H4_LINE",    "L4_LINE"};
string camarillaTextNames[]  = {"H1_TXT",      "L1_TXT",     "H2_TXT",     "L2_TXT",     "H3_TXT",     "L3_TXT",     "H4_TXT",     "L4_TXT"};
color  camarillaLineColor[]  = {clrAquamarine, clrAquamarine,clrYellow,    clrYellow,    clrBlue,      clrRed,       clrBlue,      clrRed,};
ENUM_LINE_STYLE camarillaLineStyle[] = {STYLE_DOT,STYLE_DOT, STYLE_DASHDOT,STYLE_DASHDOT,STYLE_DASH,   STYLE_DASH,   STYLE_SOLID,  STYLE_SOLID};
//+------------------------------------------------------------------+
//| EA initialization function                                       |
//+------------------------------------------------------------------+
int OnInit()
 {
   // EventSetTimer(1);
   loadOrderInfoLocations();
   loadCamarillaInfoLocations();
   workCamarillaTF = CamarillaTF;
   // Ensure orderingTime is set correctly.
   initializeIsOKToOrder();
   //
   for(ENUM_CAMARILLA_IDX i=0; i<endCamarillaIdx; i++)
    {
      camarillaPrompNames[i] += IntegerToString(MAGIC_NUM);
      camarillaValName[i]    += IntegerToString(MAGIC_NUM);
      camarillaLineNames[i]  += IntegerToString(MAGIC_NUM);
      camarillaTextNames[i]  += IntegerToString(MAGIC_NUM);
    }
   for(ENUM_ORDER_IDX i=0; i<endOrderIdx; i++)
    {
      orderTypeNames[i]   += IntegerToString(MAGIC_NUM);
      orderTypeCntName[i] += IntegerToString(MAGIC_NUM);
      ticketObjName[i]    += IntegerToString(MAGIC_NUM);
    }
   //
   return(INIT_SUCCEEDED);
 }
void initializeIsOKToOrder(void)
 {
   datetime calcTime;
   for( int barsBack=(24*60); barsBack>=0; barsBack--) // go back 24 hrs to get at least 1 turn on or turn off
    {
      calcTime = iTime(Symbol(),PERIOD_M1, barsBack);
      orderingTime = isOrderingOK( orderingTime, calcTime);
    }
 }
void loadCamarillaInfoLocations( void )
 {
   int xPos=10, xPlus=80, yPos=120, yPlus = 20;
   for(ENUM_CAM_YPOS i=0; i<endCamRows; i++)  // Load the y Positions
    {
      camarillaYpos[i] = yPos + (yPlus*i);
    }   
   for(ENUM_CAMARILLA_IDX i=0; i<endCamarillaIdx; i++)    // Load the x Positions
    {
      camarillaXpos[i] = xPos + (xPlus*i);
    }
 }
void loadOrderInfoLocations( void )
 {
   int xPos=10, xPlus=80, yPos=50, yPlus = 20;
   for(ENUM_ORDER_YPOS i=0; i<endOrderRows; i++)  // Load the y Positions
    {
      orderYpos[i] = yPos + (yPlus*i);
    }   
   for(ENUM_ORDER_IDX i=0; i<endOrderIdx; i++)    // Load the x Positions
    {
      orderXpos[i] = xPos + (xPlus*i);
    }
 }
//+------------------------------------------------------------------+
//| Expert Exit Function                                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
   // EventKillTimer();
   long chartID = ChartID();
   for(ENUM_CAMARILLA_IDX i=0; i<endCamarillaIdx; i++)
    {
      ObjectDelete(chartID,camarillaLineNames[i]);
      ObjectDelete(chartID,camarillaTextNames[i]);
      ObjectDelete(chartID,camarillaPrompNames[i]);
      ObjectDelete(chartID,camarillaValName[i]);
    }
   for(ENUM_ORDER_IDX i=0; i<endOrderIdx; i++)
    {
      ObjectDelete(chartID,orderTypeNames[i]);
      ObjectDelete(chartID,orderTypeCntName[i]);
      ObjectDelete(chartID,ticketObjName[i]);
    }
   if( (msg != "") && (reason != REASON_INITFAILED) )
      Comment("");
 }
void OnTimer()
 {
   static int callCount = 0;
   callCount++;
   string source = __FUNCTION__+" "+IntegerToString(callCount);
   // runEA(source);
 }
//+------------------------------------------------------------------+
//| EA Quote Processing Function                                     |
//+------------------------------------------------------------------+
void OnTick()
 {
   static int callCount = 0;
   callCount++;
   string source = __FUNCTION__+" "+IntegerToString(callCount);
   runEA(source);
 }
//
void runEA(const string& calledFrom)
 {
   static int callCount = 0;
   datetime calcTime = TimeCurrent();
   callCount++;
   // msg = StringConcatenate(__FUNCTION__," Called ",IntegerToString(callCount)," times from ",calledFrom);
   // Comment(msg);
   //
   int    openTrades = 0;
   int    slippage = 5;  //  int [in]  Value of the maximum price slippage in points.
   //
   setCamarillaValues(workCamarillaTF);
   //
   orderingTime = isOrderingOK(orderingTime, calcTime);
   //
   if( ! orderingTime )
    {
      closeAllEAOrders(slippage); // Close all open orders
    }
   //
   openTrades = countEATrades();  // This counts the # of orders of each type
   //
   if( orderingTime == true )
    {
   	setStopOrders(slippage);
    }
 }
//
bool isOrderingOK( const bool& orderTime, const datetime& calcTime )  // Turn ordering on and off
 {
   bool isOKtoOrder = orderTime;
   if( (TimeHour(calcTime) == EndHour) && (TimeMinute(calcTime)>=EndMinute) ) // This will go wrong if Start's overlap
    {
   	isOKtoOrder = false;   // Stop processing Orders
    }
   if( (TimeHour(calcTime) == StartHour) && (TimeMinute(calcTime)>=StartMinute) ) // This will go wrong if Ends's overlap
    {
   	isOKtoOrder = true;  // turn ordering on
    }
   return(isOKtoOrder);
 }
//
void setStopOrders(const int& slippage)
 {
	if( (ticketCnts[BUY_ORDER]<1) && (ticketCnts[SELL_ORDER]<1) ) // No Trades, ensure starting trades are in place
	 {
		if( (ticketCnts[BUY_STOP]<1) && (camarillaVals[H3_IDX]>Ask) )
		 {
		   if( MOrderSend(Symbol(),OP_BUYSTOP, camarillaVals[H3_IDX],slippage,camarillaVals[L1_IDX],camarillaVals[H4_IDX],"",MAGIC_NUM,0,clrBlue,__FUNCTION__) )
		    {
		      ticketCnts[BUY_STOP]++;
		    }
		 }
		if( (ticketCnts[SELL_STOP]<1) && (camarillaVals[L3_IDX]<Bid) )
		 {
		   if( MOrderSend(Symbol(),OP_SELLSTOP,camarillaVals[L3_IDX],slippage,camarillaVals[H1_IDX],camarillaVals[L4_IDX],"",MAGIC_NUM,0,clrRed,__FUNCTION__) )
		    {
		      ticketCnts[SELL_STOP]++;
		    }
		 }
	 }
	else if( (ticketCnts[BUY_ORDER]>0) && (ticketCnts[SELL_STOP]<1) && (camarillaVals[L3_IDX]<Bid) )  // No opposing Sell Stop, make it
	 {
		if( MOrderSend(Symbol(),OP_SELLSTOP,camarillaVals[L3_IDX],slippage,camarillaVals[H1_IDX],camarillaVals[L4_IDX],"",MAGIC_NUM,0,clrRed,__FUNCTION__) )
		 {
		   ticketCnts[SELL_STOP]++;
		 }
	 }
	else if( (ticketCnts[SELL_ORDER]>0) && (ticketCnts[BUY_STOP]<1) && (camarillaVals[H3_IDX]>Ask) )  // No opposing Buy Stop, make it
	 {
		if( MOrderSend(Symbol(),OP_BUYSTOP, camarillaVals[H3_IDX],slippage,camarillaVals[L1_IDX],camarillaVals[H4_IDX],"",MAGIC_NUM,0,clrBlue,__FUNCTION__) )
	    {
	      ticketCnts[BUY_STOP]++;
	    }
	 }
 }
//
void displayAllOrders( void )
 {
   for(ENUM_ORDER_IDX i=0; i<endOrderIdx; i++)
    {
      orderDisplay(i);
    }
 }
 void orderDisplay(const ENUM_ORDER_IDX & idx)
 {
   manageALabel(orderTypeNames[idx],   orderPromptDisplay(idx), orderXpos[idx], orderYpos[ORDR_PROMPT_ROW], clrOrangeRed);
   manageALabel(orderTypeCntName[idx], IntegerToString(ticketCnts[idx]),        orderXpos[idx], orderYpos[ORDER_CNT_ROW],   clrYellowGreen, 10);
   manageALabel(ticketObjName[idx],    IntegerToString(ticketNums[idx]),        orderXpos[idx], orderYpos[ORDER_TKT_ROW], clrYellowGreen, 10);
 }
string orderPromptDisplay( const ENUM_ORDER_IDX& idx)
 {
   string displayStr;
   switch (idx)
    {
      case BUY_ORDER:  displayStr = "BUYS";   break;
      case SELL_ORDER: displayStr = "SELLS";  break;
      case BUY_STOP:   displayStr = "BSTOPS"; break;
      case SELL_STOP:  displayStr = "SSTOPS    "+(orderingTime==TRUE?"Open Time":"Closed Time")+" "+IntegerToString(Hour())+":"+IntegerToString(Minute()); break;
      default:
         msg=StringConcatenate(__FUNCTION__,"called with invalid value: ",IntegerToString(idx));
         Comment(msg); Print(msg);
         break;
    }
   return(displayStr);
 }
//========================
void displayAllCamarilla( void )
 {
   for(ENUM_CAMARILLA_IDX i=0; i<endCamarillaIdx; i++)
    {
      camarillaDisplay(i);
    }
 }
void camarillaDisplay(const ENUM_CAMARILLA_IDX& idx)
 {
   manageALabel(camarillaPrompNames[idx], camarillaPrompstring(idx), camarillaXpos[idx], camarillaYpos[CAM_PROMPT_ROW], clrOrangeRed);
   manageALabel(camarillaValName[idx], DoubleToStr(camarillaVals[idx],Digits), camarillaXpos[idx], camarillaYpos[CAM_VALS_ROW], clrYellowGreen);
 }
string camarillaPrompstring( const ENUM_CAMARILLA_IDX& idx)
 {
   string displayStr;
   switch (idx)
    {
      case H1_IDX: displayStr = "H1";  break;
      case L1_IDX: displayStr = "L1";  break;
      case H2_IDX: displayStr = "H2";  break;
      case L2_IDX: displayStr = "L2";  break;
      case H3_IDX: displayStr = "H3";  break;
      case L3_IDX: displayStr = "L3";  break;
      case H4_IDX: displayStr = "H4";  break;
      case L4_IDX:
          {
            int movementTicks  = (int) ((camarillaVals[H3_IDX]-camarillaVals[L1_IDX])/_Point);
            double volume = LotsForRisk(riskPct, movementTicks);
            displayStr = "L4"+"  Lots: "+DoubleToString(volume,2);
          }
         break;
      default:
         msg=StringConcatenate(__FUNCTION__,"called with invalid value: ",IntegerToString(idx));
         Comment(msg); Print(msg);
         break;
    }
   return(displayStr);
 }
//========================
//+------------------------------------------------------------------+
//| Special Convertion Functions                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void manageALabel(const string& objName, const string dispStr, const int& xPos, const int& yPos, const color dispClr, const int fontSize = 12)
 {
   static long chartID = ChartID();
   if ( ObjectFind(chartID,objName) < 0 )
    {
      ObjectCreate    (chartID, objName, OBJ_LABEL, WINDOW_ZERO,  0, 0);
      ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE,  fontSize);
      ObjectSetString (chartID, objName, OBJPROP_FONT,      "Arial");
      ObjectSetInteger(chartID, objName, OBJPROP_COLOR,     dispClr);
      ObjectSetInteger(chartID, objName, OBJPROP_CORNER,    CORNER_LEFT_UPPER);
      ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR,    ANCHOR_LEFT_UPPER);
      ObjectSetInteger(chartID, objName, OBJPROP_BACK,      true); 
      ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(chartID, objName, OBJPROP_SELECTED,  false); 
      ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN,    true);
    }
   ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, xPos );
   ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, yPos );
   ObjectSetString (chartID, objName, OBJPROP_TEXT,      dispStr );
 }
//+------------------------------------------------------------------+
void setCamarillaValues(const ENUM_TIMEFRAMES& camarillaTF)
 {
   static datetime lastCalcPeriod = 0;
   //
   if( (lastCalcPeriod != iTime(Symbol(),camarillaTF,0)) )
    {
       lastCalcPeriod = iTime(Symbol(),camarillaTF,0);
       int shift = getCamaillaShift(camarillaTF);
       double range  = (iHigh(Symbol(), camarillaTF, shift) - iLow(Symbol(), camarillaTF, shift));
       double close  = iClose(Symbol(), camarillaTF, shift);
       //
       camarillaVals[H1_IDX] = close + (range * (1.1/12.0));
       camarillaVals[L1_IDX] = close - (range * (1.1/12.0));
       camarillaVals[H2_IDX] = close + (range * (1.1/6.0));
       camarillaVals[L2_IDX] = close - (range * (1.1/6.0));
       camarillaVals[H3_IDX] = close + (range * (1.1/4.0));
       camarillaVals[L3_IDX] = close - (range * (1.1/4.0));
       camarillaVals[H4_IDX] = close + (range * (1.1/2.0));
       camarillaVals[L4_IDX] = close - (range * (1.1/2.0));
    }
   displayAllCamarillalLines();
   displayAllCamarilla();
 }
int getCamaillaShift( const ENUM_TIMEFRAMES& camarillaTF)
 {
   int shift = 1;
   if( camarillaTF == PERIOD_D1)  // Saturday and Sunday are skipped
    {
      int dayOfWeek = TimeDayOfWeek(Time[0]);
      if( (dayOfWeek==1)  ) // today is Sunday
       {
         shift = 2; // use Friday
       }
      else if( (dayOfWeek==2) ) // Today is Monday
       {
         shift = 3; // use Friday
       }
     }
   return( shift );
 }
//========================
int countEATrades(void)
 {
   int openTrades=0;
   ArrayInitialize(ticketCnts, NULL);
   ArrayInitialize(ticketNums, NULL);
   for (int cnt=OrdersTotal()-1; cnt>=0; cnt--)
    {
   	if( MOrderSelect(cnt) )
   	 {
      	if( (OrderSymbol() == Symbol())  && (OrderMagicNumber() == MAGIC_NUM) ) 
      	 {
            openTrades++;
            int orderType = OrderType();
            switch (orderType)
             {
               case OP_BUY:
                  ticketCnts[BUY_ORDER]++;
                  ticketNums[BUY_ORDER] = OrderTicket();
                  break;
               case OP_SELL:
                  ticketCnts[SELL_ORDER]++;
                  ticketNums[SELL_ORDER] = OrderTicket();
                  break;
               case OP_BUYSTOP:
                  ticketCnts[BUY_STOP]++;
                  ticketNums[BUY_STOP] = OrderTicket();
                  break;
               case OP_SELLSTOP:
                  ticketCnts[SELL_STOP]++;
                  ticketNums[SELL_STOP] = OrderTicket();
                  break;
               default:
                  msg=StringConcatenate( __FUNCTION__," order detected of invalid type for this EA: ",IntegerToString(orderType) );
                  Comment(msg); Print(msg);
                  break;
             }
          }
       }
    }
   displayAllOrders();
   return( openTrades );
 }
void closeAllEAOrders(const int& slippage)
 {
	for(int outerCnt=OrdersTotal()-1; outerCnt>=0; outerCnt--)
	 {
	   if( MOrderSelect(outerCnt) )
	    {
         if( (OrderSymbol() == Symbol()) && (OrderMagicNumber() == MAGIC_NUM) ) 
          {		
    		   if( (OrderType() ==  OP_SELLSTOP) )
    		    {
    		      MOrderDelete(OrderTicket());
    		    }
    		   else
    		    {
    		      ticketCnts[SELL_STOP]--;
    		    }		
    		   if( (OrderType() ==  OP_BUYSTOP) )
    		    {
    		      MOrderDelete(OrderTicket());
    		    }
    		   else
    		    {
    		      ticketCnts[BUY_STOP]--;
    		    }			
    			if( (OrderType() ==  OP_BUY) )
    			   if( !OrderClose(OrderTicket(),OrderLots(),Bid,slippage,clrBlue))
    			    {
    			      int errorCode = GetLastError();
    			      msg = StringConcatenate(__FUNCTION__," Buy order close for ",IntegerToString(OrderTicket())," failed, error: ",IntegerToString(errorCode),", ",ErrorDescription(errorCode));
    			      Comment(msg); Print(msg);
    			    }
    			   else
    			    {
    			      ticketCnts[BUY_ORDER]--;
    			    }
    			if( (OrderType() ==  OP_SELL) )
    			   if( !OrderClose(OrderTicket(),OrderLots(),Ask,slippage,clrRed))
    			    {
    			      int errorCode = GetLastError();
    			      msg = StringConcatenate(__FUNCTION__," Sell order close for ",IntegerToString(OrderTicket())," failed, error: ",IntegerToString(errorCode),", ",ErrorDescription(errorCode));
    			      Comment(msg); Print(msg);
    			    }
    			   else
    			    {
    			      ticketCnts[SELL_ORDER]--;
    			    }
          }
       }
    }
 }
bool MOrderDelete( const int ticket )
 {
   bool deleteSuccess = true;
   if( !OrderDelete(ticket) )
    {
      int errorCode = GetLastError();
      msg = StringConcatenate(__FUNCTION__," Order delete for ",IntegerToString(OrderTicket())," failed, error: ",IntegerToString(errorCode),", ",ErrorDescription(errorCode));
      Comment(msg); Print(msg);
      deleteSuccess = false;
    }
  return ( deleteSuccess );
 }
bool MOrderSelect(const int& cnt)
 {
   bool result = true;
   if( OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES) == false )
    {
      result = false;
      msg = StringConcatenate(__FUNCTION__," Order Select failed, position: ",IntegerToString(cnt),", Error: ",IntegerToString(GetLastError()),", ",ErrorDescription(GetLastError()));
      Comment(msg); Print(msg);
    }
   return(result);
 }
//
bool MOrderSend( const string symbol, const int cmd, const double price, const int slippage,
                 const double stopLoss, const double takeProfit, const string comment="", const int magic=0,
                 const datetime expiration=0, const color arrow_color=CLR_NONE, const string source="")
 {
  bool result = true;
  double normPrice = NormalizeDouble(price,Digits);
  double normStopLoss = NormalizeDouble(stopLoss,Digits);
  double normTakeProfit = NormalizeDouble(takeProfit,Digits);
  double volume;
  if( LOTS_MODE == PCT_FREE_MARGIN )
   {
    int movementTicks = (int) (MathAbs(normPrice-normStopLoss)/_Point);
    volume = LotsForRisk(riskPct, movementTicks);
   }
  else 
   volume =FixedLots;
  if( OrderSend( symbol, cmd, volume, normPrice, slippage, normStopLoss, normTakeProfit, comment, magic, expiration, arrow_color ) == (-1) )
   {
      result = false;
      string cmdStr = getCommandTxt(cmd);
      int lastErr = GetLastError();
      msg = StringConcatenate(__FUNCTION__," ",cmdStr," Order Send failed, error: ",IntegerToString(lastErr),", ",ErrorDescription(lastErr),
         ", Price: ",DoubleToStr(normPrice,Digits),", stopLoss: ",DoubleToStr(normStopLoss,Digits),", takeprofit: ",DoubleToStr(normTakeProfit,Digits),", slippage: ",IntegerToString(slippage),", Source: ",source);
      Comment(msg); Print(msg);
   }
  else
   {
      string cmdStr = getCommandTxt(cmd);
      msg = StringConcatenate(__FUNCTION__," ",cmdStr," Order Send SUCCESS, Price: ",DoubleToStr(normPrice,Digits),", stopLoss: ",
                              DoubleToStr(normStopLoss,Digits),", takeprofit: ",DoubleToStr(normTakeProfit,Digits),", slippage: ",IntegerToString(slippage),", Source: ",source);
      Comment(msg); Print(msg);
   }
  return(result);
 }
string getCommandTxt( const int& cmd )
 {
   string cmdTxt = "";
   switch(cmd)
    {
      case OP_BUY:      cmdTxt = "OP_BUY "+DoubleToStr(Ask,Digits)+":";       break;
      case OP_SELL:     cmdTxt = "OP_SELL "+DoubleToStr(Bid,Digits)+":";      break;
      case OP_SELLSTOP: cmdTxt = "OP_SELLSTOP "+DoubleToStr(Bid,Digits)+":";  break;
      case OP_BUYSTOP:  cmdTxt = "OP_BUYSTOP "+DoubleToStr(Ask,Digits)+":";   break;
      default: cmdTxt = "Oher: "+IntegerToString(cmd); break;
    }
   return(cmdTxt);
 }
//========================
void displayAllCamarillalLines( void )
 {
   for(ENUM_CAMARILLA_IDX i=0; i<endCamarillaIdx; i++)
    {
      drawCamarillaLine(i);
      drawCamarillaText(i);
    }
 }
void drawCamarillaLine(const ENUM_CAMARILLA_IDX& idx)
 {
   datetime startTime = iTime(Symbol(),workCamarillaTF,0), endTime = Time[0]+(Period()*(60*5));
   manageHorizontalLine(camarillaLineNames[idx], camarillaVals[idx], startTime, endTime, camarillaLineColor[idx], camarillaLineStyle[idx]);
 }
void manageHorizontalLine(const string& objName, const double& linePrice, const datetime& startTime, const datetime& endTime, const color& lineColor, const ENUM_LINE_STYLE& lineStyle)
 {
   static long chartID = ChartID();
   if ( ObjectFind(chartID,objName) < 0 )
    {
      ObjectCreate    (chartID, objName, OBJ_TREND, WINDOW_ZERO,  startTime, linePrice, endTime, linePrice);
      ObjectSetInteger(chartID, objName, OBJPROP_COLOR,     lineColor);
      ObjectSetInteger(chartID, objName, OBJPROP_STYLE,         lineStyle);
      ObjectSetInteger(chartID, objName, OBJPROP_WIDTH,         1);
      ObjectSetInteger(chartID, objName, OBJPROP_BACK,      true);
      ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(chartID, objName, OBJPROP_SELECTED,  false);
      ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN,    true);
      ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, false); 
    }
   ObjectMove(chartID, objName, PRICE_POINT_0, startTime, linePrice);
   ObjectMove(chartID, objName, PRICE_POINT_1, endTime,   linePrice);
 }
void drawCamarillaText(const ENUM_CAMARILLA_IDX& idx)
 {
   datetime anchorTime = Time[0]+(Period()*(60*6));
   manageTextObject(camarillaTextNames[idx], camarillaLevelText(idx), camarillaVals[idx], anchorTime, clrWhite);
 }
string camarillaLevelText( const ENUM_CAMARILLA_IDX& idx)
 {
   string displayStr;
   switch (idx)
    {
      case H1_IDX: displayStr = "Stop Loss for Short at H1";  break;
      case L1_IDX: displayStr = "Stop Loss for Long at L1";  break;
      case H2_IDX: displayStr = "H2";  break;
      case L2_IDX: displayStr = "L2";  break;
      case H3_IDX: displayStr = "Buy at H3";  break;
      case L3_IDX: displayStr = "Sell at L3";  break;
      case H4_IDX: displayStr = "Long TP at H4";  break;
      case L4_IDX: displayStr = "Short TP at L4";  break;
      default:
         msg=StringConcatenate(__FUNCTION__,"called with invalid value: ",IntegerToString(idx));
         Comment(msg); Print(msg);
         break;
    }
   return(displayStr);
 }
//========================
void manageTextObject(const string& objName, string dispStr, const double& anchorPrice, const datetime& anchorTime, const color dispClr, const int fontSize = 9)
 {
   static long chartID = ChartID();
   if ( ObjectFind(chartID,objName) < 0 )
    {
      ObjectCreate    (chartID, objName, OBJ_TEXT, WINDOW_ZERO,  0, 0);
      ObjectSetString (chartID, objName, OBJPROP_FONT,      "Arial");
      ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE,  fontSize);
      ObjectSetDouble (chartID, objName, OBJPROP_ANGLE,     0.0); 
      ObjectSetInteger(chartID, objName, OBJPROP_COLOR,     dispClr);
      ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR,    ANCHOR_LEFT);    // ANCHOR_CENTER);
      ObjectSetInteger(chartID, objName, OBJPROP_BACK,      true); 
      ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(chartID, objName, OBJPROP_SELECTED,  false); 
      ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN,    true);
    }
   ObjectSetString(chartID, objName, OBJPROP_TEXT, dispStr);
   ObjectMove     (chartID, objName, PRICE_POINT_0, anchorTime, anchorPrice);
 }
//
double LotsForRisk(const double& freeMarginPct, const int& ticksToRisk)
{
   double minLot = MarketInfo(Symbol(), MODE_MINLOT); // Smallest part of a lot that can be opened.
   minLot = (minLot>0)?minLot:0.01;                   // on weekend, Marketingo has been observed to return 0; ensure there is a value.
   
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT); // Maximum number of lots that can be ordered.
   maxLot = (maxLot<1.0)?1.0:maxLot;                  //  on weekend, Marketingo has been observed to return 0; ensure there is a value.
            
   double oneTickValue = MarketInfo(Symbol(), MODE_TICKVALUE);  // MODE_TICKVALUE == Tick value in the deposit currency
   oneTickValue = (oneTickValue<_Point)?1.0:oneTickValue;
   
   double marginToRisk = AccountFreeMargin()*(freeMarginPct/100);   // Get the currency amount to risk.
   
   double minMovementCost = ticksToRisk * oneTickValue;     // Minumum amount of money for the price movement in the risk.
   double lotsForRisk = marginToRisk/minMovementCost;     // lots that the risk money can cover.
   
   lotsForRisk = MathFloor(lotsForRisk/minLot) * minLot;   /* removes digits that are too insignificant.
      could use NormalizeDouble, but this allows us to do it without knowing the actual number of significant digits. */
   if ( lotsForRisk < minLot )     // smallest possible part of a lot to open
      lotsForRisk = 0;
   if ( lotsForRisk > maxLot )
      maxLot = 10;
   
   return(lotsForRisk); 
}
//+------------------------------------------------------------------+
//| End                                                              |
//+------------------------------------------------------------------+
//