English 中文 Español Deutsch 日本語 Português
preview
Разработка системы репликации - Моделирование рынка (Часть 14): Появление СИМУЛЯТОРА (IV)

Разработка системы репликации - Моделирование рынка (Часть 14): Появление СИМУЛЯТОРА (IV)

MetaTrader 5Тестер | 29 сентября 2023, 09:31
610 0
Daniel Jose
Daniel Jose

Введение

В предыдущей статье "Разработка системы репликации - Моделирование рынка (Часть 13): Появление СИМУЛЯТОРА (III)" я показал изменения, внесенные в служебный файл для лучшего представления тиков и их обработки. Тем не менее, основная цель предыдущей статьи заключалась в том, чтобы показать, как это можно сделать и где нужно изменить и добавить код для получения данных из сервиса. Это позволит нам перенести эти данные в другое место, в данном случае в файл. Имея на руках этот файл, мы сможем использовать программу, в данном случае я показал, как использовать EXCEL, для анализа данных, которые будет генерировать симулятор.

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


Попытайтесь совершить свободное случайное блуждание

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

inline void Simulation(const MqlRates &rate, MqlTick &tick[])
                        {
#define macroRandomLimits(A, B) (int)(MathMin(A, B) + (((rand() & 32767) / 32767.0) * MathAbs(B - A)))

                                long il0, max;
                                double v0, v1;
                                int p0;
                                
                                ArrayResize(m_Ticks.Rate, (m_Ticks.nRate > 0 ? m_Ticks.nRate + 3 : def_BarsDiary), def_BarsDiary);
                                m_Ticks.Rate[++m_Ticks.nRate] = rate;                           
                                max = rate.tick_volume - 1;     
                                v0 = 4.0;
                                v1 = (60000 - v0) / (max + 1.0);
                                for (int c0 = 0; c0 <= max; c0++, v0 += v1)
                                {
                                        tick[c0].last = 0;
                                        tick[c0].flags = 0;
                                        il0 = (long)v0;
                                        tick[c0].time = rate.time + (datetime) (il0 / 1000);
                                        tick[c0].time_msc = il0 % 1000;
                                        tick[c0].volume_real = 1.0;
                                }
                                tick[0].last = rate.open;
                                tick[max].last = rate.close;
                                for (int c0 = (int)(rate.real_volume - rate.tick_volume); c0 > 0; c0--)
                                        tick[macroRandomLimits(0, max)].volume_real += 1.0;
                                for (int c0 = 1; c0 < max; c0++)
                                        tick[c0].last = macroRandomLimits(rate.low, rate.high);                                 
                                il0 = (long)(max * (0.3));
                                tick[macroRandomLimits(il0, il0 * 2)].last = rate.low;
                                tick[macroRandomLimits(max - il0, max)].last = rate.high;                                         
                                for (int c0 = 0; c0 <= max; c0++)
                                {
                                        ArrayResize(m_Ticks.Info, (m_Ticks.nTicks + 1), def_MaxSizeArray);
                                        m_Ticks.Info[m_Ticks.nTicks++] = tick[c0];
                                }
                        }
                        
#undef macroRandomLimits

Очень важно усвоить этот код выше, чтобы понять, что мы будем делать дальше. Если вы запустите именно этот код, вы получите очень запутанный график. Важно знать, как работает эта самая базовая функция, чтобы вы могли понять, как будут работать более сложные функции. Начнем с определения макроса. Вопрос: что делает этот макрос? Возможно, вы смотрите и думаете: что это за безумие? Действительно ли нам нужно что-то настолько странное? Ответ на этот вопрос — ДА и НЕТ.

ДА, потому что нам нужно, чтобы случайное значение было сгенерировано в очень конкретном диапазоне. Для этого нам нужно установить какое-то ограничение. И НЕТ, потому что для генерации СЛУЧАЙНОГО БЛУЖДАНИЯ нам не понадобится сам этот расчет. Но опять же, мы должны понять, как работает эта более простая система, чтобы понять другие, более сложные.

