Documentazione

Applicazioni

Ultimo aggiornamento il 4. 8. 2021 da Mark Fric

Esempio - analisi personalizzata per strategia

Come primo esempio realizzeremo un'analisi personalizzata per strategia. Si tratta solo di una semplice dimostrazione, ma mostra come utilizzare le analisi personalizzate anche in combinazione con le colonne personalizzate della banca dati.

L'esempio prevede le seguenti operazioni:

  • Il metodo di analisi personalizzato analizza i risultati memorizzati dopo i backtest della strategia e calcola il numero di controlli incrociati utilizzati.
  • Una nuova colonna personalizzata della banca dati visualizza questo numero nella banca dati.

 

Passo 1 - Creare un nuovo snippet di analisi personalizzato

Aperto Editor di codice, fare clic su Creare un nuovo e scegliere Analisi personalizzata (CA) in fondo alla pagina. Nome CAExampleStr.

Questo creerà un nuovo snippet CAExampleStr.java in cartella Utente/Snippet/SQ/Analisi personalizzata

Questo snippet attualmente si presenta come segue:

pacchetto SQ.CustomAnalysis;

importare com.strategyquant.lib.*;

importare java.util.ArrayList;

importare com.strategyquant.datalib.*;
importare com.strategyquant.tradinglib.*;

public class CAExampleStr extends CustomAnalysisMethod {

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    
    public CAExampleStr() {
        super("CAExampleStr", TYPE_FILTER_STRATEGY);
    }
    
    //------------------------------------------------------------------------
    
    @Override
    public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        return true;
    }
    
    
    //------------------------------------------------------------------------
    
    @Override
    public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception {
        restituisce databankRG;
    }
}

 

Come si può vedere, ha tre metodi:

CAExampleStr()
un costruttore, le uniche cose da impostare qui sono il nome del metodo CA che apparirà nell'interfaccia utente e il tipo.

Per impostazione predefinita, il tipo è TYPE_FILTER_STRATEGY, il che significa che si tratta di un metodo per strategia.

Altre opzioni possibili sono:

TYPE_PROCESS_DATABANK - CA che elabora l'intera banca dati; la mostreremo in un altro esempio.
TYPE_BOTH - CA che dispone di metodi di analisi sia per strategia che per banca dati.

Il tipo di analisi personalizzata determina se questo frammento viene mostrato nella scelta per strategia o per banca dati.


strategia di filtraggio()

è un metodo che viene richiamato per ogni strategia prima che venga salvata nella banca dati, se è configurato l'uso dell'analisi personalizzata. Otterrà una strategia con backtest e controlli incrociati completati (oggetto ResultsGroup) e dovrà restituire true/false.


elaboraBancaDati()
è un metodo che viene chiamato per elaborare l'intera banca dati: riceve come parametro un array di tutti i risultati della strategia (ResultsGroups) e restituisce un array di ResutsGroups.

Poiché il nostro metodo è solo per strategia, non abbiamo bisogno di elaboraBancaDati() e possiamo eliminarlo dallo snippet.

 

Passo 2 - Implementare il metodo filterStrategy()

Tutta la "magia" sarà fatta in strategia di filtraggio() qui conteremo il numero di controlli incrociati che sono stati utilizzati nella strategia. Come fare?

Gruppo di risultati è un oggetto che contiene la strategia e tutti i risultati dei backtest e delle verifiche incrociate per la strategia. Come suggerisce il nome, si tratta di un gruppo di risultati memorizzati sotto varie chiavi.

Per contare quanti controlli incrociati sono stati utilizzati, dobbiamo esaminare tutti i risultati e verificare se esistono i risultati di un determinato controllo incrociato. In caso contrario, il controllo incrociato non è stato utilizzato.

Per complicare le cose, alcuni risultati (ad esempio quelli di Monte Carlo) sono memorizzati in modo speciale, quindi dobbiamo determinare il loro utilizzo in modo diverso.

