Bescheuerter Workaround für AMA Envelopes

 

Hallo liebe ForistInnen,

hier habe ich ein kleines Projekt, an dem ich immer mal wieder gearbeitet habe, es handelt sich um Envelopes, aber mit AMA als Berechnungsgrundlage.
Viele wissen ja um die Vorteile des AMA und dass er eine Noise-Reduction Formel enthält, die auf einen Perry Kaufman zurückgeht.

Da ich selbst nicht aus dem Programmierbereich komme und einen schweren Start hatte, ist dieses Thema in einem Niveau gehalten, das gerade für Neulinge nützlich ist.


Eigentlich hätte es ganz einfach sein müssen: Das Handle des AMAs in das Handle des Envelopes einsetzen, ein Shift für Beide verwenden, damit die Plots immer gleich verschoben werden, aber das hier passierte:


AnfangOhneShift

Mit Shift=0 sah noch Alles ganz gut aus.




AnfangShit10

Dann aber das. Man sehe sich die Kurve an.



AnfangShift-10

Bei Shift=-10 wird sie zwar verschoben, hört jedoch zu früh auf.


Hier der FALSCHE Code:

//+------------------------------------------------------------------+
//|                                              iAMAEnvelopes01.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3                //die Zahl der verwendeten Buffers und Plots wurden angepasst s.u.
#property indicator_plots   3
#property indicator_type1   DRAW_LINE        //bestimmte Eigenschaften der Plots werden hier eingegeben
#property indicator_color1  clrAqua
#property indicator_label1  "Upper band"
#property indicator_width1  2
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrAqua
#property indicator_label2  "Lower band"
#property indicator_width2  2
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGold
#property indicator_label3  "AMA"
#property indicator_width3  2

input int InpPeriodAMA=10;      // AMA period
input int InpFastPeriodEMA=2;   // Fast EMA period
input int InpSlowPeriodEMA=20;  // Slow EMA period
input int InpShiftAMA=0;        // AMA shift

/*input*/ int                InpMAPeriod=1;              // Period      *diese Inputs wurden festgesetzt, da der
/*input*/ int                InpMAShift=0;                // Shift      eingebaute iMA des Envelopes-Indikators
/*input*/ ENUM_MA_METHOD     InpMAMethod=MODE_SMA;        // Method     hier nicht benötigt wird.*
input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price
input double             InpDeviation=1.0;            // Deviation

double                   ExtAMABuffer[];

double                   ExtUpBuffer[];
double                   ExtDownBuffer[];

// diese drei Buffer werden benötigt. Einer enthält die Werte des AMA für jeden Balken. Zu diesen Werten wird
// die Deviation der Envelopes addiert bzw. subtrahiert. Dies geschieht jedoch automatisch innerhalb deren
// Handles iAMA bzw. iEnvelopes.

int Envelopeshandle, AMAhandle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtUpBuffer,INDICATOR_DATA);    //Alle drei Buffer werden geplottet, ansonsten enthielten
   SetIndexBuffer(1,ExtDownBuffer,INDICATOR_DATA);  //sie nur INDICATOR_CALCULATIONS
   SetIndexBuffer(2,ExtAMABuffer,INDICATOR_DATA);
   
   AMAhandle=iAMA(_Symbol,_Period,InpPeriodAMA,InpFastPeriodEMA,InpSlowPeriodEMA,InpShiftAMA,InpAppliedPrice);
   Envelopeshandle=iEnvelopes(_Symbol,_Period,InpMAPeriod,InpShiftAMA,InpMAMethod,AMAhandle,InpDeviation);

// Als Preis wurde hier das Handle des AMA in das Handle des Envelopes eingesetzt (AMAhandle)   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   CopyBuffer(AMAhandle,0,0,rates_total,ExtAMABuffer);
   CopyBuffer(Envelopeshandle,0,0,rates_total,ExtUpBuffer);
   CopyBuffer(Envelopeshandle,1,0,rates_total,ExtDownBuffer);
   
// Wie man später noch sehen wird sind die CopyBuffer hier die einzigen Berechnungen, die benötigt werden.   
// Natürlich könnte die Wirtschaftlichkeit verbessert werden, indem nur der letzte Balken neu berechnet wird 
// und nicht Alles. Doch der Einfachheit halber und weil ich mich damit noch nicht so gut auskenne, habe ich es erstmal
// weggelassen. Dies gehört auch zu einem anderen Thema.   
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+





