//+------------------------------------------------------------------+
//|                                            HitZilla RealTime.mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#define LT    0
#define GT    1
#define GTE   2
#define LTE   3
#define EQ    4
#define NEQ   5
#define ARR_RESERVE   1000

#define propVersion  "1.10"
#property version   propVersion

#property strict
#property indicator_chart_window


input int    MagicNumber = 755;
input string MagicNumbersToHedge          = "2601,2701,2801,2901"; // Magic Numbers to hedge
input bool   HedgeTheSignals = true; // Hedge the signal (false = same dir)
input bool   CreateFreshTrades = true; // Create fresh trades/baskets
input color  ColorBuy = clrAqua;
input color  ColorSell = clrOrange;

input bool   ShowSignalCounter = true; // Show signal counter
input bool   SaveScreenshot = false; // Save screenshot (at signal time)
input bool   AlertAtSignal = false; // Alert when signal
input bool   ShowDashboard = true; // Show dashboard (left)

string EAName = "HitZilla RT TopBottom";
string   globVarPrefix = "rt_";
struct structSignalLine {
   int     dir;
   datetime dt;
   double  price;
};
structSignalLine rec, signalLine[];

double   pip, bidPrev, askPrev, avgSignals, avgFlips, noOfDays;
double   upperPrice=0, lowerPrice=0, price;
int      size, chartWidth, periodPrev, signals[2], flips[2], startHourH1H4, orderType;
datetime lastCandle, lastCandleLower, lastPrepareTime;
bool     showDash2, firstTick=false, firstTickSinceInit=true;
string   rtMn[];
double rtPrice[2], rtWeight[2];
int mn=0, rtDir=0;
datetime rtTime[2];

int    x = 3, x2;
int    y = 15, y2 = 15;
int    txtLine, txtLines, txtLinesPrev;
int    txtLine2, txtLines2, txtLinesPrev2;

