English 日本語
preview
Der MQL5 Standard Library Explorer (Teil 1): Einführung in CTrade, CiMA, und CiATR

Der MQL5 Standard Library Explorer (Teil 1): Einführung in CTrade, CiMA, und CiATR

MetaTrader 5Beispiele |
141 0
Clemence Benjamin
Clemence Benjamin

Struktur der Diskussion:

  1. Einführung
  2. Umsetzung
  3. Tests und Ergebnisse
  4. Schlussfolgerung
  5. Wichtigste Erkenntnisse
  6. Anlagen



Einführung

Viele Entwickler, vor allem diejenigen, die neu in MQL5 sind, schrecken oft vor der Verwendung von Klassen und Bibliotheken zurück. Dieses Zögern ist verständlich, denn eine einfache Prozedurale Programmierung wirkt unmittelbarer und ist leichter zu begreifen. Dies ist zwar ein guter Ausgangspunkt, aber der Übergang zu komplexeren Systemen erfordert ein Umdenken. Bei der Einführung in das prozedurale Programmieren geht es nicht nur um zusätzliche Komplexität, sondern auch darum, ein höheres Maß an Professionalität, Effizienz und Einfachheit zu erreichen.

Die MQL5-Standardbibliothek ist die perfekte Verkörperung dieses Prinzips. Es handelt sich nicht um ein kryptisches Regelwerk, das es zu beherrschen gilt, sondern um eine Sammlung leistungsfähiger, vorgefertigter Tools, mit denen sich wiederholende Aufgaben vermieden werden können. Stellen Sie sich vor, Sie erfinden das Rad nicht von Grund auf neu, sondern bauen ein Hochleistungsfahrzeug aus fachmännisch gefertigten Teilen zusammen. Die Bibliothek liefert die Puzzleteile; Ihre Aufgabe ist es, sie zu einem vollständigen Bild zusammenzufügen.

Diese Artikelserie soll ein solcher Leitfaden sein. Egal, ob Sie ein Neuling sind, der seinen ersten Expert Advisor erstellen möchte, oder ein erfahrener Profi, der seinen Code optimieren möchte, wir werden die Standardbibliothek entmystifizieren. Unser Ziel ist es, Ihnen zu zeigen, wie Sie komplexe, robuste Handelssysteme mit minimalem Boilerplate-Code konstruieren können, indem Sie die von den MetaQuotes-Entwicklern bereits geleistete Arbeit nutzen.

Ich habe immer wieder beobachtet, dass viele Entwickler den großen Nutzen der Standardbibliothek übersehen und sich oft schwer damit tun, Funktionen zu implementieren, die bereits in der Bibliothek vorhanden sind. Diese Bibliothek ist ein Tor zur Einfachheit und bietet elegante Lösungen für häufige Herausforderungen im algorithmischen Handel.

Außerdem ist das Potenzial der Bibliothek noch weitgehend ungenutzt. Viele seiner Bestandteile bleiben im Hintergrund, versteckte Schätze, die darauf warten, entdeckt und angewendet zu werden. Mit jedem Update von MetaTrader 5 wird die Standardbibliothek leistungsfähiger und umfangreicher. Indem wir lernen, damit zu arbeiten, benutzen wir nicht nur ein Werkzeug, sondern lernen eine Sprache der Effizienz, die es uns ermöglicht, seine Fähigkeiten zu erweitern und selbst neue Funktionen zu erfinden.

In dieser Diskussion wird der Vorhang gelüftet und auf diese verborgenen Schätze eingegangen. Lassen Sie uns gemeinsam das volle Potenzial der MQL5-Standardbibliothek ausschöpfen, um die Art und Weise, wie wir programmieren und handeln, zu verändern. 

In diesem ersten Teil unserer Serie entwickeln wir einen kompletten Expert Advisor, der zeigt, wie drei beliebte Klassen aus der MQL5-Standardbibliothek – CTrade, CiMA und CiATR – zu einem praktischen Handelssystem kombiniert werden können. Der Schwerpunkt liegt hier auf der Lieferung einer voll funktionsfähigen Idee, die die Leserinnen und Leser zusammenstellen, testen und anpassen können, ohne auf künftige Ausgaben warten zu müssen.

Hintergrund

Während die MQL5-Dokumentation die formale Definition von Klassen wie CTrade, CiMA und CiATRenthält – mit einer Auflistungihrer Vererbung, verfügbaren Methoden und kurzen Beschreibungen – zeigt sie Entwicklern nicht, wie sie diese in praktischen Handelssystemen kombinieren können. Für einen Neuling kann diese Lücke einschüchternd sein; die Dokumentation sagt Ihnen, was es gibt, aber nicht, wie Sie es effektiv nutzen können. Deshalb sind unsere Diskussion und viele andere Artikel so wichtig.

Hier gehen wir über die API-Listen hinaus und treten in die Anwendung ein. Wir erklären nicht nur, was die einzelnen Klassen darstellen, sondern auch, wie sie in den Lebenszyklus des Expert Advisors integriert werden, wie ihre Ausgaben zu interpretieren sind und wie sie mit anderen Klassen interagieren, um eine vollständige Strategie zu bilden. Kurz gesagt, diese Serie überbrückt die Lücke zwischen Referenzdokumentation und praktischer Anwendung, indem sie den Lesern einen geführten Weg von rohen Klassendefinitionen zu einem funktionierenden Handelsroboter bietet.

Warum diese Klassen?

Die MQL5-Standardbibliothek wird mit jeder MetaTrader 5-Installation mitgeliefert, und die Quelldateien sind in MetaEditor 5 leicht zugänglich. Standardmäßig befinden sich diese Dateien unter dem Include-Verzeichnis Ihrer MQL5-Installation (z. B. MQL5\Include\Trade\ oder MQL5\Include\Indicators\). Jedes Modul ist in Header-Dateien (.mqh) organisiert, die wiederverwendbare Klassen wie CTrade, CiMA und CiATR definieren. In MetaEditor können Sie diese Dateien ganz einfach im Navigator unter Include → Standardbibliothek durchsuchen oder sie direkt über Datei → Öffnen öffnen. Diese Zugänglichkeit bedeutet, dass Sie die Klassen in Ihren Projekten verwenden können, indem Sie #include-Anweisungen hinzufügen, und auch den Quellcode selbst einsehen können, um zu lernen, wie die Bibliothek strukturiert ist, und sie sogar für Ihre eigenen Entwicklungsbedürfnisse erweitern oder anpassen können

AktieX_fVhTmSxwMI

Abbildung 1. Zugriff auf die MQL5-Standardbibliothek in MetaEditor 5

CTrade – die Ausführungsmaschine

CTrade ist der Wrapper der Standardbibliothek, der die Handelsübermittlung und die grundlegende Auftragsverwaltung für Sie übernimmt. Anstatt jedes Mal MqlTradeRequest-Strukturen auf niedriger Ebene zu konstruieren, stellt CTrade einfache Methoden (Buy, Sell, PositionClose usw.) zur Verfügung und meldet dann standardisierte Ergebnisse, die Sie überprüfen können. Im EA werden wir uns für alle Ausführungsaufgaben auf CTrade verlassen: Platzieren von Einträgen mit der berechneten Größe, Überprüfen des zurückgegebenen Status, Protokollieren des Fehlergrundes, wenn eine Anfrage abgelehnt wird, und Ausführen sicherer Wiederholungsversuche oder Deaktivieren des Handels, wenn systemische Fehler auftreten. Durch die Verwendung von CTrade wird der Ausführungscode kürzer, einfacher zu prüfen und konsistenter zwischen den Brokern.

#include <Trade\Trade.mqh>

// Global declarations
CTrade trade;

CiATR – Volatilität und Größenordnung

CiATR (aus Indicators\Oscillators.mqh) liefert uns die Average True Range in Preiseinheiten, die wir als Volatilitätsmotor verwenden. In der Praxis lesen wir den ATR-Wert, um (a) zu entscheiden, ob der Markt zu unruhig oder zu ruhig ist, um zu handeln, (b) einen dynamischen Stop-Abstand zu berechnen (z. B. Stop = ATR * Multiplikator) und (c) diesen Abstand in Geld pro Lot umzurechnen, damit wir eine risikobasierte Lot-Größe berechnen können. Der EA erstellt einmal eine CiATR-Instanz, aktualisiert sie bei jedem Tick, prüft, ob die Ausgabe gültig ist, und verwendet eine kleine Hilfsroutine, um ATR → Loss-per-Lot → Lots normalisiert auf den Volumenschritt des Brokers umzurechnen.

#include <Indicators\Oscilators.mqh>
CiATR atr;

CiMA – der Trenddetektor

CiMA (aus Indicators\Trend.mqh) umfasst die Logik des gleitenden Durchschnitts und die Pufferverarbeitung, sodass Sie lesbare, stabile MA-Werte in Ihrem EA zur Verfügung haben. Wir verwenden zwei CiMA-Instanzen (schnell und langsam), um einen einfachen direktionalen Filter zu erstellen: Wenn der schnelle MA über dem langsamen MA liegt, wird der Markt als „Aufwärtstrend“ betrachtet und umgekehrt. CiMA bietet auch bequemen Zugriff auf die jüngsten MA-Werte (aktueller oder letzter geschlossener Balken), sodass Sie eine Pullback-Logik implementieren können (z. B. einsteigen, wenn der Kurs um einen Bruchteil der ATR in Richtung des schnellen MA zurückgeht). Wie die anderen, CiMA einmal erstellen, bei Ticks aktualisieren, vor EMPTY_VALUE schützen und Main(1) für Bar-Close-Entscheidungen bevorzugen, wenn Sie nicht wiederholte Signale wünschen.

#include <Indicators\Trend.mqh>
CiMA fastMA, slowMA;

Wesentlicher Lebenszyklus (kurz)

  • OnInit() – Create() jeder Klasseninstanz einmal.
  • OnTick() – Aufruf von Refresh() bei jedem Tick, Lesen von Main() (Prüfung auf EMPTY_VALUE), Ausführen der Entscheidungslogik, Berechnen der Größe, dann Aufruf der CTrade-Methoden zur Ausführung.
  • OnDeinit() – Aufruf von FullRelease() bei Indikatoren und Bereinigung von Chart-Objekten

Mit diesen Grundsätzen – klare Zuständigkeiten für jede Klasse, ein disziplinierter Lebenszyklus, einheitsbewusstes Sizing und robuste Ausführungsprüfungen – können wir nun mit der Implementierung eines prägnanten, lesbaren EA beginnen, der CiMA, CiATR und CTrade in die vollständige Entscheidungspipeline (Init → Refresh → Detect → Size → Execute → Manage) einbindet und die Sicherheits- und Protokollierungshaken enthält, die wir für zuverlässige Tests benötigen.


Umsetzung

Nachdem die Grundlagen gelegt sind, wenden wir uns nun der praktischen Seite dieser Diskussion zu – der Frage, wie man diese Klassen tatsächlich zu einer funktionierenden Handelslösung zusammenführt. Dabei geht es nicht nur um abstrakte Beschreibungen, sondern um klare, strukturierte Schritte, die zeigen, wie sich jede Klasse – ob für die Handelsausführung, die Indikatoranalyse oder die Kontoüberwachung – in die allgemeine Handelslogik einfügt. Dieser Abschnitt führt Sie vom Konzept zum Code und stellt sicher, dass der Übergang von der Theorie zur Praxis sowohl logisch als auch nachvollziehbar ist.

Dateikopf, Includes und Nutzereingaben

Dieser erste Block deklariert, was das Programm ist und bringt die Bausteine ein, die der EA verwendet. Es bietet auch eine Reihe von Nutzereingaben, sodass der Leser Zeiträume, Risiken und Sicherheitsgrenzen einstellen kann, ohne den Code zu ändern. Wenn die Parameter ganz oben stehen, sind Experimente und Tests im Klassenzimmer einfach.

//+------------------------------------------------------------------+
//| CiMA_Trend_Trader.mq5                                            |
//| Compact, working EA that uses CiMA (trend), CiATR (volatility)   |
//| and CTrade (execution). Adjustable inputs.                       |
//+------------------------------------------------------------------+
#property copyright "Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"

#include <Trade\Trade.mqh>
#include <Indicators\Trend.mqh>          // CiMA
#include <Indicators\Oscilators.mqh>     // CiATR

input int    InpFastMAPeriod   = 8;      // Fast MA period
input int    InpSlowMAPeriod   = 34;     // Slow MA period
input int    InpATRPeriod      = 14;     // ATR period
input double InpRiskPercent    = 0.5;    // % of balance risk per trade
input double InpATRstopMult    = 1.5;    // SL = ATR * this
input double InpPullbackFactor = 0.5;    // price within this * ATR of fastMA to consider entry
input double InpTakeProfitRR   = 2.0;    // TP = R * RR
input double InpMaxChopPct     = 0.006;  // skip if ATR/price > this (too choppy)
input double InpMinVolPct      = 0.0005; // skip if ATR/price < this (too quiet)
input double InpMaxDailyLossPct= 2.0;    // disable trading for the day if loss exceeds this %
input int    InpMaxPosPerSym   = 1;      // max open positions per symbol (basic cap)
input int    InpMagicNumber    = 202507; // EA magic number for labeling
input int    InpSlippage       = 5;      // slippage in points (not required for CTrade but useful to log)
input bool   InpShowTradeLabels = true;  // draw arrows/labels on chart

Globale Objekte und einfacher Zustand

Hier deklarieren wir die gemeinsam genutzten Objekte, die der EA kontinuierlich verwenden wird: den Trade Handler und die Indikatorinstanzen. Eine kleine Zustandsvariable erfasst die letzte Handelszeit. Diese globalen Variablen bleiben über Initialisierung, Ticks und Deinitialisierung hinweg bestehen, sodass die Logik Handles wiederverwenden und eine teure Neuerstellung vermeiden kann.

// Global objects
CTrade  trade;
CiMA    fastMA, slowMA;
CiATR   atr;

// Internal tracking
datetime g_lastTradeTime = 0;

Initialisierung: Erstellung von Indikatoren und Vorbereitung des EA

Beim Starten wird jeder Indikator einmal erstellt und die Erstellung bestätigt. Wenn ein Erstellungsschritt fehlschlägt, bricht der EA mit einer klaren Meldung ab. Ein kurzer Timer ist für die optionale Haushaltsführung eingestellt. Dieses Muster vermeidet Ressourcenlecks und hält den Aufwand pro Tick minimal.

int OnInit()
{
  // Create indicator objects
  if(!fastMA.Create(_Symbol, _Period, InpFastMAPeriod, 0, MODE_EMA, PRICE_CLOSE))
  {
    Print("[OnInit] fastMA.Create failed for ", _Symbol);
    return(INIT_FAILED);
  }
  if(!slowMA.Create(_Symbol, _Period, InpSlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE))
  {
    Print("[OnInit] slowMA.Create failed for ", _Symbol);
    return(INIT_FAILED);
  }
  if(!atr.Create(_Symbol, _Period, InpATRPeriod))
  {
    Print("[OnInit] atr.Create failed for ", _Symbol);
    return(INIT_FAILED);
  }

  EventSetTimer(1); // optional: ensure OnTimer for housekeeping if needed
  Print("CiMA_Trend_Trader initialized: ", _Symbol, " ", EnumToString(_Period));
  return(INIT_SUCCEEDED);
}

Deinitialisierung und optionaler Timer

Wenn der EA entfernt wird, geben wir alle Indikatorressourcen frei und stoppen den Timer. Der Timer-Handler selbst wird als kleiner Aufhänger für Diagnosen oder Rücksetzungen belassen, falls man den EA später erweitern möchte.

void OnDeinit(const int reason)
{
  // release indicator resources
  fastMA.FullRelease(true);
  slowMA.FullRelease(true);
  atr.FullRelease(true);
  EventKillTimer();
}

void OnTimer()
{
  // Simple daily reset or housekeeping can be added here if required
}

Positionszählung (Sicherheitssteuerung)

Bevor der EA neue Trades eröffnet, prüft er, wie viele Positionen für dieses Symbol bereits offen sind. Diese Funktion durchsucht die aktuellen Positionen und gibt die Anzahl zurück. Sie wird verwendet, um eine einfache Maximalwährungsregel einzuhalten.

int CountOpenPositionsForSymbol()
{
  int total = PositionsTotal();
  int count = 0;
  for(int i=0;i<total;i++)
  {
    ulong ticket = PositionGetTicket(i);
    if(ticket==0) continue;
    if(!PositionSelectByTicket(ticket)) continue;
    string sym = PositionGetString(POSITION_SYMBOL);
    if(sym == _Symbol) count++;
  }
  return(count);
}

Tagesverlustschutz (Risikoschutz)

Um unkontrollierte Verluste zu vermeiden, prüft diese Routine die abgeschlossenen Handelsgeschäfte für den heutigen Tag und summiert den Gewinn/Verlust. Wenn die heutigen Verluste den konfigurierten Prozentsatz des Kontostands überschreiten, weigert sich der EA, weitere Geschäfte zu eröffnen. Es ist eine einfache, aber effektive Notbremse.

bool IsDailyLossExceeded()
{
  // compute today's closed profit/loss for the account in account currency
  double closedPL = 0.0;
  datetime dayStart = iTime(_Symbol, PERIOD_D1, 0); // start of current day on chart's server timezone
  ulong from = (ulong)dayStart;

  int deals = HistoryDealsTotal();
  for(int i=deals-1;i>=0;i--)
  {
    ulong ticket = HistoryDealGetTicket(i);
    if(ticket==0) continue;
    datetime t = (datetime)HistoryDealGetInteger(ticket, DEAL_TIME);
    if(t < dayStart) continue;
    double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT) + HistoryDealGetDouble(ticket, DEAL_COMMISSION) + HistoryDealGetDouble(ticket, DEAL_SWAP);
    closedPL += profit;
  }

  // If closedPL is negative and its absolute exceeds percent of balance, return true
  double threshold = AccountInfoDouble(ACCOUNT_BALANCE) * (InpMaxDailyLossPct/100.0);
  if(closedPL < -threshold) return(true);
  return(false);
}

Normalisierung der Losgröße (Maklerregeln)

Verschiedene Broker beschränken Mindest-, Höchst- und Schrittgrößen für das Volumen. Dieses Hilfsmittel wandelt eine rohe Losnummer in ein gültiges Los um, das den Symboleinstellungen entspricht, und gibt Null zurück, wenn das berechnete Volumen unter dem Mindestwert des Brokers liegt. Die Normalisierung verhindert die Ablehnung von Aufträgen aufgrund von ungültigen Volumina.

double NormalizeLotToStep(double lots)
{
  double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
  double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
  double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
  if(lotStep <= 0) lotStep = 0.01; // fallback
  if(minLot <= 0) minLot = 0.01;

  // floor to step
  double steps = MathFloor(lots / lotStep);
  double result = steps * lotStep;
  if(result < minLot) result = 0.0;
  if(result > maxLot) result = maxLot;

  // round to reasonable decimals (broker may require 2-3 decimals)
  int digits = 2;
  // attempt to infer decimals from lotStep
  if(lotStep < 0.01) digits = MathMax(0, (int)MathCeil(-MathLog10(lotStep)));
  result = NormalizeDouble(result, digits);
  return(result);
}

Volumenberechnung aus ATR (Risk Sizing)

Diese Routine zeigt die praktische Umwandlung von einer Volatilitätsdistanz in ein Handelsvolumen. Es berechnet zunächst den monetären Verlust pro Lot für die vorgeschlagene Stop-Distanz und teilt dann den zulässigen Risikobetrag durch diesen Verlust, um Lots zu erhalten. Für Symbole ohne Tick-Value-Metadaten gibt es einen sicheren Rückhalt.

double CalculateVolume(double stop_distance_price)
{
  if(stop_distance_price <= 0) return(0.0);

  double risk_amount = AccountInfoDouble(ACCOUNT_BALANCE) * (InpRiskPercent/100.0);

  double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
  double tick_size  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);

  if(tick_value <= 0 || tick_size <= 0)
  {
    // fallback approximate using point and lot value: (this may be inaccurate for some symbols)
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double contract_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
    if(point<=0 || contract_size<=0) return(0.0);
    double value_per_price = contract_size; // rough
    double loss_per_lot = stop_distance_price * value_per_price;
    if(loss_per_lot <= 0) return(0.0);
    double lots = risk_amount / loss_per_lot;
    return NormalizeLotToStep(lots);
  }

  double value_per_price = tick_value / tick_size; // money per price unit for 1 lot
  double loss_per_lot = stop_distance_price * value_per_price;
  if(loss_per_lot <= 0) return(0.0);

  double lots = risk_amount / loss_per_lot;
  double normalized = NormalizeLotToStep(lots);
  return(normalized);
}

Visuelle Kennzeichnung der Einträge

Zur Verdeutlichung während der Prüfung zeichnet diese Hilfe einen Pfeil und eine kurze Beschriftung zum Zeitpunkt der Eingabe. Visuelle Hinweise sind von unschätzbarem Wert, wenn es darum geht, numerische Protokolle mit Chart-Ereignissen abzugleichen, und helfen den Schülern, die Entscheidungen des EA auf einen Blick zu überprüfen.

void DrawEntryLabel(bool isLong, datetime when, double price, string tag)
{
  if(!InpShowTradeLabels) return;
  string objName = tag + "_" + IntegerToString((int)when);
  int arrow = isLong ? 233 : 234; // Wingdings arrows
  // create arrow
  if(!ObjectCreate(0, objName, OBJ_ARROW, 0, when, price))
  {
    // try to remove old and recreate
    ObjectDelete(0, objName);
    ObjectCreate(0, objName, OBJ_ARROW, 0, when, price);
  }
  ObjectSetInteger(0, objName, OBJPROP_COLOR, isLong ? clrBlue : clrRed);
  ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
  ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, arrow);
  ObjectSetString(0, objName, OBJPROP_TEXT, tag);
}

Ordereingabeversuche (lang und kurz)

Diese beiden Verfahren kapseln den vollständigen Ablauf von Vorprüfung → Dimensionierung → Ausführung für jede Richtung. Sie führen Sicherheitsprüfungen durch, berechnen Stopp und Ziel, ermitteln ein normalisiertes Volumen und erteilen dann einen Auftrag. Bei Misserfolg protokollieren sie den Grund, bei Erfolg halten sie die Zeit fest und markieren optional die Karte.

void TryOpenLong(double atr_val)
{
  // safety checks
  if(CountOpenPositionsForSymbol() >= InpMaxPosPerSym) return;
  if(IsDailyLossExceeded()) return;

  double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
  double stop_distance_price = atr_val * InpATRstopMult;
  if(stop_distance_price<=0) return;

  double sl = price - stop_distance_price;
  double tp = price + stop_distance_price * InpTakeProfitRR;

  double vol = CalculateVolume(stop_distance_price);
  if(vol <= 0) return;

  // attempt to place market buy
  bool ok = trade.Buy(vol, NULL, 0.0, sl, tp, "CiMA_Long_");
  if(!ok)
  {
    PrintFormat("[TryOpenLong] Buy failed. retcode=%d comment=%s", trade.ResultRetcode(), trade.ResultComment());
    return;
  }

  // success
  PrintFormat("[TryOpenLong] Bought %.2f lots at %.5f SL=%.5f TP=%.5f", vol, price, sl, tp);
  g_lastTradeTime = TimeCurrent();
  DrawEntryLabel(true, TimeCurrent(), price, "CiMA_LONG");
}

void TryOpenShort(double atr_val)
{
  // safety checks
  if(CountOpenPositionsForSymbol() >= InpMaxPosPerSym) return;
  if(IsDailyLossExceeded()) return;

  double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
  double stop_distance_price = atr_val * InpATRstopMult;
  if(stop_distance_price<=0) return;

  double sl = price + stop_distance_price;
  double tp = price - stop_distance_price * InpTakeProfitRR;

  double vol = CalculateVolume(stop_distance_price);
  if(vol <= 0) return;

  bool ok = trade.Sell(vol, NULL, 0.0, sl, tp, "CiMA_Short_");
  if(!ok)
  {
    PrintFormat("[TryOpenShort] Sell failed. retcode=%d comment=%s", trade.ResultRetcode(), trade.ResultComment());
    return;
  }

  PrintFormat("[TryOpenShort] Sold %.2f lots at %.5f SL=%.5f TP=%.5f", vol, price, sl, tp);
  g_lastTradeTime = TimeCurrent();
  DrawEntryLabel(false, TimeCurrent(), price, "CiMA_SHORT");
}

Entscheidungspipeline pro Tick

Bei jedem Markttick aktualisiert der EA seine Indikatoren, liest die neuesten Werte, prüft grundlegende Volatilitätsfilter und wendet dann die Rücksetzer-Einstiegsregel an. Diese zentrale Schleife verbindet alle Helfer miteinander: Sie ist das Herzstück der Strategie und der Punkt, an dem sich Indikatoren, Dimensionierung und Ausführung treffen.

void OnTick()
{
  // refresh indicators (cheap relative to trading operations)
  // Refresh indicators (the Refresh method returns void in the Standard Library; use flag -1 to update recent data)
  fastMA.Refresh(-1);
  slowMA.Refresh(-1);
  atr.Refresh(-1);
  // Note: Refresh does not return a status — check indicator values for EMPTY_VALUE below and skip until ready
  

  double fast = fastMA.Main(0);
  double slow = slowMA.Main(0);
  double atr_val = atr.Main(0); // price units

  if(fast==EMPTY_VALUE || slow==EMPTY_VALUE || atr_val==EMPTY_VALUE) return;

  double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
  bool uptrend = (fast > slow);
  bool downtrend = (fast < slow);

  // normalized volatility check
  double norm_vol = atr_val / price;
  if(norm_vol > InpMaxChopPct || norm_vol < InpMinVolPct)
  {
    // skip trading in these conditions
    return;
  }

  // Pullback distance between price and fast MA
  double dist = MathAbs(price - fast);

  // Only consider entries on bar close for non-repainting behaviour
  // ensure we use the current completed bar (shift=1) for MA reference if you prefer
  // for simplicity here we use Main(0) but teachers may show Main(1) alternative

  if(uptrend && dist <= InpPullbackFactor * atr_val)
  {
    TryOpenLong(atr_val);
  }
  else if(downtrend && dist <= InpPullbackFactor * atr_val)
  {
    TryOpenShort(atr_val);
  }
}

