English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Графики и диаграммы в формате HTML

Графики и диаграммы в формате HTML

MetaTrader 5Примеры | 18 января 2011, 13:32
31 427 15
Victor
Victor

Введение

Скорее всего MetaTrader 5 является вполне самодостаточным продуктом и в дополнительных расширениях не нуждается. MetaTrader 5 обеспечивает связь с брокером, отображает котировки, позволяет использовать для анализа рынка разнообразные индикаторы и, конечно, предоставляет трейдеру возможность осуществлять торговые операции. Совершенно ясно, что ориентированный в первую очередь на предоставление возможности комфортно торговать, MetaTrader 5 не может, да, наверное, и не должен являться абсолютно универсальным инструментом, предназначенным для научных исследований, анализа математических методов, создания мультимедийного контента и так далее.

Более того, стремление к излишней универсальность программного продукта в конечном итоге чаще всего приводит к снижению его эффективности, надежности и безопасности. С другой стороны, в той или иной ситуации у пользователя может возникнуть потребность в каких-то дополнительных возможностях, тем более что трейдерами являются люди, имеющие различные специальности и разное образование. Поэтому любые дополнительные возможности могут увеличить привлекательность торговой платформы, если, конечно, они достигаются достаточно простым способом и не за счет снижения ее надежности и безопасности.

В данной статье рассмотрим один из вариантов такого дополнения, который может дать возможность строить на основе полученных в терминале различные графики и диаграммы.

Каждая программа должна делать то, что у нее лучше всего получается. Если придерживаться такого принципа, то давайте возложим на MetaTrader 5 обязанности обмена с брокером, сбор и обработку полученной информации, а для графического отображения этой информации будем использовать другую, предназначенную для этих целей программу.


WEB-браузер

Сегодня трудно найти компьютер, на котором не был бы установлен WEB-браузер. Браузеры уже на протяжении длительного времени постоянно развиваются и совершенствуются. Современные браузеры достаточно надежны, стабильны в работе и, что немаловажно, бесплатны. Учитывая, что WEB-браузер является практически основным инструментом служащим для доступа в сеть Internet, подавляющее большинство пользователей хорошо знакомы с ним и не испытывают ни каких трудностей при его использовании.

Возможности современных браузеров достаточно широки, мы привыкли к тому, что с помощью WEB-браузера просматриваем видеоролики, слушаем музыку, играем в игры и уже совершенно не обращаем на это внимания. Таким образом, WEB-браузер на сегодняшний день является достаточно развитым инструментом для отображения различного рода информации, которая может быть представлена в совершенно разных форматах.

Нельзя не упомянуть тот факт, что в настоящее время существует несколько популярных, хорошо себя зарекомендовавших WEB-браузеров, среди них InternetExplorer, Mozilla Firefox, Google Chrome, Opera. В части программной реализации и пользовательского интерфейса эти браузеры могут существенно отличаться друг от друга. Но при этом, теоретически, должны в полной мере поддерживать основные стандарты, принятые в сети для обмена информацией, что в первую очередь касается непосредственно стандартов языка HTML.

На практике, несмотря на усилия разработчиков, браузеры все же имеют некоторые индивидуальные особенности в плане реализации тех или иных протоколов или технологий. Если мы сталкиваемся с тем, что тот или иной браузер благодаря своим индивидуальным особенностям нас не устраивает, то эту проблему легко решить установкой на компьютер дополнительно одного или нескольких разных WEB-браузеров. Даже ярые приверженцы, например, Firefox, все равно кроме него имеют в системе как минимум Internet Explorer.

Несмотря на то, что WEB-браузеры разрабатывались как клиентская часть, обеспечивающая взаимодействие с удаленным сервером, они также могут использоваться и для отображения локальной информации, размещенной на компьютере пользователя. Примером тому может быть просмотр ранее сохраненных на компьютере WEB-страниц. При таком локальном режиме работы доступ в сеть браузеру может вовсе не понадобиться.

Таким образом, WEB-браузер, работающий в offline-режиме, является очень привлекательным кандидатом на роль программы, используемой для расширения графических возможностей терминала MetaTrader 5. Для его использования не потребуются ни дорогостоящие покупки, ни громоздкие длительные инсталляции, ни освоение пользователем нового программного продукта. Поэтому далее в статье будем рассматривать возможность использования именно WEB-браузера для построения графиков и диаграмм на основе данных полученных в MetaTrader 5.


HTML и JavaScript

Остановив свой выбор на использовании в качестве расширения WEB-браузера, определим для себя основное правило, которого в дальнейшем будем строго придерживаться - отображение созданных нами HTML-страниц должно осуществляться без участия локального или удаленного WEB-сервера. То есть мы не будем устанавливать на нашем компьютере серверное программное обеспечение, и отображение наших страниц не потребует наличия выхода в сеть. Созданные нами HTML-страницы должны отображаться только средствами самого WEB-браузера и должны быть размещены на нашем компьютере. Это правило позволит свести к минимуму риск, связанный с возможным снижением безопасности за счет выхода во внешние сети.

Используя для вывода информации только возможности HTML 4, можно создавать WEB-страницы с таблицами и форматированным текстом, размещать на странице изображения, но эти возможности нас не могут полностью удовлетворить, так как нашей целью является построение полноценных графиков и диаграмм на основе данных полученных от MetaTrader 5.

В большинстве случаев, то, что мы видим в браузере, путешествуя по различным сайтам, создано при помощи расширений языка HTML. В основном эти расширения исполняются на стороне сервера и по этой причине нам совершенно не подходят. Для нас могут представлять интерес технологии, которые в состоянии работать на стороне браузера и не требуют серверного программного обеспечения, например, Macromedia Flash, JavaScript, Java.

Если для исполнения на стороне браузера приложений Macromedia Flash и Java нам понадобится как минимум установка дополнительных плагинов, то пользовательские программы, написанные на JavaScript, выполняются непосредственно самим браузером. Все распространенные WEB-браузеры имеют собственный встроенный JavaScript интерпретатор. Для того чтобы избежать необходимости в инсталляции каких либо дополнительных программ или плагинов,остановим свой выбор на JavaScript.

Таким образом, в дальнейшем будем использовать только MetaTrader 5 с MQL5 и WEB-браузер с HTML и JavaScript, никакого дополнительного программного обеспечения не понадобится. Следует напомнить, что HTML-страница является ни чем иным, как текстовым файлом. Поэтому для создания документа в формате HTML подойдет любой текстовый редактор. Можно, например, создавать и редактировать HTML-код в том же MetaEditor 5.  При написании статьи редактирование HTML-кода осуществлялось в браузере Opera@USB v10.63, который позволяет редактировать содержимое страницы, сохранять измененную страницу и видеть в соседней закладке как она будет отображаться.

У человека не знакомого с языками HTML и JavaScript может резонно возникнуть опасение в связи с возможными трудностями, связанными с их освоением. Для того что бы максимально облегчить себе задачу и избежать углубленного изучения HTML и JavaScript, попробуем использовать готовые решения, базирующиеся на этой технологии. Так как в рамках данной статьи наша задача ограничивается только построением графиков и диаграмм, обратимся к готовым, специально для этого написанным JavaScript-библиотекам.