Поэтому, когда мы выполняем операцию AND, мы ограничиваем значение диапазоном. Это первый пункт. Если мы разделим это значение на верхнюю границу диапазона, то мы получим значение, которое будет находиться в диапазоне от 0 до 1. Затем мы умножим данное значение, которое будет между 0 и 1, на разницу между верхней и нижней границами. Таким образом, мы получим значение, которое будет находиться в диапазоне от 0 до максимального значения, которое будет нашим диапазоном. Теперь, если мы добавим данный диапазон к минимальному значению, то мы получим значение, которое нам действительно нужно и которое следует использовать. Таким образом, нам не нужно будет беспокоиться о проведении каких-либо других тестов: макрос сам будет гарантировать, что значение находится в допустимых границах. Вы поняли идею этого сумасшедшего макроса? Это чистая математика, не более того.

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

Вы могли заметить, что я устанавливаю каждый моделируемый тик так, чтобы изначально он имел минимальное значение объема. Данный момент также важен для следующего шага. Теперь входим в следующий цикл. Здесь всё становится интереснее, поскольку первое, что мы делаем, — определяем, какова будет цена открытия и закрытия 1-минутного бара. Однако, вот что действительно интересно — это то, что происходит внутри цикла. Обратите внимание, что мы вычтем общий объем из количества тиков, которые будут использованы. При этом мы получаем значение, представляющее собой объем, который еще не был распределен. Мы могли бы разместить это значение непосредственно на последнем тике или на каком-то другом. Однако это приведет к резкому изменению объема, что не часто случается на реальном рынке. Следовательно, нам нужен другой метод для распределения оставшихся тиков таким образом, чтобы итоговый объем был выражен в значении 1-минутного бара. Чтобы создать это распределение наиболее плавным и случайным образом, мы воспользуемся нашим макросом. Обратите внимание, что при каждом вызове макрос генерирует значение, которое находится в определенных пределах. И именно в этот момент значение, присутствующее в объёме, увеличится на 1. Иными словами, общий объем будет распределяться случайным и плавным образом, создавая впечатление, что данные аналогичны данным реального рынка.

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

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

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

Хотя это отличная идея для использования в тестере стратегии, такой подход не совсем адекватен для системы репликации/моделирования. Требуется другой подход, чуть более творческий, но в то же время более сложный. Так родилась система, которую я только что объяснил. Там мы начинаем достаточно просто "рандомизировать" движения внутри 1-минутного бара. Но данный подход не совсем адекватен, если наше намерение заключается в том, чтобы иметь стиль движения, очень похожий на стиль движения объекта, подвешенного в жидкости, поскольку между точками осуществились скачки. Чтобы вам было проще понять, как это делается, важно знать, как преобразовать ряд данных во что-то видимое на графике. Самый простой способ сделать это — использовать для преобразования EXCEL. Опять же, важно, чтобы вы знали, как это сделать.

В предыдущей статье "Разработка системы репликации - Моделирование рынка (Часть 13): Появление СИМУЛЯТОРА (III)", есть видео, в котором дается объяснение. Очень важно, чтобы вы знали, как это сделать, если вы действительно хотите понять, что будет происходить в этой статье. Так происходит, потому что здесь мы создадим моделирование движения, которое будет выглядеть как СЛУЧАЙНОЕ БЛУЖДАНИЕ. Просматривая графики, созданные симулятором, вы сразу заметите, что движение очень похоже на такое движение, которое наблюдается на этапе торговли активом. Я не буду включать в эту статью математические формулы или что-то подобное, не вижу никакой пользы в таком подходе. Что действительно интересует всех, так это именно сам код и то, что он производит. Используемые математические формулы для многих вообще ничего не добавляют и не дают никаких знаний, поскольку многие не понимают рассматриваемых абстрактных вопросов. Следовательно, это скорее усложнит дело, чем его объяснит. Но наверняка каждый поймет полученные результаты.