Kleines Dienstprogramm für lesbare Protokolle

Ein kleines Hilfsmittel wandelt das Zeitrahmen-Enum in eine kurze Textbezeichnung um. Sie verbessert die protokollierten Meldungen und macht die Fehlersuche bei der Ausführung mehrerer Zeitrahmen übersichtlicher.

string EnumToString(const ENUM_TIMEFRAMES tf)
{
  switch(tf)
  {
    case PERIOD_M1: return("M1");
    case PERIOD_M5: return("M5");
    case PERIOD_M15: return("M15");
    case PERIOD_H1: return("H1");
    case PERIOD_D1: return("D1");
    default: return(IntegerToString((int)tf));
  }
}


Tests und Ergebnisse

Der CiMA-Trend-Trader EA kann, nachdem er kompiliert wurde, im Strategy Tester ausgewertet werden. In dieser Phase ging es mir nicht um die unmittelbare Rentabilität, sondern vielmehr darum, zu bestätigen, dass der EA korrekt funktioniert und sein primäres Designziel – die Trendfolge – einhält. Bei meinen Testläufen habe ich festgestellt, dass der EA auf höheren Zeitrahmen wie H4 und höher, wo die Markttrends klarer sind und von den Handelssystemen stärker beachtet werden, konsistenter funktioniert.

Andererseits neigen niedrigere Zeitrahmen zu abgehackten und erratischen Strukturen, die Rauschen verursachen und die Ergebnisse eines trendfolgenden Ansatzes wie dem unseren negativ beeinflussen können. Die folgenden Bilder illustrieren meine Erfahrungen mit dem Strategy Tester und zeigen, wie der EA unter verschiedenen Marktbedingungen reagiert.

Erster Test auf einem 30-Minuten-Zeitrahmen-Chart

metatester64_mZwsgVXny3.gif

Abbildung 2. Strategy Tester Visualisierung von GBPUSD, M30 Zeitrahmen mit CiMA_Trend_Trader EA von Juni 2024

terminal64_co9AY2VC6g.png

Abbildung 3. Stetiger Kapitalrückgang während des ersten Tests im M30-Zeitrahmen

terminal64_lZ68zax1Hi.png

Abbildung 4. GBPUSD, M30, Backtest-Ergebnisse

Der erste M30-Test für GBPUSD war aus Sicht der Rentabilität enttäuschend. Während einer einjährigen Simulation produzierte der EA eine stetige Reihe von Verlustgeschäften, und die Kapitalkurve sank um etwa 50 %. Die visuelle Inspektion im Strategietester zeigte die Ursache: Die M30-Marktstruktur auf GBPUSD enthält viele kurze Fehlbewegungen und abgehackte Konsolidierungsphasen, in denen das System immer wieder in „falsche“ Trends einstieg und ausgestoppt wurde.

Anstatt weiterhin aggressiv um diese verrauschten Signale herum zu tunen, änderte ich den Zeitrahmen des Strategietesters auf eine höhere Auflösung – H4 – und wiederholte den Test. Die H4-Ergebnisse im nächsten Abschnitt zeigen ein deutlich verbessertes Verhalten; die Trends sind klarer, die Signale treten seltener auf, und die einzelnen Trades berücksichtigen die größere Marktstruktur besser.

Test auf einem 4-Stunden-Zeitrahmen-Chart

terminal64_706hvT4Eyn.png

Abbildung 5. Leichter Anstieg der Aktien während eines Tests im H4-Zeitrahmen

terminal64_zrDt2ZmaZM.png

Abbildung 6. GBPUSD, H4, Backtest-Ergebnisse

Höhere Zeiträume zeigten eine stärkere und konsistentere Beachtung von Trends, was durch die oben dargestellten Ergebnisse bestätigt wird. Dies deutet darauf hin, dass unser Trendfolgesystem verlässlichere Ergebnisse erzielen kann, wenn es Signale aus Daten mit höherem Zeitrahmen filtert. Meine Entscheidung, auf H4 umzusteigen, war ein zusätzlicher Schritt, um die Leistung des Systems zu verbessern, und hat die potenziellen Vorteile deutlich gemacht. Es gibt jedoch noch viele Parameter innerhalb des EA, die fein abgestimmt werden können, um die Ergebnisse weiter zu verbessern.

Der Handel auf höheren Zeitskalen bringt jedoch seine eigenen Nachteile mit sich. Der Händler muss sich in Geduld üben, da die Signale seltener auftreten und es Tage oder sogar Wochen dauern kann, bis sich die Positionen entwickeln. Dieser Ansatz eignet sich daher am besten für disziplinierte Händler mit einer langfristigen Perspektive und weniger für Scalper oder diejenigen, die schnelle, häufige Gewinne anstreben. Für diese Handelsstrategie ist ein größeres Kapital erforderlich, da es höhere Losgrößen pro Handel ermöglicht. Dies wiederum erhöht die Gesamtgewinne, die sich auf lange Sicht ansammeln können.

Unten sehen Sie ein Bild (Abbildung 7) des H4-Charts, das sowohl die Pfeile der Handelsgeschichte als auch die Signalpfeile anzeigt. Die Trends sind klar erkennbar, wobei die von der CiMA-Klasse generierten gleitenden Durchschnitte eine reibungslose Darstellung der Marktrichtung ermöglichen. Diese Klarheit ist größtenteils auf die Wahl eines höheren Zeitrahmens zurückzuführen, der natürlich einen Großteil des Rauschens herausfiltert, das auf niedrigeren Zeitrahmen zu sehen ist.

