Documentación

Aplicaciones

Última actualización el 21. 7. 2022 by Mark Fric

Fusionar varios resultados en una cartera

En este artículo mostraremos cómo StrategyQuant X maneja los resultados de backtest, y cómo podemos fusionarlos en la cartera.

Esto ya se puede hacer en SQX seleccionando varias estrategias y eligiendo Cartera -> Fusionar estrategiaspero mostraremos cómo se hace en el fondo.

Esto pretende ser una primera parte de una serie múltiple, nos gustaría utilizar esta funcionalidad para explorar si el comercio podría mejorarse mediante la selección de subconjunto particular de las estrategias para el comercio - esto será examinado en los próximos artículos.

 

Tenga en cuenta que por fusión en cartera nos referimos a la fusión de los resultados finales de las pruebas retrospectivas en un resultado de cartera, no a la fusión de estrategias de negociación individuales.

 

Esta función se presenta de nuevo en forma de fragmento de análisis personalizado, y el fragmento completo se adjunta a este artículo.

 

Trabajar con resultados de backtest - Objeto ResultsGroup

Sólo un recordatorio rápido de que en SQX todos los resultados de backtest se almacenan en el objeto Result, y se agrupan en el objeto ResultsGroup.

RegultGroup es lo que se ve en el banco de datos - puede contener uno o más resultados - backtests de la estrategia en el mercado principal, mercados adicionales, etc.

Hay un artículo con introducción: Trabajar con ResultsGroup

 

Cuando queremos fusionar los resultados de varias estrategias en una cartera tenemos que

  • crear un nuevo objeto ResultsGroup que contendrá la cartera
  • recorrer el objeto ResultsGroup de cada estrategia en el banco de datos
  • encontrar el resultado principal - el que contiene backtest en los datos principales - este es el que vamos a fusionar
  • crear un nuevo objeto Resultado para esta estrategia y añadirlo a la cartera
  • clonar y copiar órdenes del Grupo de Resultados original a la cartera
  • copiar símbolos del ResultsGroup original a la cartera - esto es necesario para el cálculo de PL, etc.
  • al final crear un nuevo resultado de Cartera y calcular todas las estadísticas

 

 

Código fuente completo del fragmento

El código está ampliamente comentado, puedes seguir su lógica.

Creará dos nuevos resultados de Cartera - uno creado por nosotros manualmente, y otro creado por el método SQX para comparación.

 

