Documentazione

Applicazioni

Ultimo aggiornamento il 24. 5. 2022 da Mark Fric

Backtesting programmatico della strategia, compresi i test di robustezza

Questo articolo è la continuazione dell'articolo precedente Esecuzione programmatica dei backtest delle strategie.

 

La presente guida mostra come eseguire un backtest in modo programmatico, questa volta includendo controlli incrociati selezionati (test di robustezza). Il principio del backtest programmatico è lo stesso, non lo spiegheremo di nuovo qui.

Vi spiegheremo solo le novità.

 

Utilizzo di processDatabank() per eseguire il backtest di una strategia

Come nell'esempio precedente, utilizzeremo lo snippet CustomAnalysis e il suo metodo elaboraBancaDati(). Sceglieremo la prima strategia dalla banca dati ed eseguiremo i backtest e i test di robustezza su di essa.

Il codice del metodo processDatabank() è:

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

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

    // ottenere la prima strategia nella banca dati per eseguire il retest su di essa
    ResultsGroup strategyToRetest = databankRG.get(0);

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

    //------------------------------------
    // CONTROLLI INCROCIATI
    runAndSaveCrossChecks(backtestResultRG, strategyToRetest.getName());

    // ottenere i dettagli del risultato del backtest
    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);

    // fare qualcosa con i nuovi risultati del backtest
    // ResultsGroup ora contiene il backtest principale + tutti i controlli incrociati configurati.
    // consultare: https://strategyquant.com/doc/programming-for-sq/working-with-resultsgroup/
    // su come ottenere i singoli risultati


    // Qui salveremo la strategia appena testata nella banca dati di destinazione.
    Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Results");

    targetDatabank.add(backtestResultRG, true);

    restituisce databankRG;
}

 

Si può notare che abbiamo due metodi secondari:

  • runMainBacktest() eseguirà il backtest principale della strategia e produrrà Gruppo di risultati con il risultato del backtest. Questo metodo è identico a quello dell'esempio originale e non verrà spiegato in questa sede.
  • runAndSaveCrosscheck() eseguirà i controlli incrociati specificati e li metterà tutti nella stessa cartella di Gruppo di risultati come risultati separati

Quindi salverà questo nuovo risultato in una banca dati di destinazione.

 

 

Configurazione dei controlli incrociati

I controlli incrociati in SQX sono implementati come plugin e ogni controllo incrociato ha un metodo runTest() che eseguirà un controllo incrociato sulla strategia.

Una volta configurati i controlli incrociati, possiamo richiamare questo metodo per ogni controllo incrociato che vogliamo eseguire.

La creazione/configurazione del controllo incrociato è la sfida da affrontare e viene effettuata in un metodo secondario configuraControlli incrociati() - questo metodo restituisce un array di controlli incrociati, che vengono eseguiti uno per uno.

 

Esistono più modi per creare configurazioni di controllo incrociato, ma il più semplice sia per la programmazione che per l'uso normale è quello di lasciarle semplicemente creare dal formato XML che SQX memorizza. Questo è il metodo che utilizziamo qui.

 

Il codice di configuraControlli incrociati() e alcuni metodi secondari:

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

   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);
       }
       altrimenti {
           lancia una nuova eccezione ("Impossibile trovare il plugin di controllo incrociato '" + 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;
   }

 

Si può vedere che la configurazione del controllo incrociato è creata dal metodo createFromXml() che riceve un file XML come parametro. Questo file XML è la definizione del controllo incrociato dato.

Il metodo otterrà prima un clone del plugin per il rispettivo controllo incrociato chiamando getCrossCheckPlugin(nome del plugin)e poi chiama semplicemente readSettings(xml) sull'oggetto per inizializzarlo con le impostazioni dell'XML.

A questo punto, l'oggetto di configurazione Crosscheck è pronto per essere eseguito.

 

Nel nostro esempio stiamo creando tre controlli incrociati:

  • Retest con timeframe più alto
  • Manipolazione Monte Carlo con alcuni metodi selezionati
  • Test Monte Carlo con metodi selezionati

Abbiamo un file XML separato con la configurazione per ciascuno di essi.

 

Come preparare il file di configurazione XML del crosscheck

L'approccio più semplice consiste nell'utilizzare l'interfaccia utente SQX per configurare le impostazioni esatte del controllo incrociato che si desidera utilizzare nel progetto Builder o Retester.

Quindi salvare l'intero progetto Builder/Retester in un file .cfx. Questo file ha un'estensione .cfx, ma è un file ZIP standard che può essere aperto con WinZip o WinRar.

All'interno del file si trova config.xml: si tratta del documento XML che contiene le impostazioni per l'intero progetto.

Qui trovate la sezione <CrossChecks> e da qui copiare e incollare l'XML del controllo incrociato desiderato in un file separato che verrà poi caricato nel nostro snippet di analisi personalizzato.

 

Un esempio di file RetestWithHigherPrecision.xml:

2
    3
  
  <Impostazioni di accettazione
    
      
        
          
        
        =" />
        .
          
        
      
      
        
          
        
        =" />
        
          
        
      
      
        
          
        
        <Comparatore valore="

 

Un esempio di file MonteCarloManipulation.xml:

.
        
          resampling
        
      
      
        
          10
        
      
    
    10
    false

 

Un esempio di file MonteCarloRetest.xml:

.
        
          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
          true
          false
          true
          true
          true
          true
          true
          false
          false
          true
        
      
    
    10
    false
    -1

 

 

 

Esecuzione di controlli incrociati

Quando abbiamo gli oggetti di configurazione dei controlli incrociati pronti, eseguiamo i controlli incrociati semplicemente richiamando i loro oggetti runTest() metodo.

Codice:

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("Esecuzione del cross check %s per %s...", crossCheck.getName(), strategyName));

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

            if(!ccResult) {
                // togliere il commento se si vuole interrompere l'esecuzione di altri controlli incrociati se uno di essi non passa
                // altrimenti tutti i controlli incrociati vengono eseguiti sulla strategia
                //ritorno;
            }

        } catch(Exception e) {
            Log.error("Eccezione di controllo incrociato: " +e.getMessage(), e);
        }
    }
}

 

Esecuzione di questo frammento di analisi personalizzata

Quando si compila e si esegue questo snippet, il risultato è il seguente. Prende la prima strategia dalla banca dati, esegue il backtest di Man e i 3 controlli incrociati che abbiamo configurato su di essa e la salva come nuovo risultato nella banca dati.

Si può notare che il nuovo risultato contiene anche i risultati di Monte Carlo

 

 

Questo articolo è stato utile? L'articolo è stato utile L'articolo non è stato utile

Abbonarsi
Notificami
1 Commento
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
Emmanuel
25. 5. 2022 12:37 pm

Eccellente !!!! questo sarà molto utile
Grazie

Messaggi correlati