#property copyright "Scriptong" #property link "http://advancetools.net" #property description "English: Horizontal channel, based on extremums between the crossing of the two Moving Averages. Multi timeframes version.\nRussian: Горизонтальный канал, опирающийся на экстремумы между пересечениями двух Moving Average. Мультипериодная версия." #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 #define TF_AMOUNT 9 #define START_Y_OFFSET 12 #define STEP_Y 15 #define START_X_OFFSET 12 #define STEP_X 23 #define FONT_SIZE_TEXT 8 #define FONT_SIZE_ARROW 10 #define FONT_NAME_TEXT "Constantia" #define FONT_NAME_ARROW "Wingdings" #define PREFIX "MACCMTF_" #define LABEL_TF_NAME "TF_NAME_" #define LABEL_TREND "TREND_" #define LABEL_PRICE_LOC "PRICE_LOC_" #define VERT_LINE "VERT_LINE" #define VERT_LINE_COLOR clrDodgerBlue #define VERT_LINE_STYLE 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_BASE_CORNER i_corner = CORNER_RIGHT_UPPER; // Corner for the summary / Угол для отображения саммари input ENUM_YESNO i_useM1 = YES; // Show the data of M1 TF / Отображать данные ТФ М1 input ENUM_YESNO i_useM5 = YES; // Show the data of M5 TF / Отображать данные ТФ М5 input ENUM_YESNO i_useM15 = YES; // Show the data of M15 TF / Отображать данные ТФ М15 input ENUM_YESNO i_useM30 = YES; // Show the data of M30 TF / Отображать данные ТФ М30 input ENUM_YESNO i_useH1 = YES; // Show the data of H1 TF / Отображать данные ТФ H1 input ENUM_YESNO i_useH4 = YES; // Show the data of H4 TF / Отображать данные ТФ H4 input ENUM_YESNO i_useD1 = YES; // Show the data of D1 TF / Отображать данные ТФ D1 input ENUM_YESNO i_useW1 = YES; // Show the data of W1 TF / Отображать данные ТФ W1 input ENUM_YESNO i_useMN1 = YES; // Show the data of MN1 TF / Отображать данные ТФ МN1 input color i_upwardTrendColor = clrBlue; // Color of arrow up / Цвет стрелки вверх input color i_downwardTrendColor = clrRed; // Color of arrow down / Цвет стрелки вниз input color i_undefinedTrendColor = clrLime; // Color of arrow right / Цвет стрелки вправо input color i_textColor = clrGreen; // Color of table header / Цвет шапки таблицы input ENUM_YESNO i_showFocusBar = YES; // Show the selected bar? / Отображать ли выбранный бар? input int i_indBarsCount = 10000; // Number of bars to display / Кол-во баров отображения 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_BIND_ERROR }; struct TFInfo { bool isShow; ENUM_TIMEFRAMES tf; string tfName; double highLimit; double lowLimit; ENUM_TREND_TYPE curTrend; }; // Global variables bool g_activate; int g_maxMAPeriod; datetime g_focusBarTime; double g_point, g_delta; ENUM_ANCHOR_POINT g_anchor; TFInfo g_tfInfo[TF_AMOUNT]; // Arrays for buffers of the indicators 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; FormTheTFArray(); if (!BuffersBind()) return INIT_FAILED; g_anchor = (i_corner == CORNER_RIGHT_UPPER || i_corner == CORNER_LEFT_UPPER)? ANCHOR_UPPER : ANCHOR_LOWER; g_focusBarTime = 0; if (i_showFocusBar == YES) ShowVLine(Time[0]); ShowSummaryTitle(); 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; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Formation the data of the TFs array | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void FormTheTFArray() { SaveTheTF(0, i_useM1 == YES, PERIOD_M1, "M1"); SaveTheTF(1, i_useM5 == YES, PERIOD_M5, "M5"); SaveTheTF(2, i_useM15 == YES, PERIOD_M15, "M15"); SaveTheTF(3, i_useM30 == YES, PERIOD_M30, "M30"); SaveTheTF(4, i_useH1 == YES, PERIOD_H1, "H1"); SaveTheTF(5, i_useH4 == YES, PERIOD_H4, "H4"); SaveTheTF(6, i_useD1 == YES, PERIOD_D1, "D1"); SaveTheTF(7, i_useW1 == YES, PERIOD_W1, "W1"); SaveTheTF(8, i_useMN1 == YES, PERIOD_MN1, "MN1"); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Save the data of one TF | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void SaveTheTF(const int index, const bool isShow, const ENUM_TIMEFRAMES tf, const string tfName) { g_tfInfo[index].isShow = isShow; g_tfInfo[index].tf = tf; g_tfInfo[index].tfName = tfName; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show one TF name | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowOneTFName(const int tfIndex, const int yCoord, int& xCoord) { if (!g_tfInfo[tfIndex].isShow) return; ShowLabel(LABEL_TF_NAME + (string)tfIndex, xCoord, yCoord, g_tfInfo[tfIndex].tfName, i_textColor, FONT_NAME_TEXT, FONT_SIZE_TEXT); xCoord += STEP_X; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show the title for summary | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowSummaryTitle() { int y = START_Y_OFFSET; if (i_corner == CORNER_RIGHT_LOWER || i_corner == CORNER_LEFT_LOWER) y += 2 * STEP_Y; int x = START_X_OFFSET; if (i_corner == CORNER_RIGHT_LOWER || i_corner == CORNER_RIGHT_UPPER) { for (int i = TF_AMOUNT - 1; i >= 0; i--) ShowOneTFName(i, y, x); } else for (int i = 0; i < TF_AMOUNT; i++) ShowOneTFName(i, y, x); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void OnDeinit(const int reason) { DeleteObjectsAll(); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Deleting the objects created by program | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void DeleteObjectsAll() { for (int i = ObjectsTotal() - 1; i >= 0; i--) if (StringSubstr(ObjectName(i), 0, StringLen(PREFIX)) == PREFIX) ObjectDelete(ObjectName(i)); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Binding of array and the indicator buffers | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ bool BuffersBind() { string name = WindowExpertName(); // Связывание буферов индикатора с массивами 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(const int barIndex, const ENUM_TIMEFRAMES tf) { double lowPrice = iLow(NULL, tf, barIndex); int total = iBars(NULL, tf); for (int i = barIndex + 1; i < total; i++) { double maFast = iMA(NULL, tf, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, i); double maSlow = iMA(NULL, tf, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, i); if (maFast > maSlow) return lowPrice; lowPrice = MathMin(lowPrice, iLow(NULL, tf, i)); } return lowPrice; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| The maximal price at the downtrend interval | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ double GetHighPrice(const int barIndex, const ENUM_TIMEFRAMES tf) { double highPrice = iHigh(NULL, tf, barIndex); int total = iBars(NULL, tf); for (int i = barIndex + 1; i < total; i++) { double maFast = iMA(NULL, tf, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, i); double maSlow = iMA(NULL, tf, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, i); if (maFast < maSlow) return highPrice; highPrice = MathMax(highPrice, iHigh(NULL, tf, 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, (ENUM_TIMEFRAMES)_Period); 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, (ENUM_TIMEFRAMES)_Period); 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, (ENUM_TIMEFRAMES)_Period); 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, (ENUM_TIMEFRAMES)_Period); g_highDot[barIndex] = EMPTY_VALUE; if (g_highSolid[barIndex + 1] == EMPTY_VALUE) g_highSolid[barIndex + 1] = g_highSolid[barIndex]; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| 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); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Data at all TFs need to recalculate on all history interval | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void RecalculateTFsData(const int total) { for (uint i = 0; i < TF_AMOUNT; i++) { if (!g_tfInfo[i].isShow) continue; g_tfInfo[i].lowLimit = EMPTY_VALUE; g_tfInfo[i].highLimit = EMPTY_VALUE; g_tfInfo[i].curTrend = TREND_TYPE_NONE; int toBarIndex = 0; if (g_focusBarTime != 0) toBarIndex = (int)MathMax(iBarShift(NULL, g_tfInfo[i].tf, g_focusBarTime), 0); for (int j = total; j > toBarIndex; j--) CalculateTFData(j, i); } } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Calculation data for all used TFs | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void CalculateTFData(const int tfBarIndex, const int tfIndex) { // Do not calculate data for unformed candle if (tfBarIndex <= 0 || tfBarIndex >= iBars(NULL, g_tfInfo[tfIndex].tf)) return; // Calculate MAs values double maFast = iMA(NULL, g_tfInfo[tfIndex].tf, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, tfBarIndex); double maSlow = iMA(NULL, g_tfInfo[tfIndex].tf, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, tfBarIndex); double maFast2 = iMA(NULL, g_tfInfo[tfIndex].tf, i_maFastPeriod, 0, i_maFastMethod, i_maFastPrice, tfBarIndex + 1); double maSlow2 = iMA(NULL, g_tfInfo[tfIndex].tf, i_maSlowPeriod, 0, i_maSlowMethod, i_maSlowPrice, tfBarIndex + 1); // Upward MA cross if (maFast > maSlow && maFast2 < maSlow2) g_tfInfo[tfIndex].lowLimit = GetLowPrice(tfBarIndex, g_tfInfo[tfIndex].tf); // Downward MA cross if (maFast < maSlow && maFast2 > maSlow2) g_tfInfo[tfIndex].highLimit = GetHighPrice(tfBarIndex, g_tfInfo[tfIndex].tf); // Breaking the resistance level if (g_tfInfo[tfIndex].curTrend != TREND_TYPE_UPWARD && iClose(NULL, g_tfInfo[tfIndex].tf, tfBarIndex) > g_tfInfo[tfIndex].highLimit) { g_tfInfo[tfIndex].curTrend = TREND_TYPE_UPWARD; return; } // Breaking the support level if (g_tfInfo[tfIndex].curTrend != TREND_TYPE_DOWNWARD && iClose(NULL, g_tfInfo[tfIndex].tf, tfBarIndex) < g_tfInfo[tfIndex].lowLimit && g_tfInfo[tfIndex].lowLimit != EMPTY_VALUE) g_tfInfo[tfIndex].curTrend = TREND_TYPE_DOWNWARD; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Convert the trend type to arrow | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ string GetStringTrend(const ENUM_TREND_TYPE trendType) { switch (trendType) { case TREND_TYPE_DOWNWARD: return CharToString(226); case TREND_TYPE_UPWARD: return CharToString(225); } return CharToString(251); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Convert the trend type to color | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ color GetColorTrend(const ENUM_TREND_TYPE trendType) { switch (trendType) { case TREND_TYPE_DOWNWARD: return i_downwardTrendColor; case TREND_TYPE_UPWARD: return i_upwardTrendColor; } return i_undefinedTrendColor; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show the text label | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowLabel(string labelID, int x, int y, string text, color clr, string fontName, int fontSize) { string name = PREFIX + labelID; if (ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, i_corner); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_ANCHOR, g_anchor); ObjectSetString(0, name, OBJPROP_FONT, fontName); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); return; } ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetString(0, name, OBJPROP_TEXT, text); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show the vertical line | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowVLine(datetime time) { string name = PREFIX + VERT_LINE; if (ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_VLINE, 0, time, 1); ObjectSetInteger(0, name, OBJPROP_COLOR, VERT_LINE_COLOR); ObjectSetInteger(0, name, OBJPROP_STYLE, VERT_LINE_STYLE); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); return; } ObjectSetInteger(0, name, OBJPROP_TIME1, time); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show one character | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowOneChar(const int tfIndex, const int yCoord, int& xCoord) { if (!g_tfInfo[tfIndex].isShow) return; ShowLabel(LABEL_TREND + (string)tfIndex, xCoord, yCoord, GetStringTrend(g_tfInfo[tfIndex].curTrend), GetColorTrend(g_tfInfo[tfIndex].curTrend), FONT_NAME_ARROW, FONT_SIZE_ARROW); xCoord += STEP_X; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Define the arrow that correspond to the relative location of price and channel | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ string GetStringPriceLocation(const TFInfo& tfInfo, const double price, color& clr) { clr = i_undefinedTrendColor; // Undefined trend direction if (tfInfo.curTrend == TREND_TYPE_NONE) return CharToString(251); // Price is located higher than channel if (tfInfo.highLimit < price) { clr = i_upwardTrendColor; return CharToString(217); } // Price is located lower than channel if (tfInfo.lowLimit > price) { clr = i_downwardTrendColor; return CharToString(218); } // Price is located in a channel return CharToString(216); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show line of the summary that displaying the direction of trend | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowTrendDirectionLine(const int y) { int x = START_X_OFFSET; if (i_corner == CORNER_RIGHT_LOWER || i_corner == CORNER_RIGHT_UPPER) { for (int i = TF_AMOUNT - 1; i >= 0; i--) ShowOneChar(i, y, x); } else for (int i = 0; i < TF_AMOUNT; i++) ShowOneChar(i, y, x); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show price location one character | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowOneCharPriceLocation(const int tfIndex, const int yCoord, int& xCoord, const double price) { if (!g_tfInfo[tfIndex].isShow) return; color arrowColor = clrNONE; string arrow = GetStringPriceLocation(g_tfInfo[tfIndex], price, arrowColor); ShowLabel(LABEL_PRICE_LOC + (string)tfIndex, xCoord, yCoord, arrow, arrowColor, FONT_NAME_ARROW, FONT_SIZE_ARROW); xCoord += STEP_X; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show line of summary that displaying price location relative to the channel | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowPriceLocation(const int y, const double price) { int x = START_X_OFFSET; if (i_corner == CORNER_RIGHT_LOWER || i_corner == CORNER_RIGHT_UPPER) { for (int i = TF_AMOUNT - 1; i >= 0; i--) ShowOneCharPriceLocation(i, y, x, price); } else for (int i = 0; i < TF_AMOUNT; i++) ShowOneCharPriceLocation(i, y, x, price); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Show the data from timeframes | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void ShowSummary(const double price) { if (i_corner == CORNER_LEFT_UPPER || i_corner == CORNER_RIGHT_UPPER) { int y = START_Y_OFFSET + STEP_Y; ShowTrendDirectionLine(y); y += STEP_Y; ShowPriceLocation(y, price); } else { int y = START_Y_OFFSET; ShowPriceLocation(y, price); y += STEP_Y; ShowTrendDirectionLine(y); } } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Calculation of indicators values | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void CalcIndicatorData(int limit, int total) { // Initialize the start data if (limit > 1) RecalculateTFsData(total); // Calculate all data of indicator for (int i = limit; i >= 0; i--) { CalculateOneBarMA(i); if (g_focusBarTime != 0) continue; for (int j = 0; j < TF_AMOUNT; j++) { if (!g_tfInfo[j].isShow) continue; int tfBarIndex = iBarShift(NULL, g_tfInfo[j].tf, Time[i]); if (tfBarIndex == 1) CalculateTFData(1, j); } } // Show the data from timeframes if (g_focusBarTime == 0) ShowSummary(Bid); // Show the focus bar if (limit == 1 && i_showFocusBar == YES) ShowVLine((g_focusBarTime == 0)? Time[0] : g_focusBarTime); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| 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; } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Process the events on a chart | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ void OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam) { // Processing only one event - click of left mouse button if (id != CHARTEVENT_CLICK) return; // Convert the decart coordinates to the coordinates of time and price double price = 0.0; datetime time = 0; int subWindow = 0; if (!ChartXYToTimePrice(0, (int)lparam, (int)dparam, subWindow, time, price)) return; // Find the bar index by place where mouse click has occurred int barIndex = iBarShift(NULL, 0, time); if (barIndex < 0 || barIndex >= Bars) return; // Processing the click if mouse coordinates are inside the bar if (price > High[barIndex] || price < Low[barIndex]) return; // Show new position of vertical line g_focusBarTime = (barIndex == 0)? 0 : Time[barIndex]; if (i_showFocusBar == YES) ShowVLine((g_focusBarTime == 0)? Time[0] : g_focusBarTime); // Recalculate TFs data int total = i_indBarsCount; if (total == 0 || total > Bars - g_maxMAPeriod - 2) total = Bars - g_maxMAPeriod - 2; RecalculateTFsData(total); // Show calculated data ShowSummary(Open[barIndex]); } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| 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 ": ошибка связывания массивов с буферами индикатора. Ошибка №"; } 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"; } return ""; }