Documentación

Aplicaciones

Última actualización el 16. 11. 2021 por Mark Fric

Ejemplo - análisis personalizado por banco de datos

Este ejemplo trata del análisis personalizado por banco de datos. A diferencia del análisis personalizado por estrategia, que procesa una estrategia, este fragmento de CA se ejecuta en todo el banco de datos y puede acceder a todos los resultados de estrategia de un banco de datos.

Los análisis personalizados por banco de datos sólo pueden ejecutarse desde una tarea personalizada en el proyecto personalizado.

En este ejemplo haremos un ejemplo bastante complejo de fragmento de análisis personalizado que construirá una cartera a partir de los resultados Walk-Forward de las estrategias del banco de datos.
Esta fue una petición de nuestra primera sesión de codificación.

 

Paso 1 - Crear un nuevo fragmento de análisis personalizado

Abra CodeEditor, haga clic en Crear nuevo y elija la opción Análisis personalizado (CA) en la parte inferior. Póngale un nombre Cartera del PMA.

Esto creará un nuevo fragmento WFPortfolio.java en carpeta Usuario/Snippets/SQ/Análisis personalizado

Esta vez, lo estableceremos como TIPO_PROCESO_BANCO_DE_DATOS en el constructor de la clase:

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

 

Paso 2 - Implementar el método processDatabank()

Esta CA llama al método procesarBancoDeDatos() que tiene 4 parámetros:

  • Proyecto de cadenas - nombre del proyecto donde se ubica la tarea CA
  • Tarea de cadena - nombre de la tarea CA
  • String databankName - nombre del banco de datos en el que funciona el fragmento de CA
  • ArrayList databankRG - lista de todas las estrategias (ResultadosGrupos) de este banco de datos.

También devuelve una lista ArrayList, que debe contener sólo las estrategias de la lista de entrada que deben conservarse en el banco de datos.

De esta manera se puede utilizar como un filtro - usted puede ir a través de las estrategias en la lista databankRG y crear una nueva lista en la que va a poner sólo estos que coinciden con algunos de sus criterios. Las estrategias que no estén en la lista de salida serán eliminadas del banco de datos.

En nuestro caso no queremos borrar algo de la base de datos, sino añadir una nueva estrategia (nuestra cartera recién creada). Vamos a ver cómo se hace.

En resumen, el código hace lo siguiente

  • Crea un nuevo ResultsGroup para la cartera - estará vacío al principio
  • Revisa cada estrategia en la base de datos, comprueba si tiene resultado WF. En caso afirmativo, copiará este resultado a una nueva cartera incluyendo todas las órdenes WF.
  • Calcular el resultado de la cartera a partir de los subresultados - por defecto no se calcula a partir de los resultados de la WF, así que debemos hacerlo nosotros mismos en el código
  • Añadir la cartera terminada ResultsGroup a la base de datos

El código es largo y complejo, no lo explicaremos todo aquí. Se muestra al final de este artículo totalmente comentado.

 

Paso 3: ejecutar nuestro fragmento de CA personalizado

Para ejecutar un fragmento de CA "por banco de datos" necesitamos crear un proyecto personalizado y una tarea personalizada de tipo CustomAnalysis.

Seleccione Cartera del PMA en la tarea personalizada.

Tarea de análisis personalizada

 

A continuación, añada algunas estrategias con resultados Walk-Forward a la base de datos Results y ejecute la tarea.

Debería crear una nueva estrategia denominada cartera de acciones WF que contendrá las acciones WF de todas las estrategias de Resultados.

wf equity databank

y la equidad de la cartera de todos los resultados del WF se ve así:

Patrimonio de la cartera WF

 

Código completo comentado del fragmento

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

 

¿Le ha resultado útil este artículo? El artículo era útil El artículo no era útil

Suscríbase a
Notificar a
3 Comentarios
Más antiguo
Más reciente Más votados
Feedbacks de Inline
Ver todos los comentarios
Emmanuel
25. 11. 2021 8:52 pm

¡¡¡¡¡¡Mark, muchas gracias por este impresionante trabajo !!!!!! ¡¡¡¡Es exactamente lo que necesito !!!!
SQX es realmente único.
Con el ejemplo, podré construir una nueva idea.

Emmanuel
26. 11. 2021 11:53 am

El código completo comentado es realmente útil

Emmanuel
26. 11. 2021 11:59

¡¡¡¡¡¡¡Funciona bien !!!!!!! Gracias a todos

Puestos relacionados