Dokumentation

Anwendungen

Zuletzt aktualisiert am 24. 5. 2022 von Mark Fric

Programmgesteuertes Backtesting der Strategie einschließlich Robustheitstests

Dieser Artikel ist eine Fortsetzung des vorherigen Artikels Programmatische Durchführung von Strategie-Backtests.

 

Es wird gezeigt, wie man einen programmatischen Backtest durchführt, diesmal einschließlich ausgewählter Gegenproben (Robustheitstests). Das Prinzip des programmatischen Backtests ist das gleiche, wir werden es hier nicht noch einmal erklären.

Wir werden nur die neuen Dinge erklären.

 

Verwendung von processDatabank() zur Durchführung eines Backtests einer Strategie

Genau wie im vorherigen Beispiel verwenden wir das Snippet CustomAnalysis und seine Methode processDatabank(). Hier wählen wir die erste Strategie aus der Datenbank aus und führen Backtest und Robustheitstests mit ihr durch.

Der Code der Methode processDatabank() lautet:

//------------------------------------------------------------------------

@Override
public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception {
    if(databankRG.size() == 0) {
        return databankRG;
    }

    // holt die erste Strategie aus der Datenbank, um sie erneut zu testen
    ErgebnisGruppe strategyToRetest = databankRG.get(0);

    //------------------------------------
    // HAUPT-SETUP BACKTEST
    ResultsGroup backtestResultRG = runMainBacktest(strategyToRetest);

    //------------------------------------
    // KREUZTESTS
    runAndSaveCrossChecks(backtestResultRG, strategyToRetest.getName());

    // Details zum Backtest-Ergebnis abrufen
    int trades = backtestResultRG.portfolio().stats(Directions.Both, PlTypes.Money, SampleTypes.FullSample).getInt(StatsKey.NUMBER_OF_TRADES);
    double profit = backtestResultRG.portfolio().stats(Directions.Both, PlTypes.Percent, SampleTypes.FullSample).getDouble(StatsKey.NET_PROFIT);

    // etwas mit den neuen Backtest-Ergebnissen machen
    // ResultsGroup enthält nun den Haupt-Backtest + alle konfigurierten Cross-Checks.
    // siehe: https://strategyquant.com/doc/programming-for-sq/working-with-resultsgroup/
    // wie man die einzelnen Ergebnisse erhält


    // Hier speichern wir einfach die neu getestete Strategie in der Zieldatenbank
    Datenbank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Results");

    targetDatabank.add(backtestResultRG, true);

    return databankRG;
}

 

Sie können sehen, dass wir dort zwei Untermethoden haben:

  • runMainBacktest() führt den Haupt-Backtest der Strategie durch und erzeugt ErgebnisGruppe mit Backtest-Ergebnis. Diese Methode ist die gleiche wie im Originalbeispiel und wird hier nicht erklärt
  • runAndSaveCrosschecks() führt die angegebenen Gegenproben durch und legt sie alle in dieselbe ErgebnisGruppe Objekt als separate Ergebnisse

Anschließend wird dieses neue Ergebnis in einer Zieldatenbank gespeichert.

 

 

Gegenkontrollen konfigurieren

Crosschecks in SQX sind als Plugins implementiert, und jeder Crosscheck hat eine Methode runTest() die eine Gegenprüfung der Strategie vornimmt.

Wenn wir also die Gegenproben konfiguriert haben, können wir diese Methode einfach bei jeder Gegenprobe, die wir durchführen wollen, aufrufen.

Die Erstellung/Konfiguration des Crosschecks ist hier die Herausforderung, sie wird in einer Untermethode durchgeführt configureCrosschecks() - gibt diese Methode ein Array von Gegenproben zurück, die dann nacheinander ausgeführt werden.

 

Es gibt noch weitere Möglichkeiten, Crosscheck-Konfigurationen zu erstellen, aber die einfachste sowohl für die Programmierung als auch für den normalen Gebrauch ist, sie einfach aus dem XML-Format erstellen zu lassen, in dem SQX sie speichert. Dies ist die Methode, die wir hier verwenden.

 

Der Kodex der configureCrosschecks() Methode und einige Untermethoden:

   //------------------------------------------------------------------------

   private ArrayList configureCrosschecks() throws Exception {
       ArrayList crossChecks = new ArrayList();

       crossChecks.add( createFromXml("c:\\RetestWithHigherPrecision.xml") );
       crossChecks.add( createFromXml("c:\\MonteCarloManipulation.xml") );
       crossChecks.add( createFromXml("c:\\MonteCarloRetest.xml") );

       return crossChecks;
   }

   //------------------------------------------------------------------------

   private ICrossCheck createFromXml(String xmlFile) throws Exception {
       Element elXml = XMLUtil.fileToXmlElement(new File(xmlFile));

       String ccName = elXml.getName();

       ICrossCheck crossCheck = getCrossCheckPlugin(ccName);
       if(crossCheck != null) {
           crossCheck.readSettings(elXml, null);
       }
       sonst {
           throw new Exception ("Cannot find cross check plugin '" + ccName + "'");
       }

       return crossCheck;
   }

   //------------------------------------------------------------------------

   private ICrossCheck getCrossCheckPlugin(String name) {
       ArrayList plugins = SQPluginManager.getPlugins(ICrossCheck.class);

       for(int i=0; i<plugins.size(); i++) {
           if(plugins.get(i).getSettingName().equals(name)) {
               return plugins.get(i).clone(null);
           }
       }

       return null;
   }

 

