English 中文 Español Deutsch 日本語 Português
Самоадаптирующийся алгоритм (Часть III): Отказываемся от оптимизации

Самоадаптирующийся алгоритм (Часть III): Отказываемся от оптимизации

MetaTrader 5Трейдинг | 28 декабря 2020, 08:53
5 663 30
Maxim Romanov
Maxim Romanov

Введение

Перед началом изучения данной статьи рекомендую ознакомиться со второй статьей серии "Разработка самоадаптирующегося алгоритма (Часть II): Повышение эффективности". Методика из текущей статьи будет существенно отличаться от всего рассмотренного ранее, но для понимания проблемы знакомство с предыдущими статьями серии будет полезным.

Анализ недостатков

Как и в прошлый раз, начну с анализа недостатков предыдущей успешной версии. В процессе анализа были выявлены следующие недостатки:

  • Сигнал на открытие и закрытие позиций генерируется на основе анализа свечей. Свечи имеют нестабильный размер, некоторые свечи большие, а некоторые маленькие. Часто возникают ситуации, когда позиции открылись на основании перевеса падающих или растущих свечей, затем падающих и растущих свечей стало поровну, но прибыль по открытым позициям все еще отрицательная. Возникает вопрос: закрывать позиции или ждать, пока будет получена прибыль. Если закрывать, то весь смысл торговли сводится на нет, алгоритм начинает получать убытки. Если не закрывать, то рано или поздно это приведет к существенной просадке.
  • Цена движется независимо от типа свечей. На рынке могут преобладать падающие свечи, а цена будет двигаться вверх из-за того, что растущие свечи будут иметь размер больше, чем падающие. Этот момент особенно негативен, когда открыты позиции.
  • Предсказать будущий размер свечей — задача сама по себе никем нерешенная.
  • Иногда после открытия позиций перевес одного типа свечей не уменьшается долгое время, и цена может продолжить движение против открытых позиций. Это приводит к существенным просадкам, а главное, непонятно, когда цена развернется и развернется ли вообще.
  • Позиции открываются по времени. Бывают моменты, когда цена долгое время стоит на месте, а позиции продолжают открываться, потому что приходят новые свечи. Особенно опасны такие моменты во время праздников, таких как Рождество, когда торговая активность низкая и алгоритм просто набирает позиции из-за того, что прошло время.
  • Настройки алгоритма необходимо оптимизировать под каждый торговый инструмент индивидуально. Единственная причина, почему установлены именно эти настройки: на истории так работало лучше. Да, алгоритм проходит бектесты за 21 год, но не по всем инструментам, и подгонять параметры под историю — не самое лучшее решение.
  • Неочевидно, почему по одним торговым инструментам он работает лучше и стабильнее, по другим сильно хуже.
  • Неизвестно, когда характер поведения торгового инструмента изменится так, что алгоритм получит убыток. По сути, неизвестно, когда наступит рисковая ситуация. Я могу посчитать вероятность наступления такого момента, но это будет очень приблизительный результат.
  • Нет теории, объясняющей как будет меняться характер инструмента в будущем и почему, поэтому приходится использовать заранее неоптимальные параметры, чтобы был запас для флуктуации статистических характеристик ценового ряда. Это сильно снижает доходность.

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

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

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

Преобразование свечного графика в другой вид

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

Анализировать буду блоки размером N пунктов. Это блоки, похожие на ренко, но построенные немного по другому алгоритму. Я уже писал про блоковые графики и их преимущества при анализе в статье "Что такое тренды и какова структура рынков — трендовая или флэтовая".

Block

Рисунок 1. Вид блокового графика

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

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

Модель рынка

Базовая закономерность будет похожа на ту, что я использовал в предыдущих алгоритмах, а именно: локальное отклонение числа падающих блоков от числа растущих блоков и последующий возврат к некоторому равновесию. Закономерность статистическая, поэтому начать нужно с анализа статистических характеристик блоковых графиков. Для этого я разработал специальный индикатор Max_distribution, который подробно рассматривался в статье "Что такое тренды и какова структура рынков — трендовая или флэтовая".

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

