English 中文 Español Deutsch 日本語 Português
preview
Как создать советник, который торгует автоматически (Часть 14): Автоматизация (VI)

Как создать советник, который торгует автоматически (Часть 14): Автоматизация (VI)

MetaTrader 5Трейдинг | 29 мая 2023, 10:23
815 0
Daniel Jose
Daniel Jose

Введение

В предыдущей статье, Как создать советник, который торгует автоматически (Часть 13): Автоматизация (V), я объяснил, как трейдер, даже не имея знаний в области программирования, может создать необходимые основы для преобразования советника в автоматический советник, что я показываю в этой последовательности статей. Эти концепции и информация применимы к любому советнику, включая любые созданные вами. В этой статье я расскажу об одном из многих способов выполнения данной задачи.

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


Появление класса C_Automaton

В предыдущей статье мы увидели следующий рисунок:

Рисунок 01

Рисунок 01 - Ручной режим работы.

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

Рисунок 02

Рисунок 02 - Автоматический режим работы.

Важно отметить, что на рисунке 02 показан образ человека как наблюдателя системы. Автоматизированная система никогда не должна работать без присмотра. Очень важно, чтобы трейдер всегда контролировал процесс, даже если он просто наблюдает и ничего не делает.

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

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

Прежде чем посмотреть, как запрограммирован класс C_Automaton, давайте быстро взглянем на код советника, который уже был изменен для автоматического использования. ПОЛНЫЙ код советника можно увидеть ниже:

#property copyright "Daniel Jose"
#property description "This one is an automatic Expert Advisor"
#property description "for demonstration. To understand how to"
#property description "develop yours in order to use a particular"
#property description "operational, see the articles where there"
#property description "is an explanation of how to proceed."
#property version   "1.14"
#property link      "https://www.mql5.com/pt/articles/11318"
//+------------------------------------------------------------------+
#include <Generic Auto Trader\C_Automaton.mqh>
//+------------------------------------------------------------------+
C_Automaton *automaton;
//+------------------------------------------------------------------+
input int       user01   = 1;           //Leverage Factor
input double    user02   = 100;         //Take Profit ( FINANCE )
input double    user03   = 75;          //Stop Loss ( FINANCE )
input bool      user04   = true;        //Day Trade ?
input double    user08   = 35;          //BreakEven ( FINANCE )
//+------------------------------------------------------------------+
input string    user90  = "00:00 - 00:00";      //Sunday
input string    user91  = "09:05 - 17:35";      //Monday
input string    user92  = "10:05 - 16:50";      //Tuesday
input string    user93  = "09:45 - 13:38";      //Wednesday
input string    user94  = "11:07 - 15:00";      //Thursday
input string    user95  = "12:55 - 16:25";      //Friday
input string    user96  = "00:00 - 00:00";      //Saturday
//+------------------------------------------------------------------+
#define def_MAGIC_NUMBER 987654321
//+------------------------------------------------------------------+
int OnInit()
{
        string szInfo;
        
        automaton = new C_Automaton(def_MAGIC_NUMBER, user03, user02, user01, user04, user08, PERIOD_M5);
        for (ENUM_DAY_OF_WEEK c0 = SUNDAY; c0 <= SATURDAY; c0++)
        {
                switch (c0)
                {
                        case SUNDAY     : szInfo = user90; break;
                        case MONDAY     : szInfo = user91; break;
                        case TUESDAY    : szInfo = user92; break;
                        case WEDNESDAY  : szInfo = user93; break;
                        case THURSDAY   : szInfo = user94; break;
                        case FRIDAY     : szInfo = user95; break;
                        case SATURDAY   : szInfo = user96; break;
                }
                (*automaton).SetInfoCtrl(c0, szInfo);
        }
        (*automaton).CheckToleranceLevel();
        EventSetMillisecondTimer(100);

        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        delete automaton;
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick() { }
//+------------------------------------------------------------------+
void OnTimer()
{
        (*automaton).Triggers();
}
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
        switch (trans.type)
        {
                case TRADE_TRANSACTION_POSITION:
                        (*automaton).UpdatePosition(trans.position);
                        break;
                case TRADE_TRANSACTION_ORDER_DELETE:
                        if (trans.order == trans.position) (*automaton).PendingToPosition();
                        else
                        {
                                (*automaton).UpdatePosition(trans.position);
                                (*automaton).EraseTicketPending(trans.order);
                        }
                        break;
                case TRADE_TRANSACTION_ORDER_UPDATE:
                        (*automaton).UpdatePending(trans.order);
                        break;
                case TRADE_TRANSACTION_REQUEST: if ((request.symbol == _Symbol) && (result.retcode == TRADE_RETCODE_DONE) && (request.magic == def_MAGIC_NUMBER)) switch (request.action)
                        {
                                case TRADE_ACTION_DEAL:
                                        (*automaton).UpdatePosition(request.order);
                                        break;
                                case TRADE_ACTION_SLTP:
                                        (*automaton).UpdatePosition(trans.position);
                                        break;
                                case TRADE_ACTION_REMOVE:
                                        (*automaton).EraseTicketPending(request.order);
                                        break;
                        }
                        break;
        }
}
//+------------------------------------------------------------------+

Обратите внимание, что в этот код было внесено лишь несколько изменений. Обработчик события OnChartEvent удален поскольку уже был ненужным, а в событии OnTime появилась новая функция. Более подробную информацию об этой функции можно будет посмотреть позже. В остальном код остается таким же, как и раньше при ручном управлении. Крайне важно заметить, что при создании автоматического советника не следует модифицировать весь код. Нужно только внести необходимые изменения, а в данном случае единственным изменением будет включение новой функции во временное событие; в противном случае код остается идентичным.

Однако данный код советника, я подчеркиваю, НЕ ЯВЛЯЕТСЯокончательным и неизменным вариантом. В зависимости от системы, которая будет использоваться, пользователю придется сделать больше или меньше определений, которые будут отражены здесь, и в конструкторе класса C_Automaton могут быть вариации. Поэтому здесь может потребоваться больше или меньше параметров. Так что не рассматривайте этот код как решение на все случаи жизни.

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

Еще вы, наверное, заметили, что класс C_Automaton наследуется от класса C_Manager. Именно поэтому код практически не меняется. Как вы могли заметить, всё будет происходить внутри класса C_Automaton.

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

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

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

Теперь давайте посмотрим, что находится внутри черного ящика класса C_Automaton.


Анализ кода класса C_Automaton

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

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

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


Видео 01 - Демонстрация автоматического советника (длительность +/- 25 мин)

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

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


Общие элементы, зависимые элементы

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

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

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

Вот общий код для любой модели:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Manager.mqh"
//+------------------------------------------------------------------+
class C_Automaton : public C_Manager

{
        protected:
                enum eTrigger {TRIGGER_NONE, TRIGGER_BUY, TRIGGER_SELL};
        private :
                struct st00
                {
                        int     Shift,
                                nBars;
                        double  OverBought,
                                OverSold;
                }m_Infos;
                double  m_Buff[];
                int     m_nBars,
                        m_Handle;
                ENUM_TIMEFRAMES m_TF;
//+------------------------------------------------------------------+
static eTrigger m_Memory;
//+------------------------------------------------------------------+  
inline eTrigger CheckTrigger(void)
                        {
                               int iRet;

                               if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE))
			       {
			       }

                               return TRIGGER_NONE;
                        }
//+------------------------------------------------------------------+  
        public  :
//+------------------------------------------------------------------+
                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                                                bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                                                const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, FinanceStop, FinanceTake, Leverage, IsDayTrade, Trailing, true, 10),
                         m_TF(iPeriod),
                         m_Handle(INVALID_HANDLE)
                        {
                                m_Infos.Shift      = iShift;
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                ArraySetAsSeries(m_Buff, true);
                                m_nBars = iBars(NULL, m_TF);
                        }
