Manipulate chart UI, scales or other approach

Piotr Lenartowicz  

Hi,

  I'm a JavaScript/TypeScript dev with some Java, C experience. I'm interested in creating custom indicator/indicators. I wish to manipulate the main chart to have some indicators on candle side and on the bottom of the chart. I want to ask more experience MQL devs on what approach would be finest.

  First i want to creata a space/margin to the right side of each candle. In this space I would like to put some info from my calcuations. Is it possible to do so? For example with chart properties/chart object from Standard Library? (see spaces.png)

  In the end I'd like it to look somewhat like in full_graphic.png. I got wide bar (width x) with same width x to the right, where I'd be able to insert objects. Also I'd like to add some histagram or bars on top or bottom of the chaart. I wonder if ObjectCreate Rectangle or Button would be a good solution(if I'd like to create volume bar with a number in it). It's also worth thinking about placing it in separate window.

  If such chart manipulation is impossible should I use a cusom created canvas for it?

I can see people making cluster like indicators. I assume the time scale does not represent correct values, but for me the price scale is most imortant.
https://www.mql5.com/en/market/product/43130?source=Site+Market+MT5+Indicator+Search+Rating006%3acluster

  I'm willing to learn MQL5 and read the docs, just need to consult the most probable solution to not waste time on programing failed ideas.  


Thank you for any knowledge you can share.

Buy the 'Clusters Chart MT5' Technical Indicator for MetaTrader 5 in MetaTrader Market
Buy the 'Clusters Chart MT5' Technical Indicator for MetaTrader 5 in MetaTrader Market
  • www.mql5.com
The indicator displays volume clusters or volume profiles to choose from. For trading symbols which contain the tape of deals, the indicator can
Files:
spaces.png  17 kb
Fernando Carreiro  

Like all languages, most things are possible, but with varying degrees of required effort. MQL5 is no different in that respect. Some of the things you mentioned can easily be done, while others require more effort.

However, in order for you to understand any suggestions that may be given to you, you will first need to dive in deep into learning MQL5 properly. You will have to fully understand how the platform functions and how MQL5 is coded. Only then will you be able to understand what is possible, what can be easily achieved, what requires more effort or might require a different approach.

There will be a steep learning curve and it will take quite a bit of time. It will take you at least a few months, before you reach a sufficient level of proficiency to be able to accomplish some of those goals.

Please note, that MQL5 does have a "Canvas" which will allow you to create your own graphs or any kind of visual output, and even has a OpenGL library. So all that you have mentioned is possible, but some of it may require quite a bit of coding effort.

Piotr Lenartowicz  

  I get " '=' - name expected Canvas.mqh 2612 9 " error when I try to initialize Canvas.

I only include the Canvas and try initialize it. 

#include <Canvas\Canvas.mqh>

...

CCanvas canvas;

Just including the Canvas\Canvas.mqh in indicator throws an error.

How is this possible? Can't google similar error or find in forum. I did not try to make any changes in libraries. Not in Canvas for sure.

Fernando Carreiro  
Piotr Lenartowicz #  I get " '=' - name expected Canvas.mqh 2612 9 " error when I try to initialize Canvas. I only include the Canvas and try initialize it. 

Just including the Canvas\Canvas.mqh in indicator throws an error. How is this possible? Can't google similar error or find in forum. I did not try to make any changes in libraries. Not in Canvas for sure.

I have no such error (example skeleton indicator code below, compiled with build 3391)!

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

#include <Canvas\Canvas.mqh>

CCanvas canvas;

int OnInit( void )
{
      return( INIT_SUCCEEDED );
};

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[] )
{
   return rates_total;
};
'Test.mq5'      Test.mq5        1       1
'Canvas.mqh'    Canvas.mqh      1       1
'FileBin.mqh'   FileBin.mqh     1       1
'File.mqh'      File.mqh        1       1
'Object.mqh'    Object.mqh      1       1
'StdLibErr.mqh' StdLibErr.mqh   1       1
'Rect.mqh'      Rect.mqh        1       1
code generated          1       1
0 errors, 0 warnings, 190 msec elapsed          1       1

Please provide sample code that causes the issue. You must be doing something wrong or putting it in the wrong place.

EDIT: What build are you using? Don't use "beta" builds!

Piotr Lenartowicz  
//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
//-------------------------------------------------------------------+
//|                                                  CandleDelta.mq5 |
//|                                                Piotr Lenartowicz |
//|                                                                  |
//+------------------------------------------------------------------+
#include <Generic\ArrayList.mqh>
#include <Canvas\Canvas.mqh>
//custom 
#include <Leny\DownloadTicks.mqh>
#include <Leny\GetTickFlags.mqh>
#include <Leny\CountDelta.mqh>
#include <Leny\ConvertDatetimeToMs.mqh>


