Documentazione

Applicazioni

Ultimo aggiornamento il 21. 7. 2022 da Mark Fric

Unire più risultati in un portafoglio

In questo articolo mostreremo come StrategyQuant X gestisce i risultati dei backtest e come possiamo unirli al portafoglio.

Questo può già essere fatto in SQX selezionando più strategie e scegliendo Portafoglio -> Strategie di fusionema mostreremo come si fa sullo sfondo.

Questa è la prima parte di una serie multipla: vorremmo utilizzare questa funzionalità per verificare se il trading può essere migliorato scegliendo particolari sottoinsiemi di strategie da negoziare - questo aspetto sarà esaminato nei prossimi articoli.

 

Si noti che per fusione di portafoglio si intende la fusione dei risultati finali dei backtest in un unico risultato di portafoglio, non la fusione di singole strategie di trading.

 

Questa funzione è ancora una volta realizzata sotto forma di snippet di analisi personalizzata e lo snippet completo è allegato a questo articolo.

 

Lavorare con i risultati del backtest - Oggetto ResultsGroup

Vorrei solo ricordare che in SQX tutti i risultati dei backtest sono memorizzati nell'oggetto Result e sono raggruppati nell'oggetto ResultsGroup.

RegultGroup è ciò che si vede nella banca dati - può contenere uno o più risultati - backtest della strategia sul mercato principale, su altri mercati, ecc.

C'è un articolo con introduzione: Lavorare con ResultsGroup

 

Quando vogliamo unire i risultati di più strategie in un unico portafoglio dobbiamo

  • creare un nuovo oggetto ResultsGroup che conterrà il portafoglio
  • passare attraverso l'oggetto ResultsGroup di ogni strategia nella banca dati
  • trovare il risultato principale, quello che contiene il backtest sui dati principali, che è quello che verrà unito
  • creare un nuovo oggetto Risultato per questa strategia e aggiungerlo al portafoglio
  • clonare e copiare gli ordini dal gruppo di risultati originale al portafoglio
  • copiare i simboli dal ResultsGroup originale al portfolio - questo è necessario per il calcolo dei PL, ecc.
  • alla fine creare un nuovo risultato di Portafoglio e calcolare tutte le statistiche

 

 

Codice sorgente completo dello snippet

Il codice è ampiamente commentato, è possibile seguirne la logica.

Verranno creati due nuovi risultati di Portafoglio: uno creato manualmente da noi e un altro creato dal metodo SQX per il confronto.

 

pacchetto SQ.CustomAnalysis;

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