Основным режимом работы индикатора является измерение количества блоков, которое проходит цена по вертикали за N шагов.

blocks vertically

Рисунок 2. Пример измерения числа блоков по вертикали за 24 шага

На рисунке 2 показан пример. Измеряется, сколько блоков по вертикали цена прошла за N шагов. Так набирается нужное число выборок (например, 100) и потом находится среднее значение. Подобный анализ проводится для блоков разного размера.

distribution

Рисунок 3. Средняя амплитуда для разного размера блоков

На рисунке 3 показан пример распределения средней амплитуды в блоках по вертикали за 24 шага. Каждый столбец гистограммы — это значение средней амплитуды для своего размера блока. Число выборок = 1000. Слева измерения для самого маленького размера блоков, справа для самого большого. Для размера блоков 0.00015 за 24 шага и 1000 выборок цена проходит в среднем 5.9 блока по вертикали. Для размера блока 0.00967 за те же 24 шага и 1000 выборок цена проходит по вертикали в среднем 4,2 блока.

Красной линией показано эталонное значение, которое было бы, если бы ценовой ряд был случайным блужданием. Для 24 шагов — это значение 3.868 блока по вертикали. Эталонное значение рассчитывается методом комбинаторики и наглядно можно представить таблицей на рисунке 4.

probability table

Рисунок 4. Расчет эталона для 24 шагов

На рисунке 4 показан расчет эталонного значения числа блоков по вертикали, которое в среднем пройдет цена за 24 шага, если будет случайным блужданием. В последнем столбце это значение переведено в степень. Можно сказать, что средняя амплитуда случайного блуждания стремится к значению 24^0.4526. Для каждого числа шагов можно пересчитать эталон. Таблицу прикрепил к статье в формате .xlsx.

Я провел исследования на разных торговых инструментах: это было около 35 валютных пар, более 100 акций, 10 криптовалют и около 10 сырьевых инструментов. Серьезных отклонений нет, в целом картина примерно похожа на всех инструментах. Средняя амплитуда колеблется от 7 на быстро растущих криптовалютах до 3.8 на валютных парах. Некоторые низко ликвидные акции могут опускаться даже ниже значения 3.8.

Получено значение средней амплитуды за 24 шага или за какое-то другое число шагов, но что это значит? Представим график в виде синусоиды, преобразованной в блоковый вид, как на рисунке 5.

Sinus

Рисунок 5. Синусоида в блоковом виде

Пусть размер блоков будет такой, что в половине периода синусоиды будет 24 шага. Тогда период будет 48 шагов. Если измерить среднюю амплитуду за 25 выборок по 24 шага, то получим среднюю амплитуду 10.33 блока за 24 шага. С увеличением числа выборок средняя амплитуда будет стремиться к 12, или к числу шагов, деленное на 2. Ценовой ряд не синусоида, но на синусоиде удобно торговать. Теперь, если при измерении средней амплитуды мы будем получать значение больше 12, значит размер блоков недостаточно большой, и 24 блока не укладываются в половину периода. Но значение меньше 12 будет говорить о двух причинах: блоки слишком большие или трендовое движение на ценовом ряде не такое линейное, как на синусоиде. Сейчас не рассматриваем трендовый наклон, это будет дальше.

По показаниям разработанного индикатора Max_distribution можно примерно оценить, насколько ценовой ряд похож на синусоиду. Для этого посмотрим на рисунке 6, как выглядит гистограмма индикатора для синусоиды.

distribution2

Рисунок 6. зависимость средней амплитуды от величины блока для синусоиды

На рисунке 6 видно, что с блоками малого размера цена проходит по вертикали за 24 шага 24 блока. Но с увеличением размера блока за 24 шага цена проходит все меньшее число блоков и затем, когда размер блока становится сопоставим с амплитудой колебаний, число блоков по вертикали падает до нуля. На графике рисунка 3 такой картины не наблюдалось, там максимальное значение было 5.9 и стремилось к эталону, 3.868. Значит, ценовой ряд можно представить как синусоиду, но зашумленную, всегда имеющую на некоторых масштабах некоторую трендовую составляющую. Другими словами, на рынке всегда должен быть масштаб, на котором сейчас флэт (вероятность разворота выше вероятности продолжения тенденции) и масштаб, на котором сейчас тренд (вероятность продолжения выше вероятности разворота).

