MetaTrader 5 herunterladen

Trademinator 3: Aufstand der Handelsrobots

20 April 2016, 14:32
Roman Zamozhnyy
0
247

Vorbemerkung

Vor langer langer Zeit begab es sich, dass in einem allzu fernen Forum (MQL5) zwei Beiträge erschienen: Genetische Algorithmen - nichts einfacher als das! von joo und Dr. Tradelove... von mir. In dem erstgenannten Artikel gibt uns der Verfasser das stärkste Hilfsmittel zur Optimierung von was immer man will einschließlich Handelsstrategien an die Hand: einen mit den Mitteln der Programmiersprache MQL5 umgesetzten genetischen Algorithmus.

In Anlehnung daran habe ich in dem zweiten Artikel versucht, ein auf diesem Algorithmus basierendes selbstoptimierendes Expert-System zu programmieren. Am Ende des genannten Beitrages wurde folgende Aufgabenstellung formuliert: Die Erstellung eines (selbstverständlich selbstoptimierenden) Expert-Systems, das nicht nur in der Lage ist, die optimalen Parameter für irgendein bestimmtes Handelssystem auszuwählen, sondern unter den bereits beschriebenen Handelsstrategien die optimalste ausmachen kann. Schauen wir einmal, ob das möglich ist und, wenn ja, wie?

Mythen von automatischen Handelssystemen

Formulieren wir also zunächst die allgemeinen Vorgaben für ein selbstoptimierendes Expert-System.

Es muss in der Lage sein (anhand älterer „historischer“ Verlaufsdaten):

  • unter den beschriebenen Strategien die beste auszumachen;
  • das beste Finanzinstrument (Währungspaarkürzel) auszuwählen;
  • den besten Einlageumfang für den Handel angesichts des Finanzhebels zu ermitteln;
  • die besten Indikatorparameter im Rahmen der gewählten Strategie zu bestimmen.

In der Praxis muss es überdies fähig sein,

  • Positionen zu eröffnen und zu schließen;
  • den Umfang der betreffenden Position zu bestimmen;
  • zu entscheiden, ob eine erneute Optimierung erforderlich ist.

Die folgende Abbildung zeigt den Grundaufbau eines solchen Expert-Systems.


Ein ausführlicher „Bauplan“ nebst Verknüpfungen befindet sich in der Datei Scheme_en im Anhang zu diesem Beitrag.

Uns der Unmöglichkeit, das Ungreifbare zu ergreifen, erinnernd machen wir uns unverzüglich an die Eingrenzung der Logik unseres Expert-Systems. Wir vereinbaren, dass (WICHTIG!):

  1. das Expert-System bei Auftreten eines neuen Balkens (in jedem von uns gewählten Zeitraum) eine Handelsentscheidung trifft.
  2. das Expert-System ausgehend von Punkt 1, jedoch nicht darauf beschränkt, ein Geschäft nur aufgrund der Signale von Indikatoren abschließt, die weder TakeProfit noch StopLoss verwenden und entsprechend auch keinen TrailingStop.
  3. die Bedingung für den Beginn einer erneuten Optimierung wie folgt lautet: der Kontostand sinkt über den beim Anlegen der Grenze voreingestellten Wert hinaus. Hier ist darauf hinzuweisen, dass es sich um meine ganz persönliche Bedingung handelt, sie kann auch ganz anders programmiert werden.
  4. die Tauglichkeitsfunktion den Handel auf der Grundlage des Kursverlaufes modelliert und den modellierten Kontostand unter der Bedingung maximiert, dass dessen durch die modellierten Abschlüsse bedingter relativer Rückgang eine bestimmte vorgegebene Grenze nicht überschreitet. Auch hierbei handelt es sich um meine ganz persönliche Tauglichkeitsfunktion, die ebenfalls beliebig anders festgelegt werden kann.
  5. wir die Anzahl der zu optimierenden Parameter neben den drei allgemeinen (Strategie, Kürzel und Anteil am Mittelbestand) auf fünf für die Parameter der Indikatorzwischenspeicher (Puffer) begrenzen. Diese Begrenzung ist eine logische Folge der Höchstzahl der Puffer für die integrierten technischen Indikatoren. Sollten Sie beabsichtigen, Strategien zu programmieren, die benutzerdefinierte Indikatoren in einer die Anzahl der Puffer übersteigenden Menge verwenden, müssen Sie in der Datei main.mq5 in der Variablen OptParamCount lediglich die erforderliche Anzahl ändern.

