Разработка инструментария для анализа движения цен (Часть 23): Индикатор силы валют
Содержание
Введение
Представьте, что вы на автогонках. Каждая машина уникальна, и на глаз нельзя просто определить, какая из них самая быстрая, а какая самая медленная. Вместо этого вы смотрите на время круга, оцениваете разгон, проверяете эффективность торможения и анализируете каждую модель по отдельности. И только после тщательного анализа каждой машины в отдельности и вы сравниваете их, чтобы оценить общую эффективность.
С валютами все работает примерно так же. Этот советник анализирует каждую валютную пару, в которой присутствует нужная валюта. Например, для USD он рассматривает пары USDJPY, EURUSD, GBPUSD, USDCHF и другие. Он измеряет изменение каждой пары на разных таймфреймах: сначала на M15, затем на H1 и, наконец, на H4. Эти периоды анализа задаются параметрами Lookback_M15, Lookback_H1 и Lookback_H4.
Если рассматриваемая валюта выступает в паре как котировочная, советник инвертирует знак этого изменения, чтобы корректно отразить ее силу. После расчета этих изменений по всем релевантным парам он усредняет результаты и получает единое значение силы для каждой валюты. Советник обновляет эти расчеты каждые несколько секунд в соответствии с параметром Update_Seconds. Затем он перерисовывает панель, чтобы отобразить текущие значения силы, записывает в лог, какие валюты сильные, слабые или нейтральные, и обновляет кривые средств счета и просадки.
В этой статье мы разработаем инструмент на MQL5, который измеряет силу валюты, анализируя поведение каждого символа в нескольких парах. Этот подход позволяет надежно выявлять самые сильные и самые слабые валюты, что позволяет принимать более уверенные торговые решения.
Знакомство со стратегией
Основная задача советника – определить, насколько сильна или слаба отдельная валюта, анализируя все пары, в которых она присутствует, на разных таймфреймах. Для этого мы выполняем следующие шаги, чтобы рассчитать силу каждой валюты по ее парам и на разных таймфреймах.
Выбор релевантных пар
Для каждой из восьми основных валют собираются все валютные пары, в которых она присутствует (например, для USD это USDJPY, EURUSD, GBPUSD и USDCHF).
Вычисление процентного изменения
На выбранном таймфрейме (например, M15, H1 или H4) рассчитывается процентное изменение за период анализа для каждой пары:
Нормализация знака
Если измеряемая валюта является котировочной (второй) валютой в паре, знак этого процентного изменения инвертируется, чтобы усиление котировочной валюты всегда отражалось как положительная сила.
Усреднение по парам
Берем значения процентного изменения с учетом знака для всех ее пар и вычисляем простое среднее. Это дает единый "индекс силы" для валюты на данном таймфрейме.