Al momento della stesura di questo articolo sono presenti 8 diversi controlli incrociati in SQ:

  1. E se le simulazioni
  2. Manipolazione dei trade Monte Carlo
  3. Maggiore precisione nei backtest
  4. Backtest su altri mercati
  5. Metodi di retest Monte Carlo
  6. profilo / Sistema. Param. Permutazione
  7. Ottimizzazione Walk-Forward
  8. Matrice di avanzamento

Se si configura Retester per eseguire tutti i controlli incrociati e si registrano tutte le chiavi e i risultati memorizzati in ResultsGroup, si otterranno queste chiavi:
Portafoglio
Principale: EURUSD_M1/H1
Controllo incrociato_CosaSe
CrossCheck_HigherPrecision
Mercato aggiuntivo: GBPUSD_M1/H1
Mercato aggiuntivo: USDJPY_M1/H1
WF: 10 corse: 20 % OOS
WF: 5 corse: 10 % OOS
...
WF: 15 corse: 40 % OOS
WF: 20 corse: 40 % OOS

Si noti che il numero effettivo di chiavi dipende anche dalla configurazione dei controlli incrociati. Ad esempio, ogni backtest aggiuntivo viene memorizzato sotto una propria chiave, lo stesso vale per le combinazioni WF runs + OOS.

Poiché erano presenti alcuni mercati aggiuntivi, esiste anche una chiave speciale Portfolio che contiene i risultati del portafoglio dei backtest principali + aggiuntivi.

Si noti inoltre che non ci sono tasti per Monte Carlo o Profilo ottico/Parametri di sistema. Param. I risultati delle permutazioni sono memorizzati in un altro modo, che spiegheremo più avanti.

 

Fase 3 - Conteggio di assegni incrociati "semplici

Per semplici si intendono i controlli incrociati che memorizzano i loro risultati come chiavi diverse in Gruppo di risultati oggetti.

Determinare se il controllo incrociato è stato utilizzato è semplice in questo caso, il codice per strategia di filtraggio() sarebbe così:

public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        List keys = rg.getResultKeys();
        
        int crosscheckCount = 0;
        booleano additionalMarketUsed = false;
        int wfCount = 0;
        
        for(int i=0; i 1) {
            // contiene la matrice Walk-Forward
            crosscheckCount++;
            
            // questo è complicato, quando la matrice WF è stata eseguita non possiamo determinare
            // se è stata eseguita anche una singola ottimizzazione Walk-Forward,
            // quindi la conteremo come tale
            crosschecksCount++;
        }

        // contiene la manipolazione degli scambi Monte Carlo
        // contiene metodi di retest Monte Carlo
        // contiene il profilo Opt. / Sys. Param. Permutazione
        // DA FARE
        ...

Determinare l'utilizzo di Cosa succede se e Maggiore precisione I controlli incrociati sono semplici: si controlla solo se l'elenco delle chiavi contiene la costante.

Determinare l'utilizzo di Backtest su altri mercati è simile, dobbiamo solo essere consapevoli che ogni backtest aggiuntivo è memorizzato con la propria chiave.

Determinare l'utilizzo di Ottimizzazione Walk-Forward e Matrice è altrettanto semplice, basterà controllare il numero (se esiste) di chiavi con prefisso "WF:".

L'unica cosa complicata è che se Matrice di avanzamento è stato usato un controllo incrociato, allora non siamo in grado di riconoscere se anche il singolo Ottimizzazione Walk-Forward perché utilizza la stessa chiave per memorizzare il risultato.

Il nostro controlli incrociatiConteggio La variabile contiene ora il numero reale di questi controlli incrociati utilizzati, ad eccezione di Monte Carlo e Profilo ottico controlli incrociati che verranno riconosciuti nella fase successiva.

 

Fase 4 - Riconoscere l'uso di un controllo incrociato "speciale

Come detto in precedenza, Monte Carlo e Profilo ottico / Sistema. Param. Permutazione i risultati vengono memorizzati in modo speciale.

Invece di salvarli sotto la propria chiave in ResultsGroup, vengono memorizzati in oggetti speciali nel risultato principale.

Possiamo determinare se la manipolazione Monte Carlo dei risultati del controllo incrociato è stata utilizzata in questo modo:

