//+------------------------------------------------------------------+
//|  Show what Single Bar Values with different ways of getting them |
//+------------------------------------------------------------------+
#property copyright "https://www.forexfactory.com/lukeb"
#property link      ""
#property version   "1.00"
#property description "Display Single Bar Values."
#property strict
#include <stdlib.mqh>
//----
#property indicator_chart_window

const int WINDOW_ZERO = 0;
const int CHARTWINDOW = 0;
const int NOSHIFT     = 0;
const int ONEBAR      = 1;
enum ANCHOR_POINTS {ANCHOR_POINT_ZERO, ANCHOR_POINT_ONE};
enum BAR_INFO_MECH {ARRAYS, IMAS, COPY_FUNCS, RATES};
enum PERIOD_PARTS  {PART_ONE, PART_TWO};
ENUM_TIMEFRAMES    workingTF;
ENUM_MA_METHOD     workingMaMethod;
BAR_INFO_MECH      workingMechanism;
//
extern int IndiOffsetNum = 3; // Unique Instance Number
//====================================
enum   ENUM_CTRL_IDX    { BAR_UP,      BAR_DN,       PERIOD_START,     PERIOD_END,       INFO_MECH,    MA_MODE,     endObjIdx};
string ctrlObjName[] = { "BAR_UP",    "BAR_DN",     "PERIOD_START",  "PERIOD_END",      "INFO_MECH",  "MODE_PROMPT"  };
int    objXPos[]     = { 10,          60,           170,              220,              270,          320            };
int    objYPos[]     = { 0,           0,            0,                0,                0,            0              };
color  objClr[]      = {clrLimeGreen, clrLimeGreen, clrLimeGreen,     clrLimeGreen,     clrLimeGreen, clrLimeGreen   };
//====================================
enum   INF_DISP_IDX    {INFO_HDR,        INFO_OPEN,      INFO_HIGH,      INFO_LOW,       INFO_CLOSE,      INFO_TIME,  endInfoIdx};
string infObjName[]  = {"INFO_HDR",      "INFO_OPEN",    "INFO_HIGH",    "INFO_LOW",     "INFO_CLOSE",    "INFO_TIME"           };
int    infXPos[]     = { 10,             10,             10,             10,             10,              10                    };
int    infYPos[]     = { 0,              0,              0,              0,              0,               0                     };
color  infClr[]      = { clrYellowGreen, clrYellowGreen, clrYellowGreen, clrYellowGreen, clrYellowGreen,  clrYellowGreen        };
//====================================
struct BoxStruct
 {
   string editBoxName;
   int displayValue;
   int xPos;
   int yPos;
 } barNumBox = {"BarNumBox", 1, 110, 30};
struct RectStruct
 {
   string           rectName;
   ENUM_LINE_STYLE lineStyle;
   int             lineWidth;
   color           fillClr;
   double          topPrice, bottomPrice;
   datetime        startTime, endTime;
 } barRectangle = {"BarRectangle", STYLE_DASHDOT, 1, clrOldLace, 0,0,0 ,0};
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
string shortName = "SingleBarIMAValues";
int OnInit()
 {
   int succeeded = INIT_SUCCEEDED;
   shortName += (IntegerToString(IndiOffsetNum));
   IndicatorShortName(shortName);
   workingTF        = getPeriodCurrent();
   workingMaMethod  = MODE_SMA;
   workingMechanism = RATES;
   for( ENUM_CTRL_IDX i=0; i<endObjIdx; i++ )
    {
      objYPos[i] = 10*IndiOffsetNum;
      ctrlObjName[i] += IntegerToString(IndiOffsetNum);
    }
   for( INF_DISP_IDX  i=0; i<endInfoIdx; i++ )
    {
      infYPos[i] = (16*IndiOffsetNum)+(i*18);
      infObjName[i] += IntegerToString(IndiOffsetNum);
    }
   barNumBox.editBoxName += IntegerToString(IndiOffsetNum);
   barRectangle.rectName += IntegerToString(IndiOffsetNum);
   //----
   runDisplay(High, Low, Close, Open, Time);
   return(succeeded);
 }
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
   long chartID = ChartID();
   for(ENUM_CTRL_IDX i=0; i<endObjIdx; i++)
    {
      ObjectDelete(chartID,ctrlObjName[i]);
    }
   for( INF_DISP_IDX  i=0; i<endInfoIdx; i++ )
    {
      ObjectDelete(chartID,infObjName[i]);
    }
   // ObjectsDeleteAll(chartID);
   ObjectDelete(chartID,barNumBox.editBoxName);
   ObjectDelete(chartID,barRectangle.rectName);
 }
