В посте «Как получать значения индикаторов в скрипте на LUA?» я обещал опубликовать соображения о том, как снизить нагрузку на терминал QIUK при частом обращении к встроенным функциям (например, getIndicatorData) за счет запуска скрипта только в момент формирования нового бара. Настоящим выполняю обещанное.
Надежный способ сделать это — использовать флаг (переменную-индикатор) и функцию обратного вызова OnCalculate.
Основная идея
Суть метода в запоминании скриптом факта обработки текущей свечи. Если свеча новая, флаг сброшен, скрипт выполняет код и поднимает флаг. Пока свеча не закрылась и не открылась новая, флаг остается поднятым. Код повторно не выполняется.
Пошаговая реализация
-- Объявляем глобальную переменную-флаг. Она будет хранить номер последнего обработанного бара
local last_processed_bar = -1
-- Основная функция, вызываемая терминалом при изменении данных:
function OnCalculate(index)
-- Получаем общее количество баров на графике
local total_bars = getNumCandles("Chart") .
-- Проверяем, является ли текущий бар новым. - Условие выполнится только если номер текущего бара больше, чем тот, что мы обработали в прошлый раз
if index > last_processed_bar then
-- Присваиваем флагу номер текущего бара:
last_processed_bar = index
-- НАЧАЛО ВАШЕГО КОДА ---
-- Этот блок выполнится только один раз при открытии нового бара
message("Сформировалась новая свеча! Номер бара: " .. index, 1)
-- Здесь можно размещать любую логику:
-- 1. Получать значения индикаторов через getIndicatorData()
-- 2. Проверять условия для входа в сделку
-- 3. Рассчитывать новые значения для своего индикатора
Пример
Получим цену закрытия предыдущего бара
local prev_close = close[index - 1]
message("Цена закрытия предыдущего бара: " .. prev_close, 1)
-- КОНЕЦ ВАШЕГО КОДА ---
end
-- Функция OnCalculate для индикаторов должна возвращать число. Если скрипт - не индикатор, этот return можно убрать.
return total_bars
end.
Как это работает (разбор кода)
local last_processed_bar = -1. Создаем переменную и инициализируем её значением -1. Это гарантирует, что при самом первом запуске скрипта условие index > last_processed_bar сработает для самого первого доступного бара (с индексом 0).
function OnCalculate(index). Это стандартная функция для скриптов-индикаторов. Терминал вызывает её каждый раз, когда на графике что-то меняется (появляется новая цена в реальном времени или меняется история).
if index > last_processed_bar then: - ключевая проверка.
Когда открывается новая свеча, параметр index, передаваемый в функцию, увеличивается (например, был 100, стал 101). Условие становится истинным (101 > 100). Код внутри блока выполняется.
Пока текущая свеча формируется, index не меняется (остается 101). При каждом тике терминал вызывает OnCalculate(101). Теперь условие ложно (101 > 101 — это ложь). Код пропускается.
last_processed_bar = index. Как только мы выполнили нужный код для новой свечи, мы обновляем значение флага. Теперь система «знает», что этот бар уже обработан.
Важное замечание про тип скрипта
1. Если вы пишете индикатор (выводит линии на график), используйте OnCalculate. Этот метод работает идеально.
2. Если вы пишете робота (торговый алгоритм), который не рисует ничего на графике, лучше использовать функцию обратного вызова OnTick(). Логика с флагом внутри OnTick() будет работать точно так же:
local is_new_bar = false
function OnTick()
local current_bar_index = getNumCandles("Chart") - 1 -- Номер последнего бара
if not is_new_bar then
-- Ваш код здесь
message("Новый тик на новом баре!", 1)
is_new_bar = true
end
end.
function OnStop() -- Сброс флага при остановке робота (не обязательно, но полезно)
end.
Примечание: Для OnTick() логика может быть чуть сложнее, так как нужно отслеживать момент перехода бара (getNumCandles), но принцип флага остается неизменным.