//
// "00-MultiSTC_v103.mq4" -- multiple time frame Schaff Trend Cycle
// 
//    Ver. 0.01  2008/10/30(Thu)  initial version
//    Ver. 1.00  2008/11/16(Sun)  release version
//    Ver. 1.03  2008/12/23(Tue)  version sync
// 
// 
#property  copyright "00 - 00mql4@gmail.com"
#property  link      "http://www.mql4.com/"

//---- indicator settings
#property  indicator_separate_window

#property  indicator_buffers  7

#property  indicator_color1  DodgerBlue  // 0: Long signal
#property  indicator_color2  Crimson     // 1: Short signal
#property  indicator_color3  0x80481e    // 2: Long turn
#property  indicator_color4  0x1e0a6e    // 3: Short turn
#property  indicator_color5  Yellow      // 4: STC, timeFrame0
#property  indicator_color6  Gold        // 5: STC, timeFrame1
#property  indicator_color7  Orange      // 6: STC, timeFrame2

#property  indicator_style1  STYLE_SOLID
#property  indicator_style2  STYLE_SOLID
#property  indicator_style3  STYLE_SOLID
#property  indicator_style4  STYLE_SOLID
#property  indicator_style5  STYLE_SOLID
#property  indicator_style6  STYLE_SOLID
#property  indicator_style7  STYLE_DOT

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  1
#property  indicator_width4  1
#property  indicator_width5  3
#property  indicator_width6  1
#property  indicator_width7  1

#property indicator_minimum  -20
#property indicator_maximum  120

//---- defines
#define LONG_MARK_POS   -5
#define SHORT_MARK_POS  105

//---- indicator parameters
extern int  timeFrame0 = 0;      // time frame 0
extern int  timeFrame1 = 0;      // time frame 1
extern int  timeFrame2 = 0;      // time frame 2
extern bool bAlert     = false;  // PlaySound() on signal
//
/*extern*/ string sHelp0 = "--- params for \"00-STC\"";
/*extern*/ string sIndSTC = "00-STC_v103";  // indicator name
extern int    nFast          = 23;             // EMA fast
extern int    nSlow          = 50;             // EMA slow
extern int    nStochas       = 10;             // Stochas period
extern bool   bDoubleStochas = true;           // apply stochas twice
extern int    appliedPrice   = PRICE_TYPICAL;  // 0:CLOSE 1:OPEN 2:HIGH 3:LOW 4:MEDIAN 5:TYPICAL 6:WEIGHTED
extern double levelLo        = 5;              // lower threshold for long signal
extern double levelHi        = 95;             // upper threshold for short signal
extern double clearLo        = 25;             // lower level to clear long turn
extern double clearHi        = 75;             // upper level to clear short turn
extern int    nMaxBars       = 2000;           // maximum number of bars to calculate, 0: no limit
/*extern*/ string sHelp1 = "--- end of params for \"00-STC\"";

//---- indicator buffers
double BufferLongTrigger[];   // 0: Long trigger
double BufferShortTrigger[];  // 1: Short trigger
double BufferLongTurn[];      // 2: Long turn
double BufferShortTurn[];     // 3: Short turn
double BufferSTC0[];          // 4: STC, timeFrame0
double BufferSTC1[];          // 5: STC, timeFrame1
double BufferSTC2[];          // 6: STC, timeFrame2

//---- vars
string   sIndicatorName = "00-MultiSTC_v103";
int      markLongTrigger  = 233;
int      markLongTurn     = 167;
int      markShortTrigger = 234;
int      markShortTurn    = 167;
datetime tAlertLast;

//----------------------------------------------------------------------
string TimeFrameToStr(int timeFrame)
{
    switch (timeFrame) {
    case 1:     return("M1");
    case 5:     return("M5");
    case 15:    return("M15");
    case 30:    return("M30");
    case 60:    return("H1");
    case 240:   return("H4");
    case 1440:  return("D1");
    case 10080: return("W1");
    case 43200: return("MN");
    }
    
    return("??");
}

//----------------------------------------------------------------------
int NextPeriod(int timeFrame)
{
    switch (timeFrame) {
    case 1:     return(5);
    case 5:     return(15);
    case 15:    return(30);
    case 30:    return(60);
    case 60:    return(240);
    case 240:   return(1440);
    case 1440:  return(10080);
    case 10080: return(43200);
    }
    
    return(0);
}

//----------------------------------------------------------------------
void init()
{
    if (timeFrame0 == 0 && timeFrame1 == 0 && timeFrame2 == 0) {
	timeFrame0 = Period();
	timeFrame1 = NextPeriod(timeFrame0);
	timeFrame2 = NextPeriod(timeFrame1);
    }
    
    if (timeFrame0 == 0) {
	timeFrame0 = Period();
    }
    if (timeFrame1 == 0) {
	timeFrame1 = Period();
    }
    if (timeFrame2 == 0) {
	timeFrame2 = Period();
    }
    
    sIndicatorName = (sIndicatorName + "(" +
		      TimeFrameToStr(timeFrame0) + "," +
		      TimeFrameToStr(timeFrame1) + "," +
		      TimeFrameToStr(timeFrame2) + ")");
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferLongTrigger);
    SetIndexBuffer(1, BufferShortTrigger);
    SetIndexBuffer(2, BufferLongTurn);
    SetIndexBuffer(3, BufferShortTurn);
    SetIndexBuffer(4, BufferSTC0);
    SetIndexBuffer(5, BufferSTC1);
    SetIndexBuffer(6, BufferSTC2);
    
    SetIndexLabel(0, "Long trigger");
    SetIndexLabel(1, "Short trigger");
    SetIndexLabel(2, "Long turn");
    SetIndexLabel(3, "Short turn");
    SetIndexLabel(4, "STC0");
    SetIndexLabel(5, "STC1");
    SetIndexLabel(6, "STC2");
    
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_LINE);
    SetIndexStyle(5, DRAW_LINE);
    SetIndexStyle(6, DRAW_LINE);
    
    SetIndexArrow(0, markLongTrigger);
    SetIndexArrow(1, markShortTrigger);
    SetIndexArrow(2, markLongTurn);
    SetIndexArrow(3, markShortTurn);
    
    int n = MathMax(nFast, nSlow) + nStochas;
    int n0 = n * timeFrame0 / Period();
    int n1 = n * timeFrame1 / Period();
    int n2 = n * timeFrame2 / Period();
    int nMax = MathMax(MathMax(n0, n1), 2);
    
    SetIndexDrawBegin(0, nMax);  // 0: Long trigger
    SetIndexDrawBegin(1, nMax);  // 1: Short trigger
    SetIndexDrawBegin(2, nMax);  // 2: Long turn
    SetIndexDrawBegin(3, nMax);  // 3: Short turn
    SetIndexDrawBegin(4, n0);    // 4: STC, timeFrame0
    SetIndexDrawBegin(5, n1);    // 5: STC, timeFrame1
    SetIndexDrawBegin(6, n2);  // 6: STC, timeFrame2
    
    SetLevelValue(0, levelLo);
    SetLevelValue(1, levelHi);
}

//----------------------------------------------------------------------
void start()
{
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    int limit0 = limit;
    if (nMaxBars > 0) {
	limit = MathMin(limit, nMaxBars);
    }
    
    // clear beyond limits
    for (int i = limit0 - 1; i >= limit; i--) {
	BufferLongTrigger[i]  = EMPTY_VALUE;  // 0: Long trigger
	BufferShortTrigger[i] = EMPTY_VALUE;  // 1: Short trigger
	BufferLongTurn[i]     = EMPTY_VALUE;  // 2: Long turn
	BufferShortTurn[i]    = EMPTY_VALUE;  // 3: Short turn
	BufferSTC0[i]         = EMPTY_VALUE;  // 4: STC, timeFrame0
	BufferSTC1[i]         = EMPTY_VALUE;  // 5: STC, timeFrame1
	BufferSTC2[i]         = EMPTY_VALUE;  // 6: STC, timeFrame2
    }
    
    for (i = limit - 1; i >= 0; i--) {
	int shift = iBarShift(NULL, timeFrame0, Time[i]);
	
	// STC value
	BufferSTC0[i] = iCustom(NULL, 0, sIndSTC, timeFrame0, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 0, shift);
	BufferSTC1[i] = iCustom(NULL, 0, sIndSTC, timeFrame1, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 0, shift);
	BufferSTC2[i] = iCustom(NULL, 0, sIndSTC, timeFrame2, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 0, shift);
	
	// long turn
	double bufLongTurn0 = iCustom(NULL, 0, sIndSTC, timeFrame0, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				      levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 3, shift);
	double bufLongTurn1 = iCustom(NULL, 0, sIndSTC, timeFrame1, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				      levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 3, shift);
	double bufLongTurn2 = iCustom(NULL, 0, sIndSTC, timeFrame2, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				      levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 3, shift);
	
	// short turn
	double bufShortTurn0 = iCustom(NULL, 0, sIndSTC, timeFrame0, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				       levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 4, shift);
	double bufShortTurn1 = iCustom(NULL, 0, sIndSTC, timeFrame1, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				       levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 4, shift);
	double bufShortTurn2 = iCustom(NULL, 0, sIndSTC, timeFrame2, nFast, nSlow, nStochas, bDoubleStochas, appliedPrice,
				       levelLo, levelHi, clearLo, clearHi, false, nMaxBars, 4, shift);
	
	// check signal
	bool bFire = false;
	
	// long signal
	bool bLong0 = (bufLongTurn0 != EMPTY_VALUE);
	bool bLong1 = (bufLongTurn1 != EMPTY_VALUE);
	bool bLong2 = (bufLongTurn2 != EMPTY_VALUE);
	
	if (bLong0 && bLong1 && bLong2) {
	    if (BufferLongTrigger[i + 1] == EMPTY_VALUE && BufferLongTurn[i + 1] == EMPTY_VALUE) {
		BufferLongTrigger[i] = LONG_MARK_POS;
		bFire = true;
	    }
	    BufferLongTurn[i] = LONG_MARK_POS;
	} else {
	    BufferLongTrigger[i] = EMPTY_VALUE;
	    BufferLongTurn[i] = EMPTY_VALUE;
	}
	
	// short signal
	bool bShort0 = (bufShortTurn0 != EMPTY_VALUE);
	bool bShort1 = (bufShortTurn1 != EMPTY_VALUE);
	bool bShort2 = (bufShortTurn2 != EMPTY_VALUE);
	
	if (bShort0 && bShort1 && bShort2) {
	    if (BufferShortTrigger[i + 1] == EMPTY_VALUE && BufferShortTurn[i + 1] == EMPTY_VALUE) {
		BufferShortTrigger[i] = SHORT_MARK_POS;
		bFire = true;
	    }
	    BufferShortTurn[i] = SHORT_MARK_POS;
	} else {
	    BufferShortTrigger[i] = EMPTY_VALUE;
	    BufferShortTurn[i] = EMPTY_VALUE;
	}
	
	if (bAlert) {
	    if (i == 0 && bFire && tAlertLast != Time[0]) {
		PlaySound("alert.wav");
		tAlertLast = Time[0];
	    }
	}
    }
}
