English Русский 中文 Español 日本語 Português Türkçe
Grid und Martingale: was sind sie und wie verwendet man sie?

Grid und Martingale: was sind sie und wie verwendet man sie?

MetaTrader 5Handelssysteme | 22 Dezember 2020, 07:32
2 332 0
Evgeniy Ilin
Evgeniy Ilin

Einführung

In diesem Artikel werde ich mich mithilfe von Mathematik und Programmierung mit diesen Strategien beschäftigen und ihre Rentabilität bewerten. Der Artikel enthält mathematische und praktische Teile. Im mathematischen Teil werde ich Gleichungen zur Berechnung des erwarteten Gewinns (expected payoff) der Strategien und anderer wichtiger Parameter bereitstellen, die von vielen Händlern nicht berücksichtigt werden. Im praktischen Teil werde ich ein einfaches Raster und Martingale entwickeln und die Gleichungen mit der Realität vergleichen. Der Artikel ist besonders für Anfänger nützlich, da diese Strategien in der Regel die ersten sind, auf die sie stoßen. Blindes Vertrauen in sie kann zu Enttäuschungen und Zeitverschwendung führen, wie es mir seinerzeit passiert ist. Hätte ich keine Ahnung von Mathe gehabt, hätte ich vielleicht trotzdem an sie geglaubt. Aber diese Strategien haben immer noch einen Grund, wenn man sie richtig betrachtet. Das werde ich nun beweisen.


Was haben diese beiden Strategien gemeinsam?

Um die Popularität dieser beiden Strategien zu verstehen, sollten wir einen Blick darauf werfen, was alle angehenden Forex Händler wollen. Die meisten angehenden Händler sind Mathematiker und Träumer, die denken, dass ihr Intellekt ihnen helfen kann, schnell und einfach reich zu werden. Auch ich war einmal ein solcher Träumer. Beide Strategien erwecken den Anschein von profitablem Handel in Form von Graphen, die im Strategietester ständig nach oben gehen. Auf vielen Segmenten der Kurshistorie kann der Tester sogar ohne jegliche Filter gralsähnliche Ergebnisse anzeigen. In jedem Tätigkeitsbereich und in jedem Geschäft besteht die Gefahr, dass sich besser informierte Personen auf Ihre Kosten bereichern können. Der Forex-Handel ist da keine Ausnahme. Im Forex gibt es viele solcher betrügerischen Praktiken, und diese beiden Strategien sind der anschaulichste und beliebteste Beweis dafür. Wenn Sie diese Strategien zum ersten Mal anwenden, werden Sie sehen, dass sie auf allen Währungspaaren mit unglaublichen Gewinnfaktoren und erwarteten Auszahlungen funktionieren und sogar mit beliebigen Spreads zurechtkommen, sodass es scheint, dass dieser Algorithmus jenseits des Marktes ist. Das liegt daran, dass sie auf reiner Mathematik und keiner Logik beruhen. Selbst nach so vielen Jahren möchte ich immer noch Algorithmen finden, die es mir ermöglichen, unabhängig von der Preisrichtung immer Gewinn zu erzielen. Mathematiker sind generell interessante Menschen. Sie sind in der Lage, mit den richtigen Gleichungen alles zu beweisen, unabhängig davon, ob dies in der Realität auch stimmt. )) Im Allgemeinen nutzen diese beiden Strategien die Illusion des Break-Even aus, um Sie zu überzeugen, sie zu verwenden. Beide funktionieren bei jedem Währungspaar und in jeder Periode, oder schaffen vielmehr die Illusion, dass sie funktionieren, um Sie von ihrer Einfachheit und Effizienz zu überzeugen. Wenn Sie sich in diese Strategien vertiefen, werden Sie früher oder später feststellen, dass Sie nichts wissen. ) Diese Phase ist jedoch notwendig, denn nur so können Sie anfangen, rational zu denken und die wahre Natur des Marktes zu verstehen und welche Strategien Sie wirklich anwenden müssen.


Grid (Raster) und seine Grundgleichungen

Das Auftragsraster wurde mit dem Ziel geschaffen, in jedem Markt Gewinne zu erzielen. Es spielt keine Rolle, ob er fällt oder steigt, wenn der Markt eine deutlich sichtbare Bewegung aufweist, dann, so die Idee, eröffnet das Grid Orders mit einem ausgeklügelten Ordereröffnungssystem, sodass diese Orders in der Summe irgendwann genug Gewinn bringen, um sie alle auf einmal zu schließen. Lassen Sie mich dies in den untenstehenden Bildern zeigen:

Hier habe ich zwei Optionen für steigende bzw. fallende Märkte dargestellt. Gemäß der Grid-Strategie sollten wir gewinnen, egal, welche Option wir bekommen. Diejenigen, die das Grid verwenden, sagen immer, dass man Pending Orders verwenden sollte, da diese zum besten Preis ausgelöst werden. Das ist richtig, aber ich glaube, dass Market Orders nicht schlechter sind, schon allein dadurch, dass man die Spreads und Slippages zum Zeitpunkt des Einstiegs kontrollieren kann. Außerdem können Sie den Einstieg etwas hinausschieben. Allerdings sind Limit-Orders bei dieser Strategie besser. Wir haben einen Startpunkt, relativ zu dem Orders gesetzt werden. Oberhalb dieses Punktes setzen wir Kauforders mit der Schrittweite "s", während wir unterhalb davon Verkaufsorders platzieren. Wenn der Preis sie erreicht, werden sie in Markt-Orders umgewandelt. Das Bild zeigt offene Orders basierend auf der jeweiligen Preissituation an. Es macht keinen Sinn, hier Limit-Orders anzuzeigen, da sie immer auf dem gleichen Niveau bleiben, das nach oben und nach unten geht, und zwar unbegrenzt. Nur offene, echte Orders sind für uns wichtig, da ihr Gewinn bzw. Verlust sich zum Gesamtgewinn bzw. -verlust addiert. Um den Gewinn zu sichern, müssen wir sicherstellen, dass es um den Faktor "K" mehr Orders als andere gibt, d.h. wir sollten K=a/d vorgeben, wobei K>=K0. K0 ist ein bestimmter Koeffizient, bei dessen Erreichen der Gesamtgewinn aller Orders des Grids größer Null ist. Auf die gleiche einfache Art und Weise können wir auch den aktuellen Gewinn einer Position oder von Orders im Falle von MetaTrader 4 berechnen. Andernfalls erhalten wir eine Situation, in der sich der Preis sofort in eine bestimmte Richtung bewegt und wir den Gewinn realisieren, nachdem sich der Preis um "n" Punkte nach oben oder unten bewegt. Streng genommen kann dieses Verhältnis berechnet werden, aber man kann es auch einfach manuell wählen. Die mögliche Berechnung sieht wie folgt aus:

  • Nl=d/s - 1
  • NP=(a+d)/s -1
  • Pr=Sum(1,NP)(s*i)=(s+s*NP)*Np/2
  • Ls=Sum(1,Nl)(s*j+ s*NP)=(s+s*Nl)*Nl/2+s*NP^2

Wenn wir den Verlust oder Gewinn aller Orders zusammenzählen, können wir sehen, dass diese Summen einer arithmetischen Reihe folgen. Es gibt eine Gleichung, die die Summe der arithmetischen Reihe beschreibt (unter Verwendung ihrer ersten und letzten Terme), die hier verwendet wird.

Betrachtet man Pr-Ls=0, so ergibt die Lösung dieser Gleichung "a" und ermöglicht die Berechnung von K0=a/d. Außerdem ermöglicht die Verwendung dieser Gleichungen die Definition des Gewinnfaktors und des erwarteten Gewinns von Handelszyklen, die offene Kauf- und Verkaufspositionen beinhalten sollen.

  • Prf=Pr/Ls 
  • M=(Pr-Ls)/(Np+Nl)

Diese Gleichungen berechnen den Gewinnfaktor und die erwartete Auszahlung eines bestimmten Handelszyklus und nicht den gesamten Graphen. Vorausgesetzt, dass unser Graph am Endpunkt des Zyklus endet, wird der Gewinnfaktor positiv sein. Ein Zyklus ist ein separates Grid. Das Grid wird aufgebaut, maximal ausgenutzt, Positionen werden geschlossen und ein neues Grid wird aufgebaut. Dies wäre ein unendlicher Prozess im Falle des unendlichen Depots. Uns so sieht ungefähr die Saldenkurve aus:


Hier zeige ich eine vereinfachte Darstellung der Saldenkurve eines Grid-Roboters beim Durchlaufen der Historie. Es gibt ein paar Zyklen, die die Einlage überstehen und die Kurve geht weiter nach oben. Aber dies endet unweigerlich mit einem Zyklus, in dem der Kontostand nicht mehr ausreicht und der gesamte sichtbare Gewinn an den Broker geht. Mathematisch gesehen gilt dies als ein unvollendeter Zyklus. Der unvollendete Zyklus ist immer unprofitabel und sein Verlust überschneidet sich mit allen Gewinnen, die während der Zyklen, die bis zum Ende gearbeitet haben, erzielt wurden. Der Zyklus kann auch aufgrund einer unzureichenden Anzahl von Orders, die zur Fortsetzung des Grids notwendig wären, nicht vollendet werden. Alle Broker setzen Grenzen für die Anzahl der gleichzeitig offenen Orders im Terminal oder auf einem bestimmten Paar. Das Grid kann nicht unbegrenzt aufgebaut werden. Selbst wenn wir annehmen, dass wir dazu in der Lage wären, erhalten wir letztendlich das oben genannte Ergebnis. Am Ende des Artikels werde ich kurz erklären, warum dies in Bezug auf die Mathematik geschieht.


