Documentazione

Applicazioni

Ultimo aggiornamento il 16. 11. 2021 da Mark Fric

Esempio - analisi personalizzata per banca dati

Questo esempio riguarda l'analisi personalizzata per banca dati. Diversamente dall'analisi personalizzata per strategia, che elabora una sola strategia, questo frammento di CA analizza l'intera banca dati e può accedere a tutti i risultati della strategia in una banca dati.

L'analisi personalizzata per banca dati può essere eseguita solo da un'attività personalizzata nel progetto personalizzato.

In questo esempio realizzeremo un esempio abbastanza complesso di snippet di analisi personalizzato che costruirà un portafoglio a partire dai risultati Walk-Forward delle strategie presenti nella banca dati.
Questa era una richiesta della nostra prima sessione di codifica.

 

Passo 1 - Creare un nuovo snippet di analisi personalizzato

Aprire CodeEditor, fare clic su Crea nuovo e scegliere l'opzione Analisi personalizzata (CA) in basso. Nominarla Portafoglio del PAM.

Questo creerà un nuovo snippet WFPortfolio.java in cartella Utente/Snippet/SQ/Analisi personalizzata

Questa volta, lo imposteremo come TIPO_PROCESSO_DI_BANCA_DATI nel costruttore della classe:

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

 

Passo 2 - Implementare il metodo processDatabank()

Questa CA chiama il metodo elaboraBancaDati() che ha 4 parametri:

  • Progetto di stringa - nome del progetto in cui è inserito il task CA
  • Compito di stringa - nome del task CA
  • Stringa databankName - nome della banca dati su cui lavora lo snippet di CA
  • ArrayList databankRG - elenco di tutte le strategie (RisultatiGruppi) da questa banca dati.

Restituisce inoltre un elenco ArrayList, che deve contenere solo le strategie dell'elenco di input che devono essere conservate nella banca dati.

In questo modo può essere utilizzato come filtro: si possono scorrere le strategie nell'elenco di databankRG e creare un nuovo elenco in cui inserire solo quelle che corrispondono a qualche criterio. Le strategie non presenti nell'elenco di output saranno eliminate dalla banca dati.

Nel nostro caso non vogliamo cancellare qualcosa dalla banca dati, ma aggiungere una nuova strategia (il nostro portafoglio appena creato). Vediamo come fare.

In sintesi, il codice fa questo:

  • Crea un nuovo gruppo di risultati per il portafoglio, che sarà vuoto all'inizio.
  • Esamina ogni strategia nella banca dati e verifica se ha un risultato WF. In caso affermativo, copierà questo risultato in un nuovo portafoglio che include tutti gli ordini WF.
  • Calcolo del risultato del portafoglio dai risultati secondari - per impostazione predefinita non viene calcolato dai risultati di WF, quindi dobbiamo farlo da soli nel codice.
  • Aggiungere il gruppo di risultati del portafoglio finito alla banca dati

Il codice è lungo e complesso, non lo spiegheremo tutto qui. È mostrato alla fine di questo articolo completamente commentato.

 

Passo 3 - esecuzione dello snippet CA personalizzato

Per eseguire uno snippet CA "per banca dati", occorre creare un progetto personalizzato e un task personalizzato di tipo Analisi personalizzata.

Selezionare la voce Portafoglio del PAM nell'attività personalizzata.

Attività di analisi personalizzata

 

Quindi aggiungere alcune strategie con risultati Walk-Forward alla banca dati dei risultati ed eseguire l'attività.

Dovrebbe creare una nuova strategia denominata Portafoglio azionario WF che conterrà le azioni WF di tutte le strategie presenti in Risultati.

banca dati azionaria wf

e il patrimonio netto del portafoglio di tutti i risultati del WF si presenta così:

Patrimonio netto del portafoglio WF

 

Codice commentato completo dello snippet

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

 

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

Abbonarsi
Notificami
3 Commenti
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
Emmanuel
25. 11. 2021 20:52

Mark, grazie mille per questo impressionante lavoro !!!!!! È esattamente ciò di cui ho bisogno !!!!
SQX è davvero unico.
Con l'esempio, sarò in grado di costruire nuove idee.

Emmanuel
26. 11. 2021 11:53

Il codice commentato completo è davvero utile

Emmanuel
26. 11. 2021 11:59

Funziona bene !!!!!!! Grazie

Messaggi correlati