Достаточно развитой графической библиотекой является Emprise JavaScript Charts, возможно читателю будет интересно познакомиться с ней по приведенной ссылке, но данная библиотека не совсем бесплатная. Поэтому обратимся к бесплатным библиотекам, например, Dygraphs JavaScript Visualization Library и Highcharts charting library. Dygraphs привлекает своей компактностью и простотой, а библиотека Highcharts в свою очередь включает в себя больше возможностей и выглядит более универсальной. Несмотря на то, что библиотека Highcharts имеет размер примерно 75 KB и дополнительно требует наличия библиотеки jQuery, которая имеет размер примерно 70 KB, все же остановим свой выбор именно на ней.

Познакомиться с возможностями библиотеки Highcharts можно на сайте http://www.highcharts.com/ в разделе “Demo Gallery”. Для каждого из примеров выбрав пункт “View options” можно посмотреть его исходный JavaScript-код. Подробная документация по библиотеке находится в разделе “Documentation/Options Reference”, в этом разделе так же можно найти большое количество примеров использования той или иной опции. На первый взгляд из-за обилия JavaScript-кода и непривычного для MQL-программиста синтаксиса, использование библиотеки может показаться излишне сложным. Но это не совсем так. Рассмотрим первый простой пример HTML-файла, который средствами библиотеки будет отображать график.

Создадим в качестве примера в редакторе “Блокнот” текстовый файл с именем Test_01.htm и для начала скопируем в него следующий простой пример использования библиотеки.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<!-- - -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
             type="text/javascript"></script>
<script src="/js/highcharts.js" type="text/javascript"></script>
<!-- - -->
<script type="text/javascript">
var chart1;
$(document).ready(function(){
  chart1 = new Highcharts.Chart({
    chart: {renderTo: 'container1'},
    series: [{data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}]
  });
});
</script>
<!-- - -->
</head>
<body>
<div id="container1" style="width: 700px; height: 400px "></div>
</body>
</html>

Код примера для наглядности разделен комментариями на четыре части. Самая первая, верхняя часть кода содержит обычные для HTML-страницы теги. Эта часть кода особого интереса для нас сейчас не представляет.

За ней следует другая часть, которая содержит два тега <script>. В первом случае мы даем браузеру указание загрузить с сайта ajax.googleapis.com код библиотеки jquery.min.js. Во втором случае предполагается, что на стороне сервера в каталоге /js/ располагается библиотека highcharts.js, которую браузер так же должен загрузить. Приняв ранее решение о том, что в процессе отображения создаваемых нами страниц не должно происходить обращение к внешним источникам, эту часть кода придется изменить. После внесения изменений эта часть кода будет выглядеть следующим образом

<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>

В этом случае мы даем указание загрузить обе библиотеки из каталога, в котором размещен наш HTML-файл, то есть из текущего каталога. Для того чтобы библиотеки были загружены браузером их необходимо предварительно скачать с http://ajax.googleapis.com/ и http://www.highcharts.com/ соответственно и скопировать в тот же каталог, где располагается наш HTML-файл. Обе эти библиотеки также можно найти в конце статьи в разделе “Файлы”.

В следующей части кода создается объект класса Highcharts.Chart. Параметр “renderTo: 'container1'“ указывает на то, что график будет выводиться в HTML-элемент с именем “container1”, а параметр “data” определяет данные, которые должны быть отображены на графике. Как видим в этом примере данные определяются непосредственно как параметры при создании объекта класса Highcharts.Chart. Путем несложных изменений вынесем определение отображаемых данных в отдельную часть кода, это позволит при необходимости отображения нескольких графиков сгруппировать их данные.

В последней части нашего примера тегом <div> объявляется HTML-элемент с именем “container1” и указываются размеры этого элемента. Как уже упоминалось ранее, именно этот HTML-элемент и будет служить для построения графика, размер которого будет определяться указанным в теге <div> размером элемента “container1”.

С учетом упомянутых изменений код нашего примера будет выглядеть следующим образом 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<!-- - -->
<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>
<!-- - -->
<script type="text/javascript">
var dat1 = [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4];
</script>
<!-- - -->
<script type="text/javascript">
var chart1;
$(document).ready(function(){
  chart1 = new Highcharts.Chart({
    chart: {renderTo: 'container1'},
    series: [{data: dat1}]
  });
});
</script>
<!-- - -->
</head>
<body>
<div id="container1" style="width: 700px; height: 400px "></div>
</body>
</html>

Этот тестовый пример с библиотеками можно скопировать из раздела “Файлы” в конце статьи. Файл примера Test_01.htm и файлы библиотек расположены в одном каталоге \Test, поэтому для просмотра результатов нашей работы достаточно просто двойным щелчком мышки открыть HTML-файл Test_01.htm. Необходимо помнить, что для нормального отображения этой тестовой страницы WEB-браузеру должно быть разрешено исполнять JavaScript. Так как браузеры в целях безопасности позволяют отключать эту опцию, она может оказаться выключенной. В результате мы должны увидеть следующее

Test_01.htm

Рисунок 1. Test_01.htm 

Это наш первый тестовый график и, несмотря на кажущуюся сложность данной технологии, его создание не заняло много времени. Следует обратить внимание на некоторые особенности отображения графиков созданных таким способом. Откройте в скопированном каталоге файл Test_01.htm, и если WEB-браузер позволяет увеличивать и уменьшать просматриваемые страницы, то вы сможете заметить, что даже при существенном увеличении качество отображения графика не ухудшается.

Это связано с тем, что такой график не является статическим изображением, как, например, PNG или JPEG-файлы, а вычерчивается заново после увеличения или уменьшения области отведенной для его прорисовки. Поэтому такое изображение нельзя сохранить на диск привычным способом, так как мы обычно сохраняем понравившиеся нам картинки. Учитывая, что график был построен средствами JavaScript, нельзя не упомянуть о том, что разные браузеры, имея собственные встроенные интерпретаторы этого языка, могут не всегда одинаково его исполнять.

Графики, построенные с помощью JavaScript, в разных браузерах иногда могут отображаться с некоторыми незначительными отличиями. Чаще всего эти отличия по сравнению с другими браузерами могут проявляться у Internet Explorer.

Но будем надеяться на то, что создатели JavaScript-библиотек позаботятся о максимально возможной совместимости их кода с большинством распространенных WEB-браузеров.


MetaTrader 5 и MQL5

В приведенном выше тестовом примере данные предназначенные для вывода на график задавались вручную, при создании HTML-страницы. Для организации передачи данных из MetaTrader 5 в создаваемый нами график воспользуемся простейшим способом. Пусть  MetaTrader 5 будет записывать данные в отдельный файл, из которого они будут загружаться в браузер при отображении графика. Напишем пример, включающий в себя HTML-страницу, которая будет отображать график, загружая данные из файла и скрипт на MQL5, который будет создавать этот файл.

В качестве HTML-файла используем созданный ранее файл Test_01.htm, внеся в него небольшие изменения. Измененный файл назовем example1.htm. Все изменения сведутся к тому, что строки