//+------------------------------------------------------------------+
inline virtual void Triggers(void) final
                        {
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY);
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL);
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                        };
//+------------------------------------------------------------------+  
};
//+------------------------------------------------------------------+
static C_Automaton::eTrigger C_Automaton::m_Memory = TRIGGER_NONE;
//+------------------------------------------------------------------+

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

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

Начнем с объявления класса в следующем фрагменте:

#include "C_Manager.mqh"
//+------------------------------------------------------------------+
class C_Automaton : public C_Manager
{
        protected:
                enum eTrigger {TRIGGER_NONE, TRIGGER_BUY, TRIGGER_SELL};

Здесь мы объявляем, что класс C_Automaton публично наследуется от класса C_Manager. Это позволяет нам иметь доступ к процедурам класса C_Manager при использовании класса C_Automaton. Это важно для инициализации некоторых элементов, связанных с классом управления. Если посмотреть на код советника, мы заметим эти точки, где осуществляется доступ к процедурам. Хотя данные процедуры не объявлены в классе C_Automaton, они происходят из других классов. Я уже объяснил это в другой статье данной серии.

Мы также создали перечислитель для высокоуровневого программирования на классе. Это перечисление указывает, какой вид триггера сработал. Еще одна деталь: хотя это перечисление объявлено в защищенной части кода, оно не будет использоваться вне класса. Однако было необходимо поместить его в эту часть для инициализации статической переменной класса, но об этом позже.

Далее приведены переменные, которые можно увидеть во фрагменте ниже:

        private :
                struct st00
                {
                        int     Shift,
                                nBars;
                        double  OverBought,
                                OverSold;
                }m_Infos;
                double  m_Buff[];
                int     m_nBars,
                        m_Handle;
                ENUM_TIMEFRAMES m_TF;
//+------------------------------------------------------------------+
static eTrigger m_Memory;

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

Чтобы проиллюстрировать то, что упомянули, давайте рассмотрим пример: на структуру ссылается одна переменная, что позволяет использовать один индикатор, каким бы он ни был. Но что, если нам нужно использовать более одного индикатора? Как действовать тогда? В таком случае нам придется внести некоторые дополнения. Они будут видны на примерах. А пока давайте сосредоточимся на основах, чтобы понять эту более простую систему.

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

static C_Automaton::eTrigger C_Automaton::m_Memory = TRIGGER_NONE;

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

Следующим моментом, на который следует обратить внимание - приватная функция класса, которую можно увидеть ниже:

inline eTrigger CheckTrigger(void)
                        {
                                int iRet;
                                        
                                if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE))
                                {
                                };
                                return TRIGGER_NONE;
                        }

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

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

Следующая функция - это конструктор класса, его лучше видно в следующем фрагменте:

                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                            bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                            const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, FinanceStop, FinanceTake, Leverage, IsDayTrade, Trailing, true, 10),
                         m_TF(iPeriod),
                         m_Handle(INVALID_HANDLE)
                        {
                                m_Infos.Shift      = iShift;
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                ArraySetAsSeries(m_Buff, true);
                                m_nBars = iBars(NULL, m_TF);
                        }

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

Поскольку класс C_Automaton наследуется от класса C_Manager, необходимо инициализировать конструктор C_Manager. По этой причине он получает данные от советника, которые в полном объеме передаются в класс C_Manager для инициализации,

но обратите внимание, что здесь есть два дополнительных параметра. При желании можно их передать назад советнику, но это может зависеть от типа сделки, создаваемой в классе C_Automaton. Я предпочитаю упоминать эти параметры здесь, чтобы их значение было понятно. Чтобы лучше понять, какое значение здесь использовать, можно смотреть класс C_Manager. Код который описывает конструктор класса, можно найти в предыдущих статьях, поэтому здесь я не буду повторяться.

