Canvas is cool! - page 99

 
Doerk Hilger #:

I have a similar thing. But the problem is that you don't get the information all the time, as many times the event is missed/forgotten/not happening.

For such cases, I have a ChartChanged() function in this library, which forcibly updates all the chart parameters. I mainly use it in the tester mode.
In general, I managed to achieve acceptable work when the acceleration of XY <=> price-time coordinates translation is tens and even hundreds of thousands of times faster than using mega-braking ChartGet.... and XY,... functions.
 
Nikolai Semko #:
For such cases, I have a ChartChanged() function in this library, which forcibly updates all the chart parameters. I mainly use it in the tester mode.
In general, I managed to achieve acceptable work when the acceleration of XY <=> price-time coordinates translation is tens and even hundreds of thousands of times faster than using mega-braking ChartGet.... and XY,... functions.

Yeah of course, right decision. I even transfer all the buffered values to the indicators and no indicator never uses any ChartGetWhatever function. Its all just hell of work to create all these workarounds and it took me months to figure out that the parallel access of any Chart values from EA and indicators is the reason for freezes of the whole MT terminal. 

MQL is simply highly critical when its getting complex. Its a fact and I would wish so much, that MQ would offer to cooperate with professionals like us. But thats just a wish. For quite a while I was in contact with Renat directly, but from some time, he simply didn´t reply anymore at all. 

A pity. 

Long term, the only way out of this is to develop whatever is possible in C# and (mis)use MQL as a host to exchange data and receive commands from C#. This is what I am working on in the meanwhile and its the most stable solution. The pipes are written in native C and I can choose between sycnhronous and asynchronous transfer. All visual stuff is executed in a separate thread. Funfact: It takes 20 microseconds to convert the whole metrics data plus all colors into a byte stream, 10 microseconds to transfer, 20 microseconds to convert the data back to a structure in C# - but 1.000 times more to execute ONE ChartGetInteger() function in MQL plus same time again in timer just to check. That is a massive bottleneck and nothing in CCanvas, as nice as it is, can make that up. 

All u can do with CCanvas, can then also be done with GDI, since CCanvas is 1:1 the same basis anyway. And with some tricks, you can use the C# Graphics GDI functions to write directly into the same array - also async in another thread without sending back the bitmap first. 

 
Doerk Hilger #:
In the long run, the only way out is to develop everything possible in C# and (incorrectly) use MQL as a host to exchange data and get commands from C#.
I would say that in the long run you have to get away from any trading platforms, and write your trading systems in C++ or Rust on a high performance server with your own connectors to the exchanges. Like all high-tech hedge funds specialising in algorithmic trading do. And the client control panel with all the necessary visualisation can be done on anything. Even in a browser.
And MT5, of course, is a great way to start thanks to the possibility to test your trading systems on real ticks and free access to quotes. Thank you very much for that!
 

for drawing in Canvas

you can use cairo https://cairographics.org/, take as surface (initial, the same as in Canvas) an array of pixels, format ARGB32 and go with a song....

Here is an example, but through a separate DLL. To write #import to API cairo_XXX honestly lazy.

MQL:

#include <WinApi/LibLoaderApi.mqh>
#import "CairoChart1.dll"
int CairoChart_Test1(int width,int height,uint &data[]);
#import

string prefix="CairoChart";
void Test1(int width=800,int height=600)
{
   uint data[];
   string obj=prefix+".test1";
   string rc_name=prefix+".test1";
   // create image   
   ArrayResize(data,width*height);
   ArrayInitialize(data,0x10101010);
   // call cairo
   CairoChart_Test1(width,height,data);
   // create(update) resource from data
   if (!ResourceCreate(rc_name,data,(uint)width,(uint)height,0,0,(uint)width,COLOR_FORMAT_ARGB_RAW)) {
      Print("ResourceCreate failed");
      return;
   }
   // create object with resource
   if (!ObjectCreate(0,obj,OBJ_BITMAP_LABEL,0,0,0)) {
      Print("ObjectCreate failed (exists?)");
   }
   ObjectSetInteger(0,obj,OBJPROP_HIDDEN,false);
   ObjectSetInteger(0,obj,OBJPROP_XSIZE,width);
   ObjectSetInteger(0,obj,OBJPROP_YSIZE,height);
   ObjectSetInteger(0,obj,OBJPROP_XDISTANCE,100);
   ObjectSetInteger(0,obj,OBJPROP_YDISTANCE,100);
   ObjectSetString(0,obj,OBJPROP_BMPFILE,"::"+rc_name);
   ChartRedraw();
}

int OnInit()
{
   EventSetTimer(60);
   // load and fixate cairo in app
   string cairoModule="libcairo-2.dll";
   if (!GlobalVariableCheck(cairoModule)) {
      GlobalVariableSet(cairoModule,1.0);
      GlobalVariableTemp(cairoModule);
      LoadLibraryW(cairoModule);
   }
   // invoke test
   Test1();
   ChartRedraw();
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   EventKillTimer();
   ObjectsDeleteAll(0,prefix+".");
   ChartRedraw();
}

