
Negociação de Notícias Facilitada (Parte 3): Realizando Negócios
Introdução
Anteriormente, criamos um Expert Advisor para armazenar dados econômicos em nosso banco de dados de calendário de notícias. Também desenvolvemos várias classes para construir uma base para que nosso especialista execute adequadamente. Neste artigo, vamos expandir essas classes em nosso projeto para finalmente alcançar nosso objetivo de negociar a partir de dados econômicos. Nosso próximo objetivo será a lucratividade, que abordaremos nos próximos artigos. Para este artigo, adicionaremos uma nova visualização ao nosso banco de dados para exibir todos os eventos exclusivos do calendário econômico MQL5 para fornecer informações sobre os diferentes eventos. Também adicionaremos novos parâmetros ao especialista para filtrar dados econômicos ao negociar, proporcionando flexibilidade. Você pode conferir o artigo anterior na série "Negociação de Notícias Facilitada", onde criamos uma classe de gerenciamento de risco para gerenciar o risco nas negociações e outras informações úteis, caso ainda não tenha visto.
O que você pode esperar?
Gráficos melhorados que são concisos, modernos e responsivos para o gráfico atual. A imagem abaixo é uma representação desses gráficos no modo Claro.
As seções: 1, 2, 3, 4, 5, 6, 7, 8 e 9 serão exibidas automaticamente sempre que o especialista estiver em um gráfico.
As seções: 10, (11, 12, 13, 14 e 15 formam um grupo) e 16 são opcionais e serão atualizadas a cada novo candle de 1 minuto (isso é para melhorar o desempenho durante os testes históricos).
Seção
- 10: Exibe a data e hora do terminal. O texto do tempo será exibido em vermelho quando um evento de notícias ocorrer enquanto o gráfico estiver no modo claro.
- 11: Exibe a data e hora do próximo evento de notícias. O texto será exibido em vermelho quando a data e hora forem iguais à hora do terminal.
- 12: Exibe o nome do evento de notícias. A cor do texto mudará dependendo da Importância do evento, por exemplo, Importância Alta será mostrada em vermelho.
- 13: Exibe o nome do país do evento de notícias. A cor do texto mudará dependendo da Importância do evento e do modo de cor do gráfico, como no modo Claro.
- 14: Exibe o nome da moeda do evento de notícias. A cor do texto variará.
- 15: Exibe a importância do evento de notícias. A cor do texto variará.
- 16: Exibe o spread para o símbolo atual e a classificação, que é calculada com 2 semanas de dados de spread de candles de 1 minuto e categorizada em grupos de excelente, bom, normal, ruim e terrível, com cores diferentes para cada categoria, variando entre o modo escuro e claro.
A imagem abaixo é uma representação de como o modo escuro é implementado.
Seção
- 17: Exibe a hora dos eventos que ocorrerão ou já ocorreram no dia atual do terminal.
Entradas de Exibição
- MODO DE COR DO GRÁFICO: O objetivo dessa opção é alternar entre o Modo Escuro ou Claro.
- EXIBIR INFORMAÇÕES DE NOTÍCIAS: O objetivo dessa opção é mostrar ou não mostrar as seções (11, 12, 13, 14, 15) no gráfico.
- EXIBIR OBJETO DE EVENTO: O objetivo dessa opção é mostrar ou não mostrar a seção 17 no gráfico.
- EXIBIR CLASSIFICAÇÃO DO SPREAD: O objetivo dessa opção é mostrar ou não mostrar a seção 16 no gráfico.
- EXIBIR DATA: O objetivo dessa opção é mostrar ou não mostrar a seção 10 no gráfico.
Entradas de Agendamento de DST
- SELECIONAR OPÇÃO DST: O objetivo dessa opção é permitir que o usuário/negociante selecione o seu agendamento DST personalizado ou permita que o especialista selecione automaticamente o agendamento DST recomendado para configurar corretamente os horários dos eventos ao realizar testes históricos no testador de estratégias.
- SELECIONAR DST PERSONALIZADO: O objetivo dessa opção é permitir que o usuário/negociante configure manualmente o agendamento DST.
Entradas de Gerenciamento de Risco
- SELECIONAR OPÇÃO DE RISCO: O objetivo dessa opção é permitir que o usuário/negociante selecione diferentes perfis de Gerenciamento de Risco, como Tamanho Mínimo de Lote, Tamanho Máximo de Lote, etc.
- PISO DE RISCO: O objetivo dessa opção é definir um risco mínimo para todos os perfis de risco. Exemplo: se não houver dinheiro suficiente para um lote de 1 lote, mas houver dinheiro suficiente para o tamanho mínimo de lote de 0,01 lote, então será usado 0,01 para abrir a negociação, ao invés de não abrir nenhuma negociação devido à falta de dinheiro. Este é apenas uma rede de segurança caso os perfis de risco não tenham sido configurados adequadamente.
- RISCO MÁXIMO: O objetivo desta opção é abrir uma negociação com a porcentagem de margem livre na conta, caso não haja dinheiro suficiente para abrir uma negociação normal. Esta opção só está operacional quando o RISCO PISO estiver configurado para RISCO-MÁXIMO.
- RISCO TETO: O objetivo desta opção é definir um limite de tamanho de lote quando a conta for grande o suficiente para abrir o lote máximo para um símbolo específico. O limite varia de TAMANHO DE LOTE MÁXIMO, o que significa que o tamanho máximo do lote possível é o definido pelo símbolo específico, enquanto TAMANHO DE LOTE MÁXIMO(x2) abrirá duas negociações com o tamanho de lote máximo, dependendo se o limite de volume permitir isso.
- PERCENTUAL DE [SALDO | MARGEM LIVRE]: O objetivo desta opção é arriscar um determinado percentual do Saldo ou da Margem Livre disponível.
- VALOR POR [SALDO | MARGEM LIVRE]: O objetivo desta opção é arriscar um determinado valor do Saldo ou da Margem Livre, por exemplo, se [SALDO | MARGEM LIVRE] for definido como 1000 e CADA VALOR for configurado para 10, isso significa que, para cada 1000 no Saldo ou Margem Livre, arrisque 10 de valor em moeda para cada operação. Portanto, se seu saldo/margem livre for 1000 USD, arrisque 10 USD para cada operação.
- TAMANHO DE LOTE POR [SALDO | MARGEM LIVRE]: O objetivo desta opção é arriscar um determinado tamanho de lote para um valor de Saldo ou Margem Livre, por exemplo, se [SALDO | MARGEM LIVRE] for definido como 1000 e CADA LOTE(VOLUME) for configurado para 0,1, isso significa que, para cada 1000 no Saldo ou Margem Livre, arrisque 0,1 de tamanho de lote para cada operação. Portanto, se seu saldo/margem livre for 1000 USD, arrisque 0,1 para cada operação.
- LOTE PERSONALIZADO: O objetivo desta opção é arriscar um tamanho de lote predeterminado para cada operação aberta.
- PERCENTUAL DE RISCO-MÁXIMO: O objetivo desta opção é arriscar um percentual do volume de risco máximo para um símbolo com a Margem Livre disponível da conta, por exemplo, se o volume de risco máximo para o AUDUSD com a Margem Livre da conta em 10.000 USD for 100 Lotes, então, se definirmos o PERCENTUAL DE RISCO-MÁXIMO para 25%, o tamanho do lote usado será 25% de 100 Lotes, ou seja, 25 Lotes.
Entradas de CONFIGURAÇÕES DE NOTÍCIAS
As Configurações de Notícias consistem em várias opções de entrada, a saber:
- IMPORTÂNCIA DO CALENDÁRIO
- FREQUÊNCIA DO EVENTO
- SETOR DO EVENTO
- TIPO DE EVENTO
- MOEDA DO EVENTO
- IMPORTÂNCIA DO CALENDÁRIO: O objetivo desta opção é filtrar os dados de notícias para uma Importância de notícia especificada.
- FREQUÊNCIA DO EVENTO: O objetivo desta opção é filtrar os dados de notícias com base na frequência de ocorrência.
- SETOR DO EVENTO: O objetivo desta opção é filtrar os dados de notícias com base no setor.
- TIPO DE EVENTO: O objetivo desta opção é filtrar os dados de notícias de acordo com o tipo, por exemplo, EVENTO é tipicamente usado para discursos e reuniões, enquanto INDICADOR é para taxas de juros, dados de emprego, etc., e FERIADO é para o Ano Novo e vários outros feriados.
- MOEDA DO EVENTO: O objetivo desta opção é filtrar os dados de notícias com base nas opções de moeda selecionadas disponíveis. MOEDAS DO SIMBOLO consideram todas as moedas do MARGEM DO SIMBOLO, BASE DO SIMBOLO e LUCRO DO SIMBOLO.
Entradas de CONFIGURAÇÕES DE NEGÓCIOS
- STOPLOSS[0=NENHUM]: O objetivo desta opção é definir um stoploss fixo para todas as negociações. Quando o stoploss é definido como zero, todas as negociações não terão um valor de stoploss.
- TAKEPROFIT[0=NENHUM]: O objetivo desta opção é definir um take-profit fixo para todas as negociações. Quando o take-profit é definido como zero, todas as negociações não terão um valor de take-profit.
- SECUNDOS ANTES DA ENTRADA: O objetivo desta opção é permitir que o usuário/operador configure o número de segundos antes da negociação ser aberta, antes do horário do evento. Então, se o SECUNDOS ANTES DA ENTRADA for configurado para 5, isso significa que 5 segundos antes do evento ocorrer será o intervalo de tempo para as negociações serem abertas antes do horário do evento. Ex. se o horário do evento for 15:00, então as negociações serão permitidas a partir de 5 segundos antes do evento, ou seja, de 14:59:45 a 14:59:59.
- DIA DA SEMANA PARA NEGÓCIOS: O objetivo desta opção é filtrar qualquer dia útil da semana, por exemplo, segunda-feira, terça-feira, etc.
Agora vamos mergulhar no código que tornará nosso expert funcional.
Classe de Propriedades do Símbolo
Alterações feitas a partir da Parte 2:
- Declaração de enumeração para avaliação de spread
//Enumeration for Spread rating enum SpreadRating { SpreadRating_Terrible,//Terrible SpreadRating_Bad,//Bad SpreadRating_Normal,//Normal SpreadRating_Good,//Good SpreadRating_Excellent//Excellent };
- Declaração de variável Booleana para configurar o modo de cor do gráfico
bool isLightMode;//Variável para configurar o modo de cor do gráfico
- Declaração de função Booleana para recuperar o spread flutuante
bool SpreadFloat(string SYMBOL=NULL);//Retrieve Spread Float
//+------------------------------------------------------------------+ //|Retrieve Spread Float | //+------------------------------------------------------------------+ bool CSymbolProperties::SpreadFloat(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { return CSymbol.SpreadFloat(); } Print("Unable to retrieve Symbol's Spread Float"); return false;//Retrieve false when failed. }
- Declaração da função de avaliação de Spread para recuperar a avaliação de spread
SpreadRating SpreadValue(string SYMBOL=NULL);//Retrieve Spread Rating
Esta função deve retornar um valor de enumeração de SpreadRating.
//+------------------------------------------------------------------+ //|Retrieve Spread Rating | //+------------------------------------------------------------------+ SpreadRating CSymbolProperties::SpreadValue(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(SpreadFloat(SYMBOL))//Check if Symbol has a floating Spread { //Declarations vector Spreads; int SpreadArray[],SpreadAvg=0,SpreadMax=0,SpreadMin=0, SpreadUpper=0,SpreadLower=0,SpreadAvgUpper=0, SpreadAvgLower=0,SpreadMidUpper=0,SpreadMidLower=0; //Get Spread data from CopySpread built-in function for 2 weeks using M1 timeframe. if(CopySpread(GetSymbolName(),PERIOD_M1,iTime(GetSymbolName(),PERIOD_W1,2), iTime(GetSymbolName(),PERIOD_M1,0),SpreadArray)==-1) { Print("Error trying to retrieve spread values"); return SpreadRating_Normal;//Retrieve default value when failed. } else { Spreads.Assign(SpreadArray);//Assign spread array into Spreads vector variable SpreadMax = int(Spreads.Max());//Assign max spread SpreadMin = int(Spreads.Min());//Assign min spread SpreadAvg = int(Spreads.Median());//Assign average spread //Divide Spread into sectors based of different averages. SpreadMidUpper = int((SpreadAvg+SpreadMax)/2); SpreadMidLower = int((SpreadAvg+SpreadMin)/2); SpreadAvgUpper = int((SpreadAvg+SpreadMidUpper)/2); SpreadAvgLower = int((SpreadAvg+SpreadMidLower)/2); SpreadUpper = int((SpreadMidUpper+SpreadMax)/2); SpreadLower = int((SpreadMidLower+SpreadMin)/2); int Spread = Spread(SYMBOL);//Assign Symbol's Spread if(Spread<SpreadLower||Spread==SpreadMin)//Excellent { return SpreadRating_Excellent; } else if(Spread>=SpreadLower&&Spread<SpreadAvgLower)//Good { return SpreadRating_Good; } else if(Spread>=SpreadAvgLower&&Spread<=SpreadAvgUpper)//Normal { return SpreadRating_Normal; } else if(Spread>SpreadAvgUpper&&Spread<=SpreadUpper)//Bad { return SpreadRating_Bad; } else//Terrible { return SpreadRating_Terrible; } } } else { return SpreadRating_Normal;//Retrieve default value when spread is fixed. } } Print("Unable to retrieve Symbol's Spread Rating"); return SpreadRating_Normal;//Retrieve default value when failed. }
Primeiro, definimos o símbolo, depois verificamos se o símbolo possui um spread flutuante antes de realizar cálculos simples para avaliar o spread com base em suas médias. Se a configuração do símbolo falhar ou se o símbolo não tiver um spread flutuante, retornaremos SpreadRating_Normal como valor padrão.
if(SetSymbolName(SYMBOL))//Set Symbol { if(SpreadFloat(SYMBOL))//Check if Symbol has a floating Spread {
Se conseguimos configurar o símbolo e o símbolo possui um spread flutuante, então declararemos uma variável vetor de Spreads e variáveis int para armazenar os valores de spread. Após declarar nossas variáveis, utilizaremos a função CopySpread para armazenar os valores de spread em nossa variável SpreadArray a partir do candle de 1 minuto, começando 2 semanas atrás até o momento atual do candle de 1 minuto. Se a função CopySpread falhar por algum motivo, retornaremos SpreadRating_Normal como valor padrão.
//Declarations vector Spreads; int SpreadArray[],SpreadAvg=0,SpreadMax=0,SpreadMin=0, SpreadUpper=0,SpreadLower=0,SpreadAvgUpper=0, SpreadAvgLower=0,SpreadMidUpper=0,SpreadMidLower=0; //Get Spread data from CopySpread built-in function for 2 weeks using M1 timeframe. if(CopySpread(GetSymbolName(),PERIOD_M1,iTime(GetSymbolName(),PERIOD_W1,2), iTime(GetSymbolName(),PERIOD_M1,0),SpreadArray)==-1) { Print("Error trying to retrieve spread values"); return SpreadRating_Normal;//Retrieve default value when failed. }
Uma vez que o CopySpread seja bem-sucedido, atribuiremos ao vetor Spreads os valores inteiros de nossa variável SpreadArray. Em seguida, precisamos obter informações básicas desses valores de array, como o spread máximo ao longo do período de 2 semanas, bem como o spread mínimo e o spread médio, que serão armazenados nas variáveis SpreadMax, SpreadMin e SpreadAvg, respectivamente. Agora queremos obter diferentes médias desses três valores anteriores.
Para a variável SpreadMidUpper, queremos a média entre SpreadAvg e SpreadMax; para a variável SpreadMidLower, queremos a média entre SpreadAvg e SpreadMin; para a variável SpreadAvgUpper, queremos a média entre SpreadAvg e SpreadMidUpper; para a variável SpreadAvgLower, queremos a média entre SpreadAvg e SpreadMidLower; para a variável SpreadUpper, queremos a média entre SpreadMidUpper e SpreadMax; para a variável SpreadLower, queremos a média entre SpreadMidLower e SpreadMin. Também precisaremos do spread atual do símbolo para comparar e classificar o spread.
Spreads.Assign(SpreadArray);//Assign spread array into Spreads vector variable SpreadMax = int(Spreads.Max());//Assign max spread SpreadMin = int(Spreads.Min());//Assign min spread SpreadAvg = int(Spreads.Median());//Assign average spread //Divide Spread into sectors based of different averages. SpreadMidUpper = int((SpreadAvg+SpreadMax)/2); SpreadMidLower = int((SpreadAvg+SpreadMin)/2); SpreadAvgUpper = int((SpreadAvg+SpreadMidUpper)/2); SpreadAvgLower = int((SpreadAvg+SpreadMidLower)/2); SpreadUpper = int((SpreadMidUpper+SpreadMax)/2); SpreadLower = int((SpreadMidLower+SpreadMin)/2); int Spread = Spread(SYMBOL);//Assign Symbol's Spread
Temos 5 classificações de spread, a saber:
- Excelente: Quando o spread atual for menor que a variável SpreadLower ou igual a SpreadMin.
- Bom: Quando o spread atual for maior ou igual à variável SpreadLower e o spread atual for menor que a variável SpreadAvgLower.
- Normal: Quando o spread atual for menor ou igual à variável SpreadAvgLower e o spread atual for menor ou igual à variável SpreadAvgUpper.
- Ruim: Quando o spread atual for maior que SpreadAvgUpper e o spread atual for menor ou igual à variável SpreadUpper.
- Terrível: Quando o spread atual for maior que a variável SpreadUpper.
if(Spread<SpreadLower||Spread==SpreadMin)//Excellent { return SpreadRating_Excellent; } else if(Spread>=SpreadLower&&Spread<SpreadAvgLower)//Good { return SpreadRating_Good; } else if(Spread>=SpreadAvgLower&&Spread<=SpreadAvgUpper)//Normal { return SpreadRating_Normal; } else if(Spread>SpreadAvgUpper&&Spread<=SpreadUpper)//Bad { return SpreadRating_Bad; } else//Terrible { return SpreadRating_Terrible; }
- Declaração da função para obter a cor do spread com base em sua classificação
color SpreadColor(string SYMBOL=NULL);//Retrieve Spread Color
Para obter a cor do spread para cada valor de enumeração de spread, consideraremos usar uma instrução switch, pois os valores de enumeração são constantes. As cores para cada classificação são as seguintes:
- Excelente: se no modo claro, então clrBlue
caso contrário, clrLightCyan
- Bom: se no modo claro, então clrCornflowerBlue
caso contrário, clrLightGreen
- Normal: se no modo claro, então clrBlack
caso contrário, clrWheat
- Ruim: clrOrange
- Terrível: clrRed
- Padrão: se no modo claro, então clrBlack, caso contrário clrWheat
//+------------------------------------------------------------------+ //|Retrieve Spread Color | //+------------------------------------------------------------------+ color CSymbolProperties::SpreadColor(string SYMBOL=NULL) { switch(SpreadValue(SYMBOL))//Get Spread Rating value { case SpreadRating_Excellent://Excellent Spread return (isLightMode)?clrBlue:clrLightCyan; break; case SpreadRating_Good://Good Spread return (isLightMode)?clrCornflowerBlue:clrLightGreen; break; case SpreadRating_Normal://Normal Spread return (isLightMode)?clrBlack:clrWheat; break; case SpreadRating_Bad://Bad Spread return clrOrange; break; case SpreadRating_Terrible://Terrible Spread return clrRed; break; default://failed to be identified return (isLightMode)?clrBlack:clrWheat;//Retrieve default color when failed. break; } }
- Declaração da função string para obter a descrição do spread
string SpreadDesc(string SYMBOL=NULL);//Retrieve Spread Description
//+------------------------------------------------------------------+ //|Retrieve Spread Description | //+------------------------------------------------------------------+ string CSymbolProperties::SpreadDesc(string SYMBOL=NULL) { switch(SpreadValue(SYMBOL))//Get Spread Rating value { case SpreadRating_Excellent://Excellent Spread return "Excellent"; break; case SpreadRating_Good://Good Spread return "Good"; break; case SpreadRating_Normal://Normal Spread return "Normal"; break; case SpreadRating_Bad://Bad Spread return "Bad"; break; case SpreadRating_Terrible://Terrible Spread return "Terrible"; break; default://failed to be identified return "Unknown";//Retrieve default value when failed. break; } }
- Declaração da função string para obter a descrição do símbolo
string Description(string SYMBOL=NULL);//Retrieve Symbol's Description
//+------------------------------------------------------------------+ //|Retrieve Symbol's Description | //+------------------------------------------------------------------+ string CSymbolProperties::Description(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { return CSymbol.Description(); } Print("Unable to retrieve Symbol's Description"); return "";//Retrieve an empty string when failed. }
Classe de Propriedades do Gráfico
Esta classe foi reestruturada a partir da Parte 2. A classe de propriedades do gráfico agora herdará da classe de gráfico das classes de inclusão MQL5. A estrutura ChartProp armazenará todas as propriedades do gráfico às quais faremos alterações. Nossa função pública ChartRefresh chamará nossa função ChartGet, que inicializará as propriedades do gráfico, e depois chamaremos a função ChartSet que configurará o gráfico com os valores das propriedades do gráfico vindos do ChartGet.
#include "SymbolProperties.mqh" #include <Charts/Chart.mqh> CSymbolProperties CSymbol;//Symbol Properties object //+------------------------------------------------------------------+ //|ChartProperties class | //+------------------------------------------------------------------+ class CChartProperties : public CChart { private: //Structure for chart properties struct ChartProp { ENUM_CHART_MODE mode;//Chart Mode color clrBackground;//Chart Background Color color clrForeground;//Chart Foreground Color color clrLineLast;//Chart Line Color color clrCandleBear;//Chart Bear Candle Color color clrBarDown;//Chart Down Candle Color color clrCandleBull;//Chart Bull Candle Color color clrBarUp;//Chart Up Candle Color color clrLineAsk;//Chart Ask Color color clrLineBid;//Chart Bid Color color clrChartLine;//Chart Line Color color clrStopLevels;//Chart Stop Level Color color clrVolumes;//Chart Volumes Color bool Foreground;//Chart Foreground Visibility bool ShowLineAsk;//Chart Ask Line Visibility bool ShowLineBid;//Chart Bid Line Visibility bool ShowPeriodSep;//Chart Period Separator Visibility bool ShowOHLC;//Chart Open-High-Low-Close Visibility bool ShowGrid;//Chart Grid Visibility ENUM_CHART_VOLUME_MODE ShowVolumes;//Chart Volumes Visibility bool AutoScroll;//Chart Auto Scroll Option bool Shift;//Chart Shift Option double ShiftSize;//Chart Shift Size bool ShowObjectDescr;//Chart Object Descriptions ulong CHART_SHOW_TRADE_LEVELS;//Chart Trade Levels Visibility ulong CHART_SHOW_ONE_CLICK;//Chart One Click Trading Visibility ulong CHART_SHOW_TICKER;//Chart Ticker Visibility ulong CHART_DRAG_TRADE_LEVELS;//Chart Drag Trade levels ENUM_CHART_POSITION Navigate;//Chart Navigate }; ChartProp DefaultChart,MyChart;//Used to store chart properties void ChartSet(ChartProp &Prop);//Apply Chart format void ChartGet();//Assign Chart property values public: CChartProperties();//Constructor ~CChartProperties(void);//Destructor //Configure the chart void ChartRefresh() {ChartGet();ChartSet(MyChart);} string GetChartPeriodName();//Retrieve Period name };
No construtor, atribuiremos a variável herdada m_chart_id o ID do gráfico atual.
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CChartProperties::CChartProperties() { m_chart_id=ChartID();//Set chart id ChartGet();//Get chart values ChartSet(MyChart);//customize chart }
Para a função ChartGet, atribuiremos valores às nossas variáveis DefaultChart e MyChart, onde DefaultChart armazenará as propriedades do gráfico atual antes de modificarmos o gráfico e onde MyChart armazenará nossos valores personalizados.
//+------------------------------------------------------------------+ //|Assign Chart property values | //+------------------------------------------------------------------+ void CChartProperties::ChartGet() { DefaultChart.mode = Mode();//assign chart mode MyChart.mode = CHART_CANDLES;//assign custom chart mode DefaultChart.clrBackground = ColorBackground();//assign Background color MyChart.clrBackground = (isLightMode)?clrWhite:clrBlack;//assign custom Background color DefaultChart.clrForeground = ColorForeground();//assign foreground color MyChart.clrForeground = (isLightMode)?clrBlack:clrWhite;//assign custom foreground color DefaultChart.clrLineLast = ColorLineLast();//assign Chart Line Color MyChart.clrLineLast = clrWhite;//assign custom Chart Line Color DefaultChart.clrCandleBear = ColorCandleBear();//assign Chart Bear Candle Color MyChart.clrCandleBear = clrBlack;//assign custom Chart Bear Candle Color DefaultChart.clrBarDown = ColorBarDown();//assign Chart Down Candle Color MyChart.clrBarDown = (isLightMode)?clrBlack:CSymbol.Background();//assign custom Chart Down Candle Color DefaultChart.clrCandleBull = ColorCandleBull();//assign Chart Bull Candle Color MyChart.clrCandleBull = CSymbol.Background();//assign custom Chart Bull Candle Color DefaultChart.clrBarUp = ColorBarUp();//assign Chart Up Candle Color MyChart.clrBarUp = (isLightMode)?clrBlack:CSymbol.Background();//assign custom Chart Up Candle Color DefaultChart.clrLineAsk = ColorLineAsk();//assign Chart Ask Color MyChart.clrLineAsk = (isLightMode)?clrBlack:clrWhite;//assign custom Chart Ask Color DefaultChart.clrLineBid = ColorLineBid();//assign Chart Bid Color MyChart.clrLineBid = (isLightMode)?clrBlack:CSymbol.Background();//assign custom Chart Bid Color DefaultChart.clrChartLine = ColorChartLine();//assign Chart Line Color MyChart.clrChartLine = (isLightMode)?clrBlack:clrWhite;//assign custom Chart Line Color DefaultChart.clrStopLevels = ColorStopLevels();//assign Chart Stop Level Color MyChart.clrStopLevels = clrRed;//assign custom Chart Stop Level Color DefaultChart.clrVolumes = ColorVolumes();//assign Chart Volumes Color MyChart.clrVolumes = clrGreen;//assign custom Chart Volumes Color DefaultChart.Foreground = Foreground();//assign Chart Foreground Visibility MyChart.Foreground = false;//assign custom Chart Foreground Visibility DefaultChart.ShowLineAsk = ShowLineAsk();//assign Chart Ask Line Visibility MyChart.ShowLineAsk = true;//assign custom Chart Ask Line Visibility DefaultChart.ShowLineBid = ShowLineBid();//assign Chart Bid Line Visibility MyChart.ShowLineBid = true;//assign custom Chart Bid Line Visibility DefaultChart.ShowPeriodSep = ShowPeriodSep();//assign Chart Period Separator Visibility MyChart.ShowPeriodSep = true;//assign custom Chart Period Separator Visibility DefaultChart.ShowOHLC = ShowOHLC();//assign Chart Open-High-Low-Close Visibility MyChart.ShowOHLC = false;//assign custom Chart Open-High-Low-Close Visibility DefaultChart.ShowGrid = ShowGrid();//assign Chart Grid Visibility MyChart.ShowGrid = false;//assign custom Chart Grid Visibility DefaultChart.ShowVolumes = ShowVolumes();//assign Chart Volumes Visibility MyChart.ShowVolumes = CHART_VOLUME_HIDE;//assign custom Chart Volumes Visibility DefaultChart.AutoScroll = AutoScroll();//assign Chart Auto Scroll Option MyChart.AutoScroll = true;//assign custom Chart Auto Scroll Option DefaultChart.Shift = Shift();//assign Chart Shift Option MyChart.Shift = true;//assign custom Chart Shift Option DefaultChart.ShiftSize = ShiftSize();//assign Chart Shift Size MyChart.ShiftSize = 15;//assign custom Chart Shift Size DefaultChart.ShowObjectDescr = ShowObjectDescr();//assign Chart Object Descriptions MyChart.ShowObjectDescr = false;//assign custom Chart Object Descriptions DefaultChart.Navigate = CHART_END;//assign Chart Navigate MyChart.Navigate = CHART_END;//assign custom Chart Navigate //---assign Chart Trade Levels Visibility DefaultChart.CHART_SHOW_TRADE_LEVELS = ChartGetInteger(ChartId(),CHART_SHOW_TRADE_LEVELS); //---assign custom Chart Trade Levels Visibility MyChart.CHART_SHOW_TRADE_LEVELS = ulong(true); //---assign Chart One Click Trading Visibility DefaultChart.CHART_SHOW_ONE_CLICK = ChartGetInteger(ChartId(),CHART_SHOW_ONE_CLICK); //---assign custom Chart One Click Trading Visibility MyChart.CHART_SHOW_ONE_CLICK = ulong(false); //---assign Chart Ticker Visibility DefaultChart.CHART_SHOW_TICKER = ChartGetInteger(ChartId(),CHART_SHOW_TICKER); //---assign custom Chart Ticker Visibility MyChart.CHART_SHOW_TICKER = ulong(false); //---assign Chart Drag Trade levels DefaultChart.CHART_DRAG_TRADE_LEVELS = ChartGetInteger(ChartId(),CHART_DRAG_TRADE_LEVELS); //---assign custom Chart Drag Trade levels MyChart.CHART_DRAG_TRADE_LEVELS = ulong(false); }
Nossa função ChartSet tomará nossa estrutura ChartProp como argumento para configurar o gráfico atual.
//+------------------------------------------------------------------+ //|Apply Chart format | //+------------------------------------------------------------------+ void CChartProperties::ChartSet(ChartProp &Prop) { Mode(Prop.mode);//Set Chart Candle Mode ColorBackground(Prop.clrBackground);//Set Chart Background Color ColorForeground(Prop.clrForeground);//Set Chart Foreground Color ColorLineLast(Prop.clrLineLast);//Set Chart Line Color ColorCandleBear(Prop.clrCandleBear);//Set Chart Bear Candle Color ColorBarDown(Prop.clrBarDown);//Set Chart Down Candle Color ColorCandleBull(Prop.clrCandleBull);//Set Chart Bull Candle Color ColorBarUp(Prop.clrBarUp);//Set Chart Up Candle Color ColorLineAsk(Prop.clrLineAsk);//Set Chart Ask Color ColorLineBid(Prop.clrLineBid);//Set Chart Bid Color ColorChartLine(Prop.clrChartLine);//Set Chart Line Color ColorStopLevels(Prop.clrStopLevels);//Set Chart Stop Level Color ColorVolumes(Prop.clrVolumes);//Set Chart Volumes Color Foreground(Prop.Foreground);//Set if Chart is in Foreground Visibility ShowLineAsk(Prop.ShowLineAsk);//Set Chart Ask Line Visibility ShowLineBid(Prop.ShowLineBid);//Set Chart Bid Line Visibility ShowPeriodSep(Prop.ShowPeriodSep);//Set Chart Period Separator Visibility ShowOHLC(Prop.ShowOHLC);//Set Chart Open-High-Low-Close Visibility ShowGrid(Prop.ShowGrid);//Set Chart Grid Visibility ShowVolumes(Prop.ShowVolumes);//Set Chart Volumes Visibility AutoScroll(Prop.AutoScroll);//Set Chart Auto Scroll Option Shift(Prop.Shift);//Set Chart Shift Option ShiftSize(Prop.ShiftSize);//Set Chart Shift Size Value ShowObjectDescr(Prop.ShowObjectDescr);//Set Chart Show Object Descriptions ChartSetInteger(ChartId(),CHART_SHOW_TRADE_LEVELS,Prop.CHART_SHOW_TRADE_LEVELS);//Set Chart Trade Levels Visibility ChartSetInteger(ChartId(),CHART_SHOW_ONE_CLICK,Prop.CHART_SHOW_ONE_CLICK);//Set Chart One Click Trading Visibility ChartSetInteger(ChartId(),CHART_SHOW_TICKER,Prop.CHART_SHOW_TICKER);//Set Chart Ticker Visibility ChartSetInteger(ChartId(),CHART_DRAG_TRADE_LEVELS,Prop.CHART_DRAG_TRADE_LEVELS);//Set Chart Drag Trade levels Navigate(Prop.Navigate);//Set Chart Navigate }
Quanto à função GetChartPeriodName, vamos recuperar o nome do período do gráfico para o gráfico atual usando uma instrução switch.
//+------------------------------------------------------------------+ //|Retrieve Period name | //+------------------------------------------------------------------+ string CChartProperties::GetChartPeriodName() { switch(ChartPeriod(ChartId()))//Get chart Period with chart id { case PERIOD_M1: return("M1"); case PERIOD_M2: return("M2"); case PERIOD_M3: return("M3"); case PERIOD_M4: return("M4"); case PERIOD_M5: return("M5"); case PERIOD_M6: return("M6"); case PERIOD_M10: return("M10"); case PERIOD_M12: return("M12"); case PERIOD_M15: return("M15"); case PERIOD_M20: return("M20"); case PERIOD_M30: return("M30"); case PERIOD_H1: return("H1"); case PERIOD_H2: return("H2"); case PERIOD_H3: return("H3"); case PERIOD_H4: return("H4"); case PERIOD_H6: return("H6"); case PERIOD_H8: return("H8"); case PERIOD_H12: return("H12"); case PERIOD_D1: return("Daily"); case PERIOD_W1: return("Weekly"); case PERIOD_MN1: return("Monthly"); } return("unknown period"); }
Nosso destruidor restaurará a configuração anterior do gráfico antes de fazermos quaisquer alterações no gráfico.
//+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CChartProperties::~CChartProperties() { ChartSet(DefaultChart);//restore chart default configuration m_chart_id=-1;//reset chart id }
Classe de Propriedades do Objeto
Nesta classe, algumas mudanças foram feitas para permitir a cor personalizada do texto do objeto. Na parte 2, você poderia usar apenas uma cor de texto para todos os objetos de texto. Nossa solução é declarar uma variável de cor fora da classe chamada TextObj_color.
#include "ChartProperties.mqh" color TextObj_color; //+------------------------------------------------------------------+ //|ObjectProperties class | //+------------------------------------------------------------------+ class CObjectProperties:public CChartProperties { private: //Simple chart objects structure struct ObjStruct { long ChartId; string Name; } Objects[];//ObjStruct variable array //-- Add chart object to Objects array void AddObj(long chart_id,string name) { ArrayResize(Objects,Objects.Size()+1,Objects.Size()+2); Objects[Objects.Size()-1].ChartId=chart_id; Objects[Objects.Size()-1].Name=name; } protected: void DeleteObj() { for(uint i=0;i<Objects.Size();i++) { ObjectDelete(Objects[i].ChartId,Objects[i].Name); } } public: CObjectProperties(void) {}//Class constructor //-- Create Rectangle chart object void Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor); //-- Create text chart object void TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10); //-- Create Event object void EventObj(long chartID,string name,string description,datetime eventdate); //-- Class destructor removes all chart objects created previously ~CObjectProperties(void) { DeleteObj(); } };
Como podemos ver abaixo, os parâmetros para a função Textobj são muitos. Para evitar que os parâmetros fiquem longos, usaremos apenas Textobj_color para alterar a cor do texto do objeto.
//+------------------------------------------------------------------+ //|Create text chart object | //+------------------------------------------------------------------+ void CObjectProperties::TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10) { ObjectDelete(chartID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chartID,name,OBJ_LABEL,0,0,0))//Create object label { AddObj(chartID,name);//Add object to array ObjectSetInteger(chartID,name,OBJPROP_XDISTANCE,x_coord);//Set x Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_YDISTANCE,y_coord);//Set y Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_CORNER,Corner);//Set object's corner anchor ObjectSetString(chartID,name,OBJPROP_TEXT,text);//Set object's text ObjectSetInteger(chartID,name,OBJPROP_COLOR,TextObj_color);//Set object's color ObjectSetInteger(chartID,name,OBJPROP_FONTSIZE,fontsize);//Set object's font-size } else { Print("Failed to create object: ",name); } }
Foi feita uma pequena alteração na nossa função Square para permitir diferentes cores de fundo dependendo do modo de cor do gráfico.
//+------------------------------------------------------------------+ //|Create Rectangle chart object | //+------------------------------------------------------------------+ void CObjectProperties::Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor) { const int sub_window=0; // subwindow index const int x=x_coord; // X coordinate const int y=y_coord; // Y coordinate const color back_clr=(isLightMode)?clrWhite:clrBlack;// background color const ENUM_BORDER_TYPE border=BORDER_SUNKEN; // border type const color clr=clrRed; // flat border color (Flat) const ENUM_LINE_STYLE style=STYLE_SOLID; // flat border style const int line_width=0; // flat border width const bool back=false; // in the background const bool selection=false; // highlight to move const bool hidden=true; // hidden in the object list ObjectDelete(chart_ID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0))//create rectangle object label { AddObj(chart_ID,name);//Add object to array ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);//Set x Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);//Set y Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);//Set object's width/x-size ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);//Set object's height/y-size ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);//Set object's background color ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border);//Set object's border type ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,Anchor);//Set objects anchor point ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);//Set object's color ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);//Set object's style ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width);//Set object's flat border width ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);//Set if object is in foreground or not ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);//Set if object is selectable/dragable ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);//Set if object is Selected ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);//Set if object is hidden in object list ChartRedraw(chart_ID); } else { Print("Failed to create object: ",name); } }
Arquivo de Cabeçalho de Variáveis Comuns
Para fins de negociação, decidi criar um banco de dados na memória. Esse banco de dados precisa de um nome, e o nome levará em consideração o nome do corretor, o ID atual do gráfico e se o expert está no testador de estratégia ou não.
#define NEWS_DATABASE_MEMORY StringFormat("Calendar_%s_%d_%s.sqlite",broker,ChartID(),(MQLInfoInteger(MQL_TESTER)?"TESTER":"REAL"))
A enumeração Choice é para personalização e será usada para a entrada do expert, substituindo o tipo de dado Booleano. A enumeração DayOfTheWeek será usada para selecionar o dia da semana de negociação, sem considerar sábado e domingo. Enquanto a função Boolean Answer converterá a enumeração Choice em um tipo de dado Booleano.
enum Choice { Yes,//YES No//NO }; enum DayOfTheWeek { Monday,//MONDAY Tuesday,//TUESDAY Wednesday,//WEDNESDAY Thursday,//THURSDAY Friday,//FRIDAY AllDays//ALL DAYS }; //+------------------------------------------------------------------+ //|Convert enumeration Choice into a boolean value | //+------------------------------------------------------------------+ bool Answer(Choice choose) { return (choose==Yes)?true:false; }
Classe de Variáveis de Tempo
O objetivo desta classe é armazenar os dados de tempo das velas. Esses dados serão usados para verificar se uma nova vela foi formada.
//+------------------------------------------------------------------+ //|TimeVariables class | //+------------------------------------------------------------------+ class CTimeVariables { private: //---Array to store candlestick times datetime CandleTime[2000]; public: CTimeVariables(void); //---Set Array index time void SetTime(uint index,datetime time); //---Get Array index time datetime GetTime(uint index); };
No construtor, definiremos um horário padrão para todos os índices dentro do array CandleTime.
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CTimeVariables::CTimeVariables() { for(uint i=0; i<CandleTime.Size(); i++) { CandleTime[i]=D'1970.01.01'; } }
Na função SetTime, temos dois parâmetros: um para o índice do array e o outro para o datetime. Se o argumento do índice for maior ou igual a zero e menor que o tamanho de CandleTime, então atribuiremos ao índice do array o valor do argumento de tempo.
//+------------------------------------------------------------------+ //|Set Array index time | //+------------------------------------------------------------------+ void CTimeVariables::SetTime(uint index,datetime time) { if(index>=0&&index<CandleTime.Size()) { CandleTime[index] = time; } }
A função GetTime aceitará um argumento inteiro positivo, para recuperar o datetime a partir do valor do índice do array CandleTime, se o argumento do índice for válido.
//+------------------------------------------------------------------+ //|Get Array index time | //+------------------------------------------------------------------+ datetime CTimeVariables::GetTime(uint index) { return (index>=0&&index<CandleTime.Size())?CandleTime[index]:datetime(0); }
Classe de Gerenciamento de Tempo
Declararemos a enumeração DSTSchedule para que o usuário/negociante possa escolher entre Auto DST ou Custom DST para a entrada do expert. A variável MySchedule será usada para armazenar o DST personalizado.
//-- Enumeration for DST schedule enum DSTSchedule { AutoDst_Selection,//AUTO DST CustomDst_Selection//CUSTOM DST } MyDST; DST_type MySchedule;//Variable for custom DST schedule
A função abaixo retornará a hora para uma data específica em um tipo de dado inteiro.
int ReturnHour(datetime time);//Returns the Hour for a specific date
//+------------------------------------------------------------------+ //|Returns the Hour for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnHour(datetime time) { return Time(time).hour; }
A função abaixo retornará o minuto para uma data específica em um tipo de dado inteiro.
int ReturnMinute(datetime time);//Returns the Minute for a specific date
//+------------------------------------------------------------------+ //|Returns the Minute for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnMinute(datetime time) { return Time(time).min; }
A função abaixo retornará o segundo para uma data específica em um tipo de dado inteiro.
int ReturnSecond(datetime time);//Returns the Second for s specific date
//+------------------------------------------------------------------+ //|Returns the Second for s specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnSecond(datetime time) { return Time(time).sec; }
A função abaixo retornará o MqlDateTime para o argumento datetime.
//-- Will convert datetime to MqlDateTime MqlDateTime Time(datetime Timetoformat);
//+------------------------------------------------------------------+ //|Will convert datetime to MqlDateTime | //+------------------------------------------------------------------+ MqlDateTime CTimeManagement::Time(datetime Timetoformat) { TimeToStruct(Timetoformat,timeFormat); return timeFormat; }
A função abaixo retornará o datetime para o argumento datetime com modificação na hora, minuto e segundo.
//-- Will return a datetime with changes to the hour,minute and second datetime Time(datetime time,int Hour,int Minute,int Second);
//+------------------------------------------------------------------+ //|Will return a datetime with changes to the hour,minute and second | //+------------------------------------------------------------------+ datetime CTimeManagement::Time(datetime time,int Hour,int Minute,int Second) { timeFormat=Time(time); timeFormat.hour=Hour; timeFormat.min=Minute; timeFormat.sec=Second; return StructToTime(timeFormat); }
A função abaixo retornará o datetime para o argumento datetime com modificação na hora e no minuto.
//-- Will return a datetime with changes to the hour and minute datetime Time(datetime time,int Hour,int Minute);
//+------------------------------------------------------------------+ //|Will return a datetime with changes to the hour and minute | //+------------------------------------------------------------------+ datetime CTimeManagement::Time(datetime time,int Hour,int Minute) { timeFormat=Time(time); timeFormat.hour=Hour; timeFormat.min=Minute; return StructToTime(timeFormat); }
A função abaixo retornará verdadeiro se o tempo TimeTradeServer estiver dentro dos argumentos BeginTime e EndTime.
//-- Check current time is within a time range bool TimeIsInRange(datetime BeginTime,datetime EndTime);
//+------------------------------------------------------------------+ //|Check current time is within a time range | //+------------------------------------------------------------------+ bool CTimeManagement::TimeIsInRange(datetime BeginTime,datetime EndTime) { if(BeginTime<=TimeTradeServer()&&EndTime>=TimeTradeServer()) { return true; } return false; }
A função abaixo retornará verdadeiro se o datetime PreEvent for menor ou igual a TimeTradeServer e EventTime for maior que TimeTradeServer.
//-- Check if current time is within preEvent time and Event time bool TimePreEvent(datetime PreEvent,datetime Event);
//+------------------------------------------------------------------+ //|Check if current time is within preEvent time and Event time | //+------------------------------------------------------------------+ bool CTimeManagement::TimePreEvent(datetime PreEventTime,datetime EventTime) { if(PreEventTime<=TimeTradeServer()&&EventTime>TimeTradeServer()) { return true; } return false; }
A função abaixo retornará o MqlDateTime para o horário atual com modificação na hora e no minuto.
//-- Return MqlDateTime for current date time with custom hour and minute MqlDateTime Today(int Hour,int Minute);
//+------------------------------------------------------------------+ //|Return MqlDateTime for current date time with custom hour and | //|minute | //+------------------------------------------------------------------+ MqlDateTime CTimeManagement::Today(int Hour,int Minute) { TimeTradeServer(today); today.hour=Hour; today.min=Minute; return today; }
A função abaixo retornará o MqlDateTime para o horário atual com modificação na hora, minuto e segundo.
//-- Return MqlDateTime for current date time with custom hour, minute and second MqlDateTime Today(int Hour,int Minute,int Second);
//+------------------------------------------------------------------+ //|Return MqlDateTime for current date time with custom hour, minute | //|and second | //+------------------------------------------------------------------+ MqlDateTime CTimeManagement::Today(int Hour,int Minute,int Second) { TimeTradeServer(today); today.hour=Hour; today.min=Minute; today.sec=Second; return today; }
A função abaixo retornará verdadeiro se o dia atual for igual ao dia correspondente da semana, ou se a enumeração DayOfTheWeek for igual a AllDays.
//-- Check current day of the week bool isDayOfTheWeek(DayOfTheWeek Day);
//+------------------------------------------------------------------+ //|Check current day of the week | //+------------------------------------------------------------------+ bool CTimeManagement::isDayOfTheWeek(DayOfTheWeek Day) { switch(Day) { case Monday://Monday if(DayOfWeek(TimeTradeServer())==MONDAY) { return true; } break; case Tuesday://Tuesday if(DayOfWeek(TimeTradeServer())==TUESDAY) { return true; } break; case Wednesday://Wednesday if(DayOfWeek(TimeTradeServer())==WEDNESDAY) { return true; } break; case Thursday://Thursday if(DayOfWeek(TimeTradeServer())==THURSDAY) { return true; } break; case Friday://Friday if(DayOfWeek(TimeTradeServer())==FRIDAY) { return true; } break; case AllDays://All days return true; break; default://Unknown break; } return false; }
A função abaixo retornará o Dia da Semana para uma data específica.
//-- Return enumeration Day of week for a certain date ENUM_DAY_OF_WEEK DayOfWeek(datetime time);
//+------------------------------------------------------------------+ //|Return enumeration Day of week for a certain date | //+------------------------------------------------------------------+ ENUM_DAY_OF_WEEK CTimeManagement::DayOfWeek(datetime time) { return (ENUM_DAY_OF_WEEK)Time(time).day_of_week; }
Classe de Propriedades de Candle
Uma nova função foi adicionada a esta classe.
//+------------------------------------------------------------------+ //|CandleProperties class | //+------------------------------------------------------------------+ class CCandleProperties : public CChartProperties { private: CTimeManagement Time;//TimeManagement object CTimeVariables CTV;//Timevariables object public: double Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Open-Price double Close(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Close-Price double High(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle High-Price double Low(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Low-Price bool IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others bool NewCandle(int index,ENUM_TIMEFRAMES period=PERIOD_CURRENT,string SYMBOL=NULL);//Check if a new candle is present };
A função NewCandle retornará verdadeiro quando um novo candle for formado e, em seguida, salvará o tempo de abertura do candle atual na classe Timevariables usando a função SetTime. O tempo salvo anteriormente será comparado com o tempo de abertura do candle atual para verificar se os tempos são diferentes. Se os tempos forem diferentes, então assumimos que um novo candle foi formado.
//+------------------------------------------------------------------+ //|Check if a new candle is present | //+------------------------------------------------------------------+ bool CCandleProperties::NewCandle(int index,ENUM_TIMEFRAMES period=PERIOD_CURRENT,string SYMBOL=NULL) { if(CTV.GetTime(index) == iTime(((SYMBOL==NULL)?Symbol():SYMBOL),period,0)) { return false;//Candle time are equal no new candles have formed } else { //--- Candle time has changed set the new time CTV.SetTime(index,iTime(((SYMBOL==NULL)?Symbol():SYMBOL),period,0)); return true; } }
Classe de Sessões
O propósito desta classe é lidar com os horários de sessões de negociação. Não vamos utilizar esses horários de sessões de negociação neste artigo, mas teremos uso para esta classe mais adiante. Esta classe herdará da classe TimeManagement, pois esta classe utilizará as funções do TimeManagement.
#include "Timemanagement.mqh" //+------------------------------------------------------------------+ //|Sessions Class | //+------------------------------------------------------------------+ class CSessions:CTimeManagement { public: CSessions(void) {} ~CSessions(void) {} //--- Check if trading Session has began bool isSessionStart(int offsethour=0,int offsetmin=0); //--- Check if trading Session has ended bool isSessionEnd(int offsethour=0,int offsetmin=45); //--- Get Session End datetime datetime SessionEnd(int offsethour=0,int offsetmin=45); };
A função abaixo verificará todas as Sessões de Negociação válidas para o Símbolo atual e o Dia da Semana. Uma vez que a sessão de negociação mais próxima seja encontrada, adicionaremos um deslocamento para este tempo, por exemplo. Se a sessão de negociação mais próxima for das 01:00-05:00, então nosso deslocamento de hora será 1 e o deslocamento de minuto será 0. Nossa sessão de negociação começará às 02:00-05:00. O objetivo de saber o horário de início da sessão é evitar grandes spreads que geralmente ocorrem no início da sessão de negociação. Se nossa sessão de negociação estiver ativa, a função retornará verdadeiro.
//+------------------------------------------------------------------+ //|Check if trading Session has started | //+------------------------------------------------------------------+ bool CSessions::isSessionStart(int offsethour=0,int offsetmin=0) { //--- Declarations datetime datefrom,dateto,DateFrom[],DateTo[]; //--- Find all session times for(int i=0; i<10; i++) { //--- Get the session dates for the current symbol and Day of week if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto)) { //--- Check if the end date's hour is at midnight if(ReturnHour(dateto)==00||ReturnHour(dateto)==24) { //--- Adjust the date to one minute before midnight dateto = Time(TimeTradeServer(),23,59); } //--- Re-adjust DateFrom Array size ArrayResize(DateFrom,int(ArraySize(DateFrom))+1,int(ArraySize(DateFrom))+2); //--- Assign the last array index datefrom value DateFrom[int(ArraySize(DateFrom))-1] = datefrom; //--- Re-adjust DateTo Array size ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2); //--- Assign the last array index dateto value DateTo[int(ArraySize(DateTo))-1] = dateto; } } //--- Check if there are session times if(DateFrom.Size()>0) { /* Adjust DateFrom index zero date as the first index date will be the earliest date from the whole array, we add the offset to this date only*/ DateFrom[0] = TimePlusOffset(DateFrom[0],MinutesS(startoffsetmin)); DateFrom[0] = TimePlusOffset(DateFrom[0],HoursS(startoffsethour)); //--- Iterate through the whole array for(uint i=0; i<DateFrom.Size(); i++) { //--- Check if the current time is within the trading session if(TimeIsInRange(DateFrom[i],DateTo[i])) { return true; } } } else { //--- If there are no trading session times return true; } return false; }
A função abaixo retornará verdadeiro se a sessão tiver terminado. Em alguns corretores, uma hora antes do fim da sessão de negociação, os spreads são enormes, então essa função pode nos ajudar a evitar negociações nesses horários.
//+------------------------------------------------------------------+ //|Check if trading Session has ended | //+------------------------------------------------------------------+ bool CSessions::isSessionEnd(int offsethour=0,int offsetmin=45) { //--- Declarations datetime datefrom,dateto,DateTo[],lastdate=0,sessionend; //--- Find all session times for(int i=0; i<10; i++) { //--- Get the session dates for the current symbol and Day of week if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto)) { //--- Check if the end date's hour is at midnight if(ReturnHour(dateto)==00||ReturnHour(dateto)==24) { //--- Adjust the date to one minute before midnight dateto = Time(TimeTradeServer(),23,59); } //--- Re-adjust DateTo Array size ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2); //--- Assign the last array index dateto value DateTo[int(ArraySize(DateTo))-1] = dateto; } } //--- Check if there are session times if(DateTo.Size()>0) { //--- Assign lastdate a default value lastdate = DateTo[0]; //--- Iterate through the whole array for(uint i=0; i<DateTo.Size(); i++) { //--- Check for the latest date in the array if(DateTo[i]>lastdate) { lastdate = DateTo[i]; } } } else { //--- If there are no trading session times return false; } /* get the current time and modify the hour and minute time to the lastdate variable and assign the new datetime to sessionend variable*/ sessionend = Today(ReturnHour(lastdate),ReturnMinute(lastdate)); //--- Re-adjust the sessionend dates with the minute and hour offsets sessionend = TimeMinusOffset(sessionend,MinutesS(offsetmin)); sessionend = TimeMinusOffset(sessionend,HoursS(offsethour)); //--- Check if sessionend date is more than the current time if(TimeTradeServer()<sessionend) { return false; } return true; }
A função abaixo retornará a data de término da sessão de negociação para o dia atual. Existem algumas limitações nos horários das sessões de negociação no MQL5. Percebi que durante um feriado, alguns símbolos podem fechar muito mais cedo do que o horário da sessão de negociação indicaria, então isso é algo a se considerar.
//+------------------------------------------------------------------+ //|Get Session End datetime | //+------------------------------------------------------------------+ datetime CSessions::SessionEnd(int offsethour=0,int offsetmin=45) { //--- Declarations datetime datefrom,dateto,DateTo[],lastdate=0,sessionend; //--- Find all session times for(int i=0; i<10; i++) { //--- Get the session dates for the current symbol and Day of week if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto)) { //--- Check if the end date's hour is at midnight if(CTV.ReturnHour(dateto)==00||CTV.ReturnHour(dateto)==24) { //--- Adjust the date to one minute before midnight dateto = Time(TimeTradeServer(),23,59); } //--- Re-adjust DateTo Array size ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2); //--- Assign the last array index dateto value DateTo[int(ArraySize(DateTo))-1] = dateto; } } //--- Check if there are session times if(DateTo.Size()>0) { //--- Assign lastdate a default value lastdate = DateTo[0]; //--- Iterate through the whole array for(uint i=0; i<DateTo.Size(); i++) { //--- Check for the latest date in the array if(DateTo[i]>lastdate) { lastdate = DateTo[i]; } } } else { //--- If there are no trading session times return 0; } /* get the current time and modify the hour and minute time to the lastdate variable and assign the new datetime to sessionend variable*/ sessionend = Today(ReturnHour(lastdate),ReturnMinute(lastdate)); //--- Re-adjust the sessionend dates with the minute and hour offsets sessionend = TimeMinusOffset(sessionend,MinutesS(offsetmin)); sessionend = TimeMinusOffset(sessionend,HoursS(offsethour)); //--- return sessionend date return sessionend; }
Classe de Notícias
Esta classe é a mais crucial de todo o projeto e a maior, abrangendo mais de 1000 linhas de código apenas. Na parte 2, fizemos grandes melhorias nesta classe e no código que interage com o banco de dados do calendário na pasta comum. Neste artigo, vamos criar outro banco de dados, mas desta vez, o banco de dados será na memória.
Benefícios dos Bancos de Dados na Memória em comparação ao Armazenamento
- Velocidade: Bancos de dados na memória armazenam dados diretamente na RAM, levando a operações de leitura e gravação significativamente mais rápidas. Isso é especialmente benéfico para aplicações que exigem processamento e análise de dados em tempo real. Como a RAM é muito mais rápida do que o armazenamento em disco, acessar dados em um banco de dados na memória é mais rápido. Isso reduz o tempo de resposta e melhora o desempenho geral.
- Desempenho: A redução da latência e o acesso mais rápido aos dados se traduzem em maior taxa de transferência, o que significa que o banco de dados pode lidar com mais transações por segundo. Bancos de dados na memória podem processar grandes volumes de dados de maneira mais eficiente, tornando-os adequados para aplicativos de big data, análises e outras tarefas intensivas de computação.
Ainda usaremos nosso banco de dados no armazenamento, vamos coletar os dados do banco de dados no armazenamento e transferir esses dados para o nosso novo banco de dados na memória para um desempenho equilibrado durante os back-tests, pois usar apenas o banco de dados no armazenamento pode afetar drasticamente dependendo das especificações do seu computador.
Começaremos com as declarações fora da classe para uso na entrada do especialista. A variável inteira DBMemoryConnection manterá o identificador de conexão inteiro para o nosso banco de dados na memória. A enumeração Calendar_Importance será usada para selecionar diferentes importâncias de eventos no parâmetro de entrada do especialista. A enumeração Event_Sector será usada para selecionar diferentes setores de eventos no parâmetro de entrada do especialista. A enumeração Event_Frequency será usada para selecionar diferentes frequências de eventos para o parâmetro de entrada do especialista. A enumeração Event_Type será usada para selecionar diferentes tipos de eventos para o parâmetro de entrada do especialista. A enumeração Event_Currency será usada para selecionar diferentes opções de moeda de evento no parâmetro de entrada do especialista. A variável da estrutura UpcomingNews Calendar armazenará os detalhes do próximo evento econômico para fácil acesso em outras classes/arquivos. Nós a declaramos fora da classe de notícias.
int DBMemoryConnection;//In memory database handle //--- Enumeration for Calendar Importance enum Calendar_Importance { Calendar_Importance_None,//NONE Calendar_Importance_Low,//LOW Calendar_Importance_Moderate,//MODERATE Calendar_Importance_High,//HIGH Calendar_Importance_All//ALL } myImportance; //--- Enumeration for Calendar Sector enum Event_Sector { Event_Sector_None,//NONE Event_Sector_Market,//MARKET Event_Sector_Gdp,//GDP Event_Sector_Jobs,//JOBS Event_Sector_Prices,//PRICES Event_Sector_Money,//MONEY Event_Sector_Trade,//TRADE Event_Sector_Government,//GOVERNMENT Event_Sector_Business,//BUSINESS Event_Sector_Consumer,//CONSUMER Event_Sector_Housing,//HOUSING Event_Sector_Taxes,//TAXES Event_Sector_Holidays,//HOLIDAYS Event_Sector_ALL//ALL } mySector; //--- Enumeration for Calendar Event Frequency enum Event_Frequency { Event_Frequency_None,//NONE Event_Frequency_Week,//WEEK Event_Frequency_Month,//MONTH Event_Frequency_Quarter,//QUARTER Event_Frequency_Year,//YEAR Event_Frequency_Day,//DAY Event_Frequency_ALL//ALL } myFrequency; //--- Enumeration for Calendar Event type enum Event_Type { Event_Type_Event,//EVENT Event_Type_Indicator,//INDICATOR Event_Type_Holiday,//HOLIDAY Event_Type_All//ALL } myType; //--- Enumeration for Calendar Event Currency enum Event_Currency { Event_Currency_Symbol,//SYMBOL CURRENCIES Event_Currency_Margin,//SYMBOL MARGIN Event_Currency_Base,//SYMBOL BASE Event_Currency_Profit,//SYMBOL PROFIT Event_Currency_ALL,//ALL CURRENCIES Event_Currency_NZD_NZ,//NZD -> NZ Event_Currency_EUR_EU,//EUR -> EU Event_Currency_JPY_JP,//JPY -> JP Event_Currency_CAD_CA,//CAD -> CA Event_Currency_AUD_AU,//AUD -> AU Event_Currency_CNY_CN,//CNY -> CN Event_Currency_EUR_IT,//EUR -> IT Event_Currency_SGD_SG,//SGD -> SG Event_Currency_EUR_DE,//EUR -> DE Event_Currency_EUR_FR,//EUR -> FR Event_Currency_BRL_BR,//BRL -> BR Event_Currency_MXN_MX,//MXN -> MX Event_Currency_ZAR_ZA,//ZAR -> ZA Event_Currency_HKD_HK,//HKD -> HK Event_Currency_INR_IN,//INR -> IN Event_Currency_NOK_NO,//NOK -> NO Event_Currency_USD_US,//USD -> US Event_Currency_GBP_GB,//GBP -> GB Event_Currency_CHF_CH,//CHF -> CH Event_Currency_KRW_KR,//KRW -> KW Event_Currency_EUR_ES,//EUR -> ES Event_Currency_SEK_SE,//SEK -> SE Event_Currency_ALL_WW//ALL -> WW } myCurrency; //--- Structure variable to store Calendar next Event data Calendar UpcomingNews;
Funcionalidade adicional para a classe de notícias:
- Expansão para a Enumeração CalendarComponents: EventInfo_View foi adicionada para exibir os detalhes dos eventos no banco de dados de armazenamento do calendário, Currencies_View foi adicionada para exibir todas as moedas disponíveis pelo calendário econômico MQL5.
- A estrutura de Array CalendarContents foi aumentada de tamanho de 10 para 12 para acomodar as duas novas visualizações EventInfo_View e Currencies_View.
- Declaração da variável DBMemory do tipo estrutura MQL5CalendarContents para armazenar as propriedades do banco de dados.
- Declaração da estrutura CalendarData e variáveis para armazenar todos os dados do banco de dados de calendário na pasta comum.
- Declaração da função GetCalendar que solicitará todos os dados filtrados do banco de dados de calendário na pasta comum e armazenará esses dados na estrutura de array CalendarData. Esses dados serão inseridos em nosso novo banco de dados de calendário na memória assim que ele for criado.
- Declaração da função GetAutoDST para recuperar a enumeração DST_type da tabela AutoDST no banco de dados de calendário na pasta comum.
- Declaração da função Request_Importance para recuperar a solicitação de string para a importância do evento com base na enumeração Calendar_Importance.
- Declaração da função Request_Frequency para recuperar a solicitação de string para a frequência do evento com base na enumeração Event_Frequency.
- Declaração da função Request_Sector para recuperar a solicitação de string para o setor do evento com base na enumeração Event_Sector.
- Declaração da função Request_Type para recuperar a solicitação de string para o tipo de evento com base na enumeração Event_Type.
- Declaração da função Request_Currency para recuperar a solicitação de string para a moeda do evento com base na enumeração Event_Currency.
- Declaração da função EconomicDetailsMemory que preencherá a estrutura de array NewsTime Calendar com os eventos para uma data específica.
- Declaração da função CreateEconomicDatabaseMemory que criará o banco de dados de calendário na memória.
- Declaração da função EconomicNextEvent que atualizará a variável da estrutura UpcomingNews com os dados do próximo evento.
- Declaração da função GetImpact que recuperará os dados de Impacto do Próximo Evento.
- Declaração da função IMPORTANCE que converterá a string de Importância na Enumeração de Importância do Evento no Calendário.
- Declaração da função IMPORTANCE que converterá a Enumeração Calendar_Importance na Enumeração de Importância do Evento no Calendário.
- Declaração da função GetImportance que converterá a Enumeração de Importância do Evento no Calendário em uma classificação de importância em string.
- Declaração da função GetImportance_color que recuperará a cor para cada Enumeração de Importância do Evento no Calendário.
- Declaração da função SECTOR que converterá a Enumeração Event_Sector na Enumeração de Setor do Evento no Calendário.
- Declaração da função FREQUENCY que converterá a Enumeração Event_Frequency na Enumeração de Frequência do Evento no Calendário.
- Declaração da função TYPE que converterá a Enumeração Event_Type na Enumeração de Tipo de Evento no Calendário.
//+------------------------------------------------------------------+ //|News class | //+------------------------------------------------------------------+ class CNews : private CCandleProperties { //Private Declarations Only accessable by this class/header file private: //-- To keep track of what is in our database enum CalendarComponents { AutoDST_Table,//AutoDST Table CalendarAU_View,//View for DST_AU CalendarNONE_View,//View for DST_NONE CalendarUK_View,//View for DST_UK CalendarUS_View,//View for DST_US EventInfo_View,//View for Event Information Currencies_View,//View for Currencies Record_Table,// Record Table TimeSchedule_Table,//TimeSchedule Table MQL5Calendar_Table,//MQL5Calendar Table AutoDST_Trigger,//Table Trigger for AutoDST Record_Trigger//Table Trigger for Record }; //-- structure to retrieve all the objects in the database struct SQLiteMaster { string type;//will store object's type string name;//will store object's name string tbl_name;//will store table name int rootpage;//will store rootpage string sql;//Will store the sql create statement } DBContents[];//Array of type SQLiteMaster //-- MQL5CalendarContents inherits from SQLiteMaster structure struct MQL5CalendarContents:SQLiteMaster { CalendarComponents Content; string insert;//Will store the sql insert statement } CalendarContents[12],DBMemory;//Array to Store objects in our database CTimeManagement CTime;//TimeManagement Object declaration CDaylightSavings_UK Savings_UK;//DaylightSavings Object for the UK and EU CDaylightSavings_US Savings_US;//DaylightSavings Object for the US CDaylightSavings_AU Savings_AU;//DaylightSavings Object for the AU bool AutoDetectDST(DST_type &dstType);//Function will determine Broker DST DST_type DSTType;//variable of DST_type enumeration declared in the CommonVariables class/header file bool InsertIntoTables(int db,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table void CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table bool CreateCalendarTable(int db,bool &tableExists);//Function for creating a table in a database bool CreateTimeTable(int db,bool &tableExists);//Function for creating a table in a database void CreateCalendarViews(int db);//Function for creating views in a database void CreateRecordTable(int db);//Creates a table to store the record of when last the Calendar database was updated/created string DropRequest;//Variable for dropping tables in the database //-- Function for retrieving the MQL5CalendarContents structure for the enumartion type CalendarComponents MQL5CalendarContents CalendarStruct(CalendarComponents Content) { MQL5CalendarContents Calendar; for(uint i=0;i<CalendarContents.Size();i++) { if(CalendarContents[i].Content==Content) { return CalendarContents[i]; } } return Calendar; } //--- To Store Calendar DB Data struct CalendarData { int EventId;//Event Id string Country;//Event Country string EventName;//Event Name string EventType;//Event Type string EventImportance;//Event Importance string EventCurrency;//Event Currency string EventCode;//Event Code string EventSector;//Event Sector string EventForecast;//Event Forecast Value string EventPreval;//Event Previous Value string EventImpact;//Event Impact string EventFrequency;//Event Frequency string DST_UK;//DST UK string DST_US;//DST US string DST_AU;//DST AU string DST_NONE;//DST NONE } DB_Data[],DB_Cal;//Structure variables //--- Will Retrieve all relevant Calendar data for DB in Memory from DB in Storage void GetCalendar(CalendarData &Data[]) { //--- Open calendar DB in Storage int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if the database was able to be opened { //if opening the database failed if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if the database Calendar exists in the common folder { return;//Returns true when the database was failed to be opened and the file doesn't exist in the common folder } } //--- Get filtered calendar DB data string SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency," "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency," "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ " "Inner Join %s TS on TS.ID=MQ.ID " "Where %s and %s and %s and %s and %s;", CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name, Request_Importance(myImportance),Request_Frequency(myFrequency), Request_Sector(mySector),Request_Type(myType),Request_Currency(myCurrency)); //--- Process Sql request int Request = DatabasePrepare(db,SqlRequest); if(Request==INVALID_HANDLE) { //--- Print details if request failed. Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); Print("SQL"); Print(SqlRequest); } else { //--- Clear data from whole array ArrayRemove(Data,0,WHOLE_ARRAY); //--- create structure variable to get data from request CalendarData data; //Assigning values from the sql query into Data structure array for(int i=0; DatabaseReadBind(Request,data); i++) { //--- Resize Data Array ArrayResize(Data,i+1,i+2); Data[i] = data; } } DatabaseFinalize(Request);//Finalize request //--- Close Calendar database DatabaseClose(db); } //--- Retrieve the AutoDST enumeration data from calendar DB in storage DST_type GetAutoDST() { string Sch_Dst; //--- open the database 'Calendar' in the common folder int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if 'Calendar' failed to be opened { if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if 'Calendar' database exists { Print("Could not find Database!"); return DST_NONE;//return default value when failed. } } //--- Sql query to get AutoDST value string request_text="SELECT DST FROM 'AutoDST'"; //--- Process sql request int request=DatabasePrepare(db,request_text); if(request==INVALID_HANDLE) { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db);//Close Database return DST_NONE;//return default value when failed. } //--- Read Sql request output data if(DatabaseRead(request)) { //-- Store the first column data into string variable Sch_Dst if(!DatabaseColumnText(request,0,Sch_Dst)) { Print("DatabaseRead() failed with code ", GetLastError()); DatabaseFinalize(request);//Finalize request DatabaseClose(db);//Closes the database 'Calendar' return DST_NONE;//return default value when failed. } } DatabaseFinalize(request);//Finalize request DatabaseClose(db);//Closes the database 'Calendar' return (Sch_Dst=="DST_UK")?DST_UK:(Sch_Dst=="DST_US")?DST_US: (Sch_Dst=="DST_AU")?DST_AU:DST_NONE;//Returns the enumeration value for each corresponding string } //--- Retrieve Sql request string for calendar event Importance string Request_Importance(Calendar_Importance Importance) { //--- Constant request prefix string const string constant="MQ.EventImportance"; //--- switch statement for Calendar_Importance enumeration switch(Importance) { case Calendar_Importance_All://String Request for all event Importance return constant+"<>'"+EnumToString(myImportance)+"'"; break; default://String Request for any event Importance return constant+"='"+EnumToString(IMPORTANCE(myImportance))+"'"; break; } } //--- Retrieve Sql request string for calendar event Frequency string Request_Frequency(Event_Frequency Frequency) { //--- Constant request prefix string const string constant="MQ.EventFrequency"; //--- switch statement for Event_Frequency enumeration switch(Frequency) { case Event_Frequency_ALL://String Request for all event frequencies return constant+"<>'"+EnumToString(myFrequency)+"'"; break; default://String Request for any event frequency return constant+"='"+EnumToString(FREQUENCY(myFrequency))+"'"; break; } } //--- Retrieve Sql request string for calendar event Sector string Request_Sector(Event_Sector Sector) { //--- Constant request prefix string const string constant="MQ.EventSector"; //--- switch statement for Event_Sector enumeration switch(Sector) { case Event_Sector_ALL://String Request for all event sectors return constant+"<>'"+EnumToString(mySector)+"'"; break; default://String Request for any event sector return constant+"='"+EnumToString(SECTOR(mySector))+"'"; break; } } //--- Retrieve Sql request string for calendar event type string Request_Type(Event_Type Type) { //--- Constant request prefix string const string constant="MQ.EventType"; //--- switch statement for Event_Type enumeration switch(Type) { case Event_Type_All://String Request for all event types return constant+"<>'"+EnumToString(myType)+"'"; break; default://String request for any event type return constant+"='"+EnumToString(TYPE(myType))+"'"; break; } } //--- Retrieve Sql request string for calendar event Currency string Request_Currency(Event_Currency Currency) { //--- Constant request prefix string and request suffix const string constant_prefix="(MQ.EventCurrency",constant_suffix="')"; //--- switch statement for Event_Currency enumeration switch(Currency) { case Event_Currency_ALL://String Request for all currencies return constant_prefix+"<>'"+EnumToString(myCurrency)+constant_suffix; break; case Event_Currency_Symbol://String Request for all symbol currencies return constant_prefix+"='"+CSymbol.CurrencyBase()+"' or MQ.EventCurrency='"+ CSymbol.CurrencyMargin()+"' or MQ.EventCurrency='"+CSymbol.CurrencyProfit()+constant_suffix; break; case Event_Currency_Margin://String Request for Margin currency return constant_prefix+"='"+CSymbol.CurrencyMargin()+constant_suffix; break; case Event_Currency_Base://String Request for Base currency return constant_prefix+"='"+CSymbol.CurrencyBase()+constant_suffix; break; case Event_Currency_Profit://String Request for Profit currency return constant_prefix+"='"+CSymbol.CurrencyProfit()+constant_suffix; break; case Event_Currency_NZD_NZ://String Request for NZD currency return constant_prefix+"='NZD' and MQ.EventCode='NZ"+constant_suffix; break; case Event_Currency_EUR_EU://String Request for EUR currency and EU code return constant_prefix+"='EUR' and MQ.EventCode='EU"+constant_suffix; break; case Event_Currency_JPY_JP://String Request for JPY currency return constant_prefix+"='JPY' and MQ.EventCode='JP"+constant_suffix; break; case Event_Currency_CAD_CA://String Request for CAD currency return constant_prefix+"='CAD' and MQ.EventCode='CA"+constant_suffix; break; case Event_Currency_AUD_AU://String Request for AUD currency return constant_prefix+"='AUD' and MQ.EventCode='AU"+constant_suffix; break; case Event_Currency_CNY_CN://String Request for CNY currency return constant_prefix+"='CNY' and MQ.EventCode='CN"+constant_suffix; break; case Event_Currency_EUR_IT://String Request for EUR currency and IT code return constant_prefix+"='EUR' and MQ.EventCode='IT"+constant_suffix; break; case Event_Currency_SGD_SG://String Request for SGD currency return constant_prefix+"='SGD' and MQ.EventCode='SG"+constant_suffix; break; case Event_Currency_EUR_DE://String Request for EUR currency and DE code return constant_prefix+"='EUR' and MQ.EventCode='DE"+constant_suffix; break; case Event_Currency_EUR_FR://String Request for EUR currency and FR code return constant_prefix+"='EUR' and MQ.EventCode='FR"+constant_suffix; break; case Event_Currency_BRL_BR://String Request for BRL currency return constant_prefix+"='BRL' and MQ.EventCode='BR"+constant_suffix; break; case Event_Currency_MXN_MX://String Request for MXN currency return constant_prefix+"='MXN' and MQ.EventCode='MX"+constant_suffix; break; case Event_Currency_ZAR_ZA://String Request for ZAR currency return constant_prefix+"='ZAR' and MQ.EventCode='ZA"+constant_suffix; break; case Event_Currency_HKD_HK://String Request for HKD currency return constant_prefix+"='HKD' and MQ.EventCode='HK"+constant_suffix; break; case Event_Currency_INR_IN://String Request for INR currency return constant_prefix+"='INR' and MQ.EventCode='IN"+constant_suffix; break; case Event_Currency_NOK_NO://String Request for NOK currency return constant_prefix+"='NOK' and MQ.EventCode='NO"+constant_suffix; break; case Event_Currency_USD_US://String Request for USD currency return constant_prefix+"='USD' and MQ.EventCode='US"+constant_suffix; break; case Event_Currency_GBP_GB://String Request for GBP currency return constant_prefix+"='GBP' and MQ.EventCode='GB"+constant_suffix; break; case Event_Currency_CHF_CH://String Request for CHF currency return constant_prefix+"='CHF' and MQ.EventCode='CH"+constant_suffix; break; case Event_Currency_KRW_KR://String Request for KRW currency return constant_prefix+"='KRW' and MQ.EventCode='KR"+constant_suffix; break; case Event_Currency_EUR_ES://String Request for EUR currency and ES code return constant_prefix+"='EUR' and MQ.EventCode='ES"+constant_suffix; break; case Event_Currency_SEK_SE://String Request for SEK currency return constant_prefix+"='SEK' and MQ.EventCode='SE"+constant_suffix; break; case Event_Currency_ALL_WW://String Request for ALL currency return constant_prefix+"='ALL' and MQ.EventCode='WW"+constant_suffix; break; default://String Request for no currencies return constant_prefix+"='"+constant_suffix; break; } } //Public declarations accessable via a class's Object public: CNews(void);//Constructor ~CNews(void);//Destructor void CreateEconomicDatabase();//Creates the Calendar database for a specific Broker datetime GetLatestNewsDate();//Gets the latest/newest date in the Calendar database void EconomicDetails(Calendar &NewsTime[],datetime date_from=0,datetime date_to=0);//Gets values from the MQL5 economic Calendar void EconomicDetailsMemory(Calendar &NewsTime[],datetime date);//Gets values from the MQL5 DB Calendar in Memory void CreateEconomicDatabaseMemory();//Create calendar database in memory void EconomicNextEvent(datetime date=0);//Will update UpcomingNews structure variable with the next event data bool UpdateRecords();//Checks if the main Calendar database needs an update or not ENUM_CALENDAR_EVENT_IMPACT GetImpact();//Will retrieve Upcoming Event Impact data //--- Convert Importance string into Calendar Event Importance Enumeration ENUM_CALENDAR_EVENT_IMPORTANCE IMPORTANCE(string Importance) { //--- Calendar Importance is High if(Importance==EnumToString(CALENDAR_IMPORTANCE_HIGH)) { return CALENDAR_IMPORTANCE_HIGH; } else //--- Calendar Importance is Moderate if(Importance==EnumToString(CALENDAR_IMPORTANCE_MODERATE)) { return CALENDAR_IMPORTANCE_MODERATE; } else //--- Calendar Importance is Low if(Importance==EnumToString(CALENDAR_IMPORTANCE_LOW)) { return CALENDAR_IMPORTANCE_LOW; } else //--- Calendar Importance is None { return CALENDAR_IMPORTANCE_NONE; } } //--- Convert Calendar_Importance Enumeration into Calendar Event Importance Enumeration ENUM_CALENDAR_EVENT_IMPORTANCE IMPORTANCE(Calendar_Importance Importance) { //--- switch statement for Calendar_Importance enumeration switch(Importance) { case Calendar_Importance_None://None return CALENDAR_IMPORTANCE_NONE; break; case Calendar_Importance_Low://Low return CALENDAR_IMPORTANCE_LOW; break; case Calendar_Importance_Moderate://Moderate return CALENDAR_IMPORTANCE_MODERATE; break; case Calendar_Importance_High://High return CALENDAR_IMPORTANCE_HIGH; break; default://None return CALENDAR_IMPORTANCE_NONE; break; } } //--- Convert Calendar Event Importance Enumeration into string Importance Rating string GetImportance(ENUM_CALENDAR_EVENT_IMPORTANCE Importance) { //--- switch statement for ENUM_CALENDAR_EVENT_IMPORTANCE enumeration switch(Importance) { case CALENDAR_IMPORTANCE_HIGH://High return "HIGH"; break; case CALENDAR_IMPORTANCE_MODERATE://Moderate return "MODERATE"; break; case CALENDAR_IMPORTANCE_LOW://Low return "LOW"; break; default://None return "NONE"; break; } } //--- Retrieve color for each Calendar Event Importance Enumeration color GetImportance_color(ENUM_CALENDAR_EVENT_IMPORTANCE Importance) { //--- switch statement for ENUM_CALENDAR_EVENT_IMPORTANCE enumeration switch(Importance) { case CALENDAR_IMPORTANCE_HIGH://High return clrRed; break; case CALENDAR_IMPORTANCE_MODERATE://Moderate return clrOrange; break; case CALENDAR_IMPORTANCE_LOW://Low return (isLightMode)?clrBlue:clrLightBlue; break; default://None return (isLightMode)?clrBlack:clrWheat; break; } } //--- Convert Event_Sector Enumeration into Calendar Event Sector Enumeration ENUM_CALENDAR_EVENT_SECTOR SECTOR(Event_Sector Sector) { //--- switch statement for Event_Sector enumeration switch(Sector) { case Event_Sector_None://NONE return CALENDAR_SECTOR_NONE; break; case Event_Sector_Market://MARKET return CALENDAR_SECTOR_MARKET; break; case Event_Sector_Gdp://GDP return CALENDAR_SECTOR_GDP; break; case Event_Sector_Jobs://JOBS return CALENDAR_SECTOR_JOBS; break; case Event_Sector_Prices://PRICES return CALENDAR_SECTOR_PRICES; break; case Event_Sector_Money://MONEY return CALENDAR_SECTOR_MONEY; break; case Event_Sector_Trade://TRADE return CALENDAR_SECTOR_TRADE; break; case Event_Sector_Government://GOVERNMENT return CALENDAR_SECTOR_GOVERNMENT; break; case Event_Sector_Business://BUSINESS return CALENDAR_SECTOR_BUSINESS; break; case Event_Sector_Consumer://CONSUMER return CALENDAR_SECTOR_CONSUMER; break; case Event_Sector_Housing://HOUSING return CALENDAR_SECTOR_HOUSING; break; case Event_Sector_Taxes://TAXES return CALENDAR_SECTOR_TAXES; break; case Event_Sector_Holidays://HOLIDAYS return CALENDAR_SECTOR_HOLIDAYS; break; default://Unknown return CALENDAR_SECTOR_NONE; break; } } //--- Convert Event_Frequency Enumeration into Calendar Event Frequency Enumeration ENUM_CALENDAR_EVENT_FREQUENCY FREQUENCY(Event_Frequency Frequency) { //--- switch statement for Event_Frequency enumeration switch(Frequency) { case Event_Frequency_None://NONE return CALENDAR_FREQUENCY_NONE; break; case Event_Frequency_Day://DAY return CALENDAR_FREQUENCY_DAY; break; case Event_Frequency_Week://WEEK return CALENDAR_FREQUENCY_WEEK; break; case Event_Frequency_Month://MONTH return CALENDAR_FREQUENCY_MONTH; break; case Event_Frequency_Quarter://QUARTER return CALENDAR_FREQUENCY_QUARTER; break; case Event_Frequency_Year://YEAR return CALENDAR_FREQUENCY_YEAR; break; default://Unknown return CALENDAR_FREQUENCY_NONE; break; } } //--- Convert Event_Type Enumeration into Calendar Event Type Enumeration ENUM_CALENDAR_EVENT_TYPE TYPE(Event_Type Type) { //--- switch statement for Event_Type enumeration switch(Type) { case Event_Type_Event://EVENT return CALENDAR_TYPE_EVENT; break; case Event_Type_Indicator://INDICATOR return CALENDAR_TYPE_INDICATOR; break; case Event_Type_Holiday://HOLIDAY return CALENDAR_TYPE_HOLIDAY; break; default://Unknown return CALENDAR_TYPE_EVENT; break; } } };
Primeiro, passaremos pela declaração SQL na função GetCalendar que solicitará todos os dados do banco de dados de calendário na pasta comum para o nosso banco de dados de calendário na memória. Nesta solicitação, selecionamos todas as colunas na tabela MQL5Calendar e na tabela TimeSchedule. Fazemos o join das tabelas onde seus IDs são iguais. Em seguida, filtramos os dados com base nas enumerações selecionadas pelo trader/usuário nos parâmetros de entrada do especialista para as configurações de notícias.
//--- Get filtered calendar DB data string SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency," "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency," "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ " "Inner Join %s TS on TS.ID=MQ.ID " "Where %s and %s and %s and %s and %s;", CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name, Request_Importance(myImportance),Request_Frequency(myFrequency), Request_Sector(mySector),Request_Type(myType),Request_Currency(myCurrency));
Vamos dar uma olhada na solicitação SQL para a seguinte configuração de Configurações de Notícias no símbolo EURUSD.
Como mostrado abaixo, podemos ver que, quando selecionamos tudo para a importância do calendário, de propósito não convertemos nossa variável de Enumeração Calendar_Importance myImportance, porque não existe nenhuma importância de evento com o valor 'Calendar_Importance_All', então podemos facilmente selecionar todos os eventos onde a EventImportance não é igual a 'Calendar_Importance_All'. O mesmo pode ser dito para todos os parâmetros de entrada de Configurações de Notícias que são selecionados para TODOS.
case Calendar_Importance_All://String Request for all event Importance return constant+"<>'"+EnumToString(myImportance)+"'";
Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency,MQ.EventCode,MQ.EventSector, MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency,TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from MQL5Calendar MQ Inner Join TimeSchedule TS on TS.ID=MQ.ID Where MQ.EventImportance<>'Calendar_Importance_All' and MQ.EventFrequency<>'Event_Frequency_ALL' and MQ.EventSector<>'Event_Sector_ALL' and MQ.EventType<>'Event_Type_All' and (MQ.EventCurrency='EUR' or MQ.EventCurrency='EUR' or MQ.EventCurrency='USD');
Vamos dar mais uma olhada em uma outra solicitação SQL da função GetCalendar para a seguinte configuração de News Settings no símbolo EURUSD.
Como mostrado abaixo, quando selecionamos qualquer outra opção além de "all" para a importância do calendário, vamos converter nossa variável de enumeração Calendar_Importance myImportance no tipo de enumeração ENUM_CALENDAR_EVENT_IMPORTANCE, para que a string possa corresponder àquela armazenada na tabela MQL5Calendar e assim obter corretamente a importância do evento de um certo tipo.
default://String Request for any event Importance return constant+"='"+EnumToString(IMPORTANCE(myImportance))+"'";
Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency,MQ.EventCode,MQ.EventSector,MQ.EventForecast, MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency,TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from MQL5Calendar MQ Inner Join TimeSchedule TS on TS.ID=MQ.ID Where MQ.EventImportance='CALENDAR_IMPORTANCE_HIGH' and MQ.EventFrequency='CALENDAR_FREQUENCY_MONTH' and MQ.EventSector='CALENDAR_SECTOR_JOBS' and MQ.EventType='CALENDAR_TYPE_INDICATOR' and (MQ.EventCurrency<>'Event_Currency_ALL');
No construtor da classe de notícias, precisamos inicializar os índices do array para as novas visualizações do nosso banco de dados de calendário na pasta comum. Para a visualização de Event Info, é assim que inicializamos o índice do array abaixo.
//--- initializing properties for the EventInfo view CalendarContents[5].Content = EventInfo_View; CalendarContents[5].name = "Event Info"; CalendarContents[5].sql = "CREATE VIEW IF NOT EXISTS 'Event Info' " "AS SELECT EVENTID as 'ID',COUNTRY as 'Country',EVENTNAME as 'Name'," "REPLACE(EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',REPLACE(EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector'," "REPLACE(EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',EVENTCURRENCY as 'Currency' " "FROM MQL5Calendar GROUP BY \"Name\" ORDER BY \"Country\" Asc," "CASE \"Importance\" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,\"Sector\" Desc;"; CalendarContents[5].tbl_name = "Event Info"; CalendarContents[5].type = "view";
Vamos passar pela instrução SQL para criar a visualização 'Event Info'. Primeiramente, criamos a visualização apenas se ela ainda não existir, depois selecionamos as colunas 'EVENTID' e renomeamos para 'ID', 'COUNTRY' e renomeamos para 'Country', 'EVENTNAME' e renomeamos para 'Name', 'EVENTTYPE' substituímos o texto 'CALENDAR_TYPE_' por uma string vazia e renomeamos a coluna para 'Type', 'EVENTSECTOR' substituímos o texto 'CALENDAR_SECTOR_' por uma string vazia e renomeamos a coluna para 'Sector', 'EVENTIMPORTANCE' substituímos o texto 'CALENDAR_IMPORTANCE_' por uma string vazia e renomeamos a coluna para 'Importance', 'EVENTCURRENCY' e renomeamos para 'Currency' da tabela MQL5Calendar. Em seguida, agrupamos a consulta pelo 'EVENTNAME', que agora é 'Name', para que os eventos com o mesmo nome de evento não sejam exibidos várias vezes na visualização. Em seguida, damos uma sequência à consulta, ordenamos primeiro o resultado por 'Country' em ordem crescente para que o país com a primeira letra do alfabeto, como a Austrália, seja mostrado primeiro, depois ordenamos o resultado por 'EVENTIMPORTANCE', que agora é chamado de 'Importance', para que os eventos com maior importância sejam exibidos. Para fazer isso, temos que dar uma classificação aos valores da string/texto de importância. Então, neste caso, quando a importância for 'HIGH', ela recebe a primeira prioridade, depois 'MODERATE' recebe a segunda prioridade, 'LOW' recebe a terceira prioridade e, finalmente, qualquer outro valor recebe a última prioridade. Além disso, ordenamos o resultado da consulta por 'EVENTSECTOR', que agora é chamado de 'Sector', em ordem decrescente. Um exemplo de visualização será mostrado abaixo.
CREATE VIEW IF NOT EXISTS 'Event Info' AS SELECT MQ.EVENTID as 'ID',MQ.COUNTRY as 'Country',MQ.EVENTNAME as 'Name',REPLACE(MQ.EVENTTYPE, 'CALENDAR_TYPE_','') as 'Type',REPLACE(MQ.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector',REPLACE(MQ.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',MQ.EVENTCURRENCY as 'Currency' FROM MQL5Calendar MQ INNER JOIN TimeSchedule TS on TS.ID=MQ.ID GROUP BY "Name" ORDER BY "Country" Asc,CASE "Importance" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,"Sector" Desc;
ID Country Name Type Sector Importance Currency 36030006 Australia RBA Governor Lowe Speech EVENT MONEY HIGH AUD 36030008 Australia RBA Interest Rate Decision INDICATOR MONEY HIGH AUD 36010029 Australia PPI q/q INDICATOR PRICES MODERATE AUD 36030014 Australia RBA Trimmed Mean CPI q/q INDICATOR PRICES MODERATE AUD 36030009 Australia RBA Weighted Median CPI q/q INDICATOR PRICES MODERATE AUD 36010031 Australia Wage Price Index q/q INDICATOR PRICES MODERATE AUD 36030026 Australia RBA Assistant Governor Boulton Speech EVENT MONEY MODERATE AUD 36030024 Australia RBA Assistant Governor Bullock Speech EVENT MONEY MODERATE AUD 36030025 Australia RBA Assistant Governor Ellis Speech EVENT MONEY MODERATE AUD 62 lines later... 76020002 Brazil BCB Interest Rate Decision INDICATOR MONEY HIGH BRL 76020004 Brazil BCB Inflation Report EVENT PRICES MODERATE BRL 76050001 Brazil FIPE CPI m/m INDICATOR PRICES MODERATE BRL 76010005 Brazil Mid-Month CPI m/m INDICATOR PRICES MODERATE BRL 76020001 Brazil BCB Focus Market Report EVENT MONEY MODERATE BRL 76020003 Brazil BCB MPC (Copom) Minutes EVENT MONEY MODERATE BRL 76020005 Brazil BCB National Monetary Council Meeting EVENT MONEY MODERATE BRL 76010009 Brazil Unemployment Rate 3-months INDICATOR JOBS MODERATE BRL 76020010 Brazil Nominal Budget Balance INDICATOR GOVERNMENT MODERATE BRL 76020011 Brazil Primary Budget balance INDICATOR GOVERNMENT MODERATE BRL 76010014 Brazil Services Volume m/m INDICATOR BUSINESS MODERATE BRL 98 lines later... 124040017 Canada BoC Governor Macklem Speech EVENT MONEY HIGH CAD 124040003 Canada BoC Governor Poloz Speech EVENT MONEY HIGH CAD 124040006 Canada BoC Interest Rate Decision INDICATOR MONEY HIGH CAD 124040009 Canada BoC Monetary Policy Report Press Conference EVENT MONEY HIGH CAD 124010011 Canada Employment Change INDICATOR JOBS HIGH CAD 124010021 Canada GDP m/m INDICATOR GDP HIGH CAD 124010008 Canada Core Retail Sales m/m INDICATOR CONSUMER HIGH CAD 124020001 Canada Ivey PMI INDICATOR BUSINESS HIGH CAD 124010024 Canada IPPI m/m INDICATOR PRICES MODERATE CAD 124010026 Canada RMPI m/m INDICATOR PRICES MODERATE CAD 124040001 Canada BoC Business Outlook Survey EVENT MONEY MODERATE CAD
Para nossa visualização de moedas, selecionamos o EventCurrency e o EventCode únicos/distintos da tabela MQL5Calendar.
//--- initializing properties for the Currencies view CalendarContents[6].Content = Currencies_View; CalendarContents[6].name = "Currencies"; CalendarContents[6].sql = "CREATE VIEW IF NOT EXISTS Currencies AS " "SELECT Distinct EventCurrency as 'Currency',EventCode as 'Code' FROM 'MQL5Calendar';"; CalendarContents[6].tbl_name = "Currencies"; CalendarContents[6].type = "view";
SELECT * FROM 'Currencies';
Currency Code NZD NZ EUR EU JPY JP CAD CA AUD AU CNY CN EUR IT SGD SG EUR DE EUR FR BRL BR MXN MX ZAR ZA HKD HK INR IN NOK NO USD US GBP GB CHF CH KRW KR EUR ES SEK SE ALL WW
Agora, inicializaremos as propriedades para nossa tabela MQL5Calendar, que estará em nosso banco de dados na memória. Essa tabela será uma grande tabela que, essencialmente, combina as tabelas em nosso banco de dados de armazenamento, essas tabelas são MQL5Calendar e TimeSchedule.
//-- initializing properties for the MQL5Calendar table for DB in System Memory DBMemory.Content = MQL5Calendar_Table; DBMemory.name = "MQL5Calendar"; DBMemory.sql = "CREATE TABLE IF NOT EXISTS MQL5Calendar(EVENTID INT NOT NULL,COUNTRY TEXT NOT NULL," "EVENTNAME TEXT NOT NULL,EVENTTYPE TEXT NOT NULL,EVENTIMPORTANCE TEXT NOT NULL," "EVENTCURRENCY TEXT NOT NULL,EVENTCODE TEXT NOT NULL,EVENTSECTOR TEXT NOT NULL," "EVENTFORECAST TEXT NOT NULL,EVENTPREVALUE TEXT NOT NULL,EVENTIMPACT TEXT NOT NULL," "EVENTFREQUENCY TEXT NOT NULL,DST_UK TEXT NOT NULL,DST_US TEXT NOT NULL," "DST_AU TEXT NOT NULL,DST_NONE TEXT NOT NULL)STRICT;"; DBMemory.tbl_name="MQL5Calendar"; DBMemory.type = "table"; DBMemory.insert = "INSERT INTO 'MQL5Calendar'(EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTCURRENCY,EVENTCODE," "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY,DST_UK,DST_US,DST_AU,DST_NONE) " "VALUES (%d,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', '%s', '%s');";
No nosso destruidor, fechamos a conexão com o banco de dados na memória, fechando a conexão com o banco de dados na memória, a tabela inteira é descartada. Então, só fechamos a conexão quando não precisarmos mais do banco de dados.
//+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CNews::~CNews(void) { if(FileIsExist(NEWS_TEXT_FILE,FILE_COMMON))//Check if the news database open text file exists { FileDelete(NEWS_TEXT_FILE,FILE_COMMON); } DatabaseClose(DBMemoryConnection);//Close DB in memory }
Anteriormente, em nossa função UpdateRecords, passamos por uma sequência para verificar se devemos atualizar o banco de dados de calendário no armazenamento. A sequência foi a seguinte:
- Verificamos se o banco de dados Calendar existe na pasta comum. Se o banco de dados não existir, realizamos uma atualização.
- Verificamos se todos os objetos do banco de dados existem no banco de dados e se suas instruções SQL são o que esperamos. Se não forem, realizamos uma atualização.
- Verificamos se a data na tabela Records é igual à data atual, caso contrário, realizamos uma atualização.
Para este artigo, adicionaremos mais uma etapa na sequência. O objetivo dessa etapa adicionada é verificar se os dados das notícias na visualização Calendar_NONE são precisos. Notei que, às vezes, os dados das notícias do calendário MQL5 podem mudar com o tempo e, se tivermos armazenado as notícias que não mudaram, precisamos ser capazes de verificar as inconsistências entre o que armazenamos e o que foi atualizado no calendário MQL5, se houver alguma alteração.
No código abaixo, recuperamos os dados das notícias do dia atual usando a função EconomicDetails e armazenamos esses dados no array TodayNews. Uma vez que os dados das notícias estão no array TodayNews, iteramos por cada evento de notícia no array e verificamos se há uma correspondência na nossa visualização Calendar_NONE. Se não encontrarmos uma correspondência, realizaremos uma atualização. Se todos os dados das notícias tiverem uma correspondência na visualização Calendar_NONE, não realizamos nenhuma atualização no banco de dados de armazenamento.
Calendar TodaysNews[]; datetime Today = CTime.Time(TimeTradeServer(),0,0,0); EconomicDetails(TodaysNews,Today,Today+CTime.DaysS()); for(uint i=0;i<TodaysNews.Size();i++) { request_text=StringFormat("SELECT ID FROM %s where Replace(Date,'.','-')=Replace('%s','.','-') and ID=%d;", CalendarStruct(CalendarNONE_View).name,TodaysNews[i].EventDate,TodaysNews[i].EventId); request=DatabasePrepare(db,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseFinalize(request); DatabaseClose(db); return perform_update; } //PrintFormat(request_text); if(!DatabaseRead(request))//Will be true if there are results from the sql query/request { DatabaseFinalize(request); DatabaseClose(db); return perform_update; } DatabaseFinalize(request); } DatabaseClose(db);//Closes the database perform_update=false; return perform_update;
O código abaixo será responsável por criar o banco de dados na memória. Primeiramente, abrimos a conexão com o banco de dados, depois descartamos a tabela MQL5Calendar se ela já existir, então criamos a tabela MQL5Calendar. Uma vez que a tabela esteja criada, obtemos todos os dados relevantes da função GetCalendar, depois inserimos todos os dados recuperados da função na nossa tabela MQL5Calendar no banco de dados na memória. Além disso, limpamos todo o array DB_Data e configuramos nosso horário de verão (DST) na variável MySchedule. Para negociações fora do Strategy Tester, o usuário/trader não poderá alterar manualmente o horário de verão (DST), isso é para evitar a configuração incorreta do horário de verão, pois a configuração do horário de verão é necessária apenas para o Strategy Tester.
//+------------------------------------------------------------------+ //|Create calendar database in memory | //+------------------------------------------------------------------+ void CNews::CreateEconomicDatabaseMemory() { //--- Open/create the database in memory DBMemoryConnection=DatabaseOpen(NEWS_DATABASE_MEMORY,DATABASE_OPEN_MEMORY); if(DBMemoryConnection==INVALID_HANDLE)//Checks if the database failed to open/create { Print("DB: ",NEWS_DATABASE_MEMORY, " open failed with code ", GetLastError()); return;//will terminate execution of the rest of the code below } //--- Drop the table if it already exists DatabaseExecute(DBMemoryConnection,StringFormat("Drop table IF EXISTS %s",DBMemory.name)); //--- Attempt to create the table if(!DatabaseExecute(DBMemoryConnection,DBMemory.sql)) { Print("DB: create the Calendar table failed with code ", GetLastError()); return; } //--- Check if the table exists if(DatabaseTableExists(DBMemoryConnection,DBMemory.tbl_name)) { //--- Get all news data and time from the database in storage GetCalendar(DB_Data); //--- Insert all the news data and times into the table for(uint i=0;i<DB_Data.Size();i++) { string request_text=StringFormat(DBMemory.insert,DB_Data[i].EventId,DB_Data[i].Country, DB_Data[i].EventName,DB_Data[i].EventType,DB_Data[i].EventImportance, DB_Data[i].EventCurrency,DB_Data[i].EventCode,DB_Data[i].EventSector, DB_Data[i].EventForecast,DB_Data[i].EventPreval,DB_Data[i].EventImpact, DB_Data[i].EventFrequency,DB_Data[i].DST_UK,DB_Data[i].DST_US, DB_Data[i].DST_AU,DB_Data[i].DST_NONE); if(!DatabaseExecute(DBMemoryConnection, request_text))//Will attempt to run this sql request/query { //--- failed to run sql request/query Print(GetLastError()); PrintFormat(request_text); return; } } } //--- Remove all data from the array ArrayRemove(DB_Data,0,WHOLE_ARRAY); //--- Assign the DST schedule MySchedule = (MQLInfoInteger(MQL_TESTER))?(MyDST==AutoDst_Selection)?GetAutoDST():MySchedule:DST_NONE; }
Ok, agora a função a seguir chamada EconomicDetailsMemory recupera todos os eventos de notícias que acontecem em uma data específica e armazena os dados das notícias no array NewsTime, que é passado por referência.
//+------------------------------------------------------------------+ //|Gets values from the MQL5 DB Calendar in Memory | //+------------------------------------------------------------------+ void CNews::EconomicDetailsMemory(Calendar &NewsTime[],datetime date) { //--- SQL query to retrieve news data for a certain date string request_text=StringFormat("WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name',EventType as 'Type'" ",EventImportance as 'Importance',%s as 'CTime',EventCurrency as 'Currency',EventCode as 'Code'," "EventSector as 'Sector',EventForecast as 'Forecast',EventPrevalue as 'Prevalue',EventImpact as'Impact'," "EventFrequency as 'Freq',RANK() OVER (PARTITION BY %s Order BY CASE EventPrevalue WHEN 'None' " "THEN 2 ELSE 1 END,CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END,CASE EventImportance WHEN " "'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN 'CALENDAR_IMPORTANCE_LOW'" " THEN 3 ELSE 4 END) Ranking FROM %s) SELECT Id,Country,Name,Type,Importance,CTime,Currency,Code,Sector," "Forecast,Prevalue,Impact,Freq FROM MySubQuery where Date(Replace(CTime,'.','-'))=Date(Replace('%s','.','-')) and " "Ranking<2 Group by CTime;",EnumToString(MySchedule),EnumToString(MySchedule),DBMemory.name, TimeToString(date)); int request=DatabasePrepare(DBMemoryConnection,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_MEMORY, " request failed with code ", GetLastError()); PrintFormat(request_text); } //--- Calendar structure variable Calendar ReadDB_Data; //--- Remove any data in the array ArrayRemove(NewsTime,0,WHOLE_ARRAY); for(int i=0; DatabaseReadBind(request,ReadDB_Data); i++)//Will read all the results from the sql query/request { //--- Resize array NewsTime ArrayResize(NewsTime,i+1,i+2); //--- Assign calendar structure values into NewsTime array index NewsTime[i] = ReadDB_Data; } //--- Removes a request created in DatabasePrepare() DatabaseFinalize(request); }
Vamos analisar a consulta SQL, pois ela é mais complexa do que qualquer uma das nossas consultas anteriores. Então, nesta consulta, utilizamos uma cláusula WITH e uma função RANK().
O que é uma cláusula WITH e como ela funciona?
A cláusula WITH, também conhecida como Expressão de Tabela Comum (CTE), é usada para definir conjuntos de resultados temporários que você pode referenciar dentro de uma instrução SELECT, INSERT, UPDATE ou DELETE. A cláusula WITH torna as consultas complexas mais fáceis de entender e manter, dividindo-as em partes mais simples. Ela também pode ajudar a melhorar o desempenho reutilizando os resultados de subconsultas caras. As CTEs são temporárias e existem apenas durante a execução da consulta. Elas não criam objetos permanentes no banco de dados.
O que é a função RANK() e como ela funciona?
A função RANK() é usada para atribuir uma classificação única a cada linha dentro de um conjunto de resultados com base nos valores de uma ou mais colunas. As linhas são ordenadas com base nos critérios especificados, e a classificação é atribuída de acordo. A função RANK() faz parte das funções de janela no SQL, o que significa que ela opera sobre uma janela (ou subconjunto) de linhas e pode retornar várias linhas para cada linha no conjunto de entrada. A função RANK() atribui uma classificação a cada linha com base na ordem especificada na cláusula ORDER BY dentro da definição da função de janela. Se várias linhas tiverem os mesmos valores nas colunas especificadas para ordenação, elas recebem a mesma classificação, e a próxima classificação é pulada pelo número de classificações idênticas. A cláusula PARTITION BY (opcional) divide o conjunto de resultados em partições, e a função RANK() é aplicada a cada partição de forma independente.
Nesta cláusula WITH destacada abaixo, selecionamos o EventId, Country, EventName, EventType, EventImportance, DST_NONE (horário de verão configurado pelo usuário/trader nos parâmetros do expert), EventCurrency, EventCode, EventSector, EventForecast, EventPrevalue, EventImpact, EventFrequency, e então usamos uma função de classificação. O objetivo desta função é dar uma classificação a cada resultado SELECT. Essa classificação será sempre 1 para um horário de evento único (DST_NONE), se tivermos múltiplos eventos com o mesmo horário de evento, aplicamos a classificação. Então, se o evento tiver um EventPrevalue igual a 'None', ele recebe uma classificação de 2, caso contrário, recebe uma classificação de 1, e assim por diante para o restante da cláusula ORDER BY.
WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name',EventType as 'Type',EventImportance as 'Importance', DST_NONE as 'CTime',EventCurrency as 'Currency',EventCode as 'Code',EventSector as 'Sector',EventForecast as 'Forecast', EventPrevalue as 'Prevalue',EventImpact as'Impact',EventFrequency as 'Freq',RANK() OVER (PARTITION BY DST_NONE Order BY CASE EventPrevalue WHEN 'None' THEN 2 ELSE 1 END,CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END, CASE EventImportance WHEN 'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN 'CALENDAR_IMPORTANCE_LOW' THEN 3 ELSE 4 END) Ranking FROM MQL5Calendar) SELECT Id,Country,Name,Type, Importance,CTime,Currency,Code,Sector,Forecast,Prevalue,Impact,Freq FROM MySubQuery where Date(Replace(CTime,'.','-'))=Date(Replace('2024.07.30 00:00','.','-')) and Ranking<2 Group by CTime;
Abaixo está um exemplo dos resultados do CTE (MySubQuery), destaquei os eventos que serão eliminados dos resultados, pois sua classificação excede 1. Consideramos apenas eventos com classificação menor que 2 e agrupamos o resultado por seu horário, pois quando plotamos os objetos do evento no gráfico, não queremos criar múltiplos objetos de evento com o mesmo horário. Queremos que apenas o evento de maior importância seja exibido.
Id Country Name Type Importance CTime Currency Code Sector Forecast Prevalue Impact Freq Ranking 392030007 Japan Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 2500000 2600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 392050002 Japan Jobs to Applicants Ratio CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 1240000 1240000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 36010001 Australia Building Approvals m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 03:30 AUD AU CALENDAR_SECTOR_BUSINESS -900000 5500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 36010002 Australia Private House Approvals m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 03:30 AUD AU CALENDAR_SECTOR_BUSINESS None 2100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 250010005 France GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_GDP 200000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 250010006 France GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_GDP 1000000 1100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 250010008 France Consumer Spending m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_CONSUMER 800000 1500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 756050001 Switzerland KOF Economic Barometer CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 CHF CH CALENDAR_SECTOR_BUSINESS 101500000 102700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 724010001 Spain CPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 200000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 724010003 Spain HICP m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 300000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 724010005 Spain GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_GDP 300000 800000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 724010002 Spain CPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 3000000 3400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 724010004 Spain HICP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 3500000 3600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 724010006 Spain GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_GDP 1900000 2500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 5 752020001 Sweden Business Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_BUSINESS 95500000 97300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020002 Sweden Manufacturing Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_BUSINESS 99000000 99200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020003 Sweden Consumer Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_CONSUMER 95300000 93300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020004 Sweden Inflation Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_CONSUMER 6300000 6200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020005 Sweden Economic Tendency Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_BUSINESS 94800000 96300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 276010008 Germany GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 10:00 EUR DE CALENDAR_SECTOR_GDP 100000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 380010020 Italy GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 10:00 EUR IT CALENDAR_SECTOR_GDP 200000 300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 276010009 Germany GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 10:00 EUR DE CALENDAR_SECTOR_GDP -400000 -900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 380010021 Italy GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 10:00 EUR IT CALENDAR_SECTOR_GDP 400000 700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 4 999030016 European Union GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_GDP 200000 300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 999030017 European Union GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_GDP 400000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 999040003 European Union Industrial Confidence Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS -9700000 -10100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040004 European Union Services Sentiment Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS 8300000 6500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040005 European Union Economic Sentiment Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS 95300000 95900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040006 European Union Consumer Confidence Index CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_CONSUMER -13000000 -13000000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040007 European Union Consumer Price Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_CONSUMER 14400000 13100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040008 European Union Industry Selling Price Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS 6300000 6100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 380020007 Italy 10-Year BTP Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 11:30 EUR IT CALENDAR_SECTOR_MARKET None 4010000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 1 380020005 Italy 5-Year BTP Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:30 EUR IT CALENDAR_SECTOR_MARKET None 3550000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 2 826130002 United Kingdom 10-Year Treasury Gilt Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:30 GBP GB CALENDAR_SECTOR_MARKET None 4371000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 2 724080001 Spain Business Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 12:00 EUR ES CALENDAR_SECTOR_BUSINESS -4100000 -5700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 76030002 Brazil FGV IGP-M Inflation Index m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 13:00 BRL BR CALENDAR_SECTOR_PRICES 1000000 810000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484020016 Mexico GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 14:00 MXN MX CALENDAR_SECTOR_GDP 0 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 276010020 Germany CPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES 0 100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 276010022 Germany HICP m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES -100000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 76010012 Brazil PPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 BRL BR CALENDAR_SECTOR_PRICES 700000 450000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 484020017 Mexico GDP n.s.a. y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 MXN MX CALENDAR_SECTOR_GDP 2000000 1600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 276010021 Germany CPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES 2200000 2200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 6 276010023 Germany HICP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES 2500000 2500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 6 76010013 Brazil PPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 14:00 BRL BR CALENDAR_SECTOR_PRICES 2200000 170000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 6 840170001 United States S&P/CS HPI Composite-20 y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 6800000 7200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840110001 United States HPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 300000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840110002 United States HPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 5700000 6300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840110003 United States HPI CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 427700000 424300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840170002 United States S&P/CS HPI Composite-20 n.s.a. m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 700000 1400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840170003 United States S&P/CS HPI Composite-20 s.a. m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 200000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840030021 United States JOLTS Job Openings CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 16:00 USD US CALENDAR_SECTOR_JOBS 7979000 8140000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840180002 United States CB Consumer Confidence Index CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 16:00 USD US CALENDAR_SECTOR_CONSUMER 108000000 100400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840060003 United States Dallas Fed Services Revenues CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 16:30 USD US CALENDAR_SECTOR_BUSINESS 3900000 1900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840060004 United States Dallas Fed Services Business Activity CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 16:30 USD US CALENDAR_SECTOR_BUSINESS -6700000 -4100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484010001 Mexico Fiscal Balance CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 22:30 MXN MX CALENDAR_SECTOR_TRADE -900000 -174071000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1
Os resultados finais são mostrados abaixo.
Id Country Name Type Importance CTime Currency Code Sector Forecast Prevalue Impact Freq Ranking 392030007 Japan Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 2500000 2600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 36010001 Australia Building Approvals m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 03:30 AUD AU CALENDAR_SECTOR_BUSINESS -900000 5500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 250010005 France GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_GDP 200000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 756050001 Switzerland KOF Economic Barometer CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 CHF CH CALENDAR_SECTOR_BUSINESS 101500000 102700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 276010008 Germany GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 10:00 EUR DE CALENDAR_SECTOR_GDP 100000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 999030016 European Union GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_GDP 200000 300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 380020007 Italy 10-Year BTP Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 11:30 EUR IT CALENDAR_SECTOR_MARKET None 4010000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 1 724080001 Spain Business Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 12:00 EUR ES CALENDAR_SECTOR_BUSINESS -4100000 -5700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 76030002 Brazil FGV IGP-M Inflation Index m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 13:00 BRL BR CALENDAR_SECTOR_PRICES 1000000 810000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484020016 Mexico GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 14:00 MXN MX CALENDAR_SECTOR_GDP 0 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 840170001 United States S&P/CS HPI Composite-20 y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 6800000 7200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840030021 United States JOLTS Job Openings CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 16:00 USD US CALENDAR_SECTOR_JOBS 7979000 8140000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840060003 United States Dallas Fed Services Revenues CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 16:30 USD US CALENDAR_SECTOR_BUSINESS 3900000 1900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484010001 Mexico Fiscal Balance CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 22:30 MXN MX CALENDAR_SECTOR_TRADE -900000 -174071000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1
Esses resultados serão armazenados na variável abaixo:
Calendário &NewsTime[]
A função abaixo, EconomicNextEvent, é semelhante à função mencionada anteriormente, EconomicDetailsMemory. A principal diferença é que o objetivo da função abaixo é obter o próximo evento, em vez de recuperar todos os eventos para uma data específica.
//+------------------------------------------------------------------+ //|Will update UpcomingNews structure variable with the next event | //|data | //+------------------------------------------------------------------+ void CNews::EconomicNextEvent(datetime date=0) { //--- Declare unassigned Calendar structure variable Empty Calendar Empty; //--- assign empty values to Calendar structure variable UpcomingNews UpcomingNews = Empty; //--- If date variable is zero then assign current date date = (date==0)?TimeTradeServer():date; //--- Query to retrieve next upcoming event. string request_text=StringFormat("WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name'," "EventType as 'Type',EventImportance as 'Importance',%s as 'CTime',EventCurrency as 'Currency'," "EventCode as 'Code',EventSector as 'Sector',EventForecast as 'Forecast'," "EventPrevalue as 'Prevalue',EventImpact as 'Impact',EventFrequency as 'Freq'," "RANK() OVER (PARTITION BY %s ORDER BY CASE EventPrevalue WHEN 'None' THEN 2 ELSE 1 END" ", CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END,CASE EventImportance " "WHEN 'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN" " 'CALENDAR_IMPORTANCE_LOW' THEN 3 ELSE 4 END) Ranking FROM %s) SELECT Id,Country,Name," "Type,Importance,CTime,Currency,Code,Sector,Forecast,Prevalue,Impact,Freq FROM MySubQuery " "where Replace(CTime,'.','-')>=Replace('%s','.','-') AND Ranking<2 Group by CTime LIMIT 1;", EnumToString(MySchedule),EnumToString(MySchedule),DBMemory.name,TimeToString(date)); int request=DatabasePrepare(DBMemoryConnection,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_MEMORY, " request failed with code ", GetLastError()); PrintFormat(request_text); } //--- Assign query results to Calendar structure variable UpcomingNews DatabaseReadBind(request,UpcomingNews); //--- Removes a request created in DatabasePrepare() DatabaseFinalize(request); }
A consulta abaixo para a função EconomicNextEvent é semelhante à consulta na função EconomicDetailsMemory, que explicamos anteriormente, a única diferença é que a consulta abaixo limitará os resultados para 1.
WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name',EventType as 'Type',EventImportance as 'Importance', DST_NONE as 'CTime',EventCurrency as 'Currency',EventCode as 'Code',EventSector as 'Sector',EventForecast as 'Forecast', EventPrevalue as 'Prevalue',EventImpact as'Impact',EventFrequency as 'Freq',RANK() OVER (PARTITION BY DST_NONE Order BY CASE EventPrevalue WHEN 'None' THEN 2 ELSE 1 END,CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END, CASE EventImportance WHEN 'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN 'CALENDAR_IMPORTANCE_LOW' THEN 3 ELSE 4 END) Ranking FROM MQL5Calendar) SELECT Id,Country,Name,Type, Importance,CTime,Currency,Code,Sector,Forecast,Prevalue,Impact,Freq FROM MySubQuery where Date(Replace(CTime,'.','-'))=Date(Replace('2024.07.30 00:00','.','-')) and Ranking<2 Group by CTime LIMIT 1;
Resultados de exemplo para a consulta acima são mostrados abaixo.
Id Country Name Type Importance CTime Currency Code Sector Forecast Prevalue Impact Freq Ranking 392030007 Japan Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 2500000 2600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1
O resultado de exemplo acima será armazenado na variável que declaramos fora da classe de notícias chamada UpcomingNews.
//--- Assign query results to Calendar structure variable UpcomingNews DatabaseReadBind(request,UpcomingNews);
A última função recém-adicionada na classe de notícias da parte 2 é chamada GetImpact, que é mostrada abaixo. O objetivo dessa função é retornar o valor de enumeração para a enumeração chamada ENUM_CALENDAR_EVENT_IMPACT para o próximo evento com base em eventos anteriores com propriedades ou valores semelhantes ao evento futuro. Deixe-me explicar melhor.
//+------------------------------------------------------------------+ //|Will retrieve Upcoming Event Impact data | //+------------------------------------------------------------------+ ENUM_CALENDAR_EVENT_IMPACT CNews::GetImpact() { //--- Declaration of string variable string impact=NULL; //--- Query to get impact data from previous event with the same event id and matching EventPrevalue and EventForecast scenarios. string request_text=StringFormat("SELECT EventImpact FROM %s where Replace(%s,'.','-')<Replace('%s','.','-') AND EventId=%d" " %s ORDER BY %s DESC LIMIT 1;",DBMemory.name,EnumToString(MySchedule),UpcomingNews.EventDate, UpcomingNews.EventId,((UpcomingNews.EventPreval=="None"||UpcomingNews.EventForecast=="None")? "AND EventImpact='CALENDAR_IMPACT_NA'":(int(UpcomingNews.EventPreval)<int(UpcomingNews.EventForecast))? "AND EventPrevalue<EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": (int(UpcomingNews.EventPreval)>int(UpcomingNews.EventForecast))? "AND EventPrevalue>EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": "AND EventPrevalue=EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'"), EnumToString(MySchedule)); int request=DatabasePrepare(DBMemoryConnection,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_MEMORY, " request failed with code ", GetLastError()); PrintFormat(request_text); } if(DatabaseRead(request))//Will read the one record in the 'Record' table { //--- assign first column result into impact variable DatabaseColumnText(request,0,impact); } //--- Removes a request created in DatabasePrepare() DatabaseFinalize(request); //--- Return equivalent Event impact in the enumeration ENUM_CALENDAR_EVENT_IMPACT if(impact=="CALENDAR_IMPACT_POSITIVE") { return CALENDAR_IMPACT_POSITIVE; } else if(impact=="CALENDAR_IMPACT_NEGATIVE") { return CALENDAR_IMPACT_NEGATIVE; } else { return CALENDAR_IMPACT_NA; } }
De acordo com minhas observações, o impacto do evento basicamente funciona da seguinte forma: eventos futuros ou eventos que ocorrem no dia atual tinham todos o valor de enumeração CALENDAR_IMPACT_NA de impacto, o que significa que o impacto não está disponível para o evento. O impacto do evento é atualizado somente após o dia do evento ter passado e somente se o evento tiver tanto o valor anterior do evento quanto o valor previsto do evento disponíveis antes que o evento ocorra. Existem algumas situações em que o impacto do evento ainda será registrado como indisponível, mesmo quando todos esses requisitos forem atendidos.
Por que precisamos do valor de impacto do evento anterior e como fazemos uso dele?
Primeiramente, a razão pela qual precisamos do impacto do evento anterior é para prever qual será o impacto do próximo evento. Então, quando o valor anterior do evento futuro não for 'None', e também o valor previsto, verificamos se esses valores são iguais ou qual valor é maior que o outro. Depois de descobrirmos qual valor é maior ou se os valores são iguais, procuramos eventos anteriores que tiveram a mesma configuração e recuperamos o impacto desse evento anterior para prever qual será o impacto do evento futuro. Ex. Se o valor anterior do evento futuro for 3000 e o valor previsto for 10.000, procuramos o último evento com o mesmo ID de evento que teve um valor anterior menor que o valor previsto e usamos o impacto desse evento para o próximo evento.
O que é o impacto do evento e com base em que ele é determinado?
O impacto do evento é a medida do efeito percebido que um evento específico teve sobre uma moeda, o impacto é baseado na moeda do evento. Então, se a taxa de desemprego for o próximo evento e o evento anterior com a configuração semelhante de valor anterior e valor previsto tiver um impacto de evento de CALENDAR_IMPACT_NEGATIVE e a moeda do evento for USD, isso essencialmente significa que o dólar americano foi negativamente afetado na taxa de desemprego anterior. Portanto, se você estivesse no símbolo EURUSD logo após o evento anterior da taxa de desemprego, idealmente veríamos o EURUSD se fortalecer, ou seja, o EUR teria ganhado valor contra o dólar americano.
Na consulta abaixo, selecionamos o impacto do evento da tabela MQL5Calendar no banco de dados na memória. Na cláusula WHERE, procuramos por datas de eventos anteriores à data do evento futuro e filtramos pelo mesmo ID de evento. Em seguida, filtramos o mesmo cenário de relacionamento entre o valor anterior do evento (EventPreval) e o valor previsto do evento (EventForecast), se UpcomingNews.EventPreval for igual a 'None' ou UpcomingNews.EventForecast for igual a 'None', então já sabemos que o impacto do evento será 'None', se UpcomingNews.EventPreval for menor que UpcomingNews. EventForecast, então procuramos eventos anteriores onde EventPrevalue<EventForecast e o impacto do evento não é NA, se UpcomingNews.EventPreval for maior que UpcomingNews.EventForecast, então procuramos eventos anteriores onde EventPreval>EventForecast e o impacto do evento não é NA, caso contrário, procuramos onde EventPrevalue=EventForecast e o impacto do evento não é NA. Todos os resultados são filtrados para a data mais recente, pois a cláusula ORDER BY está em ordem decrescente para a data do evento e a cláusula LIMIT permitirá que apenas um registro seja retornado/enviado.
//--- Query to get impact data from previous event with the same event id and matching EventPrevalue and EventForecast scenarios. string request_text=StringFormat("SELECT EventImpact FROM %s where Replace(%s,'.','-')<Replace('%s','.','-') AND EventId=%d" " %s ORDER BY %s DESC LIMIT 1;",DBMemory.name,EnumToString(MySchedule),UpcomingNews.EventDate, UpcomingNews.EventId,((UpcomingNews.EventPreval=="None"||UpcomingNews.EventForecast=="None")? "AND EventImpact='CALENDAR_IMPACT_NA'":(int(UpcomingNews.EventPreval)<int(UpcomingNews.EventForecast))? "AND EventPrevalue<EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": (int(UpcomingNews.EventPreval)>int(UpcomingNews.EventForecast))? "AND EventPrevalue>EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": "AND EventPrevalue=EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'"), EnumToString(MySchedule));
Um exemplo de como a consulta acima se apresenta quando todas as variáveis são preenchidas com dados. Como você pode ver abaixo, selecionamos o EventImpact DA tabela MQL5Calendar onde Replace(DST_NONE,'.','-')<Replace('2024.08.01 16:30','.','-') E EventId=124500001 E EventPrevalue<EventForecast E EventImpact<>'CALENDAR_IMPACT_NA' ordenamos os resultados em ordem decrescente em relação ao DST_NONE e, finalmente, limitamos os resultados para um.
SELECT EventImpact FROM MQL5Calendar where Replace(DST_NONE,'.','-')<Replace('2024.08.01 16:30','.','-') AND EventId=124500001 AND EventPrevalue<EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA' ORDER BY DST_NONE DESC LIMIT 1;
Classe de Gráficos Comuns
Esta classe é responsável por mostrar os elementos visuais do expert no gráfico. Então, agora você deve ter notado que os visuais para a Parte 3 são um passo maior em relação à Parte 2, assim como será o código que cria esses elementos visuais. Vamos dar uma olhada no código. Então, esta classe precisará de acesso às informações de notícias, informações de gerenciamento de risco, informações da conta, por isso essas classes são incluídas.
#include "ObjectProperties.mqh" #include "RiskManagement.mqh" #include "CommonVariables.mqh" #include "News.mqh" //+------------------------------------------------------------------+ //|CommonGraphics class | //+------------------------------------------------------------------+ class CCommonGraphics:CObjectProperties { private: //--- GraphicText structure this structure is responsible for managing the graphical text struct GraphicText { //--- private declaration for struct GraphicText private: //--- this structure will store properties for the subtext struct subtextformat { string Label;//Store text label string Text;//Store text value }; //--- this structure inherits from subtextformat and is responsible for finding text struct found:subtextformat { bool isFound;//Check if text is found int index;//Get index for the text }; //--- structure array for subtexts subtextformat sub_text[]; //--- function to find text properties from text's label found FoundText(string label) { found find; find.Label=""; find.Text=""; find.isFound=false; find.index=-1; for(uint i=0;i<sub_text.Size();i++) { //--- If text label is found in array if(label==sub_text[i].Label) { //--- Assign text properties find.Label=sub_text[i].Label; find.Text=sub_text[i].Text; find.isFound=true; find.index=int(i); return find;//return found text properties } } return find;//return text properties } //--- public declaration for struct GraphicText public: //--- string variable string text; //--- function to set/add text properties void subtext(string label,string value) { //--- Get text properties from label found result = FoundText(label); //--- Check if text label was found/exists in array sub_text if(!result.isFound) { //--- Resize array sub_text ArrayResize(sub_text,sub_text.Size()+1,sub_text.Size()+2); //--- Add text properties for new array index sub_text[sub_text.Size()-1].Label = label; sub_text[sub_text.Size()-1].Text = value; } else { /* Set new text/override text from text label that exists in the array sub_text array */ sub_text[result.index].Text = value; } } //--- function to retrieve text from text label string subtext(string label) { return FoundText(label).Text; } };// End of struct GraphicText //--- AccountInfo object declaration CAccountInfo CAccount; //--- News object declaration CNews NewsObj; //--- TimeManagement object declaration CTimeManagement CTime; //--- Calendar structure array declaration Calendar CalendarArray[]; //--- color variable declaration color EventColor; //--- unit variable declarations uint Fontsize,X_start,Y_start; //--- void function declarations for Graphical blocks void Block_1(); void Block_2(uint SecondsPreEvent=5); CRiskManagement CRisk;//Risk management class object //--- GraphicText structure array declarations GraphicText Texts_Block1[9],Texts_Block2[7]; //--- structure to store text height and width struct Text_Prop_Size { uint Height;//store text height uint Width;//store text width }; //--- void function to retrieve sum of the texts height and the maximum width of texts from GraphicText array Texts void GetTextMaxWidthAndHeight(GraphicText &Texts[],uint &Max_Height,uint &Max_Width,uint FontSize) { //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- set variables to default value of zero Max_Height=0; Max_Width=0; //--- loop through all texts in the GraphicText array Texts for(uint i=0;i<Texts.Size();i++) { //--- temporary declarations for height and width uint Height=0,Width=0; //--- retrieve text height and width from index in Texts array TextGetSize(Texts[i].text,Width,Height); //--- sum texts height to variable Max_Height Max_Height+=Height; //--- assign width if text width is more than variable Max_Width value Max_Width=(Width>Max_Width)?Width:Max_Width; } } //--- function to retrieve text height and width properties in the structure Text_Prop_Size format Text_Prop_Size GetText(string Text,uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- retrieve text height and width from Text string variable TextGetSize(Text,Size.Width,Size.Height); //--- return structure Text_Prop_Size variable return Size; } //--- Function to get texts height sum and max width in the structure Text_Prop_Size format Text_Prop_Size GetTextMax(GraphicText &Texts[],uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- uint variable declarations for text properties uint Max_Height; uint Max_Width; //--- Retrieve sum of texts height and maximum texts width into Max_Height,Max_Width GetTextMaxWidthAndHeight(Texts,Max_Height,Max_Width,FontSize); //--- assign values into structure Text_Prop_Size variable Size.Height = Max_Height; Size.Width = Max_Width; //--- return structure Text_Prop_Size variable return Size; } //--- Boolean declarations bool is_date,is_spread,is_news,is_events; public: //--- class constructor CCommonGraphics(bool display_date,bool display_spread,bool display_news,bool display_events); ~CCommonGraphics(void) {}//class destructor void GraphicsRefresh(uint SecondsPreEvent=5);//will create/refresh the chart objects //--- will update certain graphics at an interval void Block_2_Realtime(uint SecondsPreEvent=5); //--- will create chart event objects void NewsEvent(); };
A estrutura abaixo chamada GraphicText não é uma estrutura comum em MQL5, ela contém declarações privadas e/ou públicas de estruturas, arrays de estruturas, funções e uma variável de string. Neste caso, a estrutura GraphicText se comporta como uma classe separada. O objetivo dessa estrutura é gerenciar e armazenar textos gráficos. O array de estruturas sub_text armazenará todas as propriedades do texto e a função FoundText procurará por qualquer correspondência de rótulo de texto dentro do array sub_text. Se houver uma correspondência, retornaremos os detalhes dessa correspondência dentro da estrutura chamada found, que herda da estrutura subtextformat. Nas declarações públicas, a variável de string chamada text armazenará o comprimento total do texto no array de estruturas sub_text. A função void subtext adicionará o rótulo de texto e texto/subtext no array sub_text ou substituirá o texto/subtext armazenado no array se a variável de string label for encontrada dentro do array. A função de string chamada subtext recuperará o texto para o rótulo associado aos rótulos no array de estruturas sub_text.
//--- GraphicText structure this structure is responsible for managing the graphical text struct GraphicText { //--- private declaration for struct GraphicText private: //--- this structure will store properties for the subtext struct subtextformat { string Label;//Store text label string Text;//Store text value }; //--- this structure inherits from subtextformat and is responsible for finding text struct found:subtextformat { bool isFound;//Check if text is found int index;//Get index for the text }; //--- structure array for subtexts subtextformat sub_text[]; //--- function to find text properties from text's label found FoundText(string label) { found find; find.Label=""; find.Text=""; find.isFound=false; find.index=-1; for(uint i=0;i<sub_text.Size();i++) { //--- If text label is found in array if(label==sub_text[i].Label) { //--- Assign text properties find.Label=sub_text[i].Label; find.Text=sub_text[i].Text; find.isFound=true; find.index=int(i); return find;//return found text properties } } return find;//return text properties } //--- public declaration for struct GraphicText public: //--- string variable string text; //--- function to set/add text properties void subtext(string label,string value) { //--- Get text properties from label found result = FoundText(label); //--- Check if text label was found/exists in array sub_text if(!result.isFound) { //--- Resize array sub_text ArrayResize(sub_text,sub_text.Size()+1,sub_text.Size()+2); //--- Add text properties for new array index sub_text[sub_text.Size()-1].Label = label; sub_text[sub_text.Size()-1].Text = value; } else { /* Set new text/override text from text label that exists in the array sub_text array */ sub_text[result.index].Text = value; } } //--- function to retrieve text from text label string subtext(string label) { return FoundText(label).Text; } };// End of struct GraphicText
A função abaixo foi criada para recuperar a soma das alturas dos textos no array de estrutura Texts, bem como a largura máxima dos textos no array.
//--- void function to retrieve sum of the texts height and the maximum width of texts from GraphicText array Texts void GetTextMaxWidthAndHeight(GraphicText &Texts[],uint &Max_Height,uint &Max_Width,uint FontSize) { //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- set variables to default value of zero Max_Height=0; Max_Width=0; //--- loop through all texts in the GraphicText array Texts for(uint i=0;i<Texts.Size();i++) { //--- temporary declarations for height and width uint Height=0,Width=0; //--- retrieve text height and width from index in Texts array TextGetSize(Texts[i].text,Width,Height); //--- sum texts height to variable Max_Height Max_Height+=Height; //--- assign width if text width is more than variable Max_Width value Max_Width=(Width>Max_Width)?Width:Max_Width; } }
A função abaixo foi criada para recuperar as propriedades de altura e largura no formato da estrutura Text_Prop_Size a partir da variável de string Text.
//--- function to retrieve text height and width properties in the structure Text_Prop_Size format Text_Prop_Size GetText(string Text,uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- retrieve text height and width from Text string variable TextGetSize(Text,Size.Width,Size.Height); //--- return structure Text_Prop_Size variable return Size; }
A função abaixo foi criada para recuperar a soma das alturas e as propriedades de largura máxima no formato da estrutura Text_Prop_Size a partir do array de estrutura Texts.
//--- Function to get texts height sum and max width in the structure Text_Prop_Size format Text_Prop_Size GetTextMax(GraphicText &Texts[],uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- uint variable declarations for text properties uint Max_Height; uint Max_Width; //--- Retrieve sum of texts height and maximum texts width into Max_Height,Max_Width GetTextMaxWidthAndHeight(Texts,Max_Height,Max_Width,FontSize); //--- assign values into structure Text_Prop_Size variable Size.Height = Max_Height; Size.Width = Max_Width; //--- return structure Text_Prop_Size variable return Size; }
No construtor da classe, inicializaremos nossas variáveis previamente declaradas, que são is_date (que será usada para decidir se exibimos as informações de data no gráfico), is_spread (que será usada para decidir se exibimos as informações de spread no gráfico), is_news (que será usada para decidir se exibimos as informações de notícias no gráfico) e is_events (que será usada para decidir se exibimos as informações do objeto evento no gráfico). NewsObject. A função EconomicNextEvent atualizará a variável UpcomingNews com os detalhes da próxima notícia.
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CCommonGraphics::CCommonGraphics(bool display_date,bool display_spread,bool display_news,bool display_events): //--- Assign variables is_date(display_date),is_spread(display_spread),is_news(display_news),is_events(display_events) { //--- get next news event NewsObject.EconomicNextEvent(); }
GraphicsRefresh será responsável por primeiro limpar o gráfico de objetos previamente criados, se houver, e então chamará outras funções que criarão objetos gráficos para exibir várias informações no gráfico atual.
//+------------------------------------------------------------------+ //|will create/refresh the chart objects | //+------------------------------------------------------------------+ void CCommonGraphics::GraphicsRefresh(uint SecondsPreEvent=5) { //--- create graphics if outside the strategy tester or in the strategy tester and visual mode is enabled if((!MQLInfoInteger(MQL_TESTER))||(MQLInfoInteger(MQL_TESTER)&&MQLInfoInteger(MQL_VISUAL_MODE))) { //--- Delete chart objects DeleteObj();//function from Object properties class Block_1();//Create graphics for block 1 //--- Check whether to create graphics for block 2 if(is_date||is_news||is_spread) { Block_2(SecondsPreEvent);//Create graphics for block 2 } //--- creates event objects NewsEvent(); } }
A função abaixo chamada Block_1 será responsável por criar os elementos gráficos para o bloco gráfico 1, conforme indicado abaixo, e consiste em:
- Nome do Símbolo
- Período do Símbolo
- Descrição do Símbolo
- Tamanho do Contrato do Símbolo
- Tamanho Mínimo de Lote do Símbolo
- Tamanho Máximo de Lote do Símbolo
- Passo de Volume do Símbolo
- Limite de Volume do Símbolo
- Opção de Risco
- Piso de Risco
- Teto de Risco
//+------------------------------------------------------------------+ //|Graphical Block 1 | //+------------------------------------------------------------------+ void CCommonGraphics::Block_1() { //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color = (isLightMode)?clrBlack:clrWheat; //--- Set text properties for Symbol name,Symbol period and Symbol description # section 1 Texts_Block1[0].text = Symbol()+", "+GetChartPeriodName()+": "+CSymbol.Description();//set main text Texts_Block1[0].subtext("Symbol Name",Symbol()+",");//set subtext - label,value Texts_Block1[0].subtext("Symbol Period",GetChartPeriodName());//set subtext - label,value Texts_Block1[0].subtext("Symbol Desc",": "+CSymbol.Description());//set subtext - label,value //--- Set text properties for Contract size # section 2 Texts_Block1[1].text = "Contract Size: "+string(CSymbol.ContractSize());//set main text Texts_Block1[1].subtext("Contract Size Text","Contract Size:");//set subtext - label,value Texts_Block1[1].subtext("Contract Size",string(CSymbol.ContractSize()));//set subtext - label,value //--- Set text properties for Minimum lot # section 3 Texts_Block1[2].text = "Minimum Lot: "+string(CSymbol.LotsMin());//set main text Texts_Block1[2].subtext("Minimum Lot Text","Minimum Lot:");//set subtext - label,value Texts_Block1[2].subtext("Minimum Lot",string(CSymbol.LotsMin()));//set subtext - label,value //--- Set text properties for Max lot # section 4 Texts_Block1[3].text = "Max Lot: "+string(CSymbol.LotsMax());//set main text Texts_Block1[3].subtext("Max Lot Text","Max Lot:");//set subtext - label,value Texts_Block1[3].subtext("Max Lot",string(CSymbol.LotsMax()));//set subtext - label,value //--- Set text properties for Volume step # section 5 Texts_Block1[4].text = "Volume Step: "+string(CSymbol.LotsStep());//set main text Texts_Block1[4].subtext("Volume Step Text","Volume Step:");//set subtext - label,value Texts_Block1[4].subtext("Volume Step",string(CSymbol.LotsStep()));//set subtext - label,value //--- Set text properties for Volume limit # section 6 Texts_Block1[5].text = "Volume Limit: "+string(CSymbol.LotsLimit());//set main text Texts_Block1[5].subtext("Volume Limit Text","Volume Limit:");//set subtext - label,value Texts_Block1[5].subtext("Volume Limit",string(CSymbol.LotsLimit()));//set subtext - label,value //--- Set text properties for Risk option # section 7 Texts_Block1[6].text = "Risk Option: "+CRisk.GetRiskOption();//set main text Texts_Block1[6].subtext("Risk Option Text","Risk Option:");//set subtext - label,value Texts_Block1[6].subtext("Risk Option",CRisk.GetRiskOption());//set subtext - label,value //--- Set text properties for Risk floor # section 8 Texts_Block1[7].text = "Risk Floor: "+CRisk.GetRiskFloor();//set main text Texts_Block1[7].subtext("Risk Floor Text","Risk Floor:");//set subtext - label,value Texts_Block1[7].subtext("Risk Floor",CRisk.GetRiskFloor());//set subtext - label,value //--- Set text properties for Risk ceiling # section 9 Texts_Block1[8].text = "Risk Ceiling: "+CRisk.GetRiskCeil();//set main text Texts_Block1[8].subtext("Risk Ceiling Text","Risk Ceiling:");//set subtext - label,value Texts_Block1[8].subtext("Risk Ceiling",CRisk.GetRiskCeil());//set subtext - label,value //--- Set basic properties Fontsize=10;//Set Fontsize X_start=2;//Set X distance Y_start=2;//Set Y distance /* Create objects # section 1*/ //-- Create the background object for width and height+3 of section 1 text Square(0,"Symbol Name background",X_start,Y_start,GetText(Texts_Block1[0].text,Fontsize).Width, GetText(Texts_Block1[0].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 1 TextObj(0,"Symbol Name",Texts_Block1[0].subtext("Symbol Name"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[0].subtext("Symbol Name"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Period",Texts_Block1[0].subtext("Symbol Period"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[0].subtext("Symbol Period"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Desc",Texts_Block1[0].subtext("Symbol Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 2*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[0].text,Fontsize).Height;//Re-adjust Y distance, add height from section 1 //-- Create the background object for width and height+3 of section 2 text Square(0,"Symbol Contract Size background",X_start,Y_start,GetText(Texts_Block1[1].text,Fontsize).Width, GetText(Texts_Block1[1].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 2 TextObj(0,"Symbol Contract Size Text",Texts_Block1[1].subtext("Contract Size Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[1].subtext("Contract Size Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Contract Size",Texts_Block1[1].subtext("Contract Size"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 3*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[1].text,Fontsize).Height;//Re-adjust Y distance, add height from section 2 //-- Create the background object for width and height+3 of section 3 text Square(0,"Symbol MinLot background",X_start,Y_start,GetText(Texts_Block1[2].text,Fontsize).Width, GetText(Texts_Block1[2].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 3 TextObj(0,"Symbol MinLot Text",Texts_Block1[2].subtext("Minimum Lot Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[2].subtext("Minimum Lot Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol MinLot",Texts_Block1[2].subtext("Minimum Lot"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 4*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[2].text,Fontsize).Height;//Re-adjust Y distance, add height from section 3 //-- Create the background object for width and height+3 of section 4 text Square(0,"Symbol MaxLot background",X_start,Y_start,GetText(Texts_Block1[3].text,Fontsize).Width, GetText(Texts_Block1[3].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 4 TextObj(0,"Symbol MaxLot Text",Texts_Block1[3].subtext("Max Lot Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[3].subtext("Max Lot Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol MaxLot",Texts_Block1[3].subtext("Max Lot"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 5*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[3].text,Fontsize).Height;//Re-adjust Y distance, add height from section 4 //-- Create the background object for width and height+3 of section 5 text Square(0,"Symbol Volume Step background",X_start,Y_start,GetText(Texts_Block1[4].text,Fontsize).Width, GetText(Texts_Block1[4].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 5 TextObj(0,"Symbol Volume Step Text",Texts_Block1[4].subtext("Volume Step Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[4].subtext("Volume Step Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Volume Step",Texts_Block1[4].subtext("Volume Step"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 6*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[4].text,Fontsize).Height;//Re-adjust Y distance, add height from section 5 //-- Create the background object for width and height+3 of section 6 text Square(0,"Symbol Volume Limit background",X_start,Y_start,GetText(Texts_Block1[5].text,Fontsize).Width, GetText(Texts_Block1[5].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 6 TextObj(0,"Symbol Volume Limit Text",Texts_Block1[5].subtext("Volume Limit Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[5].subtext("Volume Limit Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Volume Limit",Texts_Block1[5].subtext("Volume Limit"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 7*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[5].text,Fontsize).Height;//Re-adjust Y distance, add height from section 6 //-- Create the background object for width and height+3 of section 7 text Square(0,"Risk Option background",X_start,Y_start,GetText(Texts_Block1[6].text,Fontsize).Width, GetText(Texts_Block1[6].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 7 TextObj(0,"Risk Option Text",Texts_Block1[6].subtext("Risk Option Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[6].subtext("Risk Option Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Risk Option",Texts_Block1[6].subtext("Risk Option"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 8*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[6].text,Fontsize).Height;//Re-adjust Y distance, add height from section 7 //-- Create the background object for width and height+3 of section 8 text Square(0,"Risk Floor background",X_start,Y_start,GetText(Texts_Block1[7].text,Fontsize).Width, GetText(Texts_Block1[7].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 8 TextObj(0,"Risk Floor Text",Texts_Block1[7].subtext("Risk Floor Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[7].subtext("Risk Floor Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Risk Floor",Texts_Block1[7].subtext("Risk Floor"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 9*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[7].text,Fontsize).Height;//Re-adjust Y distance, add height from section 8 //-- Create the background object for width and height+3 of section 9 text Square(0,"Risk Ceil background",X_start,Y_start,GetText(Texts_Block1[8].text,Fontsize).Width, GetText(Texts_Block1[8].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 9 TextObj(0,"Risk Ceil Text",Texts_Block1[8].subtext("Risk Ceiling Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[8].subtext("Risk Ceiling Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Risk Ceil",Texts_Block1[8].subtext("Risk Ceiling"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); }
A função abaixo chamada Block_2 será responsável por criar os elementos gráficos para o bloco gráfico 2, conforme indicado abaixo, e consiste em:
- Data e Hora Atuais
- Data do Evento
- Nome do Evento
- País do Evento
- Moeda do Evento
- Importância do Evento
- Classificação de Spread
//+------------------------------------------------------------------+ //|Graphical Block 2 | //+------------------------------------------------------------------+ void CCommonGraphics::Block_2(uint SecondsPreEvent=5) { //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; if(is_date)//Check whether to display date information { //--- Set text properties for Date and Time # section 10 Texts_Block2[0].text = "Date:"+TimeToString(TimeTradeServer(),TIME_DATE)+"|| Time:"+TimeToString(TimeTradeServer(),TIME_MINUTES) +" ";//set main text Texts_Block2[0].subtext("Date Text","Date:");//set subtext - label,value Texts_Block2[0].subtext("Date",TimeToString(TimeTradeServer(),TIME_DATE));//set subtext - label,value Texts_Block2[0].subtext("Time Text","|| Time:");//set subtext - label,value Texts_Block2[0].subtext("Time",TimeToString(TimeTradeServer(),TIME_MINUTES));//set subtext - label,value } if(is_news)//Check whether to display news information { //--- Set text object color depending on upcoming news event's Importance EventColor = NewsObj.GetImportance_color(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)); //--- Set text properties for Event Date # section 11 Texts_Block2[1].text = "Event: @"+UpcomingNews.EventDate+" ";//set main text Texts_Block2[1].subtext("Event Date Text","Event: @");//set subtext - label,value Texts_Block2[1].subtext("Event Date",UpcomingNews.EventDate);//set subtext - label,value //--- Set text properties for Event Name # section 12 Texts_Block2[2].text = "Name: "+UpcomingNews.EventName+" ";//set main text Texts_Block2[2].subtext("Event Name Text","Name: ");//set subtext - label,value Texts_Block2[2].subtext("Event Name",UpcomingNews.EventName);//set subtext - label,value //--- Set text properties for Event Country # section 13 Texts_Block2[3].text = "Country: "+UpcomingNews.CountryName+" ";//set main text Texts_Block2[3].subtext("Event Country Text","Country: ");//set subtext - label,value Texts_Block2[3].subtext("Event Country",UpcomingNews.CountryName);//set subtext - label,value //--- Set text properties for Event Currency # section 14 Texts_Block2[4].text = "Currency: "+UpcomingNews.EventCurrency+" ";//set main text Texts_Block2[4].subtext("Event Currency Text","Currency: ");//set subtext - label,value Texts_Block2[4].subtext("Event Currency",UpcomingNews.EventCurrency);//set subtext - label,value //--- Set text properties for Event Importance # section 15 Texts_Block2[5].text = "Importance: "+NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance))+" ";//set main text Texts_Block2[5].subtext("Importance Text","Importance: ");//set subtext - label,value Texts_Block2[5].subtext("Importance",NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)));//set subtext - label,value } if(is_spread)//Check whether to display spread information { //--- Set text properties for Spread # section 16 Texts_Block2[6].text = "Spread: "+string(CSymbol.Spread())+" Rating: "+CSymbol.SpreadDesc()+" ";//set main text Texts_Block2[6].subtext("Spread Text","Spread:");//set subtext - label,value Texts_Block2[6].subtext("Spread",string(CSymbol.Spread()));//set subtext - label,value Texts_Block2[6].subtext("Rating Text"," Rating:");//set subtext - label,value Texts_Block2[6].subtext("Rating Desc",CSymbol.SpreadDesc());//set subtext - label,value } //--- Set basic properties Fontsize=10; X_start=2;//Reset X distance Y_start=GetTextMax(Texts_Block1,Fontsize).Height+29;//Re-adjust Y distance from graphical block 1 Height /* Create objects # section 10*/ if(is_date)//Check whether to display date information { //-- Create the background object for width and height+3 of section 10 text Square(0,"Datetime background",X_start,Y_start,GetText(Texts_Block2[0].text,Fontsize).Width, GetText(Texts_Block2[0].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 10 TextObj(0,"Date Text",Texts_Block2[0].subtext("Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Date",Texts_Block2[0].subtext("Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Time Text",Texts_Block2[0].subtext("Time Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Time Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Time",Texts_Block2[0].subtext("Time"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(UpcomingNews.CountryName!=NULL&&is_news)//Check whether to display news information and if upcoming news is available { /* Create objects # section 11*/ Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0;//Re-adjust Y distance depending if section 10 is shown X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 11 text Square(0,"Event Date background",X_start,Y_start,GetText(Texts_Block2[1].text,Fontsize).Width, GetText(Texts_Block2[1].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 11 TextObj(0,"Event Date Text",Texts_Block2[1].subtext("Event Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[1].subtext("Event Date Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Event Date",Texts_Block2[1].subtext("Event Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 12*/ Y_start+=GetText(Texts_Block2[1].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 12 text Square(0,"Event Name background",X_start,Y_start,GetText(Texts_Block2[2].text,Fontsize).Width, GetText(Texts_Block2[2].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 12 TextObj(0,"Event Name Text",Texts_Block2[2].subtext("Event Name Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[2].subtext("Event Name Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Name",Texts_Block2[2].subtext("Event Name"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 13*/ Y_start+=GetText(Texts_Block2[2].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 13 text Square(0,"Event Country background",X_start,Y_start,GetText(Texts_Block2[3].text,Fontsize).Width, GetText(Texts_Block2[3].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 13 TextObj(0,"Event Country Text",Texts_Block2[3].subtext("Event Country Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[3].subtext("Event Country Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Country",Texts_Block2[3].subtext("Event Country"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 14*/ Y_start+=GetText(Texts_Block2[3].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 14 text Square(0,"Event Currency background",X_start,Y_start,GetText(Texts_Block2[4].text,Fontsize).Width, GetText(Texts_Block2[4].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 14 TextObj(0,"Event Currency Text",Texts_Block2[4].subtext("Event Currency Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[4].subtext("Event Currency Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Currency",Texts_Block2[4].subtext("Event Currency"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 15*/ Y_start+=GetText(Texts_Block2[4].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 15 text Square(0,"Event Importance background",X_start,Y_start,GetText(Texts_Block2[5].text,Fontsize).Width, GetText(Texts_Block2[5].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 15 TextObj(0,"Importance Text",Texts_Block2[5].subtext("Importance Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[5].subtext("Importance Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Importance",Texts_Block2[5].subtext("Importance"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=GetText(Texts_Block2[5].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 16 text Square(0,"Spread background",X_start,Y_start,GetText(Texts_Block2[6].text,Fontsize).Width, GetText(Texts_Block2[6].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 16 TextObj(0,"Symbol Spread Text",Texts_Block2[6].subtext("Spread Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } } else /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0;//Re-adjust Y distance depending if section 10 is shown X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 16 text Square(0,"Spread background",X_start,Y_start,GetText(Texts_Block2[6].text,Fontsize).Width, GetText(Texts_Block2[6].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 16 TextObj(0,"Symbol Spread Text",Texts_Block2[6].subtext("Spread Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } }
A função abaixo atualizará quaisquer mudanças nas seções do Bloco Gráfico 2. E não recriará todos os elementos da função Block_2.
//+------------------------------------------------------------------+ //|will update certain graphics at an interval | //+------------------------------------------------------------------+ void CCommonGraphics::Block_2_Realtime(uint SecondsPreEvent=5) { if(MQLInfoInteger(MQL_TESTER)&&!MQLInfoInteger(MQL_VISUAL_MODE)) { return;//exit if in strategy tester and not in visual mode } if(is_date)//Check whether to display date information { //--- Set text properties for Date and Time # section 10 Texts_Block2[0].text = "Date:"+TimeToString(TimeTradeServer(),TIME_DATE)+"|| Time:"+TimeToString(TimeTradeServer(),TIME_SECONDS) +" ";//set main text Texts_Block2[0].subtext("Date Text","Date:");//set subtext - label,value Texts_Block2[0].subtext("Date",TimeToString(TimeTradeServer(),TIME_DATE));//set subtext - label,value Texts_Block2[0].subtext("Time Text","|| Time:");//set subtext - label,value Texts_Block2[0].subtext("Time",TimeToString(TimeTradeServer(),TIME_SECONDS));//set subtext - label,value } if(is_news)//Check whether to display news information { //--- Set text object color depending on upcoming news event's Importance EventColor = NewsObj.GetImportance_color(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)); //--- Set text properties for Event Date # section 11 Texts_Block2[1].text = "Event: @"+UpcomingNews.EventDate+" ";//set main text Texts_Block2[1].subtext("Event Date Text","Event: @");//set subtext - label,value Texts_Block2[1].subtext("Event Date",UpcomingNews.EventDate);//set subtext - label,value //--- Set text properties for Event Name # section 12 Texts_Block2[2].text = "Name: "+UpcomingNews.EventName+" ";//set main text Texts_Block2[2].subtext("Event Name Text","Name: ");//set subtext - label,value Texts_Block2[2].subtext("Event Name",UpcomingNews.EventName);//set subtext - label,value //--- Set text properties for Event Country # section 13 Texts_Block2[3].text = "Country: "+UpcomingNews.CountryName+" ";//set main text Texts_Block2[3].subtext("Event Country Text","Country: ");//set subtext - label,value Texts_Block2[3].subtext("Event Country",UpcomingNews.CountryName);//set subtext - label,value //--- Set text properties for Event Currency # section 14 Texts_Block2[4].text = "Currency: "+UpcomingNews.EventCurrency+" ";//set main text Texts_Block2[4].subtext("Event Currency Text","Currency: ");//set subtext - label,value Texts_Block2[4].subtext("Event Currency",UpcomingNews.EventCurrency);//set subtext - label,value //--- Set text properties for Event Importance # section 15 Texts_Block2[5].text = "Importance: "+NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance))+" ";//set main text Texts_Block2[5].subtext("Importance Text","Importance: ");//set subtext - label,value Texts_Block2[5].subtext("Importance",NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)));//set subtext - label,value } if(is_spread)//Check whether to display spread information { //--- Set text properties for Spread # section 16 Texts_Block2[6].text = "Spread: "+string(CSymbol.Spread())+" Rating: "+CSymbol.SpreadDesc()+" ";//set main text Texts_Block2[6].subtext("Spread Text","Spread:");//set subtext - label,value Texts_Block2[6].subtext("Spread",string(CSymbol.Spread()));//set subtext - label,value Texts_Block2[6].subtext("Rating Text"," Rating:");//set subtext - label,value Texts_Block2[6].subtext("Rating Desc",CSymbol.SpreadDesc());//set subtext - label,value } //--- Set basic properties Fontsize=10; X_start=2;//Reset X distance Y_start=GetTextMax(Texts_Block1,Fontsize).Height+29;//Re-adjust Y distance from section block 1 /* Create objects # section 10*/ if(is_date)//Check whether to display date information { //-- Check if the background object x-size for section 10 is the same size as section 10 text width if(ObjectGetInteger(0,"Datetime background",OBJPROP_XSIZE)!=GetText(Texts_Block2[0].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 10 text width ObjectSetInteger(0,"Datetime background",OBJPROP_XSIZE,long(GetText(Texts_Block2[0].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 10 TextObj(0,"Date Text",Texts_Block2[0].subtext("Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Date",Texts_Block2[0].subtext("Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Time Text",Texts_Block2[0].subtext("Time Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Time Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Time",Texts_Block2[0].subtext("Time"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(UpcomingNews.CountryName!=NULL&&is_news)//Check whether to display news information { /* Create objects # section 11*/ Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0; X_start=2;//Reset X distance //-- Check if the background object x-size for section 11 is the same size as section 11 text width if(ObjectGetInteger(0,"Event Date background",OBJPROP_XSIZE)!=GetText(Texts_Block2[1].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 11 text width ObjectSetInteger(0,"Event Date background",OBJPROP_XSIZE,long(GetText(Texts_Block2[1].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 11 TextObj(0,"Event Date Text",Texts_Block2[1].subtext("Event Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[1].subtext("Event Date Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Event Date",Texts_Block2[1].subtext("Event Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 12*/ Y_start+=GetText(Texts_Block2[1].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 12 is the same size as section 12 text width if(ObjectGetInteger(0,"Event Name background",OBJPROP_XSIZE)!=GetText(Texts_Block2[2].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 12 text width ObjectSetInteger(0,"Event Name background",OBJPROP_XSIZE,long(GetText(Texts_Block2[2].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 12 TextObj(0,"Event Name Text",Texts_Block2[2].subtext("Event Name Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[2].subtext("Event Name Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Name",Texts_Block2[2].subtext("Event Name"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 13*/ Y_start+=GetText(Texts_Block2[2].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 13 is the same size as section 13 text width if(ObjectGetInteger(0,"Event Country background",OBJPROP_XSIZE)!=GetText(Texts_Block2[3].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 13 text width ObjectSetInteger(0,"Event Country background",OBJPROP_XSIZE,long(GetText(Texts_Block2[3].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 13 TextObj(0,"Event Country Text",Texts_Block2[3].subtext("Event Country Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[3].subtext("Event Country Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Country",Texts_Block2[3].subtext("Event Country"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 14*/ Y_start+=GetText(Texts_Block2[3].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 14 is the same size as section 14 text width if(ObjectGetInteger(0,"Event Currency background",OBJPROP_XSIZE)!=GetText(Texts_Block2[4].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 14 text width ObjectSetInteger(0,"Event Currency background",OBJPROP_XSIZE,long(GetText(Texts_Block2[4].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 14 TextObj(0,"Event Currency Text",Texts_Block2[4].subtext("Event Currency Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[4].subtext("Event Currency Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Currency",Texts_Block2[4].subtext("Event Currency"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 15*/ Y_start+=GetText(Texts_Block2[4].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 15 is the same size as section 15 text width if(ObjectGetInteger(0,"Event Importance background",OBJPROP_XSIZE)!=GetText(Texts_Block2[5].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 15 text width ObjectSetInteger(0,"Event Importance background",OBJPROP_XSIZE,long(GetText(Texts_Block2[5].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 15 TextObj(0,"Importance Text",Texts_Block2[5].subtext("Importance Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[5].subtext("Importance Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Importance",Texts_Block2[5].subtext("Importance"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=GetText(Texts_Block2[5].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 16 is the same size as section 16 text width if(ObjectGetInteger(0,"Spread background",OBJPROP_XSIZE)!=GetText(Texts_Block2[6].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 16 text width ObjectSetInteger(0,"Spread background",OBJPROP_XSIZE,long(GetText(Texts_Block2[6].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //-- Will create the text object for the Symbol's name X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; //-- Will update the text objects for section 16 TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } } else /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 16 is the same size as section 16 text width if(ObjectGetInteger(0,"Spread background",OBJPROP_XSIZE)!=GetText(Texts_Block2[6].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 16 text width ObjectSetInteger(0,"Spread background",OBJPROP_XSIZE,long(GetText(Texts_Block2[6].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //-- Will create the text object for the Symbol's name X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; //-- Will update the text objects for section 16 TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } }
A função abaixo criará o objeto de evento no gráfico com todos os eventos de notícias disponíveis para o dia atual.
//+------------------------------------------------------------------+ //|will create chart event objects | //+------------------------------------------------------------------+ void CCommonGraphics::NewsEvent() { if(!is_events||(MQLInfoInteger(MQL_TESTER)&&!MQLInfoInteger(MQL_VISUAL_MODE))) {return;}//exit if in strategy tester and not in visual mode or is_events variable is false //--- Retrieve news events for the current Daily period into array CalendarArray NewsObj.EconomicDetailsMemory(CalendarArray,iTime(Symbol(),PERIOD_D1,0)); //--- Iterate through all events in CalendarArray for(uint i=0;i<CalendarArray.Size();i++) { //--- Create event object with the news properties EventObj(0,CalendarArray[i].EventName+" "+CalendarArray[i].CountryName+" "+CalendarArray[i].EventDate, CalendarArray[i].EventName+"["+CalendarArray[i].CountryName+"]",StringToTime(CalendarArray[i].EventDate)); } //--- Refresh the chart/ update the chart ChartRefresh(); }
Classe de Gerenciamento de Trades
Esta classe será responsável por abrir trades para o nosso expert. A funcionalidade dessa classe provavelmente se expandirá em artigos posteriores. A classe de gerenciamento de trades herdará da classe de gerenciamento de risco para configurar os tamanhos de lote para cada trade.
#include <Trade\Trade.mqh> #include <Trade\OrderInfo.mqh> #include <Trade\SymbolInfo.mqh> #include "RiskManagement.mqh" #include "TimeManagement.mqh" //+------------------------------------------------------------------+ //|TradeManagement class | //+------------------------------------------------------------------+ class CTradeManagement:CRiskManagement { private: CTrade Trade;//Trade class object CSymbolProperties CSymbol;//SymbolProperties class object CTimeManagement CTime;//TimeManagement class object bool TradeResult;//boolean to store trade result double mySL;//double variable to store Stoploss double myTP;//double variable to store Takeprofit public: //--- Class constructor CTradeManagement(string SYMBOL=NULL) { //--- Set symbol name CSymbol.SetSymbolName(SYMBOL); } //--- Class destructor ~CTradeManagement(void) {} //--- Will retrieve if there are any open trades bool OpenTrade(ENUM_POSITION_TYPE Type,ulong Magic,string COMMENT=NULL); //--- Will retrieve if there are any deals bool OpenedDeal(ENUM_DEAL_TYPE Type,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade bool Buy(double SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade with integer SL bool Buy(int SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade with integer TP bool Buy(double SL,int TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade with integer SL & TP bool Buy(int SL,int TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade bool Sell(double SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade with integer SL bool Sell(int SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade with integer TP bool Sell(double SL,int TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade with integer SL & TP bool Sell(int SL,int TP,ulong Magic,string COMMENT=NULL); };
A função abaixo verificará se há posições abertas com um tipo específico de posição (Compra/Venda), Magic (Pegada única), Comentário (Detalhes da posição). Usaremos esta função para verificar se já abrimos um trade quando o evento de notícias está ocorrendo, para evitar abrir trades extras/desnecessários.
//+------------------------------------------------------------------+ //|Will retrieve if there are any open trades | //+------------------------------------------------------------------+ bool CTradeManagement::OpenTrade(ENUM_POSITION_TYPE Type,ulong Magic,string COMMENT=NULL) { //--- Iterate through all open positions for(int i=0; i<PositionsTotal(); i++) { //--- Check if Position ticket is above zero if(PositionGetTicket(i)>0) { //--- Check if the Position's Symbol,Magic,Type,Comment is correct if(PositionGetString(POSITION_SYMBOL)==CSymbol.GetSymbolName()&&PositionGetInteger(POSITION_MAGIC)==Magic &&PositionGetInteger(POSITION_TYPE)==Type&&PositionGetString(POSITION_COMMENT)==COMMENT) { //--- Return true when there is an open position return true; } } } //--- No open positions found. return false; }
A função OpenedDeal verificará se há deals abertas, podendo ser deals de compra/venda. Precisamos dessa função para evitar que nós/o expert abramos novos trades quando um trade foi fechado durante um evento de notícias. Sem essa função, o expert abriria um trade de compra, por exemplo, quando o NFP (Non-Farm Payroll) está prestes a acontecer, se o trade aberto for fechado devido à volatilidade. Não queremos que o expert abra outro trade, pois já negociamos o evento e não há necessidade de mais trades que possam resultar em perdas desnecessárias.
//+------------------------------------------------------------------+ //|Will retrieve if there are any deals | //+------------------------------------------------------------------+ bool CTradeManagement::OpenedDeal(ENUM_DEAL_TYPE Type,ulong Magic,string COMMENT=NULL) { //--- Check History starting from 2 minutes ago if(HistorySelect(CTime.TimeMinusOffset(TimeTradeServer(),CTime.MinutesS(2)),TimeTradeServer())) { //--- Iterate through all history deals for(int i=0; i<HistoryDealsTotal(); i++) { //--- Assign history deal ticket ulong ticket = HistoryDealGetTicket(i); //--- Check if ticket is more than zero if(ticket>0) { //--- Check if the Deal's Symbol,Magic,Type,Comment is correct if(HistoryDealGetString(ticket,DEAL_SYMBOL)==CSymbol.GetSymbolName()&& HistoryDealGetInteger(ticket,DEAL_MAGIC)==Magic&&HistoryDealGetInteger(ticket,DEAL_TYPE)==Type &&HistoryDealGetString(ticket,DEAL_COMMENT)==COMMENT) { //--- Return true when there are any deals return true; } } } } //--- No deals found. return false; }
A função abaixo abrirá todas as ordens de Mercado para trades de compra/long.
//+------------------------------------------------------------------+ //|Will attempt open buy trade | //+------------------------------------------------------------------+ bool CTradeManagement::Buy(double SL,double TP,ulong Magic,string COMMENT=NULL) { //--- Normalize the SL Price CSymbol.NormalizePrice(SL); //--- Normalize the TP Price CSymbol.NormalizePrice(TP); //--- Set the order type for Risk management calculation SetOrderType(ORDER_TYPE_BUY); //--- Set open price for Risk management calculation OpenPrice = CSymbol.Ask(); //--- Set close price for Risk management calculation ClosePrice = SL; //--- Set Trade magic number Trade.SetExpertMagicNumber(Magic); //--- Check if there are any open trades or opened deals already if(!OpenTrade(POSITION_TYPE_BUY,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_BUY,Magic,COMMENT)) { //--- Iterate through the Lot-sizes if they're more than max-lot for(double i=Volume();i>=CSymbol.LotsMin();i-=CSymbol.LotsMax()) { //--- normalize Lot-size NormalizeLotsize(i); //--- Open trade with a Lot-size not more than max-lot TradeResult = Trade.Buy((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,CSymbol.GetSymbolName(),CSymbol.Ask(),SL,TP,COMMENT); //--- Check if trade failed. if(!TradeResult) { return TradeResult; } } } else { //--- Trade failed because there is an open trade or opened deal return false; } //--- Return trade result. return TradeResult; }
A função abaixo abrirá todas as ordens de Mercado para trades de venda/short.
//+------------------------------------------------------------------+ //|Will attempt open sell trade | //+------------------------------------------------------------------+ bool CTradeManagement::Sell(double SL,double TP,ulong Magic,string COMMENT=NULL) { //--- Normalize the SL Price CSymbol.NormalizePrice(SL); //--- Normalize the TP Price CSymbol.NormalizePrice(TP); //--- Set the order type for Risk management calculation SetOrderType(ORDER_TYPE_SELL); //--- Set open price for Risk management calculation OpenPrice = CSymbol.Bid(); //--- Set close price for Risk management calculation ClosePrice = SL; //--- Set Trade magic number Trade.SetExpertMagicNumber(Magic); //--- Check if there are any open trades or opened deals already if(!OpenTrade(POSITION_TYPE_SELL,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_SELL,Magic,COMMENT)) { //--- Iterate through the Lot-sizes if they're more than max-lot for(double i=Volume();i>=CSymbol.LotsMin();i-=CSymbol.LotsMax()) { //--- normalize Lot-size NormalizeLotsize(i); //--- Open trade with a Lot-size not more than max-lot TradeResult = Trade.Sell((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,CSymbol.GetSymbolName(),CSymbol.Bid(),SL,TP,COMMENT); //--- Check if trade failed. if(!TradeResult) { return TradeResult; } } } else { //--- Trade failed because there is an open trade or opened deal return false; } //--- Return trade result. return TradeResult; }
Expert de Trading de Notícias
Temos novas entradas para o expert, já vimos as explicações na introdução.
//--- width and height of the canvas (used for drawing) #define IMG_WIDTH 200 #define IMG_HEIGHT 100 //--- enable to set color format ENUM_COLOR_FORMAT clr_format=COLOR_FORMAT_XRGB_NOALPHA; //--- drawing array (buffer) uint ExtImg[IMG_WIDTH*IMG_HEIGHT]; #include "News.mqh" CNews NewsObject;//Class object for News #include "TimeManagement.mqh" CTimeManagement CTM;//Class object for Time Management #include "WorkingWithFolders.mqh" CFolders Folder;//Class object for Folders #include "ChartProperties.mqh" CChartProperties Chart;//Class object for Chart Properties #include "RiskManagement.mqh" CRiskManagement CRisk;//Class object for Risk Management #include "CommonGraphics.mqh" CCommonGraphics *CGraphics;//Class pointer object for Common Graphics CCandleProperties *CP;//Class pointer object for Candle Properties #include "TradeManagement.mqh" CTradeManagement Trade;//Class object for Trade Management //--- used to separate Input Menu enum iSeparator { Delimiter//__________________________ }; //--- for chart color Mode selection enum DisplayMode { Display_LightMode,//LIGHT MODE Display_DarkMode//DARK MODE }; sinput group "+--------| DISPLAY |--------+"; sinput DisplayMode iDisplayMode=Display_LightMode;//CHART COLOUR MODE sinput Choice iDisplay_NewsInfo=Yes;//DISPLAY NEWS INFO sinput Choice iDisplay_EventObj=Yes;//DISPLAY EVENT OBJ sinput Choice iDisplay_Spread=Yes;//DISPLAY SPREAD RATING sinput Choice iDisplay_Date=Yes;//DISPLAY DATE sinput group ""; sinput group "+--------| DST SCHEDULE |--------+"; input DSTSchedule ScheduleDST=AutoDst_Selection;//SELECT DST OPTION sinput iSeparator iCustomSchedule=Delimiter;//__________________________ sinput iSeparator iCustomScheduleL=Delimiter;//CUSTOM DST input DST_type CustomSchedule=DST_NONE;//SELECT CUSTOM DST sinput group ""; sinput group "+--------| RISK MANAGEMENT |--------+"; input RiskOptions RISK_Type=MINIMUM_LOT;//SELECT RISK OPTION input RiskFloor RISK_Mini=RiskFloorMin;//RISK FLOOR input double RISK_Mini_Percent=75;//MAX-RISK [100<-->0.01]% input RiskCeil RISK_Maxi=RiskCeilMax;//RISK CEILING sinput iSeparator iRisk_1=Delimiter;//__________________________ sinput iSeparator iRisk_1L=Delimiter;//PERCENTAGE OF [BALANCE | FREE-MARGIN] input double Risk_1_PERCENTAGE=3;//[100<-->0.01]% sinput iSeparator iRisk_2=Delimiter;//__________________________ sinput iSeparator iRisk_2L=Delimiter;//AMOUNT PER [BALANCE | FREE-MARGIN] input double Risk_2_VALUE=1000;//[BALANCE | FREE-MARGIN] input double Risk_2_AMOUNT=10;//EACH AMOUNT sinput iSeparator iRisk_3=Delimiter;//__________________________ sinput iSeparator iRisk_3L=Delimiter;//LOTSIZE PER [BALANCE | FREE-MARGIN] input double Risk_3_VALUE=1000;//[BALANCE | FREE-MARGIN] input double Risk_3_LOTSIZE=0.1;//EACH LOTS(VOLUME) sinput iSeparator iRisk_4=Delimiter;//__________________________ sinput iSeparator iRisk_4L=Delimiter;//CUSTOM LOTSIZE input double Risk_4_LOTSIZE=0.01;//LOTS(VOLUME) sinput iSeparator iRisk_5=Delimiter;//__________________________ sinput iSeparator iRisk_5L=Delimiter;//PERCENTAGE OF MAX-RISK input double Risk_5_PERCENTAGE=1;//[100<-->0.01]% sinput group ""; sinput group "+--------| NEWS SETTINGS |--------+"; input Calendar_Importance iImportance=Calendar_Importance_High;//CALENDAR IMPORTANCE input Event_Frequency iFrequency=Event_Frequency_ALL;//EVENT FREQUENCY input Event_Sector iSector=Event_Sector_ALL;//EVENT SECTOR input Event_Type iType=Event_Type_Indicator;//EVENT TYPE input Event_Currency iCurrency=Event_Currency_Symbol;//EVENT CURRENCY sinput group ""; sinput group "+--------| TRADE SETTINGS |--------+"; input uint iStoploss=500;//STOPLOSS [0=NONE] input uint iTakeprofit=500;//TAKEPROFIT [0=NONE] input uint iSecondsPreEvent=5;//PRE-ENTRY SEC input DayOfTheWeek TradingDay=AllDays;//TRADING DAY OF WEEK sinput group ""; //--- to keep track of start-up time datetime Startup_date;
Na função OnInit Integer abaixo, passamos por diferentes procedimentos ao configurar o expert para negociar, seja no testador de estratégia ou não.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Assign if in LightMode or not isLightMode=(iDisplayMode==Display_LightMode)?true:false; //--- call function for common initialization procedure InitCommon(); //--- store Init result int InitResult; if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester { //--- initialization procedure outside strategy tester InitResult=InitNonTester(); } else { //--- initialization procedure inside strategy tester InitResult=InitTester(); } //--- Create DB in memory NewsObject.CreateEconomicDatabaseMemory(); //--- Initialize Common graphics class pointer object CGraphics = new CCommonGraphics(Answer(iDisplay_Date),Answer(iDisplay_Spread),Answer(iDisplay_NewsInfo),Answer(iDisplay_EventObj)); CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create chart objects //--- Initialize Candle properties pointer object CP = new CCandleProperties(); //--- Store start-up time. Startup_date = TimeTradeServer(); //--- return Init result return InitResult; }
Na função abaixo, inicializamos propriedades tanto para o testador de estratégia quanto para o ambiente de negociação normal.
//+------------------------------------------------------------------+ //|function for common initialization procedure | //+------------------------------------------------------------------+ void InitCommon() { //Initializing CRiskManagement variable for Risk options RiskProfileOption = RISK_Type; //Initializing CRiskManagement variable for Risk floor RiskFloorOption = RISK_Mini; //Initializing CRiskManagement variable for RiskFloorMax RiskFloorPercentage = (RISK_Mini_Percent>100)?100: (RISK_Mini_Percent<0.01)?0.01:RISK_Mini_Percent;//Percentage cannot be more than 100% or less than 0.01% //Initializing CRiskManagement variable for Risk ceiling RiskCeilOption = RISK_Maxi; //Initializing CRiskManagement variable for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) Risk_Profile_1 = (Risk_1_PERCENTAGE>100)?100: (Risk_1_PERCENTAGE<0.01)?0.01:Risk_1_PERCENTAGE;//Percentage cannot be more than 100% or less than 0.01% //Initializing CRiskManagement variables for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) Risk_Profile_2.RiskAmountBoF = Risk_2_VALUE; Risk_Profile_2.RiskAmount = Risk_2_AMOUNT; //Initializing CRiskManagement variables for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) Risk_Profile_3.RiskLotBoF = Risk_3_VALUE; Risk_Profile_3.RiskLot = Risk_3_LOTSIZE; //Initializing CRiskManagement variable for Risk option (CUSTOM LOTSIZE) Risk_Profile_4 = Risk_4_LOTSIZE; //Initializing CRiskManagement variable for Risk option (PERCENTAGE OF MAX-RISK) Risk_Profile_5 = (Risk_5_PERCENTAGE>100)?100: (Risk_5_PERCENTAGE<0.01)?0.01:Risk_5_PERCENTAGE;//Percentage cannot be more than 100% or less than 0.01% //--- Initializing DST Schedule variables MyDST = ScheduleDST; MySchedule = CustomSchedule; //--- Initializing News filter variables myFrequency=iFrequency; myImportance=iImportance; mySector=iSector; myType=iType; myCurrency=iCurrency; Chart.ChartRefresh();//Load chart configurations }
A função abaixo será inicializada apenas para o ambiente de negociação normal.
//+------------------------------------------------------------------+ //|function for initialization procedure outside strategy tester | //+------------------------------------------------------------------+ int InitNonTester() { //--- Check if in Strategy tester! if(MQLInfoInteger(MQL_TESTER)) { //--- Initialization failed. return(INIT_SUCCEEDED); } //--- create OBJ_BITMAP_LABEL object for drawing ObjectCreate(0,"STATUS",OBJ_BITMAP_LABEL,0,0,0); ObjectSetInteger(0,"STATUS",OBJPROP_XDISTANCE,5); ObjectSetInteger(0,"STATUS",OBJPROP_YDISTANCE,22); //--- specify the name of the graphical resource ObjectSetString(0,"STATUS",OBJPROP_BMPFILE,"::PROGRESS"); uint w,h; // variables for receiving text string sizes uint x,y; // variables for calculation of the current coordinates of text string anchor points /* In the Do while loop below, the code will check if the terminal is connected to the internet. Se o programa for interrompido, o loop será interrompido. Se o programa não for interrompido e o terminal estiver conectado à internet, a função CreateEconomicDatabase será chamada do objeto do arquivo de cabeçalho News.mqh chamado NewsObject e o loop será interrompido quando chamado. */ bool done=false; do { //--- clear the drawing buffer array ArrayFill(ExtImg,0,IMG_WIDTH*IMG_HEIGHT,0); if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { //-- integer dots used as a loading animation static int dots=0; //--- set the font TextSetFont("Arial",-150,FW_EXTRABOLD,0); TextGetSize("Waiting",w,h);//get text width and height values //--- calculate the coordinates of the 'Waiting' text x=10;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically //--- output the 'Waiting' text to ExtImg[] buffer TextOut("Waiting",x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CSymbol.Background()),clr_format); //--- calculate the coordinates for the dots after the 'Waiting' text x=w+13;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically TextSetFont("Arial",-160,FW_EXTRABOLD,0); //--- output of dots to ExtImg[] buffer TextOut(StringSubstr("...",0,dots),x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CSymbol.Background()),clr_format); //--- update the graphical resource ResourceCreate("::PROGRESS",ExtImg,IMG_WIDTH,IMG_HEIGHT,0,0,IMG_WIDTH,clr_format); //--- force chart update Chart.Redraw(); dots=(dots==3)?0:dots+1; //-- Notify user that program is waiting for connection Print("Waiting for connection..."); Sleep(500); continue; } else { //--- set the font TextSetFont("Arial",-120,FW_EXTRABOLD,0); TextGetSize("Getting Ready",w,h);//get text width and height values x=20;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically //--- output the text 'Getting Ready...' to ExtImg[] buffer TextOut("Getting Ready...",x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CSymbol.Background()),clr_format); //--- update the graphical resource ResourceCreate("::PROGRESS",ExtImg,IMG_WIDTH,IMG_HEIGHT,0,0,IMG_WIDTH,clr_format); //--- force chart update Chart.Redraw(); //-- Notify user that connection is successful Print("Connection Successful!"); NewsObject.CreateEconomicDatabase();//calling the database create function done=true; } } while(!done&&!IsStopped()); //-- Delete chart object ObjectDelete(0,"STATUS"); //-- force chart to update Chart.Redraw(); //--- Initialization succeeded. return(INIT_SUCCEEDED); }
A função abaixo será inicializada apenas para o ambiente do testador de estratégia.
//+------------------------------------------------------------------+ //|function for initialization procedure inside strategy tester | //+------------------------------------------------------------------+ int InitTester() { //--- Check if not in Strategy tester! if(!MQLInfoInteger(MQL_TESTER)) { //--- Initialization failed. return(INIT_SUCCEEDED); } //Checks whether the database file exists if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON)) { //--- Warning messages Print("Necessary Files Do not Exist!"); Print("Run Program outside of the Strategy Tester"); Print("Necessary Files Should be Created First"); //--- Initialization failed. return(INIT_FAILED); } else { //Checks whether the latest database date includes the time and date being tested datetime latestdate = CTM.TimeMinusOffset(NewsObject.GetLatestNewsDate(),CTM.DaysS());//Day before the latest recorded time in the database if(latestdate<TimeTradeServer()) { Print("Necessary Files outdated!"); Print("To Update Files: Run Program outside of the Strategy Tester"); } Print("Database Dates End at: ",latestdate); PrintFormat("Dates after %s will not be available for backtest",TimeToString(latestdate)); } //--- Initialization succeeded. return(INIT_SUCCEEDED); }
A função abaixo será executada em cada novo tick.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Run procedures Execution(); }
Nesta função abaixo, chamamos todas as funções que tornarão o expert funcional. Nem toda função precisa ser executada a cada tick, então chamamos apenas algumas funções em cada nova vela específica, por exemplo, a cada vela diária. Isso ajuda no desempenho e reduz chamadas de funções desnecessárias e o uso de recursos.
//+------------------------------------------------------------------+ //|Execute program procedures | //+------------------------------------------------------------------+ void Execution() { //--- Update realtime Graphic every 1 min if(CP.NewCandle(1,PERIOD_M1)) { CGraphics.Block_2_Realtime(iSecondsPreEvent); } //--- function to open trades EnterTrade(); //--- Check if not start-up date if(!CTM.DateisToday(Startup_date)) { //--- Run every New Daily Candle if(CP.NewCandle(2,PERIOD_D1)) { //--- Check if not in strategy tester if(!MQLInfoInteger(MQL_TESTER)) { //--- Update/Create DB in Memory NewsObject.CreateEconomicDatabaseMemory(); } CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create/Re-create chart objects //--- Update Realtime Graphics CGraphics.Block_2_Realtime(iSecondsPreEvent); } //--- Check if not in strategy tester if(!MQLInfoInteger(MQL_TESTER)) { //--- Run every New Hourly Candle if(CP.NewCandle(3,PERIOD_H1)) { //--- Check if DB in Storage needs an update if(NewsObject.UpdateRecords()) { //--- initialization procedure outside strategy tester InitNonTester(); } } } } else { //--- Run every New Daily Candle if(CP.NewCandle(4,PERIOD_D1)) { //--- Update Event objects on chart CGraphics.NewsEvent(); } } }
A função abaixo será responsável por abrir trades para ordens de Mercado baseadas no impacto do evento e na moeda do evento. Se a moeda do evento for igual à moeda do Lucro e o tipo de impacto for CALENDAR_IMPACT_NEGATIVE, abrimos um trade de compra, pois assumimos que a moeda do Lucro enfraquecerá durante o evento de notícias. Se a moeda do evento for igual à moeda do Lucro e o tipo de impacto for CALENDAR_IMPACT_POSITIVE, abrimos um trade de venda, pois assumimos que a moeda do Lucro se fortalecerá durante o evento de notícias.
//+------------------------------------------------------------------+ //|function to open trades | //+------------------------------------------------------------------+ void EnterTrade() { //--- static variable for storing upcoming event Impact value static ENUM_CALENDAR_EVENT_IMPACT Impact=CALENDAR_IMPACT_NA; //--- Check if Upcoming news date has passed and if upcoming news is not null and if new minute candle has formed. if(datetime(UpcomingNews.EventDate)<TimeTradeServer()&&UpcomingNews.CountryName!=NULL&&CP.NewCandle(5,PERIOD_M1)) { //--- Update for next upcoming news NewsObject.EconomicNextEvent(); //--- Get impact value for upcoming news Impact=NewsObject.GetImpact(); } //--- Check if upcoming news date is about to occur and if it is the trading day of week if(CTM.TimePreEvent(CTM.TimeMinusOffset(datetime(UpcomingNews.EventDate),(iSecondsPreEvent==0)?1:iSecondsPreEvent) ,datetime(UpcomingNews.EventDate)) &&CTM.isDayOfTheWeek(TradingDay)) { //--- Check each Impact value type switch(Impact) { //--- When Impact news is negative case CALENDAR_IMPACT_NEGATIVE: //--- Check if profit currency is news event currency if(UpcomingNews.EventCurrency==CSymbol.CurrencyProfit()) { //--- Open buy trade with Event id as Magic number Trade.Buy(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } else { //--- Open sell trade with Event id as Magic number Trade.Sell(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } break; //--- When Impact news is positive case CALENDAR_IMPACT_POSITIVE: //--- Check if profit currency is news event currency if(UpcomingNews.EventCurrency==CSymbol.CurrencyProfit()) { //--- Open sell trade with Event id as Magic number Trade.Sell(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } else { //--- Open buy trade with Event id as Magic number Trade.Buy(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } break; //--- Unknown default: break; } } }
Conclusão
Neste artigo, passamos por como adicionar um banco de dados na memória e criar visualizações adicionais para fornecer mais informações sobre os eventos no calendário econômico MQL5. Criamos objetos gráficos adicionais no gráfico para exibir informações sobre o próximo evento, além de implementar um recurso de modo escuro. Além disso, adicionamos opções de entrada relevantes para o usuário/operador filtrar os dados das notícias de acordo com suas preferências, bem como entradas do Expert Advisor para negociação. O artigo também fornece uma explicação de como abrimos ordens de mercado com base no impacto do evento e como o impacto do evento é relevante para a nossa estratégia de negociação.
Estou aberto a ouvir suas opiniões, e qualquer opinião compartilhada será apreciada. No próximo artigo, adicionaremos mais funcionalidades às entradas de notícias para atender a eventos econômicos individuais e negociação usando ordens pendentes para mais flexibilidade, além de negociação que não requer impacto do evento. Obrigado pela leitura!
Video
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15359
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- 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
Muito obrigado
Laurent
No entanto, não quero visualizar este
Os comentários não quero visualizá-los.
Obrigado pelo artigo, muito bom.
No entanto, não quero visualizar isso
Os comentários não quero visualizá-los.