English 中文 Español Deutsch 日本語 Português
MT4TerminalSync - система синхронизации терминалов MetaTrader 4

MT4TerminalSync - система синхронизации терминалов MetaTrader 4

MetaTrader 4Примеры | 6 июля 2007, 10:38
3 021 5
Valery V. Chesnokov
Valery V. Chesnokov

Введение

Многие трейдеры и разработчики торговых систем для технических целей имеют несколько копий терминалов MetaTrader 4. На них открыты разные графики, разные счета, проверяются разные стратегии. При этом периодически выходят новые версии терминала, появляются новые индикаторы, советники, другой MQL код.

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



На кого рассчитана эта статья

В статье рассмотрено создание примера программной системы для синхронизации нескольких копий терминалов.

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



Необходимость системы синхронизации терминалов

Допустим, у вас восемь копий терминалов. Вы ставите новую вышедшую версию. Как? По очереди нажимаете восемь раз на скачанный файл https://www.mql4.com/ files/mt4setup.exe и указываете ему ваши папки, в которых установлены копии? Хорошо, это несложно.

Далее, вы разработали три новых индикатора, два эксперта и одну библиотеку. Вам нужно проверить их в разных ситуациях на тех же восьми копиях терминалов. Значит, исходные MQL и бинарные ex4 файлы нужно также обновить. Вы вели эти разработки в одной, исходной копии терминала. Нужно тиражировать их в остальные копии. Вы открываете по очереди подпапки исходного терминала: experts, затем experts\indicators и experts\libraries. В каждой из них в Проводнике Windows копируете нужные файлы, далее открываете в каждой обновляемой копии терминала такую же папку и копируете в неё нужные файлы. И повторяете этот двойной цикл для каждой исходной подпапки и каждой аналогичной подпапки обновляемого терминала.

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

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



Технические условия

Данная статья создана по тематике: "Расширение возможностей MQL4 - программ путем использования функций операционных систем, а также других средств разработки программ". Поэтому сразу укажу, что используемые в ней инструменты выходят за рамки терминала MetaTrader 4 и языка MQL.

Созданная и описываемая система синхронизации копий терминалов требует для своей работы следующие программные средства:
1. Операционная система - Microsoft Windows 2000 SP4 или выше: Microsoft Windows 2000, Windows XP, Windows Server 2003, Windows Server 2003 R2, Windows Vista.
2. Платформа Microsoft .NET Framework 2.0. Её можно скачать с страницы сайта Microsoft:
2.1. http://www.microsoft.com/downloads/details.aspx?displaylang=ru&FamilyID=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5 - русскоязычный (RUS) дистрибутив для x86 процессоров, файл dotnetfx.exe размером 22 Мб.
2.2. http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5 - англоязычный (EN) дистрибутив для x86 процессоров, файл dotnetfx.exe размером 22 Мб.
2.3. http://www.microsoft.com/downloads/details.aspx?familyid=B44A0000-ACF8-4FA1-AFFB-40E78D788B00&displaylang=en - англоязычный (EN) дистрибутив для x64 процессоров, файл NetFx64.exe размером 45 Мб.
3. Настольный однопользовательский сервер баз данных Microsoft SQL Server 2005 Compact Edition. Эта редакция SQL сервера состоит буквально из восьми dll файлов, и может быть скачена с страницы http://www.microsoft.com/downloads/details.aspx?FamilyId=%2085E0C3CE-3FA1-453A-8CE9-AF6CA20946C3&displaylang=en - файл SQLServerCE31-EN.msi размером 1,7 Мб. Подробнее об этой системе можно прочитать в статье MSDN "Установка SQL Server Compact Edition на настольных и планшетных компьютерах" по адресу http://technet.microsoft.com/ru-ru/library/bb190958.aspx (RUS).

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

Если вы хотите попробовать создать подобную систему с применением указанных в статье технологий, вам понадобится среда разработки Microsoft Visual Studio 2005, например, одна из бесплатных редакций Visual Studio 2005 Express Editions для языка C# или VB.NET. Скачать версии Microsoft® Visual Studio® 2005 Express Editions Service Pack 1 можно со страницы http://www.microsoft.com/downloads/details.aspx?FamilyId=7B0B0339-613A-46E6-AB4D-080D4D4A8C4E&displaylang=en. Вы можете заказать ознакомительные (триальные) версии Visual Studio 2005 с страницы http://www.microsoft.com/emea/msdn/visualstudio/ruru/getthetrials/. Или же использовать более новую версию Visual Studio "Orcas", которая на момент написания статьи существует в виде редакции Beta 1. Её предварительное название Orcas может перейти в Visual Studio 2008. Об актуальной версии Visual Studio следующего поколения вы можете узнать на странице http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx.