Martingale und seine Grundgleichungen

Wie beim Grid ist die Idee hinter dem Martingal, unabhängig von der Marktrichtung zu gewinnen. Sie basiert auf der gleichen Illusion eines ewigen Gewinns. Wenn wir eine Order eröffnen und sie sich als profitabel erweist, handeln wir einfach weiter. Sobald wir einen Verlust erleiden, erhöhen wir die Losgröße der nächsten Order "n" mal relativ zur Verlustposition. Wenn unsere Order profitabel ist, schließen wir sie einfach und setzen die Losgröße wieder auf den Anfangswert zurück. Wenn sich die Order wieder als verlustbringend erweist, wiederholen wir den vorherigen Schritt und erhöhen dabei das Lot "n" mal relativ zur Summe der Losgrößen aller Verlustpositionen innerhalb des Zyklus. Wiederholen Sie dies, bis wir wieder eine profitable Position haben. Die letzte Position im Zyklus ist immer profitabel und ihr Gewinn deckt immer den Verlust der Verlustpositionen. Auf diese Weise entsteht der Graph, der aus Zyklen besteht. Vorausgesetzt, dass der Graph mit dem letzten Zyklus endet, erhalten wir einen positiven Erwartungswert und Gewinnfaktor. Es ist nicht von Bedeutung, wie und wo wir diese Orders eröffnen. Vorzugsweise sollten diese Orders einen festen Gewinn und Verlust haben oder einfach auf festen Stop-Levels schließen. So sieht die Saldenkurve eines Martingale-Roboters aus:


Wie wir sehen können, ist sie der Saldenkurve des Grid sehr ähnlich, da das Martingal in Zyklen arbeitet, genau wie das Grid. Der einzige Unterschied ist, dass es immer eine einzelne Order öffnet und wartet, bis diese geschlossen ist, um die nächste zu öffnen. Genau wie beim Grid wird der Kontostand früher oder später nicht mehr ausreichen, um den Zyklus zu beenden, alle Orders werden geschlossen und das Depot wird ausgelöscht. Um profitable Zyklen zu gewährleisten, muss der Gewinn der letzten Position den Verlust der vorherigen decken:

  • Nl
  • Np=1
  • Pr=L[Nl+Np]*TP[Nl+Np]*TickSize
  • Ls=Sum(1,Nl)(L[i]*SL[i])*TickSize

Hier wird der Gewinn in der Kontowährung und nicht in Punkten berechnet, da das System mit Losgrößen arbeitet. Die Losgrößen einer bestimmten Order werden mittels Rekursion berechnet:

  • L[1]=StartLot
  • for(2,Nl) L[i]=(K*Sum(1,i-1)(L[j]*SL[j]))/TP[i]

wobei "K" der erforderliche Gewinnfaktor des Zyklus ist. Spreads, Kommissionen und Swaps werden hier nicht berücksichtigt, aber ich denke nicht, dass dies entscheidend ist. Bei Bedarf können die Gleichungen leicht modifiziert werden, obwohl ich den Sinn darin nicht sehe. Die Martingal-Gleichungen ähneln den Grid-Gleichungen. SL und TP sind der erzielte Verlust und der gewünschte Gewinn einer Order. Wir können die Definition durch Lösen der folgenden einfachen Gleichung erhalten: K=(L[i]* TP[i])/Sum(1,i-1)(L[j]*SL[j]).


Entwickeln und Testen des einfachsten Grid EA

Um die obigen Annahmen zu testen, lassen Sie uns einfache EAs für Grid und Martingale in der Sprache MQL5 schreiben, um sie zu testen und die Ergebnisse zu sehen. Ich werde mit dem Grid beginnen. Fügen wir zunächst ein paar praktische Klassen für die Arbeit mit Positionen zu unserer Vorlage hinzu:

#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
CPositionInfo  m_position=CPositionInfo();// trade position object
CTrade         m_trade=CTrade();          // trading object

Diese beiden Bibliotheken sind im MetaTrader 5 standardmäßig immer vorhanden, sodass es keine Kompilierungsprobleme geben wird. 

Als Nächstes wollen wir alle notwendigen Eingaben beschreiben:

///grid variables
input int MaxChannelSizePoints=500;//Max Of a+d
input int MinMoveToClose=100;//Mininum Move
input int GridStepPoints=20;//Grid Step In Points
input int BarsI=999;//Bars To Start Calculate
input double KClose=3.5;//Asymmetry
///

////////minimum trading implementation
input int SlippageMaxOpen=15; //Slippage For Open In Points
input double Lot=0.01;//Lot
input int MagicC=679034;//Magic
/////////

Der erste Block implementiert alle notwendigen Grid-Parameter, während der zweite Block die Fähigkeit implementiert, eine feste Losgröße in einfachster Form zu handeln.

Beim Start des EA benötigen wir die Überprüfung und Wiederherstellung der Grid-Parameter aus der vorherigen Sitzung für den Fall, dass der Vorgang fehlerhaft beendet wurde. Diese Funktion ist optional, aber es ist besser, solche Dinge im Voraus zu implementieren:

void DimensionAllMQL5Values()//////////////////////////////
   {
   ArrayResize(Time,BarsI,0);
   ArrayResize(High,BarsI,0);
   ArrayResize(Low,BarsI,0);
   }

void CalcAllMQL5Values()///////////////////////////////////
   {
   ArraySetAsSeries(High,false);                        
   ArraySetAsSeries(Low,false);                              
   ArraySetAsSeries(Time,false);                                                            
   CopyHigh(_Symbol,_Period,0,BarsI,High);
   CopyLow(_Symbol,_Period,0,BarsI,Low);
   CopyTime(_Symbol,_Period,0,BarsI,Time);
   ArraySetAsSeries(High,true);                        
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Time,true);
   }

Dieser Code ist notwendig, um vordefinierte Arrays zu implementieren, damit die anfängliche Analyse abgeschlossen werden kann. Wir werden diese Arrays später nicht mehr benötigen. Wir werden sie nur während der anfänglichen Berechnung verwenden.

Die Wiederherstellung wird auf folgende Weise durchgeführt:

void RestoreGrid()//recover the grid if the robot is restarted
   {
   DimensionAllMQL5Values();
   CalcAllMQL5Values(); 
   bool ord=PositionSelect(Symbol());
   if ( ord && int(PositionGetInteger(POSITION_MAGIC)) == MagicC )
      {
      GridStartTime=datetime(PositionGetInteger(POSITION_TIME));
      GridStartPrice=double(PositionGetDouble(POSITION_PRICE_OPEN));
      GridUpPrice=GridStartPrice;
      GridDownPrice=GridStartPrice;      
      
      for(int i=0;i<BarsI;i++)
         {
         if ( High[i] > GridUpPrice ) GridUpPrice=High[i];
         if ( Low[i] < GridDownPrice ) GridDownPrice=Low[i];
         if ( Time[i] < GridStartTime ) break;         
         }
      bCanUpdate=true;
      bTryedAlready=false;         
      }
   }

Um den aktuellen Grid-Status zu verfolgen, benötigen wir zusätzliche Variablen, die den oberen und unteren Preis des bestehenden Grids anzeigen, sowie den Startpreis des Grids und die Zeit, zu der es gesetzt wurde.

datetime GridStartTime;//grid construction time
double GridStartPrice;//grid starting price
double GridUpPrice;//upper price within the corridor
double GridDownPrice;//lower price within the corridor

Wir benötigen auch zwei boolesche Variablen, um die Grid-Variablen während der Preisbewegung zu verfolgen bzw. zu aktualisieren, sowie für zusätzliche Versuche, das Grid zu schließen, wenn der erste Versuch fehlgeschlagen ist.

bool bCanUpdate;//whether it is possible to update the grid
bool bTryedAlready;//whether there was an attempt to close a position

Das Erstellen und Aktualisieren der Grid-Parameter während der Entwicklung sieht wie folgt aus:

void CreateNewGrid()//create a new grid
   {
   SymbolInfoTick(Symbol(),LastTick);  
   GridStartTime=TimeCurrent();
   GridStartPrice=LastTick.bid;
   GridUpPrice=GridStartPrice;
   GridDownPrice=GridStartPrice;
    
   double SummUp=LastTick.ask+double(GridStepPoints)*_Point;
   double SummDown=LastTick.bid-double(GridStepPoints)*_Point;
   
   while ( SummUp <= LastTick.ask+double(MaxChannelSizePoints)*_Point )
      {
      m_trade.BuyStop(Lot,SummUp,Symbol());
      SummUp+=double(GridStepPoints)*_Point;
      }
     
   while ( SummDown >= LastTick.bid-double(MaxChannelSizePoints)*_Point )
      {
      m_trade.SellStop(Lot,SummDown,Symbol());
      SummDown-=double(GridStepPoints)*_Point;
      }
   }

