Секреты TSLab | Торговые роботы | События
19 Май

Адаптивные индикаторы TSLab. Высший пилотаж.

TSLab существует уже достаточно давно, и так же давно существует набор стандартных индикаторов в нем. Среди них SMA, EMA, ATR и тому подобные.  Но всегда хотелось чего-то большего. Были многочисленные просьбы добавить индикаторы, параметры которых можно было бы задавать подавая на один из входов кубика некое число. Таким образом, можно было бы получить индикаторы имеющие способность к адаптации к текущей рыночной ситуации. Проще говоря, все хотели иметь адаптивные индикаторы. Команда RusAlgo напряглась и выдала набор адаптивных индикаторов. В этой статье разберем принципы создания и особенности работы таких индикаторов.

Адаптивные индикаторы. Что это? Зачем это?

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

Адаптивная скользящая средняя Кауфмана (AMA, KAMA, AMkA от англ.Kaufman’s Adaptive Moving Average) — технический индикатор, разновидность адаптивной скользящей средней, построенной на базе экспоненциально сглаженной скользящей средней и оригинальной методики определения и применения волатильности в качестве динамически изменяющейся сглаживающей константы

Если ввести в google запрос “адаптивная скользящая”, то результатов будет тьма.

адаптивные индикаторы tslab. высший пилотаж.

Рисунок 1. Что гугл знает об адаптивных скользящих.

Поисковик отлично знает о существовании адаптивных скользящих и есть большое количество статей на эту тему, возможно, друг у друга содранных :). А давайте теперь дадим запрос “адаптивные индикаторы” и посмотрим итоги.

адаптивные индикаторы tslab. высший пилотаж.

Рисунок 2. Что гугл знает об адаптивных индикаторах.

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

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

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

Адаптивная скользящая средняя. Реализация.

Разбирать основные фичи будем на примере “aSma” (простая адаптивная скользящая средняя). В остальных индикаторах все похожим образом реализовано, за исключением индикаторов где применяется EMA. Определим исходные параметры нашего индикатора:

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

Режим потоковой работы

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

    [HandlerCategory("RusAlgo")]
    [HandlerName("Adaptive SMA")]
    public class ASma : ITwoSourcesHandler, IDoubleInput0, IDoubleInput1, IDoubleReturns, IStreamHandler, IContextUses
    {
        public IContext Context { set; private get; }

        public IList<double> Execute(IList<double> price, IList<double> period)
        {
            var values = new double[Context.BarsCount];

            for (var i = 0; i < Context.BarsCount; i++)
            {
                var currPeriod = Math.Max(Convert.ToInt32(period[i]), 1);
                // использую хеш код объекта цен, чтобы фильтрануть разные списки цен и считать по разному.
                var sma = Context.GetData("AdaptiveSmaRusAlgo",
                                          new[]
                                              {
                                                  currPeriod.ToString(CultureInfo.InvariantCulture),
                                                  price.GetHashCode().ToString(CultureInfo.InvariantCulture)
                                              },
                                          () => Series.SMA(price, currPeriod));
                values[i] = sma[i];
            }
            return values;
        }

Внутри метода “Execute()” мы применяем кэш скриптов и про него следует рассказать отдельно. Все остальные элементы типичны и про них не буду распространяться. Представим что на входе у нас две последовательности цифр, где вторая является периодами скользящей.

> data = c(1,4,6,8,23,45,4,3,2,1); data;
 [1]  1  4  6  8 23 45  4  3  2  1
> periods = c(1,4,3,1,2,1,3,5,1,2); periods;
 [1] 1 4 3 1 2 1 3 5 1 2
> SMA(data, periods[1]);
 [1]  1  4  6  8 23 45  4  3  2  1

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

> SMA(data, periods[2]);
[1]  0.25 1.25 2.75 4.75 10.25 20.50 20.00 18.75 13.50  2.50

для четвертого бара расчет скользящей будет точно такой же как и для бара 1. Но если мы в момент расчета бара 1 произвели кэширование данных, то сейчас нам будет достаточно просто вытащить расчет из кэша и взять значение для нужного бара. Я думаю это круто сократит количество расчетов и естественно ваш скрипт будет работать быстрее. Можете попробовать убрать кэширование и посмотреть на скорость работы индикатора. Вся хитрость заключена в том, что мы избегаем повторных расчетов скользящих для повторяющихся периодов и экономим на процессорных тактах. В противовес экономии процессора, мы получаем значительную нагрузку на память. Чем больше у нас свечек, и чем больший диапазон покрывают значения периода, тем больше памяти будет тратиться на кэш и больше памяти ваш ПК должен иметь на борту. Вообще рекомендуется адаптивные индикаторы использовать только для x64 версии TSLab  иначе, легко можете получить нехватку памяти. При кэшировании значений используется странный способ формированию ключа кэша, что может вызвать непонимание. Но давайте представим что мы формируем ключ кэша обычным способом:

var sma = Context.GetData("AdaptiveSmaRusAlgo",
                                          new[] {currPeriod.ToString(CultureInfo.InvariantCulture)},
                                          () => Series.SMA(price, currPeriod));

А теперь добавим два разных инструмента в скрипт и посчитаем от цен закрытия инструментов адаптивную скользящую. Что получим? Полный бред :). При расчете первой скользящей от первого инструмента в кэшэ скрипта появится куча записей с ключами “AdaptiveSmaRusAlgo1″, “AdaptiveSmaRusAlgo3″ и так далее. Когда начнет считаться вторая скользящая она просто не поймет что данные в кэшэ принадлежат другому инструменту и будет брать их для своих нужд. В итоге расчеты перемешаются и будет полный коллапс. Чтобы такого избежать мы ввели некий уникальный идентификатор “price.GetHashCode()”, который в текущих условиях вполне может служить для формирования правильного ключа, ведь для разного набора исходных данных будет разный хеш код.

