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

Кэш скриптов для чайника. Часть 3.

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

Кэш скриптов – хранитель важного

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

using TSLab.Script;
using TSLab.Script.Handlers;

namespace test
{
    public class StoreLoadExecCounter : IExternalScript
    {
        public void Execute(IContext ctx, ISecurity sec)
        {
            var cache = ctx.LoadObject("counter");
            var counter = cache == null ? 0 : (int) cache;
            counter++;
            ctx.StoreObject("counter", counter);
            ctx.Log("Число запусков == " + counter, new Color(), true);
        }
    }
}

В строке 10, мы запрашиваем данные из кэша для ключа “counter”. Важно помнить, что данных может и не быть, тогда метод возвращает null. Для этого в строке 11 я добавил проверку. Сам метод возвращает данные типа object, поэтому я так же добавил преобразование типа. Тут главное не ошибиться, и преобразовать к правильному типу данных. Какой тип кладете в кэш, такой тип будете и извлекать из него. Ну, а дальше все просто. Я увеличиваю счетчик на единицу и сохраняю новое значение в кэш скриптов под ключем “counter”. Когда случится следующий пересчет, вся процедура повторится заново.

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

Кэш скриптов для чайника. Часть 3.

Рисунок 1. Результат работы скрипта.

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

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

Сохранение данных между пересчетами на практике

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

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

using System.Linq;
using TSLab.Script;
using TSLab.Script.Handlers;

namespace test
{
    public class StoreLoadQueue : IExternalScript
    {
        public void Execute(IContext ctx, ISecurity sec)
        {
            // получаем стаканы
            var buyQ = sec.GetBuyQueue(0);
            var sellQ = sec.GetSellQueue(0);

            // считаем сумму объемов по пок и по прод
            var buyVolume = buyQ.Sum(d => d.Quantity);
            var sellVolume = sellQ.Sum(d => d.Quantity);

            // читаем кэш и сравниваем стаканы если в кэшэ чтото есть
            var cache = ctx.LoadObject("queue");
            if (cache == null)
            {
                var qRec = new QRec() { BuyVolume = buyVolume, SellVolume = sellVolume };
                ctx.StoreObject("queue", qRec);
                ctx.Log("В кэшэ стакана не было", new Color(), true);
            }
            else
            {
                var qRec = (QRec)cache;
                if (qRec.BuyVolume - qRec.SellVolume > buyVolume - sellVolume)
                    ctx.Log("Перевес покупцов уменьшился.", new Color(), true);
                else
                    ctx.Log("Перевес покупцов увеличился.", new Color(), true);

                qRec.BuyVolume = buyVolume;
                qRec.SellVolume = sellVolume;
            }
        }

        class QRec
        {
            public double BuyVolume { get; set; }
            public double SellVolume { get; set; }
        }
    }
}

Обратите пристальное внимание на блок кода if-else. Если у нас кэш еще пустой, тогда мы просто сохраняем стакан в кэшэ. Если кэш содержит стакан, мы не производим сохранение стакана в кэш, мы просто изменяем свойства текущего объекта находящегося в стакане (строки 35 и 36). Принципы передачи объектов в методы говорят, что передается только ссылка на объект, при этом сам объект не копируется. Такой способ передачи называется “передача по ссылке”. Естественно, когда мы запрашиваем кэш через LoadObject(), мы получаем ссылку на объект. В дальнейшем мы можем просто изменять сам объект без пересохранения оного в кэш. Это бывает очень удобно. В первом примере с кодом мы сохраняли счетчик заново потому, что int всегда передается “по значению” путем копирования, и “ход конем” совершить не удастся.

ВАЖНО: кэш скрипта доступный через методы Load/Store сбрасывается только в момент пересборки скрипта (кнопка сохранить и выполнить). То есть, и в лаборатории и в агенте данные кэша будут доступны между пересчетами. Именно это и позволяет сохранять что-то полезное на одном пересчете скрипта и использовать это на другом пересчете. Как ранее указывалось, метод GetData() работает иначе.

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

Продолжение следует в четвертой части


comments powered by HyperComments