void UpdateGrid()//update the grid parameters
   {
   SymbolInfoTick(Symbol(),LastTick);
   if ( LastTick.bid > GridUpPrice ) GridUpPrice=LastTick.bid;
   if ( LastTick.bid < GridDownPrice ) GridDownPrice=LastTick.bid;
   }

Die Funktionen zum Schließen von Positionen und Löschen der verbleibenden Limit-Orders sowie die Prädikatsfunktion, die die Bedingung für das Schließen des Grids erkennt:

void ClosePosition()//close a position by a symbol
   {
   bool ord;
   ord=PositionSelect(Symbol());
   if ( ord && int(PositionGetInteger(POSITION_MAGIC)) == MagicC  )
      {
      if(m_position.SelectByIndex(0)) m_trade.PositionClose(m_position.Ticket());          
      }
   }

void CleanLimitOrders()//clear limit orders
   {
   int orders=OrdersTotal();
   for(int i=0;i<orders;i++)
      {
      ulong ticket=OrderGetTicket(i);
      if(ticket!=0)
         {
         m_trade.OrderDelete(ticket);
         }
      }
   }

bool bCanClose()//closure condition
   {
   if ( GridStartPrice == GridUpPrice && (GridStartPrice-GridDownPrice)/_Point >= MinMoveToClose ) return true;
   if ( GridStartPrice == GridDownPrice && (GridUpPrice-GridStartPrice)/_Point >= MinMoveToClose ) return true;
   
   if ( GridStartPrice != GridUpPrice && GridStartPrice != GridDownPrice 
   && (GridStartPrice-GridDownPrice)/(GridUpPrice-GridStartPrice) >= KClose 
   && (GridStartPrice-GridDownPrice)/_Point >= MinMoveToClose ) return true;
   if ( GridStartPrice != GridDownPrice && GridStartPrice != GridUpPrice 
   && (GridUpPrice-GridStartPrice)/(GridStartPrice-GridDownPrice) >= KClose
   && (GridUpPrice-GridStartPrice)/_Point >= MinMoveToClose ) return true;
   
   /*
   if ( GridUpPrice >= GridStartPrice+MaxChannelSizePoints*_Point 
   //|| GridDownPrice <= GridStartPrice-MaxChannelSizePoints*_Point ) return true;
   */
   return false;
   }

Ich habe die letzte Bedingung in der Prädikatsfunktion auskommentiert. Sie schließt das Grid, falls sich der Preis außerhalb des Grids bewegt. Sie können sie nach Belieben verwenden, sie ändert sonst nichts. Jetzt müssen wir nur noch die Haupthandelsfunktion schreiben:

void Trade()//the main function where all actions are performed
   {
   bool ord=PositionSelect(Symbol());
   
   if ( bCanUpdate ) UpdateGrid();
   
   if ( ord && bCanClose() )//if there is a position and the closing condition is met
       {
       ClosePosition();
       CleanLimitOrders();
       bCanUpdate=false;
       bTryedAlready=true;
       }
   if ( bTryedAlready ) ClosePosition();
          
   if ( !bCanUpdate && !ord )
       {
       CleanLimitOrders();
       CreateNewGrid();
       bCanUpdate=true;
       bTryedAlready=false;
       }
   }

 Außerdem legen wir fest, wo und was bei der Initialisierung des EA aufgerufen werden soll und was zu tun ist:

int OnInit()
  {
  m_trade.SetExpertMagicNumber(MagicC);//set the magic number for positions
  RestoreGrid();//restore the grid if present
   return(INIT_SUCCEEDED);
  }

void OnTick()
  {
  Trade();
  }

Wir haben den Grid EA entwickelt. Jetzt wollen wir ihn testen und sehen, wie er sich verhält:


Wie Sie sehen können, haben sich die Annahmen über den unvorteilhaften Zyklus bestätigt. Am Anfang funktioniert das Grid ziemlich gut, aber dann kommt ein Moment, in dem das Grid unzureichend ist, was zu einem Verlustzyklus führt, der den gesamten Gewinn vernichtet. Trendige Marktsegmente zeigen in der Regel gute Ergebnisse, während Verluste meist in flachen Segmenten auftreten. Das Gesamtergebnis ist immer ein Verlust, da wir immer noch einen Spread haben.


Entwickeln und Testen des einfachsten Martingale EA

Nachdem wir uns nun mit dem Grid beschäftigt haben, wollen wir uns dem Martingale EA zuwenden. Sein Code wird viel einfacher sein. Um mit Positionen zu arbeiten, werden wir die im Grid EA verwendeten Bibliotheken verwenden. Es macht keinen Sinn, den Code ein zweites Mal zu zeigen. Wenden wir uns gleich den Eingaben zu:

input int SLE=100;//Stop Loss Points
input int TPE=300;//Take Profit Points
input int SlippageMaxOpen=15; //Slippage For Open In Points
input double Lot=0.01;//Start Lot
input int MagicC=679034;//Magic
input int HistoryDaysLoadI=10;//History Deals Window Days

Der Einfachheit halber habe ich das System gewählt, in dem Positionen konsequent durch Stop Loss oder Take Profit geschlossen werden. Die letzte Variable erlaubt uns, nicht ständig die gesamte Orderhistorie zu laden, sondern nur das notwendige Fenster (rein zur Optimierung). Ich glaube, die anderen Variablen sind selbsterklärend.

Der EA benötigt nur zwei Funktionen:

double CalcLot()//calculate the lot
   {
   bool ord;
   double TotalLot=0;
   HistorySelect(TimeCurrent()-HistoryDaysLoadI*86400,TimeCurrent());
   for ( int i=HistoryDealsTotal()-1; i>=0; i-- )
      {
      ulong ticket=HistoryDealGetTicket(i);
      ord=HistoryDealSelect(ticket);
      if ( ord && HistoryDealGetString(ticket,DEAL_SYMBOL) == _Symbol 
      && HistoryDealGetInteger(ticket,DEAL_MAGIC) == MagicC 
      && HistoryDealGetInteger(ticket,DEAL_ENTRY) == DEAL_ENTRY_OUT )
         {
         if ( HistoryDealGetDouble(ticket,DEAL_PROFIT) < 0 )
            {
            TotalLot+=HistoryDealGetDouble(ticket,DEAL_VOLUME);
            }
         else
            {
            break;
            }
         }
      } 
   return TotalLot == 0 ? Lot: TotalLot;
   }


void Trade()//the main function where all actions are performed
   {
   bool ord=PositionSelect(Symbol());
   SymbolInfoTick(Symbol(),LastTick);
   if ( !ord )
      {
      if ( MathRand() > 32767.0/2.0 )
         {
         m_trade.Buy(CalcLot(),_Symbol,LastTick.ask,LastTick.bid-double(SLE)*_Point,LastTick.ask+double(TPE)*_Point);
         }
      else
         {
         m_trade.Sell(CalcLot(),_Symbol,LastTick.ask,LastTick.ask+double(SLE)*_Point,LastTick.bid-double(TPE)*_Point);
         }
      }
   }

Die erste wird benötigt, um die endgültige Losgröße zu berechnen, die zur Eröffnung einer Position verwendet wird, nachdem man sich die Historie der Positionen angesehen hat. Wenn die letzte Position unprofitabel ist, entspricht die nächste Losgröße der Summe der Losgrößen der vorherigen Verlustpositionen bis zur ersten profitablen Position. Wenn die letzte Position profitabel ist, wird die Losgröße auf ihren Anfangswert zurückgesetzt. In der Hauptfunktion öffnen wir Orders in verschiedenen Richtungen mit festen Stop-Levels nach dem Zufallsprinzip, während die Volumina mit der ersten Funktion berechnet werden. Damit all dies korrekt funktioniert, müssen wir dem EA bei der Initialisierung eine Magicnummer zuweisen, während die Hauptfunktion in OnTick aufgerufen wird, genau wie im Grid.

Damit ist die Entwicklung des einfachsten Martingals abgeschlossen. Testen wir ihn nun und sehen uns das Ergebnis an:


Der Fall ist ähnlich wie beim Grid. Wir können die Zyklen sehen. Der Martingal-EA arbeitet kurz bevor der Verlustzyklus einsetzt. Die Marge wird unzureichend, um die nächste Position zu öffnen und der Verlust tritt ein. Genau wie das Grid, irgendwo funktioniert es, irgendwo nicht, aber es endet immer mit einem Verlust. Nachdem wir nun beide Strategien besprochen haben, ist es an der Zeit, mathematische Schlussfolgerungen zu ziehen, die uns zu wichtigeren Antworten führen, als nur diese beiden Strategien zu verstehen.


Gemeinsame Mathematik hinter Grid und Martingale

Warum glaube ich, dass die gemeinsame Mathematik hinter Grid und Martingale so wichtig ist? Wenn wir sie gründlich verstehen, können wir uns endlich von einer ganzen Reihe von Ideen verabschieden, die uns niemals Gewinn bringen werden, auch wenn wir vielleicht an sie glauben wollen. Zumindest werden wir verstehen, welche Bedingungen zur Performance dieser Strategien beitragen können. Außerdem werden wir erkennen, warum reine Martingale und Grids Verluststrategien sind.

