При разработке скриптов приходится работать с большими массивами данных. Создание и удаление больших массивов трудозатратный процесс. Если в скрипте часто создаются большие массивы, то загрузка процессора может просесть, что сказывается на времени оптимизации.
Чтобы этого избежать, можно использовать внутренний пул массивов в TSLab. Это работает только для оптимизации.
Пул массивов - это коллекция массивов, которые находятся в памяти. Например, запускаем оптимизацию скрипта. В скрипте запрашиваем новый массив из пула. Пул ищет у себя подходящий свободный массив, по типу и длине данных. Если такого массива в пуле нет, то он создается. Далее скрипт помещает в этот массив свои данные, производит вычисления, выводит их на график если надо. После выполнения скрипта контекст данных освобождается, и все массивы из пула, которые были использованы в этом контексте, очищаются и помещаются обратно в пул. Далее, при проходе следующего итерации оптимизации, скрипт запрашивает массив из пула и действия повторяются. Таким образом, сокращается количество создаваемых массивов.
При освобождении контекста массив будет помещаться обратно в пул, только если он не закеширован.
Методы:
T[] IContext.GetArray<T>(int count) – получить массив с типом T и количеством элементов count из пула. Если в пуле нет такого массива, то он создается.
void ReleaseArray(Array array) – передать обратно массив в пул. При этом массив очищается. Метод ReleaseArray вызывается автоматически при освобождении контекста (IContext), после прохода оптимизации (если массив не был помещен в кеш).
Рассмотрим пример. Создадим массив с double числами, поместим в него среднюю цену бара и в конце выведем в лог хеш-код этого объекта.
Теперь проведем оптимизацию, только в настройках TSLab поставим 'Количество потоков оптимизации' равное 1. Это нужно чтобы проверить как часто у нас создается новый массив. Так как указали количество потоков 1, то сначала пройдет один проход итерации, потом второй и так далее, друг за другом. В логе мы видим разные значения хеш-кодов. Это означает, что при каждом проходе оптимизации создавался новый массив.
Теперь мы немного изменим наш пример, вместо создания массива будем получать его из пула: var arr = ctx.GetArray<double>(bars.Count);
Запускаем оптимизацию, снова с одним потоком. В логе мы видим одинаковый хеш-код. Это означает что во всех итерациях оптимизации использовался только один массив. Мы брали его из пула, использовали, при завершении итерации он помещался обратно в пул. При следующей итерации мы снова берем этот же массив из пула.
Что будет если в настройках поставить максимальное количество потоков и запустить оптимизацию на 10000 проходов? Оптимизация запустится на всех имеющихся потоках процессора. При каждой итерации будет браться массив из пула, обрабатываться и помещаться обратно в пул. Но так как потоков теперь у нас много, то теперь одного массива в пуле на всех не хватит. В этом случае будут созданы дополнительные массивы в пуле. И в конце оптимизации окажется что количество массивов в пуле равно количеству потоков. Хотя проходов у нас было 10000.
Во многих стандартных блоках TSLab используется пул массивов. Например блок расчета ATR:
Заметка: Пул потоков в TSLab это аналог ArrayPool из .NET Core.
C++/CLI — один из языков платформы .NET Framework — редко используется для разработки больших самостоятельных проектов. Его главное назначение — создание сборок для взаимодействия .NET с родным (неуправляемым) кодом.
В TSLab можно подключать скрипты написанные на C#, VB.NET. Или подключать библиотеки dll написанные на .NET (C#, VB.NET, C++/CLI).
Для примера, напишем библиотеку на C++/CLI и подключим в TSLab.
И так, создадим новый проект в Visual Studio 2019. Выберем тип: CLR Class Library на языке C++.
Сразу переключим проект на x64, добавим библиотеки TSLab.Script.dll, TSLab.Script.Handlers.dll, TSLab.DataSource.dll.
Пример скрипта возьмем из статьи Первый скрипт (API) написанный на C#, но мы его переделаем на C++. Создадим класс BuyScript, и напишем следующий код:
Теперь можно собрать проект и если нет ошибок, то студия создаст библиотеку \x64\Debug\TestLibC.dll ее и подключим в TSLab.
Как видим, скрипт подключился, на графике отобразились сделки.
IContext.ScriptResults - Вычисляемые пользователем значения, которые отображаются на вкладке общих результатов скрипта и на вкладке результатов оптимизации. Это свойство имеет тип Dictionary. В котором, ключ - это название поля, а значение - это число double.
Это "не официальная" возможность. Мы не афишировали возможность делать свои оптимизаторы.
В версии 1.2 при выборе оптимизатора мы попадаем в Name а затем в GetMetodParameters() Это нужно, чтобы представить параметры оптимизатора, как параметры стратегии.
В версии 2.0 Параметры оптимизатора должны появляться под параметрами блоков
На контрольной панели можно размещать значения индикаторов, кнопки, текст.
Создать контрольную панель: var controlPane = ctx.CreateControlPane("Control", "Control", "My control");
Первый элемент "Control" – уникальный id элемента.
Второй элемент "Control" – название панели
Третий элемент "My control" – заголовок панели, если он не указан, то значение будет браться из названия панели.
Добавить элемент на контрольную панель: var pane = controlPane.AddControl("SMA", "", ControlParameterType.NumericUpDown, true, 0, 0, double.NaN, double.NaN, false, false, null, Period);
"SMA" - название элемента
"" - название свойства, если пустое, то будет браться название последней переменной, в данном случае Period.
ControlParameterType.NumericUpDown - тип элемента, в данном случае число с элементом управления.
Period - параметр скрипта OptimProperty
Пример: Добавим индикатор SMA и контрольную панель. На контрольную панель выведем значение индикатора. При изменении значения будет пересчитываться скрипт и меняться индикатор SMA.