Почему я принял именно такое определение тренда и флэта, можно прочитать в одной из предыдущих моих статей "Что такое тренды и какова структура рынков — трендовая или флэтовая".

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

multysample

Рисунок 7. Зависимость средней амплитуды от числа шагов в выборке

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

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

Возьму среднюю амплитуду для 24 шагов с рисунка 7, это значение 3.86. Предположу, что по аналогии с синусоидой движение будет состоять из трендовой и флэтовой части. Тогда можно рассчитать, какая будет трендовая часть для такой средней амплитуды. Для этого 3.86*2=7.72 блока по вертикали за 24 шага округлю в большую сторону до 8, потому что блоки могут быть только целыми. Если попадем на трендовый участок, то цена проходит 8 блоков по вертикали за 24 шага. Да, цена может пройти и 24 блока по вертикали за 24 шага, ничего ей не мешает, но дальше станет ясно, почему это не важно.

Получилось, что на трендовом участке цена пройдет за 24 шага 8 блоков по вертикали. Значит будет движение, у которого блоков одного направления будет 16, блоков другого направления будет 8. Так же известно, что за трендовой частью должна следовать флэтовая часть, чтобы средняя амплитуда оставалась стабильной (а она достаточно стабильна на большом числе выборок). Но рынок не синусоида, и как видно из рисунка 7, с увеличением числа шагов число блоков по вертикали увеличивается. Поэтому буду считать, что отклонение от среднего, возникшее на меньшем числе шагов, совершит возврат к среднему значению на большем числе шагов.

По графику на рисунке 7 посмотрим, сколько в среднем должна проходить цена за 26, 28, 30, 32, 34 шагов:

26 шагов = 3.98; 28 шагов = 4.11; 30 шагов = 4.2; 32 шага = 4.36.

За 24 шага цена уже прошла 8 блоков по вертикали, но за 28 шагов в среднем должна пройти 4.1 блока по вертикали, округляем до целого = 4. Значит, в ближайшее 4 шага возможен откат от предыдущего движения 4 блока. Рынок не настолько предсказуем и маловероятно, что события будут развиваться по данному сценарию. Из того же графика на рисунке 7 можно узнать, что 8 блоков по вертикали цена проходит в среднем за 116 шагов.

rollback 1

rollback 2

Рисунок 8. Возможные варианты развития событий

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

В конечном итоге, амплитуда движений будет стремиться к своему среднему значению. Для 24 шагов — это 3.8 блока по вертикали, а для 116 шагов — это 8 блоков по вертикали.

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

rollback

Рисунок 9. Пример трендового движения и глубины отката

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

Причины такого поведения можно объяснить не только тем, что у ценового ряда есть средняя амплитуда и он ее придерживается, но и тем, что резкие движения вызваны резким притоков/оттоком капитала в актив на суммы, значительно превышающие текущую ликвидность. После того, как позиция на большую сумму открыта, ее нужно закрыть. При этом неважно, кому принадлежал объем средств — одному участнику или несколькими. Если сразу же закрыть позицию на всю сумму, то цена вернется на первоначальный уровень, то есть откат будет 100%. Но если позиция будет закрываться постепенно, учитывая приходящую ликвидность, то большая сумма вызовет меньшее движение. Чем быстрее игрок выходит из позиции, тем сильнее будет откат от движения, которое он создал своим капиталом.

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

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

Отслеживание тренда

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

Робот будет анализировать число падающих и растущих блоков. Если он находит существенное отклонение числа растущих блоков от нормального значения, то генерирует сигнал для серии Sell позиций. Для падающих аналогично, только отклонение падающих блоков генерирует сигнал серии Buy.

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

Пороговый процент для начала и завершения серии