Установка Microsoft .NET 2.0 и SQL Compact Edition при наличии двух нужных файлов (dotnetfx.exe и SQLServerCE31-EN.msi для x86 версий Windows) занимает не более двух-трёх минут и не представляет собой ничего сложного. Нужно скачать файл, и щёлкнуть по нему мышью, нажимая кнопки Далее (Next) и Готово (Finish).



Состав системы

Кроме указанных выше сторонних программных продуктов, собственно система синхронизации состоит из множества файлов, показанных ниже.

В ней .exe и .dll файлы являются бинарным исполняемым кодом, файл config.xml является файлом настройки оболочки запуска (о нём подробнее ниже), файл MT4TerminalSync.sdf - это вся база данных системы, и файл Log. txt содержит записи об ошибках, возникавших при работе системы.

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

Устанавливать саму систему синхронизации не нужно. Достаточно поставить перечисленные выше сторонние продукты, и скопировать файлы системы в папку на локальном жёстком диске.



Идеология создаваемой системы

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

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

1. Настройки системы (пути к исходному/конечным терминалам, расширения файлов) придётся «зашивать» прямо в исходные тексты скриптов. Или писать свой парсер (анализатор) некоего .ini файла.
2. Контроля ошибок копирования файлов практически не будет. Узнать, были ли ошибки при копировании командами типа xcopy довольно сложно, и собрать их в один доступный для просмотра вид тоже не просто.

В итоге мною было принято решение создать скомпилированную систему с хранением всех настроек в базе данных для максимальной гибкости решения. Для создания системы я предпочёл использовать знакомые мне технологии разработки от Microsoft. Именно в этих рамках и происходил дальнейший выбор инструментов.



Описание базы данных системы

Для хранения параметров системы (пути, маски файлов и т.д.) можно использовать разные варианты: записать всё в код программы, использовать текстовый ini файл, XML файл или СУБД. Я выбрал последний вариант, чтобы использовать возможности промышленных реляционных баз данных (СУБД) и не изобретать свои собственные методы.

Какую СУБД выбрать? Я исходил из двух критериев:
1. Возможно, что систему будут применять как корпоративный инструмент, т.е. это будет сетевая многопользовательская система. Значит, мы можем взять в качестве базы файл Microsoft Access или SQL сервер. Однако Access может быть установлен не у каждого пользователя, поскольку он входит в версию Microsoft Office Professional Edition.
2. Систему будут использовать и индивидуальные пользователи. Значит, нужно уменьшить размер всей системы и упростить процесс развёртывания. С этой точки зрения у SQL сервера есть бесплатные редакции: Express Edition и Compact Edition. Для минимизации размера я выбрал редакцию SQL Server 2005 Compact Edition. Её установка занимает всего 1,7 Мб в одном файле.

Именно редакция сервера SQL 2005 Compact Edition позволяет совместить в себе эти критерии - это настольная компактная для скачивания версия СУБД, которая тем не менее демонстрирует все требуемые возможности при переходе на корпоративную сетевую версию системы синхронизации. Для этого достаточно воссоздать базу данных на более мощной редакции SQL сервера 2005 - любой, начиная с Express Edition.

С выбором базы данных определились. Теперь что мы будем хранить?

Замечание: для понимания следующего раздела вам могут понадобиться знания о языке SQL - Structured Query Language, язык структурированных запросов к базам данных. Подробнее об этом языке можно прочитать на ресурсе Википедии https://ru.wikipedia.org/wiki/SQL.

Приведём на рисунке ниже снимок экрана с таблицами и полями используемой нами SQL базы данных.

