Новый бар
Вся логика советника в терминале MetaTrader реализуется в функции OnTick(), а индикатора в функции OnCalculate(). Эти функции вызываются при каждом изменении цены торгового символа, на графике которого работает советник или индикатор. Это событие также называют "новый тик цены" или "новый ценовой тик".
Обычно программный код торгового робота или индикатора производит большой объем вычислений, при этом каждую секунду может приходить несколько тиков. Такие вычисления при постоянном повторении могут производить большую нагрузку на компьютер. Тем более нагрузка увеличивается при одновременном использовании программы на нескольких графиках.
Также, большой объем вычислений происходящий на каждом тике, существенно замедляет процессы тестирования и оптимизации в тестере торгового терминала.
При этом, далеко не всегда требуется выполнение всей логики программы на каждом новом тике. И многие торговые стратегии определяют момент входа в рынок или появление сигнала на открытие/закрытие сделок, по сигналам индикаторов именно при появлении нового бара.
Отслеживая появление нового бара на графике, мы можем разделить процесс и запускать одну часть кода на каждом тике, а другую с заданной периодичностью. Например, при появлении нового бара на графике с тайм-фреймом М5, код будет запускаться каждые 5 минут, а на графике Н1 - каждый час.
Чтобы определять появление нового бара, мы создадим соответствующую функцию. Но вначале посмотрим как она будет использоваться в советнике, чтобы иметь представление как это всё работает.
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
// Здесь вызываем функции, которые должны работать на каждом новом тике цены, то есть всегда
CheckPositions(); // Пример вызова вымышленной функции
// Проверяем - если это не момент появления нового бара, то выходим из функции OnTick()
if(!IsNewBar())
return;
// Здесь вызываем функции, которые должны работать только при появлении нового бара
CheckTradingSignal(); // Пример вызова вымышленной функции
//---
}
И далее сама функция IsNewBar():
//+-----------------------------------------------------------------+
//| Возвращает true, если появился новый бар для пары символ/период |
//+-----------------------------------------------------------------+
bool IsNewBar(const int period=0, const string symbol=NULL)
{
//--- Устанавливаем значения текущего графика для символа и периода,
// если их значения не были переданы
int _period = period == 0 ? Period() : period;
string _symbol = symbol == "" ? Symbol() : symbol;
//--- В статической переменной будем хранить время открытия последнего бара
static datetime last_time = 0;
//--- Время открытия последнего бара по символу-периоду
datetime lastbar_time = (datetime)SeriesInfoInteger(_symbol, ENUM_TIMEFRAMES(_period), SERIES_LASTBAR_DATE);
//--- если это первый вызов функции
if(last_time == 0)
{
//--- установим время и выйдем
last_time = lastbar_time;
return(false);
}
//--- если время отличается
if(last_time != lastbar_time)
{
//--- запомним время и вернем true
last_time = lastbar_time;
return(true);
}
//--- дошли до этого места - значит бар не новый, вернем false
return(false);
}
Функция IsNewBar() принимает символ и период графика, на котором будет отслеживаться момент появления нового бара. Если вызвать её без параметров: IsNewBar()
, то проверка будет происходить на текущем графике, на котором работает программа - форекс робот или индикатор.
Также мы можем делать проверку появления нового бара на другом тайм-фрейме финансового инструмента текущего графика: IsNewBar(PERIOD_D1)
, или вообще на любом тайм-фрейме любого графика: IsNewBar(PERIOD_D1, "USDJPY")
, в зависимости от торговой стратегии советника.
Но есть одно ограничение: функция IsNewBar() одновременно может использоваться только для отслеживания одного символа и периода. Например, если торговая стратегия ищет сигналы на открытие сделок по индикаторам на периоде М15 (15 минут), и ищет сигналы на закрытие сделок на старшем периоде - D1 (один день), то не получится каждый раз вызывать эту функцию и передавать разные периоды.
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
// Действия при появлении нового бара на текущем графике
if(IsNewBar())
{
...
}
// Действия при появлении нового бара на графике текущего символа с периодом 1 день
if(IsNewBar(PERIOD_D1))
{
...
}
//---
}
Так происходит потому что в функции IsNewBar() используется статическая переменная static datetime last_time
.
Статические переменные работают также как и глобальные переменные - их значение хранится в течение всего времени работы программы и не сбрасывается при каждом новом вызове функции. При этом, статическая переменная создается внутри функции, и доступна для чтения и изменения только внутри этой функции.
Если функция будет вызываться каждый раз с новыми параметрами, то значение переменной last_time
будет каждый раз меняться для этих параметров, но при этом вначале будет проводиться проверка на появление нового бара на графике с параметрами - символом и/или периодом, которые были переданы при предыдущем вызове функции.
Но это ограничение можно легко обойти. Если вам не нужно отслеживать большое количество символов и периодов, то можно просто создать дубликат функции IsNewBar() с другим названием, например, IsNewBarD1() и использовать его. При этом, можно убрать входные параметры const int period=0, const string symbol=NULL
и задать их "жестко" в теле функции, чтобы название функции соответствовало тому, что она возвращает:
string _symbol = Symbol();
int period = PERIOD_D1;
Если вам нужна большая гибкость в определении события появления нового графика, то рекомендуем использовать следующие библиотеки, доступные на сайте MQL5:
CCheckNewCandle - в этой библиотеке нет ограничения на поиск нового бара одновременно на нескольких символах и тайм-фреймах.
New Bar Event - другая реализация, которая позволяет определить наступление события нового бара в мультивалютном советнике. То есть также - одновременно на любом количестве символов и тайм-фреймов, но работает более эффективно в мультивалютных советниках.
Обе эти библиотеки проверены и работают в MQL 4 и 5 версии, также как и весь код представленный выше.