<script type="text/javascript">
var dat1 = [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4];
</script>
заменим на
<script type="text/javascript">
var dat1=[0];
</script>
<script src="exdat.txt" type="text/javascript"></script>
Теперь браузер в процессе загрузки HTML-страницы должен будет подгрузить текстовый файл exdat.txt, в котором и будет производиться присвоение массиву dat1 значений предназначенных для отображения на графике. Этот файл должен содержать в себе просто фрагмент JavaScript-кода. Такой файл легко может быть создан в MetaTreder 5 при помощи соответствующего скрипта. Пример такого скрипта приведен ниже
//+------------------------------------------------------------------+
//|                                                     Example1.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
  int i,n,fhandle;
  double gr[25];
  string str;
  
  n=ArraySize(gr);
  for(i=0;i<n;i++)
    {
    gr[i]=NormalizeDouble(MathSin(i*3*2*M_PI/n),4);
    }

  str=DoubleToString(gr[0],4);
  for(i=1;i<n;i++)
    {
    str+=","+DoubleToString(gr[i],4);
    }
  
  ResetLastError();
  fhandle=FileOpen("exdat.txt",FILE_WRITE|FILE_TXT|FILE_ANSI);
  if(fhandle<0){Print("File open failed, error ",GetLastError());return;}
  
  FileWriteString(fhandle,"dat1=["+str+"];\n");
  
  FileClose(fhandle);
  }
//+------------------------------------------------------------------+

В этом скрипте для хранения отображаемых данных используется массив gr[] размером 25 элементов. Это массив, в качестве примера, заполняется отсчетами синусоиды, при этом производится округление до четырех знаков после запятой. Массив, конечно, может быть заполнен любыми другими, более полезными данными.

Далее эти данные форматируются и объединяются в одну текстовую строку. Для того чтобы сократить объем создаваемого текстового файла, в строку выводятся значения элементов массива gr[] только с четырьмя знаками после запятой. Для этого используется функция DoubleToString(). После того как текстовая строка str сформирована она сохраняется в файле exdat.txt. В случае успешного исполнения скрипта, текстовый файл exdat.txt будет создан в каталоге клиентского терминала в подкаталоге \MQL5\Files; если такой файл уже существует, то он будет перезаписан.

Файлы jquery.min.js, highcharts.js, Example1.mq5, Example1.htm и exdat.txt представлены в конце статьи в разделе “Файлы”. Эти пять файлов размещены в каталоге \Example1. Для того что бы просто посмотреть на полученный результат, достаточно скопировать данный пример и двойным щелчком в каталоге \Example1 открыть файл Example1.htm. График будет построен по данным из файла exdat.txt.

Example1.htm 

Рисунок 2. Example1.htm

Конечно же, для того что бы можно было запускать скрипт Example1.mq5 он должен быть размещен в каталоге клиентского терминала в подкаталоге \MQL5\Scripts и откомпилирован. Как уже упоминалось, после запуска скрипта файл exdat.txt будет создан в подкаталоге \MQL5\Files, но в нашем примере HTML-файл, файлы библиотек и файл с данными должны находиться в одном каталоге. Поэтому придется скопировать файлы jquery.min.js, highcharts.js и Example1.htm в подкаталог \MQL5\Files или копировать exdat.txt туда, где у нас располагаются эти файлы.

В приведенном примере HTML-страница и библиотеки хранятся в разных файлах. На этапе разработки может оказаться полезным тот факт, что разные части проекта размещены в отдельных файлах. Это поможет избежать, например, случайного изменения кода библиотек при редактировании HTML-файла. Но после того как HTML-страница полностью отредактирована и вносить в нее изменения больше не предполагается, библиотеки могут быть включены непосредственно в код HTML-файла.

Это возможно потому, что JavaScript-библиотеки являются ни чем иным, как просто текстовыми файлами. Если открыть jquery.min.js или highcharts.js текстовым редактором, то ничего вразумительного мы не увидим потому, что исходный текст библиотек был, насколько это возможно, сжат. Сжатие производится за счет удаления служебных символов, например, перевода строки или серии пробелов. После такого сжатия полностью теряется любое форматирование, но текст остается текстом, тип файла не изменяется. Поэтому браузеру совершенно безразлично подключать код библиотеки из внешнего файла с расширением .js или прочитать его из текущего HTML-файла, который в свою очередь тоже является текстовым. Для того что бы объединить файлы заменим в Example1.htm строки

<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>

на

<script type="text/javascript">

</script>

Далее текстовым редактором, например, "Блокнот", откроем файл библиотеки jquery.min.js и, выбрав команду "Выделить все", скопируем содержимое файла. Далее откроем файл Example1.htm, вставим скопированный текст библиотеки между тегами <script type="text/javascript"> и </script>. Сохраним полученный файл под именем Example2.htm. В этот файл таким же образом скопируем содержимое библиотеки highcharts.js,  поместив его между текстом ранее скопированной библиотеки и тегом </script>.

В результате копирования HTML-файл увеличился в размерах, но зато теперь для его корректного отображения не требуется наличия отдельных файлов библиотек. Достаточно в том же каталоге иметь только файл с данными exdat.txt. Каталог \Example2, включающий в себя файлы Example2.htm и exdat.txt находятся в конце статьи в разделе “Файлы”.


Отчет об истории торгового счета в графическом виде

Для более полной демонстрации предложенного способа отображения графической информации создадим отчет отображающий историю торгового счета на заданном интервале времени. В качестве прототипа будет служить HTML-отчет, который создается в терминале MetaTrader 5 при выборе команды "Отчет" контекстного меню вкладки "История". Этот отчет включает в себя большое количество различных показателей сведенных в одну таблицу. Рассчитывая на то, что эти показатели, представленные в виде графиков и диаграмм, будут выглядеть более наглядно, отобразим их при помощи графической библиотеки highcharts.js.

В приведенных ранее примерах при построении графика использовались установки отображения принятые по умолчанию в данной версии библиотеки highcharts.js. Для практических целей обойтись таким вариантом не удастся, в каждом случае придется подстраивать вид графика под индивидуальные конкретные требования. Для этого библиотека highcharts.js предоставляет широкие возможности, располагая большим количеством опций, которые могут быть применены к графику или диаграмме. Как уже упоминалось, список этих опций с их достаточно подробным описанием и примерами можно найти на сайте http://www.highcharts.com/.

Учитывая, что данная статья призвана только предложить и продемонстрировать возможность привлечения WEB-браузера для отображения информации полученной от MetaTrader 5, не будем останавливаться на описании опций графической библиотеки и особенностях их использования. Тем более что в зависимости от конкретных требований при создании WEB-страницы может быть использована какая-нибудь другая JavaScript-библиотека. Заинтересованный читатель может самостоятельно выбрать для себя наиболее подходящую ему библиотеку и углубиться в ее изучение настолько, насколько этого потребует практика ее использования.

Для отображения истории торгового счета был создан файл ProfitReport.htm, он находится в конце статьи в разделе “Файлы”. Вместе с ним в каталоге \Report находится файл data.txt, который содержит отображаемые данные. Файл data.txt помещен в каталог только в качестве примера. Скопировав каталог \Report и открыв файл ProfitReport.htm мы увидим представленные в графическом виде показатели торговли на созданном для данного примера тестовом счете.

ProfitReport.htm

Рисунок 3. ProfitReport.htm