В данной статье вы увидите самый простой способ преобразования рисунка 01 в рисунок 02:                   

                       

Рисунок 01 – Произвольное движение, выполняемое скачками



Рисунок 02 - Случайное движение, выполняемое шагами


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


Рисунок 03 – База данных, используемая в обоих движениях


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

Хватит разговоров, давайте посмотрим, как на самом деле работает система. Но перед этим, если вы не читали предыдущую статью "Разработка системы репликации - Моделирование рынка (Часть 13): Появление СИМУЛЯТОРА (III)", я настоятельно рекомендую вам сначала остановиться и прочитать предыдущую статью. Причина в том, что здесь мы остановимся только на необходимых изменениях и на том, как их следует реализовать. Не будем повторять пояснения, которые были даны в предыдущей статье. И понимание предыдущего контента будет важно для понимания этого. Особенно та часть, которая связана с преобразованием данных в графике внутри Excel.

Давайте теперь перейдем к теме реализации.


Применение СЛУЧАЙНОГО БЛУЖДАНИЯ при абсолютно свободном движении

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

inline void Simulation(const MqlRates &rate, MqlTick &tick[])
                        {
#define macroRandomLimits(A, B) (int)(MathMin(A, B) + (((rand() & 32767) / 32767.0) * MathAbs(B - A)))

                                long il0, max;
                                double v0, v1;
                                
                                ArrayResize(m_Ticks.Rate, (m_Ticks.nRate > 0 ? m_Ticks.nRate + 3 : def_BarsDiary), def_BarsDiary);
                                m_Ticks.Rate[++m_Ticks.nRate] = rate;
                                max = rate.tick_volume - 1;     
                                v0 = 4.0;
                                v1 = (60000 - v0) / (max + 1.0);
                                for (int c0 = 0; c0 <= max; c0++, v0 += v1)
                                {
                                        tick[c0].last = 0;
                                        tick[c0].flags = 0;
                                        il0 = (long)v0;
                                        tick[c0].time = rate.time + (datetime) (il0 / 1000);
                                        tick[c0].time_msc = il0 % 1000;
                                        tick[c0].volume_real = 1.0;
                                }
                                tick[0].last = rate.open;
                                tick[max].last = rate.close;
                                for (int c0 = (int)(rate.real_volume - rate.tick_volume); c0 > 0; c0--)
                                        tick[macroRandomLimits(0, max)].volume_real += 1.0;
                                for (int c0 = 1; c0 < max; c0++)
                                        tick[c0].last = macroRandomLimits(rate.low, rate.high);
                                        tick[c0].last = tick[c0 - 1].last + (m_PointsPerTick * ((rand() & 1) == 1 ? 1 : -1));
                                il0 = (long)(max * (0.3));
                                tick[macroRandomLimits(il0, il0 * 2)].last = rate.low;
                                tick[macroRandomLimits(max - il0, max)].last = rate.high;
                                for (int c0 = 0; c0 <= max; c0++)
                                {
                                        ArrayResize(m_Ticks.Info, (m_Ticks.nTicks + 1), def_MaxSizeArray);
                                        m_Ticks.Info[m_Ticks.nTicks++] = tick[c0];
                                }
#undef macroRandomLimits
                        }                       

Будьте внимательны, мы меняем только способ работы функции, но всё равно мы сохранили ту же нагрузку. Таким образом, мы будем использовать одинаковое количество тиков. Однако обратите внимание на кое-что в выделенной части. И теперь обратите внимание на следующий факт: УДАЛЕНЫЙ код необходимо удалить, а на его место вставить выделенный код. Реализовав только это изменение, мы сможем создать СЛУЧАЙНОЕ БЛУЖДАНИЕ, но это неподходящий ход. Еще нет, потому что даже если в какой-то редкий момент произойдет движение, которое останется в пределах 1-минутного бара, иными словами, если соблюдаются максимум и минимум и удерживаются в пределах этой амплитуды, то в предыдущем коде у нас нет уверенности или контроля над этим. Это можно заметить, если его запустить и проверить полученный график.

