//+------------------------------------------------------------------+ //| ABCR.mq5 | //| Azotskiy Aktiniy ICQ:695710750 | //| https://login.mql5.com/ru/users/Aktiniy | //+------------------------------------------------------------------+ //--- Auto Build Chart Renko #property copyright "Azotskiy Aktiniy ICQ:695710750" #property link "https://login.mql5.com/ru/users/Aktiniy" #property version "1.00" #property description "Auto Build Chart Renko" #property description " " #property description "This indicator makes drawing a chart Renko as a matter of indicator window, and in the main chart window" #property indicator_separate_window #property indicator_buffers 9 #property indicator_plots 1 //--- plot RENKO #property indicator_label1 "RENKO" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrBlue,clrRed,C'0,0,0',C'0,0,0',C'0,0,0',C'0,0,0',C'0,0,0',C'0,0,0' #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- вид построения enum type_step_renko { point=0, // Пункт percent=1, // Процент }; //--- вид цены для построения enum type_price_renko { close=0, // Close open=1, // Open high=2, // High low=3, // Low }; //--- input parameters input double step=10; // Шаг input type_step_renko type_step=point; // Вид шага input long magic_numb=65758473787389; // Магический номер input int levels_number=1000; // Количество уровней (0-без уровней) input color levels_color=clrLavender; // Цвет уровней input ENUM_TIMEFRAMES time_frame=PERIOD_CURRENT; // Период расчёта input ENUM_TIMEFRAMES time_redraw=PERIOD_M1; // Период обновления графика input datetime first_date_start=D'2013.09.13 00:00:00'; // Начальная дата input type_price_renko type_price=close; // Вид цены для построения input bool shadow_print=true; // Показывать ли тени (цены создавшие сразу несколько кирпичей) input int filter_number=0; // Значение количества кирпичей для разворота input bool zig_zag=true; // Рисовать ZigZag на главном графике input bool zig_zag_shadow=true; // Рисовать ZigZag по ценам минимумов и максимумов input int zig_zag_width=2; // Толщина линии ZigZag input color zig_zag_color_up=clrBlue; // Цвет восходящей линии ZigZag input color zig_zag_color_down=clrRed; // Цвет нисходящей линии ZigZag input bool square_draw=true; // Рисовать ли кирпичи на главном графике input color square_color_up=clrBlue; // Цвет кирпича на главном графике вверх input color square_color_down=clrRed; // Цвет кирпича на главном графике вниз input bool square_fill=true; // Заливка кирпича на главном графике input int square_width=2; // Толщина линии кирпича на главном графике input bool frame_draw=true; // Рисовать ли рамки кирпичей input int frame_width=2; // Толщина линии рамки кирпича input color frame_color_up=clrBlue; // Цвет рамок кирпичей вверх input color frame_color_down=clrRed; // Цвет рамок кирпичей вниз //--- indicator buffers double RENKO_open[]; double RENKO_high[]; double RENKO_low[]; double RENKO_close[]; double RENKO_color[]; double Price[]; // буфер для хранения скопированных цен double Date[]; // буфер для хранения скопированных дат double Price_high[]; // буфер для хранения скопированных цен максимумов double Price_low[]; // буфер для хранения скопированных цен минимумов //--- массивы буферов калькуляции double up_price[]; // верхняя цена кирпича double down_price[]; // нижняя цена кирпича char type_box[]; // тип кирпича (вверх, вниз) datetime time_box[]; // время закрытия кирпича double shadow_up[]; // верхний максимум цены double shadow_down[]; // нижний минимум цены int number_id[]; // индекс из массивов Price_high и Price_low //--- глобальные переменные для расчётов int obj=0; // переменная для хранения количества графических объектов int a=0; // переменная подсчёта кирпичей int bars; // количество баров datetime date_stop; // текущая дата datetime date_start; // переменная начальной даты, для расчётов bool date_change; // переменная хранения информации об изменениях во времени //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,RENKO_open,INDICATOR_DATA); ArraySetAsSeries(RENKO_open,true); SetIndexBuffer(1,RENKO_high,INDICATOR_DATA); ArraySetAsSeries(RENKO_high,true); SetIndexBuffer(2,RENKO_low,INDICATOR_DATA); ArraySetAsSeries(RENKO_low,true); SetIndexBuffer(3,RENKO_close,INDICATOR_DATA); ArraySetAsSeries(RENKO_close,true); SetIndexBuffer(4,RENKO_color,INDICATOR_COLOR_INDEX); ArraySetAsSeries(RENKO_color,true); //--- SetIndexBuffer(5,Price,INDICATOR_CALCULATIONS); // инициализируем буфер цен SetIndexBuffer(6,Date,INDICATOR_CALCULATIONS); // инициализируем буфер дат SetIndexBuffer(7,Price_high,INDICATOR_CALCULATIONS); // инициализируем буфер цен максимумов SetIndexBuffer(8,Price_low,INDICATOR_CALCULATIONS); // инициализируем буфер цен минимумов //--- задаём какие значения не будут прорисовываться PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); //--- устанавливаем внешний вид индикатора IndicatorSetString(INDICATOR_SHORTNAME,"ABCR "+IntegerToString(magic_numb)); // имя индикатора //--- точность отображения IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //--- запрещяем показ результатов текущих значений для индикатора PlotIndexSetInteger(0,PLOT_SHOW_DATA,false); //--- присвоение значения переменной начальной даты date_start=first_date_start; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- if(func_new_bar(time_redraw)==true) { func_concolidation(); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| OnChartEvent | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // идентификатор события const long& lparam, // параметр события типа long const double& dparam, // параметр события типа double const string& sparam) // параметр события типа string { //--- событие нажатия клавиши на клавиатуре if(id==CHARTEVENT_KEYDOWN) { if(lparam==82) //--- была нажата клавиша "R" { //--- вызов функции консолидации func_concolidation(); } if(lparam==67) //--- была нажата клафиша "C" { //--- очистка графика от построенных объектов индикатора func_all_delete(); } } } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- очистка графика от построенных объектов индикатора func_all_delete(); } //+------------------------------------------------------------------+ //| Func All Delete | //+------------------------------------------------------------------+ void func_all_delete() { //--- подсчёт графических обьектов obj=ObjectsTotal(0,-1,-1); //--- удаление всех графических объектов принадлежащих индикатору func_delete_objects(IntegerToString(magic_numb)+"_Line_",obj); func_delete_objects(IntegerToString(magic_numb)+"_Square_",obj); func_delete_objects(IntegerToString(magic_numb)+"_Frame_",obj); //--- периресовка графика ChartRedraw(0); } //+------------------------------------------------------------------+ //| Func Consolidation | //+------------------------------------------------------------------+ void func_concolidation() { //--- удаление всех графических объектов принадлежащих индикатору func_all_delete(); //--- получение текущей даты date_stop=TimeCurrent(); //--- изменение начальной даты в виду ограниченных возможностей размера буфера if((bars=Bars(_Symbol,time_frame,date_start,date_stop))>ArraySize(Price)) { date_start=func_calc_date_start(date_start,date_stop); Alert("Начальная дата была изменена системой из за нехватка размера графика"); date_change=true; //--- подсчёт баров на расчётном промежутке времени bars=Bars(_Symbol,time_frame,date_start,date_stop); } //--- bool result_copy_price=func_copy_price(Price,time_frame,date_start,date_stop,type_price); bool result_copy_date=func_copy_date(Date,time_frame,date_start,date_stop); //--- меняем параметр изменения даты if(result_copy_price=true && result_copy_date==true)date_change=false; //--- if(zig_zag_shadow==true) { func_copy_price(Price_high,time_frame,date_start,date_stop,2); func_copy_price(Price_low,time_frame,date_start,date_stop,3); } //--- func_draw_renko(Price,Date,filter_number,shadow_print,type_step,step); if(zig_zag==true)func_draw_zig_zag(zig_zag_shadow,zig_zag_width,zig_zag_color_up,zig_zag_color_down); //--- func_draw_renko_main_chart(square_color_up,square_color_down,frame_color_up,frame_color_down,square_width,frame_width,square_draw,square_fill,frame_draw); func_create_levels(levels_number,levels_color); //--- перерисовка графика ChartRedraw(0); } //+------------------------------------------------------------------+ //| Func Calculate Date Start | //+------------------------------------------------------------------+ datetime func_calc_date_start(datetime input_data_start,// первоначально назначенная дата начала datetime data_stop) // дата окончания расчёта (текущая дата) //--- { int Array_Size=ArraySize(Price); int Bars_Size=Bars(_Symbol,time_frame,input_data_start,data_stop); for(;Bars_Size>Array_Size;input_data_start+=864000) // 864000 = 10 дней { Bars_Size=Bars(_Symbol,time_frame,input_data_start,data_stop); } return(input_data_start); //--- } //+------------------------------------------------------------------+ //| Func Copy Price | //+------------------------------------------------------------------+ bool func_copy_price(double &result_array[], ENUM_TIMEFRAMES period,// Таим фреим datetime data_start, datetime data_stop, char price_type) // 0-Close, 1-Open, 2-High, 3-Low { //--- int x=false; // переменная для ответа int result_copy=-1; // количество скопированных данных //--- static double price_interim[]; // временный динамический массив для хранения скопированных данных static int bars_to_copy; // количество баров для копирования static int bars_copied_0; // количество уже скопированных баров с начальной даты Close static int bars_copied_1; // количество уже скопированных баров с начальной даты Open static int bars_copied_2; // количество уже скопированных баров с начальной даты High static int bars_copied_3; // количество уже скопированных баров с начальной даты Low static int bars_copied; // количество уже скопированных баров с начальной даты общая переменная //--- обнуление переменных ввиду изменения начальной даты if(date_change==true) { ZeroMemory(price_interim); ZeroMemory(bars_to_copy); ZeroMemory(bars_copied_0); ZeroMemory(bars_copied_1); ZeroMemory(bars_copied_2); ZeroMemory(bars_copied_3); ZeroMemory(bars_copied); } //--- узнаём текущее колличество баров на временном промежутке bars_to_copy=Bars(_Symbol,period,data_start,data_stop); //--- присвоение общей переменной значение одной из копируемых переменных switch(price_type) { case 0: //--- Close bars_copied=bars_copied_0; break; case 1: //--- Open bars_copied=bars_copied_1; break; case 2: //--- High bars_copied=bars_copied_2; break; case 3: //--- Low bars_copied=bars_copied_3; break; } //--- подсчитываем колличество баров которые надо скопировать bars_to_copy-=bars_copied; //--- если данные копируются не в первый раз if(bars_copied!=0) { bars_copied--; bars_to_copy++; } //--- меняем размер приёмного массива ArrayResize(price_interim,bars_to_copy); //--- копируем данные во временный массив switch(price_type) { case 0: //--- Close { result_copy=CopyClose(_Symbol,period,0,bars_to_copy,price_interim); } break; case 1: //--- Open { result_copy=CopyOpen(_Symbol,period,0,bars_to_copy,price_interim); } break; case 2: //--- High { result_copy=CopyHigh(_Symbol,period,0,bars_to_copy,price_interim); } break; case 3: //--- Low { result_copy=CopyLow(_Symbol,period,0,bars_to_copy,price_interim); } break; } //--- проверяем результат копирования данных if(result_copy!=-1) // если копирование в промежуточный массив было успешно { ArrayCopy(result_array,price_interim,bars_copied,0,WHOLE_ARRAY); // копируем данные из временного в основной массив x=true; // присваиваем положительный ответ функции bars_copied+=result_copy; // увеличиваем значение скопированных данных } //--- возвращение информации о скопированных данных одной из копируемых переменных switch(price_type) { case 0: //--- Close bars_copied_0=bars_copied; break; case 1: //--- Open bars_copied_1=bars_copied; break; case 2: //--- High bars_copied_2=bars_copied; break; case 3: //--- Low bars_copied_3=bars_copied; break; } //--- return(x); } //+------------------------------------------------------------------+ //| Func Copy Date | //+------------------------------------------------------------------+ bool func_copy_date(double &result_array[], ENUM_TIMEFRAMES period,// таймфрейм datetime data_start, datetime data_stop) { //--- int x=false; // переменная для ответа int result_copy=-1; // количество скопированных данных static datetime time_interim[]; // временный динамический массив для хранения скопированных данных static int bars_to_copy; // количество баров для копирования static int bars_copied; // количество уже скопированных баров с начальной датой //--- обнуление переменных в виду изменения начальной даты if(date_change==true) { ZeroMemory(time_interim); ZeroMemory(bars_to_copy); ZeroMemory(bars_copied); } //--- bars_to_copy=Bars(_Symbol,period,data_start,data_stop); // узнаём текущее количество баров на временном промежутке bars_to_copy-=bars_copied; // подсчитываем Количество баров которые надо скопировать //--- if(bars_copied!=0) // если данные копируются не в первый раз { bars_copied--; bars_to_copy++; } //--- ArrayResize(time_interim,bars_to_copy); // меняем размер приёмного массива result_copy=CopyTime(_Symbol,period,0,bars_to_copy,time_interim); //--- if(result_copy!=-1) // если копирование в промежуточный массив было успешно { ArrayCopy(result_array,time_interim,bars_copied,0,WHOLE_ARRAY); // копируем в основной массив данных, данные из временного x=true; // присваиваем положительный ответ функции bars_copied+=result_copy; // увеличиваем значение скопированных данных } //--- return(x); } //+------------------------------------------------------------------+ //| Func Calculate Doorstep | //+------------------------------------------------------------------+ int func_calc_dorstep(double price, // цена char type_doorstep,// тип шага double doorstep) // шаг { double x=0; // переменная для ответа if(type_doorstep==0) // если расчёт нужно произволить по пунктам { x=doorstep; } if(type_doorstep==1) // если расчёт нужно производить в процентах { x=price/_Point*doorstep/100; } return((int)x); } //+------------------------------------------------------------------+ //| Func Draw Renko | //+------------------------------------------------------------------+ void func_draw_renko(double &price[], // массив цен double &date[], // массив дат int number_filter, // количество кирпичей для разворота bool draw_shadow, // рисовать тень char type_doorstep,// тип шага double doorstep) // шаг { //--- обнуление массивов //--- массивы буферов отрисовки ZeroMemory(RENKO_close); ZeroMemory(RENKO_color); ZeroMemory(RENKO_high); ZeroMemory(RENKO_low); ZeroMemory(RENKO_open); //--- вспомогательные переменные для расчётов int doorstep_now; // текущий шаг int point_go; // пройдено пунктов //--- вспомогательные переменные для подсчёта количества кирпичей a=0; double up_price_calc=price[0]; double down_price_calc=price[0]; char type_box_calc=0; for(int z=0; z цикл подсчёта кирпичей { //--- вычисляем размер шага учитывая текущюю расматриваему цену doorstep_now=func_calc_dorstep(price[z],type_doorstep,doorstep); //--- если цена идёт вверх if((price[z]-up_price_calc)/_Point>=doorstep_now) { //--- вычисляем пройденное количество пунктов point_go=int((price[z]-up_price_calc)/_Point); //--- до этого цена шла вверх или направление цены неизвестно if(type_box_calc==1 || type_box_calc==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- добавляем следующий кирпич a++; //--- устанавливаем значение нижней цены следующего кирпича down_price_calc=up_price_calc; //--- устанавливаем значение верхней цены следующего кирпича up_price_calc=down_price_calc+(doorstep_now*_Point); //--- установка типа кирпича (вверх) type_box_calc=1; } } //--- до этого цена шла вниз if(type_box_calc==-1) { if((point_go/doorstep_now)>=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- добавляем следующий кирпич a++; //--- устанавливаем значение нижней цены следующего кирпича down_price_calc=up_price_calc; //--- устанавливаем значение верхней цены следующего кирпича up_price_calc=down_price_calc+(doorstep_now*_Point); //--- установка типа кирпича (вверх) type_box_calc=1; } } } } //--- если цена идёт вниз if((down_price_calc-price[z])/_Point>=doorstep_now) { //--- вычисляем пройденное количество пунктов point_go=int((down_price_calc-price[z])/_Point); //--- до этого цена шла вниз или предыдущее направление неизвестно if(type_box_calc==-1 || type_box_calc==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- добавляем следующий кирпич a++; //--- устанавливаем значение нижней цены следующего кирпича up_price_calc=down_price_calc; //--- устанавливаем значение верхней цены следующего кирпича down_price_calc=up_price_calc-(doorstep_now*_Point); //--- установка типа кирпича (вверх) type_box_calc=-1; } } //--- до этого цена шла вверх if(type_box_calc==1) { if((point_go/doorstep_now)>=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- добавляем следующий кирпич a++; //--- устанавливаем значение нижней цены следующего кирпича up_price_calc=down_price_calc; //--- устанавливаем значение верхней цены следующего кирпича down_price_calc=up_price_calc-(doorstep_now*_Point); //--- установка типа кирпича (вверх) type_box_calc=-1; } } } } } //---< цикл подсчёта кирпичей //--- подсчитываем количество отображаемых баров int b=Bars(_Symbol,PERIOD_CURRENT); //--- меняем размеры массивов ArrayResize(up_price,b); ArrayResize(down_price,b); ArrayResize(type_box,b); ArrayResize(time_box,b); ArrayResize(shadow_up,b); ArrayResize(shadow_down,b); ArrayResize(number_id,b); //--- обнуляем массивы буферов калькуляции ZeroMemory(up_price); ZeroMemory(down_price); ZeroMemory(type_box); ZeroMemory(time_box); ZeroMemory(shadow_up); ZeroMemory(shadow_down); ZeroMemory(number_id); //--- заполняем начальными значениями массивы up_price[0]=price[0]; down_price[0]=price[0]; type_box[0]=0; //--- высчитываем количество лишних кирпичей int l=a-b; int turn_cycle=l/(b-1); int turn_rest=(int)MathMod(l,(b-1))+2; int turn_var=0; //--- выводим сообщение о частичном отображении кирпичей if(a>b)Alert("Кирпичей больше чем может поместиться на графике, возможно шаг мал"); a=0; //--- обнуляем переменную подсчёта кирпичей for(int z=0; z Главный цикл { //--- вычисляем размер шага учитывая текущюю расматриваему цену doorstep_now=func_calc_dorstep(price[z],type_doorstep,doorstep); //--- если цена идёт вверх if((price[z]-up_price[a])/_Point>=doorstep_now) { //--- вычисляем пройденное количество пунктов point_go=int((price[z]-up_price[a])/_Point); //--- до этого цена шла вверх или направление цены неизвестно if(type_box[a]==1 || type_box[a]==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- добавляем следующий кирпич if((a==b && turn_var=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- добавляем следующий кирпич if((a==b && turn_var=doorstep_now) { //--- вычисляем пройденное количество пунктов point_go=int((down_price[a]-price[z])/_Point); //--- до этого цена шла вниз или предыдущее направление неизвестно if(type_box[a]==-1 || type_box[a]==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- добавляем следующий кирпич if((a==b && turn_var=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- добавляем следующий кирпич if((a==b && turn_var0 && Price_low[id-1]0 && Price_high[id-1]>Price_high[id])id--; if(Price_high[id+1]>Price_high[id])id++; price_2=Price_high[id]; date_2=(datetime)Date[id]; } else { price_2=up_price[z-1]; date_2=time_box[z-1]; } func_create_trend_line(name_line,price_1,price_2,date_1,date_2,line_width,line_color_up); price_1=price_2; date_1=date_2; } } } } //+------------------------------------------------------------------+ //| Func Create Square or Rectangle | //+------------------------------------------------------------------+ void func_create_square_or_rectangle(string name, double price1, double price2, datetime time1, datetime time2, int width, color color_square, bool fill) { //--- создадим прямоугольник по заданным координатам ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2); //--- установим цвет прямоугольника ObjectSetInteger(0,name,OBJPROP_COLOR,color_square); //--- установим стиль линий прямоугольника ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- установим толщину линий прямоугольника ObjectSetInteger(0,name,OBJPROP_WIDTH,width); //--- включим (true) или отключим (false) режим заливки прямоугольника ObjectSetInteger(0,name,OBJPROP_FILL,fill); //--- отобразим на переднем (false) или заднем (true) плане ObjectSetInteger(0,name,OBJPROP_BACK,false); } //+------------------------------------------------------------------+ //| Func Draw Renko Main Chart | //+------------------------------------------------------------------+ void func_draw_renko_main_chart(color color_square_up, color color_square_down, color color_frame_up, color color_frame_down, int width_square, int width_frame, bool square, bool fill, bool frame) { string name_square; string name_frame; for(int z=2; z<=a; z++) { name_square=IntegerToString(magic_numb)+"_Square_"+IntegerToString(z); name_frame=IntegerToString(magic_numb)+"_Frame_"+IntegerToString(z); if(type_box[z]==1) { if(square==true)func_create_square_or_rectangle(name_square,up_price[z],down_price[z],time_box[z-1],time_box[z],width_square,color_square_up,fill); if(frame==true)func_create_square_or_rectangle(name_frame,up_price[z],down_price[z],time_box[z-1],time_box[z],width_frame,color_frame_up,false); } if(type_box[z]==-1) { if(square==true)func_create_square_or_rectangle(name_square,up_price[z],down_price[z],time_box[z-1],time_box[z],width_square,color_square_down,fill); if(frame==true)func_create_square_or_rectangle(name_frame,up_price[z],down_price[z],time_box[z-1],time_box[z],width_frame,color_frame_down,false); } } } //+------------------------------------------------------------------+ //| Func Create Levels | //+------------------------------------------------------------------+ void func_create_levels(int level_number, color level_color) { //--- установка количества уровней в окне индикатора IndicatorSetInteger(INDICATOR_LEVELS,level_number); //--- с какого кирпича начинается прорисовка уровней int k=0; if(a>level_number)k=a-level_number; //--- назначение цен уровней for(int z=0;(z<=level_number && k<=a); z++,k++) { IndicatorSetDouble(INDICATOR_LEVELVALUE,z,up_price[k]); IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,level_color); } } //+------------------------------------------------------------------+ //| Func Delete Objects | //+------------------------------------------------------------------+ void func_delete_objects(string name, int number) { string name_del; for(int x=0; x<=number; x++) { name_del=name+IntegerToString(x); ObjectDelete(0,name_del); } } //+------------------------------------------------------------------+ //| Func New Bar | //+------------------------------------------------------------------+ bool func_new_bar(ENUM_TIMEFRAMES period_time) { //--- static datetime old_times; // переменная хранения старых значений bool res=false; // переменная результата анализа datetime new_time[1]; // время нового бара //--- int copied=CopyTime(_Symbol,period_time,0,1,new_time); // скопируем время последнего бара в ячейку new_time //--- if(copied>0) // все ок. данные скопированы { if(old_times!=new_time[0]) // если старое время бара не равно новому { if(old_times!=0) res=true; // если это не первый запуск, то истина = новый бар old_times=new_time[0]; // запоминаем время бара } } //--- return(res); } //+------------------------------------------------------------------+