Documentation

Applications

Dernière mise à jour le 4. 8. 2021 par Mark Fric

Exemple - analyse personnalisée par stratégie

Le premier exemple sera une analyse personnalisée par stratégie. Ce n'est qu'une simple démonstration, mais elle montre comment utiliser les analyses personnalisées en conjonction avec les colonnes personnalisées de la banque de données.

Cet exemple permet d'obtenir les résultats suivants :

  • La méthode d'analyse personnalisée passe en revue les résultats enregistrés après les backtests de la stratégie et calcule le nombre de contrôles croisés utilisés.
  • Une nouvelle colonne personnalisée de la banque de données affiche alors ce nombre dans la banque de données.

 

Étape 1 - Créer un nouveau snippet d'analyse personnalisé

Ouvrir Éditeur de codecliquer sur Créer un nouveau et choisissez Analyse personnalisée (CA) tout en bas de la page. Nommez-le CAExampleStr.

Cela créera un nouveau snippet CAExampleStr.java dans le dossier Utilisateur/Snippets/SQ/Analyse personnalisée

Cet extrait se présente actuellement comme suit :

package SQ.CustomAnalysis ;

import com.strategyquant.lib.* ;

import java.util.ArrayList ;

import com.strategyquant.datalib.* ;
import 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 {
        return databankRG ;
    }
}

 

Comme vous pouvez le constater, il existe trois méthodes :

CAExampleStr()
un constructeur, les seules choses que vous devez définir ici sont le nom de votre méthode d'AC qui apparaîtra dans l'interface utilisateur, et le type.

Par défaut, le type est TYPE_FILTER_STRATEGY, ce qui signifie qu'il s'agit d'une méthode par stratégie.

D'autres options sont possibles :

TYPE_PROCESS_DATABANK - CA qui traitera l'ensemble de la banque de données, nous le montrerons dans un autre exemple.
TYPE_BOTH - AC qui possède des méthodes d'analyse à la fois par stratégie et par banque de données.

Le type d'analyse personnalisée détermine si cet extrait est affiché dans le choix par stratégie ou par banque de données.


filterStrategy()

Il s'agit d'une méthode qui est appelée pour chaque stratégie avant qu'elle ne soit sauvegardée dans la banque de données - si l'utilisation de l'analyse personnalisée est configurée. Elle récupère une stratégie dont les backtests et le crosscheck sont terminés (objet ResultsGroup) et doit renvoyer true/false.


processDatabank()
est une méthode qui est appelée pour traiter l'ensemble de la banque de données - elle reçoit en paramètre un tableau de tous les résultats de la stratégie (ResultsGroups) et renvoie un tableau de ResutsGroups.

Comme notre méthode ne s'applique qu'à une stratégie, nous n'avons pas besoin de processDatabank() et nous pouvons la supprimer de l'extrait.

 

Étape 2 - Mise en œuvre de la méthode filterStrategy()

Toute la "magie" sera faite en filterStrategy() nous allons ici compter le nombre de contrôles croisés qui ont été utilisés dans la stratégie. Comment procéder ?

Groupe de résultats est un objet qui contient la stratégie et tous les résultats de backtest + crosscheck pour la stratégie. Comme son nom l'indique, il s'agit d'un groupe de résultats stockés sous différentes clés.

Pour compter le nombre de contrôles croisés utilisés, nous devons passer en revue tous les résultats et vérifier si les résultats d'un contrôle croisé donné existent. Si ce n'est pas le cas, le contrôle croisé n'a pas été utilisé.

Pour compliquer les choses, certains résultats (par exemple Monte Carlo) sont stockés d'une manière particulière et nous devons donc déterminer leur utilisation différemment.

Au moment de la rédaction de cet article, il existe 8 contrôles croisés différents à la SQ :

  1. Et si les simulations
  2. Manipulation des opérations de Monte Carlo
  3. Plus grande précision du backtest
  4. Backtests sur des marchés supplémentaires
  5. Méthodes de retest de Monte Carlo
  6. profil / Sys. Param. Permutation
  7. Optimisation de la marche en avant
  8. Matrice de la marche en avant