Stellen wir uns vor, dass jede Strategie aus einer unendlichen Anzahl der einfachsten Strategien besteht. Wenn eine Order eröffnet wird, wird eine von ihnen aktiviert. Wir werden annehmen, dass diese Orders mit einem festen Verlust oder Gewinn geschlossen werden. Setzen wir sie in Korrespondenz mit den Arrays C [i] und Losgröße [i], wobei die Größe dieser Arrays gleich ist und gegen unendlich tendiert. Nehmen wir an, dass die Losgröße, die von jeder der Strategien angewendet wird, immer unterschiedlich ist. Außerdem wollen wir die Wahrscheinlichkeit einführen, dass eine dieser Strategien ausgelöst wird. PC[i], natürlich bilden diese Ereignisse eine vollständige Gruppe, sodass Summe(0,n)( PC[i] ) = 1. Alle Ergebnisse dieser Ereignisse bilden neue Ereignisräume S[i], T[i], die jeweils Aktivierungen durch Verlust und Gewinn darstellen. Diese Ereignisse haben ihre eigenen bedingten Wahrscheinlichkeiten PS[i], PT[i], die natürlich auch eine vollständige Gruppe bilden. Die grafische Darstellung ist unten angegeben:

Besprechen wir nun eine beliebige Einzelstrategie aus dieser Liste und berechnen ihren erwarteten Gewinn.

  • M[i]=(PT[i]*TP-PS[i]*SL)*Lot[i]*TickSize.

Wenn wir die Preisrichtung bei der Positionseröffnung nicht kennen, können wir sagen, dass M[i]=0, wobei M[i] die Reihe der erwarteten Gewinne bestimmter Strategien ist. Mit anderen Worten, wenn wir nicht wissen, in welche Richtung der Preis geht, erhalten wir 0, unabhängig davon, wie wir handeln, vorausgesetzt, dass die Anzahl der Positionen gegen unendlich tendiert.

Die allgemeine Gleichung des erwarteten Gewinns sieht wie folgt aus:

  • M0=Sum(0,n)(PC[i]*M[i])

Wir wissen, dass, wenn n gegen unendlich tendiert, alle M[i] gegen Null tendieren, was bedeutet, dass alle Terme unserer Summe gegen 0 tendieren, falls die Anzahl der Strategien endlich ist, während die Anzahl der Positionen unendlich ist. Das wiederum bedeutet, dass der allgemeine erwartete Gewinn M0 immer noch gleich 0 ist. Wenn wir weiter denken, stellt sich heraus, dass eine unendliche Menge solcher endlichen Mengen von Strategien auch gleich 0 ist, da die Summierung einer unendlichen Anzahl von Nullen 0 ergibt. Im Falle des Grids ist die Losgröße überall gleich, während sie im Falle des Martingals unterschiedlich ist, aber dieser Unterschied beeinflusst den Enderwartungswert in keiner Weise. Beide Strategien können mit dieser allgemeinen Gleichung beschrieben werden, ohne sich mit Kombinatorik zu beschäftigen. Alles ist ganz einfach und geradlinig.

Da diese Strategien mit dieser Gleichung beschrieben werden können, funktioniert sie für jede Strategie. Daraus ergibt sich die Schlussfolgerung, dass alle Strategien, die Variation und Manipulation von Positionen beinhalten, sowie die Systeme für Ordereröffnungen und -schließungen jeglicher Komplexität zum Scheitern verurteilt sind, wenn man nicht die ungefähre Bewegungsrichtung zum Zeitpunkt der Eröffnung und Schließung von Positionen oder zumindest einige zusätzliche Marktparameter kennt. Ohne eine korrekte Vorhersage sind alle unsere Bemühungen nur eine Verschwendung von Zeit und Geld.


Wie man Grid und Martingale richtig einsetzt

Das Grid kann nützlich sein, wenn Sie über die bevorstehende Marktbewegung in eine bestimmte Richtung Bescheid wissen oder die Wahrscheinlichkeit eines solchen Ereignisses hoch ist, während gleichzeitig das Risiko einer Kurslücke (gap) besteht. Kurslücken und Grids passen nicht sehr gut zusammen. Das liegt daran, dass die Orders mit einer bestimmten Schrittweite platziert werden, und es kann passieren, dass der nächste Tick an allen Orders vorbeifliegt und weit außerhalb des Grids erscheint. Natürlich ist dies ein seltener Fall, aber es reduziert unweigerlich die Systemleistung. Die Grid-Größe sollte gleich oder etwas kleiner als die vorhergesagte Bewegung eingestellt werden, wobei wir die Richtung der Bewegung nicht kennen müssen, sondern nur ihren ungefähren Wert. Unten sehen Sie, wie die Saldenkurve im Falle eines erfolgreichen Algorithmus zur Trenderkennung aussieht:


Es ist nicht immer möglich, einen Trend im Voraus zu definieren. Dies führt oft zu Verlustzyklen (oben rot markiert) und der Drawdown ist ebenfalls recht groß. Das Grid kann für diejenigen nützlich sein, die über Methoden zur Erkennung großer Bewegungen verfügen. In diesem Fall kann das Grid auf dem nutzerdefinierten Signal basieren. Ich habe mich mit dieser Frage noch nicht beschäftigt, wenn also jemand gute Algorithmen zur Erkennung von starken Bewegungen hat, können Sie gerne Ihre Erfahrungen teilen.

Besprechen wir nun das Martingal. Wenn wir ein beliebiges Signal mit der erwarteten Auszahlung von "0" haben, aber es ist bekannt, dass die Sequenz von Verlusten so ist, dass die Wahrscheinlichkeit einer profitablen Position für eine bestimmte Anzahl von Verlusten in einer Reihe nahe bei eins liegt, dann kann das Signal für Martingale verwendet werden. Die Saldenkurve sieht wie folgt aus:

Aber ich persönlich glaube, dass Martingal in jedem Fall gefährlich ist. Ich glaube, dass es fast unmöglich ist, solche Bedingungen zu erreichen, wie ich sie beschrieben habe, obwohl im Falle des Grids alles einfacher und vor allem klarer erscheint.


Schlussfolgerung

In diesem Artikel habe ich versucht, diese beiden Strategien so klar wie möglich zu beschreiben und ihre Gemeinsamkeiten, Vorteile und Nachteile hervorzuheben. Ich glaube, alle Erklärungen sind auch für Anfänger leicht zu verstehen. Der Artikel war vor allem für unerfahrene Händler gedacht, jedoch sind die abgeleiteten Schlussfolgerungen viel wichtiger als nur eine einfache Bewertung der Strategien und der Grenzen ihrer Anwendung. Die hier bereitgestellten allgemeinen mathematischen Schlussfolgerungen ermöglichen es jedem, seine Zeit effizient zu nutzen, während er seine eigenen Handelssysteme entwickelt. Der Artikel selbst bringt nichts Neues zum Verständnis der Marktphysik, aber ich denke, er kann viele Händler davor bewahren, diese Prinzipien gedankenlos zu ihrem eigenen Vorteil auszunutzen.

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

Beigefügte Dateien |
Easy_Grid.mq5 (14.27 KB)
Uncle_Martin.mq5 (6.47 KB)
Neuronale Netze leicht gemacht (Teil 4): Rekurrente Netze Neuronale Netze leicht gemacht (Teil 4): Rekurrente Netze
Wir setzen unser Studium der Welt der Neuronalen Netze fort. In diesem Artikel werden wir einen anderen Typ der Neuronalen Netzen betrachten, nämlich die Rekurrenten Netze. Dieser Typ wird für die Verwendung mit Zeitreihen vorgeschlagen, die in der Handelsplattform MetaTrader 5 durch Preisdiagramme dargestellt werden.
Brute-Force-Ansatz zur Mustersuche Brute-Force-Ansatz zur Mustersuche
In diesem Artikel werden wir nach Marktmustern suchen, Expert Advisors basierend auf den identifizierten Mustern erstellen und prüfen, wie lange diese Muster gültig bleiben, wenn sie überhaupt ihre Gültigkeit behalten.
Zeitreihen in der Bibliothek DoEasy (Teil 54): Abgeleitete Klassen des abstrakten Basisindikators Zeitreihen in der Bibliothek DoEasy (Teil 54): Abgeleitete Klassen des abstrakten Basisindikators
Der Artikel betrachtet das Erstellen von Klassen von abgeleiteten Objekten des abstrakten Basisindikators. Solche Objekte ermöglichen den Zugriff auf die Funktionen der Erstellung von Indikator-EAs, das Sammeln und Abrufen von Datenwertstatistiken verschiedener Indikatoren und Preise. Außerdem wird eine Kollektion von Indikatorobjekten erstellt, von der aus der Zugriff auf die Eigenschaften und Daten jedes im Programm erstellten Indikators möglich sein wird.
Zeitreihen in der Bibliothek DoEasy (Teil 53): Abstrakte Basisklasse der Indikatoren Zeitreihen in der Bibliothek DoEasy (Teil 53): Abstrakte Basisklasse der Indikatoren
Der Artikel beschäftigt sich mit dem Erstellen eines abstrakten Indikators, der im Weiteren als Basisklasse für die Erstellung von Objekten der Standard- und nutzerdefinierten Indikatoren der Bibliothek verwendet wird.