Разработка инструментария для анализа Price Action (Часть 44): Создание в MQL5 сигнального советника на основе пересечений VWMA
Введение
Успешность торговли зависит от умения отделять значимые ценовые тренды от фонового рыночного шума. На протяжении десятилетий скользящие средние, такие как простая скользящая средняя (SMA) и экспоненциальная скользящая средняя (EMA), помогали трейдерам сглаживать волатильность и яснее видеть направление рынка. Тем не менее эти традиционные индикаторы упускают важнейший компонент ценового движения: объем торгов, который часто и определяет реальную значимость тренда.
Появление объемно-взвешенной скользящей средней (VWMA) позволило преодолеть это ограничение: цены, сопровождавшиеся более высокой торговой активностью, получают в ней больший вес. В результате VWMA дает более четкий и надежный сигнал о реальном рыночном импульсе и помогает трейдерам отличать сильные движения, подтвержденные объемом, от слабых колебаний при низкой активности.
В этой статье рассматривается практическое применение пересечений VWMA в алгоритмической торговле. В ней будут рассмотрены подход VWMA, его реализация на MQL5, результаты тестирования и ключевые выводы как для трейдеров, принимающих решения вручную, так и для трейдеров, использующих системный подход.
Опираясь на эти принципы, советник VWMA Crossover реализует стратегию пересечения VWMA и дополняет ее интуитивно понятной панелью на графике. Этот инструмент спроектирован так, чтобы оставаться понятным и удобным на любом фоне графика: он автоматически обнаруживает события пересечения, выделяет актуальные сигналы и своевременно отправляет алерты, упрощая мониторинг рынка и помогая быстрее реагировать на торговые сигналы.
Ниже приведено содержание статьи. Каждый из перечисленных разделов будет подробно рассмотрен далее.
Знакомство с концепцией VWMA
В отличие от многих индикаторов, связанных с именем конкретного автора, VWMA возникла органично в среде технического анализа, когда практики начали взвешивать средние значения по фактическому объему торгов. Она опирается на долгую традицию скользящих средних (восходящую к ранним методам сглаживания начала XX века) и частично заимствует подход из институциональных практик с VWAP, чье историческое происхождение документировано лучше.
Ниже приведены некоторые преимущества VWMA по сравнению с SMA и EMA.
| Преимущество | Пояснение |
|---|---|
| Учет объема | VWMA отражает, где был сосредоточен основной объем сделок, а не только направление движения цены. |
| Более надежное подтверждение тренда | Подтверждает реальные развороты и продолжения тренда с поддержкой объема. |
| Адаптивная чувствительность | Быстро реагирует на рыночные движения с высоким объемом и отфильтровывает шум при низком объеме. |
| Выявляет активность крупных участников | Полезна для выявления накопления или распределения со стороны крупных участников. |
Формула VWMA:

