вместо CodeBase - iPrice

24 апреля 2025, 15:21
Maxim Kuznetsov
0
31

фильтр цены, как умножение цен последних трёх баров на матрицу коэфф. В какой-то момент достало постоянно использовать ENUM_APPLIED_PRICE и во многих приложениях используется более тонкий тюнинг. Поэтому вот такая нетленка

//+------------------------------------------------------------------+
//|                                                       iPrice.mq5 |
//|                                                  Maxim Kuznetsov |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Maxim Kuznetsov"
#property link      "https://luxtrade.unaux.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot iPrice
#property indicator_label1  "iPrice"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- коэффициенты
// цены трёх баров
input double   open_0=0.0;
input double   high_0=0.0;
input double   low_0=0.0;
input double   close_0=1.0;

input double   open_1=0.0;
input double   high_1=0.0;
input double   low_1=0.0;
input double   close_1=0.0;

input double   open_2=0.0;
input double   high_2=0.0;
input double   low_2=0.0;
input double   close_2=0.0;
// статистические: медиана, максимум,минимум
input double   open_median=0.0;
input double   high_median=0.0;
input double   low_median=0.0;
input double   close_median=0.0;

input double   open_max=0.0;
input double   high_max=0.0;
input double   low_max=0.0;
input double   close_max=0.0;

input double   open_min=0.0;
input double   high_min=0.0;
input double   low_min=0.0;
input double   close_min=0.0;

