
Построение фрактальных линий
Введение
Фракталами пользуется практически каждый трейдер, но спросите
его, что такое фрактал, и в лучшем случае он ответит, что это
индикатор из системы Билла Вильямса. Более продвинутые скажут,
что это последовательность из 5 баров, в которых если High среднего
бара выше остальных в последовательности, то это Up фрактал,
а если Low среднего бара ниже остальных, то это Down фрактал. Как
говорится – “Вот и все, что я могу сказать о войне”.
Коротко о фракталах, в частности, об их природе и использовании говорится в книге Билла Вильямса “Новые измерения биржевой торговли”, кое-что есть в статье Чекулаева «Фракталы». Математически фракталы неплохо описаны в книге Ширяева – «Основы стохастической математики».
Использование фракталов
Можно выделить два вида пробития фракталов – простое, когда
цена поднимается выше Up фрактала (ниже Down фрактала), причем лучше
дождаться цены закрытия и открывать позицию на открытии следующего
бара.
Соответствующие Buy и Sell фракталы отмечены стрелками на рисунке. Мы рассмотрели простое пробитие фрактала. В сложном пробитии используются 2 фрактала – последний и предпоследний. Через них проводится прямая, которая должна быть пробита ценой закрытия.
Места входа при пробитии фрактальной линии обозначены голубой и красненькой стрелочками. Лучше разобраться во фрактальной идеологии нам поможет язык MQL4.
Сформулируем задачу для тестирования фракталов.
- нарисовать фракталы buy/sell;
- нарисовать горизонтальные уровни пробития;
- нарисовать фрактальные линии;
- предполагаемые места входа пометить стрелочками.
Нарисовать фракталы buy/sell
Самая элементарная часть. Учитывая еще и наличие индикатора iFractal на MQL4 (в Omege этот индикатор сам писал и из-за ее особенностей очень запарился). Примеры написания этого индикатора можно посмотреть в Code Base.
Горизонтальные уровни пробития
Воспользуемся стандартными горизонтальными линиями. В качестве ценовых координат укажем цену фрактала, а в качестве временных – дата образования фрактала и текущее время.
ObjectCreate("SimpleUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],Time[i-1],bufUpPrice[Up]); ObjectSet("SimpleUp"+Up,OBJPROP_COLOR,Aqua); ObjectSet("SimpleUp"+Up,OBJPROP_RAY,True);
Фрактальные линии
Казалось бы простой выход – прорисовка трендовых линий через 2 точки. Делаем линию лучом и ждем пробития. Но на деле сравнить цену закрытия и значение цены на фрактальной линии не представилось возможным, так как функция ObjectGet может вернуть только значения точек, которые образовали фрактальную линию. Что же делать?
Вспомнить аналитическую геометрию. У нас есть 2 точки, значит имеем уравнение прямой, а по уравнению прямой, зная координату времени, элементарно получаем значение цены. Каноническое уравнение прямой выглядит так:
Вместо х и у подставляем цены и время. Реализация представлена в функции LevelCalculate, которая рассчитывает уровень пробоя, а заодно и определяет новые координаты фрактальной линии, которые устанавливаются с помощью функции ObjectSet.
ObjectCreate("LineUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],bufUpDate[Up-1],bufUpPrice[Up-1]); ObjectSet("LineUp"+Up,OBJPROP_COLOR,Blue); ObjectSet("LineUp"+Up,OBJPROP_RAY,False);
Расстановка стрелок
В цикле строим все необходимые линии и сравниваем с текущими ценами. Если пробой уровня простой , то ставим желтую стрелочку. Если пробой фрактальной линии, то на Buy – синюю, а на Sell – красную.
Все это реализовано в качестве индикатора FractalLines.mq4.
//+------------------------------------------------------------------+ //| FractalLines.mq4 | //| Copyright © 2006, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Blue #property indicator_color2 Red //---- input parameters extern int lines=5; //Количество видимых фрактальных линий extern int MaxFractals=10000; // :) extern bool ShowHorisontalLines=true; extern bool ShowFractalLines=true; //---- buffers double ExtMapBuffer1[]; double ExtMapBuffer2[]; //--- my variables double bufUpPrice[10000]; //массив цен Up фракталов double bufUpDate[10000]; //массив дат Up фракталов double bufDownPrice[10000]; //массив цен Down фракталов double bufDownDate[10000]; //массив дат Down фракталов int Up = 0; //счетчик Up фракталов int Down = 0; //счетчик Down фракталов //Функция считает значение цены пробития фрактальной линии по простейшим //уравниниям аналитической геометрии double LevelCalculate(double Price1, double Time1, double Price2, double Time2, double NewTime) { double level; if (Time2!=Time1)// На всякий случай, чтобы не было деления на 0. { level=(NewTime-Time1)*(Price2-Price1)/(Time2-Time1)+Price1; } else { return(Price2); } return(level); } //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators SetIndexStyle(0,DRAW_ARROW); SetIndexArrow(0,217); SetIndexBuffer(0,ExtMapBuffer1); SetIndexEmptyValue(0,0.0); SetIndexStyle(1,DRAW_ARROW); SetIndexArrow(1,218); SetIndexBuffer(1,ExtMapBuffer2); SetIndexEmptyValue(1,0.0); //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { int counted_bars=IndicatorCounted(); //---- последний посчитанный бар будет пересчитан if(counted_bars > 0) counted_bars--; int limit = Bars - counted_bars; // Пожалуй, расставим стрелки в момент пробития фрактальных линий, // оценим эффективность // Идея позаимствована у Rosha, надеюсь, не обидится :) string arrowName; // здесь будут назначаться уникальное имя объекта-стрелки //Номер пробитого фрактала //Пробитие фрактальной линии int FractalUp = 0; int FractalDown = 0; //Простое пробитие фрактала int SimpleFractalUp = 0; int SimpleFractalDown = 0; double BuyFractalLevel = 0; //уровень пробития фрактальной линии Up double SellFractalLevel = 0; //уровень пробития фрактальной линии Down double buf = 0; // буферной значение наличие фрактала, если 0, то фрактала нет //---- основной цикл for(int i = limit; i>0; i--) { //Рисуем простые фрактальные уровни //Определим текущие фрактальные уровни BuyFractalLevel=LevelCalculate(bufUpPrice[Up],bufUpDate[Up], bufUpPrice[Up-1],bufUpDate[Up-1],Time[i]); //Двигаем вторую координату фрактальной прямой Up ObjectSet("LineUp"+Up,OBJPROP_TIME1,Time[i]); ObjectSet("LineUp"+Up,OBJPROP_PRICE1,BuyFractalLevel); SellFractalLevel=LevelCalculate(bufDownPrice[Down], bufDownDate[Down],bufDownPrice[Down-1], bufDownDate[Down-1],Time[i]); //Двигаем вторую координату фрактальной прямой Down ObjectSet("LineDown"+Down,OBJPROP_TIME1,Time[i]); ObjectSet("LineDown"+Down,OBJPROP_PRICE1,SellFractalLevel); //Ищем простое пробитие if (Close[i]>ObjectGet("SimpleUp"+Up,OBJPROP_PRICE1)&& (Up>SimpleFractalUp)) { arrowName="SimleUpArrow"+Up; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], Low[i-1]-Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,241); ObjectSet(arrowName,OBJPROP_COLOR,Yellow); SimpleFractalUp=Up; } if (Close[i]<ObjectGet("SimpleDown"+Down,OBJPROP_PRICE1)&& (Down>SimpleFractalDown)) { arrowName="SimleUpArrow"+Down; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], High[i-1]+Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,242); ObjectSet(arrowName,OBJPROP_COLOR,Yellow); SimpleFractalDown=Down; } //Ищем сложное пробитие if ((Close[i]>BuyFractalLevel)&&(Up>FractalUp)) { //Ставим стрелочку вверх arrowName="UpArrow"+Up; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], Low[i-1]-Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,241); ObjectSet(arrowName,OBJPROP_COLOR,Blue); FractalUp=Up; } if ((Close[i]<SellFractalLevel)&&(Down>FractalDown)) { //Ставим стрелочку вверх arrowName="DownArrow"+Down; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], High[i-1]+Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,242); ObjectSet(arrowName,OBJPROP_COLOR,Red); FractalDown=Down; } //Рисуем сам фрактал Up ExtMapBuffer1[i] = iFractals(NULL, 0, MODE_UPPER, i); //Если он есть, то заносим его в массив фракталов buf = iFractals(NULL, 0, MODE_UPPER, i); if (buf!=0) { Up++; bufUpPrice[Up]=iFractals(NULL, 0, MODE_UPPER, i); bufUpDate[Up]=Time[i]; //Текущий уровень пробития фрактала - сам фрактал BuyFractalLevel=bufUpPrice[Up]; if (Up>1) { //Простой фрактал ObjectCreate("SimpleUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],Time[i-1],bufUpPrice[Up]); ObjectSet("SimpleUp"+Up,OBJPROP_COLOR,Aqua); ObjectSet("SimpleUp"+Up,OBJPROP_RAY,True); //Чертим фрактальные линии по 2 координатам ObjectCreate("LineUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],bufUpDate[Up-1],bufUpPrice[Up-1]); ObjectSet("LineUp"+Up,OBJPROP_COLOR,Blue); ObjectSet("LineUp"+Up,OBJPROP_RAY,False); //Удаляем устаревшии линии if (Up>lines+1) { ObjectDelete("LineUp"+(Up-lines)); ObjectDelete("SimpleUp"+(Up-lines)); } } } //Аналогичный блок, но на Down фракталы ExtMapBuffer2[i] = iFractals(NULL, 0, MODE_LOWER, i); buf = iFractals(NULL, 0, MODE_LOWER, i); if (buf!=0) { Down++; bufDownPrice[Down]=iFractals(NULL, 0, MODE_LOWER, i); bufDownDate[Down]=Time[i]; SellFractalLevel=bufDownPrice[Down]; if (Down>1) { ObjectCreate("SimpleDown"+Down,OBJ_TREND,0,bufDownDate[Down], bufDownPrice[Down],Time[i-1],bufDownPrice[Down]); ObjectSet("SimpleDown"+Down,OBJPROP_COLOR,LightCoral); ObjectSet("SimpleDown"+Down,OBJPROP_RAY,True); ObjectCreate("LineDown"+Down,OBJ_TREND,0, bufDownDate[Down],bufDownPrice[Down], bufDownDate[Down-1],bufDownPrice[Down-1]); ObjectSet("LineDown"+Down,OBJPROP_COLOR,Red); ObjectSet("LineDown"+Down,OBJPROP_RAY,False); if (Down>lines+1) { ObjectDelete("LineDown"+(Down-lines)); ObjectDelete("SimpleDown"+(Down-lines)); } } } if (!ShowHorisontalLines) { ObjectDelete("SimpleDown"+Down); ObjectDelete("SimpleUp"+Up); } if (!ShowFractalLines) { ObjectDelete("LineDown"+Down); ObjectDelete("LineUp"+Up); } } //---- return(0); } //+-----------------------------------------------------------------
Старые линии необходимо удалять, а то чарт станет палитрой. В индикаторе предусмотрена еще пара дополнительных настроек, таких как видимость различных линий и количество линий. Результат работы индикатора приведен ниже.
Незаменимая вещь для любителей фракталов!





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Терминологический вопрос. Почему локальные экстремумы на Форекс называют фракталами? С легкой руки Билла Вильямса?
У меня похожий индикатор - пришлось линии заменить на точки, а фракталы - на горизонтальные линии.
Да и линии : по верхним фракталам только те, что смотрят вниз; по нижним фракталам - только те, что смоьтрят вверх.
Вот как выглядит у меня :
Терминологический вопрос. Почему локальные экстремумы на Форекс называют фракталами? С легкой руки Билла Вильямса?
Фрактал, по одной из геометических трактовок, есть статистически самоподобная фигура. Для рынка такой самоподобной фигурой, обнаруживаемой при любом масштабе, является волна Элиота.
Волна Элиота содержит 4 или 5 локальных максимумов, третий, как правило, выше всех других. Сводя ее к предельно простому графическому примитиву, получаем фрактал Вильямса.