Как сделать несколько гистограмм на один бар?

 

Подскажите, как можно на 1 баре разместить несколько гистограмм для разных буферов рядом друг с другом или накопительно? Примеры на рисунке.


 
Sergey Savinkin:

Ну верхний вариант понятно как - делаем дополнительные 2 буфера.
Сначала выводим буфер сумм трёх первичных буферов, потом буфер двух первичных, потом один из первичных.

Второй вариант не знаю вообще ли возможен (я про 4ку). В МТ5 возможно есть какие-то танцы с бубнами

Всяко линии в таких случаях нагляднее гисты будут

 
Andrei Fandeev:

Ну верхний вариант понятно как - делаем дополнительные 2 буфера.
Сначала выводим буфер сумм трёх первичных буферов, потом буфер двух первичных, потом один из первичных.

Второй вариант не знаю вообще ли возможен (я про 4ку). В МТ5 возможно есть какие-то танцы с бубнами

Всяко линии в таких случаях нагляднее гисты будут

Спасибо, я про МТ5. Про разные буферы в одном индикаторном окне я не подумал. Это вариант. Попробую.

 
Sergey Savinkin:

Спасибо, я про МТ5. Про разные буферы в одном индикаторном окне я не подумал. Это вариант. Попробую.

Самый длинный столбец должен иметь наименьший индекс буфера, самый короткий - наибольший индекс. В общем - бутерброд...

 
Artyom Trishkin:

Самый длинный столбец должен иметь наименьший индекс буфера, самый короткий - наибольший индекс. В общем - бутерброд...

Спасибо, так и сделаю.

 

Вариант через канвас в первом приближении (реализовано только для макс. увеличения)

Даже собственные буферы для гистограмы по сути не нужны

#property indicator_chart_window
#include <Canvas\iCanvas.mqh> // https://www.mql5.com/ru/code/22164

#property indicator_buffers 3
#property indicator_plots   3
//--- plot Ma1
#property indicator_label1  "Ma1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Ma2
#property indicator_label2  "Ma2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Ma3
#property indicator_label3  "Ma3"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- indicator buffers
double         Ma1Buffer[];
double         Ma2Buffer[];
double         Ma3Buffer[];

int MaHandle1,MaHandle2,MaHandle3,RT=0;
////////////////////////////////////////////////////////////////////////////////
int OnInit()
  {
//--- indicator buffers mapping
   ChartSetInteger(0,CHART_SCALE,0,5);
   SetIndexBuffer(0,Ma1Buffer,INDICATOR_DATA);
   SetIndexBuffer(1,Ma2Buffer,INDICATOR_DATA);
   SetIndexBuffer(2,Ma3Buffer,INDICATOR_DATA);
   MaHandle1=iMA(NULL,0,10,0,MODE_SMA,PRICE_CLOSE);
   MaHandle2=iMA(NULL,0,20,0,MODE_SMA,PRICE_CLOSE);
   MaHandle3=iMA(NULL,0,30,0,MODE_SMA,PRICE_CLOSE);
   ChartSetInteger(0,CHART_CROSSHAIR_TOOL,0,true);

   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason) {if (reason<2) ChartRedraw(); }