При создании файла ProfitReport.htm сначала была произведена примерная разметка страницы, и было приблизительно определено, где и какая информация будет располагаться. Далее на странице были размещены графики с опциями принятыми по умолчанию. После создания такого шаблона индивидуально для каждого из графиков были подобраны наиболее подходящие опции. После завершения редактирования в страницу простым копированием были включены тексты библиотек. Как уже говорилось, для нормального отображения страницы она должна быть размещена в том же каталоге, что и файл data.txt содержащий предназначенные для отображения данные.

Файл data.txt был создан в MetaTrader 5 при помощи скрипта ProfitReport.mq5. В случае успешного исполнения этого скрипта в каталоге \MQL5\Files создается файл data.txt содержащий значения показателей торговли для активного в данный момент счета. Не следует забывать, что скрипт для его использования должен быть помещен в каталог \MQL5\Scripts и откомпилирован.

//-----------------------------------------------------------------------------------
//                                                                   ProfitReport.mq5
//                                          Copyright 2011, MetaQuotes Software Corp.
//                                                                https://www.mql5.com
//-----------------------------------------------------------------------------------
#property copyright   "Copyright 2011, MetaQuotes Software Corp."
#property link        "https://www.mql5.com"
#property version     "1.00"
#property script_show_inputs

#include <Arrays\ArrayLong.mqh>
#include <Arrays\ArrayDouble.mqh>
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayInt.mqh>

//--- input parameters
input int nD=30;               // Number of days
//--- global
double   balabce_cur=0;        // balance
double   initbalance_cur=0;    // Initial balance (без учета пополнения счета)
int      days_num;             // количество дней в отчете (включая текущий)
datetime tfrom_tim;            // Date from
datetime tend_tim;             // Date to
double   netprofit_cur=0;      // Total Net Profit
double   grossprofit_cur=0;    // Gross Profit
double   grossloss_cur=0;      // Gross Loss
int      totaltrades_num=0;    // Total Trades
int      longtrades_num=0;     // Number of Long Trades
double   longtrades_perc=0;    // % of Long Trades
int      shorttrades_num=0;    // Number of Short Trades
double   shorttrades_perc=0;   // % of Short Trades
int      proftrad_num=0;       // Number of All Profit Trades
double   proftrad_perc=0;      // % of All Profit Trades
int      losstrad_num=0;       // Number of All Loss Trades
double   losstrad_perc=0;      // % of All Loss Trades
int      shortprof_num=0;      // Number of Short Profit Trades
double   shortprof_perc=0;     // % of Short Profit Trades
double   shortloss_perc=0;     // % of Short Loss Trades
int      longprof_num=0;       // Number of Long Profit Trades
double   longprof_perc=0;      // % of Long Profit Trades
double   longloss_perc=0;      // % of Long Loss Trades
int      maxconswins_num=0;    // Number of Maximum consecutive wins
double   maxconswins_cur=0;    // Maximum consecutive wins ($)
int      maxconsloss_num=0;    // Number of Maximum consecutive losses
double   maxconsloss_cur=0;    // Maximum consecutive losses ($)
int      aveconswins_num=0;    // Number of Average consecutive wins
double   aveconswins_cur=0;    // Average consecutive wins ($)
int      aveconsloss_num=0;    // Number of Average consecutive losses
double   aveconsloss_cur=0;    // Average consecutive losses ($)
double   largproftrad_cur=0;   // Largest profit trade
double   averproftrad_cur=0;   // Average profit trade
double   larglosstrad_cur=0;   // Largest loss trade
double   averlosstrad_cur=0;   // Average loss trade
double   profitfactor=0;       // Profit Factor
double   expectpayoff=0;       // Expected Payoff
double   recovfactor=0;        // Recovery Factor
double   sharperatio=0;        // Sharpe Ratio
double   ddownabs_cur=0;       // Balance Drawdown Absolute
double   ddownmax_cur=0;       // Balance Drawdown Maximal
double   ddownmax_perc=0;      // % of Balance Drawdown Maximal
int      symbols_num=0;        // Numbre of Symbols
  
string       Band="";
double       Probab[33],Normal[33];
CArrayLong   TimTrad;
CArrayDouble ValTrad;
CArrayString SymNam;
CArrayInt    nSymb;