Так как для анализа используется диапазон блоков (например, 24-34), то брать фиксированный пороговый процент для каждого числа блоков — неверное решение. Вероятность появления комбинации из 24 блоков с 75% перевесом преобладающих блоков не равна вероятности появления такой комбинации для 34 блоков. Нужно чтобы вероятность появления комбинаций была одинаковая, значит, пороговый процент нужно использовать динамический, который зависит от вероятности появления данной комбинации.

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

probability table

Рисунок 10. Таблица вероятностей 

На рисунке 10 показана таблица, через которую пересчитывается вероятность попадания в диапазон в процент для открытия.  В таблице принято, что все 100% движений попадут в диапазон от 0 до 16 блоков по вертикали за 16 шагов. Вероятность попадания в диапазон 2.1% (для таблицы на рисунке 10) означает, что только 2.1% всех движений пройдет по вертикали за 16 шагов от 10 до 16 блоков. В настройках задаем вероятность попадания в диапазон, например, 2.2, и алгоритм по таблице ищет ближайшее значение меньше или равно 2.2, потом берет процент, соответствующий этому значению, в данном случае это 81.25%. Так для каждого числа блоков будет свой пороговый процент. Таблицу прикрепил к статье в формате .xlsx.

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

Пороговый процент для закрытия тоже рассчитывается через вероятность попадания в диапазон. Но вероятность попадания в диапазон имеет обратную шкалу. Это непринципиальный момент, просто я так сделал. В таблице для расчета процента закрытия выделен отдельный столбец. Предположим, что я хочу закрыть позиции, когда значение станет больше или равно 75. Тогда находится ближайшее значение больше 75. Для 16 блоков это 78.9, что соответствует пороговому проценту закрытия = 62.5%. 

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

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

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

Разработана методика порогового процента, и можно ответить на вопрос (не используя оптимизацию): какой пороговый процент использовать. Для этого разработана формула:

%open

  • Nb - число блоков для анализа;
  • aa - средняя амплитуда по показаниям индикатора для данного числа блоков;
  • Ka - коэффициент умножения средней амплитуды. Для синусоиды это коэффициент 2, но для рынка нужно сделать настраиваемый, чтобы можно было немного увеличить;
  • Kc - коэффициент умножения средней амплитуды для расчета процента закрытия;
  • %open - пороговый процент начала серии.

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

Процент закрытия тоже можно рассчитать заранее на основе показаний индикатора.

%close;

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

Исходя из анализа средней амплитуды, равной 3.8, можно установить пороговый процент открытия для 24 блоков, равный 66,67%, для остальных значений пересчитать через таблицу вероятностей.

Отслеживание тренда

Как я писал выше, рынок не имеет стабильных закономерностей и стабильной амплитуды колебаний. А анализировать степень тренда на фиксированном числе блоков с фиксированным размером решение сомнительное. Окно для анализа должно быть динамическим и корректироваться в реальном времени. Пусть число блоков для анализа задается диапазоном от 24 до 28. 

Сразу отвечу на необходимый вопрос, почему окно анализа именно 24-28 блоков. Эти значения выбраны на основе средней амплитуды = 3.8 и зависят от порогового процента открытия/закрытия. При таком числе блоков после сигнала на начало серии мы получим 4 блока прибыли. Чем больше блоков в окне для анализа, тем точнее будет работать алгоритм. Принципиальной разницы нет, сколько блоков прибыли получать: 4 или 10, если размер блока будет пропорционально изменен. Но так как позиции будут открываться на каждом новом блоке, то их число будет расти с увеличением точности работы, а это не очень хорошо отразится на результатах. 

Далее нужно определить минимальный размер блока, который имеет смысл анализировать. Блоки строятся по сформированным минутным свечам. Минимальная частота дискретизации получается 1 минута. Нельзя делать блоки слишком маленькие, потому что тогда они начнут строиться внутри свечи, и такой анализ не будет иметь смысла. Поэтому минимальный размер блоков будет определяться на основе размера свечей. Для этого можно использовать индикатор ATR за большой период, например, 1440 минут (сутки) или выше, и умножать его значение на коэффициент. Коэффициент от 2 до 5 должен быть приемлемым, но зависит от особенностей торгового инструмента.

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

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

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