////////////////////////////////////////////////////////////////////////////////
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[])
  {
   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<=0) to_copy=rates_total;
   else
     {
      to_copy=rates_total-prev_calculated;
      to_copy++;
     }
   if(CopyBuffer(MaHandle1,0,0,to_copy,Ma1Buffer)<=0) Print("Error CopyBuffer1 - ",GetLastError());
   if(CopyBuffer(MaHandle2,0,0,to_copy,Ma2Buffer)<=0) Print("Error CopyBuffer2 - ",GetLastError());
   if(CopyBuffer(MaHandle3,0,0,to_copy,Ma3Buffer)<=0) Print("Error CopyBuffer3 - ",GetLastError());
   if(rates_total==prev_calculated && W.Right_bar<1)
     {
      Canvas.FillRectangle((int)Canvas.X(0.0)-11,W.Height-1,(int)Canvas.X(0.0)+11, 0,0);
      Canvas.FillRectangle((int)Canvas.X(0.0)-11,W.Height-1,(int)Canvas.X(0.0)-5, W.Height-Round(fabs(close[RT-1]-Ma1Buffer[RT-1])/W.dy_pix),0xA0FF0000);
      Canvas.FillRectangle((int)Canvas.X(0.0)- 3,W.Height-1,(int)Canvas.X(0.0)+3, W.Height-Round(fabs(close[RT-1]-Ma2Buffer[RT-1])/W.dy_pix),0xA00000FF);
      Canvas.FillRectangle((int)Canvas.X(0.0)+ 5,W.Height-1,(int)Canvas.X(0.0)+11,W.Height-Round(fabs(close[RT-1]-Ma3Buffer[RT-1])/W.dy_pix),0xA000FF00);
      Canvas.Update();
     }
   RT=rates_total;
   return(rates_total);
  }
////////////////////////////////////////////////////////////////////////////////
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      Canvas.Erase(0);
      for(int i=W.Left_bar;i>=W.Right_bar; i--)
        {
         double curPrice=iClose(NULL,0,i);
         Canvas.FillRectangle((int)Canvas.X((double)i)-11,W.Height-1,(int)Canvas.X((double)i)-5, W.Height-Round(fabs(curPrice-Ma1Buffer[RT-1-i])/W.dy_pix),0xA0FF0000);
         Canvas.FillRectangle((int)Canvas.X((double)i)- 3,W.Height-1,(int)Canvas.X((double)i)+3, W.Height-Round(fabs(curPrice-Ma2Buffer[RT-1-i])/W.dy_pix),0xA00000FF);
         Canvas.FillRectangle((int)Canvas.X((double)i)+ 5,W.Height-1,(int)Canvas.X((double)i)+11,W.Height-Round(fabs(curPrice-Ma3Buffer[RT-1-i])/W.dy_pix),0xA000FF00);
        }
      Canvas.Update();
     }
  }

желтым маркером выделено то, что непосредственно относится к рисованию трехцветной гистограммы

 
Nikolai Semko:

Вариант через канвас в первом приближении (реализовано только для макс. увеличения)

Даже собственные буферы для гистограмы по сути не нужны

желтым маркером выделено то, что непосредственно относится к рисованию трехцветной гистограммы

А без рисуемых МА? И чтобы в окне данных были значения каждого столбца гистограммы, а не просто трёх скользящих?

 
Artyom Trishkin:

А без рисуемых МА? И чтобы в окне данных были значения каждого столбца гистограммы, а не просто трёх скользящих?

Так я машки взял просто с потолка для примера, как основа для расчета. Я же не знаю какие значения нужны в гистограммы выводить. 
Если машки не рисовать, то будет еще проще и короче.

 
Artyom Trishkin:

А без рисуемых МА? И чтобы в окне данных были значения каждого столбца гистограммы, а не просто трёх скользящих?

Nikolai Semko:

Так я машки взял просто с потолка для примера. Я же не знаю какие значения нужны в гистограммы выводить. 
Если машки не рисовать, то будет еще проще и короче.

Не проще, не короче не будет. Чтобы в окне данных были значения нужны индикаторные буферы. И не важно чем и как их заполнять. ИМХО.

 
Alexey Viktorov:

Не проще, не короче не будет. Чтобы в окне данных были значения нужны индикаторные буферы. И не важно чем и как их заполнять. ИМХО.

Заполнять буферы можете чем угодно. Здесь речь об отображении. 
Канвас нужен для реализации того, что физически не возможно стандартными индикаторными примочками реализовать.

 
Artyom Trishkin:

А без рисуемых МА? И чтобы в окне данных были значения каждого столбца гистограммы, а не просто трёх скользящих?

Вы это имели ввиду?