//-----------------------------------------------------------------------------------
// Script program start function
//-----------------------------------------------------------------------------------
void OnStart()
  {
  int         i,n,m,k,nwins=0,nloss=0,naverw=0,naverl=0,nw=0,nl=0;
  double      bal,sum,val,p,stdev,vwins=0,vloss=0,averwin=0,averlos=0,pmax=0;
  MqlDateTime dt;
  datetime    ttmp,it;
  string      symb,br;
  ulong       ticket;
  long        dtype,entry;
  
  if(!TerminalInfoInteger(TERMINAL_CONNECTED)){printf("Terminal not connected.");return;}
  days_num=nD;
  if(days_num<1)days_num=1;             // количество дней в отчете (включая текущий)
  tend_tim=TimeCurrent();                                                  // date to
  tfrom_tim=tend_tim-(days_num-1)*86400;
  TimeToStruct(tfrom_tim,dt);
  dt.sec=0; dt.min=0; dt.hour=0;
  tfrom_tim=StructToTime(dt);                                            // date from
//---------------------------------------- Bands
  ttmp=tfrom_tim;
  br="";
  if(dt.day_of_week==6||dt.day_of_week==0)
    {
    Band+=(string)(ulong)(ttmp*1000)+",";
    br=",";ttmp+=86400;
    }
  for(it=ttmp;it<tend_tim;it+=86400)
    {
    TimeToStruct(it,dt);
    if(dt.day_of_week==6){Band+=br+(string)(ulong)(it*1000)+","; br=",";}
    if(dt.day_of_week==1&&br==",") Band+=(string)(ulong)(it*1000);
    }
  if(dt.day_of_week==6||dt.day_of_week==0) Band+=(string)(ulong)(tend_tim*1000);

//----------------------------------------
  balabce_cur=AccountInfoDouble(ACCOUNT_BALANCE);                          // Balance

  if(!HistorySelect(tfrom_tim,tend_tim)){Print("HistorySelect failed");return;}
  n=HistoryDealsTotal();                                           // Number of Deals
  for(i=0;i<n;i++)
    {
    ticket=HistoryDealGetTicket(i);
    entry=HistoryDealGetInteger(ticket,DEAL_ENTRY);
    if(ticket>=0&&(entry==DEAL_ENTRY_OUT||entry==DEAL_ENTRY_INOUT))
      {
      dtype=HistoryDealGetInteger(ticket,DEAL_TYPE);
      if(dtype==DEAL_TYPE_BUY||dtype==DEAL_TYPE_SELL)
        {
        totaltrades_num++;                                            // Total Trades
        val=HistoryDealGetDouble(ticket,DEAL_PROFIT);
        val+=HistoryDealGetDouble(ticket,DEAL_COMMISSION);
        val+=HistoryDealGetDouble(ticket,DEAL_SWAP);
        netprofit_cur+=val;                                       // Total Net Profit
        if(-netprofit_cur>ddownabs_cur)ddownabs_cur=-netprofit_cur; // Balance Drawdown Absolute
        if(netprofit_cur>pmax)pmax=netprofit_cur;
        p=pmax-netprofit_cur;
        if(p>ddownmax_cur)
          {
          ddownmax_cur=p;                                 // Balance Drawdown Maximal
          ddownmax_perc=pmax;
          }
        if(val>=0)              //win
          {
          grossprofit_cur+=val;                                       // Gross Profit 
          proftrad_num++;                                  // Number of Profit Trades
          if(val>largproftrad_cur)largproftrad_cur=val;       // Largest profit trade
          nwins++;vwins+=val;
          if(nwins>=maxconswins_num)
            {
            maxconswins_num=nwins;
            if(vwins>maxconswins_cur)maxconswins_cur=vwins;
            }
          if(vloss>0){averlos+=vloss; nl+=nloss; naverl++;}
          nloss=0;vloss=0;
          }
        else                    //loss
          {
          grossloss_cur-=val;                                           // Gross Loss
          if(-val>larglosstrad_cur)larglosstrad_cur=-val;       // Largest loss trade
          nloss++;vloss-=val;
          if(nloss>=maxconsloss_num)
            {
            maxconsloss_num=nloss;
            if(vloss>maxconsloss_cur)maxconsloss_cur=vloss;
            }
          if(vwins>0){averwin+=vwins; nw+=nwins; naverw++;}
          nwins=0;vwins=0;
          }
        if(dtype==DEAL_TYPE_SELL)
          {
          longtrades_num++;                                  // Number of Long Trades
          if(val>=0)longprof_num++;                   // Number of Long Profit Trades
          }
        else if(val>=0)shortprof_num++;              // Number of Short Profit Trades

        symb=HistoryDealGetString(ticket,DEAL_SYMBOL);                     // Symbols
        k=1;
        for(m=0;m<SymNam.Total();m++)
          {
          if(SymNam.At(m)==symb)
            {
            k=0;
            nSymb.Update(m,nSymb.At(m)+1);
            }
          }
        if(k==1)
          {
          SymNam.Add(symb);
          nSymb.Add(1);
          }
        
        ValTrad.Add(val);
        TimTrad.Add(HistoryDealGetInteger(ticket,DEAL_TIME));
        }
      }
    }
  if(vloss>0){averlos+=vloss; nl+=nloss; naverl++;}
  if(vwins>0){averwin+=vwins; nw+=nwins; naverw++;}
  initbalance_cur=balabce_cur-netprofit_cur;
  if(totaltrades_num>0)
    {
    longtrades_perc=NormalizeDouble((double)longtrades_num/totaltrades_num*100,1);     // % of Long Trades
    shorttrades_num=totaltrades_num-longtrades_num;                                    // Number of Short Trades
    shorttrades_perc=100-longtrades_perc;                                              // % of Short Trades
    proftrad_perc=NormalizeDouble((double)proftrad_num/totaltrades_num*100,1);         // % of Profit Trades
    losstrad_num=totaltrades_num-proftrad_num;                                         // Number of Loss Trades
    losstrad_perc=100-proftrad_perc;                                                   // % of All Loss Trades
    if(shorttrades_num>0)
      {
      shortprof_perc=NormalizeDouble((double)shortprof_num/shorttrades_num*100,1);     // % of Short Profit Trades
      shortloss_perc=100-shortprof_perc;                                               // % of Short Loss Trades
      }
    if(longtrades_num>0)
      {
      longprof_perc=NormalizeDouble((double)longprof_num/longtrades_num*100,1);        // % of Long Profit Trades
      longloss_perc=100-longprof_perc;                                                 // % of Long Loss Trades
      }
    if(grossloss_cur>0)profitfactor=NormalizeDouble(grossprofit_cur/grossloss_cur,2);  // Profit Factor
    if(proftrad_num>0)averproftrad_cur=NormalizeDouble(grossprofit_cur/proftrad_num,2);// Average profit trade
    if(losstrad_num>0)averlosstrad_cur=NormalizeDouble(grossloss_cur/losstrad_num,2);  // Average loss trade
    if(naverw>0)
      {
      aveconswins_num=(int)NormalizeDouble((double)nw/naverw,0);
      aveconswins_cur=NormalizeDouble(averwin/naverw,2);
      }
    if(naverl>0)
      {
      aveconsloss_num=(int)NormalizeDouble((double)nl/naverl,0);
      aveconsloss_cur=NormalizeDouble(averlos/naverl,2);
      }
    p=initbalance_cur+ddownmax_perc;
    if(p!=0)
      {
      ddownmax_perc=NormalizeDouble(ddownmax_cur/p*100,1); // % of Balance Drawdown Maximal
      }
    if(ddownmax_cur>0)recovfactor=NormalizeDouble(netprofit_cur/ddownmax_cur,2); // Recovery Factor

    expectpayoff=netprofit_cur/totaltrades_num;                    // Expected Payoff
    
    sum=0;
    val=balabce_cur;
    for(m=ValTrad.Total()-1;m>=0;m--)
      {
      bal=val-ValTrad.At(m);
      p=val/bal;
      sum+=p;
      val=bal;
      }
    sum=sum/ValTrad.Total();
    stdev=0;
    val=balabce_cur;
    for(m=ValTrad.Total()-1;m>=0;m--)
      {
      bal=val-ValTrad.At(m);
      p=val/bal-sum;
      stdev+=p*p;
      val=bal;
      }
    stdev=MathSqrt(stdev/ValTrad.Total());
    if(stdev>0)sharperatio=NormalizeDouble((sum-1)/stdev,2);    // Sharpe Ratio

    stdev=0;
    for(m=0;m<ValTrad.Total();m++)
      {
      p=ValTrad.At(m)-expectpayoff;
      stdev+=p*p;
      }
    stdev=MathSqrt(stdev/ValTrad.Total());                      // Standard deviation
    if(stdev>0)
      {
      ArrayInitialize(Probab,0.0);
      for(m=0;m<ValTrad.Total();m++)                                     // Histogram
        {
        i=16+(int)NormalizeDouble((ValTrad.At(m)-expectpayoff)/stdev,0);
        if(i>=0 && i<ArraySize(Probab))Probab[i]++;
        }
      for(m=0;m<ArraySize(Probab);m++) Probab[m]=NormalizeDouble(Probab[m]/totaltrades_num,5);
      }
    expectpayoff=NormalizeDouble(expectpayoff,2);                  // Expected Payoff  
    k=0;
    symbols_num=SymNam.Total();                                            // Symbols
    for(m=0;m<(6-symbols_num);m++)
      {
      if(k==0)
        {
        k=1;
        SymNam.Insert("",0);
        nSymb.Insert(0,0);
        }
      else
        {
        k=1;
        SymNam.Add("");
        nSymb.Add(0);
        }
      }
    }
  p=1.0/MathSqrt(2*M_PI)/4.0;
  for(m=0;m<ArraySize(Normal);m++)                             // Normal distribution
    {
    val=(double)m/4.0-4;
    Normal[m]=NormalizeDouble(p*MathExp(-val*val/2),5);
    }

  filesave();
  }
