Documentação

Aplicações

Última atualização em 4. 8. 2021 por Mark Fric

Exemplo - por análise personalizada de estratégia

Faremos uma análise personalizada por estratégia como primeiro exemplo. É apenas uma demonstração simples, mas mostra como usar a análise personalizada também em conjunto com colunas de bancos de dados personalizados.

Este exemplo fará o seguinte:

  • O método de análise personalizado passará pelos resultados armazenados após os backtests estratégicos e calculará quantos crosschecks foram utilizados
  • Uma nova coluna personalizada do banco de dados exibe então este número no banco de dados

 

Passo 1 - Criar novo snippet de análise personalizada

Aberto CodeEditorclique em Criar novos e escolha Análise personalizada (CA) no fundo do poço. Dê-lhe um nome CAExampleStr.

Isto criará um novo snippet CAExemploStr.java em pasta Usuário/Snippets/SQ/CustomAnalysis

Este trecho atualmente é parecido com este:

pacote SQ.CustomAnalysis;

import com.strategyquant.lib.*;

importação java.util.ArrayList;

import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

classe pública CAExampleStr estende o método CustomAnalysisMethod {

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    
    CAExampleStr() {
        super("CAExampleStr", TYPE_FILTER_STRATEGY);
    }
    
    //------------------------------------------------------------------------
    
    @Override
    filtro booleano públicoEstratégia (projeto String, tarefa String, banco de dados StringName, ResultsGroup rg) lança Exceção {
        retornar verdadeiro;
    }
    
    
    //------------------------------------------------------------------------
    
    @Override
    public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) lança Exceção {
        banco de dados de retornoRG;
    }
}

 

Como você pode ver, ele tem três métodos:

CAExampleStr()
um construtor, a única coisa que você deve definir aqui é o nome de seu método CA que aparecerá na IU, e o tipo.

Por padrão, o tipo é TYPE_FILTER_STRATEGY, o que significa que é um método por estratégia.

Outras opções possíveis são:

TYPE_PROCESS_DATABANK - CA que processará todo o banco de dados, vamos mostrá-lo em outro exemplo.
TYPE_BOTH - CA que possui métodos para análise tanto por estratégia como por banco de dados.

O tipo de análise personalizada determina se este snippet é mostrado por estratégia ou por escolha do banco de dados.


filterStrategy()

este é um método que é chamado para cada estratégia antes de ser gravado no banco de dados - se o uso de análise personalizada for configurado. Ele obterá uma estratégia com backtests concluídos e crosscheck (objeto ResultsGroup) e deve retornar verdadeiro/falso.


processDatabank()
é um método que é chamado para processar todo o banco de dados - ele obterá como parâmetro um conjunto de todos os resultados da estratégia (ResultsGroups) e retorna um conjunto de ResutsGroups de volta.

Como nosso método é apenas por estratégia, não precisamos processDatabank() e podemos excluí-lo do snippet.

 

Etapa 2 - Implementar o método filterStrategy()

Toda a "magia" será feita em filterStrategy() aqui, vamos contar o número de verificações cruzadas que foram utilizadas na estratégia. Como fazer isso?

ResultadosGrupo é um objeto que contém a estratégia e todos os resultados do backtest + crosscheckck para a estratégia. Como o nome sugere, é um grupo de resultados que são armazenados sob várias chaves.

Para contar quantos crosschecks foram utilizados, devemos verificar todos os resultados e verificar se os resultados de um determinado crosscheck existem. Caso contrário, a checagem cruzada não foi utilizada.

Para tornar mais complicado, alguns resultados (por exemplo, Monte Carlo) são armazenados de uma forma especial, portanto, devemos determinar seu uso de forma diferente.

No momento da redação deste artigo, há 8 verificações cruzadas diferentes no SQ:

  1. E se as simulações
  2. Manipulação do comércio de Monte Carlo
  3. Maior precisão na retaguarda
  4. Testes de fundo em mercados adicionais
  5. Métodos de reteste Monte Carlo
  6. perfil / Sistema. Parâmetro. Permutação
  7. Otimização do Walk-Forward
  8. Matriz de Avanço

Se você configurar o Retester para realizar todas as verificações cruzadas e depois registrar todas as chaves+resultados que são armazenados no ResultsGroup, você receberá estas chaves:
Portfólio
Principal: EURUSD_M1/H1
CrossCheck_WhatIf
CrossCheck_HigherPrecision
AdditionalMarket: GBPUSD_M1/H1
AdditionalMarket: USDJPY_M1/H1
WF: 10 execuções : 20 % OOS
WF: 5 execuções : 10 % OOS

WF: 15 corridas : 40 % OOS
WF: 20 corridas : 40 % OOS