// otteniamo il risultato principale, dove vengono memorizzate le simulazioni Monte Carlo
Risultato mainResult = rg.mainResult();
        
if(mainResult.getInt("MonteCarloManipulation_NumberOfSimulations") > 0) {
// contiene il risultato della manipolazione Monte Carlo
        crosscheckCount++;
}

Main result è il risultato principale del backtest; qui vengono memorizzati i risultati MC. Cerchiamo semplicemente di ottenere un numero di simulazioni MC e se è maggiore di 0 sappiamo che contiene alcuni risultati di manipolazione MC.

È possibile verificare l'utilizzo di Monte Carlo retest crosscheck in modo analogo:

if(mainResult.getInt("MonteCarloRetest_NumberOfSimulations") > 0) {
    // contiene il risultato della manipolazione delle operazioni Monte Carlo
    crosscheckCount++;
}

L'ultimo da controllare è Opt. profilo / Sys. Param. Permutazione. È memorizzato in un proprio oggetto in ResutsGroup; controlleremo semplicemente se l'oggetto esiste:

if(rg.getOptimizationProfile() != null) {
        // contiene il profilo Opt. / Sys. Param. Risultato della permutazione
        crosscheckCount++;
    }

 

Fase 5 - Salvare il conteggio dei risultati della strategia

Ora che abbiamo il conteggio dei controlli incrociati utilizzati, vogliamo visualizzarlo in una nuova colonna della banca dati (che verrà creata in seguito)

Al momento, il numero di controlli incrociati è salvato in una variabile crosscheckCount, ma è necessario salvarlo come dato personalizzato in ResultsGroup, in modo che lo snippet di colonne della banca dati possa recuperarlo quando ne visualizzerà il valore.

Fortunatamente, questo è abbastanza semplice: possiamo salvare qualsiasi oggetto nei valori speciali di ResultsGroup chiamando:

rg.specialValues().set(String key, Object value);

nel nostro caso:

rg.specialValues().set("CA_NumberOfCrosschecks", crosscheckCount);

Nel prossimo passo recupereremo questo valore per visualizzarlo nella banca dati.

Come ultima cosa, restituiremo true perché non utilizzeremo questa analisi personalizzata per il filtraggio.


Nota -
Se si desidera utilizzare un'analisi personalizzata per il filtraggio, il metodo restituisce semplicemente true o false in base ai calcoli dei backtest della strategia e in base a ciò la strategia viene eliminata o salvata nella banca dati.

Quindi il codice completo del nostro strategia di filtraggio() è il metodo:

    @Override
public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
    List keys = rg.getResultKeys();
    
    int crosscheckCount = 0;
    booleano additionalMarketUsed = false;
    int wfCount = 0;
    
    for(int i=0; i 1) {
        // contiene i risultati della matrice Walk-Forward
        crosscheckCount++;
        
        // questo è complicato, quando è stata eseguita la matrice WF non possiamo determinare
        // se è stata eseguita anche una singola ottimizzazione Walk-Forward,
        // quindi la conteremo anche in questo caso
        crosschecksCount++;
    }

    // otteniamo il risultato principale, dove vengono memorizzate le simulazioni di Monte Carlo
    Risultato mainResult = rg.mainResult();
    
    if(mainResult.getInt("MonteCarloManipulation_NumberOfSimulations") > 0) {
        // contiene il risultato della manipolazione Monte Carlo
        crosscheckCount++;
    }

    if(mainResult.getInt("MonteCarloRetest_NumberOfSimulations") > 0) { // contiene il risultato della manipolazione dei trade Monte Carlo.
        // contiene il risultato della manipolazione delle operazioni Monte Carlo
        crosschecksCount++;
    }
    
    if(rg.getOptimizationProfile() != null) {
        // contiene il profilo di ottimizzazione / Sys. Param. Risultato della permutazione
        crosscheckCount++;
    }
    
    
    rg.specialValues().set("CA_NumberOfCrosschecks", crosschecksCount);
    
    restituisce true;
}

 

Passo 6 - Aggiungere una nuova colonna della banca dati

Abbiamo calcolato il numero di controlli incrociati utilizzati nello snippet di analisi personalizzato e ora vogliamo visualizzarlo nel database. Per farlo, è necessario creare una nuova colonna del database.

Di nuovo, fare clic su Creare un nuovo in Editor di codice e questa volta creare una nuova colonna della banca dati. Nominarla Numero di CC.

Il codice predefinito per lo snippet di colonne della banca dati si presenta così:

pacchetto SQ.Columns.Databanks;

importare com.strategyquant.lib.*;
importare com.strategyquant.datalib.*;
importare com.strategyquant.tradinglib.*;

public class NumberOfCC extends DatabankColumn {
    
  public NumberOfCC() {
    super("NumberOfCC",
          DatabankColumn.Decimal2, // formato di visualizzazione del valore
          ValueTypes.Maximize, // se il valore deve essere massimizzato / minimizzato / approssimato a un valore
          0, // valore target se è stata scelta l'approssimazione
          0, // minimo medio di questo valore
          100); // massimo medio di questo valore
    
    setWidth(80); // larghezza predefinita della colonna in pixel
    
    setTooltip("Il vostro tooltip qui");
    
    /* Se questa nuova colonna dipende da altre colonne che devono essere calcolate prima, inserirle qui.
       Assicurarsi di non creare dipendenze circolari, come ad esempio A dipende da B e B dipende da A.
       Le colonne (=valori statistici) sono identificate dal nome della classe)
    */
    //setDependencies("DrawdownPct", "NumberOfTrades");
  }
  
  //------------------------------------------------------------------------

  /**
   * Questo metodo deve restituire il valore calcolato di questa nuova colonna. In genere si dovrebbe calcolarlo dall'elenco degli ordini
   * o da alcuni valori statistici già calcolati (altre colonne della banca dati).
   */
  @Override
  public double compute(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception {
    
    /* un esempio: ecco come ottenere altri valori da cui dipende questo nuovo valore */
    //int numberOfTrades = stats.getInt("NumberOfTrades");
    //double drawdownPct = stats.getDouble("DrawdownPct");
    
    /* un esempio: calcolare il profitto netto dall'elenco dei trade */
    double netProfit = 0;

    for(int i = 0; i<ordersList.size(); i++) {
      Ordine = ordersList.get(i);
      
      if(order.isBalanceOrder()) {
        // non contare gli ordini di saldo (depositi, prelievi) in
        continuare;
      }
      
      /* il metodo getPLByStatsType restituisce automaticamente il PL a seconda del tipo di statistiche date - in denaro, % o pips */
      double PL = getPLByStatsType(ordine, combinazione);
      
      netProfit += PL;
    }

    /* arrotonda e restituisce il valore. Verrà salvato nelle statistiche sotto la chiave "NumberOfCC" */
    return round2(netProfit);
  }
}

Ha un calcolo() che può esaminare le statistiche e gli ordini per calcolare la metrica specifica.

Nel nostro caso non ne abbiamo bisogno, non useremo nulla dagli ordini, ma recupereremo il valore di CA_Numero di assegni incrociati che abbiamo calcolato nell'analisi personalizzata.

Quindi possiamo cancellare l'intero file calcolo() e utilizzare un metodo speciale getValue() invece. Questo non viene generato per impostazione predefinita, ma viene utilizzato per recuperare valori speciali, ad esempio il simbolo e il timeframe.

getValue() ottiene il Gruppo di risultati come parametro e restituisce una stringa che viene visualizzata nella banca dati per questa colonna.

La colonna della nostra banca dati semplificata si presenta così:

pacchetto SQ.Columns.Databanks;

importare com.strategyquant.lib.*;
importare com.strategyquant.datalib.*;
importare com.strategyquant.tradinglib.*;

public class NumberOfCC extends DatabankColumn {
    
  public NumberOfCC() {
    super("NumberOfCC", DatabankColumn.Decimal2, ValueTypes.Maximize, 0, 0, 100);
  }
  
  //------------------------------------------------------------------------
  