double         PRICE[];
enum ENUM_PRICE {
   OPEN=0,HIGH,LOW,CLOSE,
   TOTAL_PRICES
};
enum ENUM_BAR {
   BAR_0=0,BAR_1,BAR_2,MEDIAN,MAX,MIN,
   TOTAL_BARS
};
enum ENUM_NEED {
   NEED_OPEN=0,NEED_HIGH,NEED_LOW,NEED_CLOSE,NEED_MEDIAN,NEED_MAX,NEED_MIN,
   TOTAL_NEEDS
};
double         WEIGHT[TOTAL_PRICES][TOTAL_BARS];  // коэфф.
double         NORM=0.0;      // нормировка=(сумма коэфф)
double           DATA[TOTAL_PRICES][TOTAL_BARS];  // данные к которым применяем
bool           NEEDS[TOTAL_NEEDS];      // используемые столбцы
MqlRates RATES[];
int OnInit()
{
   // буфер и граф
   SetIndexBuffer(0,PRICE,INDICATOR_DATA);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   ArraySetAsSeries(PRICE,true);
   // нормировка := сумма коэфф.
   NORM+=open_0+high_0+low_0+close_0;
   NORM+=open_1+high_1+low_1+close_1;
   NORM+=open_2+high_2+low_2+close_2;
   NORM+=open_median+high_median+low_median+close_median;
   NORM+=open_max+high_max+low_max+close_max;
   NORM+=open_min+high_min+low_min+close_min;
   // заполняем веса
   WEIGHT[OPEN][0]=open_0;          WEIGHT[HIGH][0]=high_0;WEIGHT[LOW][0]=low_0;WEIGHT[CLOSE][0]=close_0;
   WEIGHT[OPEN][1]=open_1;          WEIGHT[HIGH][1]=high_1;WEIGHT[LOW][1]=low_1;WEIGHT[CLOSE][1]=close_1;
   WEIGHT[OPEN][2]=open_2;          WEIGHT[HIGH][2]=high_2;WEIGHT[LOW][2]=low_2;WEIGHT[CLOSE][2]=close_2;
   WEIGHT[OPEN][MEDIAN]=open_median;WEIGHT[HIGH][MEDIAN]=high_median;WEIGHT[LOW][MEDIAN]=low_median;WEIGHT[CLOSE][MEDIAN]=close_median;
   WEIGHT[OPEN][MAX]=open_max;WEIGHT[HIGH][MAX]=high_max;WEIGHT[LOW][MAX]=low_max;WEIGHT[CLOSE][MAX]=close_max;
   WEIGHT[OPEN][MIN]=open_min;WEIGHT[HIGH][MIN]=high_min;WEIGHT[LOW][MIN]=low_min;WEIGHT[CLOSE][MIN]=close_min;
   // проверяем веса (не должно быть отрицательных)
   for(int i=0;i<TOTAL_PRICES && NORM!=0;i++) {
      for(int j=0;j<TOTAL_BARS;j++) {
         if (WEIGHT[i][j]<0.0) {
            PrintFormat("negative mult. %f",WEIGHT[i][j]);
            NORM=0;
            // можно вернуть INIT_FAILED, но это крайне нехорошо
            break;
         }
      }
   }
   // какие данные будут использоваться в рассчётах
   ArrayInitialize(NEEDS,false);
   if (open_0!=0.0 || open_1!=0.0 || open_2!=0.0 || open_median!=0.0 || open_max!=0.0 || open_min!=0.0) NEEDS[NEED_OPEN]=true;
   if (high_0!=0.0 || high_1!=0.0 || high_2!=0.0 || high_median!=0.0 || high_max!=0.0 || high_min!=0.0)  NEEDS[NEED_HIGH]=true;
   if (low_0!=0.0 || low_1!=0.0 || low_2!=0.0 || low_median!=0.0 || low_max!=0.0 || low_min!=0.0 ) NEEDS[NEED_LOW]=true;
   if (close_0!=0.0 || close_1!=0.0 || close_2!=0.0 || close_median!=0.0 || close_max!=0.0 || close_min!=0.0) NEEDS[NEED_CLOSE]=true;
   if (open_median!=0.0 || high_median!=0.0 || low_median!=0.0 || close_median!=0.0) NEEDS[NEED_MEDIAN]=true;
   if (open_max!=0.0 || high_max!=0.0 || low_max!=0.0 || close_max!=0.0) NEEDS[NEED_MAX]=true;
   if (open_min!=0.0 || high_min!=0.0 || low_min!=0.0 || close_min!=0.0) NEEDS[NEED_MIN]=true;
   // рабочий массив, для получения котировок
   ArrayResize(RATES,3);
   ArraySetAsSeries(RATES,true);
   
   return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
                const int 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 int &spread[])
{
   for(int bar=prev_calculated>0?prev_calculated-1:0 ; bar<rates_total ; bar++) {
      int idx=rates_total - bar - 1;
      
      if (bar==0) PRICE[idx]=0.0;
      else PRICE[idx]=PRICE[idx+1];
      
      if (NORM==0 || CopyRates(_Symbol,_Period,idx,3,RATES)!=3) {
         continue;
      }
      ArrayInitialize(DATA,0);      
      if (NEEDS[NEED_OPEN]) { DATA[OPEN][0]=RATES[0].open; DATA[OPEN][1]=RATES[1].open; DATA[OPEN][2]=RATES[2].open; }
      if (NEEDS[NEED_HIGH]) { DATA[HIGH][0]=RATES[0].high; DATA[HIGH][1]=RATES[1].high; DATA[HIGH][2]=RATES[2].high; }
      if (NEEDS[NEED_LOW])  { DATA[LOW][0]=RATES[0].low;  DATA[LOW][1]= RATES[1].low; DATA[LOW][2]=RATES[2].low; }
      if (NEEDS[NEED_CLOSE]){ DATA[CLOSE][0]=RATES[0].close;DATA[CLOSE][1]=RATES[1].close; DATA[CLOSE][2]=RATES[2].close; }
      if (NEEDS[NEED_MEDIAN]) { 
         for(int p=0;p<TOTAL_PRICES;p++) {
            if (WEIGHT[p][MEDIAN]!=0) DATA[p][MEDIAN]=Median(DATA[p][0],DATA[p][1],DATA[p][2]);
         }
      }
      if (NEEDS[NEED_MAX] || NEEDS[NEED_MIN]) { 
         for(int p=0;p<TOTAL_PRICES;p++) {
            if (WEIGHT[p][MAX]!=0) DATA[p][MAX]=Max(DATA[p][0],DATA[p][1],DATA[p][2]);
            if (WEIGHT[p][MIN]!=0) DATA[p][MIN]=Min(DATA[p][0],DATA[p][1],DATA[p][2]);
         }
      }
      
      double sum=0.0;
      for(int i=0;i<TOTAL_PRICES;i++) {
         for(int j=0;j<TOTAL_BARS;j++) {
            sum+=DATA[i][j]*WEIGHT[i][j];
         }
      }
      sum/=NORM;
      PRICE[idx]=sum;
   }
   return(rates_total);
}

double Median(const double &v1,const double &v2,const double &v3)
{
   if (v1<=v2 && v1>=v3) return v1;
   if (v2<=v1 && v2>=v3) return v2;
   return v3;
}
double Max(const double &v1,const double &v2,const double &v3)
{
   if (v1>=v2 && v1>=v3) return v1;
   if (v2>=v1 && v2>=v3) return v2;
   return v3;
}
double Min(const double &v1,const double &v2,const double &v3)
{
   if (v1<=v2 && v1<=v3) return v1;
   if (v2<=v1 && v2<=v3) return v2;
   return v3;
}

Как использовать, на мой взгляд очевидно : задать нужные коэффициенты в input :-)


Файлы:
iPrice.mq5  15 kb
iPrice.ex5  16 kb