Эти таблицы хранят информацию о следующих параметрах системы:
1. Таблица CopyExtentions - маски копируемых файлов, возможно с относительными путями. Примеры: *.ini, experts\*.mq?, experts\indicators\*.ex4.
2. Таблица DestiantionTerminal - абсолютные пути к терминалам для обновления. Эти копии терминалов будут обновляться с шаблона - исходной, контрольной копии терминала. Для каждого профиля пользователя (смотрите таблицу UserProfile) множество терминалов своё.
3. Таблица SourceTerminal - абсолютный путь к исходной копии терминала. Это терминал-источник, контрольный шаблон для обновления с него копий терминала из таблицы DestiantionTerminal. Для каждого пользователя исходный терминал - свой.
4. Таблица UserProfile - список пользователей (профилей пользователей) системы. Это элемент проектирования многопользовательской системы, где каждый пользователь хранит свои настройки путей терминалов с привязкой к своему профилю. Для индивидуального пользователя в различных профилях можно хранить логически сгруппированные множества терминалов. Например, вы можете разбить их на две группы, одну часто обновляемую, вторую - редко. Переключаясь между профилями, вы будете управлять, какую группу стоит обновить. Лишние профили можно блокировать. Если не блокированный профиль в системе будет один, он автоматически будет выбираться в клиентской части системы как активный.

Поскольку на показанном выше рисунке не видно детальной схемы таблиц базы данных, ниже покажем рисунки SQL таблиц с типами полей. В редакции Compact Edition, к сожалению, нет возможности показать диаграмму базы данных, поэтому каждая таблица будет отображена отдельно.

Ниже показана схема таблицы CopyExtentions:

Ниже показана схема таблицы DestinationTerminal:

Ниже показана схема таблицы SourceTerminal:

Ниже показана схема таблицы UserProfile:

Таким образом, схемы всех таблиц базы данных детально показаны на рисунках выше.



Идеология разработки клиентской части системы

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

Клиентская часть представляет собой .NET приложение вида Windows Forms, т.е. так называемый "толстый" exe-клиент. Клиента устанавливать не надо, просто скопируйте все его файлы в одну папку на локальном жёстком диске.

Я опишу кратко свою идеологию создания подобных систем.
Я считаю, что подобные клиентские системы нужно создавать по модульному принципу. Преимуществ как минимум два:
1. Из модулей, как из кирпичиков, собирается одно, единое конечное приложение с любыми требуемыми функциями. Пользователям нет нужды запускать десять разных программ, он запускает всегда одну, которая содержит все нужные ему функции. Список модулей можно настроить под каждого пользователя системы отдельно, согласно его полномочиям.
2. Модульный принцип разработки позволяет масштабировать сам процесс разбработки систем, т.е. привлекать большее число разработчиков при увеличении объёма разработки.

Что конкретно я предлагаю? Мною был в своё время сделан каркас для запуска .NET модулей - приложение-оболочка класса Windows Forms для загрузки .NET сборок (сборка - assembly) и активации .NET компонентов (компонент - User Control), т.е. технически любого класса, порождённого от стандартного .NET 1.1 или 2.0 класса System.Windows.Forms.UserControl.

Оболочка управляется содержимым XML файла config.xml, лежащим в той же папке. Ниже на рисунке показано, как выглядит эта оболочка.

Её преимущество, как мне кажется, состоит в широком выборе языков программирования и сред разработки (IDE). По сути это любые .NET совместимые IDE для версий .NET Framework 1.1 и 2.0, такие, как Borland Developer Studio 2006 (BDS) под .NET 1.1, Microsoft Visual Studio .NET 2003 под .NET 1.1, Microsoft Visual Studio 2005 под .NET 2.0, Visual Studio Orcas под .NET 2.0.

Из стандартных языков программирования - C# и VB.NET, хотя подойдёт любой CLR-совместимый язык, способный создать проект вида Windows Control Library и User Control в нём.

Ниже показан пример работы компонента, созданного в Visual Studio .NET 2003 и загруженного в оболочку.

Ещё для примера показан компонент, созданный в Visual Studio Orcas March 2007 CTP.

Итак, с методикой разработки клиентской части мы разобрались, приступим к её созданию.



Клиентская часть системы

Используем Microsoft Visual Studio 2005 для разработки компонентов системы синхронизации.
Создаём проект вида Windows Control Library.

Все компоненты системы (user controls) будут находится в одном, данном проекте. Физически результатом будет файл MT4TSyncUCLib.dll в папке проекта, содержащий бинарный код компонентов. Пополним проект соответствующими программными компонентами.

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