importare java.util.ArrayList;

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

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

    public CAMergeStrategiesToPortfolio() {
        super("Merge Strategies To Portfolio", 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) {
            // se non c'è nessuna o una sola strategia non c'è nulla da unire
            return databankRG;
        }

        // ottenere la banca dati di destinazione per salvare il risultato finale
        Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Portfolios");
        if(targetDatabank == null) {
            throw new Exception("Si prega di creare una nuova banca dati denominata 'Portfolios'!");
        }

        // ------------------------------
        // Creare manualmente un portafoglio


        // unire tutte le strategie della banca dati in un unico portafoglio
        ResultsGroup caPortfolio = mergeStrategiesToPortfolio(databankRG);

        // creare il risultato finale del portafoglio per sommare tutti i risultati secondari
        createPortfolioResult(caPortfolio);

        // aggiungere il nuovo portafoglio alla banca dati di destinazione
        targetDatabank.add(caPortfolio, false);


        // ------------------------------
        // Creare il portafoglio in modo standard chiamando il metodo SQ - per controllo
        ResultsGroup standardPortfolio = ResultsGroup.merge(databankRG, new String[] { ResultsGroup.AdditionalMarket }, null);

        standardPortfolio.createPortfolioResult(PortfolioInitialBalanceTypes.SINGLE, null);

        targetDatabank.add(standardPortfolio, false);

        restituisce databankRG;
    }

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

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

        // aggiungere le singole strategie al portafoglio
        for(ResultsGroup rg : databankRG) {
            addResult(caPortfolio, rg);
        }

        addSymbolsMap(caPortfolio, databankRG);

        restituire caPortfolio;
    }

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

    private void addSymbolsMap(ResultsGroup rgCSPortfolio, ArrayList databankRG) {
        for(ResultsGroup rg : databankRG) {
            // aggiunge tutti i simboli degli RG uniti alla mappa dei simboli del portafoglio
            rgCSPortfolio.symbols().add(rg.symbols());
        }
    }

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

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

        // prima crea un nuovo risultato per RG nel nostro nuovo portafoglio
        // newResultKey sarà restituita come chiave di risultato utilizzata nel nostro portafoglio
        String newResultKey = mergeResult(caPortfolio, rg);

        // Successivamente cloniamo e copiamo gli ordini per questo risultato da RG al portafoglio
        copyOrdersToPortfolio(caPortfolio, rg, newResultKey);

        // aggiungere tutti i dati dei simboli dalla RG fusa alla mappa dei simboli del portafoglio - questo è necessario per il calcolo dei PL ecc.
        caPortfolio.symbols().add(rg.symbols());
    }

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

    private String mergeResult(ResultsGroup caPortfolio, ResultsGroup rg) throws Exception {
        // otteniamo il risultato principale dalla strategia corrente, che è quello da unire
        Risultato rgMainResult = rg.mainResult();
        String mainResultKey = rgMainResult.getResultKey();

        // determiniamo la nuova chiave del risultato - deve essere unica, quindi dobbiamo controllare
        // se non ci sono risultati con questa chiave già nel nostro portafoglio
        String newResultKey = rg.getName();

        if(caPortfolio.hasResult(newResultKey)) {
            // la stessa chiave esiste già, dobbiamo trovare una nuova chiave
            newResultKey = SQUtils.generateUniqueName(mainResultKey, new IUniqueNameChecker() {
                public boolean checkNameExist(String name) throws Exception {
                    return caPortfolio.hasResult(nome);
                }
            });
        }

        // creare un risultato unito
        SettingsMap copiedSettingsMap = rgMainResult.getSettings().clone();

        // creare un nuovo risultato unito e aggiungerlo al portafoglio
        Risultato mergedResult = nuovo Risultato(newResultKey, caPortfolio, copiedSettingsMap);
        caPortfolio.addSubresult(newResultKey, copiedSettingsMap, mergedResult);

        // impostare il simbolo e il timeframe della strategia unita
        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));

        restituire newResultKey;
    }

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

    private void copyOrdersToPortfolio(ResultsGroup caPortfolio, ResultsGroup rg, String newResultKey) throws Exception {
        // otteniamo l'elenco degli ordini dal portafoglio corrente
        OrdersList mergedOrdersList = caPortfolio.orders();

        // ottenere tutti gli ordini dal risultato della strategia di fusione - si noti che devono essere clonati!
        String mainResultKey = rg.mainResult().getResultKey();
        OrdersList filteredOL = rg.orders().filterWithClone(mainResultKey, Directions.Both, SampleTypes.FullSample);

        // non scorriamo questi ordini e li aggiungiamo all'elenco degli ordini del portafoglio
        for(int i=0; i<filteredOL.size(); i++) {
            Ordine = filteredOL.get(i);

            // order.SetupName è usato come identificatore per sapere a quale risultato appartiene l'ordine
            // quindi dobbiamo impostarlo su newResultKey
            order.SetupName = newResultKey;

            mergedOrdersList.add(ordine);
        }
    }

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

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

        // per il portafoglio ordinare gli ordini in base all'orario di apertura
        OrdersList ordersList = caPortfolio.orders();
        ordersList.sort(new OrderComparatorByOpenTime());

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

        caPortfolio.updated = true;
    }

}

 

Questo articolo è stato utile? L'articolo è stato utile L'articolo non è stato utile

Abbonarsi
Notificami
1 Commento
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
Emmanuel
21. 7. 2022 12:14 pm

Esempio eccellente !!! Esattamente quello di cui avevo bisogno! Grazie Mark

Messaggi correlati