Где:
- 𝑃(𝑖) = цена свечи i (обычно цена закрытия)
- 𝑉(𝑖) = объем торгов свечи i
- 𝑛 = количество периодов (например, 20)
Допустим, мы хотим рассчитать 5-периодную VWMA по следующим данным:
| Свеча | Цена закрытия | Объем |
|---|---|---|
| 1 | 10 | 100 |
| 2 | 11 | 200 |
| 3 | 12 | 150 |
| 4 | 13 | 300 |
| 5 | 14 | 250 |
Теперь рассчитаем:
- Умножим каждую цену на соответствующий объем:
(10×100) + (11×200) + (12×150) + (13×300) + (14×250) = 1 000 + 2 200 + 1 800 + 3 900 + 3 500 = 12 400
- Сложим все объемы:
100 + 200 + 150 + 300 + 250 = 1 000
- Разделим сумму (цена × объем) на общий объем:
VWMA = 12 400/1 000 = 12,4
Итак, 5-периодная VWMA = 12,4.
- Когда цена > VWMA, рынок часто находится в восходящем тренде, подтвержденном объемом.
- Когда цена < VWMA, это указывает на нисходящий тренд, подтвержденный объемом.
- Плоская или боковая VWMA указывает на слабую активность участников либо на торговлю в диапазоне.
Ниже приведен краткий фрагмент кода, который показывает, как вручную рассчитать объемно-взвешенную скользящую среднюю (VWMA) в советнике или индикаторе на MQL5:
double VWMA(const string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift) { if(period <= 0) return EMPTY_VALUE; MqlRates rates[]; if(CopyRates(symbol, timeframe, shift, period, rates) != period) return EMPTY_VALUE; double sumPriceVolume = 0, sumVolume = 0; for(int i = 0; i < period; i++) { sumPriceVolume += rates[i].close * rates[i].tick_volume; sumVolume += rates[i].tick_volume; } return (sumVolume == 0) ? EMPTY_VALUE : sumPriceVolume / sumVolume; }
В этой разработке используются и быстрая, и медленная объемно-взвешенные скользящие средние (VWMA) для отслеживания соответственно краткосрочного и долгосрочного рыночных трендов.
Быстрая VWMA
- Имеет более короткий период (например, 10 или 20 баров).
- Быстро реагирует на недавние изменения цены и объема.
- Более чувствительна к краткосрочным рыночным движениям.
- Полезна для выявления краткосрочных трендов, импульса и возможных точек входа и выхода.
Медленная VWMA
- Имеет более длительный период (например, 50 или 60 баров).
- Реагирует медленнее на недавние изменения цены и объема.
- Сглаживает мелкие колебания и помогает сосредоточиться на более крупном тренде.
- Полезна для определения общего направления рынка и фильтрации шума.
Логика генерации торговых сигналов в этом советнике почти повторяет стандартные стратегии пересечения скользящих средних (MA): сигнал на покупку или продажу возникает, когда быстрая VWMA пересекает медленную снизу вверх или сверху вниз.
Медвежий сигнал