Sie können sehen, dass die Crosscheck-Konfiguration mit der Methode createFromXml() die eine XML-Datei als Parameter erhält. Diese XML-Datei ist die Definition des gegebenen Crosschecks.

Die Methode erstellt zunächst einen Klon des Plugins für die jeweilige Gegenprobe, indem sie getCrossCheckPlugin(pluginName)und ruft dann einfach readSettings(xml) auf das Objekt, um es mit Einstellungen aus XML zu initialisieren.

Danach ist das Cross-Check-Konfigurationsobjekt einsatzbereit.

 

In unserem Beispiel erstellen wir drei Gegenkontrollen:

  • Erneuter Test mit höherem Zeitrahmen
  • Monte-Carlo-Manipulation mit einigen ausgewählten Methoden
  • Monte-Carlo-Wiederholungstests mit ausgewählten Methoden

Wir haben eine separate XML-Datei mit der Konfiguration für jedes dieser Systeme.

 

So bereiten Sie die XML-Konfigurationsdatei für den Crosscheck vor

Am einfachsten ist es, die SQX-Benutzeroberfläche zu verwenden, um die genauen Einstellungen für den Cross-Check zu konfigurieren, den Sie entweder im Builder- oder im Retester-Projekt verwenden möchten.

Speichern Sie dann das gesamte Builder/Retester-Projekt in einer .cfx-Datei. Diese Datei hat die Erweiterung .cfx, ist aber eine Standard-ZIP-Datei, die Sie mit WinZip oder WinRar öffnen können.

In der Datei finden Sie die Datei config.xml - das ist das XML-Dokument, das die Einstellungen für das gesamte Projekt enthält.

Hier finden Sie den Abschnitt <CrossChecks> und fügen Sie von dort aus per Copy & Paste das gewünschte XML der Gegenprobe in eine separate Datei ein, die Sie später in unser benutzerdefiniertes Analyseschnipsel laden werden.

 

Ein Beispiel für die Datei RetestWithHigherPrecision.xml:

2
    3
  
  
    
      
        
          
        
        =" />
        
          
        
      
      
        
          
        
        =" />
        
          
        
      
      
        
          
        
        <Vergleicher value="

 

Ein Beispiel für eine MonteCarloManipulation.xml-Datei:

Resampling
        
      
      
        
          10
        
      
    
    10
    false

 

Ein Beispiel für eine MonteCarloRetest.xml-Datei:

20
          10
          20
          10
          true
        
      
      
        
          40
        
      
      
        
          0.0
          10.0
        
      
      
        
          0.0
          5.0
        
      
      
        
          1.0
          5.0
        
      
      
        
          100
        
      
      
        
          10
          20
          true
        
      
      
        
          10
          20
          true
          wahr
          falsch
          wahr
          true
          wahr
          true
          true
          false
          false
          true
        
      
    
    10
    false
    -1

 

 

 

Laufende Gegenkontrollen

Wenn wir die Cross-Check-Konfigurationsobjekte fertig haben, führen wir die Crosschecks einfach aus, indem wir ihre runTest() Methode.

Code:

private void runAndSaveCrossChecks(ResultsGroup mainResult, String strategyName) throws Exception {
    ArrayList crossChecks = configureCrosschecks();

    StopPauseEngine stopPauseEngine = new StopPauseEngine();

    for(int i=0; i<crossChecks.size(); i++) {

        ICrossCheck crossCheck = crossChecks.get(i);
        crossCheck.setStopPauseEngine(stopPauseEngine);

        try {
            Log.info(String.format("Running cross check %s for %s...", crossCheck.getName(), strategyName));

            boolean ccResult = crossCheck.runTest(mainResult, i, globalATR, null, true, null, strategyName);

            if(!ccResult) {
                // Unkommentiert lassen, wenn Sie die Ausführung anderer Kreuztests stoppen wollen, wenn einer von ihnen nicht bestanden wird
                // Andernfalls werden alle Cross-Checks für die Strategie ausgeführt
                //zurückgeben;
            }

        } catch(Exception e) {
            Log.error("Cross check exception: "+e.getMessage(), e);
        }
    }
}

 

Ausführen dieses benutzerdefinierten Analyse-Snippets

Wenn Sie dieses Snippet kompilieren und ausführen, sieht das Ergebnis wie folgt aus. Es nimmt die erste Strategie aus der Datenbank, führt einen Backtest und die 3 Gegenproben durch, die wir für sie konfiguriert haben, und speichert sie als neues Ergebnis in der Datenbank.

Sie können sehen, dass das neue Ergebnis auch Monte-Carlo-Ergebnisse enthält

 

 

War dieser Artikel hilfreich? Der Artikel war nützlich Der Artikel war nicht nützlich

Abonnieren
Benachrichtigen Sie mich bei
1 Kommentar
Älteste
Neuestes Meistgewählt
Inline-Rückmeldungen
Alle Kommentare anzeigen
Emmanuel
25. 5. 2022 12:37 Uhr

Hervorragend !!!! dies wird sehr hilfreich sein
Dankeschön

Verwandte Beiträge