Entwicklung des Price Action Analysis Toolkit (Teil 38): Tick Buffer VWAP und Short-Window Imbalance Engine
Inhalt
- Einführung
- Eingehender Überblick über die wichtigsten Funktionen des Tools
- Implementierung in MQL5
- Ergebnisse
- Schlussfolgerung
Einführung
Die meisten Händler lernen schnell, dass Preischarts nicht die ganze Geschichte erzählen. Was den Markt wirklich bewegt, liegt unter der Oberfläche verborgen – im Orderbuch, wo Gebote und Nachfragen zeigen, wer darauf wartet, zu kaufen, wer bereit ist zu verkaufen, und wo sich die Liquidität stapelt. Professionelle Händler nutzen diese Informationen tagtäglich, um Angebots- und Nachfragezonen zu bestimmen, Ungleichgewichte zu erkennen und kurzfristige Preisveränderungen mit bemerkenswerter Präzision vorherzusehen.
Einzelhändler sehen dieses Bild jedoch nur selten. Viele Plattformen bieten überhaupt keinen direkten Zugang zum Orderbuch, während andere den Zugang auf verzögerte oder unvollständige Daten beschränken, oft hinter einer zusätzlichen Paywall. Auf gängigen Handelsplattformen wie MetaTrader 5 hängt die Transparenz vollständig vom Broker ab, und die meisten Händler müssen sich ohne die mikrostrukturellen Einblicke, die für Profis selbstverständlich sind, durch die Märkte bewegen.
Das Slippage-Tool wurde entwickelt, um diese Lücke zu schließen. Es wird zwar nicht versucht, ein vollständiges Orderbuch oder ein Rohband nachzubilden, aber es rekonstruiert die wichtigsten Erkenntnisse, die Händler normalerweise aus der Markttiefe gewinnen – und zwar nur aus den Tick-Daten, die jeder Broker bereitstellt. Es berechnet einen kursgewichteten VWAP (Volume Weighted Average Price), um hervorzuheben, wo sich die Aktivitäten häufen, misst kurzfristige Ungleichgewichte bei den Aufträgen, um den Richtungsdruck zu erfassen, und aggregiert die Tick-Volumina, um ein klareres Bild der jüngsten Beteiligung zu zeichnen. Diese Metriken werden dann mit Spread- und ATR-Kontext gepaart, um Händlern zu helfen, zu erkennen, wann die Bedingungen ihre direktionale Tendenz begünstigen.
Das Tool wird direkt auf dem Chart mit Warnhinweisen und Handelsmarkierungen angezeigt und bietet Privatanlegern einen praktischen Proxy für den Orderflow. So können sie Liquiditätsverschiebungen beobachten, Ungleichgewichte erkennen und ihre Eingaben effektiver timen, auch ohne Zugang zu einem professionellen Marktbuch.
Das nachstehende Chart veranschaulicht dies in der Praxis. Beachten Sie die rückläufige Bewegung von Punkt E nach F. Der Rückgang verläuft nicht geradlinig, sondern der Markt schwankt, was zu vorübergehenden Hochs und Tiefs führt und die Liquidität mitreißt. Ein Händler, der bei Punkt C in einen Verkauf einsteigt, könnte mit der Richtung richtig liegen, aber bei schlechtem Risikomanagement oder einem übergroßen Lot könnte ihn der Rücksetzer in Richtung D aufhalten. Das Slippage-Tool umrahmt dies, indem es eine Gegenbewegung vorschlägt: Kaufen bei C und Schließen bei D, wodurch ein potenzieller Verlust in eine kontrollierbare Gelegenheit umgewandelt wird. Wenn der Kurs von A aus ansteigt, hebt das Tool B als günstige Verkaufszone hervor und hilft den Händlern, mit den Schwankungen zu handeln, anstatt von ihnen durchgeschüttelt zu werden.

Der Handel wird immer mit Volatilität, Umkehrungen und Liquiditätsfallen verbunden sein. Der entscheidende Unterschied besteht darin, ob diese Bewegungen die Händler aus dem Markt drängen oder ob sie eine Gelegenheit bieten, das Risiko und die Ausführung effektiver zu steuern. Das Slippage-Tool beseitigt zwar nicht die Unsicherheit, bringt aber das Element einer strukturellen Klarheit in das Chart des einzelnen Händlers und verkleinert die Kluft zwischen lokalen Handelsplattformen und einer professionellen Handelsinfrastruktur.
In den folgenden Abschnitten wird die Funktionsweise des Tools im Detail erläutert, die Bedeutung der einzelnen Kernmetriken erklärt und gezeigt, wie diese Funktionen zur Verbesserung von Handelsentscheidungen eingesetzt werden können. Egal, ob Sie ein diskretionärer Händler sind, der präzisere Handelseröffnungen sucht, oder ein algorithmischer Entwickler, der neue Signalquellen erforscht, das Slippage-Tool bietet eine schlanke, leichtgewichtige Lösung für eine der hartnäckigsten Einschränkungen des Einzelhandels: den begrenzten Zugang zu zuverlässigen Daten der Markttiefe.
Eingehender Überblick über die wichtigsten Funktionen des Tools
Das Slippage Tool ist ein MetaTrader 5 On-Chart-System, das Orderflow-Signale aus dem Live-Tick-Stream rekonstruiert (VWAP, Tick/Volumen-Ungleichgewicht, Spread- und ATR-Kontext), handelbare Ränder über Alerts und Marker anzeigt und optional eine erwartete Slippage-Pauschale in die Risiko-/Lot-Größe einbezieht, die als praktischer Ersatz für Marktbucheinblicke dient, wenn DOM nicht verfügbar ist.
Nachstehend finden Sie die mathematischen Berechnungen und ausführliche Erläuterungen zu den wichtigsten Merkmalen dieses Systems.
1. VWAP (Volumengewichteter Durchschnittspreis)
In einer früheren Diskussion habe ich eine eingehende Analyse des VWAP (volumengewichteter Durchschnittspreis) vorgestellt. VWAP ist eine hochentwickelte Benchmark, die sowohl Preis- als auch Volumendaten kombiniert, um einen gewichteten Durchschnittspreis über einen bestimmten Zeitraum zu ermitteln. Im Gegensatz zu einem einfachen arithmetischen Mittelwert, bei dem jeder Preispunkt gleich behandelt wird, misst der VWAP den Preisniveaus, bei denen ein höheres Handelsvolumen stattgefunden hat, eine größere Bedeutung bei. Dieser Ansatz stellt sicher, dass der VWAP genau die Kursniveaus widerspiegelt, zu denen der Großteil der Handelsaktivitäten stattfand, und somit den tatsächlichen Marktkonsens während des Zeitraums erfasst.
Durch die Einbeziehung des Volumens in die Berechnung bietet der VWAP einen aussagekräftigeren Maßstab für den „fairen Wert“ des Marktes, da er die Intensität des Handels auf verschiedenen Kursniveaus berücksichtigt. Händler und institutionelle Teilnehmer nutzen den VWAP häufig, um die Marktbedingungen zu beurteilen, potenzielle Einstiegs- und Ausstiegspunkte zu ermitteln und die Gesamtrichtung des Marktes im Vergleich zu dieser Benchmark abzuschätzen. Aufgrund seiner Dynamik dient er als zuverlässiger Bezugspunkt für die Bewertung von Intraday-Kursbewegungen und Liquiditätsbedingungen, was ihn zu einem unverzichtbaren Instrument sowohl für Ausführungsstrategien als auch für die breitere Marktanalyse macht.

wobei:
𝑃(i) = Preis des i-ten Ticks𝑉(i) = Tickvolumen des i-ten Ticks
Wird der Kurs über dem VWAP gehandelt, deutet dies darauf hin, dass der Markt im Vergleich zu seinem Durchschnitt mit einem Aufschlag gehandelt wird, was auf eine Aufwärts-Stimmung hindeutet. Wird der Kurs hingegen unter dem VWAP gehandelt, deutet dies auf einen Abschlag hin, der eine Abwärtstrend widerspiegelt. Händler nutzen den VWAP häufig als dynamisches Unterstützungs- oder Widerstandsniveau, um ihre Entscheidungen an dieser Benchmark auszurichten.

Da nicht alle Broker umfassende Daten des Marktbuchs anbieten, rekonstruiert dieses Tool eine VWAP-Linie, die ausschließlich aus eingehenden Tick-Daten abgeleitet wird. Dieser Ansatz ermöglicht es Händlern, Erkenntnisse zu gewinnen, die mit den „Fair-Value-Zonen“ im Orderbuch vergleichbar sind, und bietet einen wertvollen Anhaltspunkt für das Marktgleichgewicht und hilft bei der Entscheidungsfindung.
2. Ungleichgewicht
Das Ungleichgewicht zeigt an, ob aggressive Käufer oder Verkäufer im Handel vorherrschen. In einem traditionellen Orderbuch wird dies in der Regel durch den Vergleich des Volumens der ruhenden Aufträge zum Geldkurs und zum Briefkurs ermittelt. Wenn jedoch keine direkten Daten des Orderbuchs zur Verfügung stehen, kann das Tool indirekt auf ein Marktungleichgewicht schließen, indem es das Tick-Verhalten analysiert und so eine Alternative zur Messung des Richtungsdrucks und der Marktstimmung bietet.

wobei:
BuyVolume = Summe der Tick-Volumina, bei denen sich der Preis nach oben bewegt hat
SellVolume = Summe der Tick-Volumina, bei denen sich der Preis nach unten bewegt hat
Ein positives Ungleichgewicht bedeutet Kaufdruck und spiegelt die Dominanz aggressiverer Käufer wider, während ein negatives Ungleichgewicht auf einen Verkaufsdruck hinweist, der von aggressiveren Verkäufern ausgeht.

Das Tool überwacht die Kursbewegungen auf Tick-by-Tick-Basis. Jede Aufwärtsbewegung (Uptick) wird als Kaufaktivität gewertet, während jede Abwärtsbewegung (Downtick) mit einem Verkauf verbunden ist. Diese fortlaufende Berechnung in Echtzeit gibt Aufschluss darüber, welche Seite derzeit den größeren Einfluss auf den Markt ausübt, und bietet so wertvolle Einblicke in die kurzfristige Richtungsdynamik.
3. Spread
Der Spread ist eine der grundlegendsten und wichtigsten Messgrößen für die Mikrostruktur des Marktes. Er stellt die Kosten der Unmittelbarkeit dar und gibt an, wie viel die Händler für die Ausführung eines sofortigen Marktauftrags „bezahlen“ müssen. Diese Kennzahl gibt einen entscheidenden Einblick in die Liquiditätsbedingungen und die Gesamteffizienz des Marktes, da sie die mit einer schnellen Ausführung verbundenen Transaktionskosten widerspiegelt.
![]()
Ein enger Spread deutet in der Regel auf liquide und effiziente Marktbedingungen hin, die einen reibungsloseren und kostengünstigeren Handel ermöglichen. Umgekehrt deutet eine hoher Spread auf eine geringere Liquidität und höhere Transaktionskosten hin und kann mitunter ein Zeichen für Marktstress oder Unsicherheit sein.

Das Tool überwacht die Ausbreitung kontinuierlich und in Echtzeit. Die Signale können anhand von vordefinierten Spread-Schwellenwerten gefiltert werden, sodass Händler in Zeiten mit ungewöhnlich hohen Transaktionskosten nicht einsteigen müssen. Dieser Ansatz simuliert das Verhalten von Orderbuchbeobachtern, die bei geringer Markttiefe vom Handel absehen und dadurch günstigere Ausführungsbedingungen fördern.
4. Flow
Der Flow fungiert als kurzfristiger Stimmungsindikator, der erfasst, ob die jüngsten Ticks innerhalb eines bestimmten rollierenden Fensters überwiegend steigen oder fallen. Es dient als Echtzeit-Puls-Check für den Druck im Flow der Aufträge und bietet Händlern einen unmittelbaren Einblick in die vorherrschende Marktdynamik.

- wobei:

Ein Flow von über Null zeigt an, dass der Großteil des Volumens mit Aufwärtsbewegungen verbunden ist, was auf Kaufdruck hindeutet. Umgekehrt deutet ein Flow unter Null darauf hin, dass der größte Teil des Volumens mit Abwärtsbewegungen des Preises einhergeht, was einen Verkaufsdruck widerspiegelt.
Durch die Aggregation der unterzeichneten Volumina in Echtzeit erstellt das Tool ein dynamisches Bild des kurzfristigen Auftragsflussdrucks. Dieser Ansatz spiegelt genau wider, wie ein Händler die sich verändernden Ungleichgewichte innerhalb eines Marktbuchs interpretiert, und bietet einen wertvollen Einblick in die unmittelbare Marktstimmung und Richtungsvorgabe.

