Canvas - это круто! - страница 99

 
Nikolai Semko #:

Я уже давно реализовал это в библиотеке iCanvas.

один экземпляр оконной структуры W автоматически заполняется при каждом событии CHARTEVENT_CHART_CHANGE
.

У меня аналогично. Но проблема в том, что вы не получаете информацию постоянно, так как много раз событие пропускается/забывается/не происходит.

 
Doerk Hilger #:

У меня аналогично. Но проблема в том, что вы не получаете информацию постоянно, так как много раз событие пропускается/забывается/не происходит.

Для таких случаев у меня в этой библиотеке есть функция ChartChanged(), которая принудительно обновляет все параметры чарта. В основном её использую в режиме тестера.
В целом удалось достичь приемлемой работы, когда ускорение перевода координат пиксели XY <=> координаты цена-время осуществляется в десятки и даже сотни тысяч раз быстрее чем с использованием мегатормознутых ChartGet... и XY,... функций.
 
Nikolai Semko #:
Для таких случаев в этой библиотеке есть функция ChartChanged(), которая принудительно обновляет все параметры графика. В основном я использую ее в режиме тестера.
В целом, мне удалось добиться приемлемой работы, когда ускорение перевода координат XY <=> цена-время происходит в десятки и даже сотни тысяч раз быстрее, чем при использовании мега-тормозных функций ChartGet.... и XY,....

Да, конечно, правильное решение. Я даже переношу все буферизованные значения в индикаторы, и ни один индикатор никогда не использует ни одной функции ChartGetWhatever. Это просто адский труд - создавать все эти обходные пути, и мне потребовались месяцы, чтобы понять, что параллельный доступ к любым значениям Chart из советника и индикаторов является причиной зависания всего терминала MT.

MQL просто очень критичен, когда он становится сложным. Это факт, и я бы очень хотел, чтобы MQ предложил сотрудничать с профессионалами вроде нас. Но это только пожелание. Некоторое время я общался с Ренатом напрямую, но с некоторых пор он просто перестал отвечать.

Очень жаль.

В долгосрочной перспективе единственный выход - это разрабатывать все возможное на C# и (неправильно) использовать MQL в качестве хоста для обмена данными и получения команд из C#. Это то, над чем я работаю в данный момент, и это самое стабильное решение. Пайпы написаны на родном C, и я могу выбирать между синхронной и асинхронной передачей. Все визуальные вещи выполняются в отдельном потоке. Забавный факт: 20 микросекунд уходит на преобразование всех данных метрики плюс всех цветов в байтовый поток, 10 микросекунд на передачу, 20 микросекунд на преобразование данных обратно в структуру на C# - но в 1.000 раз больше на выполнение ОДНОЙ функции ChartGetInteger() на MQL плюс еще столько же в таймере просто для проверки. Это огромное узкое место, и ничто в CCanvas, каким бы хорошим он ни был, не может его компенсировать.

Все, что вы можете сделать с помощью CCanvas, можно сделать и с помощью GDI, поскольку CCanvas в любом случае 1:1 имеет ту же основу. И с некоторыми хитростями, вы можете использовать функции C# Graphics GDI для записи непосредственно в тот же массив - также async в другом потоке, не отправляя сначала обратно растровое изображение.

 
Doerk Hilger #:
В долгосрочной перспективе единственный выход - это разрабатывать все возможное на C# и (неправильно) использовать MQL в качестве хоста для обмена данными и получения команд из C#. 
Я бы сказал, что в долгосрочной перспективе надо уходить от каких-либо трейдерских платформ, и писать свои торговые системы на С++ или Rust на высокопроизводительном сервере со своими коннекторами к биржам. Как это делают все высокотехнологичные хеджфонды, специализирующиеся на алгоритмическом трейдинге. А клиентскую панель управления со всей необходимой визуализацией можно делать на чем угодно. Да хоть в браузере.
А MT5, конечно же, отличная возможность для старта благодаря возможности протестировать свои торговые системы на реальных тиках и бесплатному доступу к котировкам. За что им большое спасибо!
 

для рисования в Canvas