metatester64_Zz8Xtlaubg.png

Abbildung 7. GBPUSD, H4-Trend Visualisierung in Strategy Tester


Schlussfolgerung

Es ist durchaus praktikabel, einen funktionalen Expert Advisor mit wenigen Fehlern zu erstellen, indem man die MQL5-Standardbibliothek nutzt. Mithilfe von CTrade, CiMA und CiATR haben wir unser Trendfolgekonzept mit kompaktem, lesbarem Code zum Leben erweckt, der die Reibungsverluste bei der Entwicklung minimiert und häufige Fehler, wie z. B. die falsche Verwaltung von Aufträgen oder die redundante Erstellung von Handles, reduziert. Da wir uns auf getestete Bibliotheksklassen stützen, konnten wir uns mehr auf die Strategielogik als auf die Details der Implementierung auf niedriger Ebene konzentrieren.

Im Strategy Tester lief der EA reibungslos und ermöglichte uns eine schnelle Iteration über mehrere Zeitrahmen hinweg. Die Ergebnisse spiegeln ein bekanntes Muster wider: Höhere Zeitrahmen wie H4 ergaben klarere, stärkere Trendeinbrüche, während kleinere Intervalle wie M30 unter falschen Ausbrüchen und verrauschten Konsolidierungen litten. Dies verdeutlicht einen wichtigen Gestaltungsgrundsatz: Trendfolgesysteme profitieren von Geduld und längeren Zeithorizonten, während kurzfristige Ansätze zusätzliche Filter und Sicherheitsvorkehrungen erfordern, um rentabel zu bleiben.

Die vielleicht wertvollste Lektion war der Prozess selbst, der Übergang vom Konzept zum Code zu den yErgebnissen. Wir begannen mit einer Handelsidee, drückten sie durch modulare Standardbibliotheksklassen aus und validierten ihr Verhalten mit der Visualisierung von Strategietestern und Backtest-Ergebnissen. Dieser systematische Arbeitsablauf führte zu einem funktionierenden EA und stärkte bewährte Programmierpraktiken wie die Trennung von Anliegen, die Verwendung visueller Diagnosen und das Testen über verschiedene Regime hinweg. Diese Praktiken bilden das Rückgrat der professionellen MQL5-Entwicklung.

Um die wichtigsten Erkenntnisse festzuhalten, haben wir eine Tabelle mit Lektionen erstellt, in der die Programmierungsprinzipien, Strategieüberlegungen und Testtechniken zusammengefasst sind, die sich aus diesem Projekt ergeben haben. Jede Lektion steht in direktem Zusammenhang mit realen Implementierungsherausforderungen und -lösungen, was das Buch zu einem praktischen Nachschlagewerk für Leser macht, die ihre eigene EA-Entwicklungsreise verfolgen.

Die Tabelle der Anhänge finden Sie unten in der Quelldatei des Projekts. Der EA CiMA_Trend_Trader.mq5 dient sowohl als praktische Demonstration als auch als wiederverwendbarer Ausgangspunkt für Leser, die weiter experimentieren möchten. Sie können den Code testen, modifizieren und erweitern – vielleicht durch die Integration anderer Standard-Bibliotheksklassen wie CiCCI, CiMACD oder Volatilitätsfilter – um neue Ansätze zu erforschen und Ihre eigenen Handelssysteme zu verfeinern.

Ihr Feedback und Ihre Erkenntnisse sind willkommen. Wir laden Sie ein, uns Ihre Erfahrungen mitzuteilen, Verbesserungsvorschläge zu machen und neue Wege zu beschreiten. Bleiben Sie dran für unsere nächste Veröffentlichung!


Wichtigste Erkenntnisse

Wichtigste Lektion Beschreibung:
Konzept → Code Übersetzen Sie Regeln in einen klaren Schritt-für-Schritt-Algorithmus und Pseudocode, bevor Sie sie implementieren; dadurch wird das Verhalten reproduzierbar und leichter zu testen.
OOP-Struktur Verwenden Sie kleine, fokussierte Klassen oder Module (Indikatoren, Größenbestimmung, Ausführung), damit jeder Teil eine einzige Verantwortung hat und wiederverwendet oder ausgetauscht werden kann.
Lebenszyklus-Management Erstellen Sie Indikatorinstanzen einmal, aktualisieren Sie sie pro Tick und geben Sie sie bei der Deinitialisierung frei, um Ressourcenlecks und Testinstabilität zu vermeiden.
Umrechnung von Einheiten Geben Sie die Einheiten genau an: Konvertieren Sie ATR (Preiseinheiten) in Punkte und monetäre Verluste unter Verwendung der Tick-Größe/des Tick-Wertes, um korrekte Stopps und Größen zu gewährleisten.
Größe der Position Machen Sie die Größenbestimmung zu einer reinen Berechnung: Risikobetrag ÷ Verlust pro Los, dann normalisieren Sie auf die Regeln des Maklervolumens für wiederholbares Engagement.
Ausführung und Fehlerbehandlung Zentralisieren Sie die Einreichung von Geschäften, überprüfen Sie stets die Ergebniscodes/Nachrichten und führen Sie klare Wiederholungs- oder Ausfallsicherungsrichtlinien für häufige Fehler ein.
Staatliche Kontrolle Behalten Sie den expliziten Status bei (Anzahl der offenen Positionen, Zeitpunkt des letzten Handels, Aktivierungskennzeichen) und aktualisieren Sie ihn zentral, um Race Conditions und Logikdrift zu vermeiden.
Defensive Kodierung Antizipieren Sie fehlende Daten, Null-Tick-Werte und kurze Historien; scheitern Sie mit Protokollen und Fallback-Verhalten, anstatt abzustürzen.
Modularität Trennen Sie Belange (Signale, Dimensionierung, Sicherheit, Zeichnung, Ausführung) in Funktionen oder Dateien, um die Prüfung und Wartung zu vereinfachen.
Protokollierung und Visualisierung Protokollieren Sie Werte auf Entscheidungsebene und verwenden Sie Chart-Overlays (MAs, ATR-Bänder, Einstiegsmarkierungen), um numerische Logik mit visuellem Verhalten zu korrelieren.
Hochwertige Tests Führen Sie 99%ige Backtests im Tick-Mode mit realistischen Spreads/Swaps durch; schlechte Daten führen zu irreführenden Schlussfolgerungen.
Disziplin der Optimierung Optimieren Sie konservativ, verwenden Sie Out-of-Sample- oder Walk-forward-Validierung und konzentrieren Sie sich auf stabile Parameterregionen und nicht auf Spitzengewinne im Backtest.
Leistungsbewusstsein Minimierung der Zuweisungen pro Tick, Wiederverwendung von Handles und Messung von CPU/Speicher bei der Skalierung auf viele Symbole oder Zeitrahmen.
Laufzeit-Schutzmaßnahmen Operative Sicherheitsvorkehrungen: maximaler Tagesverlust, maximale Positionen, Notstopp und Gesundheitsprüfungen zur Begrenzung des Live-Risikos.
Arbeitsablauf eines Experiments Verfolgen Sie Experimente (Codeversionen, .set-Dateien, Metriken), führen Sie A/B-Vergleiche durch und arbeiten Sie an kleinen, messbaren Änderungen.


Anlagen

Dateiname Beschreibung
CiMA_Trend_Trader.mq5 Eigenständiger trendfolgender Expert Advisor, der die praktische Verwendung von drei Standardbibliothek-Klassen demonstriert: CiMA (sich schnell und langsam bewegende Durchschnitte zur Richtungsbestimmung), CiATR (ATR-basierte Volatilität für dynamische Stopps und Positionsgrößen) und CTrade (Auftragsausführung). Verfügt über abstimmbare Eingaben (MA-Perioden, ATR-Periode & Multiplikatoren, Risiko %, TP/SL RR, Volatilitätsfilter, maximaler Tagesverlust, maximale Positionen), brokerabhängige Lot-Normalisierung, Sicherheitsprüfungen, einfache visuelle Einstiegsmarkierungen und eine klare Protokollierung für die Validierung durch den Strategy Tester.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/19341

Beigefügte Dateien |
Entwicklung von Handelsstrategien mit den Oszillatoren Parafrac und Parafrac V2: Einzeleintritt Performance Insights Entwicklung von Handelsstrategien mit den Oszillatoren Parafrac und Parafrac V2: Einzeleintritt Performance Insights
In diesem Artikel werden der ParaFrac Oscillator und sein V2-Modell als Handelsinstrumente vorgestellt. Es werden drei Handelsstrategien vorgestellt, die mit Hilfe dieser Indikatoren entwickelt wurden. Jede Strategie wurde getestet und optimiert, um ihre Stärken und Schwächen zu ermitteln. Die vergleichende Analyse zeigte die Leistungsunterschiede zwischen dem Original und dem V2-Modell auf.
Entwicklung eines volatilitätsbasierten Ausbruchssystems Entwicklung eines volatilitätsbasierten Ausbruchssystems
Das auf der Volatilität basierende Breakout-System identifiziert Marktbereiche und handelt dann, wenn der Preis über oder unter diese Niveaus bricht, gefiltert durch Volatilitätsmaße wie ATR. Dieser Ansatz hilft, starke Richtungsbewegungen zu erfassen.
Entwicklung eines nutzerdefinierten Indikators für die Kontoperformance-Matrix Entwicklung eines nutzerdefinierten Indikators für die Kontoperformance-Matrix
Dieser Indikator fungiert als Disziplinierungsinstrument, indem er Kontokapital, Gewinn/Verlust und Drawdown in Echtzeit verfolgt und ein Performance-Dashboard anzeigt. Es kann den Händlern helfen, konsistent zu bleiben, übermäßiges Handeln zu vermeiden und die Regeln für die Anfechtung von Prop-Firmen einzuhalten.
Der Parafrac V2 Oszillator: Integration von Parabolic SAR mit Average True Range Der Parafrac V2 Oszillator: Integration von Parabolic SAR mit Average True Range
Der Parafrac V2 Oszillator ist ein fortschrittliches technisches Analysewerkzeug, das den Parabolic SAR mit der Average True Range (ATR) integriert, um die Einschränkungen seines Vorgängers zu überwinden, der auf Fraktalen beruhte und anfällig für Signalspitzen war, die vorherige und aktuelle Signale überschatteten. Durch die Nutzung des ATR-Volatilitätsmaßes bietet die Version 2 eine sanftere, zuverlässigere Methode zur Erkennung von Trends, Umkehrungen und Divergenzen und hilft Händlern, Überlastung des Charts und Analyselähmungen zu vermeiden.