Diese vier Merkmale (VWAP, Imbalance, Spread und Flow) fassen die wesentlichen Erkenntnisse über ein Marktorderbuch zusammen. Sie erreichen dies, indem sie die wichtigsten Marktdynamiken ausschließlich aus rohen Tickdaten ableiten und so wertvolle Informationen über die Mikrostruktur selbst bei Brokern liefern, die keine vollständige Orderbuchunterstützung anbieten.
Implementierung in MQL5
In diesem Abschnitt werde ich Ihnen Schritt für Schritt erklären, wie Sie das Sippage Tool mit der Programmiersprache MQL5 erstellen können.
Datei-Header, Includes und Forward-Deklarationen.
Am Anfang der Datei setzt das Skript Metadaten (#Eigenschaft) und schließt Handel.mqh ein, deklariert dann die Signaturen von VWAP und Flow, damit sie vor ihren Definitionen verwendet werden können. Der Header dient drei praktischen Zwecken: Er dokumentiert Urheberschaft/Version für die spätere Wartung, er aktiviert den Strict-Modus des Compilers, der eine sicherere moderne MQL5-Semantik erzwingt, und er deklariert Abhängigkeiten, damit der EA Handelsroutinen aufrufen kann, wenn automatisierte Einträge hinzugefügt werden. Die Vorwärtsdeklarationen sind eine kleine stilistische Erleichterung – sie ermöglichen es Ihnen, die menschenfreundlichen High-Level-Funktionen an beliebiger Stelle in der Datei zu platzieren, ohne sich um die textliche Anordnung zu kümmern. Aus Sicht der Wartung ist dieser oberste Block der Fahrplan, den die Leser des Artikels erwarten: Er informiert sie darüber, welche externen Fähigkeiten (Indikator-Handles, Trading-Helfer) verfügbar sind, und bereitet den Leser darauf vor, die später implementierten Hauptmetriken zu finden.
// File metadata and includes #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict #include <Trade\Trade.mqh> // CTrade utility for possible auto-trade usage
Enums und Eingabeparameter (Konfigurationsoberfläche).
Die Enum-Definitionen und die lange Liste der Eingabevariablen bilden die öffentliche API des Tools: Dies sind die Knöpfe, mit denen ein Händler das Verhalten einstellen kann, ohne den Code zu ändern. Die Enumeration bieten lesbare Namen für UI-Optionen (Ecken für das Panel, Warnmodi). Die Eingaben exponieren die kritischen Signalparameter – VWAP-Fenster in Minuten, Imbalance-Fenster in Sekunden, Spread-zu-ATR-Anteil für die „billige“ Spread-Erkennung, Schwelle für den Flow und Hysteresefunktion für Alarme, Risikoprozentsatz und ATR-Multiplikator für Stops sowie viele UI/Layout-Optionen. Diese als Eingabewerte darzustellen, ist eine wichtige Design-Entscheidung: Sie macht den EA vielseitig für verschiedene Instrumente und Handelsstile einsetzbar.
Erläutern Sie in einem Produktionsartikel den empfohlenen Bereich für jede Eingabe und den Kompromiss: Längerfristige VWAP-Fenster sorgen beispielsweise für Stabilität, verlieren aber an kurzfristiger Reaktionsfähigkeit; ein größeres InpImbWindowSec glättet den Flow, dämpft aber die Mikrostruktursignale. Hervorzuheben ist auch, dass sinnvolle Standardwerte bereitgestellt werden, die jedoch von den Nutzern auf die Tickrate und die Marktmikrostruktur des jeweiligen Instruments abgestimmt werden sollten.
// Enums (UI choices) and user-exposed inputs (tuning knobs) enum eCorner { COR_LT=0, COR_LB=1, COR_RT=2, COR_RB=3 }; enum eAlertMode { AM_SINGLE=0, AM_ROLLING_CLEAR=1, AM_POOL_REUSE=2 }; input int InpVWAPminutes = 1440; // VWAP window in minutes (rolling) input int InpImbWindowSec = 30; // Imbalance/flow window in seconds input double InpCheapSpreadFrac = 0.50; // Spread < ATR * this fraction => "cheap" input double InpFlowTh = 0.30; // flow threshold for alerts input double InpFlowHystFactor = 0.80; // hysteresis factor for flow reset input double InpRiskPct = 1.0; // risk per trade as % of balance input double InpStopATRmult = 1.2; // stop = ATR * this multiplier input uint InpRingSize = 20000; // tick ring buffer size input uint InpTimerSec = 2; // UI refresh / aggregation cadence
Globaler Zustand und Namenskonventionen.
Die globalen Variablen initialisieren den Betriebszustand: Symboleinstellungen, Marktparameter (g_point, g_tickVal), das Handle des ATR-Indikators, ein CTrade-Objekt und eine Reihe von Arrays, die einen ringförmigen Tick-Puffer implementieren. Der Code verwendet das Präfix g_ prefix für Chart-Objektnamen. Diese Namensgebung ist für eine sichere Objektbereinigung von entscheidender Bedeutung, da sie sicherstellt, dass die EA nur ihre eigenen Labels bearbeitet und nicht versehentlich die Zeichnungen anderer Indikatoren entfernt.
Die Ringpuffer-Arrays (g_time, g_bid, g_ask, g_last, g_vol) sowie die Indizes g_head, g_used, g_size sind das Rückgrat aller aggregierten Berechnungen; die lokale Speicherung von Ticks verhindert wiederholte Aufrufe von Plattform-APIs, verbessert den Determinismus und ermöglicht eine zeitlich begrenzte Aggregation. Die globalen Variablen halten auch frühere Werte für die Erkennung von Änderungen fest, um die UI-Zusätze zu reduzieren. In den Artikeln wird hervorgehoben, dass der globale Zustand in MQL5 sorgfältig verwaltet werden muss, da das Terminal auf einem einzigen Thread läuft und Speicherlecks von Indikator-Handles oder verwaisten Objekten häufige Probleme sind.
// Globals: symbol settings, ring-buffer arrays and indices string g_sym=""; double g_point=0.0, g_tickVal=0.0, g_tickSize=0.0; double g_volMin=0, g_volMax=0, g_volStep=0; int g_atrHandle = INVALID_HANDLE; MqlTick g_latestTick; datetime g_time[]; // ring buffer timestamps double g_bid[], g_ask[], g_last[], g_vol[]; // ring buffer data int g_head = -1; // index of most recent slot int g_used = 0; // number of filled slots int g_size = 0; // capacity (InpRingSize)
Kleine Helfer (SafeDiv, ARGB, RR).
Ein paar kleine Hilfsfunktionen verbessern die Korrektheit und Lesbarkeit. SafeDiv ist ein defensiver Wrapper, der Fehler einer Division durch Null vermeidet – ein wichtiges Muster beim Umgang mit Live-Daten, die Nullen oder nicht initialisierte Werte enthalten können. ARGB setzt eine alphanumerische Farbmischung für die Panel-Hintergründe zusammen; die Wahl einer Alpha-Routine zentralisiert die Farbberechnung und hält den UI-Code übersichtlich. RR berechnet ein Risiko-Ertrags-Verhältnis in einem einzigen Ausdruck, wobei ein Nenner von Null gewahrt bleibt. Diese Hilfsprogramme sind kurz, aber unerlässlich: Sie sorgen dafür, dass sich die Hauptlogik auf die Handelssemantik und nicht auf wiederholte Klempnerarbeiten konzentriert, und schützen vor Laufzeitausnahmen, die beim Live-Handel schwer zu beheben sind.// Defensive helpers used across the codebase double SafeDiv(double a, double b) { return (b == 0.0 ? 0.0 : a/b); } uint ARGB(color c, int a) // produce ARGB color integer { if(a<0) a=0; if(a>255) a=255; return ((uint)a<<24) | (c & 0x00FFFFFF); } double RR(double entry,double stop,double tp) // simple R/R guard { return (entry - stop != 0.0 ? (tp - entry) / (entry - stop) : 0.0); }
Initialisieren und erweitern der Ringpuffer (BufInit / BufAdd).
Das Design des Ringpuffers ist gewollt: BufInit erzwingt eine Mindestkapazität und ändert die Größe von Arrays, während BufAdd den letzten Tick in den nächsten Slot schreibt und mit Modulus-Arithmetik umbricht. Dies führt zu einer Einfügezeit von O(1) und zu einem kompakten Festspeicherbedarf. In der Praxis wird dieses Muster den unbeschränkten Pushs (wie ArrayResize bei jedem Tick) vorgezogen, um Speicherveränderungen bei hochfrequenten Instrumenten zu vermeiden. BufAdd normalisiert auch das Volumen unter Verwendung von volume_real, wenn vorhanden, und greift auf volume oder 1,0 zurück, da viele Einzelhandels-Feeds entweder keine realistischen Volumen enthalten oder sie anders darstellen. Eine größere InpRingSize bewahrt mehr Historie für lange VWAP-Fenster, verbraucht aber mehr Speicher. Dieser Kompromiss wirkt sich auf die Reaktionsfähigkeit und die RAM-Nutzung aus.// Initialize ring buffer with minimum capacity void BufInit(int n) { if(n < 128) n = 128; g_size = n; ArrayResize(g_time, n); ArrayResize(g_bid, n); ArrayResize(g_ask, n); ArrayResize(g_last, n); ArrayResize(g_vol, n); g_head = -1; g_used = 0; } // Append a tick into the circular buffer (O(1) insertion) void BufAdd(const MqlTick &q) { if(g_size <= 0) return; g_head = (g_head + 1) % g_size; g_time[g_head] = q.time; g_bid[g_head] = q.bid; g_ask[g_head] = q.ask; g_last[g_head] = q.last; double vol = (q.volume_real > 0 ? q.volume_real : q.volume); g_vol[g_head] = (vol > 0 ? vol : 1.0); // safe fallback if(g_used < g_size) g_used++; }
Preis-Accessor (Mid-Funktion).
Die Funktion Mid gibt den besten verfügbaren Kurs für einen gespeicherten Tick zurück: Sie bevorzugt „Last“ (letztes Handelsgeschäft), falls vorhanden, und verwendet andernfalls den Mittelwert von Geld- und Briefkurs. Dieser mehrstufige Ansatz ist pragmatisch: Handelsausdrucke sind der direkteste Nachweis für den ausgeführten Preis, aber einige Tick-Updates enthalten nur Notierungen, sodass der Mittelwert dem fairen Wert nahe kommt. Die Rückgabe von 0 für unbrauchbare Slots signalisiert dem Aufrufer, diese Einträge zu überspringen. In der Praxis sollten Sie den Lesern erklären, dass die Bevorzugung des letzten gegenüber dem mittleren Punkt die Empfindlichkeit beeinflusst: Ein VWAP oder Flow, der sich auf den letzten Punkt konzentriert, reagiert nur, wenn Abschlüsse stattfinden, während die Verwendung des mittleren Punktes die Dichte erhöht, aber zu Kursrauschen führen kann.// Prefer last trade price; fallback to midpoint if last absent double Mid(int idx) { if(idx < 0 || idx >= g_size) return 0.0; if(g_last[idx] > 0.0) return g_last[idx]; if(g_bid[idx] > 0.0 && g_ask[idx] > 0.0) return 0.5 * (g_bid[idx] + g_ask[idx]); return 0.0; }
Spread- und ATR-Zugaben.
SpreadPips und ATR kapseln zwei orthogonale Maße: unmittelbare Transaktionskosten und Marktvolatilität. SpreadPips ruft SymbolInfoTick auf und dividiert (Ask – Bid) durch g_point, um den Spread in Pips (oder Punkten) auszudrücken, was einen Vergleich mit ATR einfach macht. ATR() liest den letzten ATR-Wert mit CopyBuffer vom Handle iATR, während ATR_Avg einen kurzen gleitenden Mittelwert berechnet. Diese Trennung ist wichtig: Die ATR wird als Volatilitäts-Basislinie behandelt, die für das Stop-Sizing und den Test des „engen Spread” test (spread < ATR * fraction) verwendet wird. Es ist wichtig, den Rechenaufwand zu berücksichtigen: CopyBuffer führt E/A aus und sollte sparsam verwendet werden; außerdem sollte klargestellt werden, dass die ATR auf einem durch InpTF bestimmten Zeitrahmen berechnet wird, sodass die Auswahl von InpTF die ATR und damit sowohl die Stopps als auch die billige Entscheidungen beeinflusst.// Spread in pips (points normalized by g_point) double SpreadPips() { MqlTick t; if(!SymbolInfoTick(g_sym, t) || g_point == 0.0) return 0.0; return (t.ask - t.bid) / g_point; } // Latest ATR (indicator handle must be created beforehand) double ATR() { if(g_atrHandle == INVALID_HANDLE) return 0.0; double buf[]; if(CopyBuffer(g_atrHandle, 0, 0, 1, buf) == 1) return buf[0]; return 0.0; } // Average ATR across 'bars' (caps at 200 to limit work) double ATR_Avg(int bars) { if(g_atrHandle == INVALID_HANDLE || bars <= 0) return 0.0; int cap = MathMin(bars, 200); double buf[]; int copied = CopyBuffer(g_atrHandle, 0, 0, cap, buf); if(copied <= 0) return 0.0; double s = 0.0; for(int i=0; i<copied; i++) s += buf[i]; return s / copied; }
Der Aggregator (Acc) – der zentrale Datensammler.
Acc ist die einzige zentrale Aggregationsroutine, die von den VWAP- und Flow-Funktionen aufgerufen wird. Anhand des Zeitstempels „since“ (seit) wird der Ringpuffer ab dem neuesten Tick rückwärts durchlaufen und Preis*Volumen (für den VWAP-Zähler), Gesamtvolumen (VWAP-Nenner) und – optional, wenn flowNeeded true ist – die Anzahl der Upticks und Downticks akkumuliert. Die Schleife hält an, wenn sie auf einen Tick stößt, der älter als „since“ ist, wodurch die Funktion fensterabhängig wird. Auf die Feinheiten der Implementierung kommt es an: prev wird auf DBL_MAX initialisiert, um den ersten Vergleich zu überspringen; Ticks mit ungültigen Preisen werden übersprungen; der Index wird umgeschlagen, wenn er den Anfang erreicht.
Die Funktion zählt absichtlich up und dn als Vorkommnisse (Tick-Count), anstatt die vorzeichenbehafteten Volumina zu summieren – dies ist eine Design-Entscheidung, die auf Einfachheit und Robustheit bei Feeds ohne zuverlässiges Volumen abzielt. Es ist wichtig, dies deutlich zu machen: Acc ermöglicht sowohl den volumengewichteten VWAP als auch den tickbasierten Flow, aber die hier gewählte Flow-Metrik zählt Ereignisse und nicht Volumen – dieser Unterschied hat praktische Konsequenzen für das Signalverhalten.
// Accumulate price*volume and volume; optionally compute up/dn tick counts void Acc(datetime since, double &pxVol, double &vol, int &up, int &dn, bool flowNeeded) { pxVol = 0.0; vol = 0.0; up = 0; dn = 0; if(g_used == 0) return; int idx = g_head; double prev = DBL_MAX; for(int i = 0; i < g_used; ++i) { if(g_time[idx] < since) break; double p = Mid(idx); if(p <= 0.0) { idx--; if(idx < 0) idx = g_size - 1; continue; } double w = (g_vol[idx] > 0.0 ? g_vol[idx] : 1.0); pxVol += p * w; // VWAP numerator vol += w; // VWAP denominator if(flowNeeded && prev != DBL_MAX) { if(p > prev) up++; else if(p < prev) dn++; } prev = p; idx--; if(idx < 0) idx = g_size - 1; } }
VWAP-Implementierung (VWAP-Funktion).
Die Funktion VWAP wandelt die allgemeine Acc in die bekannte Formel um. Sie berechnet „since“ aus TimeCurrent() abzüglich der konfigurierten Minuten, übergibt dies an Acc, um px und v zu erhalten, und gibt px / v zurück. Die Funktion gibt Null zurück, wenn kein Volumen vorhanden ist, um NaNs zu vermeiden. Aus konzeptioneller Sicht ist VWAP in diesem Tool ein rollierendes Zeitfenster-VWAP (standardmäßig kein Sitzungs-VWAP), das den Lesern über InpVWAPminutes die Kontrolle über die Reaktionsfähigkeit gibt. VWAP wird in der Regel auf zwei Arten verwendet: VWAP auf Basis eines längeren Fensters als Fair-Value-Anker und VWAPs auf Basis eines kürzeren Fensters für die Intraday-Mikrostruktur – und zum Zeigen, wie man sie modifiziert, um bei Bedarf einen sitzungsbasierten VWAP zu berechnen.// Rolling VWAP over last 'minutes' minutes double VWAP(int minutes) { if(minutes <= 0) return 0.0; datetime since = TimeCurrent() - (datetime)minutes * 60; double px = 0.0, v = 0.0; int u, d; Acc(since, px, v, u, d, false); return (v > 0.0 ? px / v : 0.0); }
Flow-Implementierung (Flow-Funktion).
Flow verwendet Acc mit flowNeeded=true, um Uptick- und Downtick-Zählungen zu erhalten, und gibt (up – dn) /(up + dn) zurück, ein normalisiertes Ungleichgewicht der Tick-Zählung in [-1,1]. Dieses einfache Verhältnis gibt einen unmittelbaren Eindruck von der Richtung der Aktivität: Werte nahe +1 zeigen an, dass fast alle Ticks im Fenster nach oben gerichtet waren, was auf aggressive Käufe durch Ticks hindeutet, während -1 auf eine Verkaufsneigung hinweist.
Die explizite Wahl der Tick-Zählung anstelle des volumengewichteten unterzeichneten Volumens ist besonders hervorzuheben: Die Zählung der Ticks verleiht allen Kursbewegungen das gleiche Gewicht und ist robust gegenüber anormalen einzelnen großen Trades; der volumengewichtete Flow misst stattdessen die Masse hinter den Bewegungen und kann informativer sein, wenn die tatsächlichen Handelsgrößen zuverlässig sind. Beide Ansätze sind gültig; das folgende Beispiel zeigt die derzeitige Umsetzung.
// Tick-count based flow (implemented in base tool) double Flow(int sec) { if(sec <= 0) return 0.0; datetime since = TimeCurrent() - sec; double px = 0.0, v = 0.0; int up = 0, dn = 0; Acc(since, px, v, up, dn, true); int tot = up + dn; return (tot ? double(up - dn) / tot : 0.0); // normalized [-1,1] } // Alternative: volume-weighted flow (replace Acc's tick-count mode) // *Requires modifying Acc to accumulate signedVol and totalVol* double VolumeWeightedFlow(int sec) { if(sec <= 0) return 0.0; datetime since = TimeCurrent() - sec; int idx = g_head; double signedVol = 0.0, totalVol = 0.0; double prev = DBL_MAX; for(int i = 0; i < g_used; ++i) { if(g_time[idx] < since) break; double p = Mid(idx); if(p <= 0.0) { idx--; if(idx < 0) idx = g_size - 1; continue; } double w = (g_vol[idx] > 0.0 ? g_vol[idx] : 1.0); if(prev != DBL_MAX) { if(p > prev) signedVol += w; else if(p < prev) signedVol -= w; } totalVol += w; prev = p; idx--; if(idx < 0) idx = g_size - 1; } return (totalVol ? signedVol / totalVol : 0.0); // normalized to [-1,1] }
Objekt-, Panel- und Kennzeichen-Helfer (EnsureObj, SetLabelIfChanged, SetRectIfChanged).
Die UI-Helfer abstrahieren sich wiederholende Objekterstellung und Eigenschaftsaktualisierungen und vermeiden auf intelligente Weise unnötige Aufrufe von ObjectSet*, indem sie aktuelle Werte vergleichen, bevor sie geändert werden. Dies verringert das Flackern und die CPU-Auslastung, da die Terminal-API-Aufrufe zum Erstellen oder Festlegen von Objekteigenschaften nicht kostenlos sind. EnsureObj zentralisiert die Semantik der Objekterstellung und SetLabelIfChanged und SetRectIfChanged standardisieren Eigenschaftsaktualisierungen für Labels und Rechteckhintergründe. Aus der Sicht der Softwareentwicklung ist dies eine gute Praxis – isolieren Sie die Macken der Plattform und halten Sie die Hauptlogik klar und deutlich. Weisen Sie in der Dokumentation darauf hin, dass diese Hilfsprogramme auch konsequent Objekte als nicht auswählbar festlegen, was eine versehentliche Manipulation des Charts verhindert und dafür sorgt, dass sich das Panel wie ein Dashboard und nicht wie interaktive Chart-Elemente verhält.// Create object if missing void EnsureObj(string name, ENUM_OBJECT type) { if(ObjectFind(0, name) == -1) ObjectCreate(0, name, type, 0, 0, 0); } // Update label text & position only if changed (reduces redraws) void SetLabelIfChanged(string name, int corner, int xdist, int ydist, string text, int fontsize, color col, string font) { EnsureObj(name, OBJ_LABEL); if(ObjectGetInteger(0,name,OBJPROP_CORNER) != corner) ObjectSetInteger(0,name,OBJPROP_CORNER,corner); if(ObjectGetInteger(0,name,OBJPROP_XDISTANCE) != xdist) ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xdist); if(ObjectGetInteger(0,name,OBJPROP_YDISTANCE) != ydist) ObjectSetInteger(0,name,OBJPROP_YDISTANCE,ydist); if(ObjectGetString(0,name,OBJPROP_TEXT) != text) ObjectSetString(0,name,OBJPROP_TEXT,text); if(ObjectGetInteger(0,name,OBJPROP_FONTSIZE) != fontsize) ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontsize); if(ObjectGetInteger(0,name,OBJPROP_COLOR) != (int)col) ObjectSetInteger(0,name,OBJPROP_COLOR,col); if(ObjectGetString(0,name,OBJPROP_FONT) != font) ObjectSetString(0,name,OBJPROP_FONT,font); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } // Update rectangle only when a property changed void SetRectIfChanged(string name,int corner,int xdist,int ydist,int xsize,int ysize,uint bgARGB) { EnsureObj(name, OBJ_RECTANGLE_LABEL); if(ObjectGetInteger(0,name,OBJPROP_CORNER) != corner) ObjectSetInteger(0,name,OBJPROP_CORNER,corner); if(ObjectGetInteger(0,name,OBJPROP_XDISTANCE) != xdist) ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xdist); if(ObjectGetInteger(0,name,OBJPROP_YDISTANCE) != ydist) ObjectSetInteger(0,name,OBJPROP_YDISTANCE,ydist); if(ObjectGetInteger(0,name,OBJPROP_XSIZE) != xsize) ObjectSetInteger(0,name,OBJPROP_XSIZE,xsize); if(ObjectGetInteger(0,name,OBJPROP_YSIZE) != ysize) ObjectSetInteger(0,name,OBJPROP_YSIZE,ysize); if((uint)ObjectGetInteger(0,name,OBJPROP_BGCOLOR) != bgARGB) ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgARGB); if((uint)ObjectGetInteger(0,name,OBJPROP_COLOR) != bgARGB) ObjectSetInteger(0,name,OBJPROP_COLOR,bgARGB); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); }
Panel-Erstellung und Layout (CreatePanelObjects und UpdatePanelObjects).
CreatePanelObjects instanziiert den Satz von Beschriftungen und Rechtecken, die das Info-Panel bilden; UpdatePanelObjects ist eine Layout-Engine, die Textbreiten, Balkengrößen und Positionen berechnet und dann die Eigenschaften aktualisiert, um die neuesten Metriken visuell wiederzugeben. Es verwendet eine Zeichenbreitenkonstante, um die Breite der Kennzeichnung zu schätzen, berechnet den verfügbaren Platz für Balken und zeichnet proportionale Vordergrundbalken für Spread, ATR und Flow.
Der Code wählt ein kompaktes visuelles Vokabular – eine Kopfzeile, Zusammenfassungszeilen, drei horizontale Balken und einen Zeitstempel in der Fußzeile – sodass Händler die wichtigsten Signale auf einen Blick erkennen können. Das Layout des Panels entspricht den folgenden Metriken: Verknüpfe jedes UI-Element mit seiner zugrunde liegenden Variablen (spPips - spread bar, flow - flow bar) und erläutere die Design-Kompromisse: Vorab berechnete ungefähre Textbreiten vermeiden komplexe Font-Metrik-Aufrufe, können jedoch bei seltenen Fonts zu leichten Fehlausrichtungen führen; das gewählte Alpha-Blending trägt zur Lesbarkeit der Nutzeroberfläche bei, ohne das Chart zu verdecken.
// Minimal set of dashboard objects used by UpdatePanelObjects void CreatePanelObjects() { EnsureObj("ESGP_bg", OBJ_RECTANGLE_LABEL); EnsureObj("ESGP_hdr", OBJ_LABEL); EnsureObj("ESGP_lbl", OBJ_LABEL); EnsureObj("ESGP_vwap", OBJ_LABEL); EnsureObj("ESGP_spbar", OBJ_RECTANGLE_LABEL); EnsureObj("ESGP_spbar_fg", OBJ_RECTANGLE_LABEL); EnsureObj("ESGP_flow_lbl", OBJ_LABEL); // Make them non-selectable by default string objs[] = {"ESGP_bg","ESGP_hdr","ESGP_lbl","ESGP_vwap","ESGP_spbar","ESGP_spbar_fg","ESGP_flow_lbl"}; for(int i=0;i<ArraySize(objs);i++) ObjectSetInteger(0,objs[i],OBJPROP_SELECTABLE,false); }
Alarmmanagement und visuelle Markierungen.
Das Alert-Subsystem unterstützt drei Modi: einmalige Ersetzung, rollierende Löschung (zeitstempelbasierte eindeutige Namen) und einen gepoolten, ringförmigen Satz von Markern. Optional werden Warnmeldungen nur dann ausgelöst, wenn der Test auf einen billigen Spread erfüllt ist und der Flow die konfigurierten Schwellenwerte überschreitet, wobei eine Hysterese eingebaut ist, um ein Flattern zu vermeiden. Der Code speichert für jede Markierung einen Zeitstempel in OBJPROP_TOOLTIP und AutoClearOldAlerts löscht veraltete Markierungen, die älter sind als InpAlertMaxAgeSec. Dies ist ein eleganter, wenig abhängiger Ansatz für das Journaling auf dem Chart: Es vermeidet die Notwendigkeit einer externen Speicherung und bietet Händlern gleichzeitig einen sichtbaren Prüfpfad für Signalereignisse. In dem Artikel wird die Nutzerfreundlichkeit des Handels hervorgehoben: Dauerhafte Markierungen vereinfachen die Überprüfung und die Backtests durch visuellen Vergleich, während die Hysterese Rauschen und falsche Wiederauslösungen reduziert.// Draw a simple buy/sell alert label in the panel corner void DrawAlertMarker(bool isBuy) { string nm = (isBuy ? "ESGP_alert_buy" : "ESGP_alert_sell"); if(ObjectFind(0, nm) != -1) ObjectDelete(0, nm); ObjectCreate(0, nm, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, nm, OBJPROP_CORNER, COR_LT); ObjectSetInteger(0, nm, OBJPROP_XDISTANCE, 8); ObjectSetInteger(0, nm, OBJPROP_YDISTANCE, isBuy ? 60 : 80); ObjectSetString(0, nm, OBJPROP_TEXT, isBuy ? "▲ BUY" : "▼ SELL"); ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 12); ObjectSetInteger(0, nm, OBJPROP_COLOR, isBuy ? clrLime : clrRed); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetString(0, nm, OBJPROP_TOOLTIP, IntegerToString((int)TimeCurrent())); // store timestamp }
Verwaltung der Lebenszyklen OnInit und OnDeinit.
OnInit führt alle notwendigen Startaufgaben durch: Symbolauswahl, optionaler Wechsel des Chart-Zeitrahmens, Abruf der Symbolparameter (SYMBOL_POINT, SYMBOL_VOLUME_STEP, etc.), Erstellung des ATR-Indikators mit iATR, Initialisierung des Ringpuffers, Erstellung des Panel-Objekts und Einrichtung des Timers mit EventSetTimer. Jeder Schritt prüft auf Fehler (z. B. ungültiges ATR-Handle) und gibt INIT_FAILED zurück, wenn eine kritische Initialisierung fehlschlägt – ein wichtiges Sicherheitselement.int OnInit() { g_sym = (_Symbol); if(!SymbolSelect(g_sym, true)) return INIT_FAILED; g_point = SymbolInfoDouble(g_sym, SYMBOL_POINT); g_tickVal = SymbolInfoDouble(g_sym, SYMBOL_TRADE_TICK_VALUE); g_tickSize= SymbolInfoDouble(g_sym, SYMBOL_TRADE_TICK_SIZE); g_volMin = SymbolInfoDouble(g_sym, SYMBOL_VOLUME_MIN); g_volMax = SymbolInfoDouble(g_sym, SYMBOL_VOLUME_MAX); g_volStep = SymbolInfoDouble(g_sym, SYMBOL_VOLUME_STEP); // create ATR handle for InpTF and InpATRperiod (example uses default TF & period) g_atrHandle = iATR(g_sym, PERIOD_M1, 14); if(g_atrHandle == INVALID_HANDLE) return INIT_FAILED; BufInit((int)InpRingSize); CreatePanelObjects(); EventSetTimer((int)InpTimerSec); return INIT_SUCCEEDED; }
OnDeinit räumt auf: Es beendet den Timer, entfernt Panel- und Alert-Objekte und gibt Indikator-Handles frei. Es sei darauf hingewiesen, dass das Versäumnis, Indikator-Handles freizugeben oder Timer aktiv zu lassen, zu versteckten Speicher-/Handle-Lecks im Terminal und unerwartetem Verhalten führen kann, wenn der EA wieder angeschlossen wird.
void OnDeinit(const int reason) { EventKillTimer(); // remove panel objects (prefix "ESGP_") int total = ObjectsTotal(0); for(int i=total-1; i>=0; --i) { string nm = ObjectName(0, i); if(StringFind(nm, "ESGP_", 0) == 0) ObjectDelete(0, nm); } if(g_atrHandle != INVALID_HANDLE) { IndicatorRelease(g_atrHandle); g_atrHandle = INVALID_HANDLE; } }
OnTick-Eingabestrategie.
OnTick ist absichtlich kurz gehalten: Es liest den letzten Tick mit SymbolInfoTick und fügt ihn über BufAdd dem Ringpuffer hinzu. Mehr Aufgaben werden in OnTimer verschoben. Dies ist eine wichtige architektonische Entscheidung: Einige Instrumente erzeugen Hunderte oder Tausende von Ticks pro Sekunde, und die Durchführung teurer UI-Aktualisierungen oder Indikatorlesungen innerhalb von OnTick kann den Hauptthread belasten und das Terminal verlangsamen. Durch die Entkopplung von Ingestion und Verarbeitung bleibt der EA reaktionsschnell und deterministisch. Diese Architektur vereinfacht auch das Testen, denn: OnTimer läuft mit einer kontrollierten Kadenz, sodass das gemessene Verhalten leichter zu reproduzieren ist.void OnTick() { MqlTick q; if(SymbolInfoTick(g_sym, q)) { g_latestTick = q; // store latest tick BufAdd(q); // append into ring buffer (fast) } }
Die Hauptschleife OnTimer – Berechnungen, Entscheidungsfindung, Nutzeroberfläche und Warnmeldungen.
OnTimer ist der Orchestrator: Er stellt sicher, dass der Puffer auf dem neuesten Stand ist, erzwingt eine Aktualisierungskadenz, berechnet Spread und ATR in Pips, wendet den Test „cheap spread“ an, ruft VWAP und Flow auf, berechnet Positionsgrößen- und Risikoparameter, entscheidet, ob das Panel (über Änderungsschwellen) aktualisiert werden soll, und evaluiert die Warnlogik. Die Risikosizing-Routine berechnet einen Stop auf der Grundlage von ATR und InpStopATRmult, konvertiert die Stop-Distanz in Ticks und Cash pro Lot und leitet eine Lotgröße ab, die das Kontorisiko gemäß InpRiskPct begrenzt, wobei auf den g_volStep des Brokers gerundet und zwischen dem minimalen und dem maximalen zulässigen Volumen geklemmt wird. Die Alarmentscheidung erfordert sowohl eine billige Spanne als auch einen Schwellenwert für die Überschreitung des Durchflusses, mit einer Hysterese über InpFlowHystFactor, um ein schnelles Umschalten zu verhindern. Präsentieren Sie diesen Absatz in Ihrem Artikel als Erklärung der „Entscheidungsmaschine“ – er zeigt, wie Kostenfilterung (Spread vs. ATR), Richtungsbestätigung (Flow) und Money-Management (Risiko-/Lot-Berechnung) zusammen ein praktisches Handelssignal ergeben.
Es ist wichtig, ausdrücklich darauf hinzuweisen, dass Flow in der aktuellen Implementierung auf der Anzahl der Ticks basiert: Es misst die Häufigkeit von Aufwärts- und Abwärtsbewegungen, nicht das Gesamtvolumen hinter diesen Bewegungen. Diese Wahl macht die Metrik robust für Feeds, die kein zuverlässiges Volumen pro Tick aufweisen, bedeutet aber auch, dass die Metrik durch viele kleine Ticks im Vergleich zu einem einzigen großen Handel verzerrt werden kann. Der VWAP ist als rollierender VWAP mit Zeitfenster (auf Minutenbasis) implementiert, nicht als Sitzungs-VWAP, was sich auf die Interpretation auswirkt: der rollierende VWAP ist reaktiv, der Sitzungs-VWAP liefert eine Intraday-Benchmark.
Der Spread wird mit g_point auf Pips normiert, während die ATR in Punkten gelesen und in Pips umgerechnet wird, damit die Vergleiche konsistent sind. Es können sowohl die implementierten Formeln als auch alternative Versionen berücksichtigt werden. Um beispielsweise den volumengewichteten Fluss zu berechnen, ändern Sie Acc so, dass es das vorzeichenbehaftete Volumen akkumuliert, und geben Sie dem Nutzer den Hinweis zum Umschalten auf einen volumengewichteten Flow (ändern Sie Acc so, dass es vorzeichenbehaftete Volumina akkumuliert und durch das Gesamtvolumen dividiert).
void OnTimer() { // 1) ensure buffer has latest tick (sometimes needed) MqlTick t; if(SymbolInfoTick(g_sym, t)) { if(g_used == 0 || g_time[g_head] != t.time) BufAdd(t); } // 2) compute metrics double spPips = SpreadPips(); double atrPts = ATR(); // ATR in price units (points) double atrPips = (atrPts > 0 && g_point > 0) ? atrPts / g_point : 0.0; bool cheap = (atrPts > 0 && spPips < atrPips * InpCheapSpreadFrac); double vwap = VWAP(InpVWAPminutes); double flow = Flow(InpImbWindowSec); // tick-count flow // 3) Example risk sizing (conservative) double bal = AccountInfoDouble(ACCOUNT_BALANCE); double bid = SymbolInfoDouble(g_sym, SYMBOL_BID); double stop = bid - InpStopATRmult * atrPts; double riskPx = bid - stop; double ticks = (g_tickSize > 0 ? riskPx / g_tickSize : 0.0); double cashPerLot = ticks * g_tickVal; double maxLoss = bal * InpRiskPct / 100.0; double rawLot = (cashPerLot > 0.0 ? maxLoss / cashPerLot : 0.0); double lot = (g_volStep > 0.0 ? MathFloor(rawLot / g_volStep) * g_volStep : 0.0); // 4) Alerting with hysteresis double resetThresh = InpFlowTh * InpFlowHystFactor; static bool buyF=false, sellF=false; if(cheap) { if(flow >= InpFlowTh && !buyF) { Alert("BUY edge: cheap spread + buy flow"); buyF = true; sellF = false; DrawAlertMarker(true); } else if(flow < resetThresh) buyF = false; if(flow <= -InpFlowTh && !sellF) { Alert("SELL edge: cheap spread + sell flow"); sellF = true; buyF = false; DrawAlertMarker(false); } else if(flow > -resetThresh) sellF = false; } }
Und schließlich Überlegungen zu Stresstests: Die Tick-Granularität des Strategietesters spiegelt möglicherweise nicht das Live-Feed-Verhalten wider, sodass Tick-Replay- oder historische Tick-Daten erforderlich sind, um die Tick-basierte Logik zu validieren. Die Protokollierung sollte mit Bedacht erfolgen (Vermeidung von Print Flooding bei aktiven Instrumenten) und es wird empfohlen, ein Profil für die CPU-Nutzung zu erstellen, wenn InpTimerSec klein ist. Empfohlene Parametervoreinstellungen (z. B. InpVWAPminutes von 60-240 für die Verwendung innerhalb eines Tages, InpImbWindowSec von 10-60 für die Mikrostrukturerkennung, InpCheapSpreadFrac 0,3-0,7 je nach Instrument). Es wird ein schrittweiser Tuning-Ansatz empfohlen: Beginnen Sie mit konservativen Schwellenwerten, überprüfen Sie Signale zunächst mit visuellen Markern und aktivieren Sie den automatischen Handel erst nach strengen Vorwärtstests. Schlagen Sie Verbesserungen vor, z. B. eine Option zur Verwendung von sitzungsbasierten VWAPs, eine Volumengewichtung der Durchflüsse, eine EMA-Glättung für Durchflüsse zur Verringerung des Whipsaw und die Aufzeichnung der Tick-Historie für eine reproduzierbare Offline-Analyse.
Ergebnisse
Nach der Entwicklung des EA war der nächste Schritt der Einsatz zum Testen, der entweder auf einem Demokonto oder durch Backtests durchgeführt werden kann. Ich werde eine Reihe von Bildern zeigen, die während des Testprozesses auf dem MetaTrader 5 Terminal aufgenommen wurden, um die Leistung und das Verhalten des Systems zu veranschaulichen.
In der nachstehenden Abbildung zeigt das Panel einen zuvor ausgegebenen BUY-Alarm an (grüne Kopfzeile/BUY-Markierung). Allerdings ist der aktuelle Strom des kurzen Fensters leicht negativ, mit einem Ungleichgewicht von etwa -10,3% und einem Flow von -0,10.
Der Spread von 71,0 Pips ist im Vergleich zur vorherrschenden Volatilität relativ gering und wird vom System als „billig“ eingestuft (die Bedingung für die billigen Spreads ist erfüllt). Da die ATR mit 469,4 Pips recht hoch ist, ergeben sich aus den auf der Basis der ATR berechneten Schutzstopps weite Stopp- und Take-Profit-Abstände – etwa 563,3 Pips für den Stopp und 1.126,6 Pips für den TP2R, was zu einem Risiko-Ertrags-Verhältnis von 2,00 führt.
Insgesamt ist der Kostenfilter des EA (der einen billigen Spread anzeigt) erfüllt. Allerdings ist die Richtungsbestätigung durch den Flow in diesem Moment leicht rückläufig, sodass das System trotz der bestehenden Kaufmarkierung aus dem früheren Signal kein neuer Kauf ausgelöst wird.
Nach dem anfänglichen Kaufsignal bewegte sich der Markt im Laufe der Zeit zu Gunsten des Handels. Das entsprechende Chart veranschaulicht diese positive Entwicklung. Aktuell wird ein neues Verkaufssignal angezeigt, das die sich verändernden Marktbedingungen widerspiegelt.
Anschließend drehte der Markt nach unten und bestätigte damit die Gültigkeit des Signals. Die nachstehende Abbildung zeigt eine visuelle Bestätigung dieser Bewegung.
Jedes einzelne Signal wird von einer Alarmbenachrichtigung begleitet und in der Registerkarte MetaTrader 5 Experts für eine umfassende Nachverfolgung und Aufzeichnung protokolliert.
Schlussfolgerung
Das Slippage Tool wurde entwickelt, um ein praktisches und häufiges Problem zu lösen, mit dem Händler konfrontiert sind: Sie haben nur begrenzten Zugang zu zuverlässigen Daten des Marktbuchs und benötigen dennoch Signale des Order-Flows, um wahrscheinliche Einstiegspunkte zu identifizieren. Dieses System versucht nicht, eine umfassende Leiter der Markttiefe zu ersetzen, sondern extrahiert die verwertbarsten Erkenntnisse über die Mikrostruktur aus dem verfügbaren Tickstream. Es verwendet einen rollierenden VWAP als Fair-Value-Anker, in einem kurzfristigen Fenster eine Ungleichgewichts- und Flow-Metrik zur Hervorhebung von direktionalem Druck und einen Spread- plus ATR-Kontext, um sicherzustellen, dass die Signale sowohl handelbar als auch risikobewusst sind. In Verbindung mit der Visualisierung auf dem Chart, Warnmeldungen und einer automatischen Logik für die Positionsgrößenbestimmung verwandelt das Tool Tick-Rohdaten in Echtzeit in entscheidungsrelevante Informationen.
Was das Sippage Tool auszeichnet, ist seine pragmatische Ausrichtung auf Robustheit und Nutzerfreundlichkeit. Funktionen wie ein Ringpuffer und eine leichtgewichtige OnTick-Ingestion tragen zur Aufrechterhaltung der Terminalleistung bei Instrumenten mit hohem Tickaufkommen bei; defensive Helfer und Änderungserkennung verhindern unnötige Redraws; und Warnmeldungen umfassen Hysterese und konfigurierbare Marker-Modi zur Minimierung von Rauschen und falschen Signalen. Die integrierte Logik zur Risikogestaltung verknüpft die Signalerzeugung mit dem tatsächlichen Geldmanagement, indem sie jeden potenziellen Handel anhand von ATR-basierten Stopps und dem Kontorisiko bewertet und so eine disziplinierte Größe gegenüber unüberlegten Positionsnahmen fördert.
Es ist wichtig, die Grenzen des Instruments zu erkennen. Es dient als Proxy für Orderbuchinformationen, nicht als direkter DOM-Feed: Der Flow wird aus Tick-Zählungen abgeleitet (oder optional volumengewichtet), und der VWAP wird aus Ausdrucken und Midpoints rekonstruiert. Folglich sollten Signale im Kontext von Charts, mehreren Zeitrahmen und wiederholten Tick-Daten validiert werden. Parameter wie das VWAP-Fenster, das Imbalance-Fenster, der Spread-Anteil und die Flow-Schwellenwerte sollten auf die Tickrate und die Volatilität des jeweiligen Instruments abgestimmt werden; es gibt keine universelle Konfiguration.
Für Praktiker, die das System sicher einführen wollen, wird ein schrittweises Vorgehen empfohlen: (1) visuelle Validierung der Signale mit Hilfe des Bedienfelds und der Markierungen im Wiederholungs- oder Demomodus, (2) konservative Einstellung der Schwellenwerte und Überprüfung der Leistung in Vorwärtstests und (3) erst dann Erwägung der Automatisierung von Eingaben mit robusten Stopp- und Timeout-Regeln sowie einer umfassenden Protokollierung. Zukünftige Verbesserungen können einen auswählbaren Sitzungs-VWAP-Modus, eine optionale volumengewichtete Durchflussberechnung, eine EMA-Glättung zur Reduzierung von „Whipsaws“ und ein exportierbares Ereignisprotokoll zur Erleichterung einer reproduzierbaren Analyse umfassen.
Siehe meine anderen Artikel.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/19290
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Dynamic Mode Decomposition angewandt auf univariate Zeitreihen in MQL5
Selbstoptimierende Expert Advisors in MQL5 (Teil 14): Betrachtung von Datentransformationen als Tuning-Parameter unseres Feedback-Controllers
Der Parafrac V2 Oszillator: Integration von Parabolic SAR mit Average True Range
Aufbau eines Handelssystems (Teil 3): Bestimmung des Mindestrisikoniveaus für realistische Gewinnziele
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
warum gibt es kein Gremium?
Sir,
warum gibt es kein Gremium?