Nach einigen Versuchen fand ich heraus, dass Input Shift in diesem Fall nicht im Handle verarbeitet werden kann, sondern in beide Handles nur ein Platzhalter Shift=0 gehört. Der Input Shift aller drei Plotbuffer muss in PlotIndexSetInteger() verbaut werden.

Hier der RICHTIGE Code:

//+------------------------------------------------------------------+
//|                                              iAMAEnvelopes01.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3                //die Anzahl der verwendeten Buffers und Plots wurde angepasst s.u.
#property indicator_plots   3                //bei den Buffern
#property indicator_type1   DRAW_LINE        
#property indicator_color1  clrAqua
#property indicator_label1  "Upper band"
#property indicator_width1  2
#property indicator_type2   DRAW_LINE        //bestimmte Eigenschaften der Plots werden hier eingegeben
#property indicator_color2  clrAqua
#property indicator_label2  "Lower band"
#property indicator_width2  2
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGold
#property indicator_label3  "AMA"
#property indicator_width3  2



input int InpPeriodAMA=10;      // AMA period
input int InpFastPeriodEMA=2;   // Fast EMA period
input int InpSlowPeriodEMA=20;  // Slow EMA period
input int InpShiftAMA=0;        // AMA shift

/*input*/ int                InpMAPeriod=1;              // Period      *diese Inputs wurden festgesetzt, da der
/*input*/ int                InpMAShift=0;                // Shift      eingebaute iMA des Envelopes-Indikators
/*input*/ ENUM_MA_METHOD     InpMAMethod=MODE_SMA;        // Method     hier nicht benötigt wird.*
input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price
input double             InpDeviation=1.0;            // Deviation

double                   ExtAMABuffer[];
double                   ExtUpBuffer[];
double                   ExtDownBuffer[];

// diese drei Buffer werden benötigt. Einer enthält die Werte des AMA für jeden Balken. Zu diesen Werten wird
// die Deviation der Envelopes addiert bzw. subtrahiert. Dies geschieht jedoch automatisch innerhalb deren
// Handles iAMA bzw. iEnvelopes, die in OnInit() aufgerufen werden.

int Envelopeshandle, AMAhandle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtUpBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ExtDownBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,ExtAMABuffer,INDICATOR_DATA);
   
   PlotIndexSetInteger(0,PLOT_SHIFT,InpShiftAMA);   //hier macht der Input Shift was er soll
   PlotIndexSetInteger(1,PLOT_SHIFT,InpShiftAMA);
   PlotIndexSetInteger(2,PLOT_SHIFT,InpShiftAMA);
   
   AMAhandle=iAMA(_Symbol,_Period,InpPeriodAMA,InpFastPeriodEMA,InpSlowPeriodEMA,InpMAShift,InpAppliedPrice);
   Envelopeshandle=iEnvelopes(_Symbol,_Period,InpMAPeriod,InpMAShift,InpMAMethod,AMAhandle,InpDeviation);

// Als Preis wurde hier das Handle des AMA in das Handle des Envelopes eingesetzt (AMAhandle).   
// Zum Schluss wurde klar, dass die Input Shift Variablen nur störten und man diese durch festgesetzte Shifts=0
// ersetzen muss, wobei der Input Shift in PlotIndexSetInteger kommt, dort tut er auch was er soll.   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   CopyBuffer(AMAhandle,0,0,rates_total,ExtAMABuffer);
   CopyBuffer(Envelopeshandle,0,0,rates_total,ExtUpBuffer);
   CopyBuffer(Envelopeshandle,1,0,rates_total,ExtDownBuffer);
   
// Wie man später noch sehen wird sind die CopyBuffer hier die einzigen Berechnungen, die benötigt werden.   
// Natürlich könnte die Wirtschaftlichkeit verbessert werden, indem nur der letzte Balken neu berechnet wird 
// und nicht Alles. Doch der Einfachheit halber und weil ich mich damit noch nicht so gut auskenne, habe ich es erstmal
// weggelassen. Dies gehört auch zu einem anderen Thema. 

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+



Und hier das Ergebnis:

Platzhaltershift10

Hier mit Shift=10



PlatzhalterShift-10

Hier mit Shift=-10

Jetzt stimmt das Ergebnis.


Aber warum muss man das so umständlich machen? Warum werden manche Input Parameter wie vorgesehen im Handle verarbeitet und Andere müssen auf so einem Weg eingegeben werden?