Si vous configurez Retester pour qu'il effectue tous les contrôles croisés et que vous enregistrez ensuite toutes les clés et tous les résultats stockés dans ResultsGroup, vous obtiendrez ces clés :
Le portefeuille
Principal : EURUSD_M1/H1
CrossCheck_WhatIf
CrossCheck_HigherPrecision
Marché additionnel : GBPUSD_M1/H1
Marché additionnel : USDJPY_M1/H1
WF : 10 runs : 20 % OOS
WF : 5 runs : 10 % OOS
...
WF : 15 runs : 40 % OOS
WF : 20 runs : 40 % OOS

Notez que le nombre réel de clés dépend également de la configuration des contrôles croisés à venir. Par exemple, chaque backtest supplémentaire est stocké sous sa propre clé, et il en va de même pour les séries WF + les combinaisons OOS.

Comme il y avait quelques marchés supplémentaires, il y a aussi une clé spéciale Portefeuille qui contient les résultats pour le portefeuille des backtests principaux et supplémentaires.

Notez également qu'il n'y a pas de touches pour Monte Carlo ou Profil opt. Param. ils sont stockés d'une autre manière que nous expliquerons plus loin.

 

Étape 3 - Comptage des chèques croisés "simples

Par simple, nous entendons les contrôles croisés qui stockent leurs résultats sous la forme de clés différentes dans le fichier Groupe de résultats objets.

Dans ce cas, il est simple de déterminer si le contrôle croisé a été utilisé. filterStrategy() se présenterait comme suit :

public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        List keys = rg.getResultKeys() ;
        
        int crosschecksCount = 0 ;
        boolean additionalMarketUsed = false ;
        int wfCount = 0 ;
        
        for(int i=0 ; i 1) {
            // contient une matrice de marche avant
            crosschecksCount++ ;
            
            // c'est délicat, lorsque la matrice WF a été exécutée, nous ne pouvons pas déterminer
            // si une seule optimisation de la marche en avant a également été exécutée,
            // nous la comptons donc également
            crosschecksCount++ ;
        }

        // contient des manipulations de transactions Monte Carlo
        // contient les méthodes de retest de Monte Carlo
        // contient le profil Opt. / Sys. Param. Permutation
        // A FAIRE
        ...

Détermination de l'utilisation des Et si et Plus grande précision Les contrôles croisés sont faciles - il suffit de vérifier si la liste des clés contient la constante.

Détermination de l'utilisation des Backtests sur des marchés supplémentaires est similaire, nous devons seulement être conscients que chaque backtest supplémentaire est stocké avec sa propre clé.

Détermination de l'utilisation des Optimisation de la marche en avant et Matrice est également simple, nous allons simplement vérifier le nombre (s'il y en a) de clés avec le préfixe "WF :"

Le seul point délicat est que si Matrice de la marche en avant a été utilisé, nous ne sommes pas en mesure de reconnaître si un seul Optimisation de la marche en avant a été utilisé, car il utilise la même clé pour stocker son résultat.

Notre Nombre de vérifications croisées La variable contient maintenant le nombre réel de ces contrôles croisés utilisés, à l'exception de Monte Carlo et Profil Opt. des recoupements que nous reconnaîtrons à l'étape suivante.

 

Étape 4 - Reconnaître l'utilisation d'un contrôle croisé "spécial

Comme indiqué précédemment, Monte Carlo et Profil opt. / Sys. Param. Permutation les résultats sont stockés d'une manière particulière.

Au lieu de les enregistrer sous leur propre clé dans ResultsGroup, ils sont stockés dans des objets spéciaux dans le résultat principal.

Nous pouvons déterminer si la manipulation Monte Carlo des résultats de la vérification croisée a été utilisée de cette manière :