Observe que o número real de chaves depende também da configuração das verificações cruzadas de chegada. Por exemplo, cada backtest adicional é armazenado sob sua própria chave, o mesmo é válido para as execuções WF + combinações OOS.

Como havia alguns mercados adicionais, há também um Portfólio chave especial que contém resultados para o portfólio de backtests principais + adicionais.

Observe também que não há chaves para Monte Carlo ou Opt. perfil / Sys. Parâmetro. Permutação de resultados, eles são armazenados de outra forma que explicaremos mais adiante.

 

Etapa 3 - Contagem de cheques cruzados "simples

Por simples entendemos os crosschecks que armazenam seus resultados como chaves diferentes em ResultadosGrupo objetos.

Determinar se o crosscheck foi utilizado é simples neste caso, o código para filterStrategy() ficaria assim:

filtro booleano públicoEstratégia(projeto String, tarefa String, banco de dados StringName, ResultsGroup rg) lança Exceção {
        Lista chaves = rg.getResultKeys();
        
        int crosschecksCount = 0;
        boolean additionalMarketUsed = falso;
        int wfCount = 0;
        
        for(int i=0; i 1) {
            // contém a Matriz Walk-Forward
            crosschecksCount+++;
            
            // isto é complicado, quando a matriz WF foi executada não podemos determinar
            // se também estivesse em execução uma única Walk-Forward Optimization,
            // por isso também o contaremos
            crosschecksCount+++;
        }

        // contém manipulação do comércio de Monte Carlo
        // contém métodos de reteste Monte Carlo
        // contém Opt. perfil / Sys. Parâmetro. Permutação
        // A SER FEITO
        ...

Determinação do uso de E se e Maior precisão A verificação cruzada é fácil - verifique apenas se a lista de chaves contém a constante.

Determinação do uso de Testes de fundo em mercados adicionais é semelhante, só devemos estar cientes de que cada backtest adicional é armazenado com sua própria chave.

Determinação do uso de Otimização do Walk-Forward e Matriz também é simples, basta verificar o número (se houver) de chaves com o prefixo "WF:".

A única coisa complicada aqui é que se Matriz de Avanço crosscheck foi usado então não somos capazes de reconhecer se também Otimização do Walk-Forward foi utilizado o crosscheck, pois utiliza a mesma chave para armazenar seu resultado.

Nosso crosschecksCount agora contém o número real desses crosschecks utilizados, exceto para Monte Carlo e Perfil da opção crosschecks que reconheceremos na próxima etapa.

 

Passo 4 - Reconhecendo o uso do crosscheck "especial

Como dito anteriormente, Monte Carlo e Perfil da opção / Sistema. Parâmetro. Permutação Os resultados são armazenados de forma especial.

Em vez de salvá-los sob sua própria chave no ResultsGroup, eles são armazenados em objetos especiais no resultado principal.

Podemos determinar se os resultados da manipulação de Monte Carlo foram utilizados desta forma:

// obter o resultado principal, é aqui que são armazenadas as simulações de Monte Carlo
Resultado mainResultado = rg.mainResultado();
        
if(mainResult.getInt("MonteCarloManipulation_NumberOfSimulations") > 0) {
// contém resultado da manipulação do comércio de Monte Carlo
        crosschecksCount+++;
}

O resultado principal é o principal resultado de backtest, aqui é onde os resultados MC são armazenados. Nós simplesmente tentamos obter uma série de simulações de MC, e se for maior que 0 sabemos que contém alguns resultados de manipulação de MC.

Podemos verificar o uso de Monte Carlo para fazer o teste cruzado de forma semelhante:

if(mainResult.getInt("MonteCarloRetest_NumberOfSimulations") > 0) {
    // contém resultado da manipulação do comércio de Monte Carlo
    crosschecksCount+++;
}

O último a verificar é Opt. perfil / Sys. Parâmetro. Permutação. É armazenado em seu próprio objeto em ResutsGroup, nós simplesmente verificaremos se o objeto existe lá:

if(rg.getOptimizationProfile() != null) {
        // contém Opt. perfil / Sys. Parâmetro. Resultado da permutação
        crosschecksCount+++;
    }

 

Passo 5 - Salvar a contagem para resultados estratégicos

Agora que temos a contagem dos crosschecks utilizados, queremos exibi-la em uma nova coluna de banco de dados (que será criada mais tarde)

Neste momento, temos o número de crosschecks salvos em um crosschecksCount variável, mas precisamos salvá-lo como um dado personalizado para ResultsGroup, para que o snippet de coluna do banco de dados possa recuperá-lo quando ele estiver exibindo seu valor.

Felizmente, isto é bastante simples - podemos salvar qualquer objeto para os valores especiais do ResultsGroup por telefone:

rg.specialValues().set(String key, Object value);

em nosso caso:

rg.specialValues().set("CA_NumberOfCrosschecks", crosschecksCount);

Recuperaremos este valor na próxima etapa para exibi-lo no banco de dados.

Como última coisa, voltaremos a ser verdadeiros porque não utilizaremos esta análise personalizada para a filtragem.


Nota -
Se você quiser usar análise personalizada para filtragem, simplesmente retornará verdadeiro ou falso neste método com base nos cálculos dos backtests da estratégia e, dependendo disso, a estratégia é descartada ou salva no banco de dados.

Assim, o código completo do nosso filterStrategy() método é:

    @Override
filtro booleano públicoEstratégia (projeto String, tarefa String, banco de dados StringName, ResultsGroup rg) lança Exceção {
    Lista chaves = rg.getResultKeys();
    
    int crosschecksCount = 0;
    boolean additionalMarketUsed = falso;
    int wfCount = 0;
    
    for(int i=0; i 1) {
        // contém resultados do Walk-Forward Matrix
        crosschecksCount+++;
        
        // isto é complicado, quando a matriz WF foi executada não podemos determinar
        // se também estivesse em execução uma única Walk-Forward Optimization,
        // por isso também o contaremos
        crosschecksCount+++;
    }

    // obter o resultado principal, é aqui que são armazenadas as simulações de Monte Carlo
    Resultado mainResultado = rg.mainResultado();
    
    if(mainResult.getInt("MonteCarloManipulation_NumberOfSimulations") > 0) {
        // contém resultado da manipulação do comércio de Monte Carlo
        crosschecksCount+++;
    }

    if(mainResult.getInt("MonteCarloRetest_NumberOfSimulations") > 0) {
        // contém resultado da manipulação do comércio de Monte Carlo
        crosschecksCount+++;
    }
    
    if(rg.getOptimizationProfile() != null) {
        // contém Opt. perfil / Sys. Parâmetro. Resultado da permutação
        crosschecksCount+++;
    }
    
    
    rg.specialValues().set("CA_NumberOfCrosschecks", crosschecksCount);
    
    retornar verdadeiro;
}

 

Passo 6 - Adicionar nova coluna de banco de dados

Calculamos o número de checagens cruzadas usadas em snippet de análise personalizada e agora queremos exibi-la no banco de dados. Para fazer isso, precisamos criar uma nova coluna de banco de dados.

Novamente, clique em Criar novos em CodeEditor e, desta vez, criar uma nova coluna de banco de dados. Dê-lhe um nome NumberOfCC.

O código padrão para o snippet de coluna do banco de dados é parecido com este:

pacote SQ.Colunas.Bancos de dados;

import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

classe pública NumberOfCC estende o DatabankColumn {
    
  público NúmeroOfCC() {
    super("NumberOfCC",
          Decimal2, // formato de exibição de valores
          ValorTipos.Maximizar, // se o valor deve ser maximizado / minimizado / aproximado a um valor
          0, // valor-alvo se a aproximação foi escolhida
          0, // mínimo médio deste valor
          100); // máximo médio deste valor
    
    setWidth(80); // largura da coluna padrão em pixels
    
    setTooltip("Sua ponta de ferramenta aqui");
    
    /* Se esta nova coluna depende de algumas outras colunas que têm que ser computadas primeiro, coloque-as aqui.
       Certifique-se de não criar dependência circular, tal como A depende de B e B depende de A.
       As colunas (= valores de estatísticas) são identificadas pelo nome da classe)
    */
    //setDependências("DrawdownPct", "NumberOfTrades");
  }
  
  //------------------------------------------------------------------------

  /**
   * Este método deve retornar o valor computado desta nova coluna. Normalmente, você deve calculá-lo a partir da lista de ordens
   * ou a partir de alguns valores estatísticos já computados (outras colunas de banco de dados).
   */
  @Override
  duplo cálculo público(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) lança Exceção {
    
    /* um exemplo - é assim que você pode obter outros valores dos quais este novo valor depende */
    //int numberOfTrades = stats.getInt("NumberOfTrades");
    //douplo drawdownPct = stats.getDouble("DrawdownPct");
    
    /* um exemplo - cálculo do lucro líquido a partir da lista de negócios */
    duplo netProfit = 0;

    for(int i = 0; i<ordersList.size(); i++) {
      Order Order = OrderList.get(i);
      
      if(order.isBalanceOrder()) {
        // não contar as ordens de saldo (depósitos, saques) em
        continuar;
      }
      
      /* método getPLByStatsType retorna PL automaticamente dependendo do tipo de estatística - em dinheiro, % ou pips */
      double PL = getPLByStatsType(pedido, combinação);
      
      netProfit += PL;
    }

    /* arredondar e devolver o valor. Ele será salvo em estatísticas sob a chave "NumberOfCC" */
    retornar round2(netProfit);
  }
}

Ele tem um compute() método que pode passar por estatísticas e ordens para calcular a métrica particular.

Em nosso caso não precisamos disso, não usaremos nada dos pedidos, em vez disso recuperaremos o valor de CA_NumberOfCrosschecks que calculamos na análise personalizada.

Assim, podemos apagar o todo compute() método e usar um método especial getValue() ao invés disso. Este não é gerado por padrão, ele é usado para recuperar valores especiais, por exemplo, símbolo e cronograma.

getValue() obtém o ResultadosGrupo como parâmetro e retorna um String que é exibido no banco de dados para esta coluna.

Nossa coluna simplificada de banco de dados tem este aspecto:

pacote SQ.Colunas.Bancos de dados;

import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

classe pública NumberOfCC estende o DatabankColumn {
    
  público NúmeroOfCC() {
    super("NumberOfCC", DatabankColumn.Decimal2, ValueTypes.Maximize, 0, 0, 100);
  }
  
  //------------------------------------------------------------------------
  
  @Override
  public String getValue(ResultsGroup rg, String resultKey, byte direction, byte plType, byte sampleType) lança Exceção {
    int value = rg.specialValues().getInt("CA_NumberOfCrosschecks", -1);
    
    if(valor == -1) {
      // isto significa que o valor não foi definido
      retornar NOT_AVAILABLE;
    senão...
      // valor de retorno convertido em String
      retornar java.lang.Integer.paraString(valor);
    }
  }
}

 

Note que utilizamos uma chamada:

rg.specialValues().getInt("CA_NumberOfCrosschecks", -1);

para obter o valor previamente armazenado por análise personalizada como int (número).

O valor -1 é o padrão, ele será usado se não houver valor para a chave CA_NumberOfCrosschecks será encontrado. Isto acontecerá se não configurarmos a interface de usuário para executar nosso método de análise personalizado.

Neste caso, devolveremos o fio N/A.

 

Nota especial sobre a filtragem de acordo com esta coluna

Como esta coluna de banco de dados é especial, e seu valor é calculado por análise personalizada, ela NÃO PODE ser usada em filtros personalizados no Ranking. Isto não funcionará porque estes filtros são avaliados antes do início da análise personalizada, e esta coluna não terá valor então.

Para filtrar usando valores computados por análise personalizada, por favor use o retorno verdadeiro/falso do filterStrategy() método em snippet de análise personalizada.

 

Passo 7 - Fazer tudo funcionar

Após a compilação bem sucedida de nossos novos trechos em CodeEditor e reinício de StrategyQuant agora podemos tentar usá-lo. Podemos fazer isso no Retester para ver como funciona.

Primeiro crie uma nova visualização do banco de dados, vamos criar uma nova visualização CA View e adicionar algumas colunas + nossa nova coluna NumberOfCC lá.

Quando mudarmos para esta visão, veremos que nossa nova coluna é N/A:

É porque o valor que ele está exibindo ainda não foi computado.

Portanto, vamos usar o novo snippet de análise personalizada no Retester - só devemos configurá-lo na guia Ranking da seguinte forma:

Nosso exemplo de snippet de análise personalizada será agora aplicado a toda estratégia que for testada novamente no Retester antes de ser salva em um banco de dados.

Então, vamos tentar ligar alguns cheques cruzados em Retester e dirigi-lo.

Dependendo de quantos crosschecks você realmente selecionou, agora você deve ver algum número na nova coluna:

 

Conclusão

Esta foi uma demonstração simples da nova funcionalidade de análise personalizada aplicada por estratégia. Como você pode ver:

  • pode ser usado para calcular novas métricas que cruzam os limites de um único backtest ou crosscheck
  • pode ser usado para implementar novas métricas que são mostradas no banco de dados
  • pode ser utilizado para filtragem (devolvendo falsos)

 

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

Assine
Notificação de
5 Comentários
Mais antigo
Novidades Mais Votados
Feedbacks em linha
Ver todos os comentários
tan8858
tan8858
21. 8. 2021 3:32 pm

Favor liberar o código completo para o passo 5 (melhor como o passo 6 Exemplo)
Em meu editor de código, ele relata um erro
"não consegue encontrar símbolo símbolo:class List location:class SQ.CustomAnalysis.CAExampleStr"

Lista chaves = rg.getResultKeys();

Desculpe, sou novo nisto e não consegui encontrar o erro.

Emmanuel
Responder a  tan8858
26. 11. 2021 4:17 pm

Eu também, estou recebendo o mesmo erro.

Emmanuel
Responder a  tan8858
26. 11. 2021 4:54 pm

Acho que temos de acrescentar : importação java.util.*;  
na parte superior do código
Deve funcionar

tan8858
tan8858
Responder a  Emmanuel
28. 11. 2021 10:00 am

Obrigado!

Emmanuel
25. 11. 2021 8:59 pm

Excelente!