Discussão do artigo "Receitas MQL5 - Criamos um buffer circular para calcular rapidamente indicadores numa janela deslizante"
Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação
fxsaber, 2016.09.16 14:32
void OnStart() { double Index = -345.23; double Size = -432.98; double Array[]; // Qualquer tamanho (e não um número inteiro) funcionará. ArrayResize(Array, (int)Size < 0 ? (int)MathAbs(Size) : (int)Size); // Em qualquer índice (e não inteiro) ALWAYS (exceto zero - se o tamanho do array for zero) será executado sem erros. // Assim, a matriz se torna uma cópia infinita de si mesma em ambas as direções Array[(int)Index < 0 ? ArraySize(Array) + ((int)Index % ArraySize(Array)) : (int)Index % ArraySize(Array)] = 1; }
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- bool calc = false; for(int i = prev_calculated; i < rates_total; i++) { Sma.AddValue(price[i]); buff[i] = Sma.SMA(); calc = true; } if(!calc) { Sma.ChangeValue(MaPeriod-1, price[rates_total-1]); buff[rates_total-1] = Sma.SMA(); } return(rates_total-1); }
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- if (prev_calculated < rates_total) for(int i = prev_calculated; i < rates_total; i++) { Sma.AddValue(price[i]); buff[i] = Sma.SMA(); } else { Sma.ChangeValue(MaPeriod-1, price[rates_total-1]); buff[rates_total-1] = Sma.SMA(); } return(rates_total-1); }
ZY Se o prev_calculated estiver zerado, haverá erros.
Artigo muito bom sobre um tópico muito importante.
Obuffer em anel é um mecanismo crucial.
Além do artigo, gostaria de acrescentar minha ideia de como o uso de buffers em anel pode ser desenvolvido ainda mais:
Se, paralelamente ao registro dos valores de um parâmetro em um buffer em anel, for criado um segundo buffer em anel para esse parâmetro, que registrará o tempo entre as alterações de valores no primeiro buffer, uma curva das alterações de valores no período atual poderá ser construída a partir dos dados de ambos os buffers em anel. Além disso, com a ajuda de operações matemáticas, é possível extrair o caráter da alteração do valor do parâmetro, ou seja, sua assinatura atual, e trabalhar não com valores específicos, mas com o contexto da alteração do parâmetro para todo o período atual.
P.S. Seria ótimo se alguém pudesse implementar isso como um mecanismo independente. Você pode tentar?
Obrigado pelo artigo! Tenho algumas perguntas e comentários cáusticos.)
По возможности избегайте запросов по получению данных множества таймфреймов. Вместо этого для расчетов воспользуйтесь одним (наименьшим) таймфреймом. Например, если вам требуется рассчитать два индикатора на M1 и H1, получите данные M1, сконвертируйте их в H1 и затем подайте эти данные для расчета индикатора на H1. Такой подход сложнее, но позволит существенно сэкономит память.
A que se deve a economia?
A série temporal H1 gerada pelo terminal ocupa mais memória do que a mesma série temporal gerada dentro do Expert Advisor?
No entanto, ainda precisamos de quase 3 GB de RAM. Há alguma outra maneira de reduzir esse valor? É possível, se otimizarmos o número de timeframes. Vamos tentar alterar um pouco o código de teste e usar apenas um período de tempo em vez de 21 - PERIOD_M1. O número de indicadores permanecerá o mesmo, apenas alguns deles serão duplicados:
Agora, os mesmos 504 indicadores no modo de cálculo interno ocupam 548 MB de RAM.
Não entendo essa mudança de jeito nenhum. Como você pode comparar o cálculo de indicadores para 21 períodos de tempo com o cálculo para 1 TF? Os resultados dos cálculos são bastante diferentes, que diferença faz a quantidade de memória utilizada?
É difícil encontrar uma aplicação mais relevante para os buffers em anel do que na negociação. É ainda mais surpreendente que esse algoritmo de construção de dados não tenha sido abordado na comunidade MQL até agora.
Konstantin Gruzdev postou sua aula e alguns exemplos em 2012. Se você fizer uma pesquisa, poderá encontrá-los.
Em geral, é claro, a técnica é boa. Uma desvantagem é que todos os indicadores precisam ser reescritos.
Obrigado pelo artigo! Tenho algumas perguntas e comentários cáusticos.)
Se possível, evite consultas para recuperar dados de vários períodos de tempo. Em vez disso, use um período de tempo (o menor) para os cálculos. Por exemplo, se você precisar calcular dois indicadores em M1 e H1, obtenha os dados de M1, converta-os em H1 e, em seguida, alimente esses dados para calcular o indicador em H1. Essa abordagem é mais complicada, mas economizará memória.
O que economizarámemória?
A série temporal H1 gerada pelo terminal ocupa mais memória do que a mesma série temporal gerada dentro do Expert Advisor?
Infelizmente, sim. E muito mais. E não importa se você solicitou uma barra ou todo o histórico disponível. Todos os dados do período de tempo especificado serão copiados para a memória interna. Não sei exatamente o quanto será copiado, mas, de acordo com minhas medições de memória, vi que quase tudo é copiado.
No entanto, ainda precisamos de quase 3 GB de RAM. Há alguma maneira de reduzir esse número? É possível, se você otimizar o número de timeframes. Vamos tentar alterar um pouco o código de teste e usar apenas um período de tempo em vez de 21 - PERIOD_M1. O número de indicadores permanecerá o mesmo, apenas alguns deles serão duplicados:
Agora, os mesmos 504 indicadores no modo de cálculo interno ocupam 548 MB de RAM.
Não entendo essa mudança de jeito nenhum. Como você pode comparar o cálculo de indicadores para 21 períodos de tempo com o cálculo para 1 TF? Os resultados dos cálculos são bem diferentes, que diferença faz a quantidade de memória usada?
Se você usar apenas um período de tempo menor para calcular vários indicadores em períodos de tempo diferentes, você economizará memória. Suponha que haja dois indicadores, um conta os valores em M1 e o outro em H1. Podemos carregar cotações para M1 e para H1. Podemos carregar cotações para cada indicador e obter valores a partir delas. No entanto, somente devido ao fato de que H1 será carregado, o uso da memória aumentará muito. Portanto, se solicitarmos o M1, convertermos o M1 em H1 e alimentarmos o indicador com esses dados no H1, a memória será significativamente economizada. Essa economia é obtida devido ao fato de que os buffers internos do MetaTrader alocam muito mais memória para armazenar cotações H1 do que se essas cotações fossem armazenadas dentro do Expert Advisor.
Outro recurso interessante que não foi mencionado no artigo. O modelo de alocação de memória no testador de estratégia é diferente e muito mais econômico. Ele aloca muito menos memória quando vários timeframes são usados, mas tudo é calculado normalmente.
...
Em geral, havia três objetivos ao escrever o artigo:
- Criar algoritmos rápidos para cálculos de indicadores dentro do Expert Advisor (concluído).
- Criar uma interface conveniente para cálculos no buffer em anel (concluído).
- Criar um cálculo de economia de memória (não implementado).
Artigo muito bom sobre um tópico muito importante.
O buffer em anel é um mecanismo crucial.
Além do artigo, gostaria de acrescentar minha ideia de como o uso de buffers em anel pode ser desenvolvido ainda mais:
Se, paralelamente ao registro dos valores de um parâmetro em um buffer em anel, for criado um segundo buffer em anel para esse parâmetro, que registrará o tempo entre as alterações de valores no primeiro buffer, uma curva das alterações de valores no período atual poderá ser construída a partir dos dados de ambos os buffers em anel. Além disso, com a ajuda de operações matemáticas, é possível extrair o caráter da alteração do valor do parâmetro, ou seja, sua assinatura atual, e trabalhar não com valores específicos, mas com o contexto da alteração do parâmetro para todo o período atual.
P.S. Seria ótimo se alguém pudesse implementar isso como um mecanismo independente. Você já experimentou?
O que você descreve é apenas um indicador. Crie uma classe, digamos CTradeChange. Dentro dela, coloque dois buffers em anel síncronos: um armazena N últimos preços e o outro N últimos valores de tempo:
CTradeChange change;
...
change.Add(value, TimeCurrent());Em seguida, no método Add, calcule a diferença entre o valor de tempo atual e o anterior.
Em geral, havia três objetivos ao escrever o artigo:
- Criar algoritmos rápidos para cálculos de indicadores dentro do Expert Advisor (concluído).
- Criar uma interface conveniente para cálculos no buffer de anel (concluído).
- Criar um cálculo de economia de memória (não implementado).
Obrigado por suas respostas.
Ao desenvolver o painel mencionado no artigo, percebi a necessidade de limitar o número de barras exibidas nos gráficos (5000). Justamente por causa da memória...
No MT4 era muito mais fácil: em primeiro lugar, cada TF era carregado independentemente, portanto, não era necessário carregar o M1 e, em segundo lugar, os buffers de indicadores ocupavam o espaço que você preenchia (até mesmo 100 barras, se você não precisasse de mais).
No 5, ele se tornou mais universal e integral devido à geração de TFs a partir do M1, mas a memória pode ser difícil.
O que você descreve é apenas um indicador. Crie uma classe, digamos CTradeChange. Dentro dela, coloque dois buffers em anel síncronos: um armazena N últimos preços e o outro N últimos valores de tempo:
Em seguida, no método Add, calcule a diferença entre o valor de tempo atual e o anterior.
Você deu uma resposta estranha. Parece que você não entendeu a ideia de forma alguma. Vou citá-la novamente:
"Se, paralelamente ao registro dos valores de parâmetro no buffer de anel, criar para esse parâmetro um segundo buffer de anel, que registrará o tempo entre as alterações de valores no primeiro buffer, então, com base nos dados de ambos os buffers de anel, será possível criar uma curva de alterações de valor no período atual. Além disso, usando operações matemáticas, você pode extrair a natureza da alteração no valor do parâmetro, ou seja, sua assinatura atual, e trabalhar não com valores específicos, mas com o contexto da alteração do parâmetro durante todo o período atual."
Observe que eu não perguntei como construir dois buffers em anel síncronos, pois seu mecanismo é bastante simples, mas sugeri tentar desenvolver o escopo de aplicação dos buffers em anel além do descrito no artigo.
A área de aplicação proposta por você no artigo é a obtenção de valores específicos por índices dentro do período atual.
Minha proposta de extensão da área é obter assinaturas de alterações nos valores dentro do período atual. Isso pode ser feito traçando uma curva (não em um gráfico) com base nos dados de dois buffers em anel:
1. buffer com valores do período atual.
2. buffer com intervalos de tempo entre os valores do primeiro buffer.
Ao combinar os dados, é possível traçar a curva matematicamente (não necessariamente em um gráfico) e representá-la e estudá-la algoritmicamente dentro do programa. Para fazer isso, é necessário examinar os dois buffers e considerar a assinatura da alteração do parâmetro.
Essa solução abre a possibilidade de operar não apenas com valores específicos do parâmetro em um período, mas com a assinatura de sua alteração durante todo o período.
Por exemplo, será possível especificar ao programa:
if(Характер_изменения_значения_параметра_за_период == BIG_WAVE)Лот += 10;
A constante BIG_WAVE é a assinatura, que expressa o caráter da alteração do valor para o período atual.
Por exemplo, podemos criar 5 padrões de assinaturas:
FLAT, RISING, BIG_WAVE, FALLING, SMALL_WAVES.
Cada uma dessas constantes é um padrão de um determinado caráter da alteração do parâmetro no período atual.
Precisamos desenvolver o formato do registro de assinatura e criar esses modelos. Em seguida, o algoritmo lerá a assinatura atual e a comparará com os modelos, encontrando as correspondências mais próximas (não pode haver correspondência absoluta) entre a natureza da alteração atual e um dos modelos.
As vantagens dessa abordagem em relação ao uso padrão de valores específicos são óbvias.
O uso de assinaturas torna possível basear as decisões no contexto extraído do conjunto de dados e não tentar extrair esse contexto de valores únicos.
P.S. Espero que você tenha entendido o que eu quis dizer dessa vez.
Essa é uma resposta estranha que você deu. Parece que você não entendeu a questão. Vou citá-la novamente:
...
Minha proposta de extensão do domínio é obter assinaturas de alterações nos valores dentro do período atual. Isso pode ser feito traçando uma curva (não em um gráfico) com base nos dados dos dois buffers de anel:
P.S. Espero que tenha entendido meu argumento desta vez.
Também entendi perfeitamente seu ponto de vista da primeira vez.
O que é uma "assinatura de alteração de valor"? É um valor que muda na dinâmica. Portanto, é um indicador. Não é necessário desenvolver um buffer em anel para essa finalidade, mas basta criar, com base em vários desses indicadores em anel, um algoritmo para calcular o próprio "caráter de mudança" de que você está falando.
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Novo artigo Receitas MQL5 - Criamos um buffer circular para calcular rapidamente indicadores numa janela deslizante foi publicado:
O buffer circular é a maneira mais simples e eficaz de organizar os dados para os cálculos numa janela deslizante. Este artigo descreve como está construído este algoritmo e mostra como usá-lo para fazer o cálculo numa janela deslizante usando um processo simples e eficiente.
No início do cálculo, o indicador simplesmente adiciona os novos valores no buffer circular de média móvel. Não é necessário controlar o número de valores adicionados. Todos os cálculos e remoção de elementos obsoletos ocorre no modo automático. Se a chamada do indicador acontecer ao alterar o preço da última barra, só será preciso mudar o último valor da média móvel para um novo, o método ChangeValue toma conta disso.
A exibição gráfica do indicador é equivalente ao indicador padrão MovingAverage:
Fig. 1. Exibição da média móvel simples calculada num buffer circular.
Autor: Vasiliy Sokolov