// obtenir le résultat principal, c'est là que les simulations de Monte Carlo sont stockées
Résultat mainResult = rg.mainResult() ;
        
if(mainResult.getInt("MonteCarloManipulation_NumberOfSimulations") > 0) {
// contient le résultat de la manipulation des opérations de Monte Carlo
        crosschecksCount++ ;
}

Main result est le résultat principal du backtest, c'est ici que les résultats MC sont stockés. Nous essayons simplement d'obtenir un nombre de simulations MC, et s'il est supérieur à 0, nous savons qu'il contient des résultats de manipulations MC.

Nous pouvons vérifier l'utilisation de Monte Carlo retest crosscheck de la même manière :

if(mainResult.getInt("MonteCarloRetest_NumberOfSimulations") > 0) {
    // contient le résultat de la manipulation des transactions Monte Carlo
    crosschecksCount++ ;
}

Le dernier point à vérifier est le profil Opt. Param. Permutation. Il est stocké dans son propre objet dans ResutsGroup, nous allons simplement vérifier si l'objet existe :

if(rg.getOptimizationProfile() != null) {
        // contient le profil Opt. / Sys. Param. Résultat de la permutation
        crosschecksCount++ ;
    }

 

Étape 5 - Enregistrer le décompte des résultats de la stratégie

Maintenant que nous disposons du nombre de contrôles croisés utilisés, nous voulons l'afficher dans une nouvelle colonne de la banque de données (qui sera créée ultérieurement).

Pour l'instant, le nombre de contrôles croisés est enregistré dans une variable crosschecksCount, mais nous devons l'enregistrer en tant que donnée personnalisée dans ResultsGroup, afin que l'extrait de colonne de la banque de données puisse l'extraire lorsqu'il affichera sa valeur.

Heureusement, c'est assez simple - nous pouvons enregistrer n'importe quel objet dans les valeurs spéciales de ResultsGroup en appelant :

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

dans notre cas :

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

Nous récupérerons cette valeur à l'étape suivante pour l'afficher dans la banque de données.

En dernier lieu, nous renverrons true car nous n'utiliserons pas cette analyse personnalisée pour le filtrage.


Note -
Si vous souhaitez utiliser une analyse personnalisée pour le filtrage, il vous suffira de renvoyer un vrai ou un faux dans cette méthode en fonction des calculs des backtests de la stratégie et, en fonction de cela, la stratégie sera rejetée ou enregistrée dans la banque de données.

Le code complet de notre filterStrategy() est la méthode :

    @Override
public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
    List keys = rg.getResultKeys() ;
    
    int crosschecksCount = 0 ;
    boolean additionalMarketUsed = false ;
    int wfCount = 0 ;
    
    for(int i=0 ; i 1) {
        // contient des résultats de la matrice Walk-Forward
        crosschecksCount++ ;
        
        // c'est délicat, lorsque la matrice WF a été exécutée, nous ne pouvons pas déterminer
        // si une seule optimisation de la marche en avant a également été exécutée,
        // nous la comptons donc également
        crosschecksCount++ ;
    }

    // obtenir le résultat principal, c'est ici que les simulations de Monte Carlo sont stockées
    Résultat mainResult = rg.mainResult() ;
    
    if(mainResult.getInt("MonteCarloManipulation_NumberOfSimulations") > 0) {
        // contient le résultat de la manipulation des opérations de Monte Carlo
        crosschecksCount++ ;
    }

    if(mainResult.getInt("MonteCarloRetest_NumberOfSimulations") > 0) {
        // contient le résultat de la manipulation des transactions Monte Carlo
        crosschecksCount++ ;
    }
    
    if(rg.getOptimizationProfile() != null) {
        // contient le profil Opt. / Sys. Param. résultat de la permutation
        crosschecksCount++ ;
    }
    
    
    rg.specialValues().set("CA_NumberOfCrosschecks", crosschecksCount) ;
    
    return true ;
}

 

Étape 6 - Ajouter une nouvelle colonne de la banque de données