//+------------------------------------------------------------------+
//| expert chart event function                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
 {
   bool display = false;
   if( (id==CHARTEVENT_OBJECT_ENDEDIT) && (sparam==barNumBox.editBoxName) )
    {
      int boxValue = (int) StringToInteger(ObjectGetString(WINDOW_ZERO,barNumBox.editBoxName,OBJPROP_TEXT,0));
      int bars = iBars(_Symbol,workingTF);
      if( !((boxValue>-1) && (boxValue<bars)) )
       {
         barNumBox.displayValue = 1;
       }
      else
       {
         barNumBox.displayValue = boxValue;
       }
      display=true;
    }
   if(id==CHARTEVENT_OBJECT_CLICK)
    {
      if(sparam==ctrlObjName[BAR_UP])
       {
         int bars = iBars(_Symbol,workingTF);
         if( (barNumBox.displayValue+1)<bars )
          {
            barNumBox.displayValue++;
          }
         else
          {
            barNumBox.displayValue = 0;
          }
         display=true;
       }
      if(sparam==ctrlObjName[BAR_DN])
       {
         int bars = iBars(_Symbol,workingTF);
         if( (barNumBox.displayValue-1)>=0 )
          {
            barNumBox.displayValue--;
          }
         else
          {
            barNumBox.displayValue = (bars-1);
          }
         display=true;
       }
      if( sparam==ctrlObjName[PERIOD_START] )
       {
         bool set = false;
         while (!set)
          {
            workingTF = getNextTF(workingTF);
            int bars = iBars(_Symbol,workingTF);
            if( barNumBox.displayValue < bars )
             {
               set=true;
             }
          }
         display=true;;
       }
      if( sparam==ctrlObjName[PERIOD_END] )
       {
         bool set = false;
         while (!set)
          {
            workingTF = getPreviousTF(workingTF);
            int bars = iBars(_Symbol,workingTF);
            if( barNumBox.displayValue < bars )
             {
               set=true;
             }
          }
         display=true;;
       }
      if(sparam==ctrlObjName[INFO_MECH])
       {
         workingMechanism = getNextMec(workingMechanism);
         display=true;
       }
      if(sparam==ctrlObjName[MA_MODE])
       {
            workingMaMethod = getNextSmoothingMode(workingMaMethod);
            display=true;
       }
    }
   if( display == true )
    {
      runDisplay(High, Low, Close, Open, Time);
    }
 }
//+------------------------------------------------------------------+
//| 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( ( rates_total - prev_calculated > 0 ) && ( prev_calculated>0 ) )// new bar and not the first time
    {
      runDisplay(high, low, close, open, time);
    }
   return(rates_total);
 }
void displayControls(void)
 {
   displayABox(barNumBox);
   for(ENUM_CTRL_IDX i=0; i<endObjIdx; i++)
    {
      string dispText = getPromptTxt(i);
      manageALabel(ctrlObjName[i], dispText, objXPos[i], objYPos[i], objClr[i], 10);
    }
 }