Диаграмма выше иллюстрирует этот процесс на примере USD. Мы измеряем силу USD во всех парах, где он присутствует, на нескольких таймфреймах. Это позволяет определить, на каком таймфрейме USD наиболее силен или слаб.
Разбор кода
В начале советника задаются основные свойства: авторское право, ссылка, версия и строгий режим компиляции. Эти директивы помогают идентифицировать советник и обеспечивают соответствие стандартам среды MetaTrader. Затем подключается библиотека SymbolInfo.mqh, которая предоставляет функции для управления символами и получения информации о них. Это необходимо для динамического выбора, включения и извлечения данных по нескольким валютным парам. Это важно, поскольку советнику нужен доступ к данным по разным символам, которые могут быть не включены по умолчанию, чтобы советник мог корректно работать сразу с несколькими парами.
#property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/ru/users/lynnchris" #property version "1.0" #property strict #include <Trade\SymbolInfo.mqh>
Затем код задает несколько входных параметров, таких как Lookback_M15, Lookback_H1 и Lookback_H4, которые определяют, сколько исторических баров используется для расчета силы валюты на соответствующих таймфреймах. Параметр Update_Seconds определяет, как часто обновляется панель, находя баланс между оперативностью и вычислительной нагрузкой.
FontSize, BackgroundColor, PanelWidth, PanelHeight и параметры начального положения позволяют пользователю настраивать внешний вид панели и ее размещение на графике, адаптируя ее под разные размеры экрана и личные предпочтения. Периоды анализа определяют, насколько чувствительными или сглаженными будут расчеты силы валюты: короткие периоды реагируют быстрее, но могут давать больше шума, а длинные обеспечивают большую стабильность, но реагируют медленнее.
input int Lookback_M15 = 96; input int Lookback_H1 = 48; input int Lookback_H4 = 30; input int Update_Seconds = 30; input int FontSize = 12; input color BackgroundColor = clrBlack; input int PanelWidth = 280; input int PanelHeight = 240; input int InitPanelX = 10; input int InitPanelY = 10;
Массивы Currencies и Pairs – это статические структуры данных, в которых перечислены основные валюты и связанные с ними валютные пары. Такая организация гарантирует, что пары, связанные с каждой валютой, сгруппированы вместе, что упрощает перебор пар при расчете силы. Например, массив Pairs содержит по четыре пары для каждой валюты, причем в каждой из них валюта выступает либо базовой, либо котировочной. Такая систематизация позволяет расчетным функциям эффективно оценивать, как каждая валюта ведет себя относительно других, анализируя сразу несколько пар и тем самым получая более полную оценку силы.
static const string Currencies[8] = {"USD","EUR","GBP","JPY","CHF","CAD","AUD","NZD"}; static const string Pairs[8][4] = { {"USDJPY","EURUSD","GBPUSD","USDCHF"}, {"EURUSD","EURJPY","EURGBP","EURCHF"}, // ... ......... };
Для хранения рассчитанных значений силы на разных таймфреймах объявлены глобальные переменные, которые записываются в двумерный массив Strength. Эти значения используются для отображения на панели и записи в лог. Дополнительные переменные, такие как LastUpdate, отслеживают момент последнего обновления данных, предотвращая лишние перерасчеты.
Переменные dragging, dragOffsetX и dragOffsetY отвечают за взаимодействие с пользователем, в частности позволяют трейдеру перемещать панель перетаскиванием мышью. Чтобы визуализировать динамику счета, объявлены массивы times[] и equities[] для хранения точек данных по средствам счета с временными метками, а dataCount отслеживает, сколько таких точек уже собрано. Они нужны для построения линий средств счета и просадки во времени.
double Strength[8][3]; // [currency][timeframe] datetime LastUpdate; int dataCount; double equities[MAX_POINTS]; datetime times[MAX_POINTS]; int PanelX, PanelY; bool dragging; int dragOffsetX, dragOffsetY;
Во время инициализации (OnInit()) советник задает начальное положение панели на основе пользовательских параметров. Затем он проходит по всем валютным парам и для каждой вызывает SymbolSelect(), чтобы включить доступ к данным. Этот шаг важен, потому что если символы не включены, последующие функции получения данных, такие как iClose(), не сработают, что приведет к неверным расчетам или ошибкам.
Затем код инициализирует временную метку LastUpdate и сбрасывает счетчик данных dataCount. Затем выполняется начальный расчет силы валют через UpdateStrengths(), чтобы панель сразу после запуска отображала актуальные данные. Функция DrawPanel() вызывается для создания панели с метками, цветными полосами и заголовками, формируя наглядный и интуитивно понятный интерфейс.
Кроме того, вызывается LogCurrencyStrengths(), чтобы вывести в терминал краткую текстовую сводку по статусам валют и дать трейдеру быстрый обзор ситуации. Наконец, EventSetTimer() задает периодический вызов процедуры обновления с интервалом, указанным в Update_Seconds, благодаря чему панель обновляется автоматически без ручного вмешательства.
int OnInit() { PanelX = InitPanelX; PanelY = InitPanelY; for(int i=0; i<8; i++) for(int j=0; j<4; j++) SymbolSelect(Pairs[i][j], true); LastUpdate = 0; dataCount = 0; UpdateStrengths(); DrawPanel(); LogCurrencyStrengths(1); EventSetTimer(Update_Seconds); return(INIT_SUCCEEDED); }
При деинициализации советника функцией (OnDeinit()) выполняется очистка: с помощью EventKillTimer() удаляется событие таймера, затем удаляются все графические объекты панели, включая фон, метки, полосы и заголовки, а также очищаются линии средств счета и просадки. Такая очистка не позволяет оставшимся объектам загромождать график и расходовать ресурсы, поэтому после удаления или перезагрузки советника рабочая среда остается чистой.
void OnTimer() { if(TimeCurrent() - LastUpdate < Update_Seconds) return; LastUpdate = TimeCurrent(); UpdateStrengths(); DrawPanel(); LogCurrencyStrengths(1); double eq = AccountInfoDouble(ACCOUNT_EQUITY); if(dataCount < MAX_POINTS) { times[dataCount] = TimeCurrent(); equities[dataCount] = eq; dataCount++; } DrawEquityLines(); DrawDrawdownLines(); }
Основная логика обновления реализована в функции OnTimer(), которая выполняется периодически. Сначала функция проверяет, прошло ли достаточно времени с момента последнего обновления, сравнивая текущее время с LastUpdate. Если указанный интервал еще не истек, функция завершается раньше, чтобы избежать лишних вычислений. Когда условие выполнено, функция обновляет LastUpdate текущим временем и вызывает UpdateStrengths(), чтобы пересчитать значения силы валют на основе последних рыночных данных.
Затем вызывается DrawPanel(), чтобы обновить панель: метки, цвета и полосы приводятся в соответствие с текущими значениями силы. Кроме того, через LogCurrencyStrengths() в лог записываются текущие статусы валют, что дает текстовую сводку ситуации. Затем функция получает текущее значение средств счета через AccountInfoDouble(ACCOUNT_EQUITY) и, если максимальное число точек данных еще не достигнуто, добавляет временную метку и это значение в соответствующие массивы.
Эти сохраненные точки данных используются функциями DrawEquityLines() и DrawDrawdownLines() для обновления линий средств счета и просадки, наглядно показывая рост счета и уровень риска во времени. Этот цикл обеспечивает синхронизацию всей панели с рыночной ситуацией в реальном времени и состоянием счета.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_OBJECT_CLICK && sparam=="CS_BG") { dragging = true; dragOffsetX = (int)lparam - PanelX; dragOffsetY = (int)dparam - PanelY; } else if(id==CHARTEVENT_MOUSE_MOVE && dragging) { PanelX = (int)lparam - dragOffsetX; PanelY = (int)dparam - dragOffsetY; DrawPanel(); } else if(dragging && id==CHARTEVENT_OBJECT_CLICK) { dragging = false; } }
Взаимодействие с пользователем обрабатывается в OnChartEvent(). Когда пользователь кликает по фоновому прямоугольнику ("CS_BG"), активируется режим перетаскивания, и запоминается смещение между положением мыши и текущей позицией панели. По мере движения мыши (CHARTEVENT_MOUSE_MOVE) позиция панели обновляется динамически, позволяя трейдеру удобно перемещать ее для лучшей видимости. Когда пользователь отпускает кнопку мыши или кликает в другом месте, режим перетаскивания отключается, а панель фиксируется в новом положении. Это делает работу удобнее и позволяет адаптировать панель под разные варианты рабочего пространства.
double CalculateStrength(int ci, ENUM_TIMEFRAMES tf, int lookback) { double sum = 0; int cnt = 0; for(int j=0; j<4; j++) { string sym = Pairs[ci][j]; if(Bars(sym, tf) < lookback+1) continue; double now = iClose(sym, tf, 0); double prev = iClose(sym, tf, lookback); if(prev == 0) continue; double pct = (now - prev) / prev * 100.0; if(StringFind(sym, Currencies[ci]) > 0) pct = -pct; sum += pct; cnt++; } return (cnt == 0) ? 0 : sum / cnt; }
Расчет силы валют выполняется в UpdateStrengths() и CalculateStrength(). UpdateStrengths() проходит по индексам всех валют, вызывая CalculateStrength() для каждого из трех таймфреймов.
CalculateStrength() получает последнюю цену закрытия через iClose() для каждой релевантной пары, а затем извлекает исторические цены закрытия за период анализа. Затем функция проверяет, достаточно ли баров для расчета; если нет, эта пара пропускается во избежание ошибок. Затем вычисляется процентное изменение за период анализа, и если рассматриваемая валюта является в паре котировочной, знак процентного изменения инвертируется, чтобы укрепление котируемой валюты также отображалось как положительное значение ее силы.
Такая инверсия гарантирует, что укрепление котировочной валюты отражается как ослабление базовой, сохраняя единообразие расчетов. Функция суммирует эти процентные изменения по всем четырем парам для каждой валюты и затем усредняет их, получая итоговый индекс силы, который сохраняется в массиве Strength для отображения и записи в лог.
void DrawPanel() { RemovePanel(); ObjectCreate(0, "CS_BG", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "CS_BG", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "CS_BG", OBJPROP_XDISTANCE, PanelX); ObjectSetInteger(0, "CS_BG", OBJPROP_YDISTANCE, PanelY); ObjectSetInteger(0, "CS_BG", OBJPROP_XSIZE, PanelWidth); ObjectSetInteger(0, "CS_BG", OBJPROP_YSIZE, PanelHeight); // Add headers, labels, colored bars for each currency }
За визуальное представление этих данных отвечает DrawPanel(), которая создает прямоугольник, охватывающий заданную область панели. Для наглядности в верхней части добавляются заголовки для каждого таймфрейма. Затем функция проходит по всем валютам, создавая метки с названием валюты, числовым значением силы (с двумя знаками после запятой) и цветную полосу, которая наглядно показывает силу или слабость.
В цветовой схеме используются зеленые оттенки для сильных валют, оранжевые – для нейтральных, а красные – для слабых, что позволяет трейдеру быстро оценивать рыночную картину визуально. Ширина полосы пропорциональна значению силы, что служит дополнительным визуальным ориентиром. Эти единообразные графические элементы делают панель информативной и позволяют быстро считывать ее с первого взгляда.
void RemovePanel() { for(int i=ObjectsTotal(0)-1; i>=0; i--) { string name = ObjectName(0, i); if(StringFind(name, "CS_") == 0 || StringFind(name, "Lbl_") == 0 || StringFind(name, "Bar_") == 0) ObjectDelete(0, name); } }
Когда панель нужно обновить или удалить, RemovePanel() удаляет все объекты, связанные с ней и имеющие определенные префиксы имен, такие как "CS_", "Hdr_", "Lbl_", "Val_" и "Bar_". Такое систематическое удаление поддерживает чистоту графика и предотвращает визуальный мусор, позволяя при каждом обновлении заново строить панель с нуля без накопления оставшихся объектов.
void DrawEquityLines()
{
for(int i=1; i< dataCount; i++)
{
string id = StringFormat("EQ_%d", i);
ObjectDelete(0, id);
ObjectCreate(0, id, OBJ_TREND, 0,
times[i-1], equities[i-1],
times[i], equities[i]);
ObjectSetInteger(0, id, OBJPROP_COLOR, clrYellow);
ObjectSetInteger(0, id, OBJPROP_WIDTH, 2);
}
} Функции DrawEquityLines() и DrawDrawdownLines() визуализируют динамику счета. Каждый раз, когда записываются новые данные по средствам счета, эти функции удаляют предыдущие объекты линий ("EQ_" и "DD_"), чтобы график оставался чистым. Затем они создают новые объекты линий, соединяя сохраненные точки данных и используя разные цвета – желтый для средств и красный для просадки, – чтобы их было легко различать.
Эти линии наглядно показывают, как менялась стоимость счета, а также какие максимальные просадки наблюдались. Эти визуальные элементы имеют смысл только в том случае, если советник активно управляет сделками, поскольку они зависят от изменений средств счета, вызванных совершенными ордерами.
void DrawDrawdownLines() { double peak = -DBL_MAX; for(int i=1; i< dataCount; i++) { peak = MathMax(peak, equities[i-1]); double dd = equities[i-1] - peak; string id = StringFormat("DD_%d", i); ObjectDelete(0, id); ObjectCreate(0, id, OBJ_TREND, 0, times[i-1], dd, times[i], equities[i] - peak); ObjectSetInteger(0, id, OBJPROP_COLOR, clrRed); ObjectSetInteger(0, id, OBJPROP_WIDTH, 2); } }
Это важный момент: хотя код построения линий средств и просадки включен и будет их рисовать, практическая польза этих линий во многом зависит от того, выполняет ли советник автоматические торговые операции. Если советник носит исключительно информационный характер или используется только при ручной торговле, значение средств счета будет меняться лишь тогда, когда трейдер сам совершает сделки или вносит/выводит средства. В таких случаях график средств счета может неточно отражать торговую динамику в реальном времени, а линии могут быть почти статичными или просто менее информативными.
Поэтому такие элементы визуализации наиболее ценны тогда, когда они встроены в советник, который активно торгует в автоматическом режиме и постоянно меняет состояние счета. Когда такая система автоторговли работает, график средств в реальном времени показывает рост счета, просадки и общую динамику, что может быть особенно полезно для управления рисками и оценки результатов.
void LogCurrencyStrengths(int tfIdx) { string sStrong="", sWeak="", sNeutral=""; for(int i=0; i<8; i++) { double v = Strength[i][tfIdx]; if(v > 0.3) sStrong += Currencies[i] + " "; else if(v < -0.3) sWeak += Currencies[i] + " "; else sNeutral += Currencies[i] + " "; } Print("Strong: ", sStrong, "| Weak: ", sWeak, "| Neutral: ", sNeutral); }
Наконец, LogCurrencyStrengths() формирует текстовую сводку, классифицируя каждую валюту как сильную, слабую или нейтральную на основе заданных порогов (например, выше +0.3% или ниже -0.3%). Функция объединяет коды валют в строки по каждой из категорий и выводит эти сводки в окно терминала. Эта текстовая сводка дает быстрое представление о рыночной ситуации по основным валютам и дополняет графическое отображение для тех трейдеров, которым важен быстрый обзор общей картины.
Результат
В этом разделе мы рассмотрим результаты тестирования нашего советника в MetaTrader 5.
| Валюта | M15 | H1 | H4 |
|---|---|---|---|
| USD | -0.11 | +1.12 | +2.20 |
| EUR | -0.23 | -0.38 | -0.38 |
| GBP | +0.20 | +0.49 | +0.67 |
| JPY | +0.01 | -1.44 | -2.48 |
| CHF | +0.32 | -0.25 | -0.33 |
| CAD | +0.17 | +0.34 | +0.16 |
| AUD | +0.05 | +0.71 | +0.52 |
| NZD | +0.10 | +0.76 | +0.13 |
- USD остается самой сильной валютой как на H1 (+1.12), так и на H4 (+2.20), несмотря на кратковременное снижение на M15.
- JPY и EUR остаются самыми слабыми валютами на H1 (-1.44 и -0.38) и H4 (-2.48 и -0.38).
- GBP, CAD, AUD и NZD показывают слабую или умеренную силу на H1/H4, поэтому их можно рассматривать как второстепенных кандидатов в сильные валюты.
Заключение
Измеритель силы валют помогает выявлять изменения в валютной паре на нескольких таймфреймах. Он дает наглядное представление о возможном направлении рынка. Это не значит, что нужно сразу входить в сделку; вместо этого используйте данный советник, чтобы находить оптимальные точки входа и применять свои стратегии управления рисками и подтверждения. Этот инструмент служит отправной точкой для оценки силы валют, и в будущем анализ можно будет углубить, а представление результатов – улучшить. Следите за дальнейшим развитием этой темы в будущих проектах.
| Дата | Название инструмента | Описание | Версия | Обновления | Примечания |
|---|---|---|---|---|---|
| 01/10/24 | Chart Projector | Скрипт для наложения эффекта призрака на движение цены за предыдущий день | 1.0 | Первоначальная версия | Инструмент номер 1 |
| 18/11/24 | Analytical Comment | Предоставляет информацию за предыдущий день в табличном формате, а также прогнозирует будущее направление рынка | 1.0 | Первоначальная версия | Инструмент номер 2 |
| 27/11/24 | Analytics Master | Регулярное обновление рыночных показателей каждые два часа | 1.01 | Вторая версия | Инструмент номер 3 |
| 02/12/24 | Analytics Forecaster | Регулярное обновление рыночных показателей каждые два часа с интеграцией с Telegram | 1.1 | Третья версия | Инструмент номер 4 |
| 09/12/24 | Volatility Navigator | Советник анализирует рыночные условия с помощью полос Боллинджера, RSI и ATR | 1.0 | Первоначальная версия | Инструмент номер 5 |
| 19/12/24 | Mean Reversion Signal Reaper | Анализирует рынок и генерирует сигналы, используя стратегию возврата к среднему | 1.0 | Первоначальная версия | Инструмент номер 6 |
| 9/01/25 | Signal Pulse | Анализирует несколько таймфреймов | 1.0 | Первоначальная версия | Инструмент номер 7 |
| 17/01/25 | Metrics Board | Панель с кнопками для анализа | 1.0 | Первоначальная версия | Инструмент номер 8 |
| 21/01/25 | External Flow | Аналитика с помощью внешних библиотек | 1.0 | Первоначальная версия | Инструмент номер 9 |
| 27/01/25 | VWAP | Взвешенная по объему средняя цена | 1.3 | Первоначальная версия | Инструмент номер 10 |
| 02/02/25 | Heikin Ashi | Сглаживание тренда и идентификация сигналов разворота | 1.0 | Первоначальная версия | Инструмент номер 11 |
| 04/02/25 | FibVWAP | Генерация сигналов с помощью анализа Python | 1.0 | Первоначальная версия | Инструмент номер 12 |
| 14/02/25 | RSI DIVERGENCE | Дивергенция цены и RSI | 1.0 | Первоначальная версия | Инструмент номер 13 |
| 17/02/25 | Parabolic Stop and Reverse (PSAR) | Автоматизация стратегии PSAR | 1.0 | Первоначальная версия | Инструмент номер 14 |
| 20/02/25 | Скрипт Quarters Drawer | Нанесение уровней четвертей на график | 1.0 | Первоначальная версия | Инструмент номер 15 |
| 27/02/25 | Intrusion Detector | Обнаружение и оповещение о достижении ценой уровней четвертей | 1.0 | Первоначальная версия | Инструмент номер 16 |
| 27/02/25 | TrendLoom Tool | Панель мультитаймфреймового анализа | 1.0 | Первоначальная версия | Инструмент номер 17 |
| 11/03/25 | Quarters Board | Панель с кнопками для включения/отключения уровней четвертей | 1.0 | Первоначальная версия | Инструмент номер 18 |
| 26/03/25 | ZigZag Analyzer | Построение линий тренда с помощью индикатора ZigZag | 1.0 | Первоначальная версия | Инструмент номер 19 |
| 10/04/25 | Correlation Pathfinder | Построение графиков корреляции валютных курсов с использованием библиотек Python. | 1.0 | Первоначальная версия | Инструмент номер 20 |
| 23/04/25 | Market Structure Flip Detector Tool | Поиск разворотов рыночной структуры | 1.0 | Первоначальная версия | Инструмент номер 21 |
| 08/05/25 | Correlation Dashboard | Корреляции между разными парами | 1.0 | Первоначальная версия | Инструмент номер 22 |
| 13/05/25 | Currency Strength Meter | Изменяет силу валюты по нескольким валютным парам с ее участием | 1.0 | Первоначальная версия | Инструмент номер 22 |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/18108
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Особенности написания Пользовательских Индикаторов
Создание самооптимизирующихся советников на MQL5 (Часть 10): Факторизация матриц
Реализация LLM-агента с SQL-памятью в MetaTrader 5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования