English Русский 中文 Español 日本語 Português
preview
Der Indikator Market Profile

Der Indikator Market Profile

MetaTrader 5Beispiele |
24 4
Artyom Trishkin
Artyom Trishkin

Inhalt



Was ist Market Profile?

Peter Steidlmayer entwickelte das Konzept des Marktprofils in den 1980er Jahren an der Chicago Mercantile Exchange. Händler, die diese Methode anwenden, betonen dessen Nützlichkeit für ein tiefes Verständnis des Marktes und die Verbesserung der Handelseffizienz.

Das Marktprofil ist kein traditioneller technischer Indikator und liefert keine direkten Handelssignale. Es ergänzt jedoch ein Handelssystem, indem es den Händlern ermöglicht, die Daten zu ordnen und zu bestimmen, wer den Markt kontrolliert, was der faire Wert ist und welche Faktoren die Preisbewegungen beeinflussen.

Das Marktprofil spiegelt die Organisation des Handels auf der Grundlage von Zeit, Preis und Volumen wider. Jeden Tag bildet sich eine Spanne mit einem Preisbereich, der das Gleichgewicht zwischen Käufern und Verkäufern darstellt. Die Kurse schwanken in diesem Bereich, und das Marktprofil hilft den Händlern, diese Veränderungen sowohl während als auch nach dem Handel zu interpretieren. Er ist auf einer Normalverteilungskurve aufgetragen, bei der etwa 70 % des Wertes innerhalb einer Standardabweichung vom Mittelwert liegen. Es handelt sich also um ein Analysewerkzeug, das die Verteilung der Volumina oder die Zeit, die der Preis auf bestimmten Niveaus verbringt, anzeigt. Es hilft den Händlern zu verstehen, wo die größten Geschäfte getätigt werden, und die wichtigsten Angebots- und Nachfrageniveaus zu identifizieren.

Die Verwendung des Marktprofils erfordert das Verständnis einiger Konzepte, die durch das Marktverhalten bedingt sind und direkt oder indirekt im Chart angezeigt werden. Der empfohlene Zeitrahmen für die Analyse ist M30.

Die erste Handelsstunde bildet das Hauptmuster des Handelstages und ist die Grundlage für die Untersuchung der Aktivitäten der Marktteilnehmer im Verlauf der Sitzung. Dieser Zeitraum ist wichtig, um festzustellen, was die Händler auf dem Markt tun, um den Preis zu finden, zu dem sich Käufer und Verkäufer auf ein Geschäft einigen werden.

Es gibt zwei Kategorien von Marktteilnehmern:

  1. Daytrader - ein Händler, der innerhalb eines Tages mit großen Volumina von mehreren Ticks arbeitet;
  2. Händler mit anderem Zeitrahmen - ein Händler, der in anderen Zeiträumen handelt mit dem Ziel, dass sich der Kurs auf neue Niveaus bewegt.

Schauen wir uns einige grundlegende Konzepte an, die Ihnen helfen werden, das Marktprofil besser zu verstehen.

  • Initial balance - Spanne der Marktpreise während der ersten Stunde einer Handelssitzung (zwei 30-Minuten-Balken nach Eröffnung der Sitzung).

  • Range - Bereich, absolute Höhe des gesamten Marktprofils.

  • Range extension - Ausweitung der Spanne, wenn sich der Preis im Verhältnis zum ursprünglichen Gleichgewicht bewegt.

  • Value area - Wertzone, ein Preisbereich, der 70 % der Handelsaktivitäten umfasst.

  • Point of control (POC) - die längste Profillinie, die auch dem Zentrum des Bereichs am nächsten ist.

  • Closing range - befindet sich in der Nähe des Schlusses der Handelssitzung.

  • Buying/Selling tail. Das Vorhandensein solcher Ausläufer (tails) deutet auf die stark zunehmende Aktivität von Händlern mit „anderen Zeitrahmen“ hin.
    Die kurze Länge der Tails deutet auf eine hinreichende Aggressivität der „other-timeframe“-Händler hin, sowohl auf der Käufer- als auch auf der Verkäuferseite.

Um das Marktprofil zu lesen, können Sie diese Grundprinzipien befolgen:

  1. Definition des Preis-Volumens
    Das Marktprofil zeigt die Preisniveaus an, die das höchste Volumen verzeichneten. Linien oder Blöcke auf dem Chart (in der Regel horizontal) zeigen an, wie viel Zeit der Kurs auf einem bestimmten Niveau verbracht hat, oder wie viel Volumen dort gehandelt wurde. Längere Linien bedeuten mehr Zeit oder mehr Volumen - dies sind wichtige Unterstützungs- und Widerstandsniveaus.

  2. Punkt der Kontrolle (POC)
    Dies ist das Kursniveau, bei dem das maximale Handelsvolumen während des Zeitraums auftrat. Er dient oft als starke Unterstützung oder Widerstand, da der Preis hier für die Marktteilnehmer am „akzeptabelsten“ ist.

  3. Faire und unfaire Preiszonen (Value Area und Non-Value Area)
    • In den Bereich von Value entfallen in der Regel etwa 70 % des Handelsvolumens im Berichtszeitraum. Dies ist der Bereich, in dem der Preis die meiste Zeit über ein „Gleichgewicht“ zwischen Angebot und Nachfrage gefunden hat.
    • Non-Value Area - Ebenen oberhalb oder unterhalb der Value Area gelten als Bereiche mit geringem Interesse. Bewegt sich der Preis in diese Zonen, kann er entweder schnell in den Value-Bereich zurückkehren oder sich aufgrund des Ungleichgewichts von Angebot und Nachfrage weiter bewegen.

  4. Erkennen von Trends und Seitwärtsbewegungen
    • Trend day - Das Marktprofil „erstreckt“ sich in eine Richtung, wenn sich der Markt stetig nach oben oder unten bewegt. In diesen Fällen verharrt der Preis nicht auf den Niveaus, sondern bewegt sich und schafft neue Bereiche von Interesse. Ein Trendtag hat einen kleinen Anfangssaldo, der weniger als 25 % der gesamten Tagesspanne ausmacht. Es handelt sich um eine deutliche Dominanz von Käufern oder Verkäufern mit einer starken Ausdehnung der Spanne in eine der beiden Richtungen.
    • Flat day - das Profil konzentriert sich auf ein Niveau, und der Wertebereich bleibt eng. Dies deutet auf ein Gleichgewicht und das Fehlen eines starken Trends hin.
    • Non-trend day zeichnet sich durch einen engen Anfangssaldo aus, der anschließend die gesamte Kursspanne des Tages enthält.
    • Normal day - ein solcher Tag hat eine breite Ausgangsbilanz, die etwa 80 % des gesamten Bereichs entspricht. Dies ist die häufigste Art von Handelstagen.
    • Normal change of a normal day - der Anfangssaldo einer solchen Struktur beträgt etwa 50 % der Tagesreichweite. In diesem Fall kommt es zu einer Erweiterung des Bereichs in die eine oder andere Richtung.
    • Neutral day - ein solches Profil zeichnet sich nicht durch sein anfängliches Gleichgewicht aus, es gibt eine Ausweitung der Spanne in beide Richtungen, und der Tag endet in der Nähe der Mitte der Spanne.

  5. Verständnis von Extremen und Preisreaktionen
    • Wenn der Kurs bei geringem Volumen neue Niveaus erreicht und schnell wieder in den POC- oder Value-Bereich zurückkehrt, kann dies ein Hinweis auf einen Rebound sein.
    • Wenn der Kurs weiterhin außerhalb der Value Area handelt und einen neuen POC bildet, signalisiert dies den möglichen Beginn eines neuen Trends.

  6. Praktische Anwendung des Marktprofils
    • Um Einstiegspunkte zu finden: Identifizieren Sie Unterstützungs- und Widerstandsniveaus mit Hilfe von POC- und Value Area-Grenzen und warten Sie auf Rückschläge von diesen Niveaus oder Ausbrüche in Richtung des Trends.
    • Festlegen von Stop-Loss und Proft-Target: Verwenden Sie POC und Value Area High/Low als Niveaus, um Schutzstopps und Gewinnmitnahmen zu platzieren.

Das klassische Marktprofil basiert auf den TPOs (Time-Price-Opportunities), die Großbuchstaben des lateinischen Alphabets sind, wobei jeder Buchstabe für 30 Minuten einer Handelssitzung steht.



Market Profile im MetaTrader 5 Terminal

Das MetaTrader 5-Client-Terminal, nämlich das Verzeichnis \MQL5\Indikatoren\FreieIndikatoren\, bietet eine einfache Version des Market Profiles. Sie finden den Code in MarketProfile.mq5. Im Gegensatz zu seiner klassischen Darstellung erstellt dieser Indikator vertikale Volumenprofile nach Sitzungen (Asien, Europa, Amerika) und visualisiert so die Zonen, in denen sich der Preis länger aufhält. Es analysiert die Intraday-Balken und unterteilt sie in drei Zeiträume, die verschiedene Marktphasen widerspiegeln. Der Indikator berechnet die Zeit, die während dieser Sitzungen auf den einzelnen Kursniveaus verbracht wurde, und stellt sie visuell als Rechtecke im Chart dar.

Die wichtigsten Punkte zum Lesen dieses Indikators:

  1. Unterteilung in Handelssitzungen:
    • Der ganze Tag ist in drei Sitzungen unterteilt: die asiatische, die europäische und die amerikanische.
    • Die Farbzonen im Chart zeigen die Zeit an, die in jeder Sitzung auf dem jeweiligen Kursniveau verbracht wurde.

  2. Preisniveau:
    • Jedes Kursniveau ist entsprechend der Sitzung und der Dauer des Kurses eingefärbt. Niveaus, auf denen der Preis länger verweilte, werden als wichtige Niveaus angesehen, da dort ein aktiver Handel stattfand.

  3. POC (Point of Control):
    • Der Indikator berechnet den POC nicht direkt, aber wir können die Niveaus mit der größten Länge der farbigen Zonen visuell hervorheben - dies sind die Kontrollpunkte, die die wichtigsten Niveaus von Angebot und Nachfrage anzeigen.

  4. Wertebereiche:
    • Wie beim standardmäßigen Marktprofil können Bereiche mit höherer Volumenkonzentration (lange Preisverweildauer) als Niveaus angesehen werden, zu denen der Preis möglicherweise zurückkehren möchte.

So hilft der Indikator Market Profile in diesem Code zu verstehen, auf welchen Ebenen sich die Hauptaktivität während des Tages konzentrierte und Unterstützungs- und Widerstandsniveaus für jede Handelssitzung hervorzuheben.

Lassen Sie uns herausfinden, wie dieser Indikator funktioniert.



Struktur und Grundsätze

Die Indikator-Eingaben umfassen:

  1. die Anzahl der Tage, für die das Profil angezeigt werden soll,
  2. den Index des Tages, der dem aktuellen Tag am nächsten liegt:
    • 0 - aktueller Tag,
    • 1 - Vortag,
    • 2 - Tag vor dem Vortag, usw.,
  3. die Farben, die zum Rendern der Sitzungen verwendet werden (asiatisch, europäisch und amerikanisch),
  4. die Öffnungszeiten der europäischen und der amerikanischen Tagung (die asiatische Tagung beginnt mit der Eröffnung des Tages)
  5. der Multiplikator für die Histogrammsegmentlänge:
//--- input parameters
input uint  InpStartDate       =0;           /* day number to start calculation */  // 0 - current, 1 - previous, etc.
input uint  InpShowDays        =3;           /* number of days to display */        // starting with and including the day in InpStartDate
input int   InpMultiplier      =1;           /* histogram length multiplier */      
input color InpAsiaSession     =clrGold;     /* Asian session */                    
input color InpEuropeSession   =clrBlue;     /* European session */                 
input color InpAmericaSession  =clrViolet;   /* American session */                 
input uint  InpEuropeStartHour =8;           /* European session opening hour */    
input uint  InpAmericaStartHour=14;          /* American session opening hour */    

Bei der Initialisierung des Indikators erstellen wir eine eindeutige ID für die Objektnamen aus den letzten vier Ziffern der Anzahl der Millisekunden, die seit dem Start des Systems vergangen sind:

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create a prefix for object names
   string number=StringFormat("%I64d", GetTickCount64());
   ExtPrefixUniq=StringSubstr(number, StringLen(number)-4);
   Print("Indicator \"Market Profile\" started, prefix=", ExtPrefixUniq);

   return(INIT_SUCCEEDED);
  }

Diese Nummer wird dann bei der Erstellung von Namen für die grafischen Objekte des Indikators verwendet, und die Objekte werden bei der Deinitialisierung mit demselben Präfix gelöscht:

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- after use, delete all graphical objects created by the indicator
   Print("Indicator \"Market Profile\" stopped, delete all objects with prefix=", ExtPrefixUniq);
   ObjectsDeleteAll(0, ExtPrefixUniq, 0, OBJ_RECTANGLE);
   ChartRedraw(0);
  }

Wie funktioniert nun der Indikator? Was ist die Logik der Darstellung? Stellen wir uns vor, dass die gesamte Größe einer Tageskerze von ihrem Tief bis zu ihrem Hoch der Größe der Tabelle entspricht. Die Zeilen der Tabelle sind dann Preisniveaus: jeder Preispunkt ist eine Tabellenzeile. Die Tabellenspalten in der einfachsten Version sind der Abstand von einem Intraday-Balken zum anderen. Die Zeile mit dem Index Null ist der niedrigste Preis, der dem Tiefstwert des Balkens entspricht. Der Preis mit dem Index 1 ist das Tief des Balkens plus einen Punkt. Dementsprechend ist die Zeichenfolge, die das Hoch des Balkens definiert, die Zeichenfolge mit dem Tief des Balkens plus der Anzahl der Punkte zwischen dem Tief und dem Hoch des Balkens.

Wenn wir nun ein einfaches Array erstellen, das den Zeilen dieser Tabelle entspricht, dann wird dessen Nullindex die Anzahl der Balken speichern, die es geschafft haben, während der Kursbewegung während des Tages beim Tiefstkurs des Balkens zu sein. Auf die gleiche Weise wird in allen anderen Zellen dieses Feldes die Anzahl der Male gespeichert, die der Preis auf diesen Niveaus war.

Wie können wir das feststellen? Es ist sehr einfach. Da das Tief des Eröffnungsbalkens des Tages der Nullindex des Arrays ist, können die Indizes aller anderen Intraday-Balken berechnet werden: Der Index der Zeile, die dem auf den Eröffnungsbalken folgenden Balken entspricht, ist das Tief dieses Balkens minus dem Tief des Eröffnungsbalkens des Tages in Punkten. Der letzte Index für diesen Balken ist das Hoch dieses Balkens minus das Eröffnungstief des Tages.

Die folgende Abbildung zeigt die Start- und Endindizes im Array für vier Sechs-Stunden-Intraday-Balken: Bar0, Bar1, Bar2, und Bar3:

Wenn wir nun im Array die Anzahl der Balken markieren, die sich auf den Preisniveaus befunden haben, und die Rechtecke des Marktprofils einzeichnen, ergibt sich folgendes Bild im Array und auf dem Chart:

Das Array wird bei jedem neuen Tick geleert, eine neue Bereichsgröße des Tagesbalkens wird dafür festgelegt, und seine Indizes werden neu mit dem Wert der Anzahl der Balken gefüllt, die sich auf jedem Preisniveau befunden haben. Auf diese Weise wird das Marktprofil dynamisch ausgefüllt und auf dem Chart mit aktuellen Informationen über die Marktlage angezeigt. Je länger sich der Kurs auf einem bestimmten Niveau befindet (mehrere Balken umfassen das Niveau), desto länger ist die Linie, die dieses Niveau anzeigt.

Schauen wir uns an, wie dies im Code des Indikators umgesetzt wird:

//+------------------------------------------------------------------+
//| 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[])
  {
//--- opening time of the current daily bar
   datetime static open_time=0;

//--- number of the last day for calculations
//--- (if InpStartDate = 0 and InpShowDays = 3, lastday = 3)
//--- (if InpStartDate = 1 and InpShowDays = 3, lastday = 4) etc ...
   uint lastday=InpStartDate+InpShowDays;

//--- if the first calculation has already been made
   if(prev_calculated!=0)
     {
      //--- get the opening time of the current daily bar
      datetime current_open=iTime(Symbol(), PERIOD_D1, 0);
      
      //--- if we do not calculate the current day
      if(InpStartDate!=0)
        {
         //--- if the opening time was not received, leave
         if(current_open==open_time)
            return(rates_total);
        }
      //--- update opening time
      open_time=current_open;
      //--- we will only calculate one day from now on, since all other days have already been calculated during the first run
      lastday=InpStartDate+1;
     }

//--- in a loop for the specified number of days (either InpStartDate+InpShowDays on first run, or InpStartDate+1 on each tick)
   for(uint day=InpStartDate; day<lastday; day++)
     {
      //--- get the data of the day with index day into the structure
      MqlRates day_rate[];
      //--- if the indicator is launched on weekends or holidays when there are no ticks, you should first open the daily chart of the symbol
      //--- if we have not received bar data for the day index of the daily period, we leave until the next call to OnCalculate()
      if(CopyRates(Symbol(), PERIOD_D1, day, 1, day_rate)==-1)
         return(prev_calculated);

      //--- get daily range (Range) in points
      double high_day=day_rate[0].high;
      double low_day=day_rate[0].low;
      double point=SymbolInfoDouble(Symbol(), SYMBOL_POINT);
      int    day_size=(int)((high_day-low_day)/point);

      //--- prepare arrays for storing price level rectangles
      int boxes_asia[], boxes_europe[], boxes_america[];
      //--- array sizes equal to the number of points in the day range
      ArrayResize(boxes_asia, day_size);
      ArrayResize(boxes_europe, day_size);
      ArrayResize(boxes_america, day_size);
      //--- zero out the arrays
      ZeroMemory(boxes_asia);
      ZeroMemory(boxes_europe);
      ZeroMemory(boxes_america);

      //--- get all intraday bars of the current day
      MqlRates bars_in_day[];
      datetime start_time=day_rate[0].time+PeriodSeconds(PERIOD_D1)-1;
      datetime stop_time=day_rate[0].time;
      //--- if the indicator is launched on weekends or holidays when there are no ticks, you should first open the daily chart of the symbol
      //--- if it was not possible to get the bars of the current timeframe for the specified day, leave until the next call of OnCalculate()
      if(CopyRates(Symbol(), PERIOD_CURRENT, start_time, stop_time, bars_in_day)==-1)
         return(prev_calculated);

      //--- we go through all the bars of the current day in a loop and mark the price cells that the bars fall into
      int size=ArraySize(bars_in_day);
      for(int i=0; i<size; i++)
        {
         //--- calculate the range of price level indices in the daily range
         int         start_box=(int)((bars_in_day[i].low-low_day)/point);  // index of the first cell of the price array corresponding to the Low price of the current i bar
         int         stop_box =(int)((bars_in_day[i].high-low_day)/point); // index of the last cell of the price array corresponding to the High price of the current i bar

         //--- get the bar hour by the loop index
         MqlDateTime bar_time;
         TimeToStruct(bars_in_day[i].time, bar_time);
         uint        hour=bar_time.hour;

         //--- determine which session the bar belongs to by the bar hour
         //--- American session
         if(hour>=InpAmericaStartHour)
           {
            //--- in the American session array, in cells from start_box to stop_box, increase the bar counters
            for(int ind=start_box; ind<stop_box; ind++)
               boxes_america[ind]++;
           }
         //--- Europe or Asia
         else
           {
            //--- European session
            if(hour>=InpEuropeStartHour && hour<InpAmericaStartHour)
               //--- in the European session array, in cells from start_box to stop_box, increase the bar counters
               for(int ind=start_box; ind<stop_box; ind++)
                  boxes_europe[ind]++;
            //--- Asian session
            else
               //--- in the Asian session array, in cells from start_box to stop_box, increase the bar counters
               for(int ind=start_box; ind<stop_box; ind++)
                  boxes_asia[ind]++;
           }
        }

      //--- draw a market profile based on the created arrays of price levels
      //---  market profile on the chart is drawn with segments of colored lines using the color specified in the settings for each trading session
      //--- segments are drawn as rectangle objects with the height of the rectangle equal to one price point and the width equal to the distance to the next bar to the right
      
      //--- define the day for the name of the graphical object and the width of the rectangle
      string day_prefix=TimeToString(day_rate[0].time, TIME_DATE);
      int    box_length=PeriodSeconds(PERIOD_CURRENT);

      //--- Asian session
      //--- in a loop by the number of points of the daily bar
      for(int ind=0; ind<day_size; ind++)
        {
         //--- if the Asian session array is full
         if(boxes_asia[ind]>0)
           {
            //--- get the next price by adding the number of 'ind' points to the Low price of the daily bar
            //--- get the start time of the segment (opening time of the daily bar)
            //--- and the end time of the segment (opening time of the daily bar + the number of bars stored in the 'ind' cell of the boxes_asia[] array)
            double   price=low_day+ind*point;
            datetime time1=day_rate[0].time;
            datetime time2=time1+boxes_asia[ind]*box_length*InpMultiplier;
            //--- create a prefix for the name of the Asian session graphical object
            string   prefix=ExtPrefixUniq+"_"+day_prefix+"_Asia_"+StringFormat("%.5f", price);

            //--- draw a rectangle (line segment) at the calculated coordinates with the color for the Asian session
            DrawBox(prefix, price, time1, time2, InpAsiaSession);
           }
        }

      //--- European session
      for(int ind=0; ind<day_size; ind++)
        {
         //--- if the European session array is full
         if(boxes_europe[ind]>0)
           {
            //--- get the next price by adding the number of 'ind' points to the Low price of the daily bar
            //--- get the start time of the segment (opening time of the daily bar + time of the right edge of the Asian session profile)
            //--- and the end time of the segment (start time of the European session segment + the number of bars stored in the 'ind' cell of the boxes_europe[] array)
            double   price=low_day+ind*point;
            datetime time1=day_rate[0].time+boxes_asia[ind]*box_length*InpMultiplier;
            datetime time2=time1+boxes_europe[ind]*box_length*InpMultiplier;
            //--- create a prefix for the name of the graphical object of the European session
            string   prefix=ExtPrefixUniq+"_"+day_prefix+"_Europe_"+StringFormat("%.5f", price);

            //--- draw a rectangle (line segment) at the calculated coordinates with the color for the European session
            DrawBox(prefix, price, time1, time2, InpEuropeSession);
           }
        }

      //--- American session
      for(int ind=0; ind<day_size; ind++)
        {
         //--- if the American session array is full
         if(boxes_america[ind]>0)
           {
            //--- get the next price by adding the number of 'ind' points to the Low price of the daily bar
            //--- get the start time of the segment (opening time of the daily bar + time of the right edge of the Asian session profile + time of the right edge of the European session profile)
            //--- and the end time of the segment (start time of the American session segment + the number of bars stored in the 'ind' cell of the boxes_america[] array) 
            double   price=low_day+ind*point;
            datetime time1=day_rate[0].time+(boxes_asia[ind]+boxes_europe[ind])*box_length*InpMultiplier;
            datetime time2=time1+boxes_america[ind]*box_length*InpMultiplier;
            //--- create a prefix for the name of the American session graphical object
            string   prefix=ExtPrefixUniq+"_"+day_prefix+"_America_"+StringFormat("%.5f", price);

            //--- draw a rectangle (line segment) at the calculated coordinates with the color for the American session
            DrawBox(prefix, price, time1, time2, InpAmericaSession);
           }
        }
     }

//--- when the loop is complete, redraw the chart
   ChartRedraw(0);

//--- return the number of bars for the next OnCalculate call
   return(rates_total);
  }

Der Code ist ausreichend detailliert kommentiert. Der Indikator kann ein Profil für mehrere Tage auf einmal zeichnen. Sie werden alle in einer Schleife entsprechend der Anzahl der angezeigten Tage dargestellt.


Hauptalgorithmus

Schauen wir uns den Algorithmus des obigen Codes genauer an. Jeder einzelne Tag wird wie folgt gezeichnet:

  • Abhängig von dem Zeitrahmen des Charts, in der der Indikator läuft, erhalten wir die Balken, die im angezeigten Tag enthalten sind:
    MqlRates day_rate[];
    if(CopyRates(Symbol(), PERIOD_D1, day, 1, day_rate)==-1)
       return(prev_calculated);
    
    MqlRates bars_in_day[];
    datetime start_time=day_rate[0].time+PeriodSeconds(PERIOD_D1)-1;
    datetime stop_time=day_rate[0].time;
    
    if(CopyRates(Symbol(), PERIOD_CURRENT, start_time, stop_time, bars_in_day)==-1)
       return(prev_calculated);
    
    
  • In einer Schleife nach der Anzahl der Intraday-Balken
    int size=ArraySize(bars_in_day);
    for(int i=0; i<size; i++)
    
    
    • für den in der Schleife ausgewählten aktuellen Balken werden die Indizes für den Anfang und das Ende der Preisspanne berechnet, in der sich der ausgewählte Balken innerhalb des Tagesbalkens befindet
      int         start_box=(int)((bars_in_day[i].low-low_day)/point);  // index of the first cell of the price array corresponding to the Low price of the current i bar
      int         stop_box =(int)((bars_in_day[i].high-low_day)/point); // index of the last cell of the price array corresponding to the High price of the current i bar
      
      
    • die Sitzung bestimmen, in der sich der in der Schleife ausgewählte Balken befindet, und im entsprechenden Array die Balkenzähler in allen Zellen erhöhen, die sich im Preisbereich des Intraday-Balkens befinden
      MqlDateTime bar_time;
      TimeToStruct(bars_in_day[i].time, bar_time);
      uint        hour=bar_time.hour;
      
      if(hour>=InpAmericaStartHour)
        {
         for(int ind=start_box; ind<stop_box; ind++)
            boxes_america[ind]++;
        }
      else
        {
         if(hour>=InpEuropeStartHour && hour<InpAmericaStartHour)
            for(int ind=start_box; ind<stop_box; ind++)
               boxes_europe[ind]++;
         else
            for(int ind=start_box; ind<stop_box; ind++)
               boxes_asia[ind]++;
         }
      
      
  • Nach dem Durchlaufen einer Schleife durch alle Intraday-Balken wird in jeder Zelle der Session-Arrays die Anzahl der Balken aufgezeichnet, die sich zu diesem Preis befunden haben. Alle Sitzungs-Arrays haben die gleiche Größe, die der Anzahl der Preispunkte im täglichen Bereich von Low bis High der Tageskerze entspricht, aber jedes Array wird entsprechend der in dieser Sitzung erreichten Preisniveaus gefüllt.
  • Anschließend werden in einer Schleife durch alle gefüllten Sitzungsfelder grafische Objekte entsprechend den berechneten Koordinaten auf dem Chart angezeigt:
    for(int ind=0; ind<day_size; ind++)
      {
       if(boxes_asia[ind]>0)
         {
          double   price=low_day+ind*point;
          datetime time1=day_rate[0].time;
          datetime time2=time1+boxes_asia[ind]*box_length*InpMultiplier;
          string   prefix=ExtPrefixUniq+"_"+day_prefix+"_Asia_"+StringFormat("%.5f", price);
          DrawBox(prefix, price, time1, time2, InpAsiaSession);
         }
      }
    
    for(int ind=0; ind<day_size; ind++)
      {
       if(boxes_europe[ind]>0)
         {
          double   price=low_day+ind*point;
          datetime time1=day_rate[0].time+boxes_asia[ind]*box_length*InpMultiplier;
          datetime time2=time1+boxes_europe[ind]*box_length*InpMultiplier;
          string   prefix=ExtPrefixUniq+"_"+day_prefix+"_Europe_"+StringFormat("%.5f", price);
          DrawBox(prefix, price, time1, time2, InpEuropeSession);
         }
      }
    
    for(int ind=0; ind<day_size; ind++)
      {
       if(boxes_america[ind]>0)
         {
          double   price=low_day+ind*point;
          datetime time1=day_rate[0].time+(boxes_asia[ind]+boxes_europe[ind])*box_length*InpMultiplier;
          datetime time2=time1+boxes_america[ind]*box_length*InpMultiplier;
          string   prefix=ExtPrefixUniq+"_"+day_prefix+"_America_"+StringFormat("%.5f", price);
          DrawBox(prefix, price, time1, time2, InpAmericaSession);
         }
      }
    
  • Das Chart zeigt dann das Marktprofil für einen Tag.

Die Funktion, die Liniensegmente zeichnet:

//+------------------------------------------------------------------+
//| Draw color box                                                   |
//+------------------------------------------------------------------+
void DrawBox(string bar_prefix, double price, datetime time1, datetime time2, color clr)
  {
   ObjectCreate(0, bar_prefix, OBJ_RECTANGLE, 0, time1, price, time2, price);
   ObjectSetInteger(0, bar_prefix, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, bar_prefix, OBJPROP_STYLE, STYLE_SOLID);
   ObjectSetInteger(0, bar_prefix, OBJPROP_WIDTH, 1);
   ObjectSetString(0, bar_prefix, OBJPROP_TOOLTIP, "\n");
   ObjectSetInteger(0, bar_prefix, OBJPROP_BACK, true);
  }

Die Segmente werden mit grafischen Objekten - Rechtecken - gezeichnet (Sie können auch mit Trendlinien zeichnen, indem Sie die Eigenschaften „Strahl nach links“ und „Strahl nach rechts“ für sie deaktivieren). Die Funktion erhält die Koordinaten des Rechtecks in Form der Start- und Endzeit sowie den Preis, der für beide Seiten des Rechtecks gleich ist. Das Ergebnis ist eine regelmäßige Linie mit der in den Eingaben angegebenen Farbe.

Wenn wir den Indikator auf dem M30-Chart des EURUSD laufen lassen, sehen wir folgendes Bild des Marktprofils:

Wenn wir Linien von jedem der vorangegangenen Tage zeichnen (von seinem Point of Control), können wir deutlich die Niveaus des „fairen“ Preises sehen, die gut als Unterstützung und Widerstand oder Anziehungskraft dienen können (die Lücke des aktuellen Tages kann sehr gut geschlossen sein, während dies der POC des Vortages ist).


Schlussfolgerung

Durch das Studium des Marktprofils werden Sie in der Lage sein, die Marktdynamik besser zu verstehen, wichtige Niveaus zu identifizieren und effiziente Einstiegs- und Ausstiegspunkte zu finden. Das Marktprofil unterscheidet sich vom Tick-Chart durch die Kombination von Preis, Volumen und Zeit in einer praktischen Form. Sie ermöglicht es, Preisgleichgewichtsniveaus zu ermitteln und zu analysieren, wer den Markt im Moment kontrolliert. Dies verschafft einen Vorteil bei Handelsentscheidungen, da es eine Anpassung an Veränderungen in der Fair-Value-Einschätzung der Händler ermöglicht.

Nachdem wir uns mit dem Indikator Market Profile vertraut gemacht haben, der mit dem MetaTrader 5-Client-Terminal geliefert wird, verstehen wir nun die Einfachheit seiner Funktionsweise, verstehen die Logik seines Aufbaus und können ihn sowohl zur Bewertung der Marktsituation in der vorgegebenen Form als auch zur Erstellung von fortgeschritteneren und komplexeren Produkten auf seiner Grundlage verwenden.

Für ein umfassendes Verständnis und einen Vergleich mit anderen Konzepten können Sie andere Arbeiten über das Marktprofil lesen, die auf mql5.com vorgestellt werden:

Der vollständig kommentierte Code des in diesem Artikel betrachteten Indikators ist unten zum Herunterladen und Studieren beigefügt.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/16461

Beigefügte Dateien |
MarketProfile.mq5 (25.87 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (4)
Alexey Viktorov
Alexey Viktorov | 28 Nov. 2024 in 17:00
Es ist merkwürdig, dass Sie nicht zu dem Schluss gekommen sind, dass es sich nicht um einen Indikator, sondern um wertlosen Blödsinn handelt. Genauso wie Fraktale nichts Gescheites zeigen.
Intrest1
Intrest1 | 8 Apr. 2025 in 13:35
Könnten Sie es so einrichten, dass das Tick-Volumen eines Levels durch die Anzahl der Bars in diesem Level geteilt wird? Der Preis kann lange Zeit unverändert bleiben, und es sammeln sich leere Ticks an. Welchen Sinn haben Niveaus ohne echtes Volumen? Das Verhältnis zwischen dem Tick-Volumen und der Anzahl der Balken des Levels zeigt das tatsächliche Gewicht des Levels an.
Silk Road Trading LLC
Ryan L Johnson | 14 Juli 2025 in 13:50

Code Basis

Volumenprofil + Bereich v6.0

Olexiy Polyakov, 2016.06.30 12:46

Volume Profile + Range v6.0 (früher TPO). Verteilung der Geschäfte nach Preisniveaus in einem bestimmten Zeitintervall. Angezeigt als Histogramm.

Silk Road Trading LLC
Ryan L Johnson | 15 Juli 2025 in 12:55

Artikel

Marktprofil-Indikator

Artyom Trishkin, 2025.07.14 11:49

In diesem Artikel werden wir uns mit dem Indikator Market Profile beschäftigen. Wir werden herausfinden, was sich hinter diesem Namen verbirgt, versuchen, seine Funktionsprinzipien zu verstehen und einen Blick auf seine Terminal-Version (MarketProfile) zu werfen.

Zyklen im Handel Zyklen im Handel
In diesem Artikel geht es um die Verwendung von Zyklen im Handel. Wir werden den Aufbau einer Handelsstrategie auf der Grundlage zyklischer Modelle in Betracht ziehen.
Neuronale Netze im Handel: Verbesserung des Wirkungsgrads des Transformers durch Verringerung der Schärfe (SAMformer) Neuronale Netze im Handel: Verbesserung des Wirkungsgrads des Transformers durch Verringerung der Schärfe (SAMformer)
Das Training von Transformer-Modellen erfordert große Datenmengen und ist oft schwierig, da die Modelle nicht gut auf kleine Datensätze verallgemeinert werden können. Der SAMformer-Rahmen hilft bei der Lösung dieses Problems, indem er schlechte lokale Minima vermeidet. Dadurch wird die Effizienz der Modelle auch bei begrenzten Trainingsdaten verbessert.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
MQL5 beherrschen, vom Anfänger bis zum Profi (Teil IV): Grundlagen der Entwicklung von Expert Advisors MQL5 beherrschen, vom Anfänger bis zum Profi (Teil IV): Grundlagen der Entwicklung von Expert Advisors
Dieser Artikel setzt die Reihe für Anfänger fort. Hier werden wir die grundlegenden Prinzipien der Entwicklung von Expert Advisors (EAs) diskutieren. Wir werden zwei EAs erstellen: der erste wird ohne Indikatoren handeln und schwebende Aufträge verwenden, der zweite wird auf dem Standard-MA-Indikator basieren und Handelsgeschäfte zum aktuellen Preis eröffnen. Hier gehe ich davon aus, dass Sie kein völliger Anfänger mehr sind und den Stoff aus den vorherigen Artikeln relativ gut beherrschen.