//+-------------------------------------------------------------------------------------+ //| TwoSwings.mq4 | //| Scriptong | //| scriptong@mail.ru | //+-------------------------------------------------------------------------------------+ #property copyright "Scriptong" #property link "scriptong@mail.ru" #property indicator_chart_window //---- input parameters extern int RSIPeriod = 14; extern int RSIHighLevel = 70; extern int RSILowLevel = 30; extern double BCtoABFrom = 1.618; extern double BCtoABTo = 2.0; bool Activate; datetime LastBar; double HighV, LowV, HighBeg, LowBeg; int HighN, LowN, Begin; string prefix = "TWSW_"; //+-------------------------------------------------------------------------------------+ //| Custom indicator initialization function | //+-------------------------------------------------------------------------------------+ int init() { //---- indicators Activate = False; // - 1 - ==================== Проверка корректности входных параметров ================== if (RSIPeriod < 1) { Alert("Период RSI должен быть положительным!"); return(0); } if (RSIHighLevel < 0 || RSIHighLevel > 100) { Alert("Уровень RSIHighLevel должен быть от 0 до 100!"); return(0); } if (RSILowLevel < 0 || RSILowLevel > 100) { Alert("Уровень RSILowLevel должен быть от 0 до 100!"); return(0); } if (RSILowLevel >= RSIHighLevel) { Alert("Уровень RSILowLevel должен быть ниже RSIHighLevel!"); return(0); } if (BCtoABFrom < 0.1) { Alert("Соотношение сторон должно быть больше 0.1!"); return(0); } if (BCtoABTo < BCtoABFrom) { Alert("BCtoABTo должно быть больше BCtoABFrom!"); return(0); } // - 1 - ================================== Окончание блока ============================= LastBar = 0; Activate = True; //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+-------------------------------------------------------------------------------------+ int deinit() { //---- for (int i = ObjectsTotal()-1; i >= 0; i--) if (StringSubstr(ObjectName(i), 0, StringLen(prefix)) == prefix) ObjectDelete(ObjectName(i)); //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Поиск локального экстремума RSI в зонах перекупленности/перепроданности | //+-------------------------------------------------------------------------------------+ int RSIExtremum(int NB) { // - 1 - =========================== Получение начальных значений ======================= double PrevRSI = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, NB-1); double CurRSI = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, NB); // - 1 - =============================== Окончание блока ================================ // - 2 - =========================== Поиск вершины или впадины RSI ====================== for (int i = NB; i < Bars-1; i++) { double NextRSI = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, i+1); if (CurRSI > NextRSI && CurRSI > RSIHighLevel && CurRSI > PrevRSI) // при нахождении return(i*2);// максимума возвращается четное значение, которое соответствует номеру // бара, умноженному на 2 if (CurRSI < NextRSI && CurRSI < RSILowLevel && CurRSI < PrevRSI) // при нахождении return(i*2 + 1); // минимума возвращается нечетное значение, которое соответствует // номеру бара, умноженному на 2, с прибавлением 1 PrevRSI = CurRSI; CurRSI = NextRSI; } // - 2 - =============================== Окончание блока ================================ return(-1); // На всей доступной истории нет значений RSI в зонах перекупленности // или перепроданности } //+-------------------------------------------------------------------------------------+ //| Поиск локальных минимума и максимума после получения сигнала от RSI | //+-------------------------------------------------------------------------------------+ int FindMaxMin(int Ext) { // - 1 - ======================= Сохранение параметров начального бара ================== Begin = MathFloor(Ext/2.0);//Номер бара, на котором зафиксирован локальный экстремум RSI HighBeg = High[Begin]; // Максимум начального бара LowBeg = Low[Begin]; // Минимум начального бара // - 1 - =============================== Окончание блока ================================ // - 2 - ===== Поиск минимума и максимума для расчета первичного свинга ================= for (int i = 2; i < MathMin(Bars - Begin, 250); i++) { // - 2.1 - ================== Поиск нисходящего первичного свинга =================== if (MathMod(Ext, 2) == 0) // Если у RSI зафиксирован максимум, то необходимо найти { // нисходящий свинг AB LowN = iLowest(NULL, 0, MODE_LOW, i, Begin); // сначала подбирается минимум HighN = iHighest(NULL, 0, MODE_HIGH, i+Begin-LowN, LowN); // от него - максимум HighV = High[HighN]; LowV = Low[LowN]; if (HighN > LowN && HighN != i+Begin-1) // минимум обязательно должен быть позже if ((HighBeg - LowV)/(HighV - LowV) >= BCtoABFrom && // отношение свинга BC к (HighBeg - LowV)/(HighV - LowV) <= BCtoABTo) // свингу АВ - заданное return(-1); // Нисходящий свинг найден, т. о. есть сигнал к продаже } // - 2.1 - ============================ Окончание блока ============================= // - 2.2 - ================== Поиск восходящего первичного свинга =================== else // Если у RSI зафиксирован минимум, то необходимо найти восходящий свинг АВ { HighN = iHighest(NULL, 0, MODE_HIGH, i, Begin); // сначала подбирается максимум LowN = iLowest(NULL, 0, MODE_LOW, i+Begin-HighN, HighN); // от него - минимум HighV = High[HighN]; LowV = Low[LowN]; if (LowN > HighN && LowN != i+Begin-1) // максимум обязательно должен быть позже if ((HighV - LowBeg)/(HighV - LowV) >= BCtoABFrom && // отношение свинга BC к (HighV - LowBeg)/(HighV - LowV) <= BCtoABTo) // свингу АВ - заданное return(1); // Восходящий свинг найден, т. о. есть сигнал к покупке } // - 2.2 - ============================ Окончание блока ============================= } // - 2 - =============================== Окончание блока ================================ return(0); } //+-------------------------------------------------------------------------------------+ //| Отображение Текстовой метки | //+-------------------------------------------------------------------------------------+ void ShowText(string name, string Text, datetime Time1, double Price, color Color) { if (ObjectFind(name) < 0) { ObjectCreate(name, OBJ_TEXT, 0, Time1, Price); ObjectSetText(name, Text, 10, "MS Sans Serif", Color); } else { ObjectMove(name, 0, Time1, Price); ObjectSetText(name, Text, 10, "MS Sans Serif", Color); } } //+-------------------------------------------------------------------------------------+ //| Отображение Трендовой линии | //+-------------------------------------------------------------------------------------+ void ShowTrendLine(string name, datetime T1, double P1, datetime T2, double P2, int Stl, color Color) { if (ObjectFind(name) < 0) // Если объект еще не был создан, то создается { ObjectCreate(name, OBJ_TREND, 0, T1, P1, T2, P2); ObjectSet(name, OBJPROP_RAY, False); ObjectSet(name, OBJPROP_STYLE, Stl); ObjectSet(name, OBJPROP_COLOR, Color); } else // Если объект уже существует, то просто перемещается на новое место { ObjectMove(name, 0, T1, P1); ObjectMove(name, 1, T2, P2); ObjectSet(name, OBJPROP_COLOR, Color); } } //+-------------------------------------------------------------------------------------+ //| Отображение найденного сигнала на графике | //+-------------------------------------------------------------------------------------+ void ShowPattern(int Res) { // - 1 - ========= Инициализация переменных, задающих координаты точек А, В и С ========= double Vol = iATR(NULL, 0, 14, 1); // - 1.1 - ======================== Значения для бычьего паттерна ====================== if (Res > 0) { datetime T1 = Time[LowN]; // Время точки А double P1 = LowV; // Цена точки А datetime T2 = Time[HighN]; // Время точки В double P2 = HighV; // Цена точки В datetime T3 = Time[Begin]; // Время точки С double P3 = LowBeg; // Цена точки С double PA = LowV - Vol/2; // Цена литерала А double PB = HighV + Vol; // Цена литерала B double PC = LowBeg - Vol/2; // Цена литерала C color Color = Blue; // Цвет свинга } // - 1.1 - ============================== Окончание блока ============================== // - 1.2 - ======================== Значения для медвежьего паттерна =================== else { T1 = Time[HighN]; // Время точки А P1 = HighV; // Цена точки А T2 = Time[LowN]; // Время точки В P2 = LowV; // Цена точки В T3 = Time[Begin]; // Время точки С P3 = HighBeg; // Цена точки С PA = HighV + Vol; // Цена литерала А PB = LowV - Vol/2; // Цена литерала B PC = HighBeg + Vol; // Цена литерала C Color = Red; // Цвет свинга } // - 1.2 - ============================== Окончание блока ============================== // - 1 - ============================= Окончание блока ================================== // - 2 - ============================= Отображение свинга АВ ============================ ShowTrendLine(prefix + "First", T1, P1, T2, P2, STYLE_SOLID, Color); // - 2 - ============================= Окончание блока ================================== // - 3 - ============================= Отображение свинга BC ============================ ShowTrendLine(prefix + "Second", T2, P2, T3, P3, STYLE_SOLID, Color); // - 3 - ============================= Окончание блока ================================== // - 4 - ======================= Отображение третьей стороны треугольника =============== ShowTrendLine(prefix + "Third", T1, P1, T3, P3, STYLE_DOT, Color); // - 4 - ============================= Окончание блока ================================== // - 5 - ======================= Отображение значения соотношения ======================= string Text = DoubleToStr(MathAbs(P2 - P3)/MathAbs(P2 - P1)*100, 1) + "%"; ShowText(prefix + "Value", Text, T1 + (T3 - T1)/2, (P1 + P3)/2, Color); // - 5 - ============================= Окончание блока ================================== // - 6 - ======================= Отображение буквенных обозначений ====================== ShowText(prefix + "LetterA", "A", T1, PA, Color); ShowText(prefix + "LetterB", "B", T2, PB, Color); ShowText(prefix + "LetterC", "C", T3, PC, Color); // - 6 - ============================= Окончание блока ================================== WindowRedraw(); } //+-------------------------------------------------------------------------------------+ //| Custom indicator iteration function | //+-------------------------------------------------------------------------------------+ int start() { if (!Activate) return(0); if (LastBar == Time[0]) return(0); // - 1 - ========================== Поиск ближайшего паттерна АВС ======================= int i = 2; // Начинается со второго бара while (i < Bars) { // - 1.1 - ======================= Поиск локального экстремума RSI ================== int Ext = RSIExtremum(i); if (Ext == -1) // Ни один экстремум не найден - отключение индикатора { Alert("На доступной истории не найден ни один свинг!"); Activate = False; return(0); } // - 1.1 - ============================ Окончание блока ============================= // - 1.2 - ======================= Поиск свинга АВС после экстремума RSI ============ i = MathFloor(Ext/2.0) + 1; // Формирование значения для перехода к следующему бару int Res = FindMaxMin(Ext); // Поиск свинга if (Res != 0) // Если свинг найден, то он отображается и цикл прерывается { ShowPattern(Res); break; } // - 1.2 - ============================ Окончание блока ============================= // Если свинг не найден, то происходит переход к следующей итерации цикла с поиском // следующего экстремума RSI } // - 1 - ================================= Окончание блока ============================== LastBar = Time[0]; return(0); }