Робот будет анализировать блоки с минимальным размером, но, когда найдет маленький трендовый участок с процентом перевеса выше порогового, должен определить максимальный масштаб на присутствие тренда. Для этого нужно просканировать участок большего размера. Так как число блоков для анализа фиксированное, то нужно увеличить сам размер блоков и посмотреть, что происходит на большем размере блоков. Минимальный размер блоков я назвал TF1 по аналогии с таймфреймом. Это синтетический блоковый таймфрейм. Блоки большего размера будут получены через коэффициент умножения, KTF, например, он будет 1.1.

1. Сигнал на начало серии

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

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

Для коэффициента KTF=1.1 достаточно просмотреть ближайшие 5 таймфреймов, так размер блока самого большего таймфрейма будет в 1.6 раза больше минимального. Если на одном из высших таймфреймов найден сигнал на начало серии, то алгоритм перейдет на этот таймфрейм и сделает его базовым. После того, как найден новый базовый таймфрейм, нужно опять создать 5 таймфреймов большего размера и повторить процедуру сканирования. Так будет найден максимальный таймфрейм с перевесом выше порогового.


work

Анимация 1.

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

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

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

size error

Рисунок 11. Погрешность построения блоков

На рисунке 11 показано, что 10 блоков большего размера могут охватывать меньше данных, чем 10 блоков меньшего размера. Для того, чтобы минимизировать этот эффект, и используется диапазон числа блоков для анализа 24-28. Робот может перейти на больший базовый таймфрейм и увеличить число блоков в выборке. Затем ему будет легче перейти на еще больший таймфрейм с меньшим числом блоков в выборке.

Отвечаю на вопрос: почему именно KTF = 1.1? Чем меньше коэффициент умножения, тем точнее будет работать алгоритм, но тем больше таймфреймов нужно просматривать одновременно. Для того, чтобы размер блока увеличился в 1.6 раза относительно базового таймфрейма, нужно просматривать всего 5 таймфреймов. Если сделать KTF = 1.05, то придется просматривать уже 10 таймфреймов, а это дополнительная вычислительная нагрузка. Но чем меньше коэффициент умножения, тем точнее работает.

2. Задержка открытия позиций

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

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

а) Задержка по трендовому участку

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

delay a

Рисунок 12. Задержка открытия позиций для перехода на высший таймфрейм

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

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

б) Задержка на основе статистических характеристик инструмента

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

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

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

formula dalay;

  • Vb — число преобладающих блоков для начала серии;
  • mnb  — минимальное число блоков из диапазона для анализа. Если диапазон 24-28, то это 24 блока;
  • Nd  — число задержки;
  • Bsd  — размер блока высшего таймфрейма;
  • BSB  — размер блока базового таймфрейма;
  • kfd  — коэффициент умножения для коррекции числа блоков задержки;
  • addkfd  — коэффициент прибавления для коррекции числа блоков задержки.

Пример: пусть mbn=24; %open=75; BSB=0.00064; Bsd= 0.0007. Тогда Vb=18. Значит, из 24 блоков 18 должно быть одного направления. Считаем, сколько пунктов цена прошла за 18 блоков на базовом таймфрейме. Для этого 18*BSB = 0.01152, рассчитываем сколько цена должна пройти за 18 блоков высшего таймфрейма. Для этого 18*Bsd = 0.0126, находим сколько пунктов не хватает, чтобы были сформированы все блоки высшего таймфрема. Для этого 0.0126-0.01152=0.00108, и делим полученное значение на размер блока высшего таймфрейма. Nd=0.00108/0.0007=1.54. Получилось, что 1.54 блока не хватает для того, чтобы перейти на высший таймфрейм.