void runDisplay(const double &high[], const double &low[], const double &close[], const double &open[], const datetime& time[])
 {
   displayControls();
   int barNum = barNumBox.displayValue;
   string barStr = IntegerToString(barNum);
   double barClose, barHigh, barLow, barOpen, price[];
   datetime theTime, barTime[];
   string hdrString, closeString, openString, highString, lowString, timeString;
   MqlRates rates[];
   switch (workingMechanism)  // enum BAR_INFO_MECH {ARRAYS, IMAS, COPY_FUNCS, RATES};
    {
      case ARRAYS:
         barClose = close[barNum];
         barHigh  = high[barNum];
         barLow   = low[barNum];
         barOpen  = open[barNum];
         theTime  = time[barNum];
         hdrString   = StringConcatenate("Bar: ",IntegerToString(barNum),"; Range: ",DoubleToString(barHigh-barLow,_Digits) );
         closeString = StringConcatenate("Close[",barStr,"] = ",DoubleToStr(close[barNum],_Digits) );
         openString  = StringConcatenate("Open[",barStr,"]  = ",DoubleToStr(open[barNum],_Digits) );
         highString  = StringConcatenate("High[",barStr,"]  = ",DoubleToStr(high[barNum],_Digits) );
         lowString   = StringConcatenate("Low[",barStr,"]   = ",DoubleToStr(low[barNum],_Digits) );
         timeString  = StringConcatenate("Time[",barStr,"]  = ",TimeToString(theTime,TIME_DATE|TIME_MINUTES) );
         break;
      case IMAS:
         {
            string modeDesc = getSmoothingModeDescription(workingMaMethod);
            barClose = iMA(_Symbol,workingTF,ONEBAR,NOSHIFT,workingMaMethod,PRICE_CLOSE,barNum);
            barHigh  = iMA(_Symbol,workingTF,ONEBAR,NOSHIFT,workingMaMethod,PRICE_HIGH,barNum);
            barLow   = iMA(_Symbol,workingTF,ONEBAR,NOSHIFT,workingMaMethod,PRICE_LOW,barNum);
            barOpen  = iMA(_Symbol,workingTF,ONEBAR,NOSHIFT,workingMaMethod,PRICE_OPEN,barNum);
            theTime  = iTime(_Symbol,workingTF,barNum);
            hdrString   = StringConcatenate("Bar: ",IntegerToString(barNum),"; Range: ",DoubleToString(barHigh-barLow,_Digits) );
            closeString = StringConcatenate("iMA(_Symbol,TF,ONEBAR,NOSHIFT,",modeDesc,",PRICE_CLOSE,",barStr,") = ",DoubleToStr(barClose,_Digits) );
            openString  = StringConcatenate("iMA(_Symbol,TF,ONEBAR,NOSHIFT,",modeDesc,",PRICE_OPEN,",barStr,")  = ",DoubleToStr(barOpen,_Digits) );
            highString  = StringConcatenate("iMA(_Symbol,TF,ONEBAR,NOSHIFT,",modeDesc,",PRICE_HIGH,",barStr,")  = ",DoubleToStr(barHigh,_Digits) );
            lowString   = StringConcatenate("iMA(_Symbol,TF,ONEBAR,NOSHIFT,",modeDesc,",PRICE_LOW,",barStr,")    = ",DoubleToStr(barLow,_Digits) );
         }
         break;
      case COPY_FUNCS:
         CopyClose(_Symbol,workingTF,barNum,ONEBAR,price);  barClose = price[0];
         CopyHigh(_Symbol,workingTF,barNum,ONEBAR,price);   barHigh = price[0];
         CopyLow(_Symbol,workingTF,barNum,ONEBAR,price);    barLow = price[0];
         CopyOpen(_Symbol,workingTF,barNum,ONEBAR,price);   barOpen = price[0];
         CopyTime(_Symbol,workingTF,barNum,ONEBAR,barTime); theTime = barTime[0];
         hdrString   = StringConcatenate("Bar: ",IntegerToString(barNum),"; Range: ",DoubleToString(barHigh-barLow,_Digits) );
         closeString = StringConcatenate("CopyClose(_Symbol,TF,",barStr,"ONEBAR,PRICE_ARRAY) = ",DoubleToStr(barClose,_Digits) );
         openString  = StringConcatenate("CopyOpen(_Symbol,TF,",barStr,"ONEBAR,PRICE_ARRAY)  = ",DoubleToStr(barOpen,_Digits) );
         highString  = StringConcatenate("CopyHigh(_Symbol,TF,",barStr,"ONEBAR,PRICE_ARRAY) = ",DoubleToStr(barHigh,_Digits) );
         lowString   = StringConcatenate("CopyLow(_Symbol,TF,",barStr,"ONEBAR,PRICE_ARRAY) = ",DoubleToStr(barLow,_Digits) );
         timeString  = StringConcatenate("CopyTime(_Symbol,TF,",barStr,"ONEBAR,TIME_ARRAY) = ",TimeToString(theTime,TIME_DATE|TIME_MINUTES) );
         break;
      case RATES:
         CopyRates(_Symbol,workingTF,barNum,ONEBAR,rates); // rates.time, rates.open, rates.high, rates.low, rates.close and more
         barClose = rates[0].close;
         barHigh  = rates[0].high;
         barLow   = rates[0].low;
         barOpen  = rates[0].open;
         theTime  = rates[0].time;
         hdrString   = StringConcatenate("Bar: ",IntegerToString(barNum),"; Range: ",DoubleToString(barHigh-barLow,_Digits) );
         closeString = StringConcatenate("rates[0].close = ",DoubleToStr(barClose,_Digits) );
         openString  = StringConcatenate("rates[0].open  = ",DoubleToStr(barOpen,_Digits) );
         highString  = StringConcatenate("rates[0].high  = ",DoubleToStr(barHigh,_Digits) );
         lowString   = StringConcatenate("rates[0].low   = ",DoubleToStr(barLow,_Digits) );
         timeString  = StringConcatenate("rates[0].time  = ",TimeToString(theTime,TIME_DATE|TIME_MINUTES) );
         break;
      default:
         hdrString = StringConcatenate("Bad Mechanism: ",IntegerToString(workingMechanism));
         barClose = Close[barNum];
         barHigh  = High[barNum];
         barLow   = Low[barNum];
         barOpen  = Open[barNum];
         theTime  = Time[barNum];
         break;
    }
   //
   manageALabel(infObjName[INFO_HDR], hdrString, infXPos[INFO_HDR], infYPos[INFO_HDR], infClr[INFO_HDR], 11);
   manageALabel(infObjName[INFO_CLOSE], closeString, infXPos[INFO_CLOSE], infYPos[INFO_CLOSE], infClr[INFO_CLOSE], 11);
   manageALabel(infObjName[INFO_OPEN], openString, infXPos[INFO_OPEN], infYPos[INFO_OPEN], infClr[INFO_OPEN], 11);
   manageALabel(infObjName[INFO_HIGH], highString, infXPos[INFO_HIGH], infYPos[INFO_HIGH], infClr[INFO_HIGH], 11);
   manageALabel(infObjName[INFO_LOW], lowString, infXPos[INFO_LOW], infYPos[INFO_LOW], infClr[INFO_LOW], 11);
   manageALabel(infObjName[INFO_TIME], timeString, infXPos[INFO_TIME], infYPos[INFO_TIME], infClr[INFO_TIME], 11);
   //
   barRectangle.topPrice    = barHigh;
   barRectangle.bottomPrice = barLow;
   barRectangle.startTime   = theTime;
   CopyTime(_Symbol,_Period,NOSHIFT,ONEBAR,barTime);
   if( barTime[0] < (theTime+PeriodSeconds(workingTF)) )
    {
      barRectangle.endTime = barTime[0]+PeriodSeconds(PERIOD_CURRENT);
    }
   else
    {
      barRectangle.endTime = theTime+PeriodSeconds(workingTF);
    }
   //
   makeARectangle(barRectangle);
 }