Nous avons calculé le nombre de contrôles croisés utilisés dans l'extrait d'analyse personnalisé et nous voulons maintenant l'afficher dans la banque de données. Pour ce faire, nous devons créer une nouvelle colonne dans la banque de données.

Cliquez à nouveau sur Créer un nouveau en Éditeur de code et créez cette fois une nouvelle colonne de la banque de données. Nommez-la Nombre de CC.

Le code par défaut de l'extrait de colonne de la banque de données ressemble à ceci :

package SQ.Columns.Databanks ;

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

public class NumberOfCC extends DatabankColumn {
    
  public NumberOfCC() {
    super("NumberOfCC",
          DatabankColumn.Decimal2, // format d'affichage de la valeur
          ValueTypes.Maximize, // si la valeur doit être maximisée / minimisée / approchée d'une valeur
          0, // valeur cible si l'approximation a été choisie
          0, // minimum moyen de cette valeur
          100) ; // moyenne du maximum de cette valeur
    
    setWidth(80) ; // largeur de colonne par défaut en pixels
    
    setTooltip("Votre info-bulle ici") ;
    
    /* Si cette nouvelle colonne dépend d'autres colonnes qui doivent être calculées en premier, mettez-les ici.
       Assurez-vous de ne pas créer de dépendance circulaire, comme A dépend de B et B dépend de A.
       Les colonnes (=valeurs statistiques) sont identifiées par le nom de la classe.)
    */
    //setDependencies("DrawdownPct", "NumberOfTrades") ;
  }
  
  //------------------------------------------------------------------------

  /**
   * Cette méthode doit renvoyer la valeur calculée de cette nouvelle colonne. Vous devriez typiquement la calculer à partir de la liste des commandes
   * ou à partir de valeurs statistiques déjà calculées (autres colonnes de la banque de données).
   */
  @Override
  public double compute(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception {
    
    /* un exemple - voici comment vous pouvez obtenir d'autres valeurs dont cette nouvelle valeur dépend */
    //int numberOfTrades = stats.getInt("NumberOfTrades") ;
    //double drawdownPct = stats.getDouble("DrawdownPct") ;
    
    /* un exemple - calculer le profit net à partir de la liste des transactions */
    double netProfit = 0 ;

    for(int i = 0 ; i<ordersList.size() ; i++) {
      Order order = ordersList.get(i) ;
      
      if(order.isBalanceOrder()) {
        // ne pas compter les ordres de solde (dépôts, retraits) en
        continuer ;
      }
      
      /* la méthode getPLByStatsType renvoie automatiquement PL en fonction du type de statistiques donné - en argent, % ou pips */
      double PL = getPLByStatsType(order, combination) ;
      
      netProfit += PL ;
    }

    /* arrondir et retourner la valeur. Elle sera sauvegardée dans les statistiques sous la clé "NumberOfCC" */
    return round2(netProfit) ;
  }
}

Il dispose d'un calculer() qui peut passer en revue les statistiques et les commandes pour calculer la mesure en question.

Dans notre cas, nous n'en avons pas besoin, nous n'utiliserons rien des commandes, mais nous récupérerons la valeur de CA_Nombre de chèques croisés que nous avons calculés dans l'analyse personnalisée.

Nous pouvons donc supprimer l'ensemble des calculer() et utiliser une méthode spéciale getValue() à la place. Celle-ci n'est pas générée par défaut, elle est utilisée pour récupérer des valeurs spéciales, par exemple le symbole et la période.

getValue() obtient le Groupe de résultats comme paramètre et renvoie une chaîne de caractères affichée dans la banque de données pour cette colonne.

Notre colonne de banque de données simplifiée se présente comme suit :

package SQ.Columns.Databanks ;

import com.strategyquant.lib.* ;
import com.strategyquant.datalib.* ;
import 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) {
      // cela signifie que la valeur n'a pas été définie
      return NOT_AVAILABLE ;
    } else {
      // renvoie la valeur convertie en chaîne de caractères
      return java.lang.Integer.toString(value) ;
    }
  }
}

 