Сигналы на продажу генерируются, когда быстрая VWMA пересекает медленную VWMA сверху вниз.
Конкретно, условия для сигнала на продажу таковы:
- На предыдущем баре быстрая VWMA была выше медленной VWMA.
- На текущем баре быстрая VWMA опустилась ниже медленной VWMA.
Такое "нисходящее пересечение" указывает на возможный переход от бычьего импульса к медвежьему, то есть может служить подходящим моментом для продажи.
bool bear = (f_prev > s_prev) && (f_now < s_now); if(bear /* && other filters */) { // Generate sell signal }
Бычий сигнал

Сигналы на покупку (бычьи) генерируются, когда быстрая VWMA пересекает медленную VWMA снизу вверх.
Конкретно, условия для сигнала на покупку таковы:
- На предыдущем баре быстрая VWMA была ниже медленной VWMA.
- На текущем баре быстрая VWMA поднялась выше медленной VWMA.
Такое "восходящее пересечение" указывает на возможный переход от медвежьего импульса к бычьему, то есть может означать благоприятный момент для покупки.
bool bull = (f_prev < s_prev) && (f_now > s_now); if(bull /* && other filters */) { // Generate buy signal }
Обратите внимание: объемно-взвешенная скользящая средняя (VWMA) не входит в стандартный набор встроенных индикаторов MetaTrader 5. Чтобы использовать VWMA в советнике или индикаторе, расчет нужно реализовать вручную по формуле, приведенной выше.
Реализация на MQL5
Чтобы приступить к разработке на MQL5, сперва убедитесь, что MetaTrader 5 установлен на вашем компьютере. MetaEditor, официальная среда для написания и редактирования кода MQL5, входит в состав каждой установки MetaTrader 5, поэтому устанавливать его отдельно не нужно. После того как MetaTrader 5 будет готов к работе, запустите MetaEditor либо из терминала MetaTrader 5 (нажав значок MetaEditor или клавишу F4), либо напрямую из меню приложений. В MetaEditor перейдите в "Файл" > "Создать", выберите "Советник (шаблон)" и укажите имя для вашего советника. После этого можно переходить к подробным инструкциям ниже и создать собственного советника на MQL5 с нуля.

1. Заголовок файла и метаданные
//+------------------------------------------------------------------+ //| VWMA CROSSOVER EA.mq5| //| Copyright 2025, Christian Benjamin.| //| https://www.mql5.com/ru/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "https://www.mql5.com/ru/users/lynnchris" #property version "1.0" #property strict
Первые строки исходного файла содержат три директивы #property, описывающие программу для терминала MetaTrader 5. URL в блоке авторских прав указывает авторство, а строка версии задает официальный номер выпуска, который позднее появится в окне "Навигатор" в терминале. Наконец, #property strict предписывает компилятору применять новейшие правила языка. Работа в строгом режиме не позволяет использовать многие устаревшие упрощения, выявляет неоднозначные преобразования типов и тем самым делает код более надежным.
2. Входные параметры
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; input uint FastPeriod = 20; input uint SlowPeriod = 60; input uint SR_LookBack = 50; input double SR_OffsetPips = 3.0; input bool Draw_Arrows = true; input bool Send_Alerts = true; input bool Show_VWMA_Lines = true; input int PlotDepth = 500;
Сразу после заголовка идут входные переменные – публичные параметры, которые пользователь увидит в окне настроек советника. InpTimeframe определяет рабочий таймфрейм; если оставить значение PERIOD_CURRENT, советник просто использует таймфрейм графика, на котором запущен. FastPeriod и SlowPeriod – это периоды расчета двух VWMA, которые затем сравниваются. Следующая пара, SR_LookBack и SR_OffsetPips, управляет простым фильтром поддержки и сопротивления: проверяются экстремумы на последних N барах, и сделка разрешается только тогда, когда цена ушла за эти уровни как минимум на заданное число пипсов (offset). Три булевых флага позволяют трейдеру выбрать, нужно ли рисовать стрелки, отправлять алерты и отображать линии скользящих средних, а PlotDepth ограничивает количество исторических баров, выводимых на график, чтобы время отрисовки оставалось разумным.
3. Глобальные переменные
datetime g_last_bar_time = 0; int g_last_signal = 0; // 1 = BUY, -1 = SELL, 0 = none datetime g_last_signal_time = 0; string DASH_BASE = "VWMA_DASH_";
Четыре глобальные переменные сохраняют состояние советника между тиками. g_last_bar_time хранит время открытия уже обработанной свечи, чтобы логика выполнялась только один раз на бар. g_last_signal и g_last_signal_time отслеживают направление и временную метку последнего алерта; эта информация затем используется в информационной панели. Наконец, DASH_BASE – это текстовый префикс, благодаря которому каждый объект панели на графике получает уникальное и легко распознаваемое имя.
4. Процедура расчета VWMA
double VWMA(const string sym, ENUM_TIMEFRAMES tf, uint per, int shift) { if(per == 0) return EMPTY_VALUE; MqlRates r[]; if(CopyRates(sym, tf, shift, per, r) != (int)per) return EMPTY_VALUE; double num = 0, den = 0; for(int i = 0; i < (int)per; i++) { double vol = (double)r[i].tick_volume; num += r[i].close * vol; den += vol; } return (den == 0) ? EMPTY_VALUE : num / den; }
Функция double VWMA(const string sym, ENUM_TIMEFRAMES tf, uint per, int shift) представляет собой математическое ядро программы. Сначала с помощью CopyRates копируются per свечей из истории, начиная с позиции shift баров назад от текущего. В простом цикле функция накапливает две суммы: num (сумму произведений close × volume) и den (общий объем). Деление первой суммы на вторую дает классическую объемно-взвешенную скользящую среднюю.
Если получить исходные ценовые данные не удается или знаменатель оказывается равен нулю, функция возвращает константу MetaTrader EMPTY_VALUE, которую последующие процедуры обрабатывают как NaN.
5. Вспомогательные функции для поддержки и сопротивления
double HighestHigh(const string s, ENUM_TIMEFRAMES tf, uint lb) { if(lb == 0) return EMPTY_VALUE; double a[]; if(CopyHigh(s, tf, 0, lb, a) != (int)lb) return EMPTY_VALUE; double m = a[0]; for(uint i = 1; i < lb; i++) if(a[i] > m) m = a[i]; return m; } double LowestLow(const string s, ENUM_TIMEFRAMES tf, uint lb) { if(lb == 0) return EMPTY_VALUE; double a[]; if(CopyLow(s, tf, 0, lb, a) != (int)lb) return EMPTY_VALUE; double m = a[0]; for(uint i = 1; i < lb; i++) if(a[i] < m) m = a[i]; return m; } bool ValidateSR(bool buy, double bid, double ask, double& sup, double& res) { res = HighestHigh(_Symbol, InpTimeframe, SR_LookBack); sup = LowestLow(_Symbol, InpTimeframe, SR_LookBack); if(res == EMPTY_VALUE || sup == EMPTY_VALUE) return false; double off = SR_OffsetPips * _Point; return buy ? (bid >= sup + off) : (ask <= res - off); }
Две короткие обертки, HighestHigh и LowestLow, просматривают последние N баров в поисках экстремального максимума и минимума, считывая необработанные массивы через CopyHigh и CopyLow. Выше расположен ValidateSR – булева функция, реализующая простой, но эффективный фильтр торговых сигналов. Сначала она вызывает обе обертки, чтобы получить недавний максимум (res) и минимум (sup). Затем к этим уровням прибавляется или вычитается заданный пользователем сдвиг (offset) в пипсах, после чего проверяется, ушла ли текущая цена Bid или Ask за эти уровни как минимум на offset пипсов. На практике это не позволяет открывать покупки прямо под потенциальным сопротивлением и продажи непосредственно на потенциальной поддержке.
6. Служебные функции для работы с объектами
//+------------------------------------------------------------------+ //| Chart Utilities | //+------------------------------------------------------------------+ void SafeDeleteObject(const string name) { if(ObjectFind(0, name) != -1) ObjectDelete(0, name); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PlotChartArrow(const string n, datetime t, double price, color clr, int code) { SafeDeleteObject(n); ObjectCreate(0, n, OBJ_ARROW, 0, t, price); ObjectSetInteger(0, n, OBJPROP_COLOR, clr); ObjectSetInteger(0, n, OBJPROP_ARROWCODE, code); ObjectSetInteger(0, n, OBJPROP_WIDTH, 2); }
SafeDeleteObject – это короткая функция: сначала она проверяет, существует ли графический объект, и удаляет его только в этом случае. Эта функция предотвращает засорение журнала терминала сообщениями, которые иначе появлялись бы при попытке удалить уже удаленный объект. PlotChartArrow – это вспомогательная функция, которая создает OBJ_ARROW с единым оформлением – цветом, кодом стрелки и шириной – в точке с заданными временем и ценой. Благодаря тому что создание и удаление сосредоточены в этих двух вспомогательных функциях, остальной код может заниматься торговой логикой, а не служебной работой с объектами графика.
7. Отрисовка ломаных линий VWMA
void DrawLineVWMA(const string name, int period, color clr, int depth) { if(!Show_VWMA_Lines) { SafeDeleteObject(name); int total = ObjectsTotal(0); for(int i = total - 1; i >= 0; i--) { string nm = ObjectName(0, i); if(StringFind(nm, name + "_seg_") == 0) ObjectDelete(0, nm); } return; } const int extra = period + 2; MqlRates r[]; if(CopyRates(_Symbol, InpTimeframe, 0, depth + extra, r) < depth + extra) return; int total = ObjectsTotal(0); for(int i = total - 1; i >= 0; i--) { string nm = ObjectName(0, i); if(StringFind(nm, name + "_seg_") == 0) ObjectDelete(0, nm); } for(int i = 0; i < depth - 1; i++) { double vw1 = VWMA(_Symbol, InpTimeframe, period, i); double vw2 = VWMA(_Symbol, InpTimeframe, period, i + 1); if(vw1 == EMPTY_VALUE || vw2 == EMPTY_VALUE) continue; datetime t1 = r[i].time; datetime t2 = r[i + 1].time; string seg = name + "_seg_" + IntegerToString(i); if(ObjectCreate(0, seg, OBJ_TREND, 0, t1, vw1, t2, vw2)) { ObjectSetInteger(0, seg, OBJPROP_COLOR, clr); ObjectSetInteger(0, seg, OBJPROP_WIDTH, 1); ObjectSetInteger(0, seg, OBJPROP_RAY_RIGHT, false); } } }
Вместо отдельного индикатора с буферами этот советник рисует линии VWMA прямо на графике с помощью функции DrawLineVWMA. Благодаря этому они естественно встроены в логику советника и всегда синхронизированы с графиком и текущими параметрами. Функция сначала проверяет флаг Show_VWMA_Lines. Если пользователь отключил отрисовку линий VWMA, она сразу удаляет все объекты, использовавшиеся для их отображения (по префиксу имени), и завершает работу, чтобы не загромождать график.
Если отрисовка линий включена, функция запрашивает через CopyRates блок исторических данных по свечам, получая достаточно баров (на основе заданной пользователем глубины плюс несколько дополнительных для точности расчета), чтобы вычислить VWMA по всему видимому диапазону. Перед отрисовкой новых линий функция еще раз проходит по всем объектам графика и удаляет остатки старых сегментов VWMA, чтобы избежать захламления и графических артефактов от предыдущих запусков. Затем основная процедура отрисовки проходит по всем соседним парам баров в пределах заданной глубины и для каждой пары вычисляет VWMA в обеих конечных точках сегмента. Если хотя бы одно значение VWMA некорректно (например, из-за нехватки данных), она переходит к следующей паре. В противном случае создается короткая двухточечная линия тренда (OBJ_TREND), которая соединяет эти два значения VWMA в соответствующих точках времени и цены. Каждому сегменту присваивается уникальное имя для последующей очистки, а сами линии оформляются выбранными цветом и шириной без продолжения за пределы конечных точек.
Повторяя эту операцию для множества пар баров, функция формирует визуально непрерывную линию VWMA. Такой подход с сегментами и эффективен, и практичен: он уменьшает расход памяти и обеспечивает быстрое обновление даже при появлении новых баров или изменении параметров. Функция рассчитана на надежное автоматическое обновление: при каждом вызове она удаляет устаревшие сегменты и заново строит их по актуальным расчетам VWMA, поэтому визуальное представление всегда остается точным и актуальным. В итоге DrawLineVWMA дает практичный и надежный механизм наложения линий VWMA на график как части визуального вывода советника. Функция сочетает наглядность, эффективность и контроль со стороны пользователя, избавляет от отдельного файла индикатора и буферов и позволяет в любой момент включать или отключать линии VWMA, поддерживая информативность и аккуратность графика.
8. Построение и обслуживание информационной панели
void UpdateDashboard(double fast_vwma, double slow_vwma) { int corner = 0, x = 12, y = 12; int panel_w = 320, panel_h = 130, pill_w = 120, pill_h = 36, gap_y = 12; int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); string prefix = DASH_BASE; // ... (creation and property setting for each rectangle and label) // See full code for all label/rectangle setup string sia = prefix + "SIGN_ARROW"; if(ObjectFind(0, sia) == -1) ObjectCreate(0, sia, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, sia, OBJPROP_CORNER, corner); ObjectSetInteger(0, sia, OBJPROP_XDISTANCE, x + pill_w + 130); ObjectSetInteger(0, sia, OBJPROP_YDISTANCE, y + (pill_h + gap_y) * 2 + 10); ObjectSetInteger(0, sia, OBJPROP_FONTSIZE, 28); string txt = ""; color arrclr = clrGray; if(g_last_signal == 1) { txt = "▲"; arrclr = clrLime; } if(g_last_signal == -1) { txt = "▼"; arrclr = clrRed; } ObjectSetInteger(0, sia, OBJPROP_COLOR, arrclr); ObjectSetString(0, sia, OBJPROP_TEXT, txt); }
UpdateDashboard создает компактную информационную панель из трех строк в верхнем левом углу графика. Черный OBJ_RECTANGLE служит фоном; внутри него две цветные плашки показывают последние значения быстрой и медленной VWMA, а более широкая плашка под ними – последний торговый сигнал. Все прямоугольники и метки получают имена с общим префиксом DASH_BASE, поэтому при выгрузке советника их можно массово удалить через DeleteDashboardObjects. Функция динамически выбирает символ стрелки, ее цвет и числовую точность значений VWMA, чтобы трейдер мог считывать информацию с первого взгляда без проверки всплывающих подсказок или журнала Experts.
9. Обработка торгового сигнала
void ExecuteSignal(bool buy, const string cmt) { g_last_signal = buy ? 1 : -1; g_last_signal_time = TimeCurrent(); // Plot arrow if(Draw_Arrows) { string name = (buy ? "SIGNAL_BUY_" : "SIGNAL_SELL_") + (string)g_last_signal_time; color clr = buy ? clrLime : clrRed; int code = buy ? 233 : 234; double price = buy ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK); PlotChartArrow(name, g_last_signal_time, price, clr, code); } // Alert if(Send_Alerts) { string msg = (buy ? "VWMA SIGNAL BUY " : "VWMA SIGNAL SELL ") + _Symbol + " | " + cmt; Alert(msg); PlaySound("alert.wav"); } // Update dashboard double f = VWMA(_Symbol, InpTimeframe, FastPeriod, 0); double s = VWMA(_Symbol, InpTimeframe, SlowPeriod, 0); if(f != EMPTY_VALUE && s != EMPTY_VALUE) UpdateDashboard(f, s); }
Когда логика стратегии определяет, что возник новый сигнал на покупку или продажу, вызывается функция ExecuteSignal, которая выполняет все связанные действия, кроме открытия сделки. Сначала обновляются глобальные переменные, в которых фиксируются тип и время последнего сигнала, чтобы поддерживать синхронизацию остальных компонентов, например информационной панели. Если отрисовка стрелок включена, функция отмечает место сигнала на графике цветной стрелкой – зеленой для покупки и красной для продажи, чтобы сигналы было легко заметить визуально. Если включены алерты, функция также показывает всплывающее сообщение и воспроизводит звук уведомления, сразу сообщая пользователю сведения о сигнале и символе. В конце обновляется информационная панель: в нее передаются последние значения VWMA, чтобы сводная визуальная информация отражала самый свежий анализ рынка. Важно помнить, что эта функция только формирует и отображает сигналы; сделки она не исполняет. Благодаря этому советник может работать как генератор сигналов, который в дальнейшем при необходимости можно расширить функциями автоматической торговли.
10. Обработчики событий жизненного цикла
int OnInit() { Print("VWMA Crossover Dashboard (signal-only) loaded."); g_last_bar_time = 0; g_last_signal = 0; g_last_signal_time = 0; return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { SafeDeleteObject("VWMA_FAST"); SafeDeleteObject("VWMA_SLOW"); int total = ObjectsTotal(0); for(int i = total - 1; i >= 0; i--) { string nm = ObjectName(0, i); if(StringFind(nm, "SIGNAL_BUY_") == 0 || StringFind(nm, "SIGNAL_SELL_") == 0) ObjectDelete(0, nm); if(StringFind(nm, "VWMA_FAST_seg_") == 0 || StringFind(nm, "VWMA_SLOW_seg_") == 0) ObjectDelete(0, nm); } DeleteDashboardObjects(); }
OnInit выполняется один раз при подключении советника к графику или после перекомпиляции. Функция обнуляет все переменные состояния и выводит приветственное сообщение в журнал, чтобы можно было убедиться, что инициализация прошла успешно. OnDeinit решает обратную задачу: очищает график, удаляя отдельные базовые объекты ("VWMA_FAST", "VWMA_SLOW"), а затем проходит по оставшимся объектам графика и удаляет те, чьи имена начинаются с "SIGNAL_BUY_", "SIGNAL_SELL_" или с префиксов сегментов, которые использует код отрисовки ломаных линий. Информационная панель также удаляется, чтобы график выглядел точно так же, как до загрузки советника.
11. Сердце советника – OnTick
void OnTick() { // Update dashboard every tick double f_now_dash = VWMA(_Symbol, InpTimeframe, FastPeriod, 0); double s_now_dash = VWMA(_Symbol, InpTimeframe, SlowPeriod, 0); if(f_now_dash != EMPTY_VALUE && s_now_dash != EMPTY_VALUE) UpdateDashboard(f_now_dash, s_now_dash); datetime cur = iTime(_Symbol, InpTimeframe, 0); if(cur == g_last_bar_time) { DrawLineVWMA("VWMA_FAST", FastPeriod, clrDodgerBlue, PlotDepth); DrawLineVWMA("VWMA_SLOW", SlowPeriod, clrOrangeRed, PlotDepth); return; } g_last_bar_time = cur; double f_prev = VWMA(_Symbol, InpTimeframe, FastPeriod, 1); double s_prev = VWMA(_Symbol, InpTimeframe, SlowPeriod, 1); double f_now = VWMA(_Symbol, InpTimeframe, FastPeriod, 0); double s_now = VWMA(_Symbol, InpTimeframe, SlowPeriod, 0); if(f_prev == EMPTY_VALUE || s_prev == EMPTY_VALUE || f_now == EMPTY_VALUE || s_now == EMPTY_VALUE) return; bool bull = (f_prev < s_prev && f_now > s_now); bool bear = (f_prev > s_prev && f_now < s_now); double sup, res; if(bull && ValidateSR(true, SymbolInfoDouble(_Symbol, SYMBOL_BID), SymbolInfoDouble(_Symbol, SYMBOL_ASK), sup, res)) ExecuteSignal(true, "VWMA BUY"); if(bear && ValidateSR(false, SymbolInfoDouble(_Symbol, SYMBOL_BID), SymbolInfoDouble(_Symbol, SYMBOL_ASK), sup, res)) ExecuteSignal(false, "VWMA SELL"); DrawLineVWMA("VWMA_FAST", FastPeriod, clrDodgerBlue, PlotDepth); DrawLineVWMA("VWMA_SLOW", SlowPeriod, clrOrangeRed, PlotDepth); }
Каждый входящий рыночный тик вызывает OnTick, но ресурсоемкая часть алгоритма выполняется только один раз на бар. Функция начинается с обновления значений на информационной панели на каждом тике, чтобы числа оставались актуальными. Затем проверяется, отличается ли текущее время свечи iTime(...,0) от g_last_bar_time; если нет, перерисовываются только линии VWMA, после чего функция быстро завершается. Когда обнаруживается новый бар, для предыдущей и текущей свечи рассчитываются значения быстрой и медленной VWMA. Бычье пересечение фиксируется, когда быстрая VWMA пересекает медленную VWMA снизу вверх; обратная ситуация образует медвежье пересечение. Затем каждая потенциальная сделка проходит через ValidateSR; если проверка уровней пройдена, вызывается ExecuteSignal. Независимо от того, появился сигнал или нет, функция в конце заново отрисовывает обе ломаные линии VWMA, чтобы визуальные элементы оставались синхронизированными с новой свечой.
После завершения работы над кодом советника на MQL5 нажмите кнопку "Компилировать" в MetaEditor. Если ошибок и предупреждений нет, советник готов к запуску и тестированию. Чтобы оценить его работу, откройте MetaTrader 5, перейдите в окно "Навигатор", раскройте раздел "Советники" и перетащите советник на график для тестирования в реальном времени или на демо-счете. В качестве альтернативы можно открыть Тестер стратегий и проверить поведение советника на исторических данных.
Выполните следующие шаги:
- скомпилируйте советник в MetaEditor, нажав кнопку "Компилировать";
- проверьте наличие ошибок и предупреждений – если их нет, советник готов к работе;
- откройте MetaTrader 5, перейдите в окно "Навигатор" (обычно слева) и найдите советник в разделе "Советники";
- перетащите советник на график, чтобы запустить его в реальном времени или на демо-счете;
- для анализа работы на исторических данных откройте Тестер стратегий (нажмите Ctrl+R или используйте меню "Вид"), выберите советник, задайте параметры и запустите тестирование на исторических данных.
Результаты
Ниже проиллюстрированы результаты тестирования нашего инструмента на исторических данных. На графике отображается отдельная панель, которая обновляется в реальном времени и показывает текущие значения как быстрой, так и медленной VWMA по мере поступления новых тиков. На графике зеленые стрелки указывают сигналы на покупку, а красные – на продажу, создавая четкие визуальные ориентиры для каждого торгового события. В целом видно, что большинство сигналов указывает на благоприятные торговые возможности. Хотя встречаются и ошибочные сигналы, их сравнительно немного, что говорит о потенциальной эффективности инструмента при фильтрации рыночного шума и выявлении реальных трендов.

Заключение
В заключение отметим: хотя традиционные скользящие средние, такие как простая скользящая средняя (SMA) и экспоненциальная скользящая средняя (EMA), остаются ценными инструментами технического анализа, они в основном опираются на ценовые данные и иногда недооценивают роль объема торгов в движении рынка. Советник на основе пересечений VWMA дополняет эти подходы, включая объем в расчеты и давая более содержательное представление о ценовом движении. Учитывая и цену, и объем, этот инструмент помогает трейдерам точнее выявлять потенциальные бычьи и медвежьи развороты, особенно в периоды повышенной рыночной активности. Такой дополнительный слой анализа может улучшить принятие решений и дать торговым сигналам больше контекста, поэтому советник на основе пересечений VWMA станет полезным дополнением к аналитическому инструментарию любого трейдера.
Читайте другие мои статьи здесь.
Примечание: Эта статья и советник пересечений VWMA предназначены для образовательных целей и помогают глубже понять технический анализ и торговлю на основе сигналов. Советник служит генератором сигналов; он не исполняет сделки автоматически, поэтому вы сохраняете полный контроль над торговыми решениями. Рекомендуем поэкспериментировать с этим инструментом, тщательно протестировать его на исторических данных и настроить входные параметры под свою стратегию и рыночные предпочтения. Используйте эти сигналы как важную часть анализа и всегда дополнительно проверяйте их собственным суждением. При тщательном тестировании и продуманной настройке этот инструмент может стать ценным дополнением к вашему торговому инструментарию.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/19843
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Алгоритм оптимизации Архимеда — Archimedes Optimization Algorithm (AOA)
Создание торговой системы (Часть 3): Определение минимального уровня риска для достижения реалистичных целей по прибыли
От "лучшего прохода" к устойчивым решениям: исследование поверхности оптимизации в MetaTrader 5
Низкочастотные количественные стратегии в MetaTrader 5: (Часть 1) Настройка OLAP-ориентированного хранилища данных
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Только что попробовал, и сигнал не показывается уже 5 дней, для XAUSD, почему сигнал не показывается?