Documentation
Applications
Dernière mise à jour le 16. 11. 2021 par Mark Fric
Exemple - par analyse personnalisée de la banque de données
Contenu des pages
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.
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.
et l'équité du portefeuille à partir de tous les résultats de la WF ressemble à ceci :
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
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.
Le code commenté complet est très utile
Cela fonctionne bien ! !!!!!! Nous vous remercions de votre attention.