Это ресурсы проекта, также компоненты для каждой сущности системы, хранящейся в SQL базе данных: исходный терминал, множество конечных терминалов, множество масок копируемых файлов и компонент собственно выполнения синхронизации. Также в проекте созданы классы для каждой из перечисленных выше сущностей, для процесса передачи данных и их редактирования в стандартном компоненте PropertyGrid (таблица с свойствами).

Замечание: в рамках данной статьи не ставится цель подробного обучения процессу разработки программных систем. Поэтому для клиентской части будут описаны и показаны контрольные точки - готовые модули, вошедшие в систему.

Конфигурационный XML файл config.xml, описывающий все видимые компоненты системы, показан ниже.

Как видно из содержания файла config.xml, я разбил пользовательское меню системы на два раздела: собственно запуск синхронизации и административная часть по настройке системы. Это деление чисто условное и может быть переделано даже самим пользователем по вкусу, если вам под силу отредактировать текстовый XML файл, не разрушив в нём ключевую информацию. Для этого нужно найти тег <menu>, зайти в раздел <items> и просто переставлять местами теги <item> с атрибутом type="folder" (папка) и type="control" (конечный пользовательский компонент).
В системе создано два пользовательских профиля меню - один полный, со всеми компонентами, названный "Администратор (всё)", и второй краткий, с именем "Запуск синхронизации", только с компонентом запуска.

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

При запуске системы нужно выбрать профиль меню, один из двух: полный или упрощённый.

Далее, на рисунке показан компонент управления пользователями.

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

Ниже показан компонент редактирования масок копируемых файлов.

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

Здесь стоит обратить внимание на логическое поле Включая подпапки, которое я сделал, чтобы упростить процесс настройки системы. Дело в том, что, например, файлы *.mq4 и *.ex4 встречаются в терминале в разных подпапках - experts, experts\indicators и т.д. Чтобы не добавлять каждую подпапку, проще указать одну запись от корня папки терминала, т.е. без относительного пути, и включить признак поиска в подпапках. Система сама пройдётся по всем подпапкам исходного терминала и скопирует файлы с такой маской в нужную конечную подпапку.

И ещё одна "военная хитрость". Обратите внимание на сами маски. В терминале есть файлы с расширениями mq4, mqh, mqt. Чтобы, опять же, не указывать их по очереди, мы укажем одну запись с маской *.mq?, что включает в себя все три предыдущих вида файлов - знак ? заменяет один символ в маске, * - заменяет произвольное множество символов. И то же самое с маской *.ex? - это маска для файлов *.exe (исполняемых файлов самого терминала) и *.ex4 - бинарных файлов MQL разработок. Удобно, верно?

Далее, компонент управления конечными синхронизируемыми терминалами.

При выборе поля Путь к терминалу с правой границы поля появится кнопка с тремя точками, нажатие на которую откроет стандартное окно Windows выбора файла на диске (Open Dialog). Вы можете указать на файл terminal.exe в нужной папке.

Компонент исходного терминала во многом аналогичен выбору конечных терминалов.

Возникает вопрос, почему я разделил в базе таблицы исходных и конечных терминалов? Обратите внимание, что для конечных терминалов, в отличие от исходных, можно указать дополнительные свойства. Например, в базе для них введено поле Запускать после обновления. Его видно в компоненте конечных терминалов. Оно не обрабатывается в системе, хотя сделать это - написать буквально две строки кода - создать процесс для полного пути к файлу terminal.exe, и второй строкой запустить его.

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

И, наконец, последний и главный компонент запуска синхронизации, ради которого и создавалась система.

Все предыдущие компоненты служили для настройки параметров системы, делая её максимально гибкой. В данном компоненте нажатие на кнопку Запуск стартует процесс синхронизации, т.е. копирования нужных файлов. В группе (groupbox) Лог операций будут показаны контрольные точки проводимой синхронизации, а именно пути к папкам и число скопированных файлов.

Если в процессе копирования возникали ошибки, они будут отображены в группе Лог ошибок красным цветом, а также записаны в файл Log.txt в папке системы. Такая методика призвана наглядно отделить информационные сообщения от критических сообщений об ошибке. Причиной ошибки может быть, например, неверный путь к исходному или конечному терминалу (в базу его занесли, а с жёсткого диска папку удалили), или ошибка при монопольной блокировке файла без доступа даже на чтение.

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