void OnTick()
{
}

C

#include <cairo.h>

#include "CairoChart.hpp"

MT_API(int) CairoChart_OnInit(void)
{
    return 0;
}
MT_API(void) CairoChart_OnDeinit(const int reason)
{
    (void) reason;
}

/** тест1: рисуем в предоставленном массиве ARGB
 *  рамка и перекрестие
 **/

MT_API(int) CairoChart_Test1(int32_t width,int32_t height,uint8_t *data)
{
    // рисуем сразу во внешнем массиве
    cairo_surface_t *surface = cairo_image_surface_create_for_data(data,CAIRO_FORMAT_ARGB32,width,height,cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,width));
    if (surface == NULL) {
        return -1;
    }
    // 
    cairo_t *cr=cairo_create(surface);
    if (cr == NULL) {
        cairo_surface_destroy(surface);
        return -1;
    }
    // всё зальём 
    cairo_set_source_rgba(cr, 0.3,0.3,0.3, 0);
    cairo_fill(cr);
    // рамка по краям области
    cairo_set_source_rgba(cr, 0,0.5,0, 0.5);        
    cairo_rectangle(cr,0,0,width-1,height-1);       
    cairo_stroke(cr);
    // диагональное перекрестие
    cairo_set_source_rgba(cr, 0.5,0,0, 0.5);        
    cairo_move_to(cr,0,0);
    cairo_line_to(cr,width-1,height-1);
    cairo_move_to(cr,0,height-1);
    cairo_line_to(cr,width-1,0);
    cairo_stroke(cr);

    cairo_surface_flush(surface);

    cairo_destroy(cr);
    cairo_surface_destroy(surface);

    return 0;
}

H

#define  MT_API(x) __declspec(dllexport) x __stdcall

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
MT_API(int) CairoChart_OnInit(void);
MT_API(void) CairoChart_OnDeinit(const int32_t reason);
MT_API(int) CairoChart_Test1(int32_t width,int32_t height,uint8_t *data);

#ifdef __cplusplus
}
#endif

and the result of course :

but the approach will not work for a dying market :-))

But it closes a lot of problems and even raises the question of whether Canvas is necessary...if you can draw on a ready array of pixels with a normal stable, mature library.

 
Maxim Kuznetsov #:

to draw in Canvas

you can use cairo https://cairographics.org/, take as surface (initial, the same as in Canvas) an array of pixels, format ARGB32 and go with a song...

Here is an example, but through a separate DLL. To write #import to the API cairo_XXX honestly lazy.

MQL:

C

H

and the result of course :

but the approach won't work for a dying market :-)

But it closes a lot of problems. and even raises the question whether Canvas is necessary...if you can draw on a ready array of pixels with a normal stable, mature library.

Actually I was aiming initially at Blend2D https://blend2d.com but there are no ready binary packages with it for win, and I couldn't build it from sorts (some cmake tricks are like that).

The principle of use is the same (you can also provide a pixel array and use it to drive), but B2D is more optimised than cairo and it is multithreaded.

If I get my hands on it next weekend, I'll tell you how to use it.

Blend2D
Blend2D
  • blend2d.com
2D Vector Graphics Engine
 
Реter Konow #:
Through the resource you can transfer a large amount of information from the tester to the Expert Advisor on the chart and trade with the panel by hand too. The system is certainly more complex than checking the states of buttons of the "dead" panel in the tester, but the possibilities are much greater.

Such a tandem cannot be sold on the Market. And the level of buyers there is not very good for such complexities. I often meet complaints like:
- I bought an Expert Advisor for MT5, but it does not work under MT4, how can I fix it?

 
Maxim Kuznetsov #:

to draw in Canvas

you can use cairo https://cairographics.org/, take as surface (initial, the same as in Canvas) an array of pixels, format ARGB32 and go with a song...

Here is an example, but through a separate DLL. To write #import to the API cairo_XXX honestly lazy.

MQL:

C

H

and the result of course :

but the approach won't work for a dying market :-)

But it closes a lot of problems. and even raises the question whether Canvas is necessary...if you can draw on a ready array of pixels with a normal stable, mature library.

and without external additional DLL, exclusively API cairographics.org

#property copyright "Maxim Kuznetsov (c) 2024"
#property link      "https://luxtrade.unaux.com"
#property version   "1.00"

#include <WinApi/LibLoaderApi.mqh>

// api cairographics.org
// как наполнится можно в отдельный mqh :-)
#define  cairo_surface_ptr ulong
#define  cairo_ptr ulong
#define  cairo_format_t int
#define  CAIRO_FORMAT_ARGB32 0

