//+------------------------------------------------------------------+ //| 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_total1) { //--- расчёт начинаем от начала исторических данных, //--- инициализируем буферы индикатора нулевыми значениями 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