Заключение

Мы обеспечили решение требуемой задачи и получили технический инструмент - систему синхронизации с настройками её параметров, логированием и отображением возможных ошибок и т.д. Маску для копируемых файлов я взял из файла INSTALL.LOG корневой папки терминала, секция [CopyFiles]. Вполне возможно, что в процессе работы вы найдёте ещё файлы с другими расширениями, которые необходимо синхронизировать. Поделитесь, пожалуйста, этой информацией в комментариях к статье, наверняка пользователям системы это будет интересно.

Готовый бинарный проект и пример кода модуля системы приложены к статье.

Прикрепленные файлы |
ctrlSync_cs.txt (11.84 KB)
MT4TerminalSync.zip (56.85 KB)
TestProject.zip (42.87 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (5)
Igor Malcev
Igor Malcev | 6 июл. 2007 в 13:34

хорошая статья, спасибо, - еще один весьма полезный инструмент для "ленивых" :-))

Valery V. Chesnokov
Valery V. Chesnokov | 16 июл. 2007 в 13:38
xeon:

хорошая статья, спасибо, - еще один весьма полезный инструмент для "ленивых" :-))


Думал, что сделаю инструмент для "занятых", оказалось - для "ленивых" ;) тоже неплохо :)
VM7
VM7 | 21 июл. 2007 в 12:16
А не решает ли случайно большинство наших хлопотных задач создание в МТ элементарной общей папки для шаблонов, индикаторов, экспертов?. ..
Большинство "нормальных" трейдеров эту статью даже и прочитать-то не решатся. Как, например, я...
Valery V. Chesnokov
Valery V. Chesnokov | 21 июл. 2007 в 17:58
VM7:
А не решает ли случайно большинство наших хлопотных задач создание в МТ элементарной общей папки для шаблонов, индикаторов, экспертов?. ..
Большинство "нормальных" трейдеров эту статью даже и прочитать-то не решатся. Как, например, я...


Терминал берёт индикаторы, эксперты, библиотеки и т.д. из своих подпапок с жёстко заданными именами (experts, indicators). На NTFS томах можно попробовать удалить эти папки и вместо них задать hard links на одну общую папку. Не знаю, будет ли это работать. Если хотите, можете проверить эту идею. Однако Ренат упоминал как-то, что терминал чувствителен к источникам некоторых файлов, особенно данных по счетам и тиковых данных валют. На форуме был такой вопрос.

Что касается "нормальных" трейдеров - обычные пользователи могут скачать систему (MT4TerminalSync.zip) и просто пользоваться ею, снимки экранов статьи поясняют, как это сделать. Вы же не пытаетесь найти исходные тексты MS Office или Open Office и узнать их "внутреннее строение", хотя наверняка чем-либо из них пользуетесь. Остальная информация в статье для разработчиков, владеющих навыками разработки "внешних", не-MQL приложений и SQL-баз данных.

Oleg
Oleg | 3 июн. 2009 в 21:23

Вот другое решение - 'Единая папка для индикаторов?' Гораздо более простое. 

У меня уже давно работает для директории "experts" - Супер! Но ни в коем случае не удаляйте Терминал с диска без 

предварительного "рассоединения" - иначе удаляется не копия "experts", а его оригинал. 

Читайте внимательно и предварительно тестируйте на ненужных директориях.

Terminal Service Client. Как подружить Pocket PC с большим братом. Terminal Service Client. Как подружить Pocket PC с большим братом.
Подключение к удаленному компьютеру с терминалом МТ4 через КПК.
Визуализация тестирования. Графики состояния счета. Визуализация тестирования. Графики состояния счета.
Погрузитесь в процесс тестирования с графиками, отображающими состояние счета - теперь вся необходимая информация всегда на виду!
Нестандартная автоматическая торговля Нестандартная автоматическая торговля
Насколько реально можно успешно и комфортно торговать, используя платформу МТ4, и не слишком обременяя себя, при этом, скрупулезным анализом рынка? Возможно ли реализовать практически такую торговую систему? Пожалуй..,. - да! Особенно в плане автоматической торговли!
Технический Анализ: невозможное - возможно! Технический Анализ: невозможное - возможно!
Ответ на вопрос: почему невозможное может быть возможным, когда многое говорит об обратном? Рассуждения о техническом анализе.