Советник также подскажет, какой период графика использовать для класса C_Automaton. Мы будем использовать данный параметр для этого.

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

На этом этапе у нас есть некоторые параметры со значениями по умолчанию. Соответственно, они могут быть объявлены или не объявлены в коде советника. Использование значений по умолчанию не мешает объявлению другого значения в коде советника

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

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

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

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

inline virtual void Triggers(void) final
                        {
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY);
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL);
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                        };

Вышеописанная процедура не является 100% готовым кодом, так как может претерпеть небольшие изменения в зависимости от торговой системы, в которой ее собираются реализовать. Однако, по сути, он показывает нам, что будет происходить при каждом вызове, поступающем из события OnTime. У многих может возникнуть соблазн переместить это в событии OnTick, но в предыдущих статьях я уже объяснял почему этого не стоит делать. Я вам рекомендую прочитать эти статьи, чтобы понять причины.

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

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

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

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

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

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

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

Чтобы понять, как класс C_Automaton может помочь автоматизировать рассматриваемый советник, мы рассмотрим несколько примеров кода, где сосредоточимся на объяснении того, как реализовать операционную систему. Перед началом необходимо уточнить некоторые моменты:

  • Ни одна автоматизированная операционная система не защищена на 100%.
  • Нет ни одной системы, гарантирующей прибыль во всех операциях.
  • Не дайте себя одурачить системой, которая работает с первого раза; это можно увидеть в видео 01.
  • Вам просто надо управлять или автоматизировать систему, которую вы уже знаете. Не пытайтесь сочетать несколько стратегий, воображая, что так вы добьетесь лучших результатов. Всё должно быть просто.
  • Вы используйте представленные здесь модели на свой страх и риск: они могут приносить как прибыль, так и убытки.

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


Заключение

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


Перевод с португальского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/pt/articles/11318

Разработка торговой системы на основе индикатора Fibonacci Разработка торговой системы на основе индикатора Fibonacci
Это продолжение серии статей, в которых мы учимся строить торговые системы на основе самых популярных индикаторов. Очередным техническим инструментом станет индикатор Фибоначчи. Давайте разберем, как написать программу по сигналам этого индикатора.
Как построить советник, работающий автоматически (Часть 13): Автоматизация (V) Как построить советник, работающий автоматически (Часть 13): Автоматизация (V)
Знаете ли вы, что такое блок-схема? Умеете ли вы ее использовать? Думаете ли вы, что блок-схемы - это дело начинающих программистов? Тогда я вам предлагаю ознакомиться с этой статьей и узнать, как работать с блок-схемами.
Нейросети — это просто (Часть 43): Освоение навыков без функции вознаграждения Нейросети — это просто (Часть 43): Освоение навыков без функции вознаграждения
Проблема обучения с подкреплением заключается в необходимости определения функции вознаграждения, которая может быть сложной или затруднительной для формализации, и для решения этой проблемы исследуются подходы, основанные на разнообразии действий и исследовании окружения, которые позволяют обучаться навыкам без явной функции вознаграждения.
Многослойный перцептрон и алгоритм обратного распространения ошибки (Часть 3): Интеграция с тестером стратегии - Обзор (I) Многослойный перцептрон и алгоритм обратного распространения ошибки (Часть 3): Интеграция с тестером стратегии - Обзор (I)
Многослойный перцептрон - это эволюция простого перцептрона, способного решать нелинейно разделяемые задачи. Вместе с алгоритмом обратного распространения можно эффективно обучить данную нейронную сеть. В третьей части серии статей о многослойном перцептроне и обратном распространении мы посмотрим, как интегрировать эту технику в тестер стратегий. Эта интеграция позволит использовать комплексный анализ данных и принимать лучшие решения для оптимизации торговых стратегий. В данном обзоре мы обсудим преимущества и проблемы применения этой методики.