#property indicator_chart_window
#include <Canvas\iCanvas.mqh> // https://www.mql5.com/ru/code/22164

#property indicator_buffers 3

//--- indicator buffers
double         Ma1Buffer[];
double         Ma2Buffer[];
double         Ma3Buffer[];

int MaHandle1,MaHandle2,MaHandle3,RT=0;
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   ChartSetInteger(0,CHART_SCALE,0,5);
   SetIndexBuffer(0,Ma1Buffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(1,Ma2Buffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,Ma3Buffer,INDICATOR_CALCULATIONS);
   MaHandle1=iMA(NULL,0,10,0,MODE_SMA,PRICE_CLOSE);
   MaHandle2=iMA(NULL,0,20,0,MODE_SMA,PRICE_CLOSE);
   MaHandle3=iMA(NULL,0,30,0,MODE_SMA,PRICE_CLOSE);
   ChartSetInteger(0,CHART_CROSSHAIR_TOOL,0,true);
//  GetWindowProperties(W);

//---
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason) {if (reason<2) ChartRedraw(); }
//+------------------------------------------------------------------+
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[])
  {
   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<=0) to_copy=rates_total;
   else
     {
      to_copy=rates_total-prev_calculated;
      to_copy++;
     }
   if(CopyBuffer(MaHandle1,0,0,to_copy,Ma1Buffer)<=0) Print("Error CopyBuffer1 - ",GetLastError());
   if(CopyBuffer(MaHandle2,0,0,to_copy,Ma2Buffer)<=0) Print("Error CopyBuffer2 - ",GetLastError());
   if(CopyBuffer(MaHandle3,0,0,to_copy,Ma3Buffer)<=0) Print("Error CopyBuffer3 - ",GetLastError());
   if(rates_total==prev_calculated && W.Right_bar<1)
     {
      Canvas.FillRectangle((int)Canvas.X(0.0)-11,W.Height-1,(int)Canvas.X(0.0)+11, 0,0);
      Canvas.FillRectangle((int)Canvas.X(0.0)-11,W.Height-1,(int)Canvas.X(0.0)-5, W.Height-Round(fabs(Ma1Buffer[RT-1]-W.Y_min)/(5*W.dy_pix)),0xA0FF0000);
      Canvas.FillRectangle((int)Canvas.X(0.0)- 3,W.Height-1,(int)Canvas.X(0.0)+3, W.Height-Round(fabs(Ma2Buffer[RT-1]-W.Y_min)/(5*W.dy_pix)),0xA00000FF);
      Canvas.FillRectangle((int)Canvas.X(0.0)+ 5,W.Height-1,(int)Canvas.X(0.0)+11,W.Height-Round(fabs(Ma3Buffer[RT-1]-W.Y_min)/(5*W.dy_pix)),0xA000FF00);
      Canvas.Update();
     }
   RT=rates_total;
   return(rates_total);
  }
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      Canvas.Erase(0);
      for(int i=W.Left_bar;i>=W.Right_bar; i--)
        {
         Canvas.FillRectangle((int)Canvas.X((double)i)-11,W.Height-1,(int)Canvas.X((double)i)-5, W.Height-Round(fabs(Ma1Buffer[RT-1-i]-W.Y_min)/(5*W.dy_pix)),0xA0FF0000);
         Canvas.FillRectangle((int)Canvas.X((double)i)- 3,W.Height-1,(int)Canvas.X((double)i)+3, W.Height-Round(fabs(Ma2Buffer[RT-1-i]-W.Y_min)/(5*W.dy_pix)),0xA00000FF);
         Canvas.FillRectangle((int)Canvas.X((double)i)+ 5,W.Height-1,(int)Canvas.X((double)i)+11,W.Height-Round(fabs(Ma3Buffer[RT-1-i]-W.Y_min)/(5*W.dy_pix)),0xA000FF00);
        }
      Canvas.Update();
     }
  }
//+------------------------------------------------------------------+