Notez que nous avons utilisé un appel :

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

pour obtenir la valeur précédemment stockée par l'analyse personnalisée en tant que int (nombre).

La valeur -1 est la valeur par défaut, elle sera utilisée si aucune valeur n'est attribuée à la clé. CA_Nombre de chèques croisés sera trouvé. Cela se produira si nous ne configurons pas l'interface utilisateur pour qu'elle exécute notre méthode d'analyse personnalisée.

Dans ce cas, nous renverrons une chaîne de caractères sans objet.

 

Note spéciale sur le filtrage selon cette colonne

Parce que cette colonne de la banque de données est spéciale et que sa valeur est calculée par l'analyse personnalisée, elle NE PEUT PAS être utilisée dans les filtres personnalisés de Ranking. Cela ne fonctionnera pas car ces filtres sont évalués avant que l'analyse personnalisée ne soit lancée, et cette colonne n'aura alors aucune valeur.

Pour filtrer à l'aide de valeurs calculées par une analyse personnalisée, veuillez utiliser le retour vrai/faux de la fonction filterStrategy() dans l'extrait d'analyse personnalisé.

 

Étape 7 - Faire fonctionner l'ensemble

Après avoir compilé avec succès nos nouveaux snippets dans le fichier Éditeur de code et le redémarrage de StrategyQuant nous pouvons maintenant essayer de l'utiliser. Nous pouvons le faire dans Retester pour voir comment cela fonctionne.

Créez d'abord une nouvelle vue de la banque de données, nommons-la CA View et ajoutez quelques colonnes + notre nouvelle colonne Nombre de CC là.

Lorsque nous passerons à cette vue, nous verrons que notre nouvelle colonne est N/A :

C'est parce que la valeur affichée n'a pas encore été calculée.

Utilisons donc le nouveau snippet d'analyse personnalisé dans le fichier Retester - il suffit de le configurer dans l'onglet Classement comme suit :

Notre exemple d'extrait d'analyse personnalisée sera désormais appliqué à chaque stratégie retestée dans Retester avant d'être sauvegardée dans une banque de données.

Essayons donc d'activer certains contrôles croisés dans Retester et l'exécuter.

En fonction du nombre de contrôles croisés que vous avez sélectionnés, vous devriez maintenant voir un certain nombre dans la nouvelle colonne :

 

Conclusion

Il s'agit d'une simple démonstration de la nouvelle fonctionnalité d'analyse personnalisée appliquée par stratégie. Comme vous pouvez le constater :

  • il peut être utilisé pour calculer de nouvelles mesures qui dépassent les limites d'un backtest ou d'un crosscheck unique
  • il peut être utilisé pour mettre en œuvre de nouvelles mesures qui sont affichées dans la banque de données
  • il peut être utilisé pour le filtrage (en renvoyant false)

 

Cet article a-t-il été utile ? L'article était utile L'article n'était pas utile

S'abonner
Notification pour
5 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
tan8858
tan8858
21. 8. 2021 3:32 pm

Veuillez publier le code complet de l'étape 5 (mieux comme l'exemple de l'étape 6).
Dans mon éditeur de code, une erreur est signalée
"cannot find symbol symbol:class List location:class SQ.CustomAnalysis.CAExampleStr"

List keys = rg.getResultKeys() ;

Désolé, je suis nouveau dans ce domaine et je n'ai pas trouvé l'erreur.

Emmanuel
Répondre à  tan8858
26. 11. 2021 4:17 pm

Moi aussi, j'obtiens la même erreur.

Emmanuel
Répondre à  tan8858
26. 11. 2021 4:54 pm

Je pense qu'il faut ajouter : l'importation java.util.*;  
en haut du code
Il devrait fonctionner

tan8858
tan8858
Répondre à  Emmanuel
28. 11. 2021 10:00 am

Merci de votre attention !

Emmanuel
25. 11. 2021 20:59

Excellent !