//-----------------------------------------------------------------------------------
// Save file
//-----------------------------------------------------------------------------------
void filesave()
  {
  int n,fhandle;
  string loginame,str="",br="";
  double sum;
  
  ResetLastError();
  fhandle=FileOpen("data.txt",FILE_WRITE|FILE_TXT|FILE_ANSI);
  if(fhandle<0){Print("File open failed, error ",GetLastError());return;}
  
  loginame="\""+(string)AccountInfoInteger(ACCOUNT_LOGIN)+", "+
                        TerminalInfoString(TERMINAL_COMPANY)+"\"";
  str+="var PName="+loginame+";\n";
  str+="var Currency=\""+AccountInfoString(ACCOUNT_CURRENCY)+"\";\n";
  str+="var Balance="+(string)balabce_cur+";\n";
  str+="var IniBalance="+(string)initbalance_cur+";\n";
  str+="var nDays="+(string)days_num+";\n";
  str+="var T1="+(string)(ulong)(tfrom_tim*1000)+";\n";
  str+="var T2="+(string)(ulong)(tend_tim*1000)+";\n";
  str+="var NetProf="+DoubleToString(netprofit_cur,2)+";\n";
  str+="var GrossProf="+DoubleToString(grossprofit_cur,2)+";\n";
  str+="var GrossLoss="+DoubleToString(grossloss_cur,2)+";\n";
  str+="var TotalTrad="+(string)totaltrades_num+";\n";
  str+="var NProfTrad="+(string)proftrad_num+";\n";
  str+="var ProfTrad="+DoubleToString(proftrad_perc,1)+";\n";
  str+="var NLossTrad="+(string)losstrad_num+";\n";
  str+="var LossTrad="+DoubleToString(losstrad_perc,1)+";\n";
  str+="var NLongTrad="+(string)longtrades_num+";\n";
  str+="var LongTrad="+DoubleToString(longtrades_perc,1)+";\n";
  str+="var NShortTrad="+(string)shorttrades_num+";\n";
  str+="var ShortTrad="+DoubleToString(shorttrades_perc,1)+";\n";
  str+="var ProfLong ="+DoubleToString(longprof_perc,1)+";\n";
  str+="var LossLong ="+DoubleToString(longloss_perc,1)+";\n";
  FileWriteString(fhandle,str); str="";
  str+="var ProfShort="+DoubleToString(shortprof_perc,1)+";\n";
  str+="var LossShort="+DoubleToString(shortloss_perc,1)+";\n";
  str+="var ProfFact="+DoubleToString(profitfactor,2)+";\n";
  str+="var LargProfTrad="+DoubleToString(largproftrad_cur,2)+";\n";
  str+="var AverProfTrad="+DoubleToString(averproftrad_cur,2)+";\n";
  str+="var LargLosTrad="+DoubleToString(larglosstrad_cur,2)+";\n";
  str+="var AverLosTrad="+DoubleToString(averlosstrad_cur,2)+";\n";
  str+="var NMaxConsWin="+(string)maxconswins_num+";\n";
  str+="var MaxConsWin="+DoubleToString(maxconswins_cur,2)+";\n";
  str+="var NMaxConsLos="+(string)maxconsloss_num+";\n";
  str+="var MaxConsLos="+DoubleToString(maxconsloss_cur,2)+";\n";
  str+="var NAveConsWin="+(string)aveconswins_num+";\n";
  str+="var AveConsWin="+DoubleToString(aveconswins_cur,2)+";\n";
  str+="var NAveConsLos="+(string)aveconsloss_num+";\n";
  str+="var AveConsLos="+DoubleToString(aveconsloss_cur,2)+";\n";
  str+="var ExpPayoff="+DoubleToString(expectpayoff,2)+";\n";
  str+="var AbsDD="+DoubleToString(ddownabs_cur,2)+";\n";
  str+="var MaxDD="+DoubleToString(ddownmax_cur,2)+";\n";
  str+="var RelDD="+DoubleToString(ddownmax_perc,1)+";\n";
  str+="var RecFact="+DoubleToString(recovfactor,2)+";\n";
  str+="var Sharpe="+DoubleToString(sharperatio,2)+";\n";
  str+="var nSymbols="+(string)symbols_num+";\n";
  FileWriteString(fhandle,str);

  str="";br="";
  for(n=0;n<ArraySize(Normal);n++)
    {
    str+=br+"["+DoubleToString(((double)n-16)/4.0,2)+","+DoubleToString(Normal[n],5)+"]";
    br=",";
    }
  FileWriteString(fhandle,"var Normal=["+str+"];\n");

  str="";
  str="[-4.25,0]";
  for(n=0;n<ArraySize(Probab);n++)
    {
    if(Probab[n]>0)
      {
      str+=",["+DoubleToString(((double)n-16)/4.0,2)+","+DoubleToString(Probab[n],5)+"]";
      }
    }
  str+=",[4.25,0]";
  FileWriteString(fhandle,"var Probab=["+str+"];\n");

  str=""; sum=0;
  if(ValTrad.Total()>0)
    {
    sum+=ValTrad.At(0);
    str+="["+(string)(ulong)(TimTrad.At(0)*1000)+","+DoubleToString(sum,2)+"]";
    for(n=1;n<ValTrad.Total();n++)
      {
      sum+=ValTrad.At(n);
      str+=",["+(string)(ulong)(TimTrad.At(n)*1000)+","+DoubleToString(sum,2)+"]";
      }
    }
  FileWriteString(fhandle,"var Prof=["+str+"];\n");
  FileWriteString(fhandle,"var Band=["+Band+"];\n");

  str="";br="";
  for(n=0;n<SymNam.Total();n++)
    {
    str+=br+"{name:\'"+SymNam.At(n)+"\',data:["+(string)nSymb.At(n)+"]}";
    br=",";
    }
  FileWriteString(fhandle,"var Sym=["+str+"];\n");

  FileClose(fhandle);
  }

Как видим, код скрипта оказался достаточно громоздким, но это связано не со сложностью задачи, а просто с большим количеством показателей торговли, значение которых необходимо определить. Для хранения этих значений в начале скрипта объявлены снабженные соответствующими комментариями глобальные переменные.

В функции OnStart() проверяется, подключен ли терминал к торговому серверу, если нет, то скрипт завершает свою работу. Так как при отсутствии подключения к серверу невозможно будет определить активный счет и получить информацию о нем.

Следующим шагом вычисляется дата, начиная с которой данные о торговле на текущем активном счете будут включены в отчет. В качестве конечной даты принимается значение текущей даты и текущего времени на момент исполнения скрипта. Количество дней, включенных в отчет можно задать при загрузке скрипта изменив значение входного параметра “Number of days”, равного по умолчанию 30 дням. После того как определено время начала и окончания отчета в строковой переменной Band формируются пары значений времени, соответствующие началу и окончанию выходных дней. Эта информация используется для того, чтобы на графике баланса интервалы времени, соответствующие субботе и воскресению, можно было пометить желтым цветом.

Далее при помощи функции HistorySelect() делается доступной история сделок и ордеров за указанный интервал и вызовом функции HistoryDealsTotal() определяется количество сделок в истории. После этого по количеству сделок организован цикл, в котором собирается статистика, необходимая для вычисления показателей торговли, и по окончанию цикла определяются их значения.