Режим последовательной работы

Добрались, наконец, и до реализации работы с последовательными значениями.  Обычно это делается через IValuesHandler, но тут такой метод не подходит. У нас на входе два ряда данных а не один, как обычно. Для таких случаев есть спец интерфейс “IValuesHandlerWithNumber”, именно для блоков с двумя и более входами. Нарисуем то, что получилось, убрав часть для потоковых данных.

    [HandlerCategory("RusAlgo")]
    [HandlerName("Adaptive SMA")]
    public class ASma : ITwoSourcesHandler, IDoubleInput0, IDoubleInput1, IDoubleReturns, IValuesHandlerWithNumber
    {
        private double[] _dataCache;

        public double Execute(double price, double period, int barNum)
        {
            if (_dataCache == null)
                _dataCache = new double[Context.BarsCount];

            _dataCache[barNum] = price;

            var currPeriod = Math.Max(Convert.ToInt32(period), 1);
            // собираем все данные начиная с текущей свечки и назад на величину периода
            var currData = _dataCache.CopyCountTo(barNum, currPeriod, false);

            // проверочка на случай кривизны
            if (currData.Last() != price)
                throw new Exception("Чтото не так.");

            var values = Series.SMA(currData, currPeriod);
            return values.Last();
        }
    }

Как видно, в наш индикатор поступают только 2 числа и номер бара,  и нам нужно как то рассчитывать скользящую для этого номера бара. Чтобы такое стало возможно применяем стандартную схему с приватным полем “_dataCache” в которое будем складывать приходящие к нам данные с первого входа. Ведь обычно, данные в кубик приходят по-порядку, и мы можем сохранять все прошлые данные в поле “_dataCache”, чтобы по ним делать расчет скользящей на текущем баре.

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

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

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

Итоги

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

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

Адаптивная экспоненциальная скользящая средняя. Особенности индикаторов с EMA внутри.

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

        public double Execute(double price, double period, int barNum)
        {
            if (_dataCache == null)
                _dataCache = new double[Context.BarsCount];

            _dataCache[barNum] = price;

            var currPeriod = Math.Max(Convert.ToInt32(period), 1);
            var currData = _dataCache.CopyCountTo(barNum, currPeriod*5, false);

            // проверочка на случай кривизны
            if (currData.Last() != price)
                throw new Exception("Чтото не так.");

            var values = Series.EMA(currData, currPeriod);
            return values.Last();
        }

Путем экспериментов было выяснено, что 5 периодов индикатора достаточны для нивелирования влияния прошлых значений на текущее. Хотя в статье “3 вещи которые вы не знали о EMA” показано, что это влияние не всегда полностью устраняется. В итоге, мы для периода 3 берем не 3 значения а 15 и по ним считаем EMA. Аналогично делаем для всех индикаторов где имеется EMA. Вы можете это посмотреть сами в коде.

 

Итоги

  • Адаптивные индикаторы возможны :)
  • Это не очень сложно, но нужны знания тонкостей работы TSLab.
  • Адаптивные индикаторы это ново и мало используется.


comments powered by HyperComments

Yury Gritsenko
2015-04-26 11:41:26
А возможен ли обратный процесс? А.и. то что удалось создать в TSLab, скрипты, индикаторы, подключить в другую программу к примеру S#?
ra81
2015-04-26 20:33:39
Боюсь что невозможно. Слишком разные парадигмы у этих программ. Вообще, если вы сделаете что то в TSLab у вас не будет повода переносить это в S# потому что долго, муторно и просто зачем? Ведь можно взять и запустить торговать.
Павел Дуков
2015-12-01 21:30:39
спасибо
Расима
2017-01-01 21:02:07
Секс знакомства http://bit.ly/2hkF2s9
8
Сен
2017

Доверительное управление. Результаты в августе 2017 года.

Доверительное управление. Результаты в августе 2017 года. Стратегия “Опционы” принесла в августе прибыль в размере… »

6
Авг
2017

Доверительное управление. Результаты в июле 2017 года.

Доверительное управление. Результаты в июле 2017 года. В июле индекс РТС вновь колебался в достаточно узком… »

14
Июл
2017

Доверительное управление. Результаты в июне 2017 года.

Доверительное управление. Результаты в июне 2017 года. Июнь индекс РТС вновь провел преимущественно в боковых движениях, а… »

11
Июн
2017

Доверительное управление. Результаты в мае 2017 года.

Доверительное управление. Результаты в мае 2017 года. В мае “болтанка” индекса РТС продолжилась, на паре… »

7
Май
2017

Доверительное управление. Результаты в апреле 2017 года.

Доверительное управление. Результаты в апреле 2017 года. В апреле мы наблюдали очередной месяц “боковика” по… »