Transferência de um Código Indicador para um Código Expert Advisor. Estrutura do Indicator
Nikolay Kositsin | 19 fevereiro, 2016
Introdução
Para melhor compreensão, o autor recomenda a leitura do seguinte material:
- MetaQuotes Software Corp. Características de Criação de Indicadores Personalizados.
- Nikolay Kositsin. Recontagem de barras nulas em em alguns indicadores.
Antes de começar a me debruçar sobre o tema do artigo, indicado no título, a seguinte pergunta seria bastante apropriada: "Para quê precisamos transferir um código indicador para um código EA, se na maioria dos casos, um EA, operando com indicadores personalizados, parece muito mais fácil do que o seu análogo, que contém todas as informações necessárias sobre os indicadores personalizados de operação dentro do próprio código? Especialmente se levarmos em consideração o fato de que, se um código é escrito corretamente, os resultados em ambos os casos serão absolutamente idênticos! "
- Se os valores de cálculo do EA calculados em uma barra zero não forem usados, naturalmente gostaríamos de omitir um recálculo desnecessário na barra zero e na primeira barra. Isto permite encurtar em três vezes o tempo de tal otimização do EA, o que é bastante relevante em um código muito complicado e com intensivo uso de recursos!
- O uso comercial de um Expert Advisor com a proteção máxima de seu código contra descompilação.
No segundo caso, a situação é bem clara e a transferência de código é razoável. E, no primeiro caso, na maioria das situações, é muito mais fácil reescrever códigos de indicadores personalizados, exceto os cálculos desnecessários! Naturalmente, tais indicadores são adequados apenas para o Expert Advisors, e não para uma negociação! Então, vamos começar a nossa discussão desta variante da solução do problema.
Exemplo de Otimização do Indicador
Primeiramente, gostaria de chamar atenção para o seguinte fragmento de código de um indicador personalizado:
int start() { int limit; int counted_bars = IndicatorCounted(); //---- the last calculated bar will be recalculated if(counted_bars > 0) counted_bars--; limit = Bars - counted_bars - 1; //---- the main cycle for(int i = limit; i >= 0; i--) { //---- ExtBlueBuffer[i] = iMA(NULL, 0, JawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtRedBuffer[i] = iMA(NULL, 0, TeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtLimeBuffer[i] = iMA(NULL, 0, LipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); } //---- return(0); }Neste caso, a seguinte linha é relevante:
if(counted_bars > 0) counted_bars--;
O significado desta verificação com diminuição do valor variável ''counted_bars" por um é o seguinte: se um indicador personalizado não incluir esta linha, ele pode enviar valores errados de seus buffers para um EA, quando a barra zero for alterada. A curva de indicador no EA terá uma forma "amassada".
Na indicadores personalizados, as variáveis 'limit' e "counted_bars" podem ter nomes diferentes, mas o código do programa deve ter essas verificações! Suponho que esta explicação é suficiente para esclarecer alegações de que alguns escritos em EA e em dados MetaTrader de buffer de indicador os mesmos dados recebidos de um indicador personalizado não são idênticos. Se um código de indicador e um código de EA estiverem escritos corretamente, não importa o quão difícil seja o código indicador, os dados serão sempre iguais!
Mas deve-se notar aqui, que alguns algoritmos suaves são sensíveis ao ponto de referência, a partir do qual começa a suavização. Isto é, a fim de ter valores idênticos, os números das barras mais antigas, a partir dos quais o novo cálculo de todas as barras inicia, em ciclos tanto no indicador e no código do indicador no interior do EA devem coincidir.
Aqui está um exemplo explicando este método de otimização de um código indicador para a sua operação mais rápida em um EA. No ciclo principal do indicador mudar de zero para um, depois que o indicador descontinuar para recalcular o seu valor na barra zero.
// instead of for(int i = limit; i >= 0; i--) // write for(int i = limit; i >= 1; i--)Como resultado, o código fonte terá a seguinte aparência:
int start() { int limit; int counted_bars = IndicatorCounted(); //---- the last bar will be recalculated if(counted_bars > 0) counted_bars--; limit = Bars - counted_bars - 1; //---- the main cycle //now the cycle ends in 1 for(int i = limit; i >= 1; i--) { //---- ExtBlueBuffer[i] = iMA(NULL, 0, JawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtRedBuffer[i] = iMA(NULL, 0, TeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtLimeBuffer[i] = iMA(NULL, 0, LipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); } //---- return(0); }
Vou repetir, o método acima é para os EA em funcionamento apenas nas barras fechadas, isto é, em todas as barras exceto a barra zero!
Se você estiver indo utilizar seriamente seu EA em negociações reais e confiar seu dinheiro, você deve verificar cuidadosamente todos os detalhes em seu Expert Advisor, bem como os indicadores com os quais o EA trabalha. Além disso, você deve fazê-lo sozinho! Penso que é muito mais fácil e mais inteligente dedicar alguns dias para uma compreensão completa da estrutura e dos métodos de otimização de códigos do que ter paciência durante durante três meses com um EA que recebe valores de um indicador mal escrito!
Então, deve ficar claro que é preciso sérias razões para a transferência de um código indicador para um código EA. Se um indicador estiver escrito corretamente, a operação do EA não vai ser muito mais lenta. É mais fácil escrever primeiro um código EA utilizando indicadores personalizados e conferir desta forma. Se o EA realmente mostrar resultados perfeitos, o código pode ser ainda mais otimizado, um por um mudando chamadas para indicadores personalizados em fragmentos de códigos indicadores.
E deve-se notar que os valores testados de perda e de lucro não devem ser modificados após a alteração do código EA!
O número de indicadores existentes é muito grande, cada um deles possui seu próprio código. É por isso que dificilmente se pode criar um método universal de transferência de código para todos os indicadores. O problema é agravado pelo fato de que um único e mesmo indicador personalizado pode ser representado em um código EA diversas vezes. Se um código indicador é mais ou menos simples, ele pode ser escrito em uma função personalizada e mudar a função de indicadores personalizados é muito fácil neste caso. Mas muitas vezes em que um código EA alcança tais dimensões, é quase impossível detectar um erro. E todos os nossos esforços são em vão.
Esquema geral de uma estrutura de indicador
Antes de começar a me debruçar sobre o tema principal do artigo, em primeiro lugar, vamos analisar uma estrutura de indicador do ponto de vista de um programador que está interessado no indicador como parte de um futuro código EA:
//+------------------------------------------------------------------+ //| IndicatorPlan.mq4 | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- drawing the indicator in the main window #property indicator_chart_window //---- number of indicator buffers #property indicator_buffers 1 //---- indicator color #property indicator_color1 Gold //---- INPUT PARAMETERS OF THE INDICATOR extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- indicator buffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- defining the graph execution style SetIndexStyle(0, DRAW_LINE); //---- 3 indicator buffers are used for calculation IndicatorBuffers(3); SetIndexBuffer(0, Ind_Buffer0); SetIndexBuffer(1, Ind_Buffer1); SetIndexBuffer(2, Ind_Buffer2); //---- end of initialization return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(Bars < period0 + period1 + period2) return(0); //----+ Insertion of variables with a floating point double Resalt0, Resalt1, Resalt2; //----+ Insertion of integer variables and getting calculated bars int limit, MaxBar,bar, counted_bars = IndicatorCounted(); //---- checking for possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated limit = Bars - counted_bars - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated MaxBar = Bars - 1 - (period0 + period1 + period2); //---- initialization of zero if(limit > MaxBar) { limit = MaxBar; for(bar = Bars - 1; bar >= MaxBar; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ THE FIRST CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt1 calculation based on the external // variable period1 Ind_Buffer1[bar] = Resalt1; } //----+ THE SECOND CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt2 calculation // based on the values of the buffer Ind_Buffer1[] // and external variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ THE MAIN CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt0 calculation // based on the values of the buffer Ind_Buffer2[] // and external variable0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+
Naturalmente, um indicador real pode ter um número diferente dos valores refletidos pelo indicador, um número diferente de buffers de indicadores utilizados nos cálculo e números diferente de ciclos de valores de cálculo do buffer de indicador, mas isso não modifica o sentido do esquema apresentado. Em outros casos, será absolutamente análogo.
Agora vamos excluir os elementos do esquema que não são interessantes para nós neste contexto e que não são necessários em um Expert Advisor:
//+------------------------------------------------------------------+ //| IndicatorPlan1.mq4 | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ //---- INPUT PARAMETERS OF THE INDICATOR extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- indicator buffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- end of initialization return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(Bars < period0 + period1 + period2) return(0); //----+ Insertion of variables with a floating point double Resalt0, Resalt1, Resalt2; //----+ Insertion of integer variables and getting calculated bars int limit, MaxBar, bar, counted_bars = IndicatorCounted(); //---- checking for possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated limit = Bars - counted_bars - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated MaxBar = Bars - 1 - (period0 + period1 + period2); //---- initialization of zero if(limit > MaxBar) { limit = MaxBar; for(bar = Bars - 1; bar >= MaxBar; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ THE FIRST CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt1 calculation // based on the external variable period1 Ind_Buffer1[bar]= Resalt1; } //----+ THE SECOND CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt2 calculation // based on the values of the buffer Ind_Buffer1[] // and external variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ THE MAIN CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt0 // based on the values of the buffer Ind_Buffer2[] // and external variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+
Este código pode ser facilmente colocado em um Código do Expert Advisor, se não fosse, infelizmente, por um par de pequenos erros:
- Primeiro de tudo, não devemos esquecer, que a função IndicatorCounted () não funciona no Expert Advisors!
- Também não podemos virar as matrizes personalizadas em direção aos indicadores no bloco de inicialização!
Assim, para uma preservação integral do código indicador, primeiramente, precisamos desenvolver um análogo da função IndicatorCounted () e de alguma forma emular análogos de buffers de indicadores em um Expert Advisor. Infelizmente, é impossível emular diretamente buffers de indicadores em um EA utilizando as funções padrão. Até agora não há análogos de SetIndexBuffer () e IndicatorBuffers() para Expert Advisors! Portanto, este problema deve ser resolvido de outras maneiras. Além disso, para isto, existem opções suficientes no MQL4.
Emulação de Buffers de indicadores no Expert Advisor
- Valores que são atribuídos às variáveis dos buffers indicadores não são perdidos entre os ciclos, quando o indicador está ligado a um gráfico e um terminal.
- Se uma barra zero (a mais recente) for alterada em um gráfico, todos os elementos do buffer do indicador serão deslocados.
- Se vier uma barra nova, o valor do limite variável mudará de um para dois, o indicador, e todos os elementos do buffer serão deslocados por um, por exemplo, uma barra zero torna-se a primeira, a primeira torna-se segunda e assim por diante.
-
Naturalmente as dimensões do buffer de indicador mudam. Se no próximo crédito a barra não mudar, todos os elementos do buffer permanecem no lugar.
//---- INDICATOR BUFFERS EMULATION int NewSize = iBars(symbol, timeframe); //---- Checking the change of the zero bar if(ArraySize(Ind_Buffer0) < NewSize) { //---- Set the direct indexing direction in the array ArraySetAsSeries(Ind_Buffer0, false); ArraySetAsSeries(Ind_Buffer1, false); ArraySetAsSeries(Ind_Buffer2, false); //---- Change the size of the emulated indicator buffers ArrayResize(Ind_Buffer0, NewSize); ArrayResize(Ind_Buffer1, NewSize); ArrayResize(Ind_Buffer2, NewSize); //---- Set the reverse indexing direction in the array ArraySetAsSeries(Ind_Buffer0, true); ArraySetAsSeries(Ind_Buffer1, true); ArraySetAsSeries(Ind_Buffer2, true); } //----
A propósito, este método de emulação de buffers de indicadores pode também ser usado em indicadores quando oito buffers de indicadores não forem suficientes para cálculos intermediários. Os exemplos estão nos arquivos anexados SMI.mq4 e SMI_New.mq4.
Substituição da função IndicatorCounted()
//+------------------------------------------------------------------+ //| NewIndicatorPlan1.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ //---- INPUT INDICATOR PARAMETERS extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- indicator buffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(Bars < period0 + period1 + period2) return(0); //---- INDICATOR BUFFERS EMULATION if(ArraySize(Ind_Buffer0) < Bars) { ArraySetAsSeries(Ind_Buffer0, false); ArraySetAsSeries(Ind_Buffer1, false); ArraySetAsSeries(Ind_Buffer2, false); //---- ArrayResize(Ind_Buffer0, Bars); ArrayResize(Ind_Buffer1, Bars); ArrayResize(Ind_Buffer2, Bars); //---- ArraySetAsSeries(Ind_Buffer0, true); ArraySetAsSeries(Ind_Buffer1, true); ArraySetAsSeries(Ind_Buffer2, true); } //----+ INSERTION OF A STATIC INTEGER MEMORY VARIABLE static int IndCounted; //----+ Insertion of variables with a floating point double Resalt0, Resalt1, Resalt2; //----+ Insertion of integer variables and getting calculated bars int limit, MaxBar, bar, counted_bars = IndCounted; //---- checking for possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--; //----+ REMEMBERING THE AMOUNT OF ALL BARS OF THE CHART IndCounted = Bars - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated limit = Bars - counted_bars - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated MaxBar = Bars - 1 - (period0 + period1 + period2); //---- initialization of zero if(limit > MaxBar) { limit = MaxBar; for(bar = Bars - 1; bar >= 0; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ THE FIRST CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt1 calculation // based on the external variable period1 Ind_Buffer1[bar] = Resalt1; } //----+ THE SECOND CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt2 calculation // based on the values of the buffer Ind_Buffer1[] and external variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ THE MAIN CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt0 calculation // based on the values of the buffer Ind_Buffer2[] and external variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+
Transformação adicional do Código Indicador e esquema final de sua estrutura
Claro, nós poderíamos simplesmente transferir o código indicador em partes para um código EA, supondo que precisamos deste indicador em um Expert Advisor para a operação no gráfico atual e apenas uma vez! Se o indicador for usado duas vezes, poderíamos simplesmente mudar, no segundo caso, nomes de todas as variáveis dos indicadores e adicionar o código mais uma vez. Mas neste caso o Expert Advisor ficará mais complicado.
iBars(string symbol, int timeframe);
NULO - para o símbolo de coda; 0 (em séries cronológicas) - para o calendário; Fechar(barra) -
para
iClose(string symbol, int timeframe, bar);
e assim por diante.
Agora vamos analisar as linhas dos indicadores:
//---- checking for possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--;
Como para a substituição oferecida da função IndicatorCounted () na nossa variante da estrutura do indicador, o indicador counted_bars nunca será inferior a zero. Assim, as linhas:
//---- checking for possible errors if(counted_bars < 0) return(-1);no código do Expert Advisor podem ser omitidas. Com as duas linhas seguintes:
//---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--;
é o mesmo. Eles devem ser deletadas, enquanto elas apenas retardam o trabalho do EA com recálculos desnecessários da primeira barra e na operação do EA essa verificação é absolutamente inútil. Depois disso o código final para a transferência em um EA tem a seguinte forma:
//+------------------------------------------------------------------+ //| NewIndicatorPlan2.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ //---- INPUT INDICATOR PARAMETERS extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- indicator buffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //---- DECLARING VARIABLES FOR CHOOSING A CHART string symbol; int timeframe; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- CHOOSING A CHART FRO INDICATOR CALCULATION symbol = Symbol();//INITIALIZATION OF THE VARIABLE symbol; timeframe =240;//INITIALIZATION OF THE VARIABLE timeframe; //---- end of initialization return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { // GETTING THE AMOUNT OF ALL BARS OF THE CHART int IBARS = iBars(symbol, timeframe); //---- Checking whether the bars number is enough for further calculation if(IBARS < period0 + period1 + period2) return(0); // INDICATOR BUFFERS EMULATION if(ArraySize(Ind_Buffer0) < IBARS) { ArraySetAsSeries(Ind_Buffer0, false); ArraySetAsSeries(Ind_Buffer1, false); ArraySetAsSeries(Ind_Buffer2, false); //---- ArrayResize(Ind_Buffer0, IBARS); ArrayResize(Ind_Buffer1, IBARS); ArrayResize(Ind_Buffer2, IBARS); //---- ArraySetAsSeries(Ind_Buffer0, true); ArraySetAsSeries(Ind_Buffer1, true); ArraySetAsSeries(Ind_Buffer2, true); } // INSERTION OF A STATIC INTEGER MEMORY VARIABLE static int IndCounted; //----+ Insertion of variables with a floating point double Resalt0, Resalt1, Resalt2; //----+ Insertion of integer variables and GETTING ALREADY CALCULATED BARS int limit, MaxBar, bar, counted_bars = IndCounted; //----+ REMEMBERING THE AMOUNT OF ALL BARS OF THE CHART IndCounted = IBARS - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated limit = IBARS - counted_bars - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated MaxBar = IBARS - 1 - (period0 + period1 + period2); //---- initialization of zero if(limit > MaxBar) { limit = MaxBar; for(bar = IBARS - 1; bar >= 0; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ THE FIRST CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt1 calculation based on the external // variable period1 Ind_Buffer1[bar] = Resalt1; } //----+ THE SECOND CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt2 calculation // based on the values of the buffer Ind_Buffer1[] and the external variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ THE MAIN CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= 0; bar--) { // Here code of the variable Resalt0 calculation // based on the values of the buffer Ind_Buffer2[] and the external variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+Aqui devemos levar em consideração um momento. Existem indicadores, que no novo cálculo múltiplo da barra zero, na primeira barra no início dos ciclos de cálculo lembram os valores de algumas variáveis para retornar o código ao estado inicial (Artigo). Em um Expert Advisor, após deletar as duas últimas linhas, essa recordação deve ocorrer na barra zero, e não na primeira barra. Normalmente, tais indicadores contêm no início dos ciclos de cálculo os fragmentos do código seguinte:
// Saving the variables values if(bar == 1) if(((limit == 1) && (time == Time[2])) || (limit > 1)) { time = Time[2]; // These variables are not interesting for us PRICE = price; TREND = trend; RESALT = Resalt; } //+------------------------------------------------------------------+
time = Time[1];
para
time = iTime(symbol, timeframe, 1);
Como resultado, temos o seguinte fragmento alterado:
// Saving variables values if(bar == 0) if(((limit == 0) && (time == iTime(symbol, timeframe, 1))) || (limit > 0)) { time = iTime(symbol, timeframe, 1); PRICE = price; TREND = trend; RESALT = Resalt; } //+------------------------------------------------------------------+
Um código indicador também pode conter funções de suavização como XXXSeries (), desenvolvida por mim. Para utilizar fragmentos com tais funções em um código EA, essas funções devem ser substituídas por seus análogos EA.