Dokumentation

Anwendungen

Zuletzt aktualisiert am 16. 11. 2021 von Mark Fric

Beispiel - benutzerdefinierte Analyse pro Datenbank

In diesem Beispiel geht es um die benutzerdefinierte Analyse pro Datenbank. Im Gegensatz zur benutzerdefinierten Analyse pro Strategie, die eine Strategie verarbeitet, läuft dieses CA-Snippet über die gesamte Datenbank und kann auf jedes Strategieergebnis in einer Datenbank zugreifen.

Die benutzerdefinierte Analyse pro Datenbank kann nur über eine benutzerdefinierte Aufgabe im benutzerdefinierten Projekt ausgeführt werden.

In diesem Beispiel werden wir ein ziemlich komplexes Beispiel für ein benutzerdefiniertes Analyse-Snippet erstellen, das ein Portfolio aus den Walk-Forward-Ergebnissen der Strategien in der Datenbank erstellt.
Dies war eine Bitte aus unserer ersten Coding-Sitzung.

 

Schritt 1 - Neues benutzerdefiniertes Analyse-Snippet erstellen

Öffnen Sie CodeEditor, klicken Sie auf Neu erstellen und wählen Sie ganz unten die Option Benutzerdefinierte Analyse (CA). Benennen Sie sie WFPortfolio.

Dadurch wird ein neues Snippet erstellt WFPortfolio.java im Ordner Benutzer/Snippets/SQ/BenutzerdefinierteAnalysen

Diesmal setzen wir sie als TYPE_PROCESS_DATABANK im Konstruktor der Klasse:

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

 

Schritt 2 - Implementierung der Methode processDatabank()

Diese CA ruft die Methode processDatabank() die 4 Parameter hat:

  • String-Projekt - Name des Projekts, in dem die CA-Aufgabe platziert ist
  • String-Aufgabe - Name der CA-Aufgabe
  • String databankName - Name der Datenbank, mit der das CA-Snippet arbeitet
  • ArrayList databankRG - Liste aller Strategien (ResultsGroups) aus dieser Datenbank.

Sie gibt auch eine Liste ArrayList zurück, die nur die Strategien aus der Eingabeliste enthalten sollte, die in der Datenbank erhalten bleiben sollen.

Auf diese Weise kann sie als Filter verwendet werden - Sie können die Strategien in der databankRG-Liste durchgehen und eine neue Liste erstellen, in die Sie nur die Strategien aufnehmen, die einige Ihrer Kriterien erfüllen. Strategien, die nicht in der Ausgabeliste enthalten sind, werden aus der Datenbank gelöscht.

In unserem Fall wollen wir nicht etwas aus der Datenbank löschen, sondern stattdessen eine neue Strategie (unser neu erstelltes Portfolio) hinzufügen. Wir werden sehen, wie es gemacht wird.

Zusammengefasst funktioniert der Code folgendermaßen:

  • Erstellt eine neue Ergebnisgruppe für das Portfolio - sie wird zu Beginn leer sein
  • Geht jede Strategie in der Datenbank durch und prüft, ob sie ein WF-Ergebnis hat. Wenn ja, wird dieses Ergebnis in ein neues Portfolio mit allen WF-Aufträgen kopiert.
  • Berechnung des Portfolio-Ergebnisses aus den Teilergebnissen - standardmäßig wird es nicht aus den WF-Ergebnissen berechnet, so dass wir dies im Code selbst tun müssen
  • Hinzufügen der fertigen Portfolio ResultsGroup zur Datenbank

Der Code ist lang und komplex, wir werden ihn hier nicht vollständig erklären. Er wird am Ende dieses Artikels vollständig kommentiert dargestellt.

 

Schritt 3 - Ausführen unseres benutzerdefinierten CA-Snippets

Um ein CA-Snippet "pro Datenbank" auszuführen, müssen wir ein benutzerdefiniertes Projekt und eine benutzerdefinierte Aufgabe des Typs BenutzerdefinierteAnalyse.

Wählen Sie die WFPortfolio in der benutzerdefinierten Aufgabe.

Benutzerdefinierte Analyseaufgabe

 

Fügen Sie dann einige Strategien mit Walk-Forward-Ergebnissen zur Ergebnisdatenbank hinzu und führen Sie die Aufgabe aus.

Es sollte eine neue Strategie mit dem Namen WF-Aktienportfolio erstellt werden, die WF-Aktien aus allen Strategien in Results enthält.

wf-Aktiendatenbank

und das Portfolio-Eigenkapital aus allen WF-Ergebnissen sieht wie folgt aus:

WF-Portfolio Eigenkapital

 

Vollständig kommentierter Code des Snippets

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());
    }
}

 

War dieser Artikel hilfreich? Der Artikel war nützlich Der Artikel war nicht nützlich

Abonnieren
Benachrichtigen Sie mich bei
3 Kommentare
Älteste
Neuestes Meistgewählt
Inline-Rückmeldungen
Alle Kommentare anzeigen
Emmanuel
25. 11. 2021 8:52 Uhr

Mark, vielen Dank für diese beeindruckende Arbeit !!!!!! Es ist genau das, was ich brauche !!!!
SQX ist wirklich einzigartig.
Anhand eines Beispiels kann ich eine neue Idee entwickeln.

Emmanuel
26. 11. 2021 11:53 Uhr

Der vollständig kommentierte Code ist wirklich hilfreich

Emmanuel
26. 11. 2021 11:59 Uhr

Es funktioniert gut !!!!!!! Dankeschön

Verwandte Beiträge