  @Override
  public String getValue(ResultsGroup rg, String resultKey, byte direction, byte plType, byte sampleType) throws Exception {
    int value = rg.specialValues().getInt("CA_NumberOfCrosschecks", -1);
    
    if(value == -1) {
      // significa che il valore non è stato impostato
      restituire NOT_AVAILABLE;
    } else {
      // restituisce il valore convertito in stringa
      return java.lang.Integer.toString(valore);
    }
  }
}

 

Si noti che abbiamo utilizzato una chiamata:

rg.specialValues().getInt("CA_NumberOfCrosschecks", -1);

per ottenere il valore precedentemente memorizzato dall'analisi personalizzata come int (numero).

Il valore -1 è quello predefinito, sarà usato se non c'è un valore per la chiave CA_Numero di assegni incrociati verrà trovato. Questo accade se non si configura l'interfaccia utente per eseguire il metodo di analisi personalizzato.

In questo caso restituiremo la stringa N/A.

 

Nota speciale sul filtraggio secondo questa colonna

Poiché questa colonna della banca dati è speciale e il suo valore viene calcolato dall'analisi personalizzata, non può essere utilizzata nei filtri personalizzati di Ranking. Non funzionerà perché questi filtri vengono valutati prima dell'avvio dell'analisi personalizzata e la colonna non avrà alcun valore.

Per filtrare utilizzando i valori calcolati dall'analisi personalizzata, utilizzare il ritorno vero/falso del comando strategia di filtraggio() nello snippet di analisi personalizzato.

 

Fase 7 - Far funzionare il tutto

Dopo aver compilato con successo i nostri nuovi snippet in Editor di codice e riavvio di StrategyQuant possiamo ora provare a usarlo. Possiamo farlo in Retester per vedere come funziona.

Per prima cosa creare una nuova vista della banca dati, chiamandola CA View e aggiungendo alcune colonne + la nostra nuova colonna Numero di CC lì.

Quando passiamo a questa vista, vedremo che la nostra nuova colonna è N/D:

È perché il valore visualizzato non è ancora stato calcolato.

Utilizziamo quindi il nuovo snippet di analisi personalizzato nel file Ritestatore - è sufficiente configurare la scheda Classificazione come segue:

Il nostro esempio di snippet di analisi personalizzata verrà ora applicato a ogni strategia ritestata in Retester prima di essere salvata in una banca dati.

Proviamo quindi ad attivare alcuni controlli incrociati in Ritestatore ed eseguirlo.

A seconda del numero di controlli incrociati effettivamente selezionati, si dovrebbe vedere un numero nella nuova colonna:

 

Conclusione

Si tratta di una semplice dimostrazione della nuova funzionalità di analisi personalizzata applicata per strategia. Come si può vedere:

  • può essere utilizzato per calcolare nuove metriche che superano i confini di un singolo backtest o di un crosscheck
  • può essere utilizzato per implementare nuove metriche che vengono visualizzate nella banca dati
  • può essere utilizzato per il filtraggio (restituendo false)

 

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

Abbonarsi
Notificami
5 Commenti
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
tan8858
tan8858
21. 8. 2021 3:32 pm

Si prega di rilasciare il codice completo per il passo 5 (meglio come il passo 6 Esempio)
Nel mio editor di codice, riporta un errore
"Impossibile trovare il simbolo simbolo:classe Elenco posizione:classe SQ.CustomAnalysis.CAExampleStr"

List keys = rg.getResultKeys();

Scusate, sono nuovo e non sono riuscito a trovare l'errore.

Emmanuel
Rispondi a  tan8858
26. 11. 2021 4:17 pm

Anch'io ricevo lo stesso errore.

Emmanuel
Rispondi a  tan8858
26. 11. 2021 4:54 pm

Credo che sia necessario aggiungere : Importazione java.util.*;  
all'inizio del codice
Dovrebbe funzionare

tan8858
tan8858
Rispondi a  Emmanuel
28. 11. 2021 10:00

Grazie!

Emmanuel
25. 11. 2021 ore 20:59

Eccellente!