Полученное значение справедливо, если цена движется строго вертикально, но она не движется строго вертикально, и из 24 блоков только 18 одного направления и 6 другого. Поэтому 1.5 блока нужно пересчитать в правильное число блоков для данного торгового инструмента, так получится значение Nbd = 3. Значит реально, учитывая характеристики трендового движения данного торгового инструмента, нужно подождать формирования трех блоков высшего таймфрейма.

Но просто так ждать, пока пройдет нужное число блоков задержки (3 из примера), неэффективно. Ждать имеет смысл, только если цена идет в направлении найденного тренда и переход на высший таймфрейм возможен. Нужно взять минимальное число блоков Nd, умножить на размер блока Bsd и отложить нужное число пунктов от цены закрытия блока базового таймфрейма в сторону тренда. Это будет контрольная точка, до которой должна дойти цена, чтобы был возможен переход на высший таймфрейм. Теперь после закрытия каждого нового блока высшего таймфрейма нужно проверять, хватит ли оставшихся блоков, чтобы цена достигла установленной контрольной точки. 

Например: Nbd = 3 блока, тренд падающий. Рассчитали контрольную точку, она на расстоянии 1.54 блока вниз от цены закрытия блока базового таймфрейма. Сформировался падающий блок высшего таймфрейма, потом сформировался растущий блок и остался 1 блок задержки. Ждать дальше смысла нет, потому что если сформируется еще 1 блок задержки, то он уже не пересечет контрольную точку. Стало известно, что продолжать задержку смысла нет, переход на высший таймфрейм не состоится, можно открывать позицию. 

Как это работает, показано на анимации 2.

work 2

Анимация 2.

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

Видно, что тест начинается с блоков маленького размера, и далее алгоритм, отслеживая тренд, увеличивает размер блоков. После того, как максимальный размер тренда определен, происходит открытие позиции. Далее рассчитывается откат от этого тренда. Для синусоиды откат 100%, поэтому рассчитывается точка закрытия и устанавливается take profit. Я выбрал синусоиду для визуализации и упрощения понимания процесса работы. Видно, что алгоритм использует почти всю амплитуду синусоиды для получения прибыли, кроме небольшого участка 2 блока в начале нового трендового участка.

3. Сопровождение серии

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

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

Заключение

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

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

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

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

Предыдущие статьи на эту тему

Разработка самоадаптирующегося алгоритма (часть I): поиск базовой закономерности
Разработка самоадаптирующегося алгоритма (часть II): повышение эффективности 