//
void displayABox( const BoxStruct& displayBox )
 {
   static long chartID = ChartID();
   string objName = displayBox.editBoxName;
   string displayStr = IntegerToString(displayBox.displayValue);
   if ( ObjectFind(chartID,objName) < 0 )
    {
      int dispWindow = WindowFind(shortName);
      dispWindow = (dispWindow>(-1))?dispWindow:0;
      ObjectCreate(chartID,objName,OBJ_EDIT,dispWindow,     0, 0);
      ObjectSetInteger(chartID,objName,OBJPROP_FONTSIZE,    10);
      ObjectSetString (chartID,objName,OBJPROP_FONT,        "Arial");
      ObjectSetInteger(chartID,objName,OBJPROP_COLOR,       clrCornflowerBlue);
      ObjectSetInteger(chartID,objName,OBJPROP_BORDER_COLOR,clrBlack); 
      ObjectSetInteger(chartID,objName,OBJPROP_BGCOLOR,     clrLightGray);
      ObjectSetInteger(chartID,objName,OBJPROP_XSIZE,       50); 
      ObjectSetInteger(chartID,objName,OBJPROP_YSIZE,       20);
      ObjectSetInteger(chartID,objName,OBJPROP_ALIGN,       ALIGN_CENTER); 
      ObjectSetInteger(chartID,objName,OBJPROP_CORNER,      CORNER_LEFT_UPPER);
      ObjectSetInteger(chartID,objName,OBJPROP_ANCHOR,      ANCHOR_LEFT_UPPER);
      ObjectSetInteger(chartID,objName,OBJPROP_READONLY,    false); 
      ObjectSetInteger(chartID,objName,OBJPROP_BACK,        false); 
      ObjectSetInteger(chartID,objName,OBJPROP_SELECTABLE,  false); 
      ObjectSetInteger(chartID,objName,OBJPROP_SELECTED,    false);
      ObjectSetInteger(chartID,objName,OBJPROP_HIDDEN,      true);
    }
   ObjectSetInteger(chartID,objName,OBJPROP_XDISTANCE,      displayBox.xPos );
   ObjectSetInteger(chartID,objName,OBJPROP_YDISTANCE,      displayBox.yPos );
   ObjectSetString (chartID, objName, OBJPROP_TEXT,         displayStr );
 }
