Documentation

Applications

Dernière mise à jour le 21. 7. 2022 par Mark Fric

Fusionner plusieurs résultats dans un portefeuille

Dans cet article, nous allons montrer comment StrategyQuant X gère les résultats des backtests, et comment nous pouvons les fusionner dans un portefeuille.

Cela peut déjà être fait dans SQX en sélectionnant plusieurs stratégies et en choisissant Le portefeuille -> Fusionner les stratégiesmais nous montrerons comment cela se fait sur le fond.

Il s'agit de la première partie d'une série multiple. Nous aimerions utiliser cette fonctionnalité pour déterminer si le trading peut être amélioré en sélectionnant un sous-ensemble particulier de stratégies à négocier - ce point sera examiné dans les prochains articles.

 

Il convient de noter que la fusion des portefeuilles signifie la fusion des résultats finaux des backtests en un seul portefeuille, et non la fusion des stratégies de négociation individuelles.

 

Cette fonctionnalité est à nouveau proposée sous la forme d'un extrait d'analyse personnalisée, dont l'extrait complet est joint à cet article.

 

Travailler avec des résultats de backtest - Objet ResultsGroup

Un petit rappel : dans SQX, tous les résultats de backtest sont stockés dans l'objet Result, et ils sont regroupés dans l'objet ResultsGroup.

RegultGroup est ce que vous voyez dans la banque de données - il peut contenir un ou plusieurs résultats - backtests de la stratégie sur le marché principal, les marchés supplémentaires, etc.

Il y a un article avec une introduction : Travailler avec ResultsGroup

 

Pour fusionner les résultats de plusieurs stratégies en un seul portefeuille, il faut

  • créer un nouvel objet ResultsGroup qui contiendra le portefeuille
  • parcourir l'objet ResultsGroup de chaque stratégie dans la banque de données
  • trouver le résultat principal - celui qui contient le backtest sur les données principales - c'est celui que nous allons fusionner
  • créer un nouvel objet Result pour cette stratégie et l'ajouter au portefeuille
  • cloner et copier les ordres du ResultsGroup d'origine vers le portefeuille
  • copier les symboles du ResultsGroup d'origine dans le portefeuille - ceci est nécessaire pour le calcul du PL, etc.
  • à la fin, créer un nouveau résultat de portefeuille et calculer toutes les statistiques

 

 

Code source complet de l'extrait

Le code est largement commenté, ce qui permet d'en suivre la logique.

Il créera deux nouveaux résultats de portefeuille - un créé par nous manuellement et un autre créé par la méthode SQX à des fins de comparaison.

 

package SQ.CustomAnalysis ;

import com.strategyquant.lib.SQUtils ;
import com.strategyquant.lib.SettingsMap ;
import com.strategyquant.lib.utils.IUniqueNameChecker ;
import com.strategyquant.tradinglib.* ;
import com.strategyquant.tradinglib.project.ProjectEngine ;
import com.strategyquant.tradinglib.results.SpecialValues ;
import com.strategyquant.tradinglib.results.stats.comparator.OrderComparatorByOpenTime ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;

import java.util.ArrayList ;

public class CAMergeStrategiesToPortfolio extends CustomAnalysisMethod {
    public static final Logger Log = LoggerFactory.getLogger("CAMergeStrategiesToPortfolio") ;

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

    public CAMergeStrategiesToPortfolio() {
        super("Fusionner les stratégies en portefeuille", TYPE_PROCESS_DATABANK) ;
    }

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