////////
struct structArr {
   datetime time;
   int dir;
};
structArr rec2, arrLabels[], arrLabelsTemp[];
datetime sortArr[][2];
//////

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){
   firstTickSinceInit=true;
   populateRtMnArr();
   if (IsTesting() == true) globVarPrefix = "bt"+globVarPrefix;
   if (IsTesting() == true) GlobalVariablesDeleteAll(globVarPrefix);
   pip = MarketInfo(Symbol(),MODE_POINT);
   if (Digits == 3 || Digits == 5) { pip = pip * 10; }
   // Gold
   if (Bid > 500) { pip = 0.1; }
   bidPrev = Bid;
   askPrev = Ask;
   periodPrev = -1;
   //updateColor();
   createButtons();
   scanSignals();
   // Remove graphical objects
   string objName;
   for (int i=ObjectsTotal()-1; i>=0; i--) {
      objName = ObjectName(0, i);
      if (ShowSignalCounter == false && (StringFind(objName, "BuyLabel_") >= 0 || StringFind(objName, "SellLabel_") >= 0) && StringFind(objName, "_"+IntegerToString(MagicNumber)+"_") >= 0) ObjectDelete(0, objName);
   }
   return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {
   if (ShowDashboard == true) deleteText();
   deleteButtons();
   ObjectsDeleteAll(0, "TradeLine_"+IntegerToString(MagicNumber)+"_"); 
   ObjectsDeleteAll(0, "OldLine_"+IntegerToString(MagicNumber)+"_"); 
   ObjectsDeleteAll(0, "Stats_"+IntegerToString(MagicNumber)+"_"); 
}

//+------------------------------------------------------------------+
//| 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[])
{
   if (DayOfWeek() == 6 || (DayOfWeek() == 0 && Hour() < 21)) return(0);

   txtLine = 0;
   y = 15;    
   x = 3;
   p(EAName + " " + propVersion + " (" + IntegerToString(MagicNumber) + ")");
   

   // ONLY ONCE PER CANDLE
   firstTick = false;
   if (iTime(Symbol(), Period(), 0) > lastCandle) {
      lastCandle = iTime(Symbol(), Period(), 0);
      firstTick = true;
      scanSignals();
   }
   
   for (int m=0; m<ArraySize(rtMn); m++) {
      mn = (int) rtMn[m];
      if (mn == 0) continue;
      // RT SIGNAL
      string rtPrefix = "rt_" + Symbol() +"_"+IntegerToString(mn) + "_";
      if (IsTesting() == true) rtPrefix = "bt"+rtPrefix;
      rtPrice[OP_BUY] = GlobalVariableGet(rtPrefix + "rtLatestBuy");
      rtTime[OP_BUY] = (datetime) GlobalVariableGet(rtPrefix + "rtLatestBuyTime");
      rtPrice[OP_SELL] = GlobalVariableGet(rtPrefix + "rtLatestSell");
      rtTime[OP_SELL] = (datetime) GlobalVariableGet(rtPrefix + "rtLatestSellTime");
      
      // CHECK FOR RT BUY SIGNAL
      if (rtPrice[OP_BUY] > 0 && rtTime[OP_BUY] > TimeCurrent()-60 && (rtTime[OP_BUY] > (datetime) globVarGet("rtLatestTime"+IntegerToString(mn)))) {
         print("RT BUY SIGNAL (MN: "+IntegerToString(mn)+"). Price: " + DoubleToString(rtPrice[OP_BUY], Digits));
         price = rtPrice[OP_BUY];
         globVarSet("rtLatestTime"+IntegerToString(mn), rtTime[OP_BUY]);
         if (HedgeTheSignals == true) orderType = OP_SELL; else orderType = OP_BUY;
         rtSignal(orderType, price);
      }
   
   
      // CHECK FOR RT SELL SIGNAL
      if (rtPrice[OP_SELL] > 0 && rtTime[OP_SELL] > TimeCurrent()-60 && (rtTime[OP_SELL] > (datetime) globVarGet("rtLatestTime"+IntegerToString(mn)))) {
         print("RT SELL SIGNAL (MN: "+IntegerToString(mn)+"). Price: " + DoubleToString(rtPrice[OP_SELL], Digits));
         price = rtPrice[OP_SELL];
         globVarSet("rtLatestTime"+IntegerToString(mn), rtTime[OP_SELL]);
         if (HedgeTheSignals == true) orderType = OP_BUY; else orderType = OP_SELL;
         rtSignal(orderType, price);
      }
   }
   

   p("Signal - Tot: " + IntegerToString(signals[OP_BUY]+signals[OP_SELL]) + ", Buy: " + IntegerToString(signals[OP_BUY]) + ", Sell: " + IntegerToString(signals[OP_SELL]));
   if (noOfDays > 0) avgSignals = (double)(signals[OP_BUY]+signals[OP_SELL])/noOfDays;
   else avgSignals = 0;
   p("Avg Signals - D1: " + DoubleToString(avgSignals, 1) + ", W1: " + DoubleToString(avgSignals*5, 0) + ", MN: " + DoubleToString(avgSignals*20.5, 0));
   p("Flips - Tot: " + IntegerToString(flips[OP_BUY]+flips[OP_SELL]) + ", Buy: " + IntegerToString(flips[OP_BUY]) + ", Sell: " + IntegerToString(flips[OP_SELL]));
   if (noOfDays > 0) avgFlips = (double)(flips[OP_BUY]+flips[OP_SELL])/noOfDays;
   else avgFlips = 0;
   p("Avg Flips - D1: " + DoubleToString(avgFlips, 1) + ", W1: " + DoubleToString(avgFlips*5, 0) + ", MN: " + DoubleToString(avgFlips*20.5, 0));
   if (flips[OP_BUY]+flips[OP_SELL] > 0) p("Signal To Flip Ratio: " + DoubleToString((double)(signals[OP_BUY]+signals[OP_SELL]) / (flips[OP_BUY]+flips[OP_SELL]), 2)); else p("Signal To Flip Ratio: 0.00");
   p("Last seq: " + DoubleToString(globVarGet("seq"), 0)); 
     
   
   cleanUpText();
   WindowRedraw();
   bidPrev = Bid;
   askPrev = Ask;
   periodPrev = Period();
   firstTickSinceInit=false;
   return(rates_total);
}
////////////////////////////////////////////////////////////////////////////
bool cd (double a,int type,double b){
  double point = 0.00001;
  // See http://forum.mql4.com/45053/page4
  // 0 compare doesn't need this function
  switch(type){
    case LT: return(b-a>point/2.);
    case GT: return(a-b>point/2.);
    case GTE: return(a-b>-point/2.);
    case LTE: return(b-a>-point/2.);
    case EQ: return(!(MathAbs(a-b)>point/2.));
    case NEQ: return(MathAbs(a-b)>point/2.);
  }
  return(false);
}
////////////////////////////////////////////////////////////////////
void p (string newString) {

   if (ShowDashboard == false) return;
   
   txtLine++;
   color colour;
   string font;
   if (txtLine == 1) {
      colour = PaleGreen;
      font = "Arial Black";
   } 
   else {
      colour = White;
      font = "Arial";
   }
   ObjectCreate("txt_bg"+IntegerToString(txtLine), OBJ_LABEL, 0, 0, 0);  
   ObjectSet("txt_bg"+IntegerToString(txtLine), OBJPROP_CORNER, 0); 
   ObjectSet("txt_bg"+IntegerToString(txtLine), OBJPROP_XDISTANCE, x); 
   ObjectSet("txt_bg"+IntegerToString(txtLine), OBJPROP_YDISTANCE, y);
   ObjectSetText("txt_bg"+IntegerToString(txtLine),"gggggggggggggg",16, "Webdings", MidnightBlue);

   ObjectCreate("txt_text"+IntegerToString(txtLine), OBJ_LABEL, 0, 0, 0);  
   ObjectSet("txt_text"+IntegerToString(txtLine), OBJPROP_CORNER, 0); 
   ObjectSet("txt_text"+IntegerToString(txtLine), OBJPROP_XDISTANCE, x+4); 
   ObjectSet("txt_text"+IntegerToString(txtLine), OBJPROP_YDISTANCE, y+4);
   ObjectSetText("txt_text"+IntegerToString(txtLine),newString,8, font, colour);
   
   y = y + 16;
}
//////////////////////////////////////////////////////////////////////
void deleteText () {
   string objectName;
   for (int i=ObjectsTotal()-1; i >= 0; i--) {
      objectName = ObjectName(i);
      if (StringSubstr(objectName, 0,4) == "txt_" || StringSubstr(objectName, 0,5) == "txt2_" || StringFind(objectName, "deltalabel") >= 0 || StringFind(objectName, "tlBuy") >= 0 || StringFind(objectName, "tlSell") >= 0 || StringFind(objectName, "Zz") >= 0 || StringFind(objectName, "Bo") >= 0) {
         ObjectDelete(objectName); 
      }   
   }    
}
/////////////////////////////////////////////////////////////////////
void cleanUpText () {
   txtLines = txtLine;
   for (int i=txtLine+1; i<=txtLinesPrev; i++) {
      ObjectDelete("txt_bg"+IntegerToString(i)); 
      ObjectDelete("txt_text"+IntegerToString(i)); 
   }
   txtLinesPrev = txtLines;
}
/////////////////////////////////////////////////////////////////////
void cleanUpText2 () {
   txtLines2 = txtLine2;
   for (int i=txtLine2+1; i<=txtLinesPrev2; i++) {
      ObjectDelete("txt2_bg"+IntegerToString(i)); 
      ObjectDelete("txt2_text"+IntegerToString(i)); 
   }
   txtLinesPrev2 = txtLines2;
}
/////////////////////////////////////////////////////////////////////
void print (string s) {
   if (true) Print(TimeToString(TimeCurrent(), TIME_SECONDS) + ": " + s);
}
////////////////////////////////////////////////////////////////////
void globVarSet (string name, double value) {
   GlobalVariableSet(globVarPrefix + Symbol() +"_"+IntegerToString(MagicNumber) + "_" + name, value);
}
double globVarGet (string name) {
   return (GlobalVariableGet(globVarPrefix + Symbol() +"_"+IntegerToString(MagicNumber) + "_" + name));
}
bool globVarCheck (string name) {
   bool returnVal = GlobalVariableCheck(globVarPrefix + Symbol() +"_"+IntegerToString(MagicNumber) + "_" + name);
   return (returnVal);
}
int globVarsDelAll (string prefix) {
   return (GlobalVariablesDeleteAll(globVarPrefix + Symbol() +"_"+IntegerToString(MagicNumber) + "_" + prefix));
}
/////////////////////////////////////////////////////////////////////
string StringRightPad(string str, int n=1, string str2=" ")
//+------------------------------------------------------------------+
// Appends occurrences of the string STR2 to the string STR to make a string N characters long
// Usage:    string x=StringRightPad("ABCDEFG",9," ")  returns x = "ABCDEFG  "
{
  return(str + StringRepeat(str2,n-StringLen(str)));
}
///////////////////////////////////////////////////////////////////////
string StringRepeat(string str, int n=1)
//+------------------------------------------------------------------+
// Repeats the string STR N times
// Usage:    string x=StringRepeat("-",10)  returns x = "----------"
{
  string outstr = "";
  for(int i=0; i<n; i++)  {
    outstr = outstr + str;
  }
  return(outstr);
}
/////////////////////////////////////////////////////////////////////////
double iif (bool condition, double ifTrue, double ifFalse ) {
    if (condition == true) return( ifTrue );
    else return( ifFalse );
}
string iifStr (bool condition, string ifTrue, string ifFalse ) {
    if( condition == true) return( ifTrue );
    else return( ifFalse );
}
int iifInt (bool condition, int ifTrue, int ifFalse ) {
    if (condition == true) return( ifTrue );
    else return( ifFalse );
}
datetime iifDt (bool condition, datetime ifTrue, datetime ifFalse ) {
    if (condition == true) return( ifTrue );
    else return( ifFalse );
}
///////////////////////////////////////////////////////////////////////
void updateColor () {
   string objName;
   for (int i=0; i<ObjectsTotal(); i++) {
      objName = ObjectName(i);
      if (StringFind(objName, "_"+IntegerToString(MagicNumber)+"_") < 0) continue;
      if (StringFind(objName, "ZzTLBuy_") >= 0) ObjectSetInteger(0, objName, OBJPROP_COLOR, ColorBuy);
      if (StringFind(objName, "ZzTLSell_") >= 0) ObjectSetInteger(0, objName, OBJPROP_COLOR, ColorSell);
      if (StringFind(objName, "ZzLabelBuy") >= 0) ObjectSetInteger(0, objName, OBJPROP_COLOR, ColorBuy);
      if (StringFind(objName, "ZzLabelSell") >= 0) ObjectSetInteger(0, objName, OBJPROP_COLOR, ColorSell);
   }
}
///////////////////////////////////////////////////////////////////////
void createButtons () {
   createButton("rtbuttonReset", "Reset Seq", 493, 14, 70, 20, clrRed, clrBlack);
   //createButton("rtbuttonBuy", "Buy", 493, 14, 70, 20, ColorBuy, clrBlack);
   //createButton("rtbuttonSell", "Sell", 573, 14, 70, 20, ColorSell, clrBlack);
}
///////////////////////////////////////////////////////////////////////
void deleteButtons () {
   string name;
   for (int i=ObjectsTotal()-1; i>=0; i--) {
      name = ObjectName(i);
      if (StringSubstr(name, 0, 8) == "rtbutton") ObjectDelete(name);
   }
}
//////////////////////////////////////////////////////////////////////
void createButton (string objName, string objText, int xDistance, int yDistance, int xSize, int ySize, color buttonCol = clrRed, color textCol = clrWhite) {
   long   chartId = 0;
   ResetLastError();
   if (ObjectFind(0, objName) < 0) {
      if( ObjectCreate(chartId, objName, OBJ_BUTTON, 0, 0, 0) == false) {
         Print(__FUNCTION__, ": failed to create the button! Error code = ",GetLastError());
         return;
      }
   }
   ObjectSetInteger(chartId, objName, OBJPROP_XDISTANCE, xDistance);
   ObjectSetInteger(chartId, objName, OBJPROP_YDISTANCE, yDistance);
   ObjectSetInteger(chartId, objName, OBJPROP_XSIZE, xSize);
   ObjectSetInteger(chartId, objName, OBJPROP_YSIZE, ySize);
   ObjectSetInteger(chartId, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetString(chartId, objName, OBJPROP_TEXT, objText);
   ObjectSetString(chartId, objName, OBJPROP_FONT, "Arial");
   ObjectSetInteger(chartId, objName, OBJPROP_FONTSIZE, 10);
   ObjectSetInteger(chartId, objName, OBJPROP_COLOR, textCol);
   ObjectSetInteger(chartId, objName, OBJPROP_BGCOLOR, buttonCol);
   ObjectSetInteger(chartId, objName, OBJPROP_BORDER_COLOR, clrGray);
   ObjectSetInteger(chartId, objName, OBJPROP_BACK, false);
   ObjectSetInteger(chartId, objName, OBJPROP_STATE, false);
   ObjectSetInteger(chartId, objName, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(chartId, objName, OBJPROP_SELECTED, false);
   ObjectSetInteger(chartId, objName, OBJPROP_HIDDEN, false);
   ObjectSetInteger(chartId, objName, OBJPROP_ZORDER, 0);
}
////////////////////////////////////////////////////////////////////////////////////////
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {
   if (sparam == "rtbuttonReset") { 
      globVarSet("seq", 0);
   }
}
////////////////////////////////////////////////////////////////////////////////////////
void printPoint (string objName, string text, int location, datetime time) {
   int shift = iBarShift(Symbol(), Period(), time, false);
   if (shift >= Bars-2) return;
   double objDistance = 0.7 * iATR(Symbol(), Period(), MathMin(7, Bars-shift-1), shift);
   color col;
   double lPrice;
   int anchorPoint;
   if (location == -1) { anchorPoint = ANCHOR_UPPER; lPrice = Low[shift] - objDistance; col = (color) ColorSell; }
   else { anchorPoint = ANCHOR_LOWER; lPrice = High[shift] + objDistance; col = (color) ColorBuy; }
   ObjectCreate(objName, OBJ_TEXT, 0, time, lPrice); 
   ObjectSetText(objName, text, 10, "Arial", col);
   ObjectSetInteger(0, objName, OBJPROP_ANCHOR, anchorPoint);
}
/////////////////////////////////////////////////////////////////////////////
void rtSignal (int oType, double pPrice, bool sendToEa=true) {
   string alertMsg, objNameTxt;
   if (firstTickSinceInit == true) sendToEa = false;
   if (oType == OP_BUY) {
      globVarSet("seq", globVarGet("seq") + 1);
      if (sendToEa == true) {
         globVarSet("rtLatestBuy", pPrice);
         globVarSet("rtLatestBuyTime", TimeCurrent());
         globVarSet("rtLatestBuySeq", globVarGet("seq"));
         globVarSet("rtCreateFreshTradeBuy", iif(CreateFreshTrades, 1, 0));
         alertMsg = "RT HEDGE Buy signal";
      }
      if (ShowSignalCounter) {
         objNameTxt = "BuyLabel_"+IntegerToString(TimeCurrent())+"_"+DoubleToString(Bid, Digits)+"_"+IntegerToString(MagicNumber)+"_";
         ObjectCreate(objNameTxt, OBJ_TEXT, 0, TimeCurrent(), Bid);
         ObjectSetText(objNameTxt, DoubleToString(globVarGet("seq"), 0), 8, "Arial Black", ColorBuy);
      }
   }
   else {
      globVarSet("seq", globVarGet("seq") + 1);
      if (sendToEa == true) {
         globVarSet("rtLatestSell", pPrice);
         globVarSet("rtLatestSellTime", TimeCurrent());
         globVarSet("rtLatestSellSeq", globVarGet("seq"));
         globVarSet("rtCreateFreshTradeSell", iif(CreateFreshTrades, 1, 0));
         alertMsg = "RT HEDGE Sell signal";
      }
      if (ShowSignalCounter) {
         objNameTxt = "SellLabel_"+IntegerToString(TimeCurrent())+"_"+DoubleToString(Bid, Digits)+"_"+IntegerToString(MagicNumber)+"_";
         ObjectCreate(objNameTxt, OBJ_TEXT, 0, TimeCurrent(), Bid);
         ObjectSetText(objNameTxt, DoubleToString(globVarGet("seq"), 0), 8, "Arial Black", ColorSell);
      }
   }
   
   // Alert
   if (AlertAtSignal == true && sendToEa == true) {
      Alert(TimeToString(TimeCurrent(), TIME_SECONDS) + " " + Symbol() + ": " + alertMsg + " " + DoubleToString(pPrice, Digits));
   }

   // Screenshot   
   if (SaveScreenshot == true) {
      string gifName = "RTHedge_Screenshots\\"+Symbol()+"\\"+TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)+".gif";
      StringReplace(gifName, ":", ".");
      if (WindowScreenShot(gifName, 1024, 768) == false) {
         Print("Error creating file: Error code: " + IntegerToString(GetLastError()));
      }  
   }
}
///////////////////////////////////////////////////////////////////////////
void scanSignals () {
   if (ShowDashboard == false) return;
   string objName;
   int tot=0, dir=0, dirPrev=0;
   datetime t;
   bool todayExists = false, firstDayExists=false;
   string activeDatesArr[];
   ArrayResize(activeDatesArr, 0, 500);
   ArrayResize(arrLabels, 0, 1000);
   signals[OP_BUY] = 0;
   signals[OP_SELL] = 0;
   flips[OP_BUY] = 0;
   flips[OP_SELL] = 0;
   size = 0;
   for (int i=0; i<ObjectsTotal(); i++) {
      objName = ObjectName(i);
      t = (datetime) ObjectGet(objName, OBJPROP_TIME1);
      if (TimeDayOfWeek(t) == 0) t = StringToTime(TimeToString(t+24*3600, TIME_DATE));
      if (StringFind(objName, "Label_") < 0) continue;
      tot++;
      if (StringFind(objName, "BuyLabel_") >= 0) { signals[OP_BUY]++; dir = 1; }
      else if (StringFind(objName, "SellLabel_") >= 0) { signals[OP_SELL]++; dir = -1; }

      rec2.time = t;
      rec2.dir = dir;
      size = ArraySize(arrLabels);
      ArrayResize(arrLabels, size+1, 1000);
      arrLabels[size] = rec2;

      /////////////////////////////
      if (t >= iTime(Symbol(), PERIOD_D1, 0)) todayExists = true;
      bool dateExists = false;
      for (int d=0; d<ArraySize(activeDatesArr); d++) {
         if (activeDatesArr[d] == TimeToString(t, TIME_DATE)) { dateExists = true; break; }
      }
      if (dateExists == false) {
         size = ArraySize(activeDatesArr);
         ArrayResize(activeDatesArr, size+1, 500);
         activeDatesArr[size] = TimeToString(t, TIME_DATE);
      }
   }
   noOfDays = ArraySize(activeDatesArr);
   if (todayExists == true) {
      double secondsNotToBeCounted = 24*3600 - (Hour()*3600 + Minute()*60 + Seconds()); 
      noOfDays = noOfDays - secondsNotToBeCounted / (24*3600);
   }
   sortArray(arrLabels, arrLabelsTemp, true);
   for (int i=0; i<ArraySize(arrLabels); i++) {
      rec2 = arrLabels[i];
      dir = rec2.dir;
      if (dir == 1 && dirPrev == -1) {
         flips[OP_BUY]++;
      }
      if (dir == -1 && dirPrev == 1) {
         flips[OP_SELL]++;
      }
      dirPrev = dir;
      //p(TimeToString(rec.time, TIME_SECONDS) + " " + rec.dir);
   }   
   
}
////////////////////////////////////////////////////////////////////////////////////////
void sortArray (structArr &arr[], structArr &arrTemp[], bool ascending = true) {
   if (ArraySize(arr) == 0) return;
   ArrayResize(sortArr, ArraySize(arr), ARR_RESERVE);
   // Copy the original arr to a temp arr
   ArrayResize(arrTemp, ArraySize(arr), ARR_RESERVE);
   ArrayCopy(arrTemp, arr);
   // Populate sortArr with the sort field from arr. In this case "profit".
   for (int i=0; i<ArraySize(arr); i++) {
      rec2 = arr[i];
      sortArr[i][0] = rec2.time;
      sortArr[i][1] = i;
   }
   // Sort sortArr
   if (ascending == true) ArraySort(sortArr,WHOLE_ARRAY,0,MODE_ASCEND);
   else ArraySort(sortArr,WHOLE_ARRAY,0,MODE_DESCEND);

   // Re-populate the original arr
   for (int i=0; i<ArraySize(arrTemp); i++) {
      arr[i] = arrTemp[(int) sortArr[i][1]];
   }
}
////////////////////////////////////////////////////////////////////////
void populateRtMnArr () {
   string rtMnStr = MagicNumbersToHedge;
   StringReplace(rtMnStr, " ", "");
   StringSplit(rtMnStr, StringGetCharacter(",",0), rtMn);
}