#import "libcairo-2.dll"
// surface
cairo_surface_ptr cairo_image_surface_create_for_data(uint &data[], cairo_format_t format,int width,int height,int stride);
void cairo_surface_flush(cairo_surface_ptr);
void cairo_surface_destroy(cairo_surface_ptr);
// cairo
cairo_ptr cairo_create(cairo_surface_ptr);
void cairo_destroy(cairo_ptr);
void cairo_stroke(cairo_ptr);
//paths
void cairo_new_path(cairo_ptr);
void cairo_move_to(cairo_ptr,double x,double y);
void cairo_rel_move_to(cairo_ptr,double dx,double dy);
void cairo_line_to(cairo_ptr,double x,double y);
void cairo_rel_line_to(cairo_ptr,double dx,double dy);
void cairo_rectangle(cairo_ptr,double x,double y,double width,double height);
void cairo_set_source_rgba(cairo_ptr,double red,double green,double blue,double alpha);
void cairo_fill(cairo_ptr);
#import

string prefix="test2";

void Test2 (int width=800,int height=600) 
{
   uint data[];
   string obj=prefix+".test1";
   string rc_name=prefix+".test1";
   // create image   
   ArrayResize(data,width*height);
   ArrayInitialize(data,0x10101010);
   // call cairo
   cairo_surface_ptr surface=cairo_image_surface_create_for_data(data,CAIRO_FORMAT_ARGB32,width,height,width*sizeof(uint));
   if (surface==0) {
      Print("cairo_image_surface_create_for_data() failed");
      return;
   }
   cairo_ptr cr=cairo_create(surface);
   if (cr==0) {
      Print("cairo_create() failed");
      cairo_surface_destroy(surface);
      return;
   }
   cairo_set_source_rgba(cr,0.8,0.8,0,0.1);
   cairo_move_to(cr,0,0);
   cairo_rectangle(cr,0,0,width-1,height-1);
   cairo_fill(cr);
   
   cairo_set_source_rgba(cr,0,0,0.9,0.5);
   cairo_rectangle(cr,0,0,width-1,height-1);
   cairo_stroke(cr);
   cairo_surface_flush(surface);      
   // create(update) resource from data
   if (!ResourceCreate(rc_name,data,(uint)width,(uint)height,0,0,(uint)width,COLOR_FORMAT_ARGB_RAW)) {
      Print("ResourceCreate failed");
      return;
   }
   cairo_destroy(cr);
   cairo_surface_destroy(surface);
   // create object with resource
   if (!ObjectCreate(0,obj,OBJ_BITMAP_LABEL,0,0,0)) {
      Print("ObjectCreate failed (exists?)");
   }
   ObjectSetInteger(0,obj,OBJPROP_HIDDEN,false);
   ObjectSetInteger(0,obj,OBJPROP_XSIZE,width);
   ObjectSetInteger(0,obj,OBJPROP_YSIZE,height);
   ObjectSetInteger(0,obj,OBJPROP_XDISTANCE,100);
   ObjectSetInteger(0,obj,OBJPROP_YDISTANCE,100);
   ObjectSetString(0,obj,OBJPROP_BMPFILE,"::"+rc_name);
   ChartRedraw();
}   
int OnInit()
{
   EventSetTimer(60);
   // load and fixate cairo in app
   string cairoModule="libcairo-2.dll";
   if (!GlobalVariableCheck(cairoModule)) {
      GlobalVariableSet(cairoModule,1.0);
      GlobalVariableTemp(cairoModule);
      LoadLibraryW(cairoModule);
   }
   // invoke test
   Test2();
   ChartRedraw();
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0,prefix+".");
   EventKillTimer();
}
void OnTick()
{
}
void OnTimer()
{
}
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
}

draws :-) WORKS !!!


 
Alexey Volchanskiy #:

You can't sell a tandem like this on the Market.

...

Well, why can't you sell it? Yes, you can. After all, it is one and the same Expert Advisor, but it is just installed on the chart and in the tester at the same time. Its panel is active on the chart, but not in the tester. The Expert Advisor from the chart writes instructions to open/close an order to the resource, which then reads the EA in the tester and places/deletes the order. Somewhere on the forum I posted a video of such a tandem (or Papkov, who I made it for, I don't remember). That video shows trade management in the tester through the panel on the MT4 chart. Maybe I will find it later.
 
Реter Konow #:
Why can't you do it? After all, it is one and the same Expert Advisor, it is just installed on the chart and in the tester at the same time. Its panel is active on the chart, but not in the tester. The Expert Advisor from the chart writes instructions to open/close an order to the resource, which then reads the EA in the tester and places/deletes the order. Somewhere on the forum I posted a video of such a tandem (or Papkov, who I made it for, I don't remember). That video shows trade management in the tester through the panel on the MT4 chart. Maybe I will find it later.

If it is the same one, then yes, I didn't think of it somehow ))) But I foresee a lot of problems with users, most of them are below the plinth level.

 
Alexey Volchanskiy #:

If it's the same one, then yes, I didn't think of it somehow )) But I foresee a lot of problems with users, most of them are below the plinth level.

Well, I don't know). I have been approached many times by people asking how to use my panels in the tester. For many people this question is relevant. And if I had not left MT4, I could easily help them. As for MT5, I assume that such a scheme will not work. But I have not checked it.

In general, there is a demand for panels trading in the tester. And it is strange that with such a level of programming power of forum members, no one has occupied an empty niche)).