можно использовать cairo https://cairographics.org/ , в качестве surface брать (исходный, тот-же что в Canvas) массив пикселей, формат ARGB32 и вперёд с песней.. 

далее пример, но через отдельную DLL. Прописывать #import на API cairo_XXX честно лень. 

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

ну и результат конечно :

но подход не покатит для умирающего маркета :-)

зато закрывается масса проблем. и даже встаёт вопрос, а нужен-ли Canvas..если по готовому массиву пикселей можно рисовать нормальной стабильной, взрослой библиотекой

 
Maxim Kuznetsov #:

для рисования в Canvas

можно использовать cairo https://cairographics.org/ , в качестве surface брать (исходный, тот-же что в Canvas) массив пикселей, формат ARGB32 и вперёд с песней.. 

далее пример, но через отдельную DLL. Прописывать #import на API cairo_XXX честно лень. 

MQL:

C

H

ну и результат конечно :

но подход не покатит для умирающего маркета :-)

зато закрывается масса проблем. и даже встаёт вопрос, а нужен-ли Canvas..если по готовому массиву пикселей можно рисовать нормальной стабильной, взрослой библиотекой

вообще-то целился изначально в Blend2D https://blend2d.com но для win готовых бинарных пакетов с ним нету и что-то слёту не удалось его собрать из сорцов (какие-то приколы cmake они такие)

принцип использования такой-же (то-же можно предоставить пиксельный массив и по нему загоняться), но B2D более оптимизирован чем cairo и он многопоточный. 

если на след.выходных руки дойдут - расскажу как с ним.

Blend2D
Blend2D
  • blend2d.com
2D Vector Graphics Engine
 
Реter Konow #:
Через ресурс можно передавать большой обьем информации из тестера в советник на графике и торговать с помощью панели руками тоже. Система безусловно более сложная чем проверка состояний кнопок "мертвой" панели в тестере, но возможностей с ней на порядок больше.

Такой тандем нельзя продать на Маркете. Да и уровень покупателей там не ахти для таких сложностей. Часто встречаю жалобы типа:
— Я купил советник для МТ5, но он не работает под МТ4, как это исправить?

 
Maxim Kuznetsov #:

для рисования в Canvas

можно использовать cairo https://cairographics.org/ , в качестве surface брать (исходный, тот-же что в Canvas) массив пикселей, формат ARGB32 и вперёд с песней.. 

далее пример, но через отдельную DLL. Прописывать #import на API cairo_XXX честно лень. 

MQL:

C

H

ну и результат конечно :

но подход не покатит для умирающего маркета :-)

зато закрывается масса проблем. и даже встаёт вопрос, а нужен-ли Canvas..если по готовому массиву пикселей можно рисовать нормальной стабильной, взрослой библиотекой

и без внешней доп.DLL, исключительно 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)
{
}

рисует :-) РАБОТАЕТ !!


 
Alexey Volchanskiy #:

Такой тандем нельзя продать на Маркете. 

...

Ну почему же нельзя, можно. Ведь это один и тот же советник, просто устанавливается одновременно на график и в тестер. На графике его панель активна, а в тестере нет. Советник с графика пишет указания открыть/закрыть ордер в ресурс, который затем читает советник в тестере и ставит/удаляет ордер. Где то на форуме я выкладывал  видео работы такого тандема (или выкладывал Папков которому я его делал, не помню). В том видео показано управление торговлей в тестере через панель на графике МТ4. Может потом найду.
 
Реter Konow #:
Ну почему же нельзя, можно. Ведь это один и тот же советник, просто устанавливается одновременно на график и в тестер. На графике его панель активна, а в тестере нет. Советник с графика пишет указания открыть/закрыть ордер в ресурс, который затем читает советник в тестере и ставит/удаляет ордер. Где то на форуме я выкладывал  видео работы такого тандема (или выкладывал Папков которому я его делал, не помню). В том видео показано управление торговлей в тестере через панель на графике МТ4. Может потом найду.

Если один и тот же, то да, как-то не подумал )) Но предвижу массу проблем с пользователями, у большинства уровень ниже плинтуса.