#property copyright "Piotr Lenartowicz"
#property link      ""
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   1
//---- plot Delta to separate window
#property indicator_label1  "Delta"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrRed, clrLime
#property indicator_style1  STYLE_SOLID
#property indicator_width1  5
//---- indicator color buffer
#property indicator_label2 "Delta Colors"
#property indicator_type2 INDICATOR_COLOR_INDEX

#define DELTA_BUFFER 0
#define DELTA_COLOR_BUFFER 1
#define BUY_BUFFER 2
#define SELL_BUFFER 3

double BuysBuffer[];
double SellsBuffer[];
double DeltaBuffer[];
double DeltaColorBuffer[];
CArrayList<ulong> Buys;
CArrayList<ulong> Sells;
CArrayList<long> Delta;
CArrayList<long> CumulativeDelta;

CCanvas canvas;


MqlTick all_ticks[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(DELTA_BUFFER, DeltaBuffer, INDICATOR_DATA);
   SetIndexBuffer(DELTA_COLOR_BUFFER, DeltaColorBuffer, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(BUY_BUFFER, BuysBuffer, INDICATOR_DATA);
   SetIndexBuffer(SELL_BUFFER, SellsBuffer, INDICATOR_DATA);
   DownloadNumberOfLastTicks(all_ticks);
//---

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
{
   if(prev_calculated  < 1)
   {
      //First timetick which we find in ticks
      static int first_candle_idx = 0;
      int tick_idx = 0;
      int size = ArraySize(time);
      while(ConvertDTtoMs(time[first_candle_idx]) < (ulong)all_ticks[0].time_msc)
      {
         Buys.Add(0);
         Sells.Add(0);
         Delta.Add(0);
         CumulativeDelta.Add(0);
         first_candle_idx++;
      }
      //Range of each tick
      int start = tick_idx;
      int end = tick_idx + 1;
      if(ArraySize(all_ticks) > 1)
      {
         for(int i = first_candle_idx; i < size; i++)
         {
            ulong current_bar_time = ConvertDTtoMs(time[i]);
            while(current_bar_time > (ulong)all_ticks[end].time_msc) end++;
            DeltaVol delta = CalculateDeltaInd(start, end, all_ticks);
            Buys.Add(delta.buys);
            Sells.Add(delta.sells);
            long current_delta = delta.buys - delta.sells;
            long cumulative_delta = 0;
            CumulativeDelta.TryGetValue(CumulativeDelta.Count() - 1, cumulative_delta);
            Delta.Add(current_delta);
            CumulativeDelta.Add(cumulative_delta);
            DeltaBuffer[i] = current_delta;
            Print("Buys: ", (string)delta.buys, ", Sells: ", (string)delta.sells);
            DeltaColorBuffer[i] = i % 2 == 0 ? clrLime : clrRed;
            start = end + 1;
         }
      }
   }
   else if(Delta.Count() < ArraySize(time))
   {
      MqlTick last_tick;
      if(SymbolInfoTick(Symbol(), last_tick))
      {
         DeltaVol last_change = GetCurrentDeltaChange(last_tick);
         Buys.Add(last_change.buys);
         Sells.Add(last_change.sells);
         long current_delta = last_change.buys - last_change.sells;
         Delta.Add(current_delta);
         long cumulative_delta = 0;
         CumulativeDelta.TryGetValue(CumulativeDelta.Count() - 1, cumulative_delta);
         cumulative_delta += current_delta;
         CumulativeDelta.Add(cumulative_delta);
         DeltaBuffer[ArraySize(DeltaBuffer) - 1] = current_delta;
      }
   }
   else
   {
      MqlTick last_tick;
      if(SymbolInfoTick(Symbol(), last_tick))
      {
         int idx = Buys.Count() - 1;
         DeltaVol last_change = GetCurrentDeltaChange(last_tick);
         long last_buy = 0;
         Buys.TryGetValue(idx, last_buy);
         Buys.TrySetValue(idx, last_buy + last_change.buys);
         long last_sell = 0;
         Sells.TryGetValue(idx, last_sell);
         Sells.TrySetValue(idx, last_sell + last_change.sells);
         long last_delta = 0;
         long current_delta = last_change.buys - last_change.sells;
         Delta.TryGetValue(idx, last_delta);
         Delta.TrySetValue(idx, last_delta + current_delta);
         long cumulative_delta = 0;
         CumulativeDelta.TryGetValue(idx, cumulative_delta);
         cumulative_delta += current_delta;
         CumulativeDelta.TrySetValue(idx, cumulative_delta);
         DeltaBuffer[idx] += current_delta;
         PrintFormat("%d, cum: %d", current_delta, cumulative_delta);
      }
   }
//---
//--- return value of prev_calculated for next call
   return(rates_total);
}
Piotr Lenartowicz  

I must be doing something wrong... I just created fresh ExpertAdvisor and  including canvas throws the same error as described above.

#include <Canvas\Canvas.mqh>
//-- custom imports
#include "DataStructures\Array.mqh"
#include "utils\DownloadTicks.mqh"
#include "utils\GetTickFlags.mqh"
#include "utils\CountDelta.mqh"
#include "utils\ConvertDatetimeToMs.mqh"

the line from Canvas 2612 is getFont values

...
//+------------------------------------------------------------------+
//| Get font params                                                  |
//+------------------------------------------------------------------+
void CCanvas::FontGet(string &name,int &size,uint &flags,uint &angle)
  {
   name =m_fontname;
   size =m_fontsize;
   flags=m_fontflags; <<<<<<<<<<<<---------------
   angle=m_fontangle;
  }
Fernando Carreiro  
Piotr Lenartowicz #:

Your code is dependant on your own include files, so we can't compile it. So, I tested as follows ...

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
//-------------------------------------------------------------------+
//|                                                  CandleDelta.mq5 |
//|                                                Piotr Lenartowicz |
//|                                                                  |
//+------------------------------------------------------------------+
#include <Generic\ArrayList.mqh>
#include <Canvas\Canvas.mqh>
//custom 
//#include <Leny\DownloadTicks.mqh>
//#include <Leny\GetTickFlags.mqh>
//#include <Leny\CountDelta.mqh>
//#include <Leny\ConvertDatetimeToMs.mqh>


#property copyright "Piotr Lenartowicz"
#property link      ""
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   1
//---- plot Delta to separate window
#property indicator_label1  "Delta"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrRed, clrLime
#property indicator_style1  STYLE_SOLID
#property indicator_width1  5
//---- indicator color buffer
#property indicator_label2 "Delta Colors"
#property indicator_type2 INDICATOR_COLOR_INDEX

#define DELTA_BUFFER 0
#define DELTA_COLOR_BUFFER 1
#define BUY_BUFFER 2
#define SELL_BUFFER 3

double BuysBuffer[];
double SellsBuffer[];
double DeltaBuffer[];
double DeltaColorBuffer[];
CArrayList<ulong> Buys;
CArrayList<ulong> Sells;
CArrayList<long> Delta;
CArrayList<long> CumulativeDelta;

CCanvas canvas;


MqlTick all_ticks[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(DELTA_BUFFER, DeltaBuffer, INDICATOR_DATA);
   SetIndexBuffer(DELTA_COLOR_BUFFER, DeltaColorBuffer, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(BUY_BUFFER, BuysBuffer, INDICATOR_DATA);
   SetIndexBuffer(SELL_BUFFER, SellsBuffer, INDICATOR_DATA);
//   DownloadNumberOfLastTicks(all_ticks);
//---

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
{
//---
//--- return value of prev_calculated for next call
   return(rates_total);
}

And it compiles with no problems ...

'Test.mq5'      Test.mq5        1       1
'ArrayList.mqh' ArrayList.mqh   1       1
'IList.mqh'     IList.mqh       1       1
'ICollection.mqh'       ICollection.mqh 1       1
'IComparer.mqh' IComparer.mqh   1       1
'EqualFunction.mqh'     EqualFunction.mqh       1       1
'IEqualityComparable.mqh'       IEqualityComparable.mqh 1       1
'ArrayFunction.mqh'     ArrayFunction.mqh       1       1
'CompareFunction.mqh'   CompareFunction.mqh     1       1
'IComparable.mqh'       IComparable.mqh 1       1
'Introsort.mqh' Introsort.mqh   1       1
'DefaultComparer.mqh'   DefaultComparer.mqh     1       1
'Canvas.mqh'    Canvas.mqh      1       1
'FileBin.mqh'   FileBin.mqh     1       1
'File.mqh'      File.mqh        1       1
'Object.mqh'    Object.mqh      1       1
'StdLibErr.mqh' StdLibErr.mqh   1       1
'Rect.mqh'      Rect.mqh        1       1
code generated          1       1
0 errors, 0 warnings, 302 msec elapsed          1       1

You will have to analyse your own includes to see what is causing the issue.

EDIT: Personally I would place the #include files AFTER the #properties.

William Roeder  
Also, don't use #defines
#define DELTA_BUFFER 0
#define DELTA_COLOR_BUFFER 1
#define BUY_BUFFER 2
#define SELL_BUFFER 3
when you mean an enumeration
enum Buffers{DELTA_BUFFER, DELTA_COLOR_BUFFER, BUY_BUFFER, SELL_BUFFER};
Piotr Lenartowicz  
Than you both!!! Your the best, I did manage to move forward with buffers and indicator. Enum was a helpfull tip. Now i need to get tick history from somewhere, I guess the best source would be trying broker demo account and checking it in MT5 View > Symbols > tick Request.
I also was able to create a CCanvas, I'll look into docs now, because I guess I got a problem attaching it to the current chart.