При создании скрипта ставилась задача сохранить смысл показателей торговли в соответствии с отчетом, генерируемым в терминале MetaTrader 5. Предполагается, что показатели, определяемые скриптом, должны соответствовать описанию, которое приведено в файле справки к терминалу.

Информацию по организации доступа к истории счета и вычислению торговых показателей можно найти в следующих статьях:

Большинство показателей вычисляются достаточно просто, поэтому в данной статье не будем рассматривать операции, связанные с вычислением каждого из них, и в дальнейшем рассмотрим только имеющиеся отличия от стандартного отчета и дополнения к нему.

В отчете, который генерируется терминалом, график баланса строится последовательным отображением значений при каждом его изменении, а на шкале Х отражено количество таких изменений. В нашем случае для построения графика используется шкала времени.

Поэтому построенный нами график профита на вид очень сильно отличается от графика, который генерируется терминалом. Выбор именно такого варианта построения графика был сделан для того, чтобы отобразить моменты закрытия позиций на реальной шкале времени. То есть чтобы было видно, когда на протяжении отчетного периода возрастала или спадала торговая активность.

При построении графика необходимо помнить, что MQL5 оперирует значением даты, представленном в виде количества секунд, прошедших с 01 января 1970 года, а графической библиотеке требуется это значение в виде количества миллисекунд, прошедших с 01 января 1970 года. Поэтому полученные в скрипте значения даты, для их корректного отображения на графике, необходимо умножать на тысячу.

Для хранения значения профита и времени закрытия сделки в скрипте используются классы CArrayDouble и CArrayLong из состава стандартной библиотеки. Каждый раз при обнаружении в теле цикла результативной сделки, информация о ней помещается при помощи метода Add() в элемент, добавляемый в конец массива. Это позволило не определять заранее требуемое количество элементов, размер массива просто увеличивается с увеличением количества обнаруженных в истории сделок.

Для каждой сделки проверяется, на каком символе она была осуществлена, при этом сохраняется имя символа и количество совершенных на нем сделок. Так же как и для графика профита, эти данные при просмотре истории накапливаются путем записи в добавляемый в конец массива элемент. Для хранения имени символа и количества сделок используются классы CArrayString и CArrayInt стандартной библиотеки.

Если на текущем счете сделки осуществлялись только по одному символу, то отображаемый на диаграмме единственный столбец будет слишком широким. Что бы избежать этого передаваемый для отображения массив данных всегда содержит не менее 7 элементов. Неиспользуемые элементы на диаграмме не отображаются, так как они содержат нулевые значения, но при этом не позволяют столбцу стать слишком широким. Для того что бы при малом количестве символов столбцы диаграммы располагались примерно посередине оси X, незначащие элементы массива поочередно вставляются то в его начало, то в конец.

Следующим отличием от стандартного отчета является попытка построения графика распределения вероятностей для последовательности значений профита по каждой из сделок.

Плотность вероятности

Рисунок 4. Плотность вероятности

Чаще всего такой график бывает представлен в виде гистограммы выборки. В нашем случае график плотности вероятности создается путем построения сплайна по имеющимся значениям столбцов такой гистограммы. Вычисленные значения оценки плотности вероятности дополняются слева и справа за пределами графика нулевыми значениями. Это необходимо для того что бы построенный сплайном график не прерывался на последнем известном значении, а продолжался за пределы графика спадая к нулю.

Для сравнения на графике плотности вероятности серым цветом выводится график нормального распределения, нормированный таким образом, что бы сумма представляющих его отсчетов была равна единице, так же как и у графика, построенного по значениям гистограммы. В приведенном примере отчета количества сделок явно недостаточно для более или менее достоверной оценки распределения вероятностей значений профита сделок. Можно предположить, что при большем количестве сделок в истории этот график будет выглядеть более достоверным.

После того, как все показатели торговли определены, в конце скрипта вызывается функция filesave(). В этой функции открывается на запись файл data.txt и в него записываются в текстовом виде имена переменных и их значения. Значения этих переменных соответствуют вычисленным показателям, а их имена соответствуют именам, которые используются в HTML-файле при передаче параметров функциям графической библиотеки. Для того, что бы при записи файла сократить количество обращений к диску, короткие строки объединяются в одну более длинную строку, и только потом происходит ее запись в файл. Файл data.txt, как это принято в MetaTrader 5, создается в каталоге MQL5\Files; в случае если такой файл уже существует, то он будет перезаписан. Для удобства в этот же каталог можно скопировать файл ProfitReport.htm и оттуда запускать его для просмотра.

В терминале MetaTrader 5 при сохранении отчета в формате HTML он автоматически открывается браузером, зарегистрированным в системе как браузер по умолчанию. Такая возможность не была реализована в приведенном в статье примере. Для того что бы добавить автозапуск необходимо в начале скрипта ProfitReport.mq5 вставить строки

#import "shell32.dll"
int ShellExecuteW(int hwnd,string lpOperation,string lpFile,string lpParameters,
                  string lpDirectory,int nShowCmd);
#import

а в конце, после вызова функции filesave(), добавить

string path=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\ProfitReport.htm";
ShellExecuteW(NULL,"open",path,NULL,NULL,1);

Если по указанному в переменной path пути существует файл ProfitReport.htm, то при вызове функции ShellExecuteW() он будет открыт браузером. Функция ShellExecuteW() находится в системной библиотеке shell32.dll, поэтому для обеспечения доступа к ней в начале файла добавлено объявление этой функции. Для того чтобы такой автозапуск срабатывал необходимо разрешить в терминале импорт функций из внешних dll, так как по умолчанию использование внешних библиотек запрещено.

Заключение

Использование WEB-браузера позволяет отображать на экране одновременно достаточно много разнообразной информации, что может оказаться полезным, например, для организации визуального контроля за внутренним состоянием отдельных модулей работающего в терминале эксперта. На экране в удобной форме может быть одновременно представлена информация о состоянии модуля управления капиталом, модулей генерирующих торговые сигналы, модуля сопровождения торговой позиции и так далее. В случае, когда информации, которую необходимо отобразить, оказывается слишком много, можно использовать многостраничные HTML-отчеты.

Следует отметить, что возможности языка JavaScript значительно шире, чем просто рисование графиков, с его помощью отображаемую WEB-страницу можно сделать по-настоящему интерактивной. В Интернете можно найти большое количество включаемых в WEB-страницу готовых JavaScript-кодов и различных примеров использования этого языка. Например, если при помощи JavaScript между терминалом и браузером удастся организовать двухсторонний обмен данными, то можно будет непосредственно из окна браузера подавать команды терминалу.

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

Файлы

JS_Lib.zip           - файлы библиотек highcharts.js и jquery.min.js
Test.zip              - файлы highcharts.js, jquery.min.js и Test_01.htm
Example1.zip       - файлы highcharts.js, jquery.min.js, Example1.htm, Example1.mq5 и exdat.txt
Example2.zip       - файлы Example2.htm и exdat.txt
Report.zip           - файлы ProfitReport.htm и data.txt
ProfitReport.mq5 - Скрипт для сбора статистики и создания файл data.txt

