#property copyright "Copyright © 2011, Murad Ismayilov" #property link "http://www.mql4.com/ru/users/wmlab" #property indicator_chart_window #property indicator_buffers 6 #property indicator_style1 STYLE_DOT #property indicator_width1 1 #property indicator_color1 Sienna #property indicator_style2 STYLE_DOT #property indicator_width2 1 #property indicator_color2 Sienna #property indicator_style3 STYLE_SOLID #property indicator_width3 2 #property indicator_color3 DodgerBlue #property indicator_style4 STYLE_SOLID #property indicator_width4 2 #property indicator_color4 DodgerBlue #property indicator_style5 STYLE_SOLID #property indicator_width5 1 #property indicator_color5 DodgerBlue #property indicator_style6 STYLE_SOLID #property indicator_width6 1 #property indicator_color6 DodgerBlue #include #include #define DOUBLEMAX 1000000.0 #define DOUBLEMIN -1000000.0 // Внешние переменные extern bool IsTopCorner = true; // Информационный блок в верхнем углу? extern int Offset = 1; // Смещение исходного образца в барах (для проверки надежности прогноза) [1..] extern bool IsOffsetStartFixed = true; // Фиксировано ли начало образца extern bool IsOffsetEndFixed = false; // Фиксирован ли конец образца extern int PastBars = 24; // Размер образца в барах, который ищется на истории [3..] extern int ForecastBars = 24; // На сколько баров вперед делать прогноз [1..] extern int MaxAlts = 5; // Искать указанное кол-во лучших образцов [1..100] extern bool ShowCloud = true; // Показывать ли облако extern bool ShowBestPattern = true; // Показывать ли максимально близкий образец extern bool IsExactTime = true; // Должно ли совпадать время образцов (для учета эффекта сессий) extern datetime MinDate = D'01.01.2001'; // Минимальная дата образца extern int PeriodMA = 2; // Периуд сглаженной средней extern double ScalePercents = 90.0; // Рассматривать только образцы с этим минимальным процентом совпадения extern color IndicatorCloudColor = Sienna; // Цвет облака похожих вариантов extern color IndicatorBestPatternColor = DodgerBlue; // Цвет самого похожего образца extern color IndicatorVLinesColor = Sienna; // Цвет вертикальных линий-границ образца extern color IndicatorTextColor = MediumBlue; // Цвет текста инф.блока extern color IndicatorTextWarningColor = Tomato; // Цвет предупреждений в тестовом инф.блоке extern int XCorner = 5; // Отступ инф.блока индикатора от правой границы графика extern int YCorner = 5; // Отступ инф.блока индикатора от верхней границы графика extern string FontName = "Arial"; // Шрифт тестового инф.блока extern int FontSize = 7; // Размер шрифта тестового инф.блока // Глобальные переменные string IndicatorName = "WmiFor"; string IndicatorVersion = "2.2"; string IndicatorAuthor = "Мурад Исмайлов (wmlab@hotmail.com)"; datetime OffsetStart, OffsetEnd; bool IsRedraw; datetime LastRedraw; double ForecastCloudHigh[]; double ForecastCloudLow[]; double ForecastBestPatternOpen[]; double ForecastBestPatternClose[]; double ForecastBestPatternHigh[]; double ForecastBestPatternLow[]; //+------------------------------------------------------------------+ //| Инициализация | //+------------------------------------------------------------------+ int init() { if (Offset < 1) { Offset = 1; } if (PastBars < 3) { PastBars = 3; } if (ForecastBars < 1) { ForecastBars = 1; } if (MaxAlts < 1) { MaxAlts = 1; } else { if (MaxAlts > 100) { MaxAlts = 100; } } SetIndexBuffer(0, ForecastCloudHigh); SetIndexStyle(0, DRAW_HISTOGRAM, EMPTY, EMPTY, IndicatorCloudColor); SetIndexShift(0, ForecastBars - Offset); SetIndexBuffer(1, ForecastCloudLow); SetIndexStyle(1, DRAW_HISTOGRAM, EMPTY, EMPTY, IndicatorCloudColor); SetIndexShift(1, ForecastBars - Offset); SetIndexBuffer(2, ForecastBestPatternOpen); SetIndexStyle(2, DRAW_HISTOGRAM, STYLE_SOLID, EMPTY, IndicatorBestPatternColor); SetIndexShift(2, ForecastBars - Offset); SetIndexBuffer(3, ForecastBestPatternClose); SetIndexStyle(3, DRAW_HISTOGRAM, STYLE_SOLID, EMPTY, IndicatorBestPatternColor); SetIndexShift(3, ForecastBars - Offset); SetIndexBuffer(4, ForecastBestPatternHigh); SetIndexStyle(4, DRAW_HISTOGRAM, STYLE_SOLID, EMPTY, IndicatorBestPatternColor); SetIndexShift(4, ForecastBars - Offset); SetIndexBuffer(5, ForecastBestPatternLow); SetIndexStyle(5, DRAW_HISTOGRAM, STYLE_SOLID, EMPTY, IndicatorBestPatternColor); SetIndexShift(5, ForecastBars - Offset); LoadHistory(Period()); RemoveOurObjects(); IsRedraw = true; return (0); } //+------------------------------------------------------------------+ //| Деинициализация | //+------------------------------------------------------------------+ int deinit() { RemoveOurObjects(); return (0); } //+------------------------------------------------------------------+ //| Работа индикатора | //+------------------------------------------------------------------+ int start() { int counted_bars = IndicatorCounted(); if (IsRedraw) { ReCalculate(); } // Проверка на наличие вертикальных линий datetime time1; string vlineOffsetStart = IndicatorName + "OffsetStart"; if (ObjectFind(vlineOffsetStart) == -1) { time1 = iTime(NULL, 0, Offset + PastBars - 1); ObjectCreate(vlineOffsetStart, OBJ_VLINE, 0, time1, 0); ObjectSetText(vlineOffsetStart, "НАЧАЛО ОБРАЗЦА", 0); ObjectSet(vlineOffsetStart, OBJPROP_COLOR, IndicatorVLinesColor); ObjectSet(vlineOffsetStart, OBJPROP_STYLE, STYLE_SOLID); ObjectSet(vlineOffsetStart, OBJPROP_WIDTH, 1); } string vlineOffsetEnd = IndicatorName + "OffsetEnd"; if (ObjectFind(vlineOffsetEnd) == -1) { time1 = iTime(NULL, 0, Offset); ObjectCreate(vlineOffsetEnd, OBJ_VLINE, 0, time1, 0); ObjectSetText(vlineOffsetEnd, "КОНЕЦ ОБРАЗЦА", 0); ObjectSet(vlineOffsetEnd, OBJPROP_COLOR, IndicatorVLinesColor); ObjectSet(vlineOffsetEnd, OBJPROP_STYLE, STYLE_SOLID); ObjectSet(vlineOffsetEnd, OBJPROP_WIDTH, 1); } datetime datetimeOffsetStart = ObjectGet(vlineOffsetStart, OBJPROP_TIME1); int indexOffsetStart = iBarShift(Symbol(), 0, datetimeOffsetStart); datetime datetimeOffsetEnd = ObjectGet(vlineOffsetEnd, OBJPROP_TIME1); int indexOffsetEnd = iBarShift(Symbol(), 0, datetimeOffsetEnd); // Проверка на их корректную установку if (indexOffsetEnd < 1) { indexOffsetEnd = 1; datetimeOffsetEnd = iTime(NULL, 0, indexOffsetEnd); ObjectSet(vlineOffsetEnd, OBJPROP_TIME1, datetimeOffsetEnd); ChangeOffset(1); } if ((indexOffsetStart - indexOffsetEnd + 1) < 3) { indexOffsetStart = indexOffsetEnd + 2; PastBars = 3; datetimeOffsetStart = iTime(NULL, 0, indexOffsetStart); ObjectSet(vlineOffsetStart, OBJPROP_TIME1, datetimeOffsetStart); } // Линии передвигали вручную? if (datetimeOffsetEnd != OffsetEnd) { ChangeOffset(indexOffsetEnd); } if ((indexOffsetStart - indexOffsetEnd + 1) != PastBars) { PastBars = indexOffsetStart - indexOffsetEnd + 1; } // Наступил новый бар? if (IsNewBar()) { // Нужно сдвинуть образец? if (!IsOffsetStartFixed && !IsOffsetEndFixed) { datetimeOffsetStart = iTime(NULL, 0, Offset + PastBars - 1); ObjectSet(vlineOffsetStart, OBJPROP_TIME1, datetimeOffsetStart); } if (!IsOffsetEndFixed) { datetimeOffsetEnd = iTime(NULL, 0, Offset); ObjectSet(vlineOffsetEnd, OBJPROP_TIME1, datetimeOffsetEnd); } } // Линии передвинулись? if ((datetimeOffsetStart != OffsetStart) || (datetimeOffsetEnd != OffsetEnd)) { OffsetStart = datetimeOffsetStart; OffsetEnd = datetimeOffsetEnd; IsRedraw = true; LastRedraw = TimeCurrent(); } return (0); } //+------------------------------------------------------------------+ //| Появился новый бар? | //+------------------------------------------------------------------+ bool IsNewBar() { static datetime prevTime = 0; datetime currentTime = iTime(NULL, 0, 0); if (prevTime == currentTime) { return (false); } prevTime = currentTime; return (true); } //+------------------------------------------------------------------+ //| Подгрузка истории | //+------------------------------------------------------------------+ void LoadHistory(int period = 0) { int iPeriod[9]; iPeriod[0] = PERIOD_M1; iPeriod[1] = PERIOD_M5; iPeriod[2] = PERIOD_M15; iPeriod[3] = PERIOD_M30; iPeriod[4] = PERIOD_H1; iPeriod[5] = PERIOD_H4; iPeriod[6] = PERIOD_D1; iPeriod[7] = PERIOD_W1; iPeriod[8] = PERIOD_MN1; for (int i = 0; i < 9; i++) { if ((period != 0) && (period != iPeriod[i])) { continue; } double open = iTime(Symbol(), iPeriod[i], 0); int error = GetLastError(); while (error == ERR_HISTORY_WILL_UPDATED) { Sleep(10000); open = iTime(Symbol(), iPeriod[i], 0); error = GetLastError(); } } } //+------------------------------------------------------------------+ //| Убираем все наши метки | //+------------------------------------------------------------------+ void RemoveOurObjects() { for (int index = 0; index < ObjectsTotal(); index++) { if (StringFind(ObjectName(index), IndicatorName) == 0) { ObjectDelete(ObjectName(index)); index--; } } } //+------------------------------------------------------------------+ //| Убираем все наши метки | //+------------------------------------------------------------------+ void ChangeOffset(int newOffset) { Offset = newOffset; for (int indexIndicator = 0; indexIndicator < 6; indexIndicator++) { SetIndexShift(indexIndicator, ForecastBars - Offset); } } //+------------------------------------------------------------------+ //| Пересчет | //+------------------------------------------------------------------+ void ReCalculate() { datetime currentTime = TimeCurrent(); if ((currentTime - LastRedraw) < 1) { return; } LastRedraw = currentTime; IsRedraw = false; if (Bars < 100) { return; } int indexBar; double x[], xp[]; double xhighest, xlowest; int foundAlts; double iAlt[], kAlt[], sAlt[]; double y[], yp[]; double yhighest, ylowest; double scale, scalep; double kspearman, kh, kl; int patternscount; bool altAdded; datetime ytime; int baseHour = TimeHour(iTime(NULL, 0, Offset)); int baseMinute = TimeMinute(iTime(NULL, 0, Offset)); // Снимаем образец и пишем исходные значения ArrayResize(x, PastBars); for (indexBar = 0; indexBar < PastBars; indexBar++) { x[indexBar] = iMA(NULL, 0, PeriodMA, 0, MODE_LWMA, PRICE_CLOSE, indexBar + Offset); } xhighest = x[ArrayMaximum(x)]; xlowest = x[ArrayMinimum(x)]; ArrayResize(xp, PastBars); SpearmenRange(x, xp); // Готовимся к поиску похожих фрагментов foundAlts = 0; patternscount = 0; ArrayResize(iAlt, MaxAlts); ArrayResize(kAlt, MaxAlts); ArrayResize(sAlt, MaxAlts); // Поиск по циклу похожего фрагмента for (int indexShift = ForecastBars + Offset + 1; indexShift < Bars; indexShift++) { ytime = iTime(NULL, 0, indexShift); if (IsExactTime) { // Время образцов должно совпадать int currentHour = TimeHour(ytime); if (currentHour != baseHour) { continue; } int currentMinute = TimeMinute(ytime); if (currentMinute != baseMinute) { continue; } } if ((indexShift + PastBars) >= Bars) { // Образец близко к началу истории break; } if (ytime < MinDate) { // Образец слишком старый break; } patternscount++; // Снимаем образец и пишем исходные значения ArrayResize(y, PastBars); for (indexBar = 0; indexBar < PastBars; indexBar++) { y[indexBar] = iMA(NULL, 0, PeriodMA, 0, MODE_LWMA, PRICE_CLOSE, indexBar + indexShift); } yhighest = y[ArrayMaximum(y)]; ylowest = y[ArrayMinimum(y)]; ArrayResize(yp, PastBars); SpearmenRange(y, yp); // Масштаб scale = (xhighest - xlowest) / (yhighest - ylowest); if (scale > 1.0) { scalep = 100.0 / scale; } else { scalep = 100.0 * scale; } if (scalep < ScalePercents) { continue; } // Проверка корреляции kspearman = SpearmenCorrelation(xp, yp); if ( ((foundAlts == 0) && (kspearman <= 0.0)) || ((foundAlts > 0) && (kspearman < (kAlt[0] - 1.0))) ) { continue; } // Добавляем образец в отсортированный список найденных altAdded = false; for (int j = 0; j < foundAlts; j++) { if (kspearman > kAlt[j]) { if (foundAlts == MaxAlts) { foundAlts = MaxAlts - 1; } for (int m = foundAlts; m >= (j + 1); m--) { kAlt[m] = kAlt[m - 1]; iAlt[m] = iAlt[m - 1]; sAlt[m] = sAlt[m - 1]; } kAlt[j] = kspearman; iAlt[j] = indexShift; sAlt[j] = scale; foundAlts++; altAdded = true; break; } } if (!altAdded) { if (foundAlts < MaxAlts) { kAlt[j] = kspearman; iAlt[j] = indexShift; sAlt[j] = scale; foundAlts++; } } } // Отсекаем лишние варианты if (foundAlts > 1) { for (int a = 1; a < foundAlts; a++) { if (kAlt[a] < (kAlt[0] - 1.0)) { foundAlts = a; break; } } } double xcbase, ycbase; int alt, altindex; ArrayInitialize(ForecastCloudHigh, EMPTY_VALUE); ArrayInitialize(ForecastCloudLow, EMPTY_VALUE); if (ShowCloud && (foundAlts > 0)) { double forecastCloudHigh; double forecastCloudLow; double yhigh, ylow; // Рисуем облако xcbase = iClose(NULL, 0, Offset); for (indexBar = 0; indexBar < (PastBars + ForecastBars); indexBar++) { forecastCloudHigh = DOUBLEMIN; forecastCloudLow = DOUBLEMAX; for (alt = 0; alt < foundAlts; alt++) { altindex = iAlt[alt] - ForecastBars + indexBar; ycbase = iClose(NULL, 0, iAlt[alt]); yhigh = xcbase + ((iHigh(NULL, 0, altindex) - ycbase) * sAlt[alt]); if (yhigh > forecastCloudHigh) { forecastCloudHigh = yhigh; } ylow = xcbase + ((iLow(NULL, 0, altindex) - ycbase) * sAlt[alt]); if (ylow < forecastCloudLow) { forecastCloudLow = ylow; } } ForecastCloudHigh[indexBar] = forecastCloudHigh; ForecastCloudLow[indexBar] = forecastCloudLow; } } ArrayInitialize(ForecastBestPatternOpen, EMPTY_VALUE); ArrayInitialize(ForecastBestPatternClose, EMPTY_VALUE); ArrayInitialize(ForecastBestPatternHigh, EMPTY_VALUE); ArrayInitialize(ForecastBestPatternLow, EMPTY_VALUE); if (ShowBestPattern && (foundAlts > 0)) { xcbase = iClose(NULL, 0, Offset); ycbase = iClose(NULL, 0, iAlt[0]); for (indexBar = 0; indexBar < (PastBars + ForecastBars); indexBar++) { altindex = iAlt[0] - ForecastBars + indexBar; ForecastBestPatternOpen[indexBar] = xcbase + ((iOpen(NULL, 0, altindex) - ycbase) * sAlt[0]); ForecastBestPatternClose[indexBar] = xcbase + ((iClose(NULL, 0, altindex) - ycbase) * sAlt[0]); ForecastBestPatternHigh[indexBar] = xcbase + ((iHigh(NULL, 0, altindex) - ycbase) * sAlt[0]); ForecastBestPatternLow[indexBar] = xcbase + ((iLow(NULL, 0, altindex) - ycbase) * sAlt[0]); } } // Рисуем текстовый блок DrawLabel("Name", "Индикатор " + IndicatorName + ", версия " + IndicatorVersion, 0, 0, IndicatorTextColor); DrawLabel("Author", IndicatorAuthor, 0, 10, IndicatorTextColor); if (patternscount < 100) { DrawLabel("Alt1", "СОВЕТ: Подгрузите историю " + Symbol(), 0, 25, IndicatorTextWarningColor); } else { DrawLabel("Alt1", "Всего рассмотрено образцов: " + patternscount, 0, 25, IndicatorTextColor); } if (foundAlts == 0) { DrawLabel("Alt2", "Похожих образцов найдено недостаточно", 0, 35, IndicatorTextColor); DrawLabel("Alt3", "СОВЕТ: Установите ScalePercents меньше " + DoubleToStr(ScalePercents - 5, 0), 0, 45, IndicatorTextWarningColor); } else { double correlationPercents = kAlt[foundAlts - 1]; DrawLabel("Alt2", "Отобрано похожих образцов: " + foundAlts, 0, 35, IndicatorTextColor); DrawLabel("Alt3", "Вероятность исполнения прогноза: " + DoubleToStr(correlationPercents, 0) + "%", 0, 45, IndicatorTextColor); } } //+------------------------------------------------------------------+ //| Ранжирование массива по Cпирмену | //+------------------------------------------------------------------+ void SpearmenRange(double x[], double &xp[]) { int xpi; int arraySize = ArraySize(x); double xlevelmin = DOUBLEMIN; for (int pass = 0; pass < arraySize; pass++) { int ixmin = -1; double xmin = DOUBLEMIN; for (int ix = 0; ix < arraySize; ix++) { if (x[ix] <= xlevelmin) { continue; } if (ixmin == -1) { ixmin = ix; xmin = x[ix]; } else { if (x[ix] < xmin) { ixmin = ix; xmin = x[ix]; } } } xpi++; xp[ixmin] = xpi; xlevelmin = xmin; } } //+------------------------------------------------------------------+ //| Корреляция массивов по Cпирмену | //+------------------------------------------------------------------+ double SpearmenCorrelation(double xp[], double yp[]) { int arraySize = ArraySize(xp); double k = 0.0; for (int indexBar = 0; indexBar < arraySize; indexBar++) { k += (xp[indexBar] - yp[indexBar]) * (xp[indexBar] - yp[indexBar]); } k = (1.0 - ((6.0 * k) / ((arraySize * arraySize * arraySize) - arraySize))) * 100.0; return (k); } //+------------------------------------------------------------------+ //| Рисование текстовой метки | //+------------------------------------------------------------------+ void DrawLabel(string label, string text, int x, int y, color clr) { int typeCorner = 1; if (!IsTopCorner) { typeCorner = 3; } string labelIndicator = IndicatorName + "Label" + label; if (ObjectFind(labelIndicator) == -1) { ObjectCreate(labelIndicator, OBJ_LABEL, 0, 0, 0); } ObjectSet(labelIndicator, OBJPROP_CORNER, typeCorner); ObjectSet(labelIndicator, OBJPROP_XDISTANCE, XCorner + x); ObjectSet(labelIndicator, OBJPROP_YDISTANCE, YCorner + y); ObjectSetText(labelIndicator, text, FontSize, FontName, clr); }