Андрей
2015-04-26 17:50:03
Родион, добрый день! Вы пишите, что ctx.StoreObject("counter", counter); не стирается между пересчетами? А в другой статье http://rusalgo.com/article/%D1%82%D0%BE%D1%80%D0%B3%D0%BE%D0%B2%D1%8B%D0%B9-%D1%80%D0%BE%D0%B1%D0%BE%D1%82-%D0%B1%D0%B5%D0%B3%D0%B5%D0%BC%D0%BE%D1%82.html вы пишите, что "дисконнект брокера приводит к обнулению кэша скрипта". Вопрос: что еще приводит к обнулению кэша? Что еще нужно знать для работы с ним?
ra81
2015-04-26 20:39:26
Да есть такая беда. Дисконнекты брокера обнуляют кэш. В итоге для защиты от такой гадости пришлось делать кэширование на диск. Но часто это не нужно. Все зависит от задачи. К обнулению кэша порой приводят какие то глюки, в результате чего кэш обнуляется каждый пересчет. До конца причина не была найдена, но наблюдалось такое.
Андрей
2015-04-26 23:22:31
А если в глобальный кэш сохранять? Или он тоже обнуляется при дисконнекте (как и при выключения ТСЛаба)? Так может правильнее самописный метод сделать, с записью/чтением данных на диске? ТСЛаб поддерживает запись на диск? Или это только как резервный вариант предусмотреть, чтобы программа при кэш == null обратилась к записанному файлу?
ra81
2015-04-27 12:55:56
глобальный не удаляется при дисконнекте. Но тут нужно будет зачищать его самому при штатной остановке скрипта. Тоже проблема. На диск можно писать из скрипта. То есть придется нарисовать свою примочку которая бы сохраняла данные на диск и считывала оттуда если в кэшэ пусто. При этом имеет смысл задать лимит на свежесть кэша. а то загрузит недельной давности :)
Андрей
2015-05-13 11:22:32
Родион, доброе утро! Подскажите, пожалуйста, а где хранится кэш? Записывается на диск или в ОЗУ? Сделал запись размера стопа в кэш, но работало очень нестабильно в первые минуты торговли - часто выбрасывало по стопсигналу, хотя в реальности, судя по графику цены, стоп сносить не должно было. Но если в первые минуты не выбрасывало, то потом работало нормально. Отключил кэш и написал метод самостоятельной записи/чтения на диск/с диска - стало работать гораздо стабильнее...
Андрей
2015-05-13 13:18:54
Сорри, кэш, по все видимости, не виноват. Для эксперимента в одном из скриптов поставил условие (bar == barsCount - 1) Проблема исчезла. Пока все работает стабильно Скорее, проблема возникала при пересчетах. А где - не пойму, т.к. при открытии позиции размер стопа брался уже только из кэша (или из файла при кэш == null)
ra81
2015-05-14 20:15:48
кэш в 1.2 хранится в памяти. но он скидывается каждый раз при дисконнекте брокера. или рестарте агента. Так что с этим надо быть осторожным.
ra81
2016-03-09 19:02:09
1) написать свой класс для этого что мы сделали. Это явствует из статьи про робота бегемота или хомяка. 2) проверяйте наличие кэша перед использованием. примеры даны в этой серии статей. нет никакой гарантии что приемник запустится после источника. Так что как то тут надо решать вопрос.
Сергей
2016-02-23 13:13:24
Добрый день Родион. 1. Как сделать кеширование на диск. 2. Как обойти такую ситуацию: В скрипте-источнике ключ формируется по названию параметра и плюс дата бара. T.e. пишется какой-то массив данных с индексом от времени. ctx.StoreGlobalObject("par + data", value); - в скрипте-источнике еще не создан кеш- обьект, а скрипт приемник уже пытается его читать. При этом он сразу вылетает по ошибке 13:12:35.31 System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта. 3. Пишу это и думаю- а может забить на самом первом баре на год вперед кэш какими-нибудь данными-т.е проинициализировать его? Прокатит, нет?
Иван
2017-01-01 03:48:54
Секс знакомства http://bit.ly/2hkF2s9
14
Июл
2017

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

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

11
Июн
2017

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

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

7
Май
2017

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

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

2
Апр
2017

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

Доверительное управление. Результаты в марте 2017 года. В марте волатильность на рынке несущественно выросла. Все… »

7
Мар
2017

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

Доверительное управление. Результаты в феврале 2017 года. Февраль был самым коротким торговым месяцем, к тому же… »