Забытая классика объёма: индикатор "Finite Volume Elements" для современных рынков
Содержание
- Введение
- Finite Volume Elements
- Реализуем FVE для MetaTrader 5
- Индикатор FinVolEleLinRegSl на основе FVE
- Интерпретация индикаторов
- Тестируем в советнике
- Заключение
Введение
В мире технического анализа индикаторы объёма играют ключевую роль в понимании рыночной динамики и подтверждении ценовых движений. Одним из таких инструментов является индикатор Finite Volume Elements (FVE), впервые подробно описанный в апрельском номере журнала Technical Analysis of STOCKS & COMMODITIES в 2003 году. FVE был разработан как усовершенствованный способ оценки баланса между покупателями и продавцами, учитывая не только направление цены, но и интенсивность объёмов торгов.
В отличие от классических индикаторов объёма, таких как On Balance Volume (OBV) или Accumulation/Distribution, FVE учитывает не только разницу между ценой закрытия и открытия, но и фильтрует незначительные колебания, устраняя рыночный "шум". Это позволяет более точно определять периоды накопления и распределения, а также выявлять истинные тренды на рынке.
В условиях современных финансовых рынков, характеризующихся высокой волатильностью и частыми ложными сигналами, Finite Volume Elements становится особенно актуальным инструментом. Его способность фильтровать незначительные движения и фокусироваться на значимых изменениях объёма делает FVE полезным как для краткосрочных трейдеров, так и для долгосрочных инвесторов, стремящихся повысить точность своих торговых решений.
Стоит отметить, что несмотря на то, что FVE был разработан более двадцати лет назад, он не утратил своей актуальности и может послужить отличную службу в современных реалиях. Как часто бывает на финансовых рынках, новое — это хорошо забытое старое, и возвращение к проверенным инструментам может дать трейдеру то самое преимущество, которого так не хватает в условиях быстро меняющейся рыночной среды.
Finite Volume Elements
В основе FVE лежит идея анализа не только направления изменения цены, но и силы этого движения, выраженной через объём торгов. Индикатор учитывает не только закрытие бара, но и его положение относительно диапазона, а также динамику типичной цены. В результате FVE позволяет более точно определять периоды накопления и распределения, а также моменты, когда на рынке преобладают покупатели или продавцы.
Для расчёта индикатора необходимо выполнить следующие шаги:
- Определить типичные цены для текущего и предыдущего баров:
CurrTP = (CurrHigh + CurrLow + CurrClose) / 3 PrevTP = (PrevHigh + PrevLow + PrevClose) / 3
- Рассчитать метрику движения цены (MF), которая учитывает не только закрытие, но и положение цены внутри бара, а также изменение типичной цены:
MF = (Close - (High + Low) / 2) + (CurrTP - PrevTP) где CurrTP - типичная цена текущего бара PrevTP - типичная цена предыдущего бара - Определить направления движения (Direction):
если MF превышает определённый порог (Cutoff), движение (Direction) считается восходящим (+1), если ниже отрицательного порога - нисходящим (-1), иначе - нейтральным (0)
- Скорректировать объём:
AdjVolume = Volume * Direction где Volume - объём текущего бара Direction - определённое на предыдущем шаге направление движения
- Суммировать скорректированные объёмы за заданный период (Samples) и разделить на общий объём за этот же период:
SumAdjVolume = AdjVolume_1 + AdjVolume_2 + ... + AdjVolume_N SumVolume = Volume_1 + Volume_2 + ... + Volume_N где N - количество баров в выбранном периоде (Samples)
- Рассчитать итоговое значение FVE, выраженное в процентах:
FVE = (SumAdjVolume / SumVolume) * 100%
Рассмотренные формулы позволяют последовательно рассчитать значение индикатора FVE для любого выбранного периода. Реализуем такой индикатор для платформы MetaTrader5.
Реализуем FVE для MetaTrader 5
Создадим индикатор, работающий в подокне графика. Индикатор будет использовать как реальный, так и тиковый объём, что важно для рынка Forex.
Входные параметры индикатора будут такими:
- Samples — период расчёта (по умолчанию 22 бара),
- Threshold (CutOff) — порог чувствительности, фильтрующий незначительные колебания (по умолчанию 0.3),
- Used Volume — тип используемого объёма (реальный или тиковый).
В каталоге терминала \MQL5\Indicators\STOCKS_COMMODITIES\FiniteVolumeElement\ создадим новый индикатор с именем FVE.mq5:
//+------------------------------------------------------------------+ //| FVE.mq5 | //| Copyright 2026, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property description "Finite Volume Elements" #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 1 //--- plot FVE #property indicator_label1 "FVE" #property indicator_type1 DRAW_LINE #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 enum ENUM_USED_VOLUME // Перечисление используемых объёмов { USED_VOLUME_REAL, // Real Volume USED_VOLUME_TICK, // Tick Volume }; //--- input parameters input(name="Samples") int InpSamples = 22; // Период расчёта input(name="Threshold") double InpCutOff = 0.3; // Порог чувствительности input(name="Used Volume") ENUM_USED_VOLUME InpUsedVolume = USED_VOLUME_TICK; // Используемый объём //--- indicator buffers double BufferFVE[]; double BufferVolumePlusMinus[]; double BufferVolumes[]; //--- global variables int samples; double cutoff; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,BufferFVE,INDICATOR_DATA); SetIndexBuffer(1,BufferVolumePlusMinus,INDICATOR_CALCULATIONS); SetIndexBuffer(2,BufferVolumes,INDICATOR_CALCULATIONS); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE); //--- Проверка и установка периода и порога samples=(InpSamples<1? 22 : InpSamples); cutoff=InpCutOff/100.0; //--- Установка имени индикатора и уровня 0 IndicatorSetString(INDICATOR_SHORTNAME,StringFormat("FVE(%d,%.3f)",samples,InpCutOff)); IndicatorSetInteger(INDICATOR_LEVELS,1); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,0.0); ArraySetAsSeries(BufferFVE,true); ArraySetAsSeries(BufferVolumePlusMinus,true); ArraySetAsSeries(BufferVolumes,true); //--- Всё успешно return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int32_t rates_total, const int32_t prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int32_t &spread[]) { //--- Проверка количества доступных баров if(rates_total<samples+1) return(0); //--- Массивы для расчёта - как таймсерии ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(close,true); ArraySetAsSeries(volume,true); ArraySetAsSeries(tick_volume,true); //--- Проверка и расчёт количества просчитываемых баров int limit=rates_total-prev_calculated; //--- Если очередной новый тик - ничего не делаем if(limit==0) return(rates_total); //--- Если первый запуск или изменения исторических данных if(limit>1) { //--- расчёт начинаем от начала исторических данных, //--- инициализируем буферы индикатора нулевыми значениями limit=rates_total-samples-1; ArrayInitialize(BufferFVE,0); ArrayInitialize(BufferVolumePlusMinus,0); ArrayInitialize(BufferVolumes,0); } //--- Расчёт индикатора (либо вся история, либо каждый очередной новый бар) for(int i=limit; i>=0; i--) { //--- Типичные цены для текущего и предыдущего баров double TP_curr=(high[i]+low[i]+close[i])/3.0; double TP_prev=(high[i+1]+low[i+1]+close[i+1])/3.0; //--- Рассчитываем текущие метрику и направление движения цены double MF=(close[i]-(high[i]+low[i])/2.0)+TP_curr-TP_prev; int FveFactor=(MF>cutoff*close[i]) ? 1 : (MF< -cutoff*close[i]) ? -1 : 0; //--- Записываем текущие скорректированный и общий объёмы в буферы long vol=Volume(i,volume,tick_volume); BufferVolumePlusMinus[i]=double(vol*FveFactor); BufferVolumes[i]=(double)vol; //--- Суммируем скорректированный и общий объём за samples баров double FVEsum=0, VolSum=0; for(int j=0;j<samples;j++) { int idx=i+j; FVEsum+=BufferVolumePlusMinus[idx]; // Сумма скорректированного объёма за samples баров VolSum+=BufferVolumes[idx]; // Сумма общего объёма за samples баров } //--- Рассчитываем FVE BufferFVE[i]=(VolSum!=0 ? (FVEsum/VolSum)*100.0 : 0.0); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Возвращает объём в зависимости от выбранного в настройках | //+------------------------------------------------------------------+ long Volume(const int index,const long &volume_real[],const long &volume_tick[]) { return(InpUsedVolume==USED_VOLUME_REAL ? volume_real[index] : volume_tick[index]); } //+------------------------------------------------------------------+
Скомпилируем индикатор и запустим на графике со значением Threshold (InpCutOff) равным 0.2:

Для каждого инструмента и периода графика значение Threshold нужно подбирать по истории (по умолчанию 0.3). Чем больше значение порога чувствительности, фильтрующего незначительные колебания цены, тем более сильные движения считаются незначительными.
Индикатор FinVolEleLinRegSl на основе FVE
С целью более эффективного выявления рыночных прорывов Маркос Катсанос предложил индикатор FinVolEleLinRegSl, который является развитием индикатора Finite Volume Element. Если FVE позволяет определить, преобладают ли на рынке покупатели или продавцы, то FinVolEleLinRegSl дополняет этот анализ оценкой динамики изменений — то есть скорости и направления изменения как самого FVE, так и цены.
Для этого в FinVolEleLinRegSl рассчитываются наклоны (slope) линейной регрессии по FVE и по цене за определённый период. Это позволяет выявлять моменты, когда объём и цена начинают двигаться согласованно или, наоборот, расходятся, и это может быть признаком скорого изменения тренда или подтверждения текущего движения.
В той же папке \MQL5\Indicators\STOCKS_COMMODITIES\FiniteVolumeElement (FVE)\ создадим новый индикатор, тоже работающий в подокне, с именем FinVolEleLinRegSl.mq5:
//+------------------------------------------------------------------+ //| FinVolEleLinRegSl.mq5 | //| Copyright 2026, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property description "Finite Volume Elements + Linear Regression Slope" #property indicator_buffers 5 #property indicator_plots 2 //--- plot FVESlope #property indicator_label1 "FVESlope" #property indicator_type1 DRAW_LINE #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot PriceSlope #property indicator_label2 "PriceSlope" #property indicator_type2 DRAW_LINE #property indicator_color2 clrBlue #property indicator_style2 STYLE_SOLID #property indicator_width2 1 enum ENUM_USED_VOLUME // Перечисление используемых объёмов { USED_VOLUME_REAL, // Real Volume USED_VOLUME_TICK, // Tick Volume }; //--- input parameters input(name="Samples") int InpSamples = 22; // Период расчёта input(name="Threshold") double InpCutOff = 0.3; // Порог чувствительности input(name="SlopePeriod") int InpSlopePeriod = 35; // Период линейной регрессии input(name="PriceSlopeFactor")double InpPriceSlopeFactor = 2500; // Масштаб цены (индивидуально под инструмент) input(name="Used Volume") ENUM_USED_VOLUME InpUsedVolume = USED_VOLUME_TICK; // Используемый объём //--- indicator buffers double BufferFVESlope[]; double BufferPriceSlope[]; double BufferFVE[]; double BufferVolumePlusMinus[]; double BufferVolumes[]; //--- global variables int samples; double cutoff; int slope_period; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- отображаемые буферы SetIndexBuffer(0,BufferFVESlope,INDICATOR_DATA); SetIndexBuffer(1,BufferPriceSlope,INDICATOR_DATA); //--- расчётные буферы SetIndexBuffer(2,BufferFVE,INDICATOR_CALCULATIONS); SetIndexBuffer(3,BufferVolumePlusMinus,INDICATOR_CALCULATIONS); SetIndexBuffer(4,BufferVolumes,INDICATOR_CALCULATIONS); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE); samples=(InpSamples<1? 22 : InpSamples); cutoff=InpCutOff/100.0; slope_period=(InpSlopePeriod<2? 35 : InpSlopePeriod); //--- Короткое имя индикатора IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("FVELinReg(%d,%.3f,%d,%.1f)",samples,InpCutOff,slope_period,InpPriceSlopeFactor)); //--- Уровень 0 индикатора IndicatorSetInteger(INDICATOR_LEVELS,1); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,0.0); ArraySetAsSeries(BufferFVE,true); ArraySetAsSeries(BufferVolumePlusMinus,true); ArraySetAsSeries(BufferVolumes,true); ArraySetAsSeries(BufferFVESlope,true); ArraySetAsSeries(BufferPriceSlope,true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int32_t rates_total, const int32_t prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int32_t &spread[]) { //--- Проверка количества доступных баров if(rates_total<samples+slope_period+1) return(0); //--- Массивы для расчёта - как таймсерии ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(close,true); ArraySetAsSeries(volume,true); ArraySetAsSeries(tick_volume,true); //--- Проверка и расчёт количества просчитываемых баров int limit=rates_total-prev_calculated; //--- Если первый запуск или изменения исторических данных if(limit>1) { limit=rates_total-samples-slope_period-1; ArrayInitialize(BufferFVE,0); ArrayInitialize(BufferVolumePlusMinus,0); ArrayInitialize(BufferVolumes,0); ArrayInitialize(BufferFVESlope,0); ArrayInitialize(BufferPriceSlope,0); } //--- Расчёт индикатора for(int i=limit; i>=0; i--) { //--- Типичные цены для текущего и предыдущего баров (FVE) double TP_curr=(high[i]+low[i]+close[i])/3.0; double TP_prev=(high[i+1]+low[i+1]+close[i+1])/3.0; //--- Рассчитываем текущие метрику и направление движения цены (FVE) double MF=(close[i]-(high[i]+low[i])/2.0)+TP_curr-TP_prev; int FveFactor=(MF>cutoff*close[i]) ? 1 : (MF< -cutoff*close[i]) ? -1 : 0; //--- Записываем текущие скорректированный и общий объёмы в буферы (FVE) long vol=Volume(i,volume,tick_volume); BufferVolumePlusMinus[i]=double(vol*FveFactor); BufferVolumes[i]=(double)vol; //--- Суммируем скорректированный и общий объём за samples баров (FVE) double FVEsum=0, VolSum=0; for(int j=0;j<samples;j++) { int idx=i+j; FVEsum+=BufferVolumePlusMinus[idx]; // Сумма скорректированного объёма за samples баров VolSum+=BufferVolumes[idx]; // Сумма общего объёма за samples баров } //--- Рассчитываем FVE BufferFVE[i]=(VolSum!=0 ? (FVEsum/VolSum)*100.0 : 0.0); // --- Линейная регрессия по FVE и по цене if(i<=rates_total-samples-slope_period-1) { BufferFVESlope[i]=LinearRegSlope(BufferFVE,i,slope_period); BufferPriceSlope[i]=LinearRegSlope(close,i,slope_period)*InpPriceSlopeFactor; } else { BufferFVESlope[i]=EMPTY_VALUE; BufferPriceSlope[i]=EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+ //| Возвращает объём в зависимости от выбранного в настройках | //+------------------------------------------------------------------+ long Volume(const int index,const long &volume_real[],const long &volume_tick[]) { return(InpUsedVolume==USED_VOLUME_REAL ? volume_real[index] : volume_tick[index]); } //+------------------------------------------------------------------+ //| Расчёт наклона линейной регрессии для массива buffer | //+------------------------------------------------------------------+ double LinearRegSlope(const double &buffer[],int start,int period) { bool as_series=ArrayGetAsSeries(buffer); double sumX=0,sumY=0,sumXY=0,sumXX=0; for(int i=0;i<period;i++) { double x=i; double y=(as_series ? buffer[start+period-1-i] : buffer[start+i]); sumX+=x; sumY+=y; sumXY+=x*y; sumXX+=x*x; } double denom=period*sumXX-sumX*sumX; if(denom==0) return(0.0); double slope=(period*sumXY-sumX*sumY)/denom; return(slope); }
Индикатор FinVolEleLinRegSl особенно полезен для трейдеров, которые ищут ранние сигналы смены тенденции или подтверждения силы текущего движения. Его можно использовать для фильтрации ложных сигналов классического FVE, а также для поиска дивергенций между объёмом и ценой. Такой подход был предложен как способ повысить надёжность сигналов индикаторов, использующих объёмы, и дать трейдеру дополнительную информацию о рыночной динамике.
Индикатор анализирует, как меняется соотношение объёма и цены на рынке. Сначала рассчитывается индикатор FVE, дающий данные о силе покупателей или продавцов. Затем определяется, ускоряется или замедляется импульс объёма, а также как быстро меняется сама цена. Для этого строятся две линии: одна отражает скорость изменения FVE, другая — скорость изменения цены:

Интерпретация индикаторов
Finite Volume Elements может использоваться как самостоятельный инструмент для определения фаз накопления и распределения, а также для фильтрации ложных сигналов других индикаторов. Основные его сигналы:- FVE > 0 — преобладают покупки, на рынке доминируют быки,
- FVE < 0 — преобладают продажи, на рынке доминируют медведи,
- Пересечение нулевой линии — потенциальный сигнал к смене тенденции.
FVE хорошо сочетается с трендовыми индикаторами и может использоваться для подтверждения сигналов на вход или выход из позиции.
Индикатор помогает не только увидеть, кто сейчас доминирует на рынке, но и понять, усиливается ли это движение или, наоборот, начинает затухать.
В модификациях FVE с анализом наклона (как в FinVolEleLinRegSl) Маркос Катсанос предлагал использовать наклон (slope) для фильтрации ложных сигналов и для более раннего выявления изменений в динамике объёма и цены. Например, если наклон FVE становится отрицательным, это может быть предупреждением о скором ослаблении тренда, даже если сам FVE ещё положителен. В индикаторе FinVolEleLinRegSl кроме наклона линии FVE отображается и наклон линии цены Close. Это позволяет анализировать взаимное расположение линий наклона линейной регрессии FVE и цены и выявлять схождения/расхождения цены и объёмов. Например, если линия наклона цены растёт, а линия наклона объёмов падает, то это может означать, что движение цены не подкрепляется объёмами, и вскоре может быть разворот тенденции или остановка направленного движения.
Варианты интерпретации индикатора FinVolEleLinRegSl, предложенные Маркосом Катсаносом:
- Основной сигнал индикатора — это пересечение линиями FVESlope и PriceSlope нулевого уровня
- когда обе линии пересекают ноль снизу вверх, это трактуется как ранний сигнал начала восходящего тренда, особенно если движение подтверждается объёмом,
- пересечение нуля сверху вниз обеими линиями — сигнал к возможному развороту вниз,
- Согласованное движение линий (обе линии растут и находятся выше нуля или обе падают и ниже нуля) подтверждает силу текущего тренда,
- Дивергенция между линиями (например, PriceSlope продолжает расти, а FVESlope начинает снижаться) может указывать на ослабление тренда и возможный разворот.
Автор отмечал, что такие расхождения часто предшествуют коррекциям или смене направления движения, - Использование наклона (slope) позволяет фильтровать ложные сигналы классического FVE и получать более ранние предупреждения о смене рыночной динамики.
Честно говоря, и в качестве ремарки: пересечение нуля, а тем более сразу же двумя линиями индикатора — это очень запоздавший сигнал, и я бы его не рассматривал. Поэтому помимо предложенных автором интерпретаций индикатора, стоит обратить внимание на взаимное расположение и форму его линий, что и будет рассмотрено ниже при тестировании.
Отмечается, что индикатор хорошо работает для поиска дивергенций между объёмом и ценой, что позволяет заранее замечать потенциальные развороты.
FinVolEleLinRegSl, как и многие другие индикаторы, желательно использовать в комплексе с другими индикаторами (например, скользящими средними или уровнями поддержки/сопротивления) для повышения надёжности сигналов. Индикатор помогает не только подтверждать текущий тренд, но и вовремя замечать его замедление или смену, что особенно ценно для активных трейдеров.
В целом, рекомендуется использовать сигналы FinVolEleLinRegSl для раннего выявления и подтверждения трендов. Также отмечается его эффективность в фильтрации ложных движений и поиске дивергенций между объёмом и ценой.
Давайте протестируем в советнике некоторые аспекты интерпретации двух этих индикаторов.
Тестируем в советнике
Для тестирования будем использовать только один индикатор — FinVolEleLinRegSl, так как он является производным от FVE, и показывает две линии — величину линейной регрессии наклона FVE и величину линейной регрессии наклона цены.
Для спецификации сигналов индикатора FinVolEleLinRegSl рассмотрим две таблицы: состояния одной (и каждой) линии индикатора и сводную таблицу взаимных расположений двух линий.
Таблица состояний линий индикатора:
| Состояние | Описание | Расшифровка |
|---|---|---|
| GROWING | Прямая линия вверх | Стабильный направленный рост. Сила быков сохраняется. |
| FALLING | Прямая линия вниз | Стабильное направленное падение. Давление медведей сохраняется. |
| TURN_TO_GROW | Форма «V» (минимум) | Точка разворота: наклон сменился с падения на рост. |
| TURN_TO_FALL | Форма «Λ» (максимум) | Точка разворота: наклон сменился с роста на падение. |
Каждая из двух линий индикатора может иметь такие состояния. Для определения общего сигнала индикатора необходимо анализировать взаимное расположение двух его линий.
Таблица взаимных расположений линий индикатора:
| № | Состояние FVE | Состояние Price | Итоговое состояние индикатора | Тип и расшифровка сигнала |
|---|---|---|---|---|
| 1 | GROWING | GROWING | FVE_GROWING_PRICE_GROWING | [Бычий] Тренд вверх: объем подтверждает рост цены. |
| 2 | GROWING | FALLING | FVE_GROWING_PRICE_FALLING | [Бычий] Конвергенция: закупка на падении цены. |
| 3 | GROWING | TURN_TO_GROW | FVE_GROWING_PRICE_TURN_GROW | [Бычий] Подтверждение: цена начала расти вслед за объемом. |
| 4 | GROWING | TURN_TO_FALL | FVE_GROWING_PRICE_TURN_FALL | [Медвежий] Скрытая дивергенция: цена падает при росте объема. |
| 5 | FALLING | FALLING | FVE_FALLING_PRICE_FALLING | [Медвежий] Тренд вниз: объем подтверждает падение цены. |
| 6 | FALLING | GROWING | FVE_FALLING_PRICE_GROWING | [Медвежий] Дивергенция: продажи актива на росте цены. |
| 7 | FALLING | TURN_TO_FALL | FVE_FALLING_PRICE_TURN_FALL | [Медвежий] Подтверждение: цена начала падать вслед за объемом. |
| 8 | FALLING | TURN_TO_GROW | FVE_FALLING_PRICE_TURN_GROW | [Бычий] Скрытая конвергенция: цена растет при падении объема. |
| 9 | TURN_TO_GROW | TURN_TO_GROW | FVE_TURN_GROW_PRICE_TURN_GROW | [Бычий] Синхронный минимум («V»): сильный импульс на покупку. |
| 10 | TURN_TO_GROW | GROWING | FVE_TURN_GROW_PRICE_GROWING | [Бычий] Импульс объема: FVE развернулся вверх вдогонку цене. |
| 11 | TURN_TO_GROW | FALLING | FVE_TURN_GROW_PRICE_FALLING | [Бычий] Начало конвергенции: объем пошел вверх (FVE «V»). |
| 12 | TURN_TO_GROW | TURN_TO_FALL | FVE_TURN_GROW_PRICE_TURN_FALL | [Бычий] Зеркальное схождение: разворот навстречу друг другу. |
| 13 | TURN_TO_FALL | TURN_TO_FALL | FVE_TURN_FALL_PRICE_TURN_FALL | [Медвежий] Синхронный максимум («Λ»): сильный импульс на продажу. |
| 14 | TURN_TO_FALL | FALLING | FVE_TURN_FALL_PRICE_FALLING | [Медвежий] Импульс объема: FVE развернулся вниз вдогонку цене. |
| 15 | TURN_TO_FALL | GROWING | FVE_TURN_FALL_PRICE_GROWING | [Медвежий] Начало дивергенции: объем пошел вниз (FVE «Λ»). |
| 16 | TURN_TO_FALL | TURN_TO_GROW | FVE_TURN_FALL_PRICE_TURN_GROW | [Медвежий] Зеркальное расхождение: разворот в разные стороны. |
Исходя из этих двух таблиц мы создадим перечисления, отражающие форму линий индикатора и их взаимное расположение. Данные из второй таблицы будем использовать в качестве фильтра сигналов советника.
Если сигнал от советника на покупку, а фильтр показывает состояние на продажу, то просто такой сигнал будем пропускать. Т.е. сделаем самое простое — если сигналы от советника и фильтра не совпадают по направлению, то такой сигнал не учитывается ТС.
Советник для тестов возьмём из CodeBase: https://www.mql5.com/ru/code/63916. Это простой советник, торгующий по сигналам от стандартных индикаторов Williams' Percent Range (WPR) и полос Боллинджера (BB).
Сохраним советник в папке \MQL5\Experts\STOCKS_COMMODITIES\FiniteVolumeElement (FVE)\ под именем ExpFVEWPRBB.mq5.
Добавим в него отключаемую фильтрацию сигналов по индикатору FinVolEleLinRegSl. Для указания типов объёмов индикатора и возврата состояния его линий определим перечисления:
//+------------------------------------------------------------------+ //| ExpFVEWPRBB.mq5 | //| Copyright 2026, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| Включаемые файлы | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> #include <Arrays\ArrayLong.mqh> //+------------------------------------------------------------------+ //| Перечисления | //+------------------------------------------------------------------+ //--- Типы сигналов enum ENUM_SIGNAL_TYPE { SIGNAL_TYPE_NONE, // Нет сигнала SIGNAL_TYPE_LONG, // Сигнал на покупку SIGNAL_TYPE_SHORT, // Сигнал на покупку }; //--- Перечисление используемых объёмов enum ENUM_USED_VOLUME { USED_VOLUME_REAL, // Real Volume USED_VOLUME_TICK, // Tick Volume }; //--- Состояния линий FVESlope и PriceSlope enum ENUM_LINE_SLOPE_STATE { LINE_SLOPE_STATE_UNKNOWN, // Состояние не определено LINE_SLOPE_STATE_FLAT, // Низкая активность LINE_SLOPE_STATE_GROWING, // Объёмы растут LINE_SLOPE_STATE_FALLING, // Объёмы падают LINE_SLOPE_STATE_TURN_TO_GROW, // Переход к росту объёмов LINE_SLOPE_STATE_TURN_TO_FALL // Переход к снижению объёмов }; //--- Взаимные состояния линии FVESlope и PriceSlope enum ENUM_FVE_STATE { FVE_STATE_UNKNOWN, // Состояние не определено //--- Группа свойств FVE GROWING (Рост) FVE_STATE_FVE_GROWING_PRICE_GROWING, // FVE растет, Цена растет FVE_STATE_FVE_GROWING_PRICE_FALLING, // FVE растет, Цена падает FVE_STATE_FVE_GROWING_PRICE_TURN_GROW, // FVE растет, Цена развернулась вверх FVE_STATE_FVE_GROWING_PRICE_TURN_FALL, // FVE растет, Цена развернулась вниз //--- Группа свойств FVE FALLING (Падение) FVE_STATE_FVE_FALLING_PRICE_FALLING, // FVE падает, Цена падает FVE_STATE_FVE_FALLING_PRICE_GROWING, // FVE падает, Цена растет FVE_STATE_FVE_FALLING_PRICE_TURN_FALL, // FVE падает, Цена развернулась вниз FVE_STATE_FVE_FALLING_PRICE_TURN_GROW, // FVE падает, Цена развернулась вверх //--- Группа свойств FVE TURN_GROW (Разворот вверх) FVE_STATE_FVE_TURN_GROW_PRICE_GROWING, // FVE развернулся вверх, Цена растет FVE_STATE_FVE_TURN_GROW_PRICE_FALLING, // FVE развернулся вверх, Цена падает FVE_STATE_FVE_TURN_GROW_PRICE_TURN_GROW, // FVE развернулся вверх, Цена развернулась вверх FVE_STATE_FVE_TURN_GROW_PRICE_TURN_FALL, // FVE развернулся вверх, Цена развернулась вниз //--- Группа свойств FVE TURN_FALL (Разворот вниз) FVE_STATE_FVE_TURN_FALL_PRICE_FALLING, // FVE развернулся вниз, Цена падает FVE_STATE_FVE_TURN_FALL_PRICE_GROWING, // FVE развернулся вниз, Цена растет FVE_STATE_FVE_TURN_FALL_PRICE_TURN_FALL, // FVE развернулся вниз, Цена развернулась вниз FVE_STATE_FVE_TURN_FALL_PRICE_TURN_GROW // FVE развернулся вниз, Цена развернулась вверх }; //+------------------------------------------------------------------+ //| Структуры | //+------------------------------------------------------------------+
Во входных параметрах добавим параметры индикатора, а в глобальных переменных — переменные для хранения скорректированных значений входных параметров:
//+------------------------------------------------------------------+ //| Структуры | //+------------------------------------------------------------------+ //--- Структура позиций struct SData { CArrayLong list_tickets; // Список тикетов открытых позиций double total_volume; // Общий объём открытых позиций }; //--- Структура данных позиций по типам struct SDataPositions { SData Buy; // Данные позиций Buy SData Sell; // Данные позиций Sell }Data; //+------------------------------------------------------------------+ //| Макроподстановки | //+------------------------------------------------------------------+ #define DATA_COUNT 3 // Количество получаемых данных от индикаторов (3 и более) #define ENV_ATTEMPTS 3 // Количество попыток ожидания получения окружения #define ENV_WAIT_ATTEMPT 1000 // Количество миллисекунд ожидания обновления окружения #define SPREAD_MLTP 3 // Множитель спреда для дистанции стоп-приказов //+------------------------------------------------------------------+ //| Входные параметры | //+------------------------------------------------------------------+ //--- WPR input int InpPeriodWPR = 32; /* WPR calculation period */ // Период расчёта WPR input double InpOverboughtWPR = -20; /* WPR Overbought Level */ // Уровень перекупленности WPR input double InpOversoldWPR = -80; /* WPR Oversold Level */ // Уровень перепроданности WPR //--- BB input int InpPeriodBB = 58; /* BB calculation period */ // Период расчёта BB input double InpDeviationBB = 2.0; /* BB deviations */ // Отклонения BB input int InpShiftBB = 0; /* BB shift */ // Сдвиг BB input ENUM_APPLIED_PRICE InpPriceBB = PRICE_CLOSE; /* BB applied price */ // Цена расчёта BB //--- ATR input int InpPeriodATR = 64; /* ATR calculation period */ // Период расчёта ATR //--- FinVolEleLinRegSl input int InpSamples = 22; /* FVERegSl Samples */ // Период расчёта input double InpCutOff = 0.3; /* FVERegSl Threshold */ // Порог чувствительности input int InpSlopePeriod = 35; /* FVERegSl SlopePeriod */ // Период линейной регрессии input double InpPriceSlopeFactor= 2500; /* FVERegSl PriceSlopeFactor */ // Масштаб цены (индивидуально под инструмент) input ENUM_USED_VOLUME InpUsedVolume = USED_VOLUME_TICK; /* FVERegSl Used Volume */ // Используемый объём input bool InpUseFilterByFVE = true; /* Use signal filtering by FVERegSl */ // Использовать фильтрацию сигналов по FVERegSl //--- Торговля input double InpVolume = 0.1; /* Position volume */ // Объем позиции sinput ulong InpDeviation = 10; /* Slippage (in points) */ // Проскальзывание (в пунктах) sinput ulong InpMagic = 123456; /* Magic number */ // Магик input int InpStopLoss = -1; /* Stop loss (in points), 0 - none, -1 - half of BB */ // Stop loss (в пунктах), 0 - отсутствует, -1 - половина BB input int InpTakeProfit = -1; /* Take profit (in points), 0 - none, -1 - ATR value */ // Take profit (в пунктах), 0 - отсутствует, -1 - значение ATR input double InpSLMltp = 2.6; /* Stop loss size multiplier, if SL==-1 */ // Множитель размера Stop loss, если Stop loss==-1 input double InpTPMltp = 1.3; /* Take profit size multiplier, if TP==-1 */ // Множитель размера Take profit, если Take profit==-1 //+------------------------------------------------------------------+ //| Глобальные переменные | //+------------------------------------------------------------------+ CTrade trade; // Объект торгового класса int handle_wpr; // Хэндл индикатора WPR int handle_bb; // Хэндл индикатора BB int handle_atr; // Хэндл индикатора ATR int handle_fve; // Хэндл индикатора FVERegSl double wpr[DATA_COUNT]={}; // Массив значений WPR double bb0[DATA_COUNT]={}; // Массив значений BB, буфер 0 (Upper) double bb1[DATA_COUNT]={}; // Массив значений BB, буфер 1 (Lower) double bb2[DATA_COUNT]={}; // Массив значений BB, буфер 2 (Middle) double atr[DATA_COUNT]={}; // Массив значений ATR double fv0[DATA_COUNT]={}; // Массив значений FVESlope double fv1[DATA_COUNT]={}; // Массив значений FVEPriceSlope MqlRates prc[DATA_COUNT]={}; // Массив цен и времени int period_wpr; // Период расчёта WPR double overbought_wpr; // Уровень перекеупленности WPR double oversold_wpr; // Уровень перепроданности WPR int period_bb; // Период расчёта BB double deviation_bb; // Отклонения BB int shift_bb; // Сдвиг BB int period_atr; // Период расчёта ATR int samples; // Период расчёта FVERegSl double cutoff; // Порог чувствительности FVERegSl int slope_period; // Период линейной регрессии FVERegSl double lot; // Объём позиции string program_name; // Имя программы int prev_total; // Количество позиций на прошлой проверке bool netto; // Признак нетто-счёта //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+
В обработчике OnInit() советника скорректируем входные параметры индикатора и создадим его хэндл:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Если счёт не с типом хеджинг - ставим флаг и сообщаем о некорректной работе советника netto=false; if(AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) { Print("The advisor is designed for use on a hedging account. Correct operation on a netting account is not guaranteed."); netto=true; } //--- Устанавливаем и корректируем входные переменные индикаторов //--- WPR period_wpr=(InpPeriodWPR<1 ? 14 : InpPeriodWPR); overbought_wpr=(InpOverboughtWPR<-99 ? -99 : InpOverboughtWPR> 0 ? 0 : InpOverboughtWPR); oversold_wpr =(InpOversoldWPR <-100 ? -100 : InpOversoldWPR >-1 ? -1 : InpOversoldWPR); if(overbought_wpr<=oversold_wpr) overbought_wpr+=1; //--- BB period_bb=(InpPeriodBB<2 ? 20 : InpPeriodBB); deviation_bb=InpDeviationBB; shift_bb=InpShiftBB; //--- ATR period_atr=(InpPeriodATR<1 ? 14 : InpPeriodATR); //--- FVERegSl samples=(InpSamples<1? 22 : InpSamples); cutoff=InpCutOff/100.0; slope_period=(InpSlopePeriod<2? 35 : InpSlopePeriod); //--- Инициализируем массивы значений индикаторов ArrayInitialize(wpr,EMPTY_VALUE); ArrayInitialize(bb0,EMPTY_VALUE); ArrayInitialize(bb1,EMPTY_VALUE); ArrayInitialize(bb2,EMPTY_VALUE); ArrayInitialize(atr,EMPTY_VALUE); ArrayInitialize(fv0,EMPTY_VALUE); ArrayInitialize(fv1,EMPTY_VALUE); ZeroMemory(prc); //--- Создаём хэндлы индикаторов //--- WPR handle_wpr=iWPR(Symbol(),PERIOD_CURRENT,period_wpr); if(handle_wpr==INVALID_HANDLE) { PrintFormat("%s: Failed to create iWPR(%d) handle",__FUNCTION__,period_wpr); return INIT_FAILED; } //--- BB handle_bb=iBands(Symbol(),PERIOD_CURRENT,period_bb,shift_bb,deviation_bb,InpPriceBB); if(handle_bb==INVALID_HANDLE) { PrintFormat("%s: Failed to create iBands(%d,%d,%.3f,%s) handle",__FUNCTION__,period_bb,shift_bb,deviation_bb,EnumToString(InpPriceBB)); return INIT_FAILED; } //--- ATR handle_atr=iATR(Symbol(),PERIOD_CURRENT,period_atr); if(handle_atr==INVALID_HANDLE) { PrintFormat("%s: Failed to create iATR(%d) handle",__FUNCTION__,period_atr); return INIT_FAILED; } //--- FVERegSl handle_fve=iCustom(Symbol(),PERIOD_CURRENT,"FinVolEleLinRegSl",samples,cutoff,slope_period,InpPriceSlopeFactor,InpUsedVolume); if(handle_fve==INVALID_HANDLE) { PrintFormat("%s: Failed to create FinVolEleLinRegSl(%d,%.3f,%d,%.1f) handle",__FUNCTION__,samples,cutoff,slope_period,InpPriceSlopeFactor); return INIT_FAILED; } //--- Имя программы и количество позиций на прошлой проверке program_name=MQLInfoString(MQL_PROGRAM_NAME); prev_total=0; //--- Автоматическая установка типа заполнения trade.SetTypeFilling(GetTypeFilling()); //--- Установка магика trade.SetExpertMagicNumber(InpMagic); //--- Установка проскальзывания trade.SetDeviationInPoints(InpDeviation); //--- Установка лота с корректировкой введённого значения lot=CorrectLots(InpVolume); //--- Всё успешно PrintFormat("%s::%s: Initialization was successful",program_name,__FUNCTION__); return(INIT_SUCCEEDED); }
Естественно, в советнике объявлен и инициализирован массив для хранения данных индикатора — точно так же, как и все остальные массивы для хранения данных всех используемых в советнике индикаторов.
Так же — по аналогии с функциями записи, хранения и получения данных индикаторов, созданы функции для работы с данными индикатора FinVolEleLinRegSl.
В обработчике OnTick() советника сигнал, полученный от индикаторов WPR и Bollinger Bands, корректируем по состоянию индикатора FinVolEleLinRegSl:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Получаем в массивы данные трёх баров индикаторов и цен if(!CopyIndicatorsData(1) || !CopyPricesData(1)) return; //--- Заполнение списков тикетов позиций int positions_total=PositionsTotal(); if(prev_total!=positions_total) { if(!FillingListTickets(Symbol(),InpMagic)) return; prev_total=positions_total; } //--- Получаем сигналы от индикаторов ENUM_SIGNAL_TYPE signal_wpr=SignalWPR(); ENUM_SIGNAL_TYPE signal_bb=SignalBB(); //--- Общий сигнал ENUM_SIGNAL_TYPE signal=(signal_wpr==signal_bb ? signal_wpr : SIGNAL_TYPE_NONE); //--- Если используется фильтрация сигналов советника, if(InpUseFilterByFVE) { //--- корректируем сигнал по состоянию индикатора FinVolEleLinRegSl signal=SignalByFVELinRegSl(signal,0); } //--- Торгуем по сигналам TradeProcess(signal); }
Функция фильтрации согналов советника по состоянию линий индикатора FinVolEleLinRegSl:
//+------------------------------------------------------------------+ //| Сигнал FinVolEleLinRegSl на указанном по индексу баре | //+------------------------------------------------------------------+ ENUM_SIGNAL_TYPE SignalByFVELinRegSl(const ENUM_SIGNAL_TYPE signal,const int index) { //--- Получаем состояние индикатора FVELinRegSl на указанном индексе ENUM_FVE_STATE fve_state=StateFVELinRegSl(index); //--- Раскомментировав строки, получим вывод состояния индикатора в комментарии на графике /* static string text=""; string txt=StringFormat("\nStateFVE: %s (%s)",StringSubstr(EnumToString(fve_state),10),FVEStateDescription(fve_state)); if(text!=txt) { text=txt; Comment(text); } */ //--- В зависимости от направления сигнала просто ограничиваем противоположные сигналы по фильтру switch(signal) { //--- при сигнале на покупку case SIGNAL_TYPE_LONG : //--- если состояние фильтра показывает противоположный сигнал - делаем основной сигнал отсутствующим switch(fve_state) { case FVE_STATE_FVE_FALLING_PRICE_FALLING : //[Медвежий] Подтвержденное падение (Trend) case FVE_STATE_FVE_FALLING_PRICE_GROWING : //[Медвежий] Устойчивая дивергенция (Distribution) case FVE_STATE_FVE_FALLING_PRICE_TURN_FALL : //[Медвежий] Цена подтвердила падение объема case FVE_STATE_FVE_GROWING_PRICE_TURN_FALL : //[Медвежий] Скрытая дивергенция (Price Reversal) case FVE_STATE_FVE_TURN_FALL_PRICE_FALLING : //[Медвежий] Импульс объема вдогонку цене case FVE_STATE_FVE_TURN_FALL_PRICE_GROWING : //[Медвежий] Начало дивергенции (FVE Top) case FVE_STATE_FVE_TURN_FALL_PRICE_TURN_FALL : //[Медвежий] Синхронный разворот вниз (Strong Signal) case FVE_STATE_FVE_TURN_FALL_PRICE_TURN_GROW : //[Медвежий] Зеркальное расхождение (Volume Reversal) return SIGNAL_TYPE_NONE; break; //--- в ином случае, если основной сигнал совпадает с направлением сигнала по фильтру, возвращаем сигнал без изменений default: return signal; } break; //--- при сигнале на продажу case SIGNAL_TYPE_SHORT : //--- если состояние фильтра показывает противоположный сигнал - делаем основной сигнал отсутствующим switch(fve_state) { case FVE_STATE_FVE_GROWING_PRICE_GROWING : //[Бычий] Подтвержденный рост (Trend) case FVE_STATE_FVE_GROWING_PRICE_FALLING : //[Бычий] Устойчивая конвергенция (Accumulation) case FVE_STATE_FVE_GROWING_PRICE_TURN_GROW : //[Бычий] Цена подтвердила рост объема case FVE_STATE_FVE_FALLING_PRICE_TURN_GROW : //[Бычий] Скрытая конвергенция (Price Reversal) case FVE_STATE_FVE_TURN_GROW_PRICE_GROWING : //[Бычий] Импульс объема вдогонку цене case FVE_STATE_FVE_TURN_GROW_PRICE_FALLING : //[Бычий] Начало конвергенции (FVE Bottom) case FVE_STATE_FVE_TURN_GROW_PRICE_TURN_GROW : //[Бычий] Синхронный разворот вверх (Strong Signal) case FVE_STATE_FVE_TURN_GROW_PRICE_TURN_FALL : //[Бычий] Зеркальное схождение (Volume Reversal) return SIGNAL_TYPE_NONE; break; //--- в ином случае, если основной сигнал совпадает с направлением сигнала по фильтру, возвращаем сигнал без изменений default: return signal; } break; //--- возвращаем сигнал без изменений default: return signal; } }
В функцию передаётся текущий сигнал советника и индекс бара, на котором необходимо получить состояние индикатора FinVolEleLinRegSl. Если сигнал советника на покупку, а состояние индикатора на продажу, то возвращается состояние отсутствия сигнала. То же самое и для сигнала на продажу. Это самое простое, что можно сделать для быстрого теста. А вообще — индикатор имеет множество различных состояний, и каждое необходимо обрабатывать соответствующим образом.
Некоторые состояния могут выступать в качестве строгого фильтра: сигнал советника и сигнал фильтра должны совпадать для принятия решения. Другие состояния указывают лишь на вероятное наступление события в будущем. Такие ситуации не следует использовать как фильтр; вместо этого необходимо дождаться подтверждения события индикатором, а уже после этого принимать торговое решение, которое не обязательно должно приводить к открытию новой позиции.
В функции, в самом начале, есть закомментированный блок кода, который выводит на график в комментарии состояние индикатора. То есть, раскомментировав этот блок кода, можно в визуальном тестере наглядно посмотреть состояния индикатора и понять, как правильно их обрабатывать в советнике.
С полным кодом советника можно ознакомиться в прикреплённых к статье файлах.
Для правильной работы советника файл индикатора должен находиться в папке расположения советника: \MQL5\Experts\STOCKS_COMMODITIES\FiniteVolumeElement (FVE)\. Файл индикатора тоже можно найти в прикреплённых к статье файлах.
Скомпилируем советник, установим в тестере стратегий параметры тестирования на дневном графике EURUSD с 01.01.2023 по текущую дату:

Во вкладке параметров советника отключим фильтрацию сигналов, оставив остальные параметры со значениями по умолчанию:

После запуска тестирования за указанный период времени, видим такие результаты:


Теперь включим фильтрацию сигналов советника по индикатору FinVolEleLinRegSl:

и запустим тот же тест ещё раз.
Теперь видим такой результат:


При сравнении графиков видно, что при отключенной фильтрации в конце 2024 — начале 2025 годов есть две существенные просадки по балансу, в то время как при включенной фильтрации подобная одна просадка была в конце 2024 года.
Здесь мы смогли избавиться от одного убыточного периода. При этом количество сделок стало меньше, что естественно, так как некоторые сделки не были открыты из-за работы фильтра. Соответственно, общая прибыль стала меньше при практически одинаковой просадке (с фильтром она всё-таки чуть меньше). Количество убыточных трейдов тоже незначительно уменьшилось.
Хороший ли это результат — судить вам. Но повторю: фильтр абсолютно грубый. Он просто отключает сигналы советника в случае, если направление сигнала не совпадает с направлением состояния фильтра.
Для тонкой настройки фильтра необходимо просматривать в визуальном режиме тестера состояние графика, направление сделки и состояние фильтра. В некоторых случаях может потребоваться не запрет открытия позиции, а перенос стопа в безубыток или включение трейлинга, а где-то, вероятно, стоит либо открыть противоположную позицию по рынку, либо выставить лимитный отложенный ордер с требуемым направлением.
Тема точной настройки фильтра выходит за рамки данной статьи. Но если кого-то заинтересует такая возможность, то он вполне сможет сам попробовать дополнить перечисление типов сигналов советника, и из функции фильтрации возвращать требуемые по ситуации сигналы. Думаю, это было бы вполне интересно.
Заключение
Сегодня мы рассмотрели индикатор Finite Volume Elements и его расширенную версию Finite Volume Elements + Linear Regression Slope. В результате простого тестирования получили незначительное улучшение работы советника со снижением просадки, но с уменьшением прибыльности. Но всё же кажется, что этот индикатор вполне заслуживает внимания. Несмотря на то, что идея индикатора появилась много лет назад, благодаря современным торговым платформам, таким как MetaTrader 5, мы можем использовать проверенные временем инструменты в новых условиях, наглядно тестируя и адаптируя ТС под свои задачи и стратегии.
Все файлы — индикаторов и советника прикреплены к статье для самостоятельного изучения, доработок и тестирования. Не бойтесь возвращаться к классике технического анализа — возможно, именно там вы найдёте ключ к успеху на рынке!
Программы, используемые в статье:
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | FVE.mqh | Индикатор | Индикатор Finite Volume Elements |
| 2 | FinVolEleLinRegSl.mqh | Индикатор | Индикатор Finite Volume Elements + Linear Regression Slope |
| 3 | ExpFVEWPRBB.mqh | Советник | Советник для тестирования индикаторов |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Нейросети в трейдинге: Асинхронная обработка событий в потоковых моделях (EVA-Flow)
Внедряем систему непрерывной адаптации LLM для алгоритмического трейдинга
Нейросети в трейдинге: Возмущённые модели пространства состояний для анализа рыночной динамики (Окончание)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования