Dokumentation

Anwendungen

Zuletzt aktualisiert am 21. 7. 2022 von Mark Fric

Zusammenführung mehrerer Ergebnisse zu einem Portfolio

In diesem Artikel zeigen wir, wie StrategyQuant X mit Backtest-Ergebnissen umgeht und wie wir sie in ein Portfolio einbinden können.

Dies ist bereits in SQX möglich, indem Sie mehrere Strategien auswählen und die Option Portfolio -> Strategien zusammenführenaber wir werden zeigen, wie es auf dem Hintergrund gemacht wird.

Dies ist als erster Teil einer mehrteiligen Serie gedacht. Wir möchten diese Funktionalität nutzen, um zu untersuchen, ob der Handel durch die Auswahl bestimmter Teilstrategien verbessert werden kann - dies wird in den nächsten Artikeln untersucht.

 

Beachten Sie, dass wir mit der Zusammenführung zum Portfolio die Zusammenführung der endgültigen Backtest-Ergebnisse zu einem Portfolio-Ergebnis meinen und nicht die Zusammenführung einzelner Handelsstrategien.

 

Diese Funktion ist wieder in Form von benutzerdefinierten Analyse-Snippet gemacht, und die vollständige Snippet ist zu diesem Artikel beigefügt.

 

Arbeiten mit Backtest-Ergebnissen - ResultsGroup-Objekt

Nur zur Erinnerung: In SQX werden alle Backtest-Ergebnisse in einem Result-Objekt gespeichert und in einem ResultsGroup-Objekt gruppiert.

RegultGroup ist das, was Sie in der Datenbank sehen - es kann ein oder mehrere Ergebnisse enthalten - Backtests der Strategie auf dem Hauptmarkt, zusätzlichen Märkten, etc.

Es gibt einen Artikel mit Einführung: Arbeiten mit ResultsGroup

 

Wenn wir mehrere Strategieergebnisse in einem Portfolio zusammenführen wollen, müssen wir

  • ein neues ResultsGroup-Objekt erstellen, das das Portfolio enthält
  • Durchlaufen des ResultsGroup-Objekts jeder Strategie in der Databank
  • Finden Sie das Hauptergebnis - das Ergebnis des Backtests mit den Hauptdaten - das ist das Ergebnis, das wir zusammenführen werden.
  • ein neues Ergebnisobjekt für diese Strategie zu erstellen und es dem Portfolio hinzuzufügen
  • Klonen und Kopieren von Aufträgen aus der ursprünglichen ResultsGroup in das Portfolio
  • Kopieren von Symbolen aus der ursprünglichen ResultsGroup in das Portfolio - dies ist für die Berechnung von PL usw. erforderlich.
  • am Ende ein neues Portfolio-Ergebnis erstellen und alle Statistiken berechnen

 

 

Vollständiger Quellcode des Snippets

Der Code ist ausführlich kommentiert, Sie können seine Logik nachvollziehen.

Es werden zwei neue Portfolio-Ergebnisse erstellt - eines, das wir manuell erstellt haben, und ein weiteres, das mit der SQX-Methode zum Vergleich erstellt wurde.

 

Paket 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("Strategien zu Portfolio zusammenführen", 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) {
            // wenn es keine oder nur eine Strategie gibt, gibt es nichts zu fusionieren
            return databankRG;
        }

        // Abrufen der Zieldatenbank zum Speichern des Endergebnisses
        Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Portfolios");
        if(targetDatabank == null) {
            throw new Exception("Bitte erstellen Sie eine neue Datenbank mit dem Namen 'Portfolios' !");
        }

        // ------------------------------
        // Portfolio manuell erstellen


        // Alle Strategien in der Datenbank zu einem Portfolio zusammenführen
        ErgebnisGruppe caPortfolio = mergeStrategiesToPortfolio(databankRG);

        // Erstellen des endgültigen Portfolioergebnisses, um alle Teilergebnisse zu summieren
        createPortfolioResult(caPortfolio);

        // neues Portfolio zu unserer Zieldatenbank hinzufügen
        targetDatabank.add(caPortfolio, false);


        // ------------------------------
        // Erstellen eines Portfolios auf standardmäßige Weise durch Aufruf der SQ-Methode - zur Kontrolle
        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");

        // einzelne Strategien zum Portfolio hinzufügen
        for(ResultsGroup rg : databankRG) {
            addResult(caPortfolio, rg);
        }

        addSymbolsMap(caPortfolio, databankRG);

        caPortfolio zurückgeben;
    }

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

    private void addSymbolsMap(ResultsGroup rgCSPortfolio, ArrayList databankRG) {
        for(ResultsGroup rg : databankRG) {
            // Hinzufügen aller Symbole aus den zusammengeführten RGs zur Portfolio-Symbolkarte
            rgCSPortfolio.symbols().add(rg.symbols());
        }
    }

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

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

        // zuerst ein neues Ergebnis für RG in unserem neuen Portfolio erstellen
        // newResultKey wird als Ergebnisschlüssel zurückgegeben und in unserem Portfolio verwendet
        String newResultKey = mergeResult(caPortfolio, rg);

        // nächstes Klonen und Kopieren von Aufträgen für dieses Ergebnis von RG in das Portfolio
        copyOrdersToPortfolio(caPortfolio, rg, newResultKey);

        // Hinzufügen aller Symboldaten aus dem zusammengeführten RG zur Portfolio-Symbole-Map - dies ist für die Berechnung von PL usw. erforderlich
        caPortfolio.symbols().add(rg.symbols());
    }

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

    private String mergeResult(ErgebnisGruppe caPortfolio, ErgebnisGruppe rg) throws Exception {
        // Abrufen des Hauptergebnisses der aktuellen Strategie - dies ist das Ergebnis, das wir zusammenführen werden
        Ergebnis rgMainResult = rg.mainResult();
        String mainResultKey = rgMainResult.getResultKey();

        // neuen Ergebnisschlüssel bestimmen - er muss eindeutig sein, also müssen wir prüfen
        // ob es nicht bereits ein Ergebnis mit diesem Schlüssel in unserem Portfolio gibt
        String newResultKey = rg.getName();

        if(caPortfolio.hasResult(newResultKey)) {
            // derselbe Schlüssel existiert bereits, wir müssen einen neuen Schlüssel finden
            newResultKey = SQUtils.generateUniqueName(mainResultKey, new IUniqueNameChecker() {
                public boolean checkNameExist(String name) throws Exception {
                    return caPortfolio.hasResult(name);
                }
            });
        }

        // Zusammengeführtes Ergebnis erstellen
        SettingsMap copiedSettingsMap = rgMainResult.getSettings().clone();

        // Neues zusammengeführtes Ergebnis erstellen und zum Portfolio hinzufügen
        Ergebnis mergedResult = new Result(newResultKey, caPortfolio, copiedSettingsMap);
        caPortfolio.addSubresult(newResultKey, copiedSettingsMap, mergedResult);

        // Symbol und Zeitrahmen der zusammengeführten Strategie festlegen
        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 {
        // Abrufen der Auftragsliste aus unserem aktuellen Portfolio
        OrdersList mergedOrdersList = caPortfolio.orders();

        // holt alle Aufträge aus dem Ergebnis der zusammengefassten Strategie - beachten Sie, dass sie geklont werden müssen!
        String mainResultKey = rg.mainResult().getResultKey();
        OrdersList filteredOL = rg.orders().filterWithClone(mainResultKey, Directions.Both, SampleTypes.FullSample);

        // nicht durch diese Aufträge gehen und sie zur Liste der Portfolioaufträge hinzufügen
        for(int i=0; i<filteredOL.size(); i++) {
            Order order = filteredOL.get(i);

            // order.SetupName wird als Bezeichner verwendet, damit wir wissen, zu welchem Ergebnis die Order gehört
            // daher müssen wir ihn auf newResultKey setzen
            order.SetupName = newResultKey;

            mergedOrdersList.add(order);
        }
    }

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

    private void createPortfolioResult(ResultsGroup caPortfolio) throws Exception {

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

        Ergebnis 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);

        // für Portfolio Aufträge nach ihrer Öffnungszeit sortieren
        OrdersList ordersList = caPortfolio.orders();
        ordersList.sort(new OrderComparatorByOpenTime());

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

        caPortfolio.updated = true;
    }

}

 

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

Abonnieren
Benachrichtigen Sie mich bei
1 Kommentar
Älteste
Neuestes Meistgewählt
Inline-Rückmeldungen
Alle Kommentare anzeigen
Emmanuel
21. 7. 2022 12:14 Uhr

Ausgezeichnetes Beispiel! Genau das, was ich brauchte! Vielen Dank Mark

Verwandte Beiträge