Preparação de indicadores com vários símbolos/períodos
Conteúdo
- Introdução
- Princípios básicos
- Classe base do indicador MSTF
- Classes de indicadores por tipo
- Classe coleção de indicadores
- Testes
- Considerações finais
Introdução
Hoje começaremos o tema de criar indicadores multissímbolo e multiperíodo, para dar continuação ao tema da criação de templates de indicadores técnicos em EAs e indicadores, iniciado no artigo sobre a criação de um painel de informações, e que se desenvolve ao longo de mais três artigos sobre osciladores, indicadores de volume e Bill Williams, assim como indicadores de tendência. Esses indicadores rodam no gráfico atual, mas são calculados com base nos dados de outros símbolos e/ou diferentes timeframes. Criaremos uma só classe base para o multi-indicador e um conjunto de classes por tipos para todos os indicadores padrão. Quanto ao indicador personalizado, também elaboraremos uma classe, o que nos dará a possibilidade de "transformar" qualquer indicador em multissímbolo e multiperíodo. Já quanto às classes de indicadores, criaremos uma só classe coleção geral, na qual colocaremos os indicadores gerados no programa, o que facilitará acessar qualquer um dos indicadores criados através dos métodos da coleção para recuperar seus dados. Em suma, o objetivo será tornar fácil tanto a criação de multi-indicadores como o trabalho com seus dados.
Princípios básicos
Para entender corretamente a lógica de trabalho com indicadores, tentaremos desvendar um pouco como tudo isso é estruturado. Bem, um indicador tem duas partes: a de cálculo e a de desenho. Cada uma dessas partes não sabe nada sobre a outra. Agora, ao criar um indicador, o subsistema do terminal verifica a presença do indicador no gráfico, conferindo o mesmo nome e parâmetros. Lembre, quando o indicador em questão já está anexado ao gráfico, ou criado para ele programaticamente, é usado o handle do indicador existente, em vez de criar um novo. Aqui, para a plotagem, a parte de desenho do indicador recebe dados da parte de cálculo mediante seu handle. Pode acontecer que várias partes de desenho acessarem uma só parte de cálculo.
No buffer da parte de cálculo, os dados do indicador calculado são armazenados em um array com os dados organizados do presente para o passado. Os dados no índice 0 do array-buffer correspondem aos dados atuais do gráfico:
Cada célula do array armazena os dados de uma barra, dados esses que correspondem à barra da série temporal do símbolo/período com o qual o indicador foi calculado. Desse modo, para obter dados do buffer da parte de cálculo do indicador e exibi-los no gráfico de outro símbolo/timeframe, é necessário calcular o número da barra no gráfico, correspondente ao tempo da barra no array-buffer da parte de cálculo. Os dados obtidos são registrados no buffer da parte de desenho do indicador de tal forma que todas as barras do gráfico atual, que coincidem com o tempo de abertura da barra no buffer da parte de cálculo, sejam inseridas nas células correspondentes do buffer de desenho.
Assi, por exemplo, uma barra no período gráfico de cinco minutos corresponde a cinco barras do gráfico de um minuto. Todas essas cinco barras do gráfico de um minuto devem ser preenchidas com o valor da barra do período gráfico de cinco minutos correspondente. Um algoritmo parecido é usado ao plotar dados de períodos menores no gráfico de um período maior. Neste caso, todas as barras das células do buffer da parte de cálculo, correspondentes ao tempo da barra do timeframe maior, são plotadas em uma só barra do buffer de desenho.
Aqui, naturalmente, haverá uma certa concessão nas leituras, pois no final apenas os dados da última barra do timeframe menor, que ocorrem no mesmo tempo da respectiva barra do timeframe maior, serão desenhados nesta barra. Tudo depende da recuperação de dados a partir do buffer da parte de cálculo do timeframe menor, em outras palavras, são os dados obtidos por último que serão desenhados na barra do gráfico do timeframe maior.
A função CopyBuffer() se destina a recuperar dados a partir do buffer do indicador calculado:
Obtém no array buffer os dados do buffer especificado do indicador especificado, na quantidade especificada.
A contagem dos elementos dos dados copiados (buffer de indicador com índice buffer_num) a partir da posição inicial é feita do presente para o passado, ou seja, a posição inicial igual a 0 representa a barra atual (valor do indicador para a barra atual).
Ao copiar um número desconhecido de dados como um array receptor buffer[], é recomendável usar um array dinâmico, pois a função CopyBuffer() tenta alocar o tamanho do array receptor para se adequar ao tamanho dos dados copiados. Se o array receptor buffer[] atuar como um buffer de indicador (array, previamente designado para armazenar valores do indicador pela função SetIndexBuffer()), então é permitida a cópia parcial.
Se for necessário realizar a cópia parcial de valores do indicador em outro array (não um buffer de indicador), então, é necessário usar um array intermediário, no qual é copiado o número necessário de dados. E, a partir desse array intermediário, deve-se realizar a cópia elemento por elemento do número necessário de valores nos locais apropriados do array receptor.
Se for necessário copiar um número conhecido de dados, é melhor fazer isso em um buffer estático alocado, para evitar o realocamento excessivo de memória.
Não importa qual propriedade o array receptor tenha, seja ela as_series=true ou as_series=false, os dados serão copiados de tal forma que o elemento mais antigo estará no início da memória física alocada para o array. Existem 3 variantes da função.
Acesso pela posição inicial e quantidade de elementos necessários
int CopyBuffer( int indicator_handle, // handle индикатора int buffer_num, // номер буфера индикатора int start_pos, // откуда начнем int count, // сколько копируем double buffer[] // массив, куда будут скопированы данные );
Acesso pela data inicial e quantidade de elementos necessários
int CopyBuffer( int indicator_handle, // handle индикатора int buffer_num, // номер буфера индикатора datetime start_time, // с какой даты int count, // сколько копируем double buffer[] // массив, куда будут скопированы данные );
Acesso pelas datas inicial e final do intervalo de tempo necessário
int CopyBuffer( int indicator_handle, // handle индикатора int buffer_num, // номер буфера индикатора datetime start_time, // с какой даты datetime stop_time, // по какую дату double buffer[] // массив, куда будут скопированы данные );
Parâmetros
indicator_handle
[in] Handle do indicador, obtido pela função indicadora correspondente.
buffer_num
[in] Número do buffer indicador.
start_pos
[in] Número do primeiro elemento a ser copiado.
count
[in] Quantidade de elementos a serem copiados.
start_time
[in] Hora da barra, correspondente ao primeiro elemento.
stop_time
[in] Hora da barra, correspondente ao último elemento.
buffer[]
[out] Array do tipo double.
Valor de retorno
Quantidade de elementos do array copiados ou -1 em caso de erro.
Nota
Ao solicitar dados do indicador, se as séries temporais solicitadas ainda não estiverem construídas ou precisarem ser carregadas do servidor, a função imediatamente retornará -1, mas, ao mesmo tempo, o processo de carregamento/construção será iniciado.
Ao solicitar dados de um EA ou script, será iniciado o carregamento do servidor, caso esses dados não estejam disponíveis localmente no terminal, ou começará a construção da série temporal necessária, se os dados puderem ser construídos a partir do histórico local, mas ainda não estiverem prontos. A função retornará a quantidade de dados que estiverem prontos no momento da expiração do tempo de espera.
Usaremos a primeira variante da função, isto é, o acesso pela posição inicial (índice do laço) e quantidade de elementos necessários.
A estrutura dos objetos será a seguinte:
- Classe base para indicadores multissímbolo/multiperíodo que contém o funcional principal, comum a todos os indicadores;
- Classes derivadas do objeto base que descrevem cada indicador por seu tipo;
- Classe de coleção de indicadores que permite criar quaisquer indicadores e adicioná-los à coleção. A classe fornecerá ao usuário todo o conjunto de ferramentas para criar indicadores e recuperar dados deles.
Ao trabalhar com dados não pertencentes ao gráfico atual, para evitar o "desalocamento" da série temporal, é necessário acessar essa série temporal pelo menos uma vez a cada dois minutos. Nesse caso, ocorrerá a "retenção" da série temporal, o que acelerará o acesso a ela (não será necessário esperar pela sincronização dos dados a cada vez). No construtor da classe, faremos o primeiro acesso à série temporal na qual o indicador é construído, o que permitirá iniciar seu carregamento (se não houver acesso a ela localmente). E, em seguida, a cada 90 segundos (um minuto e meio) no timer da classe base, acessaremos a série temporal para mantê-la.
Calculo eficiente do indicador
Para a exibição do indicador, é necessário um cálculo eficiente de modo que, no primeiro lançamento, o indicador possa ser calculado com base em todos os dados históricos, enquanto nos lançamentos subsequentes apenas uma ou duas barras sejam suficientes.
No manipulador OnCalculate() existem variáveis constantes predefinidas que armazenam o tamanho dos dados de entrada (série temporal ou array) e o número de dados calculados na chamada anterior do OnCalculate():
Cálculo baseado em array de dados
int OnCalculate( const int rates_total, // размер массива price[] const int prev_calculated, // количество обработанных баров на предыдущем вызове const int begin, // номер индекса в массиве price[], с которого начинаются значимые данные const double& price[] // массив значений для расчета );
Cálculos baseados nas séries temporais do timeframe atual
int OnCalculate( const int rates_total, // размер входных таймсерий const int prev_calculated, // количество обработанных баров на предыдущем вызове const datetime& time{}, // массив Time const double& open[], // массив Open const double& high[], // массив High const double& low[], // массив Low const double& close[], // массив Close const long& tick_volume[], // массив Tick Volume const long& volume[], // массив Real Volume const int& spread[] // массив Spread );
A presença desses dados permite fazer um cálculo rápido e eficiente do indicador. Por exemplo, um desses cálculos poderia ser a determinação do valor de limit:
//--- Количество баров для расчёта int limit=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; //--- Если в индикаторе есть какие-либо буферы, то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов }
Na primeira execução do indicador, temos o tamanho da série temporal (rates_total) e a quantidade de dados calculados na chamada anterior (prev_calculated). O valor das barras calculadas anteriormente na primeira execução é zero, portanto o indicador ainda não foi calculado. Assim, o valor de limit será maior que 1 (será igual ao número de barras disponíveis menos zero). Nesse caso, definimos o valor de limit como igual a rates_total-1, o que representa todo o histórico disponível para cálculo. Assim sendo, é necessário primeiramente apagar todos os dados previamente plotados nos buffers do indicador, por exemplo.
ArrayInitialize(Buffer,EMPTY_VALUE);
Depois disso, no laço principal, será calculado todo o histórico, porque o laço é construído a partir do valor de limit até zero:
for(int i=limit;i>=0;i--) { // Расчёт индикатора на каждом баре цикла (i) }
Deve-se notar que, com esse método de cálculo, todos os arrays utilizados nos cálculos e o próprio buffer do indicador devem ter a flag de indexação como para a série temporal:
ArraySetAsSeries(array,true);
Se o limit calculado for igual a 1, significa a abertura de uma nova barra no gráfico: o indicador calculará a primeira e a barra zero da série temporal, com o laço indo de 1 a 0, incluindo ambos.
Quando o limit calculado é igual a 0, isso indica que estamos trabalhando no tick atual: o indicador calculará apenas a barra zero da série temporal, com o laço indo de 0 a 0, incluindo este último.
Se um cálculo é necessário a partir da barra zero indo para trás nos dados históricos (para evitar inverter os arrays de séries temporais e buffers), então a estrutura do laço será invertida:
int i=fmax(0, prev_calculated-1); for(;i<rates_total;i++) { // Расчёт индикатора на каждом баре цикла (i) }
Assim, já é fácil fazer um cálculo eficiente no gráfico atual. Mas e se forem necessários os dados de um gráfico diferente? Quando copiar todo o array de dados da parte de cálculo e quando copiar apenas uma ou duas últimas barras?
Aqui é onde as funções Bars() e BarsCalculated() podem ajudar. Estas são análogas às variáveis constantes predefinidas do indicador rates_total e prev_calculated, mas retornam o número de barras para o símbolo/período especificado e a quantidade de dados calculados pelo indicador. Como o indicador é construído sobre o símbolo/período especificado, então a quantidade de dados calculados se refere a esse símbolo/período. O indicador é obtido pelo seu handle.
Com base no fato de que podemos calcular para qualquer símbolo/período quantas barras precisam ser copiadas (para evitar copiar o array inteiro a cada tick), faremos exatamente a mesma estrutura na classe base do indicador, assim como para o símbolo/período atual.
limit=rates_total-prev_calculated;
Apenas as variáveis limit, rates_total e prev_calculated serão membros privados da classe, e seus valores serão obtidos das funções Bars() e BarsCalculated(). Em cada tick, será calculado o limit, e, se for zero, apenas os dados das duas últimas barras (a barra atual e o anterior) serão copiados. Se o limit for igual a 1, isso indica a abertura de uma nova barra no símbolo/período do indicador, e é necessário aumentar o array em 1, e então copiar os dados a partir do buffer do indicador — também apenas dois. Quando o limit é maior que um, o array inteiro do buffer de cálculo do indicador é copiado para o array-buffer receptor da classe, pois se assume que isso representa ou o primeiro lançamento ou uma mudança no histórico.
Essa lógica se aplica ao pregão, quando os ticks estão aparecendo.
Um dia de folga, entretanto, requer uma abordagem diferente. Este é um caso isolado. Aqui não há ticks, a função Bars() muitas vezes retorna zero, e o número de barras calculadas pelo indicador não é registrado, sendo também zero. O indicador, se houver algum erro nos dados de origem para o cálculo, deve retornar zero, para, assim, esperar pela atualização dos dados até o próximo tick e recalcular. Mas no dia de folga, não há tick além do primeiro lançamento.
No primeiro lançamento, o indicador primeiro limpará os arrays de buffer, depois será calculado. Mas o cálculo pode falhar por insuficiência de dados para o cálculo, ou simplesmente porque prev_calculated retorna um valor zero. E o indicador sai de OnCalculate(), retornando zero novamente. Por isso, se você atualizar o gráfico com o botão direito do mouse, o que é essencialmente uma emulação de tick, então o indicador verá novamente que foi calculado com erro e inicializará os buffers novamente, pensando que é o primeiro lançamento. E assim por diante, apagando os dados recém-plotados no gráfico dos buffers de desenho... Mas há uma saída.
Se no primeiro lançamento o cálculo do indicador não funcionou imediatamente, você pode esperar o próximo tick por 20 a 30 segundos e emular um tick programaticamente. Isso pode ser feito usando a função ChartSetSymbolPeriod(). Se chamada, especificando o símbolo/período atual do gráfico, isso causará o recálculo dos indicadores anexados ao gráfico. Dessa forma, é possível calcular o indicador no gráfico mesmo na ausência de ticks.
Basta esperar 20 segundos para carregar o histórico necessário do símbolo/período do indicador e calculá-lo. Mas precisamos de uma flag de que o indicador já foi calculado (já que prev_calculated retorna zero), e se não marcarmos a flag de sucesso do cálculo, o indicador apagará seus buffers novamente. Por isso, para entender que o indicador foi calculado com sucesso, basta ver que o número de barras calculadas para o objeto indicador é igual ao número de barras para seu símbolo/período. Se Bars() retorna zero, podemos descobrir de outra maneira o número disponível de barras do símbolo/período necessário (não esquecemos que estamos falando de indicadores multissímbolo e multiperíodo, que são calculados em outro programa — um EA ou indicador, lançado no gráfico atual). Na função SeriesInfoInteger() podemos obter a data de início do histórico disponível por símbolo/período e a data de término:
SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE); // Самая первая дата по символу-периоду на данный момент SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE); // Время открытия последнего бара по символу-периоду
A partir dessas duas datas e do período do gráfico da série temporal, podemos facilmente calcular o número de barras disponíveis, mesmo se Bars(symbol,period) ou SeriesInfoInteger(symbol,period,SERIES_BARS_COUNT) retornarem zero.
Após todos os dados serem recebidos e o indicador ser corretamente calculado, a flag de sucesso do cálculo é definida. Essa flag é verificada quando limit > 1 (nesse caso, é necessário inicializar os arrays de buffer do indicador com um "valor vazio"). Na primeira execução, a flag de sucesso é resetada — os arrays são inicializados e é feita uma tentativa de calcular o indicador no símbolo/período do gráfico atual. Se o cálculo falhar, espera-se 20 segundos no timer do próximo tick.
Se for um dia de folga, não haverá tick, e após 20 segundos é enviada uma ordem para ajustar o gráfico ao símbolo e período atuais — emulação de tick. Na reinicialização do indicador no timer (após 20 segundos), os dados já devem ter sido carregados e o indicador deve ser calculado sem erros. Neste ponto, é definida a flag de sucesso do cálculo. Na próxima entrada no timer, esta flag é verificada e, se estiver definida, o tick não será emulado. Existem um total de três tentativas para desenhar os buffers do indicador. Após as três tentativas, a flag de sucesso é forçosamente definida, e as tentativas de emulação de tick são encerradas. Se o indicador não conseguir ser calculado após três ticks emulados, então só resta manualmente: ou (botão direito do mouse --> Atualizar), ou alternar o timeframe do gráfico para frente e para trás, para reiniciar todo o processo de emulação de ticks com o carregamento de dados.
Essa é a teoria. Vamos passar para a prática, a criação de classes de multi-indicadores.
Classe base do indicador MSTF
Na pasta do terminal \MQL5\Include\IndMSTF, vamos criar um novo arquivo IndMSTF.mqh da classe CIndMSTF. A classe deve ser herdada do objeto base da Biblioteca Padrão CObject. O arquivo do objeto base deve ser incluído no arquivo da nova classe criada:
//+------------------------------------------------------------------+ //| IndMSTF.mqh | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Object.mqh> //+------------------------------------------------------------------+ //| Базовый класс мультисимвольного мультипериодного индикатора | //+------------------------------------------------------------------+ class CIndMSTF : public CObject { private: protected: public: //--- Конструктор/деструктор CIndMSTF(); ~CIndMSTF(); };
Antes de adicionarmos métodos nas diferentes seções da classe, vamos adicionar algumas macros, enumerações e a estrutura do buffer do indicador.
Precisaremos de um timer de segundos, para monitorar dois períodos de tempo:
- 90 segundos, após os quais acessaremos séries temporais de indicadores calculados não fora do símbolo/período atual,
- 20 segundos, após os quais emularemos um tick para desenhar o indicador nos dias de folga.
//--- includes #include <Object.mqh> //--- defines #define TIMER_COUNT_1 (90) // Размер таймера 1. Не должен быть более двух минут (120) #define TIMER_COUNT_2 (20) // Размер таймера 2. Слишком малые значения быстро запускают эмуляцию тика, что не желательно при активном рынке
Diferentes indicadores padrão no terminal do cliente pertencem a diferentes categorias. Para podermos ordenar os indicadores criados por categorias ou criar listas de indicadores pertencentes a uma determinada categoria, vamos escrever uma enumeração das diferentes categorias de indicadores:
//--- defines #define TIMER_COUNT_1 (90) // Размер таймера 1. Не должен быть более двух минут (120) #define TIMER_COUNT_2 (20) // Размер таймера 2. Слишком малые значения быстро запускают эмуляцию тика, что не желательно при активном рынке //--- enums enum ENUM_IND_CATEGORY // Категории индикаторов { IND_CATEGORY_NONE, // Не задана IND_CATEGORY_TREND, // Трендовые IND_CATEGORY_OSCILLATOR, // Осцилляторы IND_CATEGORY_VOLUME, // Объемы IND_CATEGORY_WILLIAMS, // Билла Вильямса IND_CATEGORY_CUSTOM, // Пользовательские };
Sobre classificação, pesquisa e filtragem
Cada objeto indicador terá propriedades pelas quais será possível encontrar o indicador necessário. Para entender que os indicadores são semelhantes entre si, é necessário comparar suas propriedades-chave: símbolo, período gráfico e os valores de todos os parâmetros de entrada. Se pelo menos um valor das propriedades comparadas for diferente, os indicadores não são idênticos. Se os indicadores forem iguais, não será criado um novo, mas será retornado um ponteiro para o já criado com os mesmos parâmetros. Isso quanto à coleção de indicadores. Quanto às propriedades, precisamos criar uma enumeração na qual serão escritas as constantes de algumas propriedades que podem ser atribuídas com sucesso ao indicador criado, e depois encontrá-lo com base nelas:
enum ENUM_COMPARE_MODE // Режим сравнения { // По умолчанию режим сравнения имеет нулевое значение, что производит сравнение по всем свойствам COMPARE_MODE_HANDLE=1, // Сравнение по хэндлу COMPARE_MODE_SYMBOL, // Сравнение по символу COMPARE_MODE_TIMEFRAME, // Сравнение по периоду графика COMPARE_MODE_ID, // Сравнение по идентификатору COMPARE_MODE_DESCRIPTION, // Сравнение по пользовательскому описанию COMPARE_MODE_CATEGORY, // Сравнение по категории };
Cada indicador criado com sucesso possui um handle, e podemos acessá-lo através desse handle. Esse é um número único atribuído à parte de cálculo do indicador. Os valores dos handles dos indicadores criados começam em 10 e aumentam em 1 para cada indicador subsequente.
As demais propriedades não são únicas e podem ser comuns a diferentes indicadores. A busca por elas é apenas por conveniência. Por exemplo, você pode definir uma descrição única para o indicador e, em seguida, acessá-lo por essa descrição.
Sobre as descrições dos estados das linhas do indicador, já falamos em artigos anteriores sobre indicadores. Aqui também usaremos essa enumeração:
enum ENUM_LINE_STATE // Состояние линии индикатора { LINE_STATE_NONE, // Неопределённое состояние LINE_STATE_UP, // Направление вверх LINE_STATE_DOWN, // Направление вниз LINE_STATE_TURN_UP, // Разворот вверх LINE_STATE_TURN_DOWN, // Разворот вниз LINE_STATE_STOP_UP, // Остановка направления вверх LINE_STATE_STOP_DOWN, // Остановка направления вниз LINE_STATE_ABOVE, // Над значением LINE_STATE_BELOW, // Под значением LINE_STATE_CROSS_UP, // Пересечение значения вверх LINE_STATE_CROSS_DOWN, // Пересечение значения вниз LINE_STATE_TOUCH_BELOW, // Касание значения снизу LINE_STATE_TOUCH_ABOVE, // Касание значения сверху LINE_STATE_EQUALS, // Равно значению };
Você pode ler mais sobre a enumeração no artigo sobre indicadores osciladores na seção de parâmetros do indicador ATR.
Cada indicador sinalizará o resultado de seu cálculo por meio de um código de erro:
enum ENUM_ERR_TYPE // Тип ошибки при расчётах индикаторов { ERR_TYPE_NO_ERROR, // Нет ошибки ERR_TYPE_NO_CYNC, // Данные не синхронизированы ERR_TYPE_NO_DATA, // Данные не загружены ERR_TYPE_NO_CALC, // Расчёт не завершён };
Por esse código, será possível determinar externamente a ação necessária para tratar o erro.
Buffers do indicador
Aqui precisamos definir a quais buffers cada um pertence.
- Buffer da parte de cálculo. Ao criar um indicador, ele é criado na memória. Essa é a parte de cálculo do indicador. Ela possui seus próprios buffers, que são gerenciados pela sub-sistema do terminal. Pode-se acessar a parte de cálculo por meio de um handle, que é retornado após a criação bem-sucedida do indicador. No buffer de um indicador criado e calculado com sucesso, sempre há dados correspondentes à série temporal na qual o indicador foi calculado. Os dados neste buffer são organizados de forma que o índice zero corresponda à barra atual da série temporal na qual o indicador foi calculado.
A função CopyBuffer() é usada para copiar dados a partir do buffer da parte de cálculo do indicador. - Buffer do objeto indicador. Cada um dos objetos das classes de multi-indicadores criados terá seus próprios arrays-buffers de acordo com o número de buffers do indicador em questão. Esses arrays receberão dados a partir do buffer da parte de cálculo. Os buffers do objeto indicador serão gerenciados dentro do objeto da classe - inicializados, aumentados de acordo com o tamanho da série temporal na qual o indicador foi criado, e atualizados a cada novo tick. Ao copiar dados para o array do objeto indicador a partir do buffer da parte de cálculo usando CopyBuffer(), os dados serão organizados de forma que a barra atual esteja localizada no final do array (ArraySize()-1).
- Buffer da parte de desenho do indicador. Cada objeto indicador pode ser criado tanto em um EA quanto em um indicador personalizado. Ao criar multi-indicadores em EAs, para calcular os indicadores é necessário chamar o método que calcula o indicador, e para obter os dados calculados, acessar o índice de buffer necessário do objeto indicador. No entanto, em um indicador personalizado, também é necessário desenhar no gráfico os dados dos multi-indicadores criados dentro dele. É aqui que surge outro buffer: o de desenho. Este é o buffer designado para os dados a serem plotados em um indicador personalizado. Os dados armazenados nos buffers dos objetos indicadores serão exibidos nele. Para desenhar linhas no gráfico, será suficiente, a partir do indicador personalizado, chamar o método da classe coleção de indicadores que calcula os indicadores e, então, após um cálculo bem-sucedido, o método que colocará os dados do buffer do objeto indicador no buffer de desenho do indicador personalizado.
No objeto indicador, um buffer será representado por uma estrutura que contém tanto o array dinâmico quanto elementos para gerenciar esse array:
//--- struct struct SBuffer // Структура индикаторного буфера { double array[]; // Массив-буфер индикатора double init_value; // Инициализирующее значение int shift; // Сдвиг буфера по горизонтали string descript; // Описание буфера //--- (1) Устанавливает, (2) возвращает инициализирующее значение, void SetInitValue(const double value) { init_value=value; } double InitValue(void) { return init_value; } //--- (1) Устанавливает, (2) возвращает сдвиг буфера void SetShift(const int value) { shift=value; } int Shift(void) { return shift; } //--- (1) Изменяет размер массива буфера, (2) возвращает размер массива буфера, //--- (3) инициализирует массив установленным "пустым" значением bool BuffResize(const int new_size) { return(ArrayResize(array,new_size)==new_size);} uint BufferSize(void) { return array.Size(); } int InitBuffer(void) { return ArrayInitialize(array,init_value); } };
Alguns valores configurados de fora, por exemplo, durante a criação do indicador, precisam ser salvos para saber quais eram esses valores posteriormente. A maneira mais simples é gravá-los diretamente na estrutura. É exatamente isso que fazemos aqui — o "valor vazio" do buffer, estabelecido a partir do programa chamador, é salvo na estrutura do buffer na variável init_value. O deslocamento da linha do indicador, que é definido durante a criação da parte de cálculo do indicador, também é facilmente salvo aqui, para que possa ser conhecido dentro do objeto da classe; ele é salvo na variável shift. Aqui também é salvo a descrição do buffer, que é definida automaticamente durante a criação da parte de cálculo do indicador, de modo a corresponder ao nome do buffer de um indicador padrão semelhante. Posteriormente, esta descrição pode ser alterada.
As funções que retornam as descrições do estado da linha do indicador e erros no cálculo do indicador são necessárias apenas para exibir no log ou no painel informativo os estados das linhas dos indicadores e os erros em sua inicialização e cálculo:
//+------------------------------------------------------------------+ //| Возвращает описание состояния линии индикатора | //+------------------------------------------------------------------+ string BufferLineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_NONE : return "None"; case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_BELOW : return "Below level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } } //+------------------------------------------------------------------+ //| Возвращает описание ошибки при расчёте индикатора | //+------------------------------------------------------------------+ string TypeErrorcDescription(ENUM_ERR_TYPE error_type) { switch(error_type) { case ERR_TYPE_NO_CYNC : return "Data is not synchronized"; case ERR_TYPE_NO_DATA : return "Data not loaded"; case ERR_TYPE_NO_CALC : return "Calculation not completed"; default : return "No error"; } }
Todos os preparativos estão concluídos. Vamos nos concentrar diretamente na classe do objeto indicador multissímbolo e multiperíodo.
Vamos especificar no corpo da classe todas as variáveis e métodos privados, protegidos e públicos necessários para o funcionamento da classe, e então examinaremos seu propósito e implementação:
//+------------------------------------------------------------------+ //| Базовый класс мультисимвольного мультипериодного индикатора | //+------------------------------------------------------------------+ class CIndMSTF : public CObject { private: ENUM_PROGRAM_TYPE m_program; // Тип программы ENUM_INDICATOR m_type; // Тип индикатора ENUM_TIMEFRAMES m_timeframe; // Период графика string m_symbol; // Символ графика int m_handle; // Хэндл индикатора int m_id; // Идентификатор bool m_success; // Флаг успешного расчёта ENUM_ERR_TYPE m_type_err; // Тип ошибки при расчёте string m_description; // Пользовательское описание индикатора string m_name; // Наименование индикатора string m_parameters; // Описание параметров индикатора protected: ENUM_IND_CATEGORY m_category; // Категория индикатора MqlParam m_param[]; // Массив параметров индикатора string m_title; // Заголовок (наименование индикатора + описание параметров) SBuffer m_buffers[]; // Буферы индикатора int m_digits; // Digits значений индикатора int m_limit; // Количество баров, необходимое для просчёта индикатора на текущем тике int m_rates_total; // Количество доступных баров для просчёта индикатора int m_prev_calculated; // Количество просчитанных баров на прошлом вызове индикатора //--- (1) Устанавливает наименование индикатора, (2) описание параметров void SetName(const string name) { this.m_name=name; } void SetParameters(const string str) { this.m_parameters=str; } //--- Изменяет размер (1) указанного, (2) всех буферов индикатора bool BufferResize(const uint buffer_num,const int new_buff_size); bool BuffersResize(const int new_buff_size); //--- Инициализирует (1) указанный, (2) все буферы индикатора bool BufferInitialize(const uint buffer_num,const int new_buff_size); bool BuffersInitialize(const int new_buff_size); //--- Возвращает флаг равенства структуры одного параметра двух объектов bool IsEqualParameters(const MqlParam &this_param,const MqlParam &compared_param) const { if(this_param.type==compared_param.type && this_param.integer_value==compared_param.integer_value && this_param.string_value==compared_param.string_value && ::NormalizeDouble(this_param.double_value-compared_param.double_value,8)==0 ) return true; return false; } //--- Возвращает результат сравнения одного параметра двух объектов int CompareParams(const MqlParam &this_param,const MqlParam &compared_param) { if(this.IsEqualParameters(this_param,compared_param)) return 0; else if(this_param.type>compared_param.type || this_param.integer_value>compared_param.integer_value || this_param.string_value>compared_param.string_value || this_param.double_value>compared_param.double_value ) return 1; else if(this_param.type<compared_param.type || this_param.integer_value<compared_param.integer_value || this_param.string_value<compared_param.string_value || this_param.double_value<compared_param.double_value ) return -1; else return -1; } public: //--- Создаёт расчётную часть индикатора, возвращает хэндл int CreateIndicator(void); //--- (1) Рассчитывает индикатор, (2) заполняет переданный массив-буфер (с учётом символа-периода графика) данными из буфера расчётной части индикатора данного класса bool Calculate(void); bool DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int limit,double &buffer[]); //--- (1) Устанавливает (2) возвращает инициализирующее значение для указанного буфера void SetBufferInitValue(const uint buffer_num,const double value); double BufferInitValue(const uint buffer_num) const; //--- (1) Устанавливает (2) возвращает значение сдвига для указанного буфера void SetBufferShift(const uint buffer_num,const int value); double BufferShift(const uint buffer_num) const; //--- Возвращает данные указанного буфера (1) как есть, (2) относительно указанного символа/таймфрейма, //--- (3) количество данных в указанном буфере, (4) состояние линии индикатора как есть в буфере расчётной части, //--- (5) состояние линии индикатора с учётом символа/периода графика, описание состояния линии (6) как есть в буфере (7) с учётом символа/периода графика double GetData(const uint buffer_num,const int index) const; double GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const; uint DataTotal(const uint buffer_num) const; ENUM_LINE_STATE BufferLineState(const uint buffer_num,const int index) const; ENUM_LINE_STATE BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const int index) const; ENUM_LINE_STATE BufferLineStateRelative(const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); ENUM_LINE_STATE BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); //--- Возвращает (1) флаг успешности, (2) тип ошибки расчёта bool IsSuccess(void) const { return this.m_success; } ENUM_ERR_TYPE TypeError(void) const { return this.m_type_err; } //--- Устанавливает (1) идентификатор, (2) Digits, (3) пользовательское описание, (4) описание указанного буфера void SetID(const int id) { this.m_id=id; } void SetDigits(const uint digits) { this.m_digits=(int)digits; } void SetDescription(const string descr) { this.m_description=descr; } void SetBufferDescription(const uint buffer_num,const string descr); //--- Устанавливает индексацию массивов буферов расчётной части не как в таймсерии void SetAsSeriesOff(void); //--- Возвращает флаг серийности указанного буфера, (2) синхронизированности исторических данных по символу/периоду bool IsSeries(const uint buffer_num) const; bool IsSynchronized(void) const { return (bool)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_SYNCHRONIZED); } //--- Возвращает (1) таймфрейм, (2) символ, (3) наименование, (4) список параметров, (5) хэндл, (6) Digits //--- количество (7) буферов, (8) баров, (9) идентификатор, (10) описание, (11) заголовок, (12) категорию, //--- (13) количество параметрпов, (14) тип программы, описание (15) категории, (16) буфера индикатора ENUM_TIMEFRAMES Timeframe(void) const { return this.m_timeframe; } string Symbol(void) const { return this.m_symbol; } string Name(void) const { return this.m_name; } string Parameters(void) const { return this.m_parameters; } int Handle(void) const { return this.m_handle; } int Digits(void) const { return this.m_digits; } uint BuffersTotal(void) const { return this.m_buffers.Size(); } uint RatesTotal(void) const { return this.m_rates_total; } int ID(void) const { return this.m_id; } string Description(void) const { return this.m_description; } string Title(void) const { return this.m_title; } ENUM_IND_CATEGORY Category(void) const { return this.m_category; } uint ParamsTotal(void) const { return this.m_param.Size(); } ENUM_PROGRAM_TYPE Program(void) const { return this.m_program; } string CategoryDescription(void); string BufferDescription(const uint buffer_num); //--- Возвращает (1) структуру параметров по индексу из массива, (2) флаг программы-индикатора, (3) описание таймфрейма MqlParam GetMqlParam(const int index) const { return this.m_param[index]; } bool IsIndicator() const { return(this.Program()==PROGRAM_INDICATOR); } string TimeframeDescription(void) const { return ::StringSubstr(::EnumToString(this.m_timeframe),7); } //--- Возвращает количество рассчитанных данных int Calculated(void) const { return ::BarsCalculated(this.m_handle); } //--- Виртуальный метод, возвращающий тип объекта (индикатора) virtual int Type(void) const { return this.m_type; } //--- Виртуальный метод сравнения двух объектов virtual int Compare(const CObject *node,const int mode=0) const { const CIndMSTF *compared=node; switch(mode) { case COMPARE_MODE_ID : return(this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : 0); case COMPARE_MODE_HANDLE : return(this.Handle()>compared.Handle() ? 1 : this.Handle()<compared.Handle() ? -1 : 0); case COMPARE_MODE_CATEGORY : return(this.Category()>compared.Category() ? 1 : this.Category()<compared.Category() ? -1 : 0); case COMPARE_MODE_SYMBOL : return(this.Symbol()>compared.Symbol() ? 1 : this.Symbol()<compared.Symbol() ? -1 : 0); case COMPARE_MODE_TIMEFRAME : return(this.Timeframe()>compared.Timeframe() ? 1 : this.Timeframe()<compared.Timeframe() ? -1 : 0); case COMPARE_MODE_DESCRIPTION : return(this.Description()>compared.Description() ? 1 : this.Description()<compared.Description() ? -1 : 0); //---Равенство всех параметров объектов default : return(this.IsEqualIndicators(compared) ? 0 : -1); } } //--- Возвращает флаг равенства параметров двух объектов-индикаторов bool IsEqualIndicators(const CIndMSTF *compared) const { if(this.Type()!=compared.Type() || this.ParamsTotal()!=compared.ParamsTotal()) return false; bool res=true; int total=(int)this.ParamsTotal(); for(int i=0;i<total;i++) res &=this.IsEqualParameters(this.m_param[i],compared.GetMqlParam(i)); res &=(this.Timeframe()==compared.Timeframe()); res &=(this.Symbol()==compared.Symbol()); return res; } //--- Таймер void OnTimer(void); //--- Конструктор/деструктор CIndMSTF(){} CIndMSTF(const ENUM_INDICATOR type,const uint buffers,const string symbol,const ENUM_TIMEFRAMES timeframe); ~CIndMSTF(); };
O propósito de cada variável e métodos é comentado no código da classe. Vamos estudar a implementação dos métodos.
Construtor da classe:
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CIndMSTF::CIndMSTF(const ENUM_INDICATOR type,const uint buffers,const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Запускаем таймер ::ResetLastError(); if(!::EventSetTimer(1)) ::PrintFormat("%s: EventSetTimer failed. Error %lu",__FUNCTION__,::GetLastError()); //--- Устанавливаем свойствам переданные в конструктор значения, или значения по умолчанию this.m_program=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE); this.m_type=type; this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe); this.m_handle=INVALID_HANDLE; this.m_digits=::Digits(); this.m_success=true; this.m_type_err=ERR_TYPE_NO_ERROR; //--- Устанавливаем массиву структуре буферов размер, равный количеству буферов индикатора ::ResetLastError(); if(::ArrayResize(this.m_buffers,buffers)!=buffers) ::PrintFormat("%s: Buffers ArrayResize failed. Error %lu"__FUNCTION__,::GetLastError()); //--- Устанавливаем "пустое" значение для каждого буфера по умолчанию (потом можно изменить) for(int i=0;i<(int)this.m_buffers.Size();i++) this.SetBufferInitValue(i,EMPTY_VALUE); //--- Устанавливаем начальные значения переменным, участвующим в экономном расчёте индикатора this.m_prev_calculated=0; this.m_limit=0; this.m_rates_total=::Bars(this.m_symbol,this.m_timeframe); //--- Если индикатор рассчитывается не на текущем графике - делаем запрос данных с нужного графика //--- (первое обращение к данным запускает подкачку этих данных) datetime array[]; if(symbol!=::Symbol() || timeframe!=::Period()) ::CopyTime(this.m_symbol,this.m_timeframe,0,this.m_rates_total,array); }
No construtor da classe são passados o tipo do indicador, o número de buffers, o nome do símbolo e o período gráfico. Em seguida, para as variáveis são definidos valores padrão, o tamanho do array de buffers, e é definido um valor inicializador padrão - "valor vazio" como EMPTY_VALUE - para os arrays de buffers. Se o objeto indicador não for calculado no gráfico atual, então, no final do construtor, faremos uma chamada à função que começa a baixar do servidor os dados da série temporal sobre a qual o indicador é calculado.
Destruidor da classe:
//+------------------------------------------------------------------+ //| Деструктор | //+------------------------------------------------------------------+ CIndMSTF::~CIndMSTF() { //--- Удаляем таймер ::EventKillTimer(); //--- Освобождаем хэндл индикатора ::ResetLastError(); if(this.m_handle!=INVALID_HANDLE && !::IndicatorRelease(this.m_handle)) ::PrintFormat("%s: %s, handle %ld IndicatorRelease failed. Error %ld",__FUNCTION__,this.Title(),m_handle,::GetLastError()); //--- Освобождаем память массивов буферов for(int i=0;i<(int)this.BuffersTotal();i++) ::ArrayFree(this.m_buffers[i].array); }
No destruidor da classe, o temporizador é destruído, o handle do indicador é liberado, e a memória dos arrays de buffers é liberada.
Timer:
//+------------------------------------------------------------------+ //| Таймер | //+------------------------------------------------------------------+ void CIndMSTF::OnTimer(void) { //--- Если символ и таймфрейм индикатора такие же, как у текущего графика - уходим if(this.Symbol()==::Symbol() && this.Timeframe()==::Period()) return; //--- Объявляем переменные счётчиков таймера static int count1=0; static int count2=0; //--- Если счётчик таймера 1 достиг заданного значения, if(count1>=TIMER_COUNT_1) { //--- вызываем функцию CopyTime (удержание таймсерии) и сбрасываем счётчик datetime array[1]; ::CopyTime(this.m_symbol,this.m_timeframe,0,1,array); count1=0; } //--- Если счётчик таймера 2 достиг заданного значения if(count2>=TIMER_COUNT_2) { static int count=0; //--- если прошлый расчёт индикатора был неуспешным - эмулируем тик с сообщением в журнал if(!this.m_success) { if(::ChartSetSymbolPeriod(0,::Symbol(),::Period())) { count++; ::PrintFormat("%s::%s: Tick emulation. Attempt %ld of 3 ...",__FUNCTION__,this.Title(),count); if(count>2) { count=0; this.m_success=true; } } } //--- сбрасываем счётчик count2=0; } //--- Увеличиваем счётчики таймеров count1++; count2++; }
No timer da classe, teremos dois contadores: um para manter a série temporal do indicador e o outro para a emulação de ticks durante os finais de semana. Se o indicador é calculado com base nos dados do símbolo/período atual do gráfico, o timer não é utilizado.
O próprio objeto indicador não é um indicador per se. É apenas uma wrapper sobre a parte de cálculo do indicador, permitindo gerenciá-la, recuperar dados dela e transferi-los ao programa. No objeto do multi-indicador, é necessário criar o próprio indicador. É esse o propósito do método para criar a parte de cálculo do indicador, retornando o handle obtido durante a criação:
//+------------------------------------------------------------------+ //| Создаёт индикатор, возвращает хэндл | //+------------------------------------------------------------------+ int CIndMSTF::CreateIndicator(void) { //--- Создаём наименование индикатора для вывода в журнал string name=::StringFormat("%s(%s,%s)",::StringSubstr(::EnumToString(this.m_type),4),this.m_symbol,this.TimeframeDescription()); //--- Создаём расчётную часть индикатора ::ResetLastError(); this.m_handle=::IndicatorCreate(this.m_symbol,this.m_timeframe,this.m_type,this.m_param.Size(),this.m_param); //--- Если расчётная часть не создана - выводим в журнал сообщение о неудачном создании индикатора if(this.m_handle==INVALID_HANDLE) ::PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,name,::GetLastError()); //--- Если индикатор создан - устанавливаем индексацию массивов индикатора не как у таймсерии else this.SetAsSeriesOff(); //--- Возвращаем хэндл созданного индикатора, либо -1 при неудаче return this.m_handle; }
Os buffers do objeto indicador são arrays dinâmicos dentro da estrutura do buffer, discutida anteriormente, que precisam ter seu tamanho alterado para acomodar constantemente o crescente volume de novos dados. Para isso, existem dois métodos: um método para alterar o tamanho do array de um buffer especificado e outro para alterar o tamanho de todos os buffers do objeto indicador simultaneamente.
Método que altera o tamanho do buffer indicador especificado:
//+------------------------------------------------------------------+ //| Изменяет размер указанного буфера индикатора | //+------------------------------------------------------------------+ bool CIndMSTF::BufferResize(const uint buffer_num,const int new_buff_size) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем false if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- Изменяем размер буфера ::ResetLastError(); bool res=this.m_buffers[buffer_num].BuffResize(new_buff_size); //--- При неудаче выводим сообщение в журнал if(!res) ::PrintFormat("%s::%s: Buffer(%lu) resize failed. Error %lu",__FUNCTION__,this.Title(),buffer_num,::GetLastError()); //--- Возвращаем результат изменения размера массива буфера return res; }
No método, é passado o número do buffer cujo array precisa ser modificado segundo um valor, que também é passado ao método. Se o número do buffer for especificado incorretamente, veremos um registro no log e o método retorna false.
Se o tamanho do array não puder ser alterado, uma mensagem aparece no log. Eventualmente, retorna-se o resultado da alteração do tamanho do array do buffer.
Método que altera o tamanho de todos os buffers do indicador:
//+------------------------------------------------------------------+ //| Изменяет размер всех буферов индикатора | //+------------------------------------------------------------------+ bool CIndMSTF::BuffersResize(const int new_buff_size) { //--- В цикле по всем буферам индикатора добавляем к переменной res результат изменения размера каждого очередного буфера bool res=true; int total=(int)this.BuffersTotal(); for(int i=0;i<total;i++) res &=this.m_buffers[i].BuffResize(new_buff_size); //--- Возвращаем результат изменения размеров всех массивов буферов индикатора return res; }
Aqui, em um loop por todos os buffers do objeto indicador, o resultado da alteração do tamanho do array do próximo buffer é adicionado à variável res, cujo valor é eventualmente retornado pelo método.
De maneira similar, são feitos os métodos para a inicialização dos arrays de buffers do objeto indicador.
Método que inicializa o buffer especificado do indicador:
//+------------------------------------------------------------------+ //| Инициализирует указанный буфер индикатора | //+------------------------------------------------------------------+ bool CIndMSTF::BufferInitialize(const uint buffer_num,const int new_buff_size) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем false if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- Изменяем размер массива буфера bool res=this.BufferResize(buffer_num,new_buff_size); //--- При удачном изменении размера инициализируем буфер установленным инициализирующим значением if(res) this.m_buffers[buffer_num].InitBuffer(); //--- Возвращаем результат return res; }
Aqui também verificamos se o número do buffer a ser inicializado foi especificado corretamente. Então, um novo tamanho é definido para o buffer e, se o tamanho for alterado com sucesso, o array é inicializado com um valor estabelecido para esse buffer.
Método que inicializatodos os buffers do indicador:
//+------------------------------------------------------------------+ //| Инициализирует все буферы индикатора | //+------------------------------------------------------------------+ bool CIndMSTF::BuffersInitialize(const int new_buff_size) { //--- В цикле по всем буферам индикатора добавляем к переменной res результат изменения размера каждого очередного буфера //--- При удачном изменении размера инициализируем буфер установленным инициализирующим значением bool res=true; int total=(int)this.BuffersTotal(); for(int i=0;i<total;i++) { res &=this.m_buffers[i].BuffResize(new_buff_size); if(res) this.m_buffers[i].InitBuffer(); } //--- Возвращаем общий результат return res; }
Em um loop por todos os buffers do objeto indicador, o resultado da alteração do tamanho do array do próximo buffer é adicionado à variável res. Se o tamanho for alterado com sucesso, o buffer é inicializado com um valor de inicialização estabelecido para ele. O método retorna o estado final da variável res, que terá o valor false se pelo menos um dos buffers não foi inicializado com sucesso.
Os demais métodos de configuração e retorno de valores dos buffers são idênticos aos examinados anteriormente:
//+------------------------------------------------------------------+ //| Устанавливает инициализирующее значение для указанного буфера | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferInitValue(const uint buffer_num,const double value) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и уходим if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Устанавливаем новое инициализирующее значение для указанного буфера this.m_buffers[buffer_num].SetInitValue(value); } //+------------------------------------------------------------------+ //| Возвращает инициализирующее значение указанного буфера | //+------------------------------------------------------------------+ double CIndMSTF::BufferInitValue(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем инициализирующее значение самого первого, иначе - EMPTY_VALUE return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE); } //--- Возвращаем инициализирующее значение запрошенного буфера return this.m_buffers[buffer_num].InitValue(); } //+------------------------------------------------------------------+ //| Устанавливает значение сдвига для указанного буфера | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferShift(const uint buffer_num,const int value) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и уходим if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Устанавливаем значение сдвига для буфера this.m_buffers[buffer_num].SetShift(value); } //+------------------------------------------------------------------+ //| Возвращает значение сдвига указанного буфера | //+------------------------------------------------------------------+ double CIndMSTF::BufferShift(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем значение сдвига самого первого, иначе - 0 return(this.BuffersTotal()>0 ? this.m_buffers[0].Shift() : 0); } //--- Возвращаем значение сдвига запрошенного буфера return this.m_buffers[buffer_num].Shift(); }
A lógica dos métodos é detalhadamente descrita nos comentários do código.
Método para o cálculo dos dados do indicador: O indicador calculado (sua parte calculada) possui um buffer que contém todos os dados calculados do indicador. É necessário copiar os dados do buffer da parte de cálculo para os arrays-buffers do objeto indicador. Além disso, é necessário realizar um cálculo eficiente, o que envolve copiar o buffer inteiro apenas no primeiro lançamento ou quando houver mudanças nos dados históricos.
Esse cálculo, que foi examinado anteriormente, também deve ser realizado no método de cálculo do objeto indicador. Então, em caso de erros, o método retornará false, e o programa que o chama deverá reagir a isso — saindo do manipulador (OnTick no EA e OnCalculate no indicador) até a chegada do próximo tick. Consideraremos como erros que exigem o retorno do método o início do carregamento de dados históricos, o carregamento incompleto do histórico, o cálculo incompleto do indicador e erros na cópia de dados a partir do buffer da parte de cálculo para o buffer do objeto indicador. O método armazenará o código do erro em uma variável, para que o programa que o chama possa lê-lo e processá-lo corretamente.
Método que preenche os buffers do objeto indicador com dados a partir do buffer da parte de cálculo:
//+------------------------------------------------------------------+ //| Заполняет буферы объекта данными из буфера расчётной части | //+------------------------------------------------------------------+ bool CIndMSTF::Calculate(void) { //--- Устанавливаем флагу успешности значение true, а типу ошибки - её отсутствие this.m_success=true; this.m_type_err=ERR_TYPE_NO_ERROR; //--- Если данные ещё не синхронизированы с торговым сервером, if(!this.IsSynchronized()) { //--- Выводим в журнал сообщение о несинхронизированности, ::PrintFormat("%s::%s: Waiting for data to sync...",__FUNCTION__,this.Title()); //--- устанавливаем тип ошибки, к флагу ошибки добавляем false и возвращаем false this.m_type_err=ERR_TYPE_NO_CYNC; this.m_success &=false; return false; } //--- Если метод Calculated вернул -1, это означает начало закачки данных if(this.Calculated()==WRONG_VALUE) { //--- Выводим в журнал сообщение о начале закачки данных, ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription()); //--- устанавливаем тип ошибки, к флагу ошибки добавляем false и возвращаем false this.m_type_err=ERR_TYPE_NO_DATA; this.m_success &=false; return false; } //--- Если метод Calculated вернул 0, это означает, что индикатор ещё не рассчитан if(this.Calculated()==0) { //--- Выводим в журнал сообщение об ожидании расчёта индикатора, ::PrintFormat("%s::%s: Waiting for a new tick and when the indicator will be calculated...",__FUNCTION__,this.Title()); //--- устанавливаем тип ошибки, к флагу ошибки добавляем false и возвращаем false this.m_type_err=ERR_TYPE_NO_CALC; this.m_success &=false; return false; } //--- Получаем количество баров данных по символу/периоду индикатора int bars=::Bars(this.m_symbol,this.m_timeframe); //--- Если функция Bars вернула нулевое значение, что часто бывает на выходных, рассчитаем доступное количество баров if(bars==0) { //--- Получим дату самого первого доступного бара в истории по символу/периоду datetime firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_FIRSTDATE); //--- Получим дату последнего (текущего) бара в истории по символу/периоду datetime lastdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE); //--- Рассчитаем количество баров между первой и последней датами истории int sec=::PeriodSeconds(this.m_timeframe); ulong date_bars=(((ulong)lastdate-(ulong)firstdate)/(sec>0 ? sec : 1))+1; //--- В переменную bars запишем меньшее значение из рассчитанного количества баров и максимального количества баров, доступных в терминале bars=(int)fmin(date_bars,::TerminalInfoInteger(TERMINAL_MAXBARS)); } //--- Запишем в m_rates_total полученное количество доступных баров if(this.m_rates_total!=bars) this.m_rates_total=bars; //--- Если количество доступных баров получено, и их два и меньше, if(this.m_rates_total>=0 && this.m_rates_total<3) { //--- Выведем в журнал сообщение о слишком маленьком количестве доступных баров ::PrintFormat("%s::%s: Not enough data for calculation: %ld bars. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_rates_total); //--- установим тип ошибки, к флагу ошибки добавим false и вернём false this.m_type_err=ERR_TYPE_NO_DATA; this.m_success &=false; return false; } //--- Рассчитаем количество необходимых баров для расчёта индикатора //--- Либо вся доступная история, либо 1 при открытии нового бара, либо 0 на текущем тике this.m_limit=this.m_rates_total-this.m_prev_calculated; this.m_prev_calculated=this.Calculated(); //--- Объявляем массив размером 2 для получения в него данных из буфера расчётной части индикатора //--- Получать будем всегда по два бара - прошлый и текущий double array[2]; //--- Получаем количество буферов индикатора int total=(int)this.BuffersTotal(); //--- Если рассчитанное значение m_limit больше 1 - значит это либо первый запуск, либо изменения в исторических данных //--- В этом случае необходим полный перерасчёт индикатора if(this.m_limit>1) { //--- В цикле по количеству буферов индикатора for(int i=0;i<total;i++) { //--- изменяем размер массива буфера индикатора и инициализируем его установленным для этого буфера "пустым" значением this.BufferInitialize(i,this.m_rates_total); ::ResetLastError(); //--- Копируем все имеющиеся исторические данные из массива расчётной части индикатора в массив-буфер объекта индикатора int copied=::CopyBuffer(this.m_handle,i,-this.m_buffers[i].Shift(),this.m_rates_total,this.m_buffers[i].array); //--- Если скопированы не все данные if(copied!=this.m_rates_total) { //--- Если CopyBuffer вернула -1, то это означает начало загрузки исторических данных //--- выведем сообщение об этом в журнал if(copied==WRONG_VALUE) ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription()); //--- В любом ином случае - ещё не все данные удалось скопировать //--- выведем сообщение об этом в журнал else ::PrintFormat("%s::%s: Not all data was copied. Data available: %lu, total copied: %ld",__FUNCTION__,this.Title(),this.m_rates_total,copied); //--- Запишем в тип ошибки отсутствие данных this.m_type_err=ERR_TYPE_NO_DATA; //--- Добавим к результату значение false и вернём false для выхода из метода и ожидания следующего тика this.m_success &=false; return false; } } //--- Если вышли из цикла копирования всех буферов индикатора, значит всё успешно - вернём true return true; } //--- Если рассчитанное значение m_limit меньше, либо равно 1 - значит это либо открытие нового бара (m_limit==1), либо текущий тик (m_limit==0) //--- В этом случае необходимо рассчитать два бара - первый и текущий if(this.m_limit<=1) { //--- В цикле по количеству буферов индикатора for(int i=0;i<total;i++) { //--- Если это открытие нового бара и не удалось изменить размер буфера индикатора, if(this.m_limit==1 && !this.BufferResize(i,this.m_rates_total)) { //--- добавим к переменной m_success значение false и вернём false //--- При этом сообщение об ошибке будет выведено в журнал из метода BufferResize this.m_success &=false; return false; } //--- Если не удалось скопировать два бара из буфера расчётной части индикатора, ::ResetLastError(); if(::CopyBuffer(this.m_handle,i,-this.m_buffers[i].Shift(),2,array)!=2) { //--- сообщим об этом в журнал, добавим к переменной m_success значение false и вернём false ::PrintFormat("%s::%s: CopyBuffer(%lu) failed. Error %lu",__FUNCTION__,this.Title(),i,::GetLastError()); this.m_success &=false; return false; } //--- Если дошли сюда, значит копирование успешно - //--- скопируем в буфер объекта-индикатора данные из массива array[], в который были скопированы последние два бара this.m_buffers[i].array[this.DataTotal(i)-1]=array[1]; this.m_buffers[i].array[this.DataTotal(i)-2]=array[0]; } //--- Успешно return true; } //--- Неопределённый вариант limit - возвращаем false return false; }
Toda a lógica do método é detalhadamente descrita nos comentários de cada bloco de código. O método deve ser chamado a partir do programa e, se retornar false, é necessário sair de OnTick ou OnCalculate até o próximo tick.
Se o método for executado sem erros, o buffer do objeto indicador conterá dados prontos para uso. Eles poderão ser acessados por meio de métodos que serão examinados posteriormente.
Nos indicadores, existem métodos especiais para transferir dados a partir do buffer de um objeto indicador, preenchido por este método, para os buffers de desenho do indicador. Estes métodos exibem os dados no buffer de desenho da mesma forma que estão armazenados no buffer do objeto indicador, ou considerando o símbolo/período gráfico. Esses métodos podem ser usados para mostrar os dados calculados no objeto indicador no gráfico atual.
Método que preenche o array passado com dados a partir do buffer da classe:
//+------------------------------------------------------------------+ //| Заполняет переданный массив данными из буфера класса | //+------------------------------------------------------------------+ bool CIndMSTF::DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int limit,double &buffer[]) { //--- Устанавливаем флаг успешности this.m_success=true; //--- Получаем направление индексации переданного в метод массива буфера и, //--- если индексация не как у таймсерии, - устанавливаем индексацию как у таймсерии bool as_series=::ArrayGetAsSeries(buffer); if(!as_series) ::ArraySetAsSeries(buffer,true); //--- Устанавливаем наименование символа и значение таймфрейма, переданные в метод string symbol=(symbol_to=="" || symbol_to==NULL ? ::Symbol() : symbol_to); ENUM_TIMEFRAMES timeframe=(timeframe_to==PERIOD_CURRENT ? ::Period() : timeframe_to); datetime array[2]; //--- Если это первый запуск, или изменения в истории - инициальзируем массив буфера, переданный в метод if(limit>1 && this.m_limit>1) { ::PrintFormat("%s::%s First start, or historical data has been changed. Initialize Buffer(%lu)",__FUNCTION__,this.Title(),buffer_num); ::ArrayInitialize(buffer,this.BufferInitValue(buffer_num)); } //--- Устанавливаем значение счётчика цикла (не более максимального количества баров в терминале на графике) int count=(limit<=1 ? 2 : ::fmin(::TerminalInfoInteger(TERMINAL_MAXBARS),limit)); //--- В цикле от нулевого бара до значения счётчика цикла for(int i=0;i<count;i++) { //--- Если таймфрейм графика совпадает с таймфреймом объекта класса - заполняем буфер напрямую из массива объекта класса if(timeframe==::Period() && this.m_timeframe==::Period()) buffer[i]=this.GetData(buffer_num,i); //--- Иначе, если таймфрейм графика не равен таймфрейму объекта класса else { //--- Узнаём какому времени данного класса принадлежит бар текущего таймфрейма графика, соответствующий индексу цикла ::ResetLastError(); if(::CopyTime(symbol,timeframe,i,2,array)!=2) { //--- Если данных нет в терминале - идём дальше if(::GetLastError()==4401) continue; //--- Ошибка получения существующих данных - возвращаем false this.m_success &=false; return false; } //--- По времени бара текущего таймфрейма графика находим соответствующий индекс бара периода графика объекта класса ::ResetLastError(); int bar=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar==WRONG_VALUE) { this.m_success &=false; continue; } //--- Если это исторические данные (не первый и не нулевой бар) - //--- записываем в буфер индикатора по индексу цикла значение, полученное из буфера расчётной части if(i>1) buffer[i]=this.GetData(buffer_num,bar); //--- Если это текущий (нулевой) или предыдущий (первый) бар else { //--- Получаем время баров 0 и 1 по символу/таймфрейму объекта класса if(::CopyTime(this.m_symbol,this.m_timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Получаем по времени индексы текущего и предыдущего баров на графике, символ/период которого передан в метод int bar0=::iBarShift(symbol,timeframe,array[1]); int bar1=::iBarShift(symbol,timeframe,array[0]); if(bar0==WRONG_VALUE || bar1==WRONG_VALUE) { this.m_success &=false; return false; } //--- Если таймфрейм графика младше таймфрейма объекта класса, if(timeframe<this.m_timeframe) { //--- в цикле от бара с меньшим временем до текущего бара графика заполняем буфер данными из двух последних ячеек массива буфера индикатора for(int j=bar1;j>=0;j--) buffer[j]=this.GetData(buffer_num,(j>bar0 ? 1 : 0)); } //--- Если таймфрейм графика старше таймфрейма объекта класса, else { //--- Получаем время текущего и предыдущего баров по символу/таймфрейму текущего графика if(::CopyTime(symbol,timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Получаем по времени индексы баров в буфере расчётной части индикатора, соответствующие времени текущего и предыдущего баров на графике int bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[1]); int bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Записываем в буфер индикатора по индексам 1 и 0 значения из соответствующих индексов буфера расчётной части buffer[1]=this.GetData(buffer_num,bar1); buffer[0]=this.GetData(buffer_num,bar0); } } } } //--- Устанавливаем изначальную индексацию переданного в метод массива буфера ::ArraySetAsSeries(buffer,as_series); //--- Успешно return true; }
A lógica do método é detalhadamente explicada na listagem. A essência do método é calcular corretamente quais barras do gráfico atual precisam ser preenchidas com dados do array do buffer do indicador calculado em outro timeframe. No método, o último parâmetro passado é o array do buffer de desenho do indicador personalizado, que deve mostrar o indicador calculado em outro símbolo/período.
Método que retorna os dados do buffer especificado como estão:
//+------------------------------------------------------------------+ //| Возвращает данные указанного буфера как есть | //+------------------------------------------------------------------+ double CIndMSTF::GetData(const uint buffer_num,const int index) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем "пустое" значение самого первого, иначе - EMPTY_VALUE return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE); } //--- Если указан не правильный индекс - возвращаем "пустое" значение указанного буфера if(index<0 || index>(int)this.DataTotal(buffer_num)-1) return this.BufferInitValue(buffer_num); //--- Рассчитываем реальный индекс в массиве-буфере и возвращаем значение по этому индексу int n=int(this.DataTotal(buffer_num)-1-index); return this.m_buffers[buffer_num].array[n]; }
O método simplesmente retorna os dados a partir do buffer do objeto indicador pelo índice especificado.
Método que retornaos dados do buffer especificado para o símbolo/timeframe indicado:
//+-------------------------------------------------------------------+ //| Возвращает данные указанного буфера на указанный символ/таймфрейм | //+-------------------------------------------------------------------+ double CIndMSTF::GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const { //--- Если указан текущий символ/период графика if(timeframe_to==::Period() && this.m_timeframe==::Period() && symbol_to==::Symbol() && this.m_symbol==::Symbol()) return this.GetData(buffer_num,index); //--- Узнаём какому времени данного класса принадлежит бар текущего таймфрейма графика, соответствующий индексу цикла datetime array[]; if(::CopyTime(symbol_to,timeframe_to,index,1,array)!=1) return this.BufferInitValue(buffer_num); //--- По времени бара текущего таймфрейма графика находим соответствующий индекс бара периода графика данного класса int bar=iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Если бар не найден - возвращаем "пустое" значение, установленное для буфера if(bar==WRONG_VALUE) return this.BufferInitValue(buffer_num); //--- Возвращаем значение из буфера объекта-индикатора по найденному индексу return this.GetData(buffer_num,bar); }
O método encontra o índice da barra da série temporal na qual o indicador foi calculado, índice esse que corresponde ao símbolo/período passado para o método, e retorna os dados a partir do buffer do objeto indicador.
Método que retorna o estado da linha do indicador como está:
//+------------------------------------------------------------------+ //| Возвращает состояние линии индикатора как есть | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineState(const uint buffer_num,const int index) const { //--- Получаем значения линии индикатора со смещением (0,1,2) относительно переданного индекса const double value0=this.GetData(buffer_num,index); const double value1=this.GetData(buffer_num,index+1); const double value2=this.GetData(buffer_num,index+2); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Разворот линии вверх (value2>value1 && value0>value1) if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_TURN_UP; //--- Направление линии вверх (value2<=value1 && value0>value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_UP; //--- Остановка направления линии вверх (value2<=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_UP; //--- Разворот линии вниз (value2<value1 && value0<value1) if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_TURN_DOWN; //--- Направление линии вниз (value2>=value1 && value0<value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_DOWN; //--- Остановка направления линии вниз (value2>=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_DOWN; //--- Неопределённое состояние return LINE_STATE_NONE; }
O método determina o estado da linha do objeto indicador pelos dados em seu buffer e retorna o valor encontrado.
Método que retorna o estado da linha do indicador considerando o símbolo/período:
//+------------------------------------------------------------------+ //| Возвращает состояние линии индикатора с учётом символа/периода | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const int index) const { //--- Определяем переданные в метод символ/период графика string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from); ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from); //--- Если получаем данные от символа/периода, равные текущему графику - возвращаем состояние из буфера "как есть" if(symbol==::Symbol() && symbol==this.m_symbol && timeframe==::Period() && timeframe==this.m_timeframe) return this.BufferLineState(buffer_num,index); //--- Объявляем переменные для поиска нужных баров на текущем графике datetime array[1]; int bar0=WRONG_VALUE; int bar1=WRONG_VALUE; int bar2=WRONG_VALUE; //--- Получаем время первого бара на графике ::ResetLastError(); if(::CopyTime(symbol,timeframe,index,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем индекс первого бара в буфере объекта-индикатора по времени открытия бара на графике bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar0==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Получаем время второго бара на графике ::ResetLastError(); if(::CopyTime(symbol,timeframe,index+1,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+1,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем индекс второго бара в буфере объекта-индикатора по времени открытия бара на графике bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar1==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Получаем время третьего бара на графике ::ResetLastError(); if(::CopyTime(symbol,timeframe,index+2,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+2,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем индекс третьего бара в буфере объекта-индикатора по времени открытия бара на графике bar2=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar2==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Получаем значения линии индикатора со смещением (0,1,2) относительно переданного индекса const double value0=this.GetData(buffer_num,bar0); const double value1=this.GetData(buffer_num,bar1); const double value2=this.GetData(buffer_num,bar2); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Разворот линии вверх (value2>value1 && value0>value1) if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_TURN_UP; //--- Направление линии вверх (value2<=value1 && value0>value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_UP; //--- Остановка направления линии вверх (value2<=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_UP; //--- Разворот линии вниз (value2<value1 && value0<value1) if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_TURN_DOWN; //--- Направление линии вниз (value2>=value1 && value0<value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_DOWN; //--- Остановка направления линии вниз (value2>=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_DOWN; //--- Неопределённое состояние return LINE_STATE_NONE; }
O método permite obter o estado da linha do objeto indicador em relação ao gráfico atual. Se o objeto indicador for calculado com base em dados de um timeframe superior ao do gráfico atual, então sua linha será "esticada" ao longo das barras do gráfico atual. O método permite obter corretamente o estado da linha do indicador na barra especificada do gráfico atual.
Método que retornao estado da linha em relação a um nível especificado:
//+------------------------------------------------------------------+ //| Возвращает состояние линии относительно указанного уровня | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Получаем значения линии индикатора со смещением (0,1) относительно переданного индекса const double value0=this.GetData(buffer_num,index); const double value1=this.GetData(buffer_num,index+1); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Определяем второй сравниваемый уровень double level=(level1==EMPTY_VALUE ? level0 : level1); //--- Линия находится под уровнем (value1<level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_BELOW; //--- Линия находится над уровнем (value1>level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_ABOVE; //--- Линия пересекла уровень снизу-вверх (value1<=level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_CROSS_UP; //--- Линия пересекла уровень сверху-вниз (value1>=level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_CROSS_DOWN; //--- Линия коснулась уровня снизу (value1<level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия коснулась уровня сверху (value1>level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия равна значению уровня (value1==level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_EQUALS; //--- Неопределённое состояние return LINE_STATE_NONE; }
Método que retornao estado da linha em relação a um nível especificado no símbolo/período indicado do gráfico:
//+------------------------------------------------------------------+ //| Возвращает состояние линии относительно указанного уровня | //| на указанном символе/периоде графика | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Определяем переданные в метод символ/период графика string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from); ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from); //--- Получаем значения линии индикатора со смещением (0,1) относительно переданного индекса const double value0=this.GetDataTo(symbol,timeframe,buffer_num,index); const double value1=this.GetDataTo(symbol,timeframe,buffer_num,index+1); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Определяем второй сравниваемый уровень double level=(level1==EMPTY_VALUE ? level0 : level1); //--- Линия находится под уровнем (value1<level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_BELOW; //--- Линия находится над уровнем (value1>level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_ABOVE; //--- Линия пересекла уровень снизу-вверх (value1<=level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_CROSS_UP; //--- Линия пересекла уровень сверху-вниз (value1>=level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_CROSS_DOWN; //--- Линия коснулась уровня снизу (value1<level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия коснулась уровня сверху (value1>level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия равна значению уровня (value1==level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_EQUALS; //--- Неопределённое состояние return LINE_STATE_NONE; }
Sobre os métodos de obtenção do estado das linhas do indicador, você pode ler mais detalhadamente no artigo sobre a integração de osciladores a Expert Advisors.
Outros métodos da classe:
//+------------------------------------------------------------------+ //| Возвращает описание категории | //+------------------------------------------------------------------+ string CIndMSTF::CategoryDescription(void) { //--- Создаём из перечисления ENUM_IND_CATEGORY наименование категории и возвращаем полученный текст string category=::StringSubstr(::EnumToString(this.m_category),13); if(category.Lower()) category.SetChar(0,ushort(category.GetChar(0)-0x20)); return category; } //+------------------------------------------------------------------+ //| Возвращает описание буфера индикатора | //+------------------------------------------------------------------+ string CIndMSTF::BufferDescription(const uint buffer_num) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем пустую строку if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return ""; } //--- Если у индикатора есть буферы, возвращаем описание указанного буфера, иначе - описание индикатора return(this.BuffersTotal()>0 ? this.m_buffers[buffer_num].descript : this.m_title); } //+------------------------------------------------------------------+ //| Устанавливает описание буфера индикатора | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferDescription(const uint buffer_num,const string descr) { //--- Если индикатор не имеет буферов - уходим if(this.BuffersTotal()==0) return; //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и уходим if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Записываем в указанный буфер переданное в метод описание this.m_buffers[buffer_num].descript=descr; } //+------------------------------------------------------------------+ //| Отключает индексацию массивов буферов как у таймсерии | //+------------------------------------------------------------------+ void CIndMSTF::SetAsSeriesOff(void) { //--- В цикле по всем буферам индикатора отключаем флаг серийности массивов for(int i=0;i<(int)this.BuffersTotal();i++) ::ArraySetAsSeries(this.m_buffers[i].array,false); } //+------------------------------------------------------------------+ //| Возвращает флаг серийности указанного буфера | //+------------------------------------------------------------------+ bool CIndMSTF::IsSeries(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем false if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- Возвращаем флаг серийности массива указанного буфера return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array); } //+------------------------------------------------------------------+ //| Возвращает количество данных указанного буфера | //+------------------------------------------------------------------+ uint CIndMSTF::DataTotal(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем ноль if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return 0; } //--- Возвращаем размер массива указанного буфера return this.m_buffers[buffer_num].array.Size(); }
A classe base do objeto indicador com vários símbolos/períodos está pronta. A classe contém toda a funcionalidade necessária para trabalhar com indicadores construídos em dados de séries temporais que não pertencem ao gráfico atual.
Para criar diferentes tipos de indicadores técnicos, é necessário criar classes derivadas da classe base recém-criada. Nos construtores das classes derivadas, serão indicados os parâmetros e propriedades que são característicos do tipo de indicador sendo criado.
Classes de indicadores por tipo
As classes derivadas da base serão as mais simples e conterão apenas o construtor. No construtor da classe, serão passados o símbolo/período gráfico no qual o indicador é calculado, e os parâmetros de entrada, característicos desse tipo de indicadores. Na linha de inicialização do construtor, os parâmetros serão passados para o construtor da classe pai.
Exemplo de classe que cria um objeto indicador, que não contém parâmetros:
//+------------------------------------------------------------------+ //| Класс индикатора Accelerator Oscillator | //+------------------------------------------------------------------+ class CIndAC : public CIndMSTF { public: //--- Конструктор CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AC,1,symbol,timeframe) { //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("AC"); this.SetDescription("Accelerator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } };
Na linha de inicialização, o tipo de indicador, o número de buffers, o símbolo e o período do gráfico são passados para a classe pai, nos quais o indicador deve ser calculado. No corpo da classe, é criada uma linha com a descrição dos parâmetros do indicador. Neste caso, se o indicador é criado com dados do gráfico atual, então a linha de parâmetros estará vazia. Caso contrário, ela conterá o símbolo e o período do gráfico, por exemplo "(EURUSD,H1)". Em seguida, no corpo do construtor, todos os parâmetros característicos desse tipo de indicador são definidos (aqui é o indicador Accelerator Oscillator).
Cada indicador tem a possibilidade de definir o número de dígitos após a vírgula, exibidos na janela de dados e no gráfico do instrumento. No construtor desta classe, não há definição de Digits, pois este valor, igual a Digits do símbolo no qual o indicador é calculado, é definido no construtor da classe pai. Se for necessário definir um valor diferente de Digits para o indicador, isso ou é feito nos construtores das classes daqueles indicadores onde os valores de Digits diferem dos Digits do símbolo, ou pode ser alterado após a criação do objeto indicador por meio do método SetDigits().
Classe do indicador que possui parâmetros:
//+------------------------------------------------------------------+ //| Класс индикатора Accumulation/Distribution | //+------------------------------------------------------------------+ class CIndAD : public CIndMSTF { public: //--- Конструктор CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // используемый объем ) : CIndMSTF(IND_AD,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("A/D"); this.SetDescription("Accumulation/Distribution"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } };
Aqui existem parâmetros, e eles precisam ser incluídos na estrutura-array de parâmetros de entrada do indicador MqlParam. E aqui mesmo definimos o valor de Digits do indicador, que é estabelecido para o Accumulation/Distribution padrão.
Lista completa de todas as classes derivadas da classe base do indicador com vários símbolos/períodos:
//+------------------------------------------------------------------+ //| Класс индикатора Accelerator Oscillator | //+------------------------------------------------------------------+ class CIndAC : public CIndMSTF { public: //--- Конструктор CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AC,1,symbol,timeframe) { //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("AC"); this.SetDescription("Accelerator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Accumulation/Distribution | //+------------------------------------------------------------------+ class CIndAD : public CIndMSTF { public: //--- Конструктор CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // используемый объем ) : CIndMSTF(IND_AD,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("A/D"); this.SetDescription("Accumulation/Distribution"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Average Directional Movement Index | //+------------------------------------------------------------------+ class CIndADX : public CIndMSTF { public: //--- Конструктор CIndADX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int adx_period // период усреднения ) : CIndMSTF(IND_ADX,3,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("ADX"); this.SetDescription("Average Directional Movement Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=2; //--- записываем описания буферов линий MAIN_LINE, PLUSDI_LINE и MINUSDI_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(PLUSDI_LINE,"+DI"); this.SetBufferDescription(MINUSDI_LINE,"-DI"); } }; //+------------------------------------------------------------------+ //| Класс индикатора Average Directional Movement Index Wilder | //+------------------------------------------------------------------+ class CIndADXW : public CIndMSTF { public: //--- Конструктор CIndADXW(const string symbol,const ENUM_TIMEFRAMES timeframe, const int adx_period // период усреднения ) : CIndMSTF(IND_ADXW,3,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("ADX Wilder"); this.SetDescription("Average Directional Movement Index Wilder"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=2; //--- записываем описания буферов линий MAIN_LINE, PLUSDI_LINE и MINUSDI_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(PLUSDI_LINE,"+DI"); this.SetBufferDescription(MINUSDI_LINE,"-DI"); } }; //+------------------------------------------------------------------+ //| Класс индикатора Alligator | //+------------------------------------------------------------------+ class CIndAlligator : public CIndMSTF { public: //--- Конструктор CIndAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, // период для расчета челюстей const int jaw_shift, // смещение челюстей по горизонтали const int teeth_period, // период для расчета зубов const int teeth_shift, // смещение зубов по горизонтали const int lips_period, // период для расчета губ const int lips_shift, // смещение губ по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_ALLIGATOR,3,symbol,timeframe) { // Номера буферов: 0 - GATORJAW_LINE, 1 - GATORTEETH_LINE, 2 - GATORLIPS_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,8)==8) { ::ZeroMemory(this.m_param); //--- период для расчета челюстей this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period); //--- смещение челюстей по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=jaw_shift; //--- период для расчета зубов this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period); //--- смещение зубов по горизонтали this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=teeth_shift; //--- период для расчета губ this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period); //--- смещение губ по горизонтали this.m_param[5].type=TYPE_INT; this.m_param[5].integer_value=lips_shift; //--- тип сглаживания this.m_param[6].type=TYPE_UINT; this.m_param[6].integer_value=ma_method; //--- тип цены или handle this.m_param[7].type=TYPE_UINT; this.m_param[7].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("Alligator"); this.SetDescription("Alligator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Записываем описания буферов линий GATORJAW_LINE, GATORTEETH_LINE и GATORLIPS_LINE this.SetBufferDescription(GATORJAW_LINE,::StringFormat("Jaws(%s%lu)", (current ? "" : symbol_period+":"),jaw_period)); this.SetBufferDescription(GATORTEETH_LINE,::StringFormat("Teeth(%s%lu)",(current ? "" : symbol_period+":"),teeth_period)); this.SetBufferDescription(GATORLIPS_LINE,::StringFormat("Lips(%s%lu)", (current ? "" : symbol_period+":"),lips_period)); //--- Записываем смещения в буферы GATORJAW_LINE, GATORTEETH_LINE и GATORLIPS_LINE this.SetBufferShift(GATORJAW_LINE,jaw_shift); this.SetBufferShift(GATORTEETH_LINE,teeth_shift); this.SetBufferShift(GATORLIPS_LINE,lips_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Adaptive Moving Average | //+------------------------------------------------------------------+ class CIndAMA : public CIndMSTF { public: //--- Конструктор CIndAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ama_period, // период AMA const int fast_ma_period, // период быстрой скользящей const int slow_ma_period, // период медленной скользящей const int ama_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_AMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- период AMA this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ama_period<1 ? 9 : ama_period); //--- период быстрой скользящей this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(fast_ma_period<1 ? 2 : fast_ma_period); //--- период медленной скользящей this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(slow_ma_period<1 ? 30 : slow_ma_period); //--- смещение индикатора по горизонтали this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=ama_shift; //--- тип цены или handle this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),ama_period,fast_ma_period,slow_ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("AMA"); this.SetDescription("Adaptive Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ama_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Awesome Oscillator | //+------------------------------------------------------------------+ class CIndAO : public CIndMSTF { public: //--- Конструктор CIndAO(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AO,1,symbol,timeframe) { //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("AO"); this.SetDescription("Awesome Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Average True Range | //+------------------------------------------------------------------+ class CIndATR : public CIndMSTF { public: //--- Конструктор CIndATR(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_ATR,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("ATR"); this.SetDescription("Average True Range"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Bears Power | //+------------------------------------------------------------------+ class CIndBears : public CIndMSTF { public: //--- Конструктор CIndBears(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_BEARS,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Bears"); this.SetDescription("Bears Power"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Bulls Power | //+------------------------------------------------------------------+ class CIndBulls : public CIndMSTF { public: //--- Конструктор CIndBulls(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_BULLS,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Bulls"); this.SetDescription("Bulls Power"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Bollinger Bands® | //+------------------------------------------------------------------+ class CIndBands : public CIndMSTF { public: //--- Конструктор CIndBands(const string symbol,const ENUM_TIMEFRAMES timeframe, const int bands_period, // период для расчета средней линии const int bands_shift, // смещение индикатора по горизонтали const double deviation, // кол-во стандартных отклонений const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_BANDS,3,symbol,timeframe) { // Номера буферов: 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период для расчета средней линии this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(bands_period<1 ? 20 : bands_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=bands_shift; //--- кол-во стандартных отклонений this.m_param[2].type=TYPE_DOUBLE; this.m_param[2].double_value=deviation; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),bands_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Bands"); this.SetDescription("Bollinger Bands"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //---Описание буферов линий BASE_LINE, UPPER_BAND и LOWER_BAND this.SetBufferDescription(BASE_LINE,this.m_title+" Middle"); this.SetBufferDescription(UPPER_BAND,this.m_title+" Upper"); this.SetBufferDescription(LOWER_BAND,this.m_title+" Lower"); //--- Записываем смещения в буферы BASE_LINE, UPPER_BAND и LOWER_BAND this.SetBufferShift(BASE_LINE,bands_shift); this.SetBufferShift(UPPER_BAND,bands_shift); this.SetBufferShift(LOWER_BAND,bands_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Commodity Channel Index | //+------------------------------------------------------------------+ class CIndCCI : public CIndMSTF { public: //--- Конструктор CIndCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_CCI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("CCI"); this.SetDescription("Commodity Channel Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Chaikin Oscillator | //+------------------------------------------------------------------+ class CIndCHO : public CIndMSTF { public: //--- Конструктор CIndCHO(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ma_period, // быстрый период const int slow_ma_period, // медленный период const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_VOLUME applied_volume // используемый объем ) : CIndMSTF(IND_CHAIKIN,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- быстрый период this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ma_period<1 ? 3 : fast_ma_period); //--- медленный период this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ma_period<1 ? 10 : slow_ma_period); //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- используемый объем this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),slow_ma_period,fast_ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("CHO"); this.SetDescription("Chaikin Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Double Exponential Moving Average | //+------------------------------------------------------------------+ class CIndDEMA : public CIndMSTF { public: //--- Конструктор CIndDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_DEMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип цены или handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("DEMA"); this.SetDescription("Double Exponential Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора DeMarker | //+------------------------------------------------------------------+ class CIndDeM : public CIndMSTF { public: //--- Конструктор CIndDeM(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_DEMARKER,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("DeM"); this.SetDescription("DeMarker"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=3; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Envelopes | //+------------------------------------------------------------------+ class CIndEnvelopes : public CIndMSTF { public: //--- Конструктор CIndEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период для расчета средней линии const int ma_shift, // смещение индикатора по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price, // тип цены или handle const double deviation // отклонение границ от средней линии ) : CIndMSTF(IND_ENVELOPES,2,symbol,timeframe) { // Номера буферов: 0 - UPPER_LINE, 1 - LOWER_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- период для расчета средней линии this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; //--- отклонение границ от средней линии this.m_param[4].type=TYPE_UINT; this.m_param[4].double_value=deviation; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Envelopes"); this.SetDescription("Envelopes"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Описание буферов линий UPPER_LINE и LOWER_LINE this.SetBufferDescription(UPPER_LINE,this.m_title+" Upper"); this.SetBufferDescription(LOWER_LINE,this.m_title+" Lower"); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Force Index | //+------------------------------------------------------------------+ class CIndForce : public CIndMSTF { public: //--- Конструктор CIndForce(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_FORCE,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); //--- тип сглаживания this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=ma_method; //--- тип объема для расчета this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Force"); this.SetDescription("Force Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Fractals | //+------------------------------------------------------------------+ class CIndFractals : public CIndMSTF { public: //--- Конструктор CIndFractals(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_FRACTALS,2,symbol,timeframe) { // Номера буферов: 0 - UPPER_LINE, 1 - LOWER_LINE //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("Fractals"); this.SetDescription("Fractals"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Описание буферов линий UPPER_LINE и LOWER_LINE this.SetBufferDescription(UPPER_LINE,this.m_title+" Up"); this.SetBufferDescription(LOWER_LINE,this.m_title+" Down"); } }; //+------------------------------------------------------------------+ //| Класс индикатора Fractal Adaptive Moving Average | //+------------------------------------------------------------------+ class CIndFrAMA : public CIndMSTF { public: //--- Конструктор CIndFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_FRAMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип цены или handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("FRAMA"); this.SetDescription("Fractal Adaptive Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Gator Oscillator | //+------------------------------------------------------------------+ class CIndGator : public CIndMSTF { public: //--- Конструктор CIndGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, // период для расчета челюстей const int jaw_shift, // смещение челюстей по горизонтали const int teeth_period, // период для расчета зубов const int teeth_shift, // смещение зубов по горизонтали const int lips_period, // период для расчета губ const int lips_shift, // смещение губ по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_GATOR,4,symbol,timeframe) { // Номера буферов: 0 - UPPER_HISTOGRAM, 1- цветовой буфер верхней гистограммы, 2 - LOWER_HISTOGRAM, 3- цветовой буфер нижней гистограммы //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,8)==8) { ::ZeroMemory(this.m_param); //--- период для расчета челюстей this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period); //--- смещение челюстей по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=jaw_shift; //--- период для расчета зубов this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period); //--- смещение зубов по горизонтали this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=teeth_shift; //--- период для расчета губ this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period); //--- смещение губ по горизонтали this.m_param[5].type=TYPE_INT; this.m_param[5].integer_value=lips_shift; //--- тип сглаживания this.m_param[6].type=TYPE_UINT; this.m_param[6].integer_value=ma_method; //--- тип цены или handle this.m_param[7].type=TYPE_UINT; this.m_param[7].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Gator"); this.SetDescription("Gator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+1; //--- Описание буферов линий UPPER_HISTOGRAM, буфер цвета верхней гистограммы, LOWER_HISTOGRAM и буфер цвета нижней гистограммы this.SetBufferDescription(UPPER_HISTOGRAM,this.m_title+" Up"); this.SetBufferDescription(1,this.m_title+" Colors Up"); this.SetBufferDescription(LOWER_HISTOGRAM,this.m_title+" Down"); this.SetBufferDescription(3,this.m_title+" Colors Down"); //--- Записываем смещения в буферы UPPER_HISTOGRAM, 1, LOWER_HISTOGRAM и 2 this.SetBufferShift(UPPER_HISTOGRAM,teeth_shift); this.SetBufferShift(1,teeth_shift); this.SetBufferShift(LOWER_HISTOGRAM,lips_shift); this.SetBufferShift(3,lips_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Ichimoku Kinko Hyo | //+------------------------------------------------------------------+ class CIndIchimoku : public CIndMSTF { public: //--- Конструктор CIndIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen, // период Tenkan-sen const int kijun_sen, // период Kijun-sen const int senkou_span_b // период Senkou Span B ) : CIndMSTF(IND_ICHIMOKU,5,symbol,timeframe) { // Номера буферов: 0 - TENKANSEN_LINE, 1 - KIJUNSEN_LINE, 2 - SENKOUSPANA_LINE, 3 - SENKOUSPANB_LINE, 4 - CHIKOUSPAN_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период Tenkan-sen this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(tenkan_sen<1 ? 9 : tenkan_sen); //--- период Kijun-sen this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(kijun_sen<1 ? 26 : kijun_sen); //--- период Senkou Span B this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(senkou_span_b<1 ? 52 : senkou_span_b); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),tenkan_sen,kijun_sen,senkou_span_b); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Ichimoku"); this.SetDescription("Ichimoku Kinko Hyo"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Описание буферов линий TENKANSEN_LINE, KIJUNSEN_LINE, SENKOUSPANA_LINE, SENKOUSPANB_LINE и CHIKOUSPAN_LINE this.SetBufferDescription(TENKANSEN_LINE,::StringFormat("Tenkan-sen(%lu)",tenkan_sen)); this.SetBufferDescription(KIJUNSEN_LINE,::StringFormat("Kijun-sen(%lu)",kijun_sen)); this.SetBufferDescription(SENKOUSPANA_LINE,"Senkou Span A"); this.SetBufferDescription(SENKOUSPANB_LINE,::StringFormat("Senkou Span B(%lu)",senkou_span_b)); this.SetBufferDescription(CHIKOUSPAN_LINE,"Chikou Span"); //--- Записываем смещения в буферы SENKOUSPANA_LINE, SENKOUSPANB_LINE и CHIKOUSPAN_LINE //this.SetBufferShift(SENKOUSPANA_LINE,kijun_sen); //this.SetBufferShift(SENKOUSPANB_LINE,kijun_sen); //this.SetBufferShift(CHIKOUSPAN_LINE,kijun_sen-senkou_span_b); } }; //+------------------------------------------------------------------+ //| Класс индикатора Market Facilitation Index | //+------------------------------------------------------------------+ class CIndBWMFI : public CIndMSTF { public: //--- Конструктор CIndBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_BWMFI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- тип объема для расчета this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("BW MFI"); this.SetDescription("Market Facilitation Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Momentum | //+------------------------------------------------------------------+ class CIndMomentum : public CIndMSTF { public: //--- Конструктор CIndMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe, const int mom_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_MOMENTUM,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(mom_period<1 ? 14 : mom_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),mom_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Momentum"); this.SetDescription("Momentum"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Money Flow Index | //+------------------------------------------------------------------+ class CIndMFI : public CIndMSTF { public: //--- Конструктор CIndMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_MFI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- тип объема для расчета this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("MFI"); this.SetDescription("Money Flow Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Moving Average | //+------------------------------------------------------------------+ class CIndMA : public CIndMSTF { public: //--- Конструктор CIndMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_MA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("MA"); this.SetDescription("Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Moving Average of Oscillator | //+------------------------------------------------------------------+ class CIndOsMA : public CIndMSTF { public: //--- Конструктор CIndOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, // период быстрой средней const int slow_ema_period, // период медленной средней const int signal_period, // период усреднения разности const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_OSMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период быстрой средней this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period); //--- период медленной средней this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period); //--- период усреднения разности this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period<2 ? 2 : signal_period); //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("OsMA"); this.SetDescription("Moving Average of Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Moving Averages Convergence/Divergence | //+------------------------------------------------------------------+ class CIndMACD : public CIndMSTF { public: //--- Конструктор CIndMACD(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, // период быстрой средней const int slow_ema_period, // период медленной средней const int signal_period, // период усреднения разности const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_MACD,2,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период быстрой средней this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period); //--- период медленной средней this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period); //--- период усреднения разности this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period); //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("MACD"); this.SetDescription("Moving Averages Convergence/Divergence"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Описание буферов линии MAIN_LINE и SIGNAL_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); } }; //+------------------------------------------------------------------+ //| Класс индикатора On Balance Volume | //+------------------------------------------------------------------+ class CIndOBV : public CIndMSTF { public: //--- Конструктор CIndOBV(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_OBV,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- тип объема для расчета this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("OBV"); this.SetDescription("On Balance Volume"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Parabolic Stop and Reverse system | //+------------------------------------------------------------------+ class CIndSAR : public CIndMSTF { public: //--- Конструктор CIndSAR(const string symbol,const ENUM_TIMEFRAMES timeframe, const double step, // шаг изменения цены - коэффициент ускорения const double maximum // максимальный шаг ) : CIndMSTF(IND_SAR,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- шаг изменения цены - коэффициент ускорения this.m_param[0].type=TYPE_DOUBLE; this.m_param[0].double_value=step; //--- максимальный шаг this.m_param[1].type=TYPE_DOUBLE; this.m_param[1].double_value=maximum; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%.2f,%.2f)",symbol_period,(current ? "" : ":"),step,maximum); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("SAR"); this.SetDescription("Parabolic SAR"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Relative Strength Index | //+------------------------------------------------------------------+ class CIndRSI : public CIndMSTF { public: //--- Конструктор CIndRSI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_RSI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("RSI"); this.SetDescription("Relative Strength Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Relative Vigor Index | //+------------------------------------------------------------------+ class CIndRVI : public CIndMSTF { public: //--- Конструктор CIndRVI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_RVI,2,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("RVI"); this.SetDescription("Relative Vigor Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=3; //--- Описание буферов линии MAIN_LINE и SIGNAL_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); } }; //+------------------------------------------------------------------+ //| Класс индикатора Standard Deviation | //+------------------------------------------------------------------+ class CIndStdDev : public CIndMSTF { public: //--- Конструктор CIndStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_STDDEV,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 20 : ma_period<2 ? 2 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("StdDev"); this.SetDescription("Standard Deviation"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Stochastic Oscillator | //+------------------------------------------------------------------+ class CIndStoch : public CIndMSTF { public: //--- Конструктор CIndStoch(const string symbol,const ENUM_TIMEFRAMES timeframe, const int Kperiod, // K-период (количество баров для расчетов) const int Dperiod, // D-период (период первичного сглаживания) const int slowing, // окончательное сглаживание const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_STO_PRICE price_field // способ расчета стохастика ) : CIndMSTF(IND_STOCHASTIC,2,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- K-период (количество баров для расчетов) this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(Kperiod<1 ? 5 : Kperiod); //--- D-период (период первичного сглаживания) this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(Dperiod<1 ? 3 : Dperiod); //--- окончательное сглаживание this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(slowing<1 ? 3 : slowing); //--- тип сглаживания this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=ma_method; //--- способ расчета стохастика this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=price_field; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),Kperiod,Dperiod,slowing); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Stoch"); this.SetDescription("Stochastic Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Описание буферов линии MAIN_LINE и SIGNAL_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); } }; //+------------------------------------------------------------------+ //| Класс индикатора Triple Exponential Moving Average | //+------------------------------------------------------------------+ class CIndTEMA : public CIndMSTF { public: //--- Конструктор CIndTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_TEMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип цены или handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("TEMA"); this.SetDescription("Triple Exponential Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Triple Exponential Moving Averages Oscillator | //+------------------------------------------------------------------+ class CIndTriX : public CIndMSTF { public: //--- Конструктор CIndTriX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_TRIX,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("TRIX"); this.SetDescription("Triple Exponential Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Larry Williams' Percent Range | //+------------------------------------------------------------------+ class CIndWPR : public CIndMSTF { public: //--- Конструктор CIndWPR(const string symbol,const ENUM_TIMEFRAMES timeframe, const int calc_period // период усреднения ) : CIndMSTF(IND_WPR,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(calc_period<1 ? 14 : calc_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),calc_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("%R"); this.SetDescription("Williams' Percent Range"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Variable Index Dynamic Average | //+------------------------------------------------------------------+ class CIndVIDyA : public CIndMSTF { public: //--- Конструктор CIndVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int cmo_period, // период Chande Momentum const int ema_period, // период фактора сглаживания const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_VIDYA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период Chande Momentum this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(cmo_period<1 ? 9 : cmo_period); //--- период фактора сглаживания this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(ema_period<1 ? 12 : ema_period); //--- смещение индикатора по горизонтали this.m_param[2].type=TYPE_INT; this.m_param[2].integer_value=ma_shift; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),cmo_period,ema_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("VIDYA"); this.SetDescription("Variable Index Dynamic Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Класс индикатора Volumes | //+------------------------------------------------------------------+ class CIndVolumes : public CIndMSTF { public: //--- Конструктор CIndVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // тип объема ) : CIndMSTF(IND_VOLUMES,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- тип объема this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Volumes"); this.SetDescription("Volumes"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс пользовательского индикатора | //+------------------------------------------------------------------+ class CIndCustom : public CIndMSTF { public: //--- Конструктор CIndCustom(const string symbol,const ENUM_TIMEFRAMES timeframe, const string path, // путь к индикатору (например, "Examples\\MACD.ex5") const string name, // имя пользовательского индикатора const uint buffers, // количество буферов индикатора const MqlParam ¶m[] // массив параметров пользовательского индикатора ) : CIndMSTF(IND_CUSTOM,buffers,symbol,timeframe) { //--- Если передан пустой массив параметров - сообщаем об этом в журнал int total=(int)param.Size(); if(total==0) ::PrintFormat("%s Error. Passed an empty array",__FUNCTION__); //--- Если массив не пустой и его размер увеличен на 1 (в первый параметр типа string должно быть записано имя индикатора) ResetLastError(); if(total>0 && ::ArrayResize(this.m_param,total+1)==total+1) { //--- Обнуляем данные в массиве и вписываем имя (путь к файлу и имя .ex5 файла) ::ZeroMemory(this.m_param); //--- имя пользовательского индикатора this.m_param[0].type=TYPE_STRING; this.m_param[0].string_value=path; //--- заполняем массив параметров индикатора for(int i=0;i<total;i++) { this.m_param[i+1].type=param[i].type; this.m_param[i+1].double_value=param[i].double_value; this.m_param[i+1].integer_value=param[i].integer_value; this.m_param[i+1].string_value=param[i].string_value; } //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName(name); this.SetDescription(name); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_CUSTOM; //--- Записываем описание первого буфера линии this.SetBufferDescription(0,this.m_title); } } };
A lista apresentada contém todas as classes para a criação de todos os indicadores técnicos disponíveis no terminal do cliente + uma classe para a criação de um indicador personalizado. Todas as classes são idênticas entre si e os pontos principais são comentados no código das classes.
A criação e o funcionamento de todos os indicadores apresentados acima não foram testados. Foram testados apenas os indicadores baseados em médias móveis, que desenham uma única linha no gráfico principal. Nos próximos artigos, escreveremos templates para a criação de versões com vários símbolos/períodos de todos os tipos de indicadores técnicos.
Essencialmente, tudo já está pronto para a criação de multi-indicadores. Mas iremos um pouco além e criaremos uma ferramenta prática para automatizar a criação e o uso de indicadores com vários símbolos/períodos. Será uma classe-coleção de indicadores, permitindo a criação fácil de indicadores padrão ou personalizados, transformando-os em indicadores com vários símbolos/períodos.
Classe coleção de indicadores
A classe-coleção de indicadores é essencialmente uma lista comum de ponteiros para objetos. Simplesmente adicionaremos a ela métodos para a fácil criação de indicadores e a adição dos recém-criados à coleção. Também será possível obter facilmente um ponteiro para o indicador desejado e recuperar os dados necessários dele. Ao adicionar um novo indicador à coleção, primeiro será verificada a presença de um indicador exatamente igual na coleção. Se ele estiver presente, o novo objeto criado é deletado e retorna-se um ponteiro para o já existente na coleção,para que dois objetos diferentes não se refiram à mesma parte de cálculo.
A estrutura da classe-coleção seguirá a estrutura da classe base do indicador com vários símbolos/períodos. Com a única diferença de que a maioria dos métodos deve primeiro encontrar o indicador desejado pelo seu handle e, em seguida, chamar o método necessário para definir ou obter um valor ou o resultado das ações.
No mesmo arquivo \MQL5\Include\IndMSTF\IndMSTF.mqh, simplesmente continuaremos a escrever uma nova classe. Para que isso funcione, é necessário incluir o arquivo da classe de array dinâmico de ponteiros para instâncias da classe CObject e seus descendentes CArrayObj:
//+------------------------------------------------------------------+ //| Класс-коллекция индикаторов | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> class CMSTFIndicators { private: public: }
Inseriremos no corpo da classe o objeto da lista e métodos para trabalhar com a classe:
//+------------------------------------------------------------------+ //| Класс-коллекция индикаторов | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> class CMSTFIndicators { private: CArrayObj m_list; //--- Создаёт индикатор для переданного объекта bool CreateIndicator(CIndMSTF *ind_obj); //--- Добавляет указанный индикатор в коллекцию int AddNewIndicator(CIndMSTF *ind_obj,const string source); public: //--- Возвращает (1) объект индикатора по хэндлу, (2) количество индикаторов в коллекции CIndMSTF *GetIndicatorObj(const int ind_handle,const string source) const; uint IndicatorsTotal(void) const { return this.m_list.Total(); } //--- Заполняет данными буферы (1) индикатора по хэндлу, (2) всех индикаторов в коллекции bool Calculate(const int ind_handle); bool Calculate(void); //--- Устанавливает (1) указанное, (2) по умолчанию описание линии буфера индикатора void SetPlotLabel(const uint plot_index,const string descript); void SetPlotLabelFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num); //--- Устанавливает смещение указанному рисуемому буферу void SetPlotShift(const uint plot_index,const int shift); //--- (1) Устанавливает (2) возвращает инициализирующее значение указанного буфера указанного по хэндлу индикатора void SetBufferInitValue(const int ind_handle,const uint buffer_num,const double value); double BufferInitValue(const int ind_handle,const uint buffer_num) const; //--- Возвращает данные индикатора по хэндлу из указанного буфера по индексу (1) как есть, (2) на указанный символ/таймфрейм double GetData(const int ind_handle,const uint buffer_num,const uint index); double GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index); //--- (1) Копирует данные указанного буфера расчётной части указанного по хэндлу индикатора в буфер индикатора с учётом символа/периода графика, //--- (2) возвращает количество данных в укакзанном буфере указанного по хэндлу индикатора bool DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const int limit,double &buffer[]); uint DataTotal(const int ind_handle,const uint buffer_num) const; //--- Возвращает (1) описание буфера, (2) состояние данных линии указанного буфера указанного по хэндлу индикатора на указанном баре //--- (3) состояние линии индикатора с учётом символа/периода графика, (4) состояние отношения линии индикатора с указанным уровнем, //--- (5) состояние отношения линии индикатора с указанным уровнем с учётом символа/периода графика, (6) описание категории индикатора string BufferDescription(const int ind_handle,const uint buffer_num); ENUM_LINE_STATE BufferLineState(const int ind_handle,const uint buffer_num,const int index); ENUM_LINE_STATE BufferLineState(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const uint buffer_num,const int index); ENUM_LINE_STATE BufferLineStateRelative(const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); ENUM_LINE_STATE BufferLineStateRelative(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); string CategoryDescription(const int ind_handle); //--- Устанавливает (1) идентификатор, (2) Digits, (3) пользовательское описание, (4) описание буфера void SetID(const int ind_handle,const int id); void SetDigits(const int ind_handle,const int digits); void SetDescription(const int ind_handle,const string descr); void SetBufferDescription(const int ind_handle,const uint buffer_num,const string descr); //--- Возвращает флаг серийности указанного буфера, (2) синхронизированности исторических данных по символу/периоду bool IsSeries(const int ind_handle,const uint buffer_num) const; bool IsSynchronized(const int ind_handle) const; //--- Возвращает (1) таймфрейм, (2) символ, (3) наименование, (4) список параметров, (5) хэндл, (6) Digits //--- количество (7) буферов, (8) баров, (9) идентификатор, (10) описание, (11) заголовок, (12) категорию, //--- (13) количество параметрпов, (14) тип программы, описание (15) категории, (16) буфера индикатора ENUM_TIMEFRAMES Timeframe(const int ind_handle) const; string Symbol(const int ind_handle) const; string Name(const int ind_handle) const; string Parameters(const int ind_handle) const; int Digits(const int ind_handle) const; uint BuffersTotal(const int ind_handle) const; uint RatesTotal(const int ind_handle) const; int ID(const int ind_handle) const; string Description(const int ind_handle) const; string Title(const int ind_handle) const; ENUM_IND_CATEGORY Category(const int ind_handle) const; uint ParamsTotal(const int ind_handle) const; //--- Возвращает (1) структуру параметров по индексу из массива, (2) описание таймфрейма MqlParam GetMqlParam(const int ind_handle,const int index) const; string TimeframeDescription(const int ind_handle) const; //--- Возвращает количество рассчитанных данных int Calculated(const int ind_handle) const; //--- Виртуальный метод, возвращающий тип объекта (индикатора) ENUM_INDICATOR Type(const int ind_handle) const; //--- Методы добавления индикаторов в коллекцию int AddNewAC(const string symbol,const ENUM_TIMEFRAMES timeframe); int AddNewAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14); int AddNewADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14); int AddNewAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe,const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN); int AddNewAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ama_period=9, const int fast_ma_period=2, const int slow_ma_period=30, const int ama_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewAO(const string symbol,const ENUM_TIMEFRAMES timeframe); int AddNewATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14); int AddNewBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13); int AddNewBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13); int AddNewBands(const string symbol,const ENUM_TIMEFRAMES timeframe,const int bands_period=20, const int bands_shift=0, const double deviation=2.0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewCCI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_TYPICAL); int AddNewChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe,const int fast_ma_period=3, const int slow_ma_period=10, const ENUM_MA_METHOD ma_method=MODE_EMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14); int AddNewEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE, const double deviation=0.1); int AddNewForce(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewFractals(const string symbol,const ENUM_TIMEFRAMES timeframe); int AddNewFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewGator(const string symbol,const ENUM_TIMEFRAMES timeframe,const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN); int AddNewIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe,const int tenkan_sen=9, const int kijun_sen=26, const int senkou_span_b=52); int AddNewBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe,const int mom_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=10, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewMACD(const string symbol,const ENUM_TIMEFRAMES timeframe,const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewSAR(const string symbol,const ENUM_TIMEFRAMES timeframe,const double step=0.02, const double maximum=0.2); int AddNewRSI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=10); int AddNewStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=20, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe,const int Kperiod=5, const int Dperiod=3, const int slowing=3, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_STO_PRICE price_field=STO_LOWHIGH); int AddNewTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shif=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewTriX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period=14); int AddNewVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int cmo_period=9, const int ema_period=12, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,const string path, // путь к индикатору (например, "Examples\\MACD.ex5") const string name, // имя пользовательского индикатора (например, "Custom MACD") const uint buffers, // количество буферов const MqlParam ¶m[]);// Массив параметров //--- Таймер void OnTimer(void) { //--- В цикле по всем индикаторам коллекции int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- получаем указатель на очередной объект-индикатор //--- и вызываем его таймер CIndMSTF *obj=this.m_list.At(i); if(obj!=NULL) obj.OnTimer(); } } //--- Конструктор/Деструктор CMSTFIndicators(void){ this.m_list.Clear(); } ~CMSTFIndicators(void){;} };
Implementação de métodos para trabalhar com indicadores na lista:
//+------------------------------------------------------------------+ //| Создаёт расчётную часть индикатора для переданного объекта | //+------------------------------------------------------------------+ bool CMSTFIndicators::CreateIndicator(CIndMSTF *ind_obj) { //--- Если расчётную часть индикатора создать не удалось if(!ind_obj.CreateIndicator()) { //--- ищем индекс объекта-индикатора в списке коллекции //--- и по полученному индексу удаляем объект-индикатор из списка коллекции this.m_list.Sort(); int index=this.m_list.Search(ind_obj); this.m_list.Delete(index); //--- Возвращаем false return false; } //--- Расчётная часть успешно создана - возвращаем true return true; } //+------------------------------------------------------------------+ //| Возвращает объект индикатора по хэндлу расчётной части | //+------------------------------------------------------------------+ CIndMSTF *CMSTFIndicators::GetIndicatorObj(const int ind_handle,const string source) const { //--- Если в метод передан невалидный хэндл - сообщаем об это и возвращаем NULL if(ind_handle==INVALID_HANDLE) { ::PrintFormat("%s: Error handle",source); return NULL; } //--- В цикле по всем объектам-индикаторам в списке коллекции int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- получаем указатель на очередной объект-индикатор CIndMSTF *obj=this.m_list.At(i); if(obj==NULL) continue; //--- Если хэндл индикатора равен переданному в метод - //--- возвращаем указатель на найденный объект-индикатор if(obj.Handle()==ind_handle) return obj; } //--- Ничего не нашли - возвращаем NULL return NULL; } //+------------------------------------------------------------------+ //| Заполняет данными буферы индикатора по хэндлу | //+------------------------------------------------------------------+ bool CMSTFIndicators::Calculate(const int ind_handle) { //--- Получаем по хэндлу указатель на объект-индикатор CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) return false; //--- Возвращаем результат работы метода Calculate полученн6ого по хэндлу объекта-индикатора return obj.Calculate(); } //+------------------------------------------------------------------+ //| Заполняет данными буферы всех индикаторов в коллекции | //+------------------------------------------------------------------+ bool CMSTFIndicators::Calculate(void) { //--- Объявляем переменную для хранения результата bool res=true; //--- В цикле по всем объектам-индикаторам в списке коллекции int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- получаем указатель на очередной объект-индикатор CIndMSTF *obj=this.m_list.At(i); if(obj==NULL) continue; //--- Добавляем к переменной res результат вызова метода Calculate очередного объекта-индикатора res &=obj.Calculate(); //--- Если метод отработал с ошибкой - сообщаем об этом в журнал if(!res) ::PrintFormat("%s::%s: Error in indicator calculation: %s",__FUNCTION__,obj.Title(),TypeErrorcDescription(obj.TypeError())); } //--- Если общий результат false - сообщаем об этом в журнал if(!res) ::PrintFormat("%s: Not all indicators have been calculated successfully. It is necessary to recalculate the buffers of all indicators",__FUNCTION__); //--- Возвращаем результат вызова методов Calculate всех индикаторов в коллекции return res; } //+------------------------------------------------------------------+ //| Возвращает данные индикатора по хэндлу | //| из указанного буфера по индексу как есть | //+------------------------------------------------------------------+ double CMSTFIndicators::GetData(const int ind_handle,const uint buffer_num,const uint index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Возвращаем данные из указанного буфера индикатора по индексу, переданному в метод return obj.GetData(buffer_num,index); } //+------------------------------------------------------------------+ //| Возвращает данные индикатора по хэндлу | //| из указанного буфера по индексу на указанный символ/таймфрейм | //+------------------------------------------------------------------+ double CMSTFIndicators::GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Возвращаем данные из указанного буфера индикатора по индексу, переданному в метод return obj.GetDataTo(symbol_to,timeframe_to,buffer_num,index); } //+------------------------------------------------------------------+ //| Заполняет переданный буфер индикатора данными | //+------------------------------------------------------------------+ bool CMSTFIndicators::DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const int limit,double &buffer[]) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Заполняем переданный в метод массив-буфер из указанного буфера индикатора return obj.DataToBuffer(symbol_to,timeframe_to,buffer_num,limit,buffer); } //+------------------------------------------------------------------+ //| Устанавливает указанное описание для линии буфера | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotLabel(const uint plot_index,const string descript) { ::PlotIndexSetString(plot_index,PLOT_LABEL,descript); } //+------------------------------------------------------------------+ //| Устанавливает описание по умолчанию линии буфера | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotLabelFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем в указанный рисуемый буфер описание указанного буфера индикатора ::PlotIndexSetString(plot_index,PLOT_LABEL,obj.BufferDescription(buffer_num)); } //+------------------------------------------------------------------+ //| Устанавливает смещение указанному рисуемому буферу | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotShift(const uint plot_index,const int shift) { ::PlotIndexSetInteger(plot_index,PLOT_SHIFT,shift); } //+------------------------------------------------------------------+ //| Возвращает описание указанного буфера | //| указанного по хэндлу индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::BufferDescription(const int ind_handle,const uint buffer_num) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если указатель на объект получен - возвращаем из него описание указанного буфера. Иначе - текст ошибки return(obj!=NULL ? obj.BufferDescription(buffer_num) : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Устанавливает инициализирующее значение указанного буфера | //| указанного по хэндлу индикатора | //+------------------------------------------------------------------+ void CMSTFIndicators::SetBufferInitValue(const int ind_handle,const uint buffer_num,const double value) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем для указанного буфера указанное инициализирующее "пустое" значение obj.SetBufferInitValue(buffer_num,value); } //+------------------------------------------------------------------+ //| Возвращает инициализирующее значение указанного буфера | //| указанного по хэндлу индикатора | //+------------------------------------------------------------------+ double CMSTFIndicators::BufferInitValue(const int ind_handle,const uint buffer_num) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем инициализирующее "пустое" значение, установленное для указанного буфера return obj.BufferInitValue(buffer_num); } //+------------------------------------------------------------------+ //| Возвращает состояние данных линии указанного буфера | //| указанного по хэндлу индикатора на указанном баре | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineState(const int ind_handle,const uint buffer_num,const int index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Возвращаем состояние линии указанного буфера на указанном индексе return obj.BufferLineState(buffer_num,index); } //+------------------------------------------------------------------+ //| Возвращает состояние данных линии указанного буфера | //| указанного по хэндлу индикатора на баре символа/таймфрейма | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineState(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const uint buffer_num,const int index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Получаем время бара, переданного в метод datetime array[1]; if(::CopyTime(symbol,timeframe,index,1,array)!=1) { ::PrintFormat("%s::%s: Failed to get the time of the bar with index %ld. Error %lu",__FUNCTION__,obj.Title(),index,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем номер бара в буфере объекта-индикатора, соответствующий найденному времени int bar=::iBarShift(obj.Symbol(),obj.Timeframe(),array[0]); //--- Если бар получен - возвращаем состояние линии на найденном баре, иначе - неопределённое состояние return(bar!=WRONG_VALUE ? obj.BufferLineState(buffer_num,bar) : LINE_STATE_NONE); } //+------------------------------------------------------------------+ //| Возвращает соотношение данных линии указанного буфера | //| указанного по хэндлу индикатора на указанном баре | //| с указанными значениями | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineStateRelative(const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Возвращаем соотношение линии индикатора и уровня в указанном буфере на указанном индексе return obj.BufferLineStateRelative(buffer_num,index,level0,level1); } //+------------------------------------------------------------------+ //| Возвращает соотношение данных линии указанного буфера | //| указанного по хэндлу индикатора на указанном баре | //| с указанными значениями на указанном символе/периоде графика | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineStateRelative(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Возвращаем соотношение линии индикатора и уровня в указанном буфере на указанном индексе return obj.BufferLineStateRelative(symbol,timeframe,buffer_num,index,level0,level1); } //+------------------------------------------------------------------+ //| Возвращает описание категории | //+------------------------------------------------------------------+ string CMSTFIndicators::CategoryDescription(const int ind_handle) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем описание категории. Иначе - текст ошибки return(obj!=NULL ? obj.CategoryDescription() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Устанавливает идентификатор | //+------------------------------------------------------------------+ void CMSTFIndicators::SetID(const int ind_handle,const int id) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем идентификатор для полученного объекта obj.SetID(id); } //+------------------------------------------------------------------+ //| Устанавливает Digits индикатора | //+------------------------------------------------------------------+ void CMSTFIndicators::SetDigits(const int ind_handle,const int digits) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем Digits для полученного объекта obj.SetDigits(digits); } //+------------------------------------------------------------------+ //| Устанавливает пользовательское описание | //+------------------------------------------------------------------+ void CMSTFIndicators::SetDescription(const int ind_handle,const string descr) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем описание для полученного объекта obj.SetDescription(descr); } //+------------------------------------------------------------------+ //| Устанавливает описание указанного буфера | //+------------------------------------------------------------------+ void CMSTFIndicators::SetBufferDescription(const int ind_handle,const uint buffer_num,const string descr) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем описание для указанного буфера полученного объекта obj.SetBufferDescription(buffer_num,descr); } //+------------------------------------------------------------------+ //| Возвращает флаг серийности указанного буфера | //+------------------------------------------------------------------+ bool CMSTFIndicators::IsSeries(const int ind_handle,const uint buffer_num) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Возвращаем флаг серийности указанного буфера полученного объекта return obj.IsSeries(buffer_num); } //+------------------------------------------------------------------+ //| Возвращает флаг синхронизированности | //| исторических данных по символу/периоду | //+------------------------------------------------------------------+ bool CMSTFIndicators::IsSynchronized(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Возвращаем флаг синхронизированности полученного объекта return obj.IsSynchronized(); } //+------------------------------------------------------------------+ //| Возвращает таймфрейм указанного индикатора | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES CMSTFIndicators::Timeframe(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем таймфрейм полученного объекта return obj.Timeframe(); } //+------------------------------------------------------------------+ //| Возвращает символ указанного индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::Symbol(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем наименование символа. Иначе - текст ошибки return(obj!=NULL ? obj.Symbol() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Возвращает наименование указанного индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::Name(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем наименование индикатора. Иначе - текст ошибки return(obj!=NULL ? obj.Name() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Возвращает список параметров указанного индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::Parameters(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем список параметров индикатора. Иначе - текст ошибки return(obj!=NULL ? obj.Parameters() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Возвращает Digits указанного индикатора | //+------------------------------------------------------------------+ int CMSTFIndicators::Digits(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем Digits полученного объекта return obj.Digits(); } //+------------------------------------------------------------------+ //| Возвращает количество буферов указанного индикатора | //+------------------------------------------------------------------+ uint CMSTFIndicators::BuffersTotal(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return 0; } //--- Возвращаем количество буферов полученного объекта return obj.BuffersTotal(); } //+------------------------------------------------------------------+ //| Возвращает количество баров таймсерии для указанного индикатора | //+------------------------------------------------------------------+ uint CMSTFIndicators::RatesTotal(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return 0; } //--- Возвращаем количество баров таймсерии полученного объекта return obj.RatesTotal(); } //+------------------------------------------------------------------+ //| Возвращает идентификатор указанного индикатора | //+------------------------------------------------------------------+ int CMSTFIndicators::ID(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем идентификатор полученного объекта return obj.ID(); } //+------------------------------------------------------------------+ //| Возвращает описание указанного индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::Description(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем описание индикатора. Иначе - текст ошибки return(obj!=NULL ? obj.Description() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Возвращает заголовок указанного индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::Title(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем заголовок индикатора. Иначе - текст ошибки return(obj!=NULL ? obj.Title() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Возвращает категорию указанного индикатора | //+------------------------------------------------------------------+ ENUM_IND_CATEGORY CMSTFIndicators::Category(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return IND_CATEGORY_NONE; } //--- Возвращаем категорию полученного объекта return obj.Category(); } //+------------------------------------------------------------------+ //| Возвращает количество параметров указанного индикатора | //+------------------------------------------------------------------+ uint CMSTFIndicators::ParamsTotal(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return 0; } //--- Возвращаем количество параметров полученного объекта return obj.ParamsTotal(); } //+------------------------------------------------------------------+ //| Возвращает структуру параметров по индексу из массива | //| для указанного индикатора | //+------------------------------------------------------------------+ MqlParam CMSTFIndicators::GetMqlParam(const int ind_handle,const int index) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); MqlParam null; ::ZeroMemory(null); return null; } //--- Возвращаем структуру параметров полученного объекта по индексу из массива параметров return obj.GetMqlParam(index); } //+------------------------------------------------------------------+ //| Возвращает описание таймфрейма для указанного индикатора | //+------------------------------------------------------------------+ string CMSTFIndicators::TimeframeDescription(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- Если объект получен, возвращаем описание таймфрейма индикатора. Иначе - текст ошибки return(obj!=NULL ? obj.Description() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Возвращает количество рассчитанных данных указанного индикатора | //+------------------------------------------------------------------+ int CMSTFIndicators::Calculated(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем количество рассчитанных данных полученного объекта return obj.Calculated(); } //+------------------------------------------------------------------+ //| Возвращает тип указанного индикатора | //+------------------------------------------------------------------+ ENUM_INDICATOR CMSTFIndicators::Type(const int ind_handle) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return (ENUM_INDICATOR)WRONG_VALUE; } //--- Возвращаем тип индикатора полученного объекта return (ENUM_INDICATOR)obj.Type(); }
A lógica de todos os métodos é comentada na listagem dos métodos. Primeiro, obtemos um ponteiro para o indicador desejado na lista, em seguida, definimos ou retornamos sua propriedade, ou realizamos um cálculo e retornamos seu resultado. Todos os métodos chamados foram discutidos acima, quando discutimos a classe base do indicador multiperíodo com vários símbolos.
Implementação de métodos para criar novos objetos indicadores:
//+------------------------------------------------------------------+ //| Добавляет указанный индикатор в коллекцию | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewIndicator(CIndMSTF *ind_obj,const string source) { //--- Устанавливаем списку коллекции флаг сортированного списка this.m_list.Sort(); //--- Ищем в списке индекс аналогичного переданному в метод объекта-индикатора int index=this.m_list.Search(ind_obj); //--- Если такой индикатор с такими же параметрами уже есть в списке, if(index>WRONG_VALUE) { //--- сообщаем об этом в журнал и удаляем новый объект-индикатор ::PrintFormat("%s: The %s indicator with such parameters %s is already in the collection",source,ind_obj.Name(),ind_obj.Parameters()); delete ind_obj; //--- Получаем указатель на уже существующий объект-индикатор в списке и возвращаем его хэндл ind_obj=this.m_list.At(index); return(ind_obj!=NULL ? ind_obj.Handle() : INVALID_HANDLE); } //--- Если такого индикатора нет в списке, но его не удалось поместить в список if(!this.m_list.Add(ind_obj)) { //--- сообщаем об ошибке в журнал, удаляем объект-индикатор и возвращаем INVALID_HANDLE ::PrintFormat("%s: Error. Failed to add %s indicator to collection",source,ind_obj.Name()); delete ind_obj; return INVALID_HANDLE; } //--- Если индикатор помещён в список, но для него не удалось создать расчётную часть - возвращаем INVALID_HANDLE //--- (при ошибке создания расчётной части из списка объект-индикатор удаляется в методе CreateIndicator) if(!this.CreateIndicator(ind_obj)) return INVALID_HANDLE; //--- Всё успешно - сообщаем о добавлении нового индикатора в коллекцию и возвращаем его хэндл ::PrintFormat("%s: %s indicator (handle %ld) added to the collection",source,ind_obj.Title(),ind_obj.Handle()); return ind_obj.Handle(); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Accelerator Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAC(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndAC *ind_obj=new CIndAC(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AC indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Accumulation/Distribution | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndAD *ind_obj=new CIndAD(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create A/D indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+--------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Average Directional Movement Index | //+--------------------------------------------------------------------+ int CMSTFIndicators::AddNewADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndADX *ind_obj=new CIndADX(symbol,timeframe,adx_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create ADX indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор | //| Average Directional Movement Index by Welles Wilder | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndADXW *ind_obj=new CIndADXW(symbol,timeframe,adx_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create ADX Wilder indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Alligator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndAlligator *ind_obj=new CIndAlligator(symbol,timeframe,jaw_period,jaw_shift,teeth_period,teeth_shift,lips_period,lips_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Alligator indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Adaptive Moving Average | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ama_period=9, const int fast_ma_period=2, const int slow_ma_period=30, const int ama_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndAMA *ind_obj=new CIndAMA(symbol,timeframe,ama_period,fast_ma_period,slow_ma_period,ama_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Awesome Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAO(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndAO *ind_obj=new CIndAO(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AO indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Average True Range | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndATR *ind_obj=new CIndATR(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create ATR indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Bears Power | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndBears *ind_obj=new CIndBears(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Bears indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Bulls Power | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndBulls *ind_obj=new CIndBulls(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Bulls indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Bollinger Bands® | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBands(const string symbol,const ENUM_TIMEFRAMES timeframe, const int bands_period=20, const int bands_shift=0, const double deviation=2.0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndBands *ind_obj=new CIndBands(symbol,timeframe,bands_period,bands_shift,deviation,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Bands indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Commodity Channel Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_TYPICAL) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndCCI *ind_obj=new CIndCCI(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create CCI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Chaikin Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ma_period=3, const int slow_ma_period=10, const ENUM_MA_METHOD ma_method=MODE_EMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndCHO *ind_obj=new CIndCHO(symbol,timeframe,fast_ma_period,slow_ma_period,ma_method,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Chaikin indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+-------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Double Exponential Moving Average | //+-------------------------------------------------------------------+ int CMSTFIndicators::AddNewDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndDEMA *ind_obj=new CIndDEMA(symbol,timeframe,ma_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create DEMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор DeMarker | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndDeM *ind_obj=new CIndDeM(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create DeMarker indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Envelopes | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE, const double deviation=0.1) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndEnvelopes *ind_obj=new CIndEnvelopes(symbol,timeframe,ma_method,ma_shift,ma_method,applied_price,deviation); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Envelopes indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Force Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewForce(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=13, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndForce *ind_obj=new CIndForce(symbol,timeframe,ma_period,ma_method,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Force indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Fractals | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewFractals(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndFractals *ind_obj=new CIndFractals(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Fractals indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Fractal Adaptive Moving Average | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndFrAMA *ind_obj=new CIndFrAMA(symbol,timeframe,ma_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create FrAMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Gator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndGator *ind_obj=new CIndGator(symbol,timeframe,jaw_period,jaw_shift,teeth_period,teeth_shift,lips_period,lips_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Gator indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Ichimoku Kinko Hyo | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen=9, const int kijun_sen=26, const int senkou_span_b=52) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndIchimoku *ind_obj=new CIndIchimoku(symbol,timeframe,tenkan_sen,kijun_sen,senkou_span_b); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Ichimoku indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Market Facilitation Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndBWMFI *ind_obj=new CIndBWMFI(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create BW MFI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Momentum | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe, const int mom_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndMomentum *ind_obj=new CIndMomentum(symbol,timeframe,mom_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Momentum indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Money Flow Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndMFI *ind_obj=new CIndMFI(symbol,timeframe,ma_period,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create MFI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Moving Average | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=10, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndMA *ind_obj=new CIndMA(symbol,timeframe,ma_period,ma_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create MA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Moving Average of Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndOsMA *ind_obj=new CIndOsMA(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create OsMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор | //| Moving Averages Convergence/Divergence | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMACD(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndMACD *ind_obj=new CIndMACD(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create MACD indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор On Balance Volume | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndOBV *ind_obj=new CIndOBV(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create OBV indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+-------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Parabolic Stop and Reverse system | //+-------------------------------------------------------------------+ int CMSTFIndicators::AddNewSAR(const string symbol,const ENUM_TIMEFRAMES timeframe, const double step=0.02, const double maximum=0.2) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndSAR *ind_obj=new CIndSAR(symbol,timeframe,step,maximum); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create SAR indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Relative Strength Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewRSI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndRSI *ind_obj=new CIndRSI(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create RSI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Relative Vigor Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=10) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndRVI *ind_obj=new CIndRVI(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create RVI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Standard Deviation | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=20, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndStdDev *ind_obj=new CIndStdDev(symbol,timeframe,ma_period,ma_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create StdDev indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Stochastic Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe, const int Kperiod=5, const int Dperiod=3, const int slowing=3, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_STO_PRICE price_field=STO_LOWHIGH) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndStoch *ind_obj=new CIndStoch(symbol,timeframe,Kperiod,Dperiod,slowing,ma_method,price_field); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Stochastic indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+-------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Triple Exponential Moving Average | //+-------------------------------------------------------------------+ int CMSTFIndicators::AddNewTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndTEMA *ind_obj=new CIndTEMA(symbol,timeframe,ma_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create TEMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор | //| Triple Exponential Moving Averages Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewTriX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndTriX *ind_obj=new CIndTriX(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create TriX indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Larry Williams' Percent Range | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period=14) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndWPR *ind_obj=new CIndWPR(symbol,timeframe,calc_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create WPR indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Variable Index Dynamic Average | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int cmo_period=9, const int ema_period=12, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndVIDyA *ind_obj=new CIndVIDyA(symbol,timeframe,cmo_period,ema_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create VIDyA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Volumes | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndVolumes *ind_obj=new CIndVolumes(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Volumes indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Добавляет в коллекцию пользовательский индикатор | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,const string path,const string name,const uint buffers,const MqlParam ¶m[]) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndCustom *ind_obj=new CIndCustom(symbol,timeframe,path,name,buffers,param); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create %s custom indicator object",__FUNCTION__,name); return INVALID_HANDLE; } //--- Возвращаем результат добавления созданного объекта-индикатора в список коллекцию return this.AddNewIndicator(ind_obj,__FUNCTION__); }
Todos os códigos para a classe de coleção de indicadores estão prontos. A lógica de cada método é comentada, e entender por conta própria não será difícil.
Testes
Para testar o trabalho com classes de multi-indicadores e sua coleção, criaremos um indicador simples no qual faremos a escolha entre várias médias móveis. O objetivo dos testes de hoje é testar o trabalho das classes com indicadores que desenham uma única linha de um buffer na janela principal do gráfico. As médias móveis do conjunto de indicadores de tendência do terminal do cliente são bem adequadas para essa finalidade. No artigos a seguir, criaremos modelos para a criação rápida e trabalho com quaisquer indicadores do conjunto de indicadores no terminal + trabalho com indicadores personalizados. E gradualmente aprimoraremos completamente as classes criadas hoje para o trabalho correto com quaisquer tipos de indicadores.
O indicador de teste mostrará as linhas dos multi-indicadores criados no gráfico, e seus dados serão exibidos no painel de informações, descrito no primeiro artigo do ciclo de trabalho com indicadores.
Dentro de um indicador, criaremos dois indicadores idênticos. Um será calculado com base nos dados do gráfico atual e o outro, com base nos dados do símbolo/período gráfico selecionados nas configurações. Assim, sempre poderemos ver a linha da média móvel no gráfico atual e a linha da mesma média móvel, mas construída em outro período gráfico. O símbolo também pode ser escolhido de outro gráfico, mas então as linhas não coincidirão no nível de preço.
Criaremos um novo arquivo de indicador chamado TestMSTFMovingAverages.mq5:
Definiremos os manipuladores OnTimer e OnChartEvent:
Escolheremos dois buffers desenhados na forma de linhas na janela principal do gráfico:
Os nomes dos buffers podem ser quaisquer, já que renomearemos no código. Clicamos em "Pronto" e obtemos o template do indicador:
//+------------------------------------------------------------------+ //| TestMSTFMovingAverages.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 //--- plot MA1 #property indicator_label1 "MA1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot MA2 #property indicator_label2 "MA2" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- indicator buffers double MA1Buffer[]; double MA2Buffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,MA1Buffer,INDICATOR_DATA); SetIndexBuffer(1,MA2Buffer,INDICATOR_DATA); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- }
Na área global adicionaremos uma enumeração para escolher o tipo de média móvel, incluiremos o arquivo da classe de indicadores multissímbolo e multiperíodo e o arquivo com a classe do painel, e declararemos as variáveis de entrada.
Renomearemos os buffers para tornar seus nomes mais legíveis e declararemos as variáveis globais do indicador:
//+------------------------------------------------------------------+ //| TestMSTFMovingAverages.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 //--- enums enum ENUM_USED_MA { USED_MA_AMA = IND_AMA, // Adaptive Moving Average USED_MA_DEMA = IND_DEMA, // Double Exponential Moving Average USED_MA_FRAMA = IND_FRAMA, // Fractal Adaptive Moving Average USED_MA_MA = IND_MA, // Moving Average USED_MA_TEMA = IND_TEMA, // Triple Exponential Moving Average USED_MA_VIDYA = IND_VIDYA, // Variable Index Dynamic Average }; //--- plot MA1 #property indicator_label1 "MA1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot MA2 #property indicator_label2 "MA2" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input ENUM_USED_MA InpIndicator = USED_MA_MA; /* Used MA */ // Используемый тип скользящей средней input string InpSymbol = NULL; /* Symbol */ // Символ скользящей средней input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм скользящей средней input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ // Используемая цена для расчёта input ENUM_MA_METHOD InpMethod = MODE_SMA; /* MA Method */ // Метод расчёта Moving Average input int InpShift = 0; /* MA Shift */ // Сдвиг скользящей средней input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferMA1[]; double BufferMA2[]; //--- global variables int handle_ma1; int handle_ma2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные
Dentro do manipulador OnInit(), escreveremos a criação de um timer, atribuiremos os buffers desenhados, criaremos handles para os indicadores selecionados e criaremos o painel informativo:
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 1 массивы BufferMA1 и BufferMA2 соответственно SetIndexBuffer(0,BufferMA1,INDICATOR_DATA); SetIndexBuffer(1,BufferMA2,INDICATOR_DATA); //--- sets indicator shift //PlotIndexSetInteger(0,PLOT_SHIFT,InpShift); // аналог в стр. 116 //PlotIndexSetInteger(1,PLOT_SHIFT,InpShift); // аналог в стр. 117 //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferMA1,InpAsSeries); ArraySetAsSeries(BufferMA2,InpAsSeries); //--- Для разных индикаторов ширина панели (width) будет индивидуальной (из-за количества параметров в описании) int width=0; //--- В зависимости от выбранного в настройках индикатора создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках switch(InpIndicator) { case USED_MA_AMA : handle_ma1=indicators.AddNewAMA(NULL,PERIOD_CURRENT,9,2,30,InpShift); handle_ma2=indicators.AddNewAMA(InpSymbol,InpTimeframe,9,2,30,InpShift); width=269; break; case USED_MA_DEMA : handle_ma1=indicators.AddNewDEMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice); handle_ma2=indicators.AddNewDEMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice); width=255; break; case USED_MA_FRAMA : handle_ma1=indicators.AddNewFrAMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice); handle_ma2=indicators.AddNewFrAMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice); width=259; break; case USED_MA_TEMA : handle_ma1=indicators.AddNewTEMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice); handle_ma2=indicators.AddNewTEMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice); width=253; break; case USED_MA_VIDYA : handle_ma1=indicators.AddNewVIDyA(NULL,PERIOD_CURRENT,9,12,InpShift,InpPrice); handle_ma2=indicators.AddNewVIDyA(InpSymbol,InpTimeframe,9,12,InpShift,InpPrice); width=267; break; default: handle_ma1=indicators.AddNewMA(NULL,PERIOD_CURRENT,10,InpShift,InpMethod,InpPrice); handle_ma2=indicators.AddNewMA(InpSymbol,InpTimeframe,10,InpShift,InpMethod,InpPrice); width=231; break; } //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_ma1==INVALID_HANDLE || handle_ma2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_ma1,0); indicators.SetPlotLabelFromBuffer(1,handle_ma2,0); //--- Устанавливаем "пустые" значения для буферов расчётной части созданных индикаторов indicators.SetBufferInitValue(handle_ma1,0,EMPTY_VALUE); indicators.SetBufferInitValue(handle_ma2,0,EMPTY_VALUE); //--- Устанавливаем смещения линиям индикатора indicators.SetPlotShift(0,InpShift); indicators.SetPlotShift(1,InpShift); //--- Панель //--- Создаём панель panel=new CDashboard(1,20,20,width,264); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); }
Adicionaremos o manipulador OnDeinit():
//+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); }
No manipulador OnCalculate() chamaremos o cálculo de todos os indicadores multissímbolo e multiperíodo. Em caso de cálculo malsucedido, deve-se sair do manipulador retornando zero, para recalcular os indicadores novamente no próximo tick.
Após um cálculo bem-sucedido, os dados nos arrays-buffers dos objetos-indicadores já estão disponíveis, já que eles podem agora ser exibidos no painel informativo. Após exibir os dados no painel, mostraremos os dados dos buffers calculados nos buffers desenhados do indicador:
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- Количество баров для расчёта int limit=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ma1,0,limit,BufferMA1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ma2,0,limit,BufferMA2)) return 0; //--- return value of prev_calculated for next call return(rates_total); }
No timer do indicador, chamaremos o timer do objeto-coleção de indicadores:
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); }
No manipulador de eventos do gráfico OnChartEvent(), chamaremos o manipulador de eventos do objeto-painel e processaremos o movimento do cursor para determinar a barra sobre a qual ele está posicionado:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Função que exibe os dados dos multi-indicadores no painel:
//+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_ma1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_ma1,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ma1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ma1,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_ma2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ma2,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ma2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ma2,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ma2,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_ma1,0,index,value2,value21); string ma1=indicators.Name(handle_ma1); string ma2=indicators.Name(handle_ma2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); }
Como vemos, para calcular os indicadores multissímbolo e multiperíodo, basta chamar o método Calculate() da classe-coleção de indicadores. Após um cálculo bem-sucedido, todos os dados já estão disponíveis. Nos Expert Advisors, eles podem ser obtidos e processados. Nos indicadores, após um cálculo bem-sucedido, os dados podem ser exibidos no gráfico na forma de linhas de buffers de desenho, utilizando o método DataToBuffer() da classe de coleção de indicadores. E isso é tudo que é necessário para o cálculo e exibição de multi-indicadores no gráfico.
Após a compilação do indicador de teste, vamos executá-lo em um gráfico com o período M1, nas configurações escolheremos o símbolo atual e o período de cálculo do indicador M5. Neste caso, serão criados dois indicadores de médias móveis selecionados nas configurações. Um será calculado com base nos dados do gráfico atual, e o outro com base nos dados do período gráfico de cinco minutos. Alternando o timeframe do gráfico, será possível ver como no M1 são desenhadas duas linhas: uma corresponderá à média móvel calculada no M1, e a outra à média móvel calculada no M5. Se mudarmos o gráfico para M5, apenas um indicador será criado, pois o segundo será idêntico ao primeiro e não será criado. Se mudarmos o gráfico para M15, um indicador será calculado no M15, e o outro no M5, e também será exibido no gráfico.
Como podemos ver, a funcionalidade anunciada funciona ao exibir no janela principal do gráfico indicadores com um buffer.
Todos os arquivos de todas as classes e do indicador de teste podem ser vistos nos arquivos anexados ao artigo.
Considerações finais
Hoje, fizemos funcionalidades para a criação rápida de indicadores multissímbolo e multiperíodo e a obtenção de seus dados em indicadores com plotagem de indicadores calculados na janela principal do gráfico. Nos próximos artigos, criaremos modelos para a criação de outros indicadores padrão multissímbolo e multiperíodo, que plotam seus dados na janela principal do gráfico, e não apenas com um buffer de desenho. No final, teremos uma ferramenta prática para transformar rapidamente quaisquer indicadores em suas versões multissímbolo e multiperíodo. E, provavelmente, as classes de multi-indicadores serão posteriormente aprimoradas com a criação de outros indicadores padrão e personalizados.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/13578
- 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