paquete 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 CAMergStrategiesToPortfolio extends CustomAnalysisMethod {
    public static final Logger Log = LoggerFactory.getLogger("CAMergeStrategiesToPortfolio");

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

    public CAMergirEstrategiasEnCartera() {
        super("Combinar estrategias en cartera", 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) {
            // si no hay o sólo hay una estrategia no hay nada que fusionar
            return databankRG;
        }

        // obtener el banco de datos de destino para guardar el resultado final
        Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Carteras");
        if(targetDatabank == null) {
            throw new Exception("¡Por favor, cree un nuevo banco de datos llamado 'Carteras'!");
        }

        // ------------------------------
        // Crear cartera manualmente


        // fusionar todas las estrategias del banco de datos en una cartera
        Grupo de resultados caPortfolio = mergeStrategiesToPortfolio(databankRG);

        // crear el resultado final de la cartera para sumar todos los subresultados
        createPortfolioResult(caPortfolio);

        // añadir la nueva cartera al banco de datos de destino
        targetDatabank.add(caPortfolio, false);


        // ------------------------------
        // Crear cartera de forma estándar llamando al método SQ - para control
        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("CarteraHechaPorCA");

        // añadir estrategias individuales a la cartera
        for(GrupoResultados rg : databankRG) {
            addResult(caCartera, rg);
        }

        addSymbolsMap(caCartera, databankRG);

        return caCartera;
    }

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

    private void addSymbolsMap(ResultsGroup rgCSPortfolio, ArrayList databankRG) {
        for(ResultsGroup rg : databankRG) {
            // añade todos los símbolos de los RG fusionados al mapa de símbolos de la cartera
            rgCSPortfolio.symbols().add(rg.symbols());
        }
    }

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

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

        // primero crear un nuevo resultado para RG en nuestra nueva cartera
        // newResultKey será devuelto como su clave de resultado utilizado en nuestra cartera
        String newResultKey = mergeResult(caPortfolio, rg);

        // a continuación clonamos y copiamos las órdenes de este resultado de RG a la cartera
        copyOrdersToPortfolio(caPortfolio, rg, newResultKey);

        // añadir todos los datos de símbolos del RG fusionado al mapa de símbolos de la cartera - esto es necesario para el cálculo de PL, etc.
        caPortfolio.symbols().add(rg.symbols());
    }

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

    private String mergeResult(ResultsGroup caPortfolio, ResultsGroup rg) throws Exception {
        // obtener el resultado principal de la estrategia actual - este es el que vamos a fusionar
        Resultado rgMainResult = rg.mainResult();
        String mainResultKey = rgMainResult.getResultKey();

        // determinar nueva clave de resultado - debe ser única por lo que tenemos que comprobar
        // si ya existe algún resultado con esta clave en nuestra cartera
        String newResultKey = rg.getName();

        if(caPortfolio.hasResult(newResultKey)) {
            // la misma clave ya existe, tenemos que encontrar una nueva clave
            newResultKey = SQUtils.generateUniqueName(mainResultKey, new IUniqueNameChecker() {
                public boolean checkNameExist(String name) throws Exception {
                    return caPortfolio.hasResult(nombre);
                }
            });
        }

        // crear resultado fusionado
        SettingsMap copiedSettingsMap = rgMainResult.getSettings().clone();

        // crear nuevo resultado fusionado y añadirlo a nuestra cartera
        Result mergedResult = new Result(newResultKey, caPortfolio, copiedSettingsMap);
        caPortfolio.addSubresult(newResultKey, copiedSettingsMap, mergedResult);

        // establecer el símbolo y el marco temporal de la estrategia combinada
        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 {
        // obtener la lista de pedidos de nuestra cartera actual
        OrdersList mergedOrdersList = caPortfolio.orders();

        // obtener todos los pedidos del resultado de la estrategia de fusión - ¡tenga en cuenta que deben ser clonados!
        String mainResultKey = rg.mainResult().getResultKey();
        OrdersList filteredOL = rg.orders().filterWithClone(mainResultKey, Directions.Both, SampleTypes.FullSample);

        // no recorrer estos pedidos y añadirlos a la lista de pedidos de la cartera
        for(int i=0; i<filteredOL.size(); i++) {
            Orden = filteredOL.get(i);

            // order.SetupName se usa como identificador para que sepamos a que resultado pertenece la orden
            // por lo que tenemos que establecerlo como newResultKey
            order.SetupName = newResultKey;

            mergedOrdersList.add(orden);
        }
    }

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

    private void createPortfolioResult(ResultsGroup caPortfolio) throws Exception {

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

        ResultadoCarteraResultado = new Resultado(GrupoResultados.Cartera, caCartera, configuración);

        caPortfolio.removeSubresult(ResultsGroup.Portfolio, true);

        caPortfolio.addSubresult(ResultsGroup.Portfolio, settings, portfolioResult);

        caPortfolio.specialValues().setString(SpecialValues.Symbol, ResultsGroup.Portfolio);

        // para la cartera ordenar las órdenes por su hora de apertura
        OrdersList ordersList = caPortfolio.orders();
        ordersList.sort(new OrderComparatorByOpenTime());

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

        caPortfolio.updated = true;
    }

}

 

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

Suscríbase a
Notificar a
1 Comentario
Más antiguo
Más reciente Más votados
Feedbacks de Inline
Ver todos los comentarios
Emmanuel
21. 7. 2022 12:14 pm

¡¡Excelente ejemplo !! ¡Exactamente lo que necesitaba! Gracias Mark

Puestos relacionados