Прикрепленные файлы |
js_lib.zip (53.99 KB)
test.zip (54.53 KB)
example1.zip (55.31 KB)
example2.zip (54.3 KB)
report.zip (57.25 KB)
profitreport.mq5 (16.53 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (15)
Denis Kirichenko
Denis Kirichenko | 21 янв. 2011 в 14:20

Вот код data-from-csv.htm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
        
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

 <title>Highcharts Example</title>


<!-- 1. Add these JavaScript inclusions in the head of your page -->

 
 <script src="jquery.min.js" type="text/javascript"></script>
 <script src="highcharts.js" type="text/javascript"></script>
<!-- - -->              



<!-- 2. Add the JavaScript to initialize the chart on document ready -->
                
 
 <script type="text/javascript">
                

$(document).ready(function() {
        
  var options = {

        chart: {
          renderTo: 'container',
          defaultSeriesType: 'column'
        },
        title: {
          text: 'Autocorrelation'
        },
        xAxis: {

          categories: []
                                
        },
        yAxis: {
          title: {
            text: 'Units'
          }
        },
        series: []
        };
                        
                        
/*
                         Load the data from the CSV file. */            

                        
$.get('data.csv', function(data) {
                                
 // Split the lines
                                
 var lines = data.split('\n');
                                
 $.each(lines, function(lineNo, line) {
                                        
   var items = line.split(',');
                                        
                                        
   // header line containes categories
                                        
   if (lineNo == 0) {
                                                
     $.each(items, function(itemNo, item) {
                                                        
       if (itemNo > 0) options.xAxis.categories.push(item);
                                                
    });
                                        }
                                        
                                        
// the rest of the lines contain data with their name in the first position
                
else {
                                                
var series = { 
                                                        
data: []
                                                
};
                                                
$.each(items, function(itemNo, item) {
                
if (itemNo == 0) {
                
series.name = item;
                                                        
} else {

series.data.push(parseFloat(item));
        
}
                                                
});
                                        
options.series.push(series);

                                        
}
                                        
                                
});
                                
                                
var chart = new Highcharts.Chart(options);
                        
});
});
                
</script>
                
        
</head>
        <body>
                
                
<!-- 3. Add the container -->
                
<div id="container" style="width: 800px; height: 400px; margin: 0 auto"></div>
        
</body>
</html>

А вот файл данных data.csv:

Categories,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21
ACF,0.0048,-0.0084,-0.0094,-0.0080,-0.0037,-0.0067,0.0052,-0.0018,0.0066,0.0267,-0.0210,0.0013,0.0032,-0.0027,0.0207,-0.0059,-0.0131,0.0160,0.0250,-0.0077
Bounds,0.0073,-0.0073,-0.0073,-0.0073,-0.0073,-0.0073,0.0073,-0.0073,0.0073,0.0073,-0.0073,0.0073,0.0073,-0.0073,0.0073,-0.0073,-0.0073,0.0073,0.0073,-0.0073

Файлы библиотек не прикладываю.

Denis Kirichenko
Denis Kirichenko | 31 янв. 2011 в 17:59

Спасибо за "помощь": как обычно, никто не помог, сам разобрался :-)

Вопрос к автору, а есть ли что-то подобное для 3D графиков?


Гребенев Вячеслав
Гребенев Вячеслав | 21 февр. 2011 в 14:29

Да уж. Графическое представление информации в МТ5 слабовато. А сколько всякого интересного можно нарисовать!: графики корреляций всего и вся, динамическое отображение текущего курса через разные вейвлет преобразования, 3D и чёрт знает что ещё. Так и хочется залепенить какой-нить яркий скрин сейвер по полухаотичным корреляциям остатков рядов разных курсов!

Особенно плохо с графикой в тестере стратегий. Даже экспорт в текстовый файл результатов тестера толком не сделан.

 Кстати, раз уж всё равно экспортировать данные в файл, то лучше потом не изобретать свою графику, а воспользоваться готовыми пакетами винниграфикс, сигмаплот, ориджин или эксель.

Особенно порадовал венец статьи - функция рапределения вероятностей. Тянется народ к разумному исследованию курса. Это радует.  

Иван
Иван | 30 окт. 2012 в 08:45

Не могу понять где можно скачать файлы, которые по идее приложены к статье? Названия файлов есть, а ссылок в них нет:

Файлы

JS_Lib.zip           - файлы библиотек highcharts.js и jquery.min.js
Test.zip              - файлы highcharts.js, jquery.min.js и Test_01.htm
Example1.zip       - файлы highcharts.js, jquery.min.js, Example1.htm, Example1.mq5 и exdat.txt
Example2.zip       - файлы Example2.htm и exdat.txt
Report.zip           - файлы ProfitReport.htm и data.txt
ProfitReport.mq5 - Скрипт для сбора статистики и создания файл data.txt

Алексей Ванин
Алексей Ванин | 16 сент. 2020 в 15:21
В своей работе web программиста использую библиотеку FusionCharts. 
Мне нравиться простая установка диаграмм и графиков по шаблону. 
1. Подключаю Java Script библиотеку FusionCharts. 
2. Создаю DIV для вывода графика (id="chart_container"). 
3. Вставляю данные графика в массив chartData. 
4. Редактирую массив chartConfig. Это дизайн и параметры диаграммы. 
5. Вызываю функцию FusionCharts.ready(function(){ var fusioncharts = new FusionCharts(chartConfig);fusioncharts.render(); }); 
Подробный код и демонстрация примера: http://profi.spage.me/jquery/creation-of-graphs-chart-and-diagrams-on-java-script
Подключение нейросетей от NeuroSolutions Подключение нейросетей от NeuroSolutions
Программный пакет NeuroSolutions позволяет не только создавать нейронные сети, но и экспортировать их в DLL. В статье описан процесс создания нейросети, генерации DLL и ее подключения к советнику для торговли в MetaTrader.
Эконометрический подход к анализу графиков Эконометрический подход к анализу графиков
В данной статье рассматриваются эконометрические методы исследования, в частности автокорреляционный анализ и анализ условной дисперсии. Что нам даёт описанный в статье подход? Применение нелинейной GARCH-модели позволяет, во-первых, формально представить исследуемый ряд с математической точки зрения, а во-вторых, создать прогноз на заданное количество шагов.
Мастер MQL5: Как написать свой модуль сопровождения открытых позиций Мастер MQL5: Как написать свой модуль сопровождения открытых позиций
Генератор торговых стратегий Мастера MQL5 значительно упрощает проверку торговых идей. В статье рассказывается о том, как написать и подключить в Мастер MQL5 свой собственный модуль управления открытыми позициями, устанавливающий уровень Stop Loss в безубыток при движении цены в благоприятном направлении, что позволяет защитить прибыль и уменьшить потери. Рассматривается структура и формат описания созданного класса для Мастера MQL5.
Собери свой торговый советник в Мастере MQL5 Собери свой торговый советник в Мастере MQL5
Знание языков программирования теперь не является обязательным условием для создания торговых роботов. Если раньше это действительно служило непроходимым препятствием для реализации своих торговых стратегий, то появление Мастера MQL5 в корне изменило ситуацию. Начинающие трейдеры могут перестать тревожиться из-за отсутствия опыта программирования - с новым визардом, позволяющим быстро генерировать код советника, он не понадобится.