DISCLAIMER – USO DE CÓDIGOS MQL5

Todo o conteúdo disponibilizado nesta página, incluindo, mas não se limitando a códigos-fonte em linguagem MQL5, exemplos de implementação, funções, rotinas, módulos e estruturas de robôs de negociação automatizada, tem finalidade exclusivamente educacional, acadêmica e demonstrativa.

Os códigos aqui apresentados NÃO devem, em hipótese alguma, ser utilizados em contas reais de negociação, seja parcial ou integralmente, sob pena de total responsabilidade do usuário por quaisquer perdas financeiras, danos patrimoniais, falhas operacionais, mau funcionamento de plataformas, bloqueios de conta, inconsistências de execução, slippage, requotes, falhas de corretoras ou quaisquer outros riscos inerentes à atividade de trading automatizado.

O uso dos códigos é estritamente permitido apenas em ambiente simulado (Conta de Demonstração – DEMO) do MetaTrader 5 (MT5), com objetivo de estudo, aprendizado, testes controlados e validação técnica de conceitos de programação e lógica de mercado.

O proprietário do site, bem como seus desenvolvedores, autores, colaboradores e representantes legais:

  • Não se responsabilizam por perdas financeiras de qualquer natureza;

  • Não oferecem garantia de rentabilidade, desempenho, estabilidade, integridade ou adequação dos códigos a qualquer finalidade específica;

  • Não prestam consultoria financeira, de investimentos ou recomendações de trading;

  • Não se responsabilizam por decisões operacionais tomadas com base direta ou indireta nos códigos aqui apresentados.

O usuário declara estar ciente de que operações no mercado financeiro envolvem riscos elevados, podendo resultar na perda total do capital investido, e que qualquer utilização dos códigos fora do ambiente educacional simulado é feita por conta e risco exclusivamente do usuário.

Ao acessar, copiar, estudar, modificar ou executar qualquer trecho de código disponibilizado nesta página, o usuário declara concordar integralmente com os termos deste aviso de isenção de responsabilidade (Disclaimer).

Caso o usuário não concorde com qualquer dos termos acima, deverá interromper imediatamente o acesso a este conteúdo e abster-se de utilizar os códigos aqui disponibilizados.

//-----------------------//
// 5. Utilitários
//------------------------//

// 5.1 DESENHAR SUPORTES E RESISTÊNCIAS.

// 5.1.1 Função para identificar topos e fundos em qualquer timeframe
void IdentificarToposFundos(ENUM_TIMEFRAMES timeframe, double &topos[], double &fundos[], datetime &time_topos[], datetime &time_fundos[])
{
MqlRates candles[];
ArraySetAsSeries(candles, true);

// Copiar os últimos 30 candles do timeframe especificado
int copied = CopyRates(_Symbol, timeframe, 0, 30, candles);
if(copied < 24) return;

// Procurar nos últimos 24 candles
int limit = (copied > 24) ? 24 : copied - 5;

for(int i = limit; i >= 5; i--)
{
// Verificar padrão de TOPO (candle do meio tem o maior high)
if(candles[i-2].high > candles[i-3].high && // maior que o primeiro à esquerda
candles[i-2].high > candles[i-4].high && // maior que o segundo à esquerda
candles[i-2].high > candles[i-1].high && // maior que o primeiro à direita
candles[i-2].high > candles[i].high) // maior que o segundo à direita
{
// Deslocar os valores antigos
for(int j = 23; j > 0; j--)
{
topos[j] = topos[j-1];
time_topos[j] = time_topos[j-1];
}

// Armazenar novo topo
topos[0] = candles[i-3].high;
time_topos[0] = candles[i-3].time;
}

// Verificar padrão de FUNDO (candle do meio tem o menor low)
if(candles[i-2].low < candles[i-3].low && // menor que o primeiro à esquerda
candles[i-2].low < candles[i-4].low && // menor que o segundo à esquerda
candles[i-2].low < candles[i-1].low && // menor que o primeiro à direita
candles[i-2].low < candles[i].low) // menor que o segundo à direita
{
// Deslocar os valores antigos
for(int j = 23; j > 0; j--)
{
fundos[j] = fundos[j-1];
time_fundos[j] = time_fundos[j-1];
}

// Armazenar novo fundo
fundos[0] = candles[i-2].low;
time_fundos[0] = candles[i-2].time;
}
}
}

// 5.1.2 Função para obter suporte e resistência atuais
void ObterSuporteResistenciaAtual(ENUM_TIMEFRAMES timeframe, double &topos[], double &fundos[], double &suporte, double &resistencia, double precoAtual)
{
suporte = 0;
resistencia = 0;

// Encontrar o suporte mais recente abaixo do preço atual
for(int i = 0; i < 24; i++)
{
if(fundos[i] > 0 && fundos[i] < precoAtual)
{
if(suporte == 0 || fundos[i] > suporte)
{
suporte = fundos[i];
}
}
}

// Encontrar a resistência mais recente acima do preço atual
for(int i = 0; i < 24; i++)
{
if(topos[i] > 0 && topos[i] > precoAtual)
{
if(resistencia == 0 || topos[i] < resistencia)
{
resistencia = topos[i];
}
}
}
}

// 5.1.3 Função para desenhar linhas de suporte e resistência
void DesenharSuportesResistencias()
{
double precoAtual = SymbolInfoDouble(_Symbol, SYMBOL_BID);

// Configurações dos timeframes
struct TimeframeConfigTF {
ENUM_TIMEFRAMES tf;
string nome;
color cor;
int estilo;
};

TimeframeConfigTF configs[5] = {
{PERIOD_M15, "M15", clrWhite, STYLE_DOT},
{PERIOD_H1, "H1", clrYellow, STYLE_DOT},
{PERIOD_H4, "H4", clrOrange, STYLE_DOT},
{PERIOD_D1, "D1", clrRed, STYLE_SOLID},
{PERIOD_W1, "W1", clrRoyalBlue, STYLE_SOLID}
};

// Primeiro, identificar topos e fundos para cada timeframe
IdentificarToposFundos(PERIOD_M15, topo_M15, fundo_M15, time_topo_M15, time_fundo_M15);
IdentificarToposFundos(PERIOD_H1, topo_H1, fundo_H1, time_topo_H1, time_fundo_H1);
IdentificarToposFundos(PERIOD_H4, topo_H4, fundo_H4, time_topo_H4, time_fundo_H4);
IdentificarToposFundos(PERIOD_D1, topo_D1, fundo_D1, time_topo_D1, time_fundo_D1);
IdentificarToposFundos(PERIOD_W1, topo_W1, fundo_W1, time_topo_W1, time_fundo_W1);

// Para cada timeframe, obter e desenhar suporte/resistência
for(int i = 0; i < 5; i++)
{
double suporte = 0, resistencia = 0;

switch(configs[i].tf)
{
case PERIOD_M15:
ObterSuporteResistenciaAtual(configs[i].tf, topo_M15, fundo_M15, suporte, resistencia, precoAtual);
break;
case PERIOD_H1:
ObterSuporteResistenciaAtual(configs[i].tf, topo_H1, fundo_H1, suporte, resistencia, precoAtual);
break;
case PERIOD_H4:
ObterSuporteResistenciaAtual(configs[i].tf, topo_H4, fundo_H4, suporte, resistencia, precoAtual);
break;
case PERIOD_D1:
ObterSuporteResistenciaAtual(configs[i].tf, topo_D1, fundo_D1, suporte, resistencia, precoAtual);
break;
case PERIOD_W1:
ObterSuporteResistenciaAtual(configs[i].tf, topo_W1, fundo_W1, suporte, resistencia, precoAtual);
break;
}

// Desenhar suporte se encontrado e abaixo do preço atual
if(suporte > 0 && suporte < precoAtual)
{
string linhaNome = configs[i].nome + " Suporte";
string labelNome = configs[i].nome + " Suporte Label";

// Remover objetos antigos
ObjectDelete(0, linhaNome);
ObjectDelete(0, labelNome);

// Criar linha de suporte
ObjectCreate(0, linhaNome, OBJ_HLINE, 0, 0, suporte);
ObjectSetInteger(0, linhaNome, OBJPROP_COLOR, configs[i].cor);
ObjectSetInteger(0, linhaNome, OBJPROP_STYLE, configs[i].estilo);
ObjectSetInteger(0, linhaNome, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, linhaNome, OBJPROP_BACK, true);

// Criar label do suporte
ObjectCreate(0, labelNome, OBJ_TEXT, 0, TimeCurrent() + 2100, suporte);
ObjectSetString(0, labelNome, OBJPROP_TEXT, configs[i].nome + " Suporte " + DoubleToString(suporte, _Digits));
ObjectSetInteger(0, labelNome, OBJPROP_COLOR, configs[i].cor);
ObjectSetInteger(0, labelNome, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
ObjectSetInteger(0, labelNome, OBJPROP_BACK, false);
ObjectSetDouble(0, labelNome, OBJPROP_PRICE, suporte - 100 * _Point); // Posiciona logo acima da linha
ObjectSetInteger(0, labelNome, OBJPROP_FONTSIZE, 8); // Fonte pequena
}

// Desenhar resistência se encontrada e acima do preço atual
if(resistencia > 0 && resistencia > precoAtual)
{
string linhaNome = configs[i].nome + " Resistência";
string labelNome = configs[i].nome + " Resistência Label";

// Remover objetos antigos
ObjectDelete(0, linhaNome);
ObjectDelete(0, labelNome);

// Criar linha de resistência
ObjectCreate(0, linhaNome, OBJ_HLINE, 0, 0, resistencia);
ObjectSetInteger(0, linhaNome, OBJPROP_COLOR, configs[i].cor);
ObjectSetInteger(0, linhaNome, OBJPROP_STYLE, configs[i].estilo);
ObjectSetInteger(0, linhaNome, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, linhaNome, OBJPROP_BACK, true);

// Criar label da resistência
ObjectCreate(0, labelNome, OBJ_TEXT, 0, TimeCurrent() + 2100, resistencia);
ObjectSetString(0, labelNome, OBJPROP_TEXT, configs[i].nome + " Resistência " + DoubleToString(resistencia, _Digits));
ObjectSetInteger(0, labelNome, OBJPROP_COLOR, configs[i].cor);
ObjectSetInteger(0, labelNome, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
ObjectSetInteger(0, labelNome, OBJPROP_BACK, false);
ObjectSetDouble(0, labelNome, OBJPROP_PRICE, resistencia + 200 * _Point); // Posiciona logo acima da linha
ObjectSetInteger(0, labelNome, OBJPROP_FONTSIZE, 8); // Fonte pequena
}
}
}

// 5.1.4 Função para limpar objetos gráficos antigos
void LimparObjetosAntigos()
{
string prefixos[5] = {"M15", "H1", "H4", "D1", "W1"};
string sufixos[2] = {"Suporte", "Resistência"};

for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 2; j++)
{
string nomeLinha = prefixos[i] + " " + sufixos[j];
string nomeLabel = prefixos[i] + " " + sufixos[j] + " Label";

ObjectDelete(0, nomeLinha);
ObjectDelete(0, nomeLabel);
}
}
}

// 5.1.5 Função para verificar se é um novo candle
bool IsNewCandle(ENUM_TIMEFRAMES periodo)
{
static datetime lastCandleTime = 0;
datetime currentCandleTime = iTime(_Symbol, periodo, 0);

if(currentCandleTime != lastCandleTime)
{
lastCandleTime = currentCandleTime;
return true;
}
return false;
}

// 5.2 Conta de Demonstração.
bool Conta_Demonstracao() {
// Verifica se a conta é de demonstração.
ENUM_ACCOUNT_TRADE_MODE accountType = (ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
if (accountType == ACCOUNT_TRADE_MODE_DEMO) {
return true; // É conta demo.
} else {
Alert("AVISO: Este robô só opera em contas DEMO! Operação bloqueada.");
return false; // É conta real ou outro tipo.
}
}

// 5.3 Descricao_Erros(), retorna a descrição de um código de erro.
string GetRetcodeDescription(int retcode) {
switch(retcode) {
case 10004: return "Requisição de trade realizada";
case 10006: return "Requisição enviada para o servidor";
case 10007: return "Ordem sendo processada";
case 10008: return "Ordem colocada";
case 10009: return "Requisição concluída";
case 10010: return "Ordem parcialmente preenchida";
case 10011: return "Ordem preenchida";
case 10012: return "Ordem cancelada";
case 10013: return "Requisição cancelada";
case 10014: return "Colocação de ordem rejeitada";
case 10015: return "Modificação rejeitada";
case 10016: return "Cancelamento rejeitado";
case 10017: return "Requisição expirada";
case 10018: return "Requisição malformada";
case 10019: return "Requisição inválida";
case 10020: return "Tipo de preenchimento inválido";
case 10021: return "Sem conexão com o servidor de trade";
case 10022: return "Operação muito frequente";
case 10023: return "Margem insuficiente";
case 10024: return "Mercado fechado";
case 10025: return "Requisição bloqueada";
case 10026: return "Ordem ou posição não encontrada";
case 10027: return "Volume inválido";
case 10028: return "Preço inválido";
case 10029: return "Stop Loss inválido";
case 10030: return "Take Profit inválido";
default: return "Erro desconhecido (" + IntegerToString(retcode) + ")";
}
}

Código Bloco 5