#property copyright "Scriptong" #property link "http://advancetools.net" #property description "English: Horizontal channel, based on extremums between the crossing of the two Moving Averages.\nRussian: Горизонтальный канал, опирающийся на экстремумы между пересечениями двух Moving Average." #property version "1.03" #property strict #property indicator_chart_window #property indicator_buffers 5 #property indicator_color1 clrBlue #property indicator_color2 clrRed #property indicator_color3 clrBlue #property indicator_color4 clrRed #property indicator_color5 clrNONE #property indicator_width1 2 #property indicator_width2 2 #property indicator_style3 STYLE_DOT #property indicator_style4 STYLE_DOT enum ENUM_YESNO { NO, // No / Нет YES // Yes / Да }; input uint i_maFastPeriod = 1; // Period of fast MA / Период расчета быстрой МА input ENUM_MA_METHOD i_maFastMethod = MODE_SMA; // Method of fast MA / Метод расчета быстрой МА input ENUM_APPLIED_PRICE i_maFastPrice = PRICE_WEIGHTED; // Applied price of fast MA / Цена расчета быстрой МА input uint i_maSlowPeriod = 21; // Period of slow MA / Период расчета медленной МА input ENUM_MA_METHOD i_maSlowMethod = MODE_EMA; // Method of slow MA / Метод расчета медленной МА input ENUM_APPLIED_PRICE i_maSlowPrice = PRICE_WEIGHTED; // Applied price od slow MA / Цена расчета медленной МА input ENUM_YESNO i_isAlert = YES; // Alert on trend change? / Сигнал при смене тренда? input ENUM_YESNO i_isPush = YES; // Notification on trend change? / Уведомлять при смене тренда? input int i_indBarsCount = 10000; // Number of bars to display / Кол-во баров отображения bool g_activate; int g_maxMAPeriod; double g_point, g_delta; enum ENUM_TREND_TYPE { TREND_TYPE_NONE, TREND_TYPE_UPWARD, TREND_TYPE_DOWNWARD }; enum ENUM_MESSAGE_CODE { MESSAGE_CODE_MA_FAST_LESS_THAN_ZERO, MESSAGE_CODE_MA_SLOW_LESS_THAN_ZERO, MESSAGE_CODE_TERMINAL_FATAL_ERROR1, MESSAGE_CODE_TREND_CHANGE_TO_UPWARD, MESSAGE_CODE_TREND_CHANGE_TO_DOWNWARD, MESSAGE_CODE_BIND_ERROR }; // Массивы буферов ндикатора double g_highSolid[]; double g_lowSolid[]; double g_highDot[]; double g_lowDot[]; double g_curTrend[]; //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Custom indicator initialization function | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ int OnInit() { g_activate = false; if (!TuningParameters()) return INIT_FAILED; if (!BuffersBind()) return INIT_FAILED; g_activate = true; return INIT_SUCCEEDED; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Checking the correctness of values of tuning parameters | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ bool TuningParameters() { string name = WindowExpertName(); if (i_maFastPeriod < 1) { Alert(name, GetStringByMessageCode(MESSAGE_CODE_MA_FAST_LESS_THAN_ZERO)); return false; } if (i_maSlowPeriod < 1) { Alert(name, GetStringByMessageCode(MESSAGE_CODE_MA_SLOW_LESS_THAN_ZERO)); return false; } g_point = Point; g_delta = -g_point / 10; if (g_point == 0) { Alert(name, GetStringByMessageCode(MESSAGE_CODE_TERMINAL_FATAL_ERROR1)); return false; } g_maxMAPeriod = (int)MathMax(i_maFastPeriod, i_maSlowPeriod); return true; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Binding of array and the indicator buffers | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ bool BuffersBind() { string name = WindowExpertName(); // IndicatorBuffers(5); // Связывание буферов индикатора с массивами if (!SetIndexBuffer(0, g_highSolid) || !SetIndexBuffer(1, g_lowSolid) || !SetIndexBuffer(2, g_highDot) || !SetIndexBuffer(3, g_lowDot) || !SetIndexBuffer(4, g_curTrend)) { Alert(name, GetStringByMessageCode(MESSAGE_CODE_BIND_ERROR), GetLastError()); return false; } // Задание графического типа буферов for (int i = 0; i < 4; i++) SetIndexStyle(i, DRAW_LINE); SetIndexStyle(4, DRAW_NONE); SetIndexLabel(0, "Resistance of downward trend"); SetIndexLabel(1, "Support of upward trend"); SetIndexLabel(2, "Breaking resistance"); SetIndexLabel(3, "Breaking support"); SetIndexLabel(4, "Trend Direction"); return true; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Initialize of all indicator buffers | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void BuffersInitializeAll() { ArrayInitialize(g_highSolid, EMPTY_VALUE); ArrayInitialize(g_lowSolid, EMPTY_VALUE); ArrayInitialize(g_highDot, EMPTY_VALUE); ArrayInitialize(g_lowDot, EMPTY_VALUE); ArrayInitialize(g_curTrend, TREND_TYPE_NONE); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Determination of bar index which needed to recalculate | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ int GetRecalcIndex(int &total, const int ratesTotal, const int prevCalculated) { total = ratesTotal - g_maxMAPeriod - 2; if (i_indBarsCount > 0 && i_indBarsCount < total) total = MathMin(i_indBarsCount, total); if (prevCalculated < ratesTotal - 1) { BuffersInitializeAll(); return total; } return (MathMin(ratesTotal - prevCalculated, total)); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| The minimal price at the downtrend interval | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ double GetLowPrice(int barIndex) { double lowPrice = Low[barIndex]; for (int i = barIndex + 1; i < Bars; i++) { double maFast = iMA(NULL, 0, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, i); double maSlow = iMA(NULL, 0, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, i); if (maFast > maSlow) return lowPrice; lowPrice = MathMin(lowPrice, Low[i]); } return lowPrice; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| The maximal price at the downtrend interval | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ double GetHighPrice(int barIndex) { double highPrice = High[barIndex]; for (int i = barIndex + 1; i < Bars; i++) { double maFast = iMA(NULL, 0, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, i); double maSlow = iMA(NULL, 0, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, i); if (maFast < maSlow) return highPrice; highPrice = MathMax(highPrice, High[i]); } return highPrice; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| The continuity of the indicator buffers values | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ContinuityBuffers(int barIndex) { if (g_curTrend[barIndex + 1] == TREND_TYPE_UPWARD) { g_lowDot[barIndex + 1] = EMPTY_VALUE; g_highSolid[barIndex + 1] = EMPTY_VALUE; } if (g_curTrend[barIndex + 1] == TREND_TYPE_DOWNWARD) { g_highDot[barIndex + 1] = EMPTY_VALUE; g_lowSolid[barIndex + 1] = EMPTY_VALUE; } g_highSolid[barIndex] = g_highSolid[barIndex + 1]; g_lowSolid[barIndex] = g_lowSolid[barIndex + 1]; g_highDot[barIndex] = g_highDot[barIndex + 1]; g_lowDot[barIndex] = g_lowDot[barIndex + 1]; g_curTrend[barIndex] = g_curTrend[barIndex + 1]; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| To process the upward MA cross | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ProcessUpwardMACross(int barIndex) { if (g_curTrend[barIndex + 1] == TREND_TYPE_DOWNWARD) { g_lowDot[barIndex] = GetLowPrice(barIndex); g_lowSolid[barIndex] = EMPTY_VALUE; if (g_lowDot[barIndex + 1] == EMPTY_VALUE) g_lowDot[barIndex + 1] = g_lowDot[barIndex]; return; } g_lowSolid[barIndex] = GetLowPrice(barIndex); g_lowDot[barIndex] = EMPTY_VALUE; if (g_lowSolid[barIndex + 1] == EMPTY_VALUE) g_lowSolid[barIndex + 1] = g_lowSolid[barIndex]; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| To process the downward MA cross | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ProcessDownwardMACross(int barIndex) { if (g_curTrend[barIndex + 1] == TREND_TYPE_UPWARD) { g_highDot[barIndex] = GetHighPrice(barIndex); g_highSolid[barIndex] = EMPTY_VALUE; if (g_highDot[barIndex + 1] == EMPTY_VALUE) g_highDot[barIndex + 1] = g_highDot[barIndex]; return; } g_highSolid[barIndex] = GetHighPrice(barIndex); g_highDot[barIndex] = EMPTY_VALUE; if (g_highSolid[barIndex + 1] == EMPTY_VALUE) g_highSolid[barIndex + 1] = g_highSolid[barIndex]; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Cast the timeframe to string value | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ string CastTFToString(ENUM_TIMEFRAMES tf) { switch(tf) { case PERIOD_H1: return "H1"; case PERIOD_H4: return "H4"; case PERIOD_D1: return "D1"; case PERIOD_W1: return "W1"; case PERIOD_MN1: return "MN1"; } return "M" + IntegerToString((int)tf); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| To process of breakout of resistance level | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ProcessResistanceBreak(int barIndex) { g_curTrend[barIndex] = TREND_TYPE_UPWARD; g_highDot[barIndex + 1] = g_highSolid[barIndex + 1]; g_highDot[barIndex] = (g_highSolid[barIndex] == EMPTY_VALUE)? g_highSolid[barIndex + 1] : g_highSolid[barIndex]; g_highSolid[barIndex] = EMPTY_VALUE; if (g_lowDot[barIndex + 1] == EMPTY_VALUE) return; g_lowSolid[barIndex + 1] = g_lowDot[barIndex + 1]; g_lowSolid[barIndex] = (g_lowDot[barIndex] == EMPTY_VALUE)? g_lowDot[barIndex + 1] : g_lowDot[barIndex]; g_lowDot[barIndex] = EMPTY_VALUE; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| To process of breakout of the support level | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ProcessSupportBreak(int barIndex) { g_curTrend[barIndex] = TREND_TYPE_DOWNWARD; g_lowDot[barIndex + 1] = g_lowSolid[barIndex + 1]; g_lowDot[barIndex] = (g_lowSolid[barIndex] == EMPTY_VALUE)? g_lowSolid[barIndex + 1] : g_lowSolid[barIndex]; g_lowSolid[barIndex] = EMPTY_VALUE; if (g_highDot[barIndex + 1] == EMPTY_VALUE) return; g_highSolid[barIndex + 1] = g_highDot[barIndex + 1]; g_highSolid[barIndex] = (g_highDot[barIndex] == EMPTY_VALUE)? g_highDot[barIndex + 1] : g_highDot[barIndex]; g_highDot[barIndex] = EMPTY_VALUE; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Calculation of the indicators values at the specified bar | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void CalculateOneBarMA(int barIndex) { double maFast = iMA(NULL, 0, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, barIndex); double maSlow = iMA(NULL, 0, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, barIndex); double maFast2 = iMA(NULL, 0, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, barIndex + 1); double maSlow2 = iMA(NULL, 0, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, barIndex + 1); ContinuityBuffers(barIndex); if (maFast > maSlow && maFast2 < maSlow2) ProcessUpwardMACross(barIndex); if (maFast < maSlow && maFast2 > maSlow2) ProcessDownwardMACross(barIndex); if (g_curTrend[barIndex] != TREND_TYPE_UPWARD && Close[barIndex] > g_highSolid[barIndex]) { ProcessResistanceBreak(barIndex); return; } if (g_curTrend[barIndex] != TREND_TYPE_DOWNWARD && Close[barIndex] < g_lowSolid[barIndex] && g_lowSolid[barIndex] != EMPTY_VALUE) ProcessSupportBreak(barIndex); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Alert and notification on trend change | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void SignalOnTrendChange(string text) { static datetime lastSignal = 0; if (lastSignal >= Time[0]) return; lastSignal = Time[0]; if (i_isAlert) Alert(_Symbol, ", ", CastTFToString((ENUM_TIMEFRAMES)_Period), ": ", text); if (i_isPush) SendNotification(_Symbol + ", " + CastTFToString((ENUM_TIMEFRAMES)_Period) + ": " + text); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Calculation of indicators values | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void CalcIndicatorData(int limit, int total) { for (int i = limit; i >= 0; i--) CalculateOneBarMA(i); if (g_curTrend[1] == TREND_TYPE_UPWARD && g_curTrend[2] != TREND_TYPE_UPWARD) SignalOnTrendChange(GetStringByMessageCode(MESSAGE_CODE_TREND_CHANGE_TO_UPWARD)); if (g_curTrend[1] == TREND_TYPE_DOWNWARD && g_curTrend[2] != TREND_TYPE_DOWNWARD) SignalOnTrendChange(GetStringByMessageCode(MESSAGE_CODE_TREND_CHANGE_TO_DOWNWARD)); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| 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 (!g_activate) return rates_total; int total; int limit = GetRecalcIndex(total, rates_total, prev_calculated); CalcIndicatorData(limit, total); return rates_total; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Getting string by code of message and terminal language | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ string GetStringByMessageCode(ENUM_MESSAGE_CODE messageCode) { string language = TerminalInfoString(TERMINAL_LANGUAGE); if (language == "Russian") return GetRussianMessage(messageCode); return GetEnglishMessage(messageCode); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Getting string by code of message for russian language | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ string GetRussianMessage(ENUM_MESSAGE_CODE messageCode) { switch (messageCode) { case MESSAGE_CODE_MA_FAST_LESS_THAN_ZERO: return ": период расчета быстрого среднего должен быть больше нуля. Индикатор отключен."; case MESSAGE_CODE_MA_SLOW_LESS_THAN_ZERO: return ": период расчета медленного среднего должен быть больше нуля. Индикатор отключен."; case MESSAGE_CODE_TERMINAL_FATAL_ERROR1: return ": фатальная ошибка терминала - пункт равен нулю. Индикатор отключен."; case MESSAGE_CODE_BIND_ERROR: return ": ошибка связывания массивов с буферами индикатора. Ошибка №"; case MESSAGE_CODE_TREND_CHANGE_TO_UPWARD: return ": смена тренда. Новый тренд - восходящий."; case MESSAGE_CODE_TREND_CHANGE_TO_DOWNWARD: return ": смена тренда. Новый тренд - нисходящий."; } return ""; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Getting string by code of message for english language | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ string GetEnglishMessage(ENUM_MESSAGE_CODE messageCode) { switch (messageCode) { case MESSAGE_CODE_MA_FAST_LESS_THAN_ZERO: return ": calculation period of fast MA must be more than zero. The indicator is turned off."; case MESSAGE_CODE_MA_SLOW_LESS_THAN_ZERO: return ": calculation period of slow MA must be more than zero. The indicator is turned off."; case MESSAGE_CODE_TERMINAL_FATAL_ERROR1: return ": terminal fatal error - point equals to zero. The indicator is turned off."; case MESSAGE_CODE_BIND_ERROR: return ": error of binding of the arrays and the indicator buffers. Error N"; case MESSAGE_CODE_TREND_CHANGE_TO_UPWARD: return ": change of trend. The new trend - upward."; case MESSAGE_CODE_TREND_CHANGE_TO_DOWNWARD: return ": change of trend. The new trend - downward."; } return ""; }