Если использовать вложенные файлы и не менять конфигурационный файл, сервис репликации/моделирования будет работать только на первой панели, и будет использована именно та панель, которая выделена на изображении ниже:



Обратите внимание на ограничения: ВЕРХНИЙ ПРЕДЕЛ => 108375 и НИЖНИЙ ПРЕДЕЛ => 107850. И это не те ограничения, которые можно увидеть, глядя на график. Даже беглым взглядом вы заметите, что эти границы не соблюдаются. Чтобы проиллюстрировать это, посмотрите на изображение графика данных одного из исполнений. Это можно увидеть ниже.


Рисунок 04 – Представление совершенно свободного СЛУЧАЙНОГО БЛУЖДАНИЯ


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

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

В отличие от того, что происходит, когда у нас есть полностью случайная система, основанная на скачках, как показано на рисунке 01, где использование графической системы MetaTrader 5 совершенно невозможно, то же самое не происходит, когда мы получаем то, что изображено на рисунке 02 или даже на рисунке 04. Хотя в обоих случаях у нас возникает проблема изолированных точек на графике, из-за которых появится странный бар. Однако, если вам не хочется переносить данные моделирования в EXCEL, можно внести некоторые изменения в код, чтобы каждый тик отображался непосредственно на графике MetaTrader 5. Однако, это сделает график более сложным для понимания из-за количества информации, которую он будет содержать. Запомните: Нужно будет размещать тик за тиком на графике, а не на барах. Если не знаете, как это сделать, прочтите эту статью: "Разработка торгового советника с нуля (Часть 13): Времена и торговля (II)", поскольку в нем я объясняю, как построить график тиков, которые мы генерируем здесь, в симуляторе. Хотя Times And Trade фокусируется на просмотре реальных тиков актива, ничто не мешает нам использовать его для просмотра тиков, сгенерированных в симуляторе. Всё дело в адаптации кода, показанного для Times And Trade.

Это не является слишком сложной задачей, но она потребует изменений, которые затем придется отменить. Поэтому я не буду показывать, как это сделать. Здесь целью является показать очень простым способом, как заставить систему генерировать движение, чтобы у нас было моделирование возможного движения в пределах 1-минутного бара, но в непрерывной форме, а не скачками. Я думаю, что многие из вас не обладают глубокими знаниями о том, как программировать эти вещи с помощью MQL5. Изменение подхода только ради личного удовлетворения совершенно выходит за рамки этой или любой другой статьи в данной последовательности. Поэтому давайте продолжим нашу работу в таком же духе. Теперь добавим в код нечто такое, чтобы он соответствовал наложенным ограничениям, которые определяются информацией, содержащейся в 1-минутном баре, выделенном на рисунке 03.


Применение СЛУЧАЙНОГО БЛУЖДАНИЯ ограниченного движения

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

inline void Simulation(const MqlRates &rate, MqlTick &tick[])
                        {
#define macroRandomLimits(A, B) (int)(MathMin(A, B) + (((rand() & 32767) / 32767.0) * MathAbs(B - A)))

                                long    il0, max;
                                double  v0, v1;
                                bool    bLowOk, bHighOk;
                                
                                ArrayResize(m_Ticks.Rate, (m_Ticks.nRate > 0 ? m_Ticks.nRate + 3 : def_BarsDiary), def_BarsDiary);
                                m_Ticks.Rate[++m_Ticks.nRate] = rate;
                                max = rate.tick_volume - 1;     
                                v0 = 4.0;
                                v1 = (60000 - v0) / (max + 1.0);
                                for (int c0 = 0; c0 <= max; c0++, v0 += v1)
                                {
                                        tick[c0].last = 0;
                                        tick[c0].flags = 0;
                                        il0 = (long)v0;
                                        tick[c0].time = rate.time + (datetime) (il0 / 1000);
                                        tick[c0].time_msc = il0 % 1000;
                                        tick[c0].volume_real = 1.0;
                                }
                                tick[0].last = rate.open;
                                tick[max].last = rate.close;
                                for (int c0 = (int)(rate.real_volume - rate.tick_volume); c0 > 0; c0--)
                                        tick[macroRandomLimits(0, max)].volume_real += 1.0;
                                bLowOk = bHighOk = false;
                                for (int c0 = 1; c0 < max; c0++)
                                {                               
                                        v0 = tick[c0 - 1].last + (m_PointsPerTick * ((rand() & 1) == 1 ? 1 : -1));
                                        if (v0 <= rate.high)
                                                v0 = tick[c0].last = (v0 >= rate.low ? v0 : tick[c0 - 1].last + m_PointsPerTick);
                                        else
                                                v0 = tick[c0].last = tick[c0 - 1].last - m_PointsPerTick;
                                        bLowOk = (v0 == rate.low ? true : bLowOk);
                                        bHighOk = (v0 == rate.high ? true : bHighOk);
                                }                                       
                                il0 = (long)(max * (0.3));
                                if (!bLowOk) tick[macroRandomLimits(il0, il0 * 2)].last = rate.low;
                                if (!bHighOk) tick[macroRandomLimits(max - il0, max)].last = rate.high;
                                for (int c0 = 0; c0 <= max; c0++)
                                {
                                        ArrayResize(m_Ticks.Info, (m_Ticks.nTicks + 1), def_MaxSizeArray);
                                        m_Ticks.Info[m_Ticks.nTicks++] = tick[c0];
                                }
#undef macroRandomLimits
                        }                       

Может показаться, что изменений не происходит или вы немного запутались во всех этих метках. Но имейте в виду, что тут добавили две новые переменные, которые помогут нам лучше контролировать ситуацию. Они инициализируются таким образом, что если к позициям, которые они представляют, не будет получен должный доступ, нам обязательно придется разместить данные точки на графике. И эти точки выбираются случайным образом. Но испытания проводятся в рамках системы поиска и анализа границ. Таким образом, мы можем сосредоточиться только и исключительно на одном: удержании СЛУЧАЙНОГО БЛУЖДАНИЯ в пределах, ранее установленных 1-минутными барами. Первое, что мы проверим — была ли нарушена и как соблюдалась верхняя граница. Если это произошло, мы немедленно вернем движение в рамки. Если она был соблюдена, мы проведем еще один тест, в котором мы проверим не была ли нарушена нижняя граница. Если да, то мы немедленно вернем движение в границы. В противном случае значение будет принято.

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


Рисунок 05 – СЛУЧАЙНОЕ БЛУЖДАНИЕ в определенных границах.


На самом деле, то, что движение охватило все изолированные точки, было чистой случайностью. Но всё же у нас есть свободная точка на графике. Эта точка представляет собой тик закрытия 1-минутного бара. На самом деле довольно сложно точно добиться этого, учитывая природу случайного движения и то, как мы его делаем. Но помимо этого можно заметить, что в отличие от рисунка 04, где ограничения не были соблюдены, на рисунке 05 они соблюдены и весь 1-минутный бар будет находиться в пределах ранее установленных ограничений, так что движение почти идеальное. И говорю «почти», потому что результат рисунка 05 был чистой удачей. В большинстве случаев мы получим результат, аналогичный показанному на рисунке 06 ниже.


Рисунок 06 – Типичный график движения в пределах границ


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


Рисунок 07 – РЕДКОЕ движение, при котором была достигнута точка закрытия.


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

Думаю, многих уже вполне устраивают результаты, представленные в данной версии. Однако мы еще можем всё это улучшить. Тем, кто считает, что этого достаточно, следующая статья может показаться ненужной. Но для перфекционистов, у меня есть еще одно предложение, над которым стоит поработать. Это приведет к созданию СЛУЧАЙНОГО БЛУЖДАНИЯ, в котором не будет свободных точек. Таким образом, все точки будут посещены безопасно, но на сегодня достаточно. Я дам вам время на усвоение знаний из этой статьи. Вам нужно будет протестировать систему несколько раз с разными типами активов, только тогда вы действительно будете знать, являются ли возможные движения в пределах 1-минутного бара адекватными и отражают возможную реальность рынка, который вы хотите использовать, используя концепцию ограниченного СЛУЧАЙНОГО БЛУЖДАНИЯ.


Конечные выводы

Практически без наличия сложных математических формул и простым языком, я думаю, что мне удалось передать вам, дорогие читатели, концепцию, которая довольно интересна и присутствует на рынке. Это так называемое RANDOM WALK (случайное блуждание). Система, представленная в этой статье, показывает, как далеко мы можем дойти, не понимая сложных концепций, хотя, конечно, всегда хорошо получать знания. Но зачем усложнять что-то, если можно объяснить это довольно простым и приятным способом, не правда ли?

В прикрепленном файле можно увидеть систему в её текущем состоянии разработки. Наверно многие из вас хотят знать, когда мы действительно начнем использовать систему ордеров в нашей репликации/моделировании. Не волнуйтесь, скоро мы начнем добавлять систему ордеров, но прежде чем мы это сделаем, нам нужно сделать еще кое-что. Так нужно, потому что система ордеров станет довольно интересной проблемой для решения. Но сначала нам нужно завершить реализацию сервиса репликации/моделирования, который сейчас, похоже, почти готов. Осталось добавить лишь несколько деталей. После этого мы можем приступить к разработке системы ордеров. Таким образом, можно будет использовать репликацию/моделирование, как будто идет торговля на реальном рынке. Хотя, возможно, вам придется изменить кое-что, прежде чем приступить к использованию. Но мы это решим позже. В любом случае, вам нужно практиковаться и тренироваться, чтобы приобрести навыки опытного программиста. В этом вам поможет то, что я пытаюсь вам объяснить. Увидимся в следующей статье, где нам предстоит закончить с этим СЛУЧАЙНЫМ БЛУЖДАНИЕМ. Данный этап еще не завершен.


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

Прикрепленные файлы |
Разработка пользовательского индикатора Heiken Ashi с помощью MQL5 Разработка пользовательского индикатора Heiken Ashi с помощью MQL5
В этой статье мы узнаем, как создать собственный индикатор с использованием MQL5 на основе наших предпочтений, который будет использоваться в MetaTrader 5 для интерпретации графиков или применяться в составе советников.
Готовые шаблоны для подключения индикаторов в экспертах (Часть 3): Трендовые индикаторы Готовые шаблоны для подключения индикаторов в экспертах (Часть 3): Трендовые индикаторы
В этой справочной статье рассмотрим стандартные индикаторы из категории "Трендовые индикаторы". Создадим готовые к применению шаблоны использования этих индикаторов в советниках — объявление и установка параметров, инициализация и деинициализация индикаторов и получение данных и сигналов из индикаторных буферов в советниках.
Популяционные алгоритмы оптимизации: Алгоритм эволюции разума (Mind Evolutionary Computation, MEC) Популяционные алгоритмы оптимизации: Алгоритм эволюции разума (Mind Evolutionary Computation, MEC)
В данной статье рассматривается алгоритм семейства MEC, называемый простым алгоритмом эволюции разума (Simple MEC, SMEC). Алгоритм отличается красотой заложенной идеи и простотой реализации.
Разработка системы репликации - Моделирование рынка (Часть 13): Появление СИМУЛЯТОРА (III) Разработка системы репликации - Моделирование рынка (Часть 13): Появление СИМУЛЯТОРА (III)
Здесь мы немного упростим несколько элементов, связанных с работой в следующей статье. Я также объясню, как можно визуализировать то, что генерирует симулятор с точки зрения случайности.