Jetzt, da die Vorgaben festgelegt und die Begrenzungen gesetzt sind, können wir uns den Programmcode anschauen, dem wir all das zu verdanken haben.

Wir beginnen mit der Funktion, um die sich alles dreht:

void OnTick()
{
  if(isNewBars()==true)
  {
    trig=false;
    switch(strat)
    {
      case  0: {trig=NeedCloseMA()   ; break;};                      //The number of case strings must be equal to the number of strategies
      case  1: {trig=NeedCloseSAR()  ; break;};
      case  2: {trig=NeedCloseStoch(); break;};
      default: {trig=NeedCloseMA()   ; break;};
    }
    if(trig==true)
    {
      if(GetRelDD()>maxDD)                                           //If a balance drawdown is above the max allowed value:
      {
        GA();                                                        //Call the genetic optimization function
        GetTrainResults();                                           //Get the optimized parameters
        maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);               //Now count the drawdown not from the balance maximum...
                                                                     //...but from the current balance
      }
    }
    switch(strat)
    {
      case  0: {trig=NeedOpenMA()   ; break;};                       //The number of case strings must be equal to the number of strategies
      case  1: {trig=NeedOpenSAR()  ; break;};
      case  2: {trig=NeedOpenStoch(); break;};
      default: {trig=NeedOpenMA()   ; break;};
    }
    Print(TimeToString(TimeCurrent()),";","Main:OnTick:isNewBars(true)",
          ";","strat=",strat);
  }
}

Womit haben wir es hier zu tun? Wie das Schema zeigt, schauen wir bei jeder Kursänderung, jedem Tick, ob ein neuer Balken aufgetaucht ist. Wenn dem so ist, rufen wir in Kenntnis der aktuell gewählten Strategie die dieser zugeordnete Funktion zur Überprüfung des Vorliegens einer eröffneten Position bzw. falls erforderlich zu deren Schließung auf. Angenommen, in dem gegebenen Moment ist SAR die beste Durchbruchstrategie, so wird folgerichtig die Funktion NeedCloseSAR aufgerufen:

bool NeedCloseSAR()
{
  CopyBuffer(SAR,0,0,count,SARBuffer);
  CopyOpen(s,tf,0,count,o);
  Print(TimeToString(TimeCurrent()),";","StrategySAR:NeedCloseSAR",
        ";","SAR[0]=",SARBuffer[0],";","SAR[1]=",SARBuffer[1],";","Open[0]=",o[0],";","Open[1]=",o[1]);
  if((SARBuffer[0]>o[0]&&SARBuffer[1]<o[1])||
     (SARBuffer[0]<o[0]&&SARBuffer[1]>o[1]))
  {
    if(PositionsTotal()>0)
    {
      ClosePosition();
      return(true);
    }
  }
  return(false);
}

Jede Funktion, die eine Position schließt, muss eine Boolesche sein und bei Schließung der Position den Wert „true“ ausgeben. Das ermöglicht dem nächsten Codeblock der Funktion OnTick() die Entscheidung, ob ein erneuter Optimierungsvorgang gestartet werden muss:

    if(trig==true)
    {
      if(GetRelDD()>maxDD)                                           //If the balance drawdown is above the max allowed one:
      {
        GA();                                                        //Call the genetic optimization function
        GetTrainResults();                                           //Get optimized parameters
        maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);                   //Now count the drawdown not from the balance maximum...
                                                                     //...but from the current balance
      }
    }

Wir erhalten den aktuellen Rückgang des Kontostandes, vergleichen ihn mit dem größtmöglichen. Übersteigt Ersterer den Zweiten, erfolgt eine erneute Optimierung (GA()). Die Funktion GA() ihrerseits ruft das Herzstück des gesamten Expert-Systems auf: die Tauglichkeitsfunktion FitnessFunction(int chromos) des Moduls GAModule.mqh:

void FitnessFunction(int chromos)                                    //A fitness function for the genetic optimizer:...
                                                                     //...selects a strategy, symbol, deposit share,...
                                                                     //...parameters of indicator buffers;...
                                                                     //...you can optimize whatever you need, but...
                                                                     //...watch carefully the number of genes
{
  double ff=0.0;                                                     //The fitness function
  strat=(int)MathRound(Colony[GeneCount-2][chromos]*StratCount);     //GA selects a strategy
 //For EA testing mode use the following code...
  z=(int)MathRound(Colony[GeneCount-1][chromos]*3);                  //GA selects a symbol
  switch(z)
  {
    case  0: {s="EURUSD"; break;};
    case  1: {s="GBPUSD"; break;};
    case  2: {s="USDCHF"; break;};
    case  3: {s="USDJPY"; break;};
    default: {s="EURUSD"; break;};
  }
//..for real mode, comment the previous code and uncomment the following one (symbols are selected in the MarketWatch window)
/*
  z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1));//GA selects a symbol
  s=SymbolName(z,true);
*/
  optF=Colony[GeneCount][chromos];                                   //GA selects a deposit share
  switch(strat)
  {
    case  0: {ff=FFMA(   Colony[1][chromos],                         //The number of case strings must be equal to the number of strategies
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
    case  1: {ff=FFSAR(  Colony[1][chromos],
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
    case  2: {ff=FFStoch(Colony[1][chromos],
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
    default: {ff=FFMA(   Colony[1][chromos],
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
  }
  AmountStartsFF++;
  Colony[0][chromos]=ff;
  Print(TimeToString(TimeCurrent()),";","GAModule:FitnessFunction",
        ";","strat=",strat,";","s=",s,";","optF=",optF,
        ";",Colony[1][chromos],";",Colony[2][chromos],";",Colony[3][chromos],";",Colony[4][chromos],";",Colony[5][chromos]);
}

Je nach gerade gewählter Strategie wird das für eben diese Strategie bestimmte Modul zur Berechnung der Tauglichkeitsfunktion aufgerufen. Angenommen die GA hat sich für den Indikator Stochastik entschieden, dann wird die Funktion FFStoch() aufgerufen, und die Optimierungsparameter der Indikatorzwischenspeicher werden an sie übermittelt:

double FFStoch(double par1,double par2,double par3,double par4,double par5)
{
  int    b;
  bool   FFtrig=false;                                               //Is there an open position?
  string dir="";                                                     //Direction of the open position
  double OpenPrice;                                                  //Position Open price
  double t=cap;                                                      //Current balance
  double maxt=t;                                                     //Maximum balance
  double aDD=0.0;                                                    //Absolute drawdown
  double rDD=0.000001;                                               //Relative drawdown
  Stoch=iStochastic(s,tf,(int)MathRound(par1*MaxStochPeriod)+1,
                         (int)MathRound(par2*MaxStochPeriod)+1,
                         (int)MathRound(par3*MaxStochPeriod)+1,MODE_SMA,STO_CLOSECLOSE);
  StochTopLimit   =par4*100.0;
  StochBottomLimit=par5*100.0;
  dig=MathPow(10.0,(double)SymbolInfoInteger(s,SYMBOL_DIGITS));
  leverage=AccountInfoInteger(ACCOUNT_LEVERAGE);
  contractSize=SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE);
  b=MathMin(Bars(s,tf)-1-count-MaxMAPeriod,depth);
  for(from=b;from>=1;from--)                                         //Where to start copying of history
  {
    CopyBuffer(Stoch,0,from,count,StochBufferMain);
    CopyBuffer(Stoch,1,from,count,StochBufferSignal);
    if((StochBufferMain[0]>StochBufferSignal[0]&&StochBufferMain[1]<StochBufferSignal[1])||
       (StochBufferMain[0]<StochBufferSignal[0]&&StochBufferMain[1]>StochBufferSignal[1]))
    {
      if(FFtrig==true)
      {
        if(dir=="BUY")
        {
          CopyOpen(s,tf,from,count,o);
          if(t>0) t=t+t*optF*leverage*(o[1]-OpenPrice)*dig/contractSize; else t=0;
          if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t;
          if((maxt>0)&&(aDD/maxt>rDD)) rDD=aDD/maxt;
        }
        if(dir=="SELL")
        {
          CopyOpen(s,tf,from,count,o);
          if(t>0) t=t+t*optF*leverage*(OpenPrice-o[1])*dig/contractSize; else t=0;
          if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t;
          if((maxt>0)&&(aDD/maxt>rDD)) rDD=aDD/maxt;
        }
        FFtrig=false;
      }
   }
    if(StochBufferMain[0]>StochBufferSignal[0]&&StochBufferMain[1]<StochBufferSignal[1]&&StochBufferMain[1]>StochTopLimit)
    {
      CopyOpen(s,tf,from,count,o);
      OpenPrice=o[1];
      dir="SELL";
      FFtrig=true;
    }
    if(StochBufferMain[0]<StochBufferSignal[0]&&StochBufferMain[1]>StochBufferSignal[1]&&StochBufferMain[1]<StochBottomLimit)
    {
      CopyOpen(s,tf,from,count,o);
      OpenPrice=o[1];
      dir="BUY";
      FFtrig=true;
    }
  }
  Print(TimeToString(TimeCurrent()),";","StrategyStoch:FFStoch",
        ";","K=",(int)MathRound(par1*MaxStochPeriod)+1,";","D=",(int)MathRound(par2*MaxStochPeriod)+1,
        ";","Slow=",(int)MathRound(par3*MaxStochPeriod)+1,";","TopLimit=",StochTopLimit,";","BottomLimit=",StochBottomLimit,
        ";","rDD=",rDD,";","Cap=",t);
  if(rDD<=trainDD) return(t); else return(0.0);
}

Die Tauglichkeitsfunktion des Stochastik-Indikators gibt den Wert des modellierten Kontostandes an die Hauptfunktion aus, welche ihn an den genetischen Algorithmus (GA) weiterleitet. An einem gewissen Zeitpunkt trifft der GA die Entscheidung, die Optimierung sowie die Funktion GetTrainResults() zu beenden, dann geben wir die aktuell besten Werte für die Strategie (wir nehmen an, es handelt sich um die gleitenden Durchschnittswerte), das Kürzel, den Anteil am Kontobestand und die Pufferparameter an das Hauptprogramm weiter und legen darüber hinaus für die weitere Arbeit „echte“ Indikatoren an:

void GetTrainResults()                                               //Get the best parameters
{
  strat=(int)MathRound(Chromosome[GeneCount-2]*StratCount);          //Remember the best strategy
//For EA testing mode use the following code...
  z=(int)MathRound(Chromosome[GeneCount-1]*3);                       //Remember the best symbol
  switch(z)
  {
    case  0: {s="EURUSD"; break;};
    case  1: {s="GBPUSD"; break;};
    case  2: {s="USDCHF"; break;};
    case  3: {s="USDJPY"; break;};
    default: {s="EURUSD"; break;};
  }
//...for real mode, comment the previous code and uncomment the following one (symbols are selected in the MarketWatch window)
/*
  z=(int)MathRound(Chromosome[GeneCount-1]*(SymbolsTotal(true)-1));  //Remember the best symbol
  s=SymbolName(z,true);
*/
  optF=Chromosome[GeneCount];                                        //Remember the best deposit share
  switch(strat)
  {
    case  0: {GTRMA(   Chromosome[1],                                //The number of case strings must be equal to the number of strategies
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
    case  1: {GTRSAR(  Chromosome[1],
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
    case  2: {GTRStoch(Chromosome[1],
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
    default: {GTRMA(   Chromosome[1],
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
  }
  Print(TimeToString(TimeCurrent()),";","GAModule:GetTrainResults",
        ";","strat=",strat,";","s=",s,";","optF=",optF,
        ";",Chromosome[1],";",Chromosome[2],";",Chromosome[3],";",Chromosome[4],";",Chromosome[5]);
}

void GTRMA(double par1,double par2,double par3,double par4,double par5)
{
  MAshort=iMA(s,tf,(int)MathRound(par1*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
  MAlong =iMA(s,tf,(int)MathRound(par2*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
  CopyBuffer(MAshort,0,from,count,ShortBuffer);
  CopyBuffer(MAlong, 0,from,count,LongBuffer );
  Print(TimeToString(TimeCurrent()),";","StrategyMA:GTRMA",
        ";","MAL=",(int)MathRound(par2*MaxMAPeriod)+1,";","MAS=",(int)MathRound(par1*MaxMAPeriod)+1);
}

Jetzt sind wir wieder da, worum sich alles dreht, bei (OnTick()): Wissend, welche Strategie aktuell die beste ist, überprüfen wir, ob die Zeit reif ist, um sich in den Markt zu stürzen:

bool NeedOpenMA()
{
  CopyBuffer(MAshort,0,0,count,ShortBuffer);
  CopyBuffer(MAlong, 0,0,count,LongBuffer );
  Print(TimeToString(TimeCurrent()),";","StrategyMA:NeedOpenMA",
        ";","LB[0]=",LongBuffer[0],";","LB[1]=",LongBuffer[1],";","SB[0]=",ShortBuffer[0],";","SB[1]=",ShortBuffer[1]);
  if(LongBuffer[0]>LongBuffer[1]&&ShortBuffer[0]>LongBuffer[0]&&ShortBuffer[1]<LongBuffer[1])
  {
    request.type=ORDER_TYPE_SELL;
    OpenPosition();
    return(false);
  }
  if(LongBuffer[0]<LongBuffer[1]&&ShortBuffer[0]<LongBuffer[0]&&ShortBuffer[1]>LongBuffer[1])
  {
    request.type=ORDER_TYPE_BUY;
    OpenPosition();
    return(false);
  }
  return(true);
}

Damit wäre der Kreis geschlossen.

Schauen wir, ob‘s funktioniert! Es folgt das Protokoll für das Jahr 2011 anhand der Stundenwerte für vier Hauptwährungspaare: EURUSD, GBPUSD, USDCHF und USDJPY:

Protokoll des Strategieprüfprogramms
InstaForex-Server (Build 567)
Einstellungen
Expert-System: Main
Kürzel: EURUSD
Zeitraum: H1 (2011.01.01 - 2011.12.31)
Eingangsparameter: trainDD=0.50000000
maxDD=0.20000000
Makler: InstaForex Companies Group
Währung: USD
Anfangseinlage: 10.000,00
Hebelwirkung: 1:100
Ergebnisse
Verlaufsdatenqualität: 100%
Balken: 6.197 Kursänderungen (Ticks): 1321631
Gesamtnettogewinn: -538,74 Bruttogewinn: 3.535,51 Bruttoverlust: -4.074,25
Gewinnfaktor: 0,87 Erwartete Auszahlung -89,79 Gewinnspanne: 85,71%
Erholungsfaktor: -0,08 Sharpe-Ratio: 0,07 OnTester-Ergebnis: 0
Wertverlust des Kontos:
Absoluter Wertverlust des Kontos: 4.074,25 Maximaler Wertverlust des Kontos: 4.074,25 (40,74%) Relativer Wertverlust des Kontos: 40,74% (4.074,25)
Wertverlust des Kapitals:
Absoluter Wertverlust des Kapitals: 4.889,56 Maximaler Wertverlust des Kapitals: 6.690,90 (50,53%) Relativer Wertverlust des Kapitals: 50,53% (6.690,90)
Abschlüsse insgesamt: 6 Kurzfristige (short) Abschlüsse (mit Gewinn %): 6 (16,67%) Langfristige (long) Abschlüsse (mit Gewinn %): 0 (0,00%)
Abschlüsse insgesamt: 12 Mit Gewinn (in % aller Abschlüsse) 1 (16,67%) Mit Verlust (in % aller Abschlüsse) 5 (83,33%)
Größter Abschluss mit Gewinn: 3.535,51 Größter Abschluss mit Verlust: -1.325,40
Durchschnittlicher Abschluss mit Gewinn: 3.535,51 Durchschnittlicher Abschluss mit Verlust: -814,85
Größte Anzahl ununterbrochener Gewinne (Gesamtgewinn in $): 1 (3.535,51) Größte Anzahl ununterbrochener Verluste (Gesamtverlust in $): 5 (-4.074,25)
Höchster ununterbrochener Gesamtgewinn (Anzahl der Abschlüsse): 3.535,51 (1) Höchster ununterbrochener Gesamtverlust (Anzahl der Abschlüsse): -4.074,25 (5)
Durchschnittliche ununterbrochene Gewinne: 1 Durchschnittliche ununterbrochene Verluste: 5

Aufträge (Orders)
Eröffnungszeitpunkt Auftrag Kürzel Art Umfang Kurs S / L T / P Uhrzeit Status Hinweise
2011.01.03 01:002USDCHFVerkauf28,21/28,210,93212011.01.03 01:00ausgeführt
2011.01.03 03:003USDCHFKauf28,21/28,210,93652011.01.03 03:00ausgeführt
2011.01.03 06:004USDCHFVerkauf24,47/24,470,93522011.01.03 06:00ausgeführt
2011.01.03 09:005USDCHFKauf24,47/24,470,93722011.01.03 09:00ausgeführt
2011.01.03 13:006USDCHFVerkauf22,99/22,990,93522011.01.03 13:00ausgeführt
2011.01.03 16:007USDCHFKauf22,99/22,990,93752011.01.03 16:00ausgeführt
2011.01.03 18:008USDJPYVerkauf72,09/72,0981,572011.01.03 18:00ausgeführt
2011.01.03 21:009USDJPYKauf72,09/72,0981,662011.01.03 21:00ausgeführt
2011.01.04 01:0010USDJPYVerkauf64,54/64,5481,672011.01.04 01:00ausgeführt
2011.01.04 02:0011USDJPYKauf64,54/64,5481,782011.01.04 02:00ausgeführt
2011.10.20 21:0012USDCHFVerkauf56,30/56,300,89642011.10.20 21:00ausgeführt
2011.10.21 12:0013USDCHFKauf56,30/56,300,89082011.10.21 12:00ausgeführt
Abschlüsse
Uhrzeit Abschluss Kürzel Art Richtung Umfang Kurs Auftrag Provision Swap Gewinn Kontostand Hinweise
2011.01.01 00:001Kontostand0,000,0010.000,0010.000,00
2011.01.03 01:002USDCHFVerkaufhinein28,210,932120,000,000,0010.000,00
2011.01.03 03:003USDCHFKaufheraus28,210,936530,000,00-1.325,408.674,60
2011.01.03 06:004USDCHFVerkaufhinein24,470,935240,000,000,008.674,60
2011.01.03 09:005USDCHFKaufheraus24,470,937250,000,00-522,198.152,41
2011.01.03 13:006USDCHFVerkaufhinein22,990,935260,000,000,008.152,41
2011.01.03 16:007USDCHFKaufheraus22,990,937570,000,00-564,027.588,39
2011.01.03 18:008USDJPYVerkaufhinein72,0981,5780,000,000,007.588,39
2011.01.03 21:009USDJPYKaufheraus72,0981,6690,000,00-794,536.793,86
2011.01.04 01:0010USDJPYVerkaufhinein64,5481,67100,000,000,006.793,86
2011.01.04 02:0011USDJPYKaufheraus64,5481,78110,000,00-868,115.925,75
2011.10.20 21:0012USDCHFVerkaufhinein56,300,8964120,000,000,005.925,75
2011.10.21 12:0013USDCHFKaufheraus56,300,8908130,00-3,783.539,299.461,26
0,00 -3,78 -534,96 9.461,26
Copyright 2001-2011, MetaQuotes Software Corp.

Ich werde die in dem Diagramm hervorgehobenen Bereiche erläutern (die Erläuterungen entstammen der Analyse der Protokolle):

  1. Nach dem Aufrufen des Expert-Systems hat der genetische Algorithmus die Durchbrechungsstrategie SAR für das Währungspaar USDCHF mit einem Handelseinsatz von 28% des Bestandes gewählt, bis zum Abend des dritten Januar gehandelt, dabei über 20% des Kontobestandes eingebüßt und mit der erneuten Optimierung begonnen.
  2. Jetzt hat das Expert-System beschlossen, USDJPY mittels SAR-Durchbrechung zu handeln, diesmal aber mit fast dem ganzen Bestand (98%). Das ging natürlich nicht lange gut, weswegen die dritte Optimierung bereits am Morgen des Vierten begann.
  3. Anschließend entschied das System, alles auf eine Karte zu setzen und Hopp oder Topp mit den gleitenden den gleitenden Durchschnittswerten für USDCHF erneut für den gesamten Bestand zu handeln. Es dauerte sage und schreibe bis zum 20. Oktober bevor sich das erste „Grabkreuz“ zeigte und es zum Höchstwert verkaufen konnte, woraufhin alle Verluste ausgeglichen waren. Danach sah das Expert-System bis zum Jahresende keine günstigen Bedingungen für einen Markteintritt mehr...

Wird es eine Fortsetzung geben?

Ist eine Fortsetzung möglich? Wie könnten die Expert-Systeme der nächsten Generation aussehen? Expert-Systeme, die selbst Strategien entwickeln und die beste auswählen... Und auch die Kapitalverwaltung selbst erledigen, sich die erforderliche Hard- und Software beschaffen, die Bandbreite steigern usw.

Warnung!

Diese kurze Ausführung enthüllt nicht lückenlos alle Arten von Risiken sowie die sonstigen beim Abschluss von Geschäften im Zusammenhang der Änderung der Wechselkursverhältnisse mit Finanzierungshebel zu beachtenden Gesichtspunkte. Sie müssen sich der Art der abgeschlossenen Geschäfte sowie der damit verbundenen Gefahren ebenso bewusst sein wie Ihrer eigenen Möglichkeiten. Bedenken Sie sorgfältig, ob Ihnen die Arbeit auf dem Devisenmarkt liegt, ob sie Ihren Erfahrungen, Zielen, finanziellen Möglichkeiten sowie Ihren sonstigen Lebensumständen entspricht.

Der Devisenmarkt ist nicht nur hoch profitabel, er ist auch hoch riskant. Unter den Bedingungen des Differenzhandels kann bereits eine vergleichsweise geringfügige Kursänderung bei einem Finanzinstrument ganz erhebliche Auswirkungen auf den Stand Ihres Handelskontos haben, in deren Folge Sie nicht nur Ihre Anfangseinlage sondern auch alle zur Stützung der eröffneten Positionen nachgeschossenen Mittel verlieren können. Sie sollten kein Geld riskieren, das zu verlieren, Sie nicht bereit sind. Vergewissern Sie sich vor Ihrem Einstieg in den Handel unbedingt, dass Ihnen die Risiken bewusst sind, und bedenken Sie den Stand Ihrer Erfahrung. Lassen Sie sich gegebenenfalls von unabhängiger Seite beraten.

Lizenzen:

Das Modul UGAlib.mqh wurde von Andrej Dik alias joo entwickelt und wird unter BSD-Lizenz vertrieben.

Das Expert-System und die Dienstmodule im Anhang zu diesem Beitrag wurden von dem Verfasser Roman Rich entwickelt und werden unter BSD-Lizenz vertrieben. Der Wortlaut der Lizenz kann in der Datei Lic.txt eingesehen werden.

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/350

Beigefügte Dateien |
lic.txt (1.43 KB)
sheme_en.gif (147.11 KB)
gamodule.mqh (7.24 KB)
main.mq5 (4.99 KB)
musthave.mqh (7.79 KB)
strategyma.mqh (5.13 KB)
strategysar.mqh (4.09 KB)
strategystoch.mqh (6.04 KB)
ugalib.mqh (33.36 KB)
Erstellen von Expert-Systemen mit dem Hilfsprogramm Expert Advisor Visual Wizard Erstellen von Expert-Systemen mit dem Hilfsprogramm Expert Advisor Visual Wizard

Das Hilfsprogramm Expert Advisor Visual Wizard für MetaTrader 5 bietet eine höchst verständliche intuitive grafische Umgebung mit einer umfangreichen Auswahl vorgefertigter Programmblöcke für den Handel, die die Erstellung automatischer Handelssysteme (hier: Expert-Systeme) zu einer Sache von Minuten machen. Die auf Anklicken, Ziehen und Ablegen (click, drag and drop) beruhende Arbeitsweise des Expert Advisor Visual Wizard ermöglicht die Erstellung grafischer Abbildungen von Handelsstrategien und -signalen wie bei der Arbeit mit Papier und Bleistift. Diese Handelsdiagramme werden automatisch von dem von Molanis entwickelten MQL5-Codegenerator analysiert und in einsatzbereite Expert-Systeme übersetzt. Die interaktive grafische Umgebung vereinfacht die Planung und beseitigt die Notwendigkeit des Schreibens von MQL5-Code.

Zeitreihenvorhersage mittels exponentieller Glättung (Fortsetzung) Zeitreihenvorhersage mittels exponentieller Glättung (Fortsetzung)

In diesem Beitrag wird versucht, einen bereits angelegten Indikator nachzubessern, außerdem wird kurz auf eine Methode zur Berechnung der Zuverlässigkeitsintervalle von Vorhersagen mittels Bootstrapping und Quantilen eingegangen. Als Ergebnis erhalten wir einen Vorhersageindikator und Skripte zur Berechnung der Vorhersagegenauigkeit.

Schutz von MQL5-Programmen: Passwörter, Schlüssel, Zeitbegrenzung, Berechtigungsfernabfrage Schutz von MQL5-Programmen: Passwörter, Schlüssel, Zeitbegrenzung, Berechtigungsfernabfrage

Die Mehrzahl der Entwickler benötigt Schutz für ihren Programmcode. In diesem Beitrag werden einige unterschiedliche Möglichkeiten zum Schutz von in MQL5 geschriebenen Programmen vorgestellt, so etwa zur Ausstattung von MQL5-Skripten, automatischen Handelssystemen und Indikatoren mit Zugriffskontrollverfahren. Dazu zählen Passwortschutz, Schlüsselgeneratoren, Zugriffskonten, Zeitbegrenzungsprüfungen sowie der Schutz mittels MQL5-RPC-Aufrufen aus der Ferne.

Unterstützen Sie Ihre Entwicklungsprojekte mit EX5-Bibliotheken Unterstützen Sie Ihre Entwicklungsprojekte mit EX5-Bibliotheken

Indem Sie die Umsetzungsdetails von Klassen/Funktionen in einer .ex5-Datei verbergen, können Sie Ihre Know-how-Algorithmen mit anderen Entwicklern teilen, gemeinsame Projekte in die Wege leiten und sie im Internet bewerben. Und während das Team von MetaQuotes keine Mühen scheut, um die direkte Vererbung von ex5-Bibliotheksklassen zu ermöglichen, setzen wir sie jetzt schon um.