Documentação

Aplicações

Última atualização em 21. 7. 2022 por Mark Fric

Fusão de múltiplos resultados em carteira

Neste artigo mostraremos como o StrategyQuant X lida com os resultados dos backtest, e como podemos fundi-los em portfólio.

Isso já pode ser feito no SQX, selecionando múltiplas estratégias e escolhendo Portfólio -> Fundir estratégiasmas mostraremos como isso é feito em segundo plano.

Esta pretende ser uma primeira parte de múltiplas séries, gostaríamos de usar esta funcionalidade para explorar se a comercialização poderia ser melhorada escolhendo um subconjunto específico de estratégias para comercializar - isto será examinado nos próximos artigos.

 

Note que, por fusão com a carteira, entendemos a fusão dos resultados finais de backtest em um resultado de carteira, não a fusão de estratégias comerciais individuais.

 

Esta característica é novamente feita na forma de snippet de Análise Personalizada, e o snippet completo é anexado a este artigo.

 

Trabalhando com resultados de backtest - Objeto ResultsGroup

Apenas um rápido lembrete de que no SQX todos os resultados backtest são armazenados no objeto Resultado, e eles são agrupados no objeto ResultadoGrupo.

RegultGroup é o que você vê no banco de dados - ele pode conter um ou mais resultados - retrocesso de estratégia no mercado principal, mercados adicionais, etc.

Há um artigo com introdução: Trabalhando com ResultsGroup

 

Quando queremos fundir vários resultados estratégicos em um único portfólio, temos que

  • criar um novo objeto do ResultsGroup que irá manter o portfólio
  • passar por ResultsGroup objeto de toda estratégia em banco de dados
  • encontrar o resultado principal - o que contém o backtest sobre os dados principais - este é o resultado que estaremos fundindo
  • criar um novo objeto de resultado para esta estratégia e adicioná-lo ao portfólio
  • clonar e copiar pedidos de resultados originaisGrupo de resultados para carteira
  • copiar símbolos do ResultsGroup original para o portfólio - isto é necessário para o cálculo do PL etc.
  • no final, criar um novo resultado de Portfólio e calcular todas as estatísticas

 

 

Código fonte completo do snippet

O código é amplamente comentado, você pode seguir sua lógica.

Ele criará dois novos resultados de Portfólio - um criado por nós manualmente, e outro criado pelo método SQX para comparação.

 

pacote SQ.CustomAnalysis;

import com.strategyquant.lib.SQUtils;
importar com.strategyquant.lib.SettingsMap;
importar com.strategyquant.lib.utils.IUniqueNameChecker;
import com.strategyquant.tradinglib.*;
importar com.strategyquant.tradinglib.project.projectEngine;
import com.strategyquant.tradinglib.results.SpecialValues;
import com.strategyquant.tradinglib.results.stats.comparator.OrderComparatorByOpenTime;
import org.slf4j.logger;
importar org.slf4j.LoggerFactory;

importação java.util.ArrayList;

classe pública CAMergeStrategiesToPortfolio estende o CustomAnalysisMethod {
    logger final estático público = LoggerFactory.getLogger("CAMergeStrategiesToPortfolio");

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

    públicas CAMergeStrategiesToPortfolio() {
        super("Merge Strategies To Portfolio", TYPE_PROCESS_DATABANK);
    }

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

    @Override
    filtro booleano públicoEstratégia(projeto String, tarefa String, banco de dados StringName, ResultsGroup rg) lança Exceção {
        retornar falso;
    }


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

    @Override
    public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) lança Exceção {
        if(databankRG.size() <= 1) {
            // se não houver nenhuma ou apenas uma estratégia, não há nada para fundir
            banco de dados de retornoRG;
        }

        // obter o banco de dados alvo para salvar o resultado final
        Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Portfolios");
        if(targetDatabank == nulo) {
            lançar uma nova exceção ("Por favor, crie um novo banco de dados chamado 'Portfólios' !");
        }

        // ------------------------------
        // Criação manual de portfólio


        // fundir todas as estratégias em banco de dados em um único portfólio
        ResultadosGrupo caPortfolio = fundirEstratégiasToPortfolio(databankRG);

        // criar resultado final de Portfólio para somar todos os sub-resultados
        createPortfolioResultado(caPortfolio);

        // adicionar novo portfólio ao nosso banco de dados alvo
        targetDatabank.add(caPortfolio, falso);


        // ------------------------------
        // Criando portfólio de maneira padrão chamando o método SQ - para controle
        ResultsGroup standardPortfolio = ResultsGroup.merge(databankRG, new String[] { ResultsGroup.AdditionalMarket }, null);

        standardPortfolio.createPortfolioResultado(PortfolioInitialBalanceTypes.SINGLE, nulo);

        targetDatabank.add(standardPortfolio, false);

        banco de dados de retornoRG;
    }

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

    resultados privadosGrupo fundeEstratégiasParaPortfolio(ArrayList banco de dadosRG) lança Exceção {
        ResultsGroup caPortfolio = novos resultadosGroup("PortfolioMadeByCA");

        // adicionar estratégias individuais ao portfólio
        for(ResultadosGrupo rg : banco de dadosRG) {
            addResultado(caPortfolio, rg);
        }

        addSymbolsMap(caPortfolio, databankRG);

        retornar caPortfolio;
    }

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

    nulo privado addSymbolsMap(ResultsGroup rgCSPortfolio, ArrayList databankRG) {
        for(ResultadosGrupo rg : banco de dadosRG) {
            // adicionar todos os símbolos dos RGs fundidos ao mapa de símbolos do portfólio
            rgCSPortfolio.symbols().add(rg.symbols());
        }
    }

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

    vazio privado adicionarResultado(ResultsGroup caPortfolio, ResultsGroup rg) joga Exceção {

        // primeiro criar um novo resultado para a RG em nosso novo portfólio
        // newResultKey será devolvido como resultado chave utilizada em nossa carteira
        String newResultKey = mergeResult(caPortfolio, rg);

        // próximo clone e pedidos de cópia para este resultado da RG para a carteira
        copyOrdersToPortfolio(caPortfolio, rg, newResultKey);

        // adicionar todos os dados de símbolo do RG fundido ao mapa de símbolos do portfólio - isto é necessário para o cálculo do PL etc.
        caPortfolio.symbols().add(rg.symbols());
    }

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

    private String mergeResultado(ResultsGroup caPortfolio, ResultsGroup rg) lança Exceção {
        // obter o principal resultado da estratégia atual - esta é a que estaremos fundindo
        Resultado rgMainResult = rg.mainResult();
        String mainResultKey = rgMainResult.getResultKey();

        // determinar nova chave de resultado - ela deve ser única, então temos que verificar
        // se não houver resultado com esta chave já em nossa carteira
        String newResultKey = rg.getName();

        if(caPortfolio.hasResultado(newResultKey)) {
            // a mesma chave já existe, temos que encontrar uma nova chave
            newResultKey = SQUtils.generateUniqueName(mainResultKey, new IUniqueNameChecker() {
                cheque booleano públicoNameExist(String name) lança Exceção {
                    retornar caPortfolio.hasResultado(nome);
                }
            });
        }

        // criar resultado fundido
        SettingsMap copiedSettingsMap = rgMainResult.getSettings().clone();

        // criar novo anúncio de resultado fundido adicioná-lo ao nosso portfólio
        Resultado fundidoResultado = novo Resultado(newResultKey, caPortfolio, copySettingsMap);
        caPortfolio.addSubresult(newResultKey, copySettingsMap, mergedResult);

        // definir o símbolo e o prazo da estratégia de fusão
        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)));
        copySettingsMap.set(SettingsKeys.PortfolioDataStart, Math.min(rgDateFrom, caDateFrom)); copySettingsMap.set(SettingsKeys.PortfolioDataStart, Math.min(rgDateFrom, caDateFrom));
        copiedSettingsMap.set(SettingsKeys.PortfolioDataEnd, Math.max(rgDateTo, caDateTo)); copiedSettingsMap.set(SettingsKeys.PortfolioDataEnd, Math.max(rgDateTo, caDateTo));

        retornar newResultKey;
    }

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

    private void copyOrdersToPortfolio(ResultsGroup caPortfolio, ResultsGroup rg, String newResultKey) lança Exceção {
        // obter a lista de pedidos de nosso portfólio atual
        OrderList mergedOrdersList = caPortfolio.orders();

        // obter todos os pedidos a partir do resultado da estratégia de fusão - note que eles devem ser clonados!
        String mainResultKey = rg.mainResult().getResultKey();
        OrderList filteredOL = rg.orders().filterWithClone(mainResultKey, Directions.Both, SampleTypes.FullSample);

        // não passar por esses pedidos e adicioná-los à lista de pedidos de carteira
        for(int i=0; i<filteredOL.size(); i++) {
            Pedido = filteredOL.get(i);

            // pedido. SetupName é usado como identificador para que saibamos a que resultado o pedido pertence
            // por isso temos que definir para a novaResultKey
            order.SetupName = newResultKey;

            mergedOrdersList.add(order);
        }
    }

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

    vazio privado criarPortfolioResultado(ResultsGroup caPortfolio) lança Exceção {

        ConfiguraçõesConfiguraçõesMapa = caPortfolio.mainResultado().getSettings();

        Resultado carteiraResultado = novo resultado(ResultsGroup.Portfolio, caPortfolio, settings);

        caPortfolio.removeSubresult(ResultsGroup.Portfolio, true);

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

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

        // para ordens de classificação de portfólio por seu tempo aberto
        OrderList ordersList = caPortfolio.orders();
        orderList.sort(novo OrderComparatorByOpenTime());

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

        caPortfolio.updated = true;
    }

}

 

Este artigo foi útil? O artigo foi útil O artigo não foi útil

Assine
Notificação de
1 Comentário
Mais antigo
Novidades Mais Votados
Feedbacks em linha
Ver todos os comentários
Emmanuel
21. 7. 2022 12:14 pm

Excelente exemplo!! Exatamente o que eu precisava!! Obrigado Mark

Postos relacionados