    @Override
    public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        return false ;
    }


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

    @Override
    public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception {
        if(databankRG.size() <= 1) {
            // s'il n'y a pas ou qu'une seule stratégie, il n'y a rien à fusionner
            return databankRG ;
        }

        // obtenir la banque de données cible pour sauvegarder le résultat final
        Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Portfolios") ;
        if(targetDatabank == null) {
            throw new Exception("Please create a new databank named 'Portfolios' !") ;
        }

        // ------------------------------
        // Création manuelle d'un portefeuille


        // Fusionner toutes les stratégies de la banque de données en un seul portefeuille
        ResultsGroup caPortfolio = mergeStrategiesToPortfolio(databankRG) ;

        // créer le résultat final du portefeuille pour additionner tous les sous-résultats
        createPortfolioResult(caPortfolio) ;

        // ajouter le nouveau portefeuille à notre banque de données cible
        targetDatabank.add(caPortfolio, false) ;


        // ------------------------------
        // Création d'un portefeuille de manière standard en appelant la méthode SQ - pour contrôle
        ResultsGroup standardPortfolio = ResultsGroup.merge(databankRG, new String[] { ResultsGroup.AdditionalMarket }, null) ;

        standardPortfolio.createPortfolioResult(PortfolioInitialBalanceTypes.SINGLE, null) ;

        targetDatabank.add(standardPortfolio, false) ;

        return databankRG ;
    }

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

    private ResultsGroup mergeStrategiesToPortfolio(ArrayList databankRG) throws Exception {
        ResultsGroup caPortfolio = new ResultsGroup("PortfolioMadeByCA") ;

        // ajoute des stratégies individuelles au portefeuille
        for(ResultsGroup rg : databankRG) {
            addResult(caPortfolio, rg) ;
        }

        addSymbolsMap(caPortfolio, databankRG) ;

        return caPortfolio ;
    }

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

    private void addSymbolsMap(ResultsGroup rgCSPortfolio, ArrayList databankRG) {
        for(ResultsGroup rg : databankRG) {
            // ajoute tous les symboles des groupes de résultats fusionnés à la carte des symboles du portefeuille
            rgCSPortfolio.symbols().add(rg.symbols()) ;
        }
    }

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

    private void addResult(ResultsGroup caPortfolio, ResultsGroup rg) throws Exception {

        // créer d'abord un nouveau résultat pour RG dans notre nouveau portefeuille
        // newResultKey sera retourné comme clé de résultat utilisée dans notre portefeuille
        String newResultKey = mergeResult(caPortfolio, rg) ;

        // cloner et copier les ordres pour ces résultats de RG vers le portefeuille
        copyOrdersToPortfolio(caPortfolio, rg, newResultKey) ;

        // ajouter toutes les données des symboles du RG fusionné à la carte des symboles du portefeuille - ceci est nécessaire pour le calcul du PL, etc.
        caPortfolio.symbols().add(rg.symbols()) ;
    }

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

    private String mergeResult(ResultsGroup caPortfolio, ResultsGroup rg) throws Exception {
        // récupère le résultat principal de la stratégie actuelle - c'est celui que nous allons fusionner
        Résultat rgMainResult = rg.mainResult() ;
        String mainResultKey = rgMainResult.getResultKey() ;

        // déterminer la nouvelle clé de résultat - elle doit être unique et nous devons donc vérifier
        // s'il n'y a pas déjà un résultat avec cette clé dans notre portefeuille
        String newResultKey = rg.getName() ;

        if(caPortfolio.hasResult(newResultKey)) {
            // la même clé existe déjà, nous devons trouver une nouvelle clé
            newResultKey = SQUtils.generateUniqueName(mainResultKey, new IUniqueNameChecker() {
                public boolean checkNameExist(String name) throws Exception {
                    return caPortfolio.hasResult(name) ;
                }
            }) ;
        }

        // créer un résultat fusionné
        SettingsMap copiedSettingsMap = rgMainResult.getSettings().clone() ;

        // créer un nouveau résultat fusionné et l'ajouter à notre portefeuille
        Result mergedResult = new Result(newResultKey, caPortfolio, copiedSettingsMap) ;
        caPortfolio.addSubresult(newResultKey, copiedSettingsMap, mergedResult) ;

        // définir le symbole et l'horizon temporel de la stratégie fusionnée
        mergedResult.setString(SpecialValues.Symbol, rg.mainResult().getString(SpecialValues.Symbol)) ;
        mergedResult.setString(SpecialValues.Timeframe, rg.mainResult().getString(SpecialValues.Timeframe)) ;

        long rgDateFrom = rg.specialValues().getLong(SpecialValues.HistoryFrom, Long.MAX_VALUE) ;
        long rgDateTo = rg.specialValues().getLong(SpecialValues.HistoryTo, Long.MIN_VALUE) ;

        long caDateFrom = caPortfolio.specialValues().getLong(SpecialValues.PortfolioHistoryFrom, Long.MAX_VALUE) ;
        long caDateTo = caPortfolio.specialValues().getLong(SpecialValues.PortfolioHistoryTo, Long.MIN_VALUE) ;

        caPortfolio.specialValues().set(SpecialValues.HistoryFrom, Math.min(rgDateFrom, caDateFrom)) ;
        caPortfolio.specialValues().set(SpecialValues.HistoryTo, Math.max(rgDateTo, caDateTo)) ;
        copiedSettingsMap.set(SettingsKeys.PortfolioDataStart, Math.min(rgDateFrom, caDateFrom)) ;
        copiedSettingsMap.set(SettingsKeys.PortfolioDataEnd, Math.max(rgDateTo, caDateTo)) ;

        return newResultKey ;
    }

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

    private void copyOrdersToPortfolio(ResultsGroup caPortfolio, ResultsGroup rg, String newResultKey) throws Exception {
        // récupère la liste des commandes de notre portefeuille actuel
        OrdersList mergedOrdersList = caPortfolio.orders() ;

        // récupère tous les ordres du résultat de la stratégie de fusion - notez qu'ils doivent être clonés !
        String mainResultKey = rg.mainResult().getResultKey() ;
        OrdersList filteredOL = rg.orders().filterWithClone(mainResultKey, Directions.Both, SampleTypes.FullSample) ;

        // ne pas parcourir ces ordres et les ajouter à la liste des ordres du portefeuille
        for(int i=0 ; i<filteredOL.size() ; i++) {
            Ordre = filteredOL.get(i) ;

            // order.SetupName est utilisé comme identifiant afin que nous sachions à quel résultat l'ordre appartient
            // il faut donc lui attribuer la valeur newResultKey
            order.SetupName = newResultKey ;

            mergedOrdersList.add(order) ;
        }
    }

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

    private void createPortfolioResult(ResultsGroup caPortfolio) throws Exception {

        SettingsMap settings = caPortfolio.mainResult().getSettings() ;

        Result portfolioResult = new Result(ResultsGroup.Portfolio, caPortfolio, settings) ;

        caPortfolio.removeSubresult(ResultsGroup.Portfolio, true) ;

        caPortfolio.addSubresult(ResultsGroup.Portfolio, settings, portfolioResult) ;

        caPortfolio.specialValues().setString(SpecialValues.Symbol, ResultsGroup.Portfolio) ;

        // pour le portefeuille, trier les ordres en fonction de leur heure d'ouverture
        OrdersList ordersList = caPortfolio.orders() ;
        ordersList.sort(new OrderComparatorByOpenTime()) ;

        portfolioResult.computeAllStats(caPortfolio.specialValues(), caPortfolio.getOOS()) ;

        caPortfolio.updated = true ;
    }

}

 

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

S'abonner
Notification pour
1 Commentaire
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Emmanuel
21. 7. 2022 12:14 pm

Excellent exemple ! Exactement ce dont j'avais besoin ! Merci Mark

Postes connexes