//+------------------------------------------------------------------+
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 makeARectangle(const RectStruct& displayRect) 
 {
   static long chartID = ChartID();
   int windowIndex   = ObjectFind(chartID, displayRect.rectName); // Find which window the object is in (does it exist?)
   if(windowIndex<0)                         // No window found with the object in it - Create the object
    {
      if( ObjectCreate(chartID, displayRect.rectName, OBJ_RECTANGLE, CHARTWINDOW, displayRect.startTime, displayRect.topPrice, displayRect.endTime, displayRect.bottomPrice) )
       {
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_COLOR,      displayRect.fillClr);
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_STYLE,      displayRect.lineStyle);
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_WIDTH,      displayRect.lineWidth);
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_BACK,       true);
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_SELECTABLE, false);
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_SELECTED,   false);
         ObjectSetInteger(chartID,  displayRect.rectName, OBJPROP_HIDDEN,     true);
       }
      else  // publish error if the object creation fails.
       { 
         int errCode      = GetLastError();
         string errString = StringConcatenate(__FUNCTION__," Failed to create object ",displayRect.rectName,", Error: ",IntegerToString(errCode),", ",ErrorDescription(errCode));
         Print(errString); Comment(errString);
       } 
    }
   else  // Move the Object, it exists already
    {
      ObjectMove(chartID, displayRect.rectName, ANCHOR_POINT_ZERO, displayRect.startTime, displayRect.topPrice );
      ObjectMove(chartID, displayRect.rectName, ANCHOR_POINT_ONE,  displayRect.endTime, displayRect.bottomPrice );
    }
 }
//--------------------------------------------------------------------
string getInfoMecDescription(BAR_INFO_MECH mechanism)
 {
   string dispString;
   switch (mechanism)
    {
      case ARRAYS:     dispString = "ARRAYS";    break;
      case IMAS:       dispString = "iMAs";      break;
      case COPY_FUNCS: dispString = "Functions"; break;
      case RATES:      dispString = "RATES";     break;
      default:         dispString = "Unknown "+IntegerToString(mechanism); break;
    }
   return( dispString );
 }
//--------------------------------------------------------------------
BAR_INFO_MECH getNextMec(BAR_INFO_MECH mechanism)  // {ARRAYS, IMAS, COPY_FUNCS, RATES};
 {
   BAR_INFO_MECH nextMech;
   switch (mechanism)
    {
      case ARRAYS:     nextMech = IMAS; workingTF = getPeriodCurrent();  break;
      case IMAS:       nextMech = COPY_FUNCS; break;
      case COPY_FUNCS: nextMech = RATES;      break;
      case RATES:      nextMech = ARRAYS;     break;
      default:         nextMech = IMAS;       break;
    }
   return( nextMech );
 }
//--------------------------------------------------------------------
string getPromptTxt(ENUM_CTRL_IDX idx)
 {
   string dispString;
   switch (idx)
    {
      case BAR_UP:
         dispString = "Bar Up";
         break;
      case BAR_DN:
         dispString = "Bar Dn";
         break;
      case PERIOD_START:
         dispString = getPeriodText(workingTF,PART_ONE);
         break;
      case PERIOD_END:
         dispString = getPeriodText(workingTF,PART_TWO);
         break;
      case INFO_MECH:
         dispString = getInfoMecDescription(workingMechanism);
         break;
      case MA_MODE:
         if( workingMechanism==IMAS)
          {
            dispString = getSmoothingModeDescription(workingMaMethod);
          }
         else
          {
            dispString = "";
          }
         break;
      default:
         dispString = "Unknown "+IntegerToString(idx);
         break;
    }
   return(dispString);
 }
string getPeriodText(ENUM_TIMEFRAMES tf, const PERIOD_PARTS partOneTwo)
{
   string returnString;
   switch (tf)
   {
      case PERIOD_M1:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M1";  break;
      case PERIOD_M2:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M2";  break;
      case PERIOD_M3:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M3";  break;
      case PERIOD_M4:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M4";  break;
      case PERIOD_M5:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M5";  break;
      case PERIOD_M6:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M6";  break;
      case PERIOD_M10: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M10"; break;
      case PERIOD_M12: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M12"; break;
      case PERIOD_M15: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M15"; break;
      case PERIOD_M20: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M20"; break;
      case PERIOD_M30: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_M30"; break;
      case PERIOD_H1:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H1";  break;
      case PERIOD_H2:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H2";  break;
      case PERIOD_H3:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H3";  break;
      case PERIOD_H4:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H4";  break;
      case PERIOD_H6:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H6";  break;
      case PERIOD_H8:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H8";  break;
      case PERIOD_H12: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_H12"; break;
      case PERIOD_D1:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_D1";  break;
      case PERIOD_W1:  returnString = (partOneTwo==PART_ONE)?"PERIOD":"_W1";  break;
      case PERIOD_MN1: returnString = (partOneTwo==PART_ONE)?"PERIOD":"_MN1"; break;
      default:  returnString = "Unknown: "+IntegerToString(tf);  break;  // whatcha gonna do?
   }
   return(returnString);
}
ENUM_TIMEFRAMES getNextTF(ENUM_TIMEFRAMES tf)
{
   ENUM_TIMEFRAMES returnTF;
   switch (tf)
   {
      case PERIOD_M1:  returnTF = PERIOD_M5;   break;
      case PERIOD_M2:  returnTF = PERIOD_M3;   break;
      case PERIOD_M3:  returnTF = PERIOD_M4;   break;
      case PERIOD_M4:  returnTF = PERIOD_M5;   break;
      case PERIOD_M5:  returnTF = PERIOD_M15;  break;
      case PERIOD_M6:  returnTF = PERIOD_M10;  break;
      case PERIOD_M10: returnTF = PERIOD_M12;  break;
      case PERIOD_M12: returnTF = PERIOD_M15;  break;
      case PERIOD_M15: returnTF = PERIOD_M30;  break;
      case PERIOD_M20: returnTF = PERIOD_M30;  break;
      case PERIOD_M30: returnTF = PERIOD_H1;   break;
      case PERIOD_H1:  returnTF = PERIOD_H4;   break;
      case PERIOD_H2:  returnTF = PERIOD_H3;   break;
      case PERIOD_H3:  returnTF = PERIOD_H4;   break;
      case PERIOD_H4:  returnTF = PERIOD_D1;   break;
      case PERIOD_H6:  returnTF = PERIOD_H8;   break;
      case PERIOD_H8:  returnTF = PERIOD_H12;  break;
      case PERIOD_H12: returnTF = PERIOD_D1;   break;
      case PERIOD_D1:  returnTF = PERIOD_W1;   break;
      case PERIOD_W1:  returnTF = PERIOD_MN1;  break;
      case PERIOD_MN1: returnTF = PERIOD_M1;   break;
      default:  returnTF = PERIOD_CURRENT;     break;  // whatcha gonna do?
    }
   return(returnTF);
 }
