Article-20940-MQL5-Finite-V.../FVE.mq5
2026-03-24 20:26:12 +07:00

145 行
12 KiB
MQL5

//+------------------------------------------------------------------+
//| 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]);
}
//+------------------------------------------------------------------+