Прикрепленные файлы |
TZ-50cV3.zip (638.45 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (30)
Jacob James
Jacob James | 1 февр. 2021 в 01:29

Please attach the sample MT5 EA for us to follow your ideas and test your theory.

Maxim Romanov
Maxim Romanov | 1 февр. 2021 в 07:48
Jacob James:

Please attach the sample MT5 EA for us to follow your ideas and test your theory.

The algorithm is not distributed in the public domain, but in the next article I will show how it works using the example of backtests.

Amba404
Amba404 | 9 февр. 2021 в 09:56

Приветствую.

Некоторые соображения и их результаты. Немножко длинно.

Два подхода к анализу отклонений блоков: график есть случайное блуждание - применяем стат.функции (на факториалах и пр.) или график не-совсем-случайное движение - используем стат. данные по движениям прошлого. Если достаточное время следили за формированием графика блоков, то, наверное, заметили, что график зависит от начальной точки построения. Если мы строим график на каждом открытии свечи, то получаем на свече N график немного не такой, как на N+1. Отсюда два варианта для формирования стат.данных по прошлым блокам: также на каждом открытии свечи или периодически, например, раз в (час/день/неделю), но при этом и график блоков должен строиться от той же нулевой точки. Подход с обсчетом всего и вся заново на каждом баре возможен, но он очень медленный.

Я отчаялся с таким вариантом что-то подобрать/проверить в тестере, и все догадки или оптимальные параметры проверял на демо, в онлайн, контролируя результаты по графику изменения Эквити/баланса тоже онлайн. Должен сказать, что на тех коротких периодах (последний с 21/01 по текущее время) алгоритм (ну, как я его понял и реализовал) достаточно устойчив. Открывал, кстати, не на каждом баре при сигнале, а при новом сигнале (т.е. был сигнал buy на H блока 150п, купил, следующий открывал на Buy H=165, и то, если оно в минус идет. Т.к. при положительном развитии дисбаланс в блуждании уменьшается, соответственно, и сигнал пропадает), В stopout ушел только один демо-счет из 8, с очень агрессивными настройками, при балансе 1000$ и плече 1:1000 использовал 48 валютных пар, металлы, 2 нефти, без контроля хеджа по валютам ("хедж" - когда купили USDJPY, нельзя купить USDCAD, но можно купить EURUSD и т.д на всем наборе символов, в статье есть), на сделку выделял 10$, лот адаптивный, зависит от размера блока, выход только по накопленному профиту на сумме сделок по символу или по сумме профита по всем открытым символам.

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

Возвращаясь к способу расчета блоков. Я сейчас использую такой вариант. Берем опорную точку - закрытие предыдущей пятницы. От нее строим (1 раз!) в прошлое наборы блоков с высотами как в статье (*1.1). За начальную высоту принял (iATR(sy, PERIOD_M1, 1440) X 5) от начальной точки. Наборы сразу строим длиной StepMax+MAX_STAT (например, 48+1000), и вычисляем распределение частот пробега и пр. для каждой длины в блоках (пусть от 24 до 48). Далее на каждом новом баре достраиваем наборы вперед, ищем сигнал для каждого H  в диапазоне длин (к примеру)  [24;48] блоков, ориентируясь на рассчитанную ранее статистику, выбираем подходящий, принимаем решение об открытии нового, закрытии/наращивании старого и пр... Данный подход дает значительный прирост в скорости расчетов, и, полагаю, не сильно отличается от предложенного в статье (расчет "с нуля" на каждом баре). При этом появляются некоторые дополнительные возможности. В частности, если в течение недели уровни не изменяются, то при наличии сигнала на H=180п (к примеру) можно расставить сетку ордеров в ожидаемом направлении движения...

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

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

Проверял на наборе символов "28 мажоров" и на наборах для каждого мажора (*AUD* и т.п.). Это уже в МТ5. Проверял разные периоды, параметры построения блоков, различные нюансы входа-выхода...

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

Maxim Romanov
Maxim Romanov | 9 февр. 2021 в 13:30
Amba404:

Приветствую.

Некоторые соображения и их результаты. Немножко длинно.

Два подхода к анализу отклонений блоков: график есть случайное блуждание - применяем стат.функции (на факториалах и пр.) или график не-совсем-случайное движение - используем стат. данные по движениям прошлого. Если достаточное время следили за формированием графика блоков, то, наверное, заметили, что график зависит от начальной точки построения. Если мы строим график на каждом открытии свечи, то получаем на свече N график немного не такой, как на N+1. Отсюда два варианта для формирования стат.данных по прошлым блокам: также на каждом открытии свечи или периодически, например, раз в (час/день/неделю), но при этом и график блоков должен строиться от той же нулевой точки. Подход с обсчетом всего и вся заново на каждом баре возможен, но он очень медленный.

Я отчаялся с таким вариантом что-то подобрать/проверить в тестере, и все догадки или оптимальные параметры проверял на демо, в онлайн, контролируя результаты по графику изменения Эквити/баланса тоже онлайн. Должен сказать, что на тех коротких периодах (последний с 21/01 по текущее время) алгоритм (ну, как я его понял и реализовал) достаточно устойчив. Открывал, кстати, не на каждом баре при сигнале, а при новом сигнале (т.е. был сигнал buy на H блока 150п, купил, следующий открывал на Buy H=165, и то, если оно в минус идет. Т.к. при положительном развитии дисбаланс в блуждании уменьшается, соответственно, и сигнал пропадает), В stopout ушел только один демо-счет из 8, с очень агрессивными настройками, при балансе 1000$ и плече 1:1000 использовал 48 валютных пар, металлы, 2 нефти, без контроля хеджа по валютам ("хедж" - когда купили USDJPY, нельзя купить USDCAD, но можно купить EURUSD и т.д на всем наборе символов, в статье есть), на сделку выделял 10$, лот адаптивный, зависит от размера блока, выход только по накопленному профиту на сумме сделок по символу или по сумме профита по всем открытым символам.

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

Возвращаясь к способу расчета блоков. Я сейчас использую такой вариант. Берем опорную точку - закрытие предыдущей пятницы. От нее строим (1 раз!) в прошлое наборы блоков с высотами как в статье (*1.1). За начальную высоту принял (iATR(sy, PERIOD_M1, 1440) X 5) от начальной точки. Наборы сразу строим длиной StepMax+MAX_STAT (например, 48+1000), и вычисляем распределение частот пробега и пр. для каждой длины в блоках (пусть от 24 до 48). Далее на каждом новом баре достраиваем наборы вперед, ищем сигнал для каждого H  в диапазоне длин (к примеру)  [24;48] блоков, ориентируясь на рассчитанную ранее статистику, выбираем подходящий, принимаем решение об открытии нового, закрытии/наращивании старого и пр... Данный подход дает значительный прирост в скорости расчетов, и, полагаю, не сильно отличается от предложенного в статье (расчет "с нуля" на каждом баре). При этом появляются некоторые дополнительные возможности. В частности, если в течение недели уровни не изменяются, то при наличии сигнала на H=180п (к примеру) можно расставить сетку ордеров в ожидаемом направлении движения...

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

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

Проверял на наборе символов "28 мажоров" и на наборах для каждого мажора (*AUD* и т.п.). Это уже в МТ5. Проверял разные периоды, параметры построения блоков, различные нюансы входа-выхода...

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

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

В тестере я проверял и покажу в следующей статье много тестов того, как это работает. На демо долго и не информативно. Тест 1 года по 28 валютным парам у меня занимает 15 суток (Ryzen 3700). В том виде, в котором это описано, доходности не велики, но он проходит бектесты очень устойчиво. Сейчас улучшаю алгоритм.

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

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

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

В общем алгоритм - заготовка и на данном этапе его задача не сливать и хоть что-то зарабатывать.

Gennady Sergienko
Gennady Sergienko | 8 мая 2021 в 10:27
Спасибо, великолепная статья! есть пища для ума.
Поиск сезонных закономерностей на валютном рынке с помощью алгоритма CatBoost Поиск сезонных закономерностей на валютном рынке с помощью алгоритма CatBoost
В статье показана возможность создания моделей машинного обучения с временными фильтрами и раскрыта эффективность такого подхода. Теперь можно исключить человеческий фактор, просто сказав модели: "Хочу, чтобы ты торговала в определенный час определенного дня недели". А поиск закономерностей возложить на плечи алгоритма.
Рынок и физика его глобальных закономерностей Рынок и физика его глобальных закономерностей
В данной статье я постараюсь проверить предположение о том, что любая система, имеющая под собой даже небольшое понимание рынка, способна работать в глобальном масштабе. Я не буду придумывать какие-то теории или законы, а буду размышлять только исходя из известных всех фактов, постепенно переводя известные нам факты на язык математического анализа.
Работа с ценами в библиотеке DoEasy (Часть 60): Список-серия тиковых данных символа Работа с ценами в библиотеке DoEasy (Часть 60): Список-серия тиковых данных символа
В статье создадим список для хранения тиковых данных одного символа и проверим его создание и получение из него требуемых данных в советнике. Такие списки тиковых данных — свой для каждого используемого символа — далее будут составлять собою коллекцию тиковых данных.
Нейросети — это просто (Часть 9): Документируем проделанную работу Нейросети — это просто (Часть 9): Документируем проделанную работу
Мы уже проделали довольно большой путь, и код нашей библиотеке сильно разрастается. Становится сложно отслеживать все связи и зависимости. И конечно, перед продолжением развития проекта нам нужно задокументировать уже проделанную работу и актуализировать документацию на каждом последующем шаге. Правильно подготовленная документация поможет нам увидеть целостность нашей работы.