ENUM_TIMEFRAMES getPreviousTF(ENUM_TIMEFRAMES tf)
 {
   ENUM_TIMEFRAMES returnTF;
   switch (tf)
    {
      case PERIOD_M1:  returnTF = PERIOD_MN1;  break;
      case PERIOD_M2:  returnTF = PERIOD_M1;   break;
      case PERIOD_M3:  returnTF = PERIOD_M2;   break;
      case PERIOD_M4:  returnTF = PERIOD_M3;   break;
      case PERIOD_M5:  returnTF = PERIOD_M1;   break;
      case PERIOD_M6:  returnTF = PERIOD_M5;   break;
      case PERIOD_M10: returnTF = PERIOD_M6;   break;
      case PERIOD_M12: returnTF = PERIOD_M10;  break;
      case PERIOD_M15: returnTF = PERIOD_M5;   break;
      case PERIOD_M20: returnTF = PERIOD_M15;  break;
      case PERIOD_M30: returnTF = PERIOD_M15;  break;
      case PERIOD_H1:  returnTF = PERIOD_M30;  break;
      case PERIOD_H2:  returnTF = PERIOD_H1;   break;
      case PERIOD_H3:  returnTF = PERIOD_H2;   break;
      case PERIOD_H4:  returnTF = PERIOD_H1;   break;
      case PERIOD_H6:  returnTF = PERIOD_H4;   break;
      case PERIOD_H8:  returnTF = PERIOD_H6;   break;
      case PERIOD_H12: returnTF = PERIOD_H8;   break;
      case PERIOD_D1:  returnTF = PERIOD_H4;   break;
      case PERIOD_W1:  returnTF = PERIOD_D1;  break;
      case PERIOD_MN1: returnTF = PERIOD_W1;   break;
      default:  returnTF = getPeriodCurrent(); break;  // whatcha gonna do?
    }
   return(returnTF);
 }
ENUM_TIMEFRAMES getPeriodCurrent(void)
 {
   ENUM_TIMEFRAMES returnTF = (ENUM_TIMEFRAMES) Period();
   /*
   switch (returnTF)
    {
      case PERIOD_M1:  returnTF = PERIOD_M1;   break;
      case PERIOD_M2:  returnTF = PERIOD_M2;   break;
      case PERIOD_M3:  returnTF = PERIOD_M3;   break;
      case PERIOD_M4:  returnTF = PERIOD_M4;   break;
      case PERIOD_M5:  returnTF = PERIOD_M5;  break;
      case PERIOD_M6:  returnTF = PERIOD_M6;  break;
      case PERIOD_M10: returnTF = PERIOD_M10;  break;
      case PERIOD_M12: returnTF = PERIOD_M15;  break;
      case PERIOD_M15: returnTF = PERIOD_M15;  break;
      case PERIOD_M20: returnTF = PERIOD_M20;  break;
      case PERIOD_M30: returnTF = PERIOD_M30;   break;
      case PERIOD_H1:  returnTF = PERIOD_H1;   break;
      case PERIOD_H2:  returnTF = PERIOD_H2;   break;
      case PERIOD_H3:  returnTF = PERIOD_H3;   break;
      case PERIOD_H4:  returnTF = PERIOD_H4;   break;
      case PERIOD_H6:  returnTF = PERIOD_H6;   break;
      case PERIOD_H8:  returnTF = PERIOD_H8;  break;
      case PERIOD_H12: returnTF = PERIOD_H12;   break;
      case PERIOD_D1:  returnTF = PERIOD_D1;   break;
      case PERIOD_W1:  returnTF = PERIOD_W1;  break;
      case PERIOD_MN1: returnTF = PERIOD_MN1;   break;
      default:  returnTF = PERIOD_M1;     break;  // whatcha gonna do?
    }
   */
   return(returnTF);
 }
ENUM_MA_METHOD getNextSmoothingMode(ENUM_MA_METHOD currentMode)
 {
   ENUM_MA_METHOD nextMode;
   switch (currentMode)
    {
      case MODE_SMA:   nextMode = MODE_EMA;   break;
      case MODE_EMA:   nextMode = MODE_SMMA;  break;
      case MODE_SMMA:  nextMode = MODE_LWMA;  break;
      case MODE_LWMA:  nextMode = MODE_SMA;   break;
      default:  nextMode = MODE_SMA;         break;  // whatcha gonna do?
    }
   return(nextMode);
 }
string getSmoothingModeDescription(ENUM_MA_METHOD currentMode)
 {
   string modeDescription;
   switch (currentMode)
    {
      case MODE_SMA:   modeDescription = "MODE_SMA";    break;
      case MODE_EMA:   modeDescription = "MODE_EMA";    break;
      case MODE_SMMA:  modeDescription = "MODE_SMMA";   break;
      case MODE_LWMA:  modeDescription = "MODE_LWMA";   break;
      default:  modeDescription = "Unknown" + IntegerToString(currentMode); break;  // whatcha gonna do?
    }
   return(modeDescription);
 }