Documentation

Applications

Dernière mise à jour le 16. 11. 2021 par Mark Fric

Exemple - par analyse personnalisée de la banque de données

Cet exemple concerne l'analyse personnalisée par banque de données. Contrairement à l'analyse personnalisée par stratégie qui ne traite qu'une seule stratégie, cet extrait d'AC s'exécute sur l'ensemble de la banque de données et peut accéder à tous les résultats de la stratégie dans une banque de données.

L'analyse personnalisée par banque de données ne peut être exécutée qu'à partir d'une tâche personnalisée dans le projet personnalisé.

Dans cet exemple, nous allons créer un exemple assez complexe de snippet d'analyse personnalisé qui construira un portefeuille à partir des résultats Walk-Forward des stratégies de la banque de données.
Il s'agit d'une demande formulée lors de notre première session de codage.

 

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

Ouvrez CodeEditor, cliquez sur Create new et choisissez l'option Custom analysis (CA) tout en bas. Nommez-la Portefeuille du PAM.

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

Cette fois-ci, nous le définirons comme suit TYPE_PROCESS_DATABANK dans le constructeur de la classe :

public WFPortfolio() {
    super("WFPortfolio", TYPE_PROCESS_DATABANK) ;
}

 

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

Cette autorité de certification appelle la méthode processDatabank() qui a 4 paramètres :

  • Projet de chaîne - nom du projet dans lequel la tâche de l'AC est placée
  • Tâche de la chaîne - nom de la tâche de l'AC
  • Chaîne Nom de la banque de données - nom de la banque de données sur laquelle le snippet de l'AC travaille
  • ArrayList databankRG - liste de toutes les stratégies (Groupes de résultats) de cette banque de données.

Elle renvoie également une liste ArrayList, qui ne doit contenir que les stratégies de la liste d'entrée qui doivent être conservées dans la banque de données.

De cette façon, elle peut être utilisée comme un filtre - vous pouvez passer en revue les stratégies de la liste databankRG et créer une nouvelle liste dans laquelle vous ne mettrez que celles qui correspondent à certains de vos critères. Les stratégies qui ne figurent pas dans la liste de sortie seront supprimées de la banque de données.

Dans notre cas, nous ne voulons pas supprimer quelque chose de la banque de données mais ajouter une nouvelle stratégie (notre portefeuille nouvellement créé). Nous allons voir comment procéder.

En résumé, le code fait ceci :

  • Crée un nouveau groupe de résultats pour le portefeuille - il sera vide au départ.
  • Il passe en revue toutes les stratégies de la banque de données et vérifie si elles ont un résultat WF. Si c'est le cas, il copiera ce résultat dans un nouveau portefeuille comprenant tous les ordres WF.
  • Calculer le résultat du portefeuille à partir des sous-résultats - par défaut, il n'est pas calculé à partir des résultats de la WF, nous devons donc le faire nous-mêmes dans le code.
  • Ajouter le ResultsGroup du portefeuille terminé à la banque de données

Le code est long et complexe, nous ne l'expliquerons pas entièrement ici. Il est présenté à la fin de cet article entièrement commenté.

 

Étape 3 - Exécution de notre extrait d'AC personnalisé

Pour exécuter un extrait d'AC "par banque de données", nous devons créer un projet personnalisé et une tâche personnalisée de type Analyse personnalisée.

Sélectionnez l'option Portefeuille du PAM dans la tâche personnalisée.

Tâche d'analyse personnalisée

 

Ajoutez ensuite quelques stratégies avec des résultats Walk-Forward à la banque de données Results et exécutez la tâche.

Il devrait créer une nouvelle stratégie nommée WF Equity portfolio qui contiendra les actions WF de toutes les stratégies de Results.

banque de données sur les actions du fm

et l'équité du portefeuille à partir de tous les résultats de la WF ressemble à ceci :

Fonds propres du portefeuille de la FMC

 

Code complet commenté de l'extrait

package SQ.CustomAnalysis;

import com.strategyquant.lib.*;

import java.util.ArrayList;

import com.strategyquant.tradinglib.*;
import com.strategyquant.tradinglib.project.ProjectEngine;
import com.strategyquant.tradinglib.results.SpecialValues;
import com.strategyquant.tradinglib.results.stats.comparator.OrderComparatorByOpenTime;

public class WFPortfolio extends CustomAnalysisMethod {

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    
    public WFPortfolio() {
        super("WFPortfolio", TYPE_PROCESS_DATABANK);
    }
    
    //------------------------------------------------------------------------
    
    @Override
    public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        return true;
    }
    
    //------------------------------------------------------------------------
    
    @Override
    public ArrayList<ResultsGroup> processDatabank(String project, String task, String databankName, ArrayList<ResultsGroup> databankRG) throws Exception {
        // create new ResultsGroup for our new portfolio
        ResultsGroup portfolioRG = new ResultsGroup("WF Equity portfolio");

        // get OrderList from new portfolio (empty so far),
        // we will insert WF orders there
        OrdersList portfolioOrdersList = portfolioRG.orders();

        // go through all strategy results in databank
        for(ResultsGroup strategyRG : databankRG) {

            // skip strategies whose name starts with "WF Equity portfolio"
            // this will ensure that we'll ignore our portfolios created
            // in previous runs
            String strName = strategyRG.getName();
            if(strName.startsWith("WF Equity portfolio")) {
                continue;
            }

            // get best Walk-Forward result from a strategy
            // If it doesn't exist it will return null
            Result wfResult = getWFResult(strategyRG);
            if(wfResult == null) {
                continue;
            }

            // ---------------------
            // wfResult is the best Walk-Forward result from existing strategy
            // clone it to a new result with all its settings

            String wfResultKey = wfResult.getResultKey();

            // we'll name the new subresult as "StrategyName "+ "existing WF result name"
            String newSubResultKey = String.format("%s-%s", strategyRG.getName(), wfResultKey);

            // clone settings to use them in the new result
            SettingsMap settingsMapCopy = wfResult.getSettings().clone();

            // create new result that will be added to the portfolio
            Result wfResultCopied = new Result(newSubResultKey, portfolioRG, settingsMapCopy);
            portfolioRG.addSubresult(newSubResultKey, settingsMapCopy, wfResultCopied);

            // ---------------------
            // copy WF orders from original strategy to new results group
            OrdersList filteredOL = strategyRG.orders().filterWithClone(wfResultKey, Directions.Both, SampleTypes.FullSample);
                
            for(int i=0; i<filteredOL.size(); i++) {
                Order order = filteredOL.get(i);
                
                // change setup name to match the new result name in the new portfolio
                order.SetupName = newSubResultKey;
                order.IsInPortfolio = 1;

                // add the order to the portfolio OrdersList
                portfolioOrdersList.add(order);
            }

            // copy also symbol definitions from old strategy
            // this is needed for proper cancullation of PL and metrics
            portfolioRG.symbols().add(strategyRG.symbols());
        }

        // ---------------------
        // compute portfolio result
        // normally we'd call portfolioRG.createPortfolioResult() but the default version
        // ignores WF results, so we have to implement it by ourselves
        createPortfolioResult(portfolioRG);


        // portfolio ResultsGroup is complete, now add it to the databank
        Databank databank = ProjectEngine.get(project).getDatabanks().get(databankName);
        databank.add(portfolioRG, true);

        return databankRG;
    }

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

    /**
     * returns best Walk-Forward result - if it exists
     */
    private Result getWFResult(ResultsGroup rg) throws Exception {
        String wfKey = rg.getBestWFResultKey();
        if(wfKey == null) {
            return null;
        }

        return rg.subResult(wfKey);
    }

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

    /**
     * creates a Portfolio result from all the existing sub-results in the ResultsGroup
     * This is function from standard SQ library, with only exception that this works
     * also on WF results - standard ResultsGroup.createPortfolioResult()
     * ignores WF results when creating portfolio.
     *
     * @param portfolioRG
     * @throws Exception
     */
    public void createPortfolioResult(ResultsGroup portfolioRG) throws Exception {
        Result firstResult = null;
        String tf = null;

        int resultsInPortfolio = 0;

        // go through all existing sub-results and get their initial capital and from-to dates
        for(String existingResultKey : portfolioRG.getResultKeys()) {
            Result result = portfolioRG.subResult(existingResultKey);
            resultsInPortfolio++;

            if(firstResult == null) {
                firstResult = result;
            }
        }

        if(resultsInPortfolio <= 1) {
            throw new Exception("ResultGroup doesn't contain more Results, cannot create a portfolio!");
        }

        if(firstResult == null) {
            throw new Exception("No Result in ResultGroup to create portfolio!");
        }

        SettingsMap settings = firstResult.getSettings();

        Result portfolioResult = new Result(ResultsGroup.Portfolio, portfolioRG, settings);
        portfolioRG.removeSubresult(ResultsGroup.Portfolio, true);
        portfolioRG.addSubresult(ResultsGroup.Portfolio, settings, portfolioResult);

        portfolioRG.specialValues().setString(SpecialValues.Symbol, ResultsGroup.Portfolio);
        portfolioRG.specialValues().setString(SpecialValues.Timeframe, "N/A");

        // for portfolio sort orders by their open time
        OrdersList ordersList = portfolioRG.orders();
        ordersList.sort(new OrderComparatorByOpenTime());

        // compute all metrics on the portfolio
        portfolioResult.computeAllStats(portfolioRG.specialValues(), portfolioRG.getOOS());
    }
}

 

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

S'abonner
Notification pour
3 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Emmanuel
25. 11. 2021 8:52 pm

Mark, merci beaucoup pour ce travail impressionnant ! !!!!! C'est exactement ce dont j'ai besoin ! !!!
SQX est vraiment unique.
Avec l'exemple, je pourrai construire une nouvelle idée.

Emmanuel
26. 11. 2021 11:53 am

Le code commenté complet est très utile

Emmanuel
26. 11. 2021 11:59 am

Cela fonctionne bien ! !!!!!! Nous vous remercions de votre attention.

Postes connexes