//+------------------------------------------------------------------+
//|                               v1_0  2011-APR-01                  |
//|                               getPeriodSymbolTimeshiftsecLib.mq4 |
//|                   Copyright © 2011, pips4life of forexfactory.com|
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, pips4life of forexfactory.com"
#property link      "http://www.forexfactory.com/showthread.php?t=206301"
#property library

/*

VERSION HISTORY:
2011-APR-01: v1_0 by pips4life of forexfactory.com.  First release.

DESCRIPTION:

This library can be included in indicators/etc. for use on period-multiplied and/or timeshifted
charts as created by "P4L PeriodCon.mq4" ( See http://www.forexfactory.com/showthread.php?t=206301 ).
For simple multiplied charts (e.g. "M10"), only the effective Period() value is changed.  Your code
must deal properly with non-standard periods such as "Period()" returning the value of "10".  
It would usally NOT be necessary to use this library for such a simple change.

However, for timeshifted charts, and for some higher-timeframe charts (> Weekly), the usual values
a program uses for functions "Period()" and/or "Symbol()" will be affected.   Your indicators must
account for these differences, AND ALSO account for any "timeshiftsec" value.  For example, if the
PeriodCon creates the chart "EURUSD+1H,Daily", the "Period()" returns "1440" (normal), but the
"Symbol()" returns "EURUSD+1H".  By using this library, you can determine the true chart symbol 
is actually just "EURUSD".   Second example: If the chart is "EU+1N_x12,Monthly", this syntax 
actually means that the true period is 12*PERIOD_MN1.  There is a timeshiftsec of 1 month (30*24*3600 sec),
and the true symbol name is "EURUSD", not just "EU".   (The reason for such complexity has to do
with MT4 limitations that restrict the legal values and length of the Symbol() and Period() values!)

This library routine can interpret the Period() and Symbol() values and return to the user the 3 values
for:  period, symbol, timeshiftsec

*** IT IS UP TO THE USER *** to properly incorporate the values into your code such that it can work
successfully on the charts created by PeriodCon.mq4.  

NOTE: Regarding any non-zero "timeshiftsec", this is the hardest to incorporate into 
your code and details vary widely.  You might be able to add the value to various times in
your program.  Do NOT, however, assume that you can use a MTF (multi-time-function) indicator 
without fully considering the implications.  If a higher-TF *timeshifted* chart calls for 
an equivalent lower-timeframe-timeshifted chart, perhaps you can just use the un-modified
output from "Symbol()" (e.g. EURUSD+1H).  You would of course have to use multiple PeriodCon 
instances to generate the live data for each desired timeframe.

If you use this library routine, do the author and everyone a favor and append this
thread with your experiences/advice/tips:  http://www.forexfactory.com/showthread.php?t=206301


USE MODEL 1.  You can put this file into your  C:/.../_your_MT4_/experts/libraries/  folder
In your code, you put:

//+-------------------------------------------------
( In the main body, prior to start/init routines )
#import "P4L getPeriodSymbolTimeshiftsecLib.ex4"
void getPeriodSymbolTimeshiftsecLib(int& periodArray[], string& symbolArray[], datetime& timeshiftsecArray[], bool AutoTimeShiftAdjust, bool Debug);
#import

// Global variables:
int      period; 
string   symbol;
datetime timeshiftsec;
extern   AutoTimeShiftAdjust = true; // Suggested to be an external variable by using "extern" here.
extern   Debug = false; // Use "true" to see the values found for period,symbol,timeshiftsec // Can be external or internal variable

init()
{
   int      per[] = {0};
   string   sym[] = {""};
   datetime ts[] = {0};
   getPeriodSymbolTimeshiftsecLib(per,sym,ts,AutoTimeShiftAdjust,Debug);
   period       = per[0];
   symbol       = sym[0];
   timeshiftsec = ts[0];
}
// The rest of your program should probably use "period" and not "Period()", "symbol" and not "Symbol()", and must account for any "timeshiftsec"
//+-------------------------------------------------


USE MODEL 2.  You can COPY this file into your source mq4 code.  You can *delete* the
"getPeriodSymbolTimeshiftsecLib" function below, but uncomment and leave the 
"getPeriodSymbolTimeshiftsec" function, plus the two other functions, "stringToUC" 
and "stringReplaceFirstMatch".

In your code, you put:

//+-------------------------------------------------
( In the main body, prior to start/init routines )
// Global variables:
int      period; 
string   symbol;
datetime timeshiftsec;
extern   AutoTimeShiftAdjust = true; // Suggested to be an external variable by using "extern" here.
extern   Debug = false; // Use "true" to see the values found for period,symbol,timeshiftsec // Can be external or internal variable

init()
{
   getPeriodSymbolTimeshiftsec(period,symbol,timeshiftsec,AutoTimeShiftAdjust,Debug);
}
// The rest of your program should probably use "period" and not "Period()", "symbol" and not "Symbol()", and must account for any "timeshiftsec"
//+-------------------------------------------------

*/
//+------------------------------------------------------------------+
void getPeriodSymbolTimeshiftsecLib(int& periodArray[], string& symbolArray[], datetime& timeshiftsecArray[], bool AutoTimeShiftAdjust, bool Debug) // USE IF part of an included library 
{
   // FYI, the use of "&" for each argument means this routine can WRITE the value, and the
   // calling parent routine's variable values actually change.
   // If one uses "getPeriodSymbolTimeshiftsec" above, this function (and also stringReplaceFirstMatch and stringToUC)
   // *must* be included in the same file as your source .mq4 file.
   //
   // If this is instead a part of an included library file, the function "getPeriodSymbolTimeshiftsecLib"
   // should be used above, AND there are 3 lines at the end of this function that must be uncommented.  
   // Note that each argument is an array (ArraySize=1), and the calling routine must call the
   // function with type array variables (each ArraySize=1).
   
   // The following detects symbol names like "EURUSD+1H,Daily" as generated by "P4L PeriodCon.mq4"
   // The "+1H" string is a timeshift (i.e. offset) that must be factored in.
   // There are extremely few regular "Symbol()" names that have a true "+" or "-" in
   // them, so this method should be sufficient. However, if there's a problem, turn off AutoTimeShiftAdjust.
   
   //bool Debug = false;
   
   int      period = Period();
   string   symbol = Symbol();
   datetime timeshiftsec = 0;
      
   if (AutoTimeShiftAdjust)
   {
      string symbolSuffix = "";
      string xmult = "";
      int plus = StringFind(Symbol(),"+",0);
      int minus = StringFind(Symbol(),"-",0);
      int uslcx = StringFind(Symbol(),"_x",0);
      int lcx = StringFind(Symbol(),"x",0);
      
      if ( plus > 0) symbolSuffix = StringSubstr(Symbol(),plus);      // The "+" is kept if "plus", dropped if "plus+1".
      else if ( minus > 0) symbolSuffix = StringSubstr(Symbol(),minus); // The "-" stays with the string.
      else if ( uslcx > 0) symbolSuffix = StringSubstr(Symbol(),uslcx); // The "_" stays with the string.
      else if ( lcx > 0) symbolSuffix = StringSubstr(Symbol(),minus); // The "-" stays with the string.
      
      if (StringLen(symbolSuffix) <= 1) return(0); // str is at least 2 chars, normally would be min, e.g. "+1M"
      
      // The following is to find the correct period, typically for timeframes > 1-month, as generated by "P4L PeriodCon.mq4".
      if (lcx > 0 && ( plus > 0 || minus > 0 || uslcx > 0)) 
      {
         // Whatever is after the "x" (which includes "_x") is the xmult value:
         xmult = StringSubstr(Symbol(),lcx+1);      // The "x" is dropped using "lcx+1".
         if (StringLen(xmult) >= 1) period = period * StrToInteger(xmult);
      }
      else
      {
         if (period < PERIOD_MN1 && PERIOD_MN1-period < 240) period = PERIOD_MN1 * (PERIOD_MN1-period);
         else if (period < PERIOD_W1 && PERIOD_W1-period < 1040) period = PERIOD_W1 * (PERIOD_W1-period);
         else if (period < PERIOD_D1 && PERIOD_D1-period < 480) period = PERIOD_D1 * (PERIOD_D1-period);
      }
   
      if (lcx > 0 || plus > 0 || minus > 0 || uslcx > 0)
      {
         int pos = 999;
         if (lcx > 0) pos = MathMin(pos,lcx);
         if (plus > 0) pos = MathMin(pos,plus);
         if (minus > 0) pos = MathMin(pos,minus);
         if (uslcx > 0) pos = MathMin(pos,uslcx);
         symbol = StringSubstr(Symbol(),0,pos);
         if (StringFind(symbol,"_",0) < 0 ) // eliminates: S&P_500,Dow_Jones, etc. 
         {
            if (StringFind(symbol,"SKRU",0) >= 0 && StringFind(symbol,"RUB",0) != 0) symbol=stringReplaceFirstMatch(symbol,"SKRU","SEKRUB");
            if (StringFind(symbol,"U",0) >= 0 && StringFind(symbol,"USD",0) != 0 && StringFind(symbol,"EUR",0) != 0 && StringFind(symbol,"RUB",0) != 0) symbol=stringReplaceFirstMatch(symbol,"U","USD");
            if (StringFind(symbol,"E",0) >= 0 && StringFind(symbol,"EUR",0) != 0 && StringFind(symbol,"SEK",0) != 0) symbol=stringReplaceFirstMatch(symbol,"E","EUR");
            if (StringFind(symbol,"G",0) >= 0 && StringFind(symbol,"GBP",0) != 0) symbol=stringReplaceFirstMatch(symbol,"G","GBP");
            if (StringFind(symbol,"J",0) >= 0 && StringFind(symbol,"JPY",0) != 0) symbol=stringReplaceFirstMatch(symbol,"J","JPY");
            if (StringFind(symbol,"A",0) >= 0 && StringFind(symbol,"AUD",0) != 0 && StringFind(stringToUC(symbol),"DJIA",0) != 0) symbol=stringReplaceFirstMatch(symbol,"A","AUD");
            if (StringFind(symbol,"NZ",0) >= 0 && StringFind(symbol,"NZD",0) != 0) symbol=stringReplaceFirstMatch(symbol,"NZ","NZD");
            if (StringFind(symbol,"CF",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"CF","CHF");
            if (StringFind(symbol,"CD",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"CD","CAD");
            if (StringFind(symbol,"NK",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"NK","NOK");
            if (StringFind(symbol,"SK",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"SK","SEK");
            if (StringFind(symbol,"DK",0) >= 0 && StringFind(symbol,"DKK",0) != 0) symbol=stringReplaceFirstMatch(symbol,"DK","DKK");
            if (StringFind(symbol,"HK",0) >= 0 && StringFind(symbol,"HKD",0) != 0) symbol=stringReplaceFirstMatch(symbol,"HK","HKD");
            // ALTERNATIVE is to do every possible pair manually:
            //if (StringFind(symbol,"EU",0) >= 0 && StringFind(symbol,"EUR",0) != 0 && StringFind(symbol,"USD",0) != 0) symbol=stringReplaceFirstMatch(symbol,"EU","EURUSD");
            //else if ...
         }
      }
      
      //if (Debug) Print("Symbol(): ",Symbol()," base-symbol: ",symbol," plus: ",plus," minus: ",minus," symbolSuffix: ",symbolSuffix," xmult: ",xmult," period: ",period);
      
      
      if (StringFind(symbolSuffix,"MN",0) > 0)
        timeshiftsec = 60 * PERIOD_MN1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"MN",0)));
      else if (StringFind(symbolSuffix,"N",0) > 0)
        timeshiftsec = 60 * PERIOD_MN1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"N",0)));
      else if (StringFind(symbolSuffix,"W",0) > 0) 
        timeshiftsec = 60 * PERIOD_W1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"W",0)));
      else if (StringFind(symbolSuffix,"D",0) > 0) 
        timeshiftsec = 60 * PERIOD_D1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"D",0)));
      else if (StringFind(symbolSuffix,"H",0) > 0) 
        timeshiftsec = 60 * PERIOD_H1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"H",0)));
      else if (StringFind(symbolSuffix,"M",0) > 0) 
        timeshiftsec = 60 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"M",0)));
      //else
      //  timeshiftsec = 60 * StrToInteger(StringSubstr(symbolSuffix,0)); //Probably not a good idea to do this.
      
   }
   
   if (Debug) Alert("symbol: ",symbol," period: ",period," timeshiftsec: ",timeshiftsec," as derived from Symbol(): ",Symbol()," , Period(): ",Period() );
      
   // These next 3 lines are for use with the LIBRARY routine: getPeriodSymbolTimeshiftsecLib
   periodArray[0] = period;
   symbolArray[0] = symbol;
   timeshiftsecArray[0] = timeshiftsec;
   
   return(0);
} // end of getPeriodSymbolTimeshiftsecLib
//+------------------------------------------------------------------+
/*   // REMOVE this line to uncomment this section, plus remove the corresponding line at the END of THIS function below:
void getPeriodSymbolTimeshiftsec(int& period, string& symbol, datetime& timeshiftsec, bool AutoTimeShiftAdjust, bool Debug) // USE IF functions are included in your source .mq4 file
{
   // FYI, the use of "&" for each argument means this routine can WRITE the value, and the
   // calling parent routine's variable values actually change.
   // If one uses "getPeriodSymbolTimeshiftsec" above, this function (and also stringReplaceFirstMatch and stringToUC)
   // *must* be included in the same file as your source .mq4 file.
   //
   // If this is instead a part of an included library file, the function "getPeriodSymbolTimeshiftsecLib"
   // should be used above, AND there are 3 lines at the end of this function that must be uncommented.  
   // Note that each argument is an array (ArraySize=1), and the calling routine must call the
   // function with type array variables (each ArraySize=1).
   
   // The following detects symbol names like "EURUSD+1H,Daily" as generated by "P4L PeriodCon.mq4"
   // The "+1H" string is a timeshift (i.e. offset) that must be factored in.
   // There are extremely few regular "Symbol()" names that have a true "+" or "-" in
   // them, so this method should be sufficient. However, if there's a problem, turn off AutoTimeShiftAdjust.
   
   //bool AutoTimeShiftAdjust = true;
   //bool Debug = false;
   
   
   period = Period();
   symbol = Symbol();
   timeshiftsec = 0;
   
   if (AutoTimeShiftAdjust)
   {
      string symbolSuffix = "";
      string xmult = "";
      int plus = StringFind(Symbol(),"+",0);
      int minus = StringFind(Symbol(),"-",0);
      int uslcx = StringFind(Symbol(),"_x",0);
      int lcx = StringFind(Symbol(),"x",0);
      
      if ( plus > 0) symbolSuffix = StringSubstr(Symbol(),plus);      // The "+" is kept if "plus", dropped if "plus+1".
      else if ( minus > 0) symbolSuffix = StringSubstr(Symbol(),minus); // The "-" stays with the string.
      else if ( uslcx > 0) symbolSuffix = StringSubstr(Symbol(),uslcx); // The "_" stays with the string.
      else if ( lcx > 0) symbolSuffix = StringSubstr(Symbol(),minus); // The "-" stays with the string.
      
      if (StringLen(symbolSuffix) <= 1) return(0); // str is at least 2 chars, normally would be min, e.g. "+1M"
      
      // The following is to find the correct period, typically for timeframes > 1-month, as generated by "P4L PeriodCon.mq4".
      if (lcx > 0 && ( plus > 0 || minus > 0 || uslcx > 0)) 
      {
         // Whatever is after the "x" (which includes "_x") is the xmult value:
         xmult = StringSubstr(Symbol(),lcx+1);      // The "x" is dropped using "lcx+1".
         if (StringLen(xmult) >= 1) period = period * StrToInteger(xmult);
      }
      else
      {
         if (period < PERIOD_MN1 && PERIOD_MN1-period < 240) period = PERIOD_MN1 * (PERIOD_MN1-period);
         else if (period < PERIOD_W1 && PERIOD_W1-period < 1040) period = PERIOD_W1 * (PERIOD_W1-period);
         else if (period < PERIOD_D1 && PERIOD_D1-period < 480) period = PERIOD_D1 * (PERIOD_D1-period);
      }
   
      if (lcx > 0 || plus > 0 || minus > 0 || uslcx > 0)
      {
         int pos = 999;
         if (lcx > 0) pos = MathMin(pos,lcx);
         if (plus > 0) pos = MathMin(pos,plus);
         if (minus > 0) pos = MathMin(pos,minus);
         if (uslcx > 0) pos = MathMin(pos,uslcx);
         symbol = StringSubstr(Symbol(),0,pos);
         if (StringFind(symbol,"_",0) < 0 ) // eliminates: S&P_500,Dow_Jones, etc. 
         {
            if (StringFind(symbol,"SKRU",0) >= 0 && StringFind(symbol,"RUB",0) != 0) symbol=stringReplaceFirstMatch(symbol,"SKRU","SEKRUB");
            if (StringFind(symbol,"U",0) >= 0 && StringFind(symbol,"USD",0) != 0 && StringFind(symbol,"EUR",0) != 0 && StringFind(symbol,"RUB",0) != 0) symbol=stringReplaceFirstMatch(symbol,"U","USD");
            if (StringFind(symbol,"E",0) >= 0 && StringFind(symbol,"EUR",0) != 0 && StringFind(symbol,"SEK",0) != 0) symbol=stringReplaceFirstMatch(symbol,"E","EUR");
            if (StringFind(symbol,"G",0) >= 0 && StringFind(symbol,"GBP",0) != 0) symbol=stringReplaceFirstMatch(symbol,"G","GBP");
            if (StringFind(symbol,"J",0) >= 0 && StringFind(symbol,"JPY",0) != 0) symbol=stringReplaceFirstMatch(symbol,"J","JPY");
            if (StringFind(symbol,"A",0) >= 0 && StringFind(symbol,"AUD",0) != 0 && StringFind(stringToUC(symbol),"DJIA",0) != 0) symbol=stringReplaceFirstMatch(symbol,"A","AUD");
            if (StringFind(symbol,"NZ",0) >= 0 && StringFind(symbol,"NZD",0) != 0) symbol=stringReplaceFirstMatch(symbol,"NZ","NZD");
            if (StringFind(symbol,"CF",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"CF","CHF");
            if (StringFind(symbol,"CD",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"CD","CAD");
            if (StringFind(symbol,"NK",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"NK","NOK");
            if (StringFind(symbol,"SK",0) >= 0) symbol=stringReplaceFirstMatch(symbol,"SK","SEK");
            if (StringFind(symbol,"DK",0) >= 0 && StringFind(symbol,"DKK",0) != 0) symbol=stringReplaceFirstMatch(symbol,"DK","DKK");
            if (StringFind(symbol,"HK",0) >= 0 && StringFind(symbol,"HKD",0) != 0) symbol=stringReplaceFirstMatch(symbol,"HK","HKD");
            // ALTERNATIVE is to do every possible pair manually:
            //if (StringFind(symbol,"EU",0) >= 0 && StringFind(symbol,"EUR",0) != 0 && StringFind(symbol,"USD",0) != 0) symbol=stringReplaceFirstMatch(symbol,"EU","EURUSD");
            //else if ...
         }
      }
      
      //if (Debug) Print("Symbol(): ",Symbol()," base-symbol: ",symbol," plus: ",plus," minus: ",minus," symbolSuffix: ",symbolSuffix," xmult: ",xmult," period: ",period);
      
      
      if (StringFind(symbolSuffix,"MN",0) > 0)
        timeshiftsec = 60 * PERIOD_MN1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"MN",0)));
      else if (StringFind(symbolSuffix,"N",0) > 0)
        timeshiftsec = 60 * PERIOD_MN1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"N",0)));
      else if (StringFind(symbolSuffix,"W",0) > 0) 
        timeshiftsec = 60 * PERIOD_W1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"W",0)));
      else if (StringFind(symbolSuffix,"D",0) > 0) 
        timeshiftsec = 60 * PERIOD_D1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"D",0)));
      else if (StringFind(symbolSuffix,"H",0) > 0) 
        timeshiftsec = 60 * PERIOD_H1 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"H",0)));
      else if (StringFind(symbolSuffix,"M",0) > 0) 
        timeshiftsec = 60 * StrToInteger(StringSubstr(symbolSuffix,0,StringFind(symbolSuffix,"M",0)));
      //else
      //  timeshiftsec = 60 * StrToInteger(StringSubstr(symbolSuffix,0)); //Probably not a good idea to do this.
   }
   
   if (Debug) Alert("symbol: ",symbol," period: ",period," timeshiftsec: ",timeshiftsec," as derived from Symbol(): ",Symbol()," , Period(): ",Period() );
      
   return(0);
} // end of getPeriodSymbolTimeshiftsec
*/
//+------------------------------------------------------------------+
string stringReplaceFirstMatch(string str, string toFind, string toReplace)
{
    int len = StringLen(toFind);
    if (len == 0) return (str); // Cannot find ""
    int pos = StringFind(str, toFind);
    if (pos == -1) {
        return (str);
    } else if (pos == 0) {
        return (StringConcatenate(toReplace,StringSubstr(str, len)));
    }
    return (StringConcatenate(StringSubstr(str, 0, pos),toReplace,StringSubstr(str, pos + len)));
} // end of stringReplaceFirstMatch
//+------------------------------------------------------------------+
string stringToUC(string str)
{
    // Convert str to upper-case
    int lS = 97, lE = 122, uS = 65, uE = 90, diff = lS - uS;
    for (int i = 0; i < StringLen(str); i++) {
        int code = StringGetChar(str, i);
        if (code >= lS && code <= lE) {
            code -= diff;
            str = StringSetChar(str, i, code);
        }
    }
    return (str);
} // end of stringToUC
//+------------------------------------------------------------------+

