
Construindo um Modelo de Restrição de Tendência com Candlestick (Parte 8): Desenvolvimento de Expert Advisor (I)
Conteúdo
- Introdução
- Solução para os desafios anteriores sobre o desenho de retângulos de risco e recompensado
- Criando um Expert Advisor que funcione com base em um indicadorr
- Testando
- Conclusão
Introdução
O software MetaEditor inclui um compilador que gerencia efetivamente os erros detectados durante as tentativas de perfilamento. Esta ferramenta me ajudou a descobrir por que a versão anterior não conseguiu exibir os retângulos de risco e recompensa como esperado. Embora o programa tenha compilado com sucesso, o problema não estava no código em si. O desafio estava no fato de que nada foi exibido dentro do intervalo dos candlesticks de retrospectiva, principalmente devido a especificidades técnicas. - O valor de retrospectiva do candle foi definido muito alto, em 5.000 barras por padrão.
- Ter múltiplos buffers em um único programa aumenta a complexidade dos cálculos, o que pode retardar a exibição da janela de gráfico do indicador.
Após discutirmos brevemente como resolvemos os problemas encontrados, vamos seguir para o principal objetivo deste artigo: desenvolver um Expert Advisor com base no Indicador de Restrição de Tendência refinado. Abaixo está uma imagem mostrando como um script separado resolveu com sucesso o problema que originalmente pretendíamos resolver com o indicador principal.
Retângulos de risco e recompensa desenhados automaticamente usando o retângulo
Solução para os desafios anteriores sobre o desenho de retângulos de risco e recompensado
Para resolver os desafios no programa do indicador:- Reduzimos o período de retrospectiva de 5000 barras para 1000 barras, diminuindo significativamente a quantidade de dados a serem calculados.
- Nosso objetivo foi reduzir a carga de trabalho do programa criando um script independente como parte do conjunto de ferramentas. Este script verifica especificamente as condições tratadas pelo Buffer 6 e Buffer 7 no indicador. Assim que essas condições são atendidas, o script desenha os retângulos necessários de risco e recompensa e coloca linhas com rótulos de preço para o preço de entrada, Stop Loss e Take Profit. No entanto, é importante observar que o script realiza uma tarefa única e não executa continuamente. O usuário deve adicionar manualmente o script ao gráfico para visualizar os níveis de negociação representados pelos objetos desenhados e as marcações de preço.
Abaixo está uma imagem mostrando o lançamento do programa do script:
Script Trend Constraint R-R: Para desenhar o retângulo de risco e recompensa quando ocorre um cruzamento de Média Móvel
Ao isolar essa funcionalidade, garantimos que nosso indicador funcione sem problemas, evitando qualquer congelamento do computador ou do terminal de negociação. Incorporar retângulos de risco e recompensa e marcar os níveis de saída permite que os traders avaliem visualmente a direção e os alvos da negociação com antecedência, possibilitando negociações manuais sem a necessidade de um Expert Advisor. O programa do script com a lógica necessária funcionou perfeitamente. Aqui está nosso programa completo de script.//+------------------------------------------------------------------+ //| Trend Constraint R-R.mq5 | //| Script program | //+------------------------------------------------------------------+ #property strict #property script_show_inputs #property copyright "2024 Clemence Benjamin" #property version "1.00" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property description "A script program for drawing risk and rewars rectangles based on Moving Averaage crossover." //--- input parameters input int FastMAPeriod = 14; input int SlowMAPeriod = 50; input double RiskHeightPoints = 5000.0; // Default height of the risk rectangle in points input double RewardHeightPoints = 15000.0; // Default height of the reward rectangle in points input color RiskColor = clrIndianRed; // Default risk color input color RewardColor = clrSpringGreen; // Default reward color input int MaxBars = 500; // Maximum bars to process input int RectangleWidth = 10; // Width of the rectangle in bars input bool FillRectangles = true; // Option to fill rectangles input int FillTransparency = 128; // Transparency level (0-255), 128 is 50% transparency //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- delete existing rectangles and lines DeleteExistingObjects(); //--- declare and initialize variables int i, limit; double FastMA[], SlowMA[]; double closePrice, riskLevel, rewardLevel; //--- calculate moving averages if (iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0 || iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0) { Print("Error in calculating moving averages."); return; } ArraySetAsSeries(FastMA, true); ArraySetAsSeries(SlowMA, true); CopyBuffer(iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE), 0, 0, MaxBars, FastMA); CopyBuffer(iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE), 0, 0, MaxBars, SlowMA); limit = MathMin(ArraySize(FastMA), ArraySize(SlowMA)); for (i = 1; i < limit - 1; i++) { //--- check for crossover if (FastMA[i] > SlowMA[i] && FastMA[i - 1] <= SlowMA[i - 1]) { //--- long position entry point (bullish crossover) closePrice = iClose(NULL, 0, i); riskLevel = closePrice + RiskHeightPoints * Point(); rewardLevel = closePrice - RewardHeightPoints * Point(); //--- draw risk rectangle DrawRectangle("Risk_" + IntegerToString(i), i, closePrice, i - RectangleWidth, riskLevel, RiskColor); //--- draw reward rectangle DrawRectangle("Reward_" + IntegerToString(i), i, closePrice, i - RectangleWidth, rewardLevel, RewardColor); //--- draw entry, stop loss, and take profit lines DrawPriceLine("Entry_" + IntegerToString(i), i, closePrice, clrBlue, "Entry: " + DoubleToString(closePrice, _Digits)); DrawPriceLine("StopLoss_" + IntegerToString(i), i, riskLevel, clrRed, "Stop Loss: " + DoubleToString(riskLevel, _Digits)); DrawPriceLine("TakeProfit_" + IntegerToString(i), i, rewardLevel, clrGreen, "Take Profit: " + DoubleToString(rewardLevel, _Digits)); } else if (FastMA[i] < SlowMA[i] && FastMA[i - 1] >= SlowMA[i - 1]) { //--- short position entry point (bearish crossover) closePrice = iClose(NULL, 0, i); riskLevel = closePrice - RiskHeightPoints * Point(); rewardLevel = closePrice + RewardHeightPoints * Point(); //--- draw risk rectangle DrawRectangle("Risk_" + IntegerToString(i), i, closePrice, i - RectangleWidth, riskLevel, RiskColor); //--- draw reward rectangle DrawRectangle("Reward_" + IntegerToString(i), i, closePrice, i - RectangleWidth, rewardLevel, RewardColor); //--- draw entry, stop loss, and take profit lines DrawPriceLine("Entry_" + IntegerToString(i), i, closePrice, clrBlue, "Entry: " + DoubleToString(closePrice, _Digits)); DrawPriceLine("StopLoss_" + IntegerToString(i), i, riskLevel, clrRed, "Stop Loss: " + DoubleToString(riskLevel, _Digits)); DrawPriceLine("TakeProfit_" + IntegerToString(i), i, rewardLevel, clrGreen, "Take Profit: " + DoubleToString(rewardLevel, _Digits)); } } } //+------------------------------------------------------------------+ //| Function to delete existing rectangles and lines | //+------------------------------------------------------------------+ void DeleteExistingObjects() { int totalObjects = ObjectsTotal(0, 0, -1); for (int i = totalObjects - 1; i >= 0; i--) { string name = ObjectName(0, i, 0, -1); if (StringFind(name, "Risk_") >= 0 || StringFind(name, "Reward_") >= 0 || StringFind(name, "Entry_") >= 0 || StringFind(name, "StopLoss_") >= 0 || StringFind(name, "TakeProfit_") >= 0) { ObjectDelete(0, name); } } } //+------------------------------------------------------------------+ //| Function to draw rectangles | //+------------------------------------------------------------------+ void DrawRectangle(string name, int startBar, double startPrice, int endBar, double endPrice, color rectColor) { if (ObjectFind(0, name) >= 0) ObjectDelete(0, name); datetime startTime = iTime(NULL, 0, startBar); datetime endTime = (endBar < 0) ? (TimeCurrent() + (PeriodSeconds() * (-endBar))) : iTime(NULL, 0, endBar); if (!ObjectCreate(0, name, OBJ_RECTANGLE, 0, startTime, startPrice, endTime, endPrice)) Print("Failed to create rectangle: ", name); // Set the color with transparency (alpha value) int alphaValue = FillTransparency; // Adjust transparency level (0-255) color fillColor = rectColor & 0x00FFFFFF | (alphaValue << 24); // Combine alpha with RGB ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor); ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, name, OBJPROP_BACK, true); // Set to background if (FillRectangles) { ObjectSetInteger(0, name, OBJPROP_COLOR, fillColor); // Fill color with transparency } else { ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor & 0x00FFFFFF); // No fill color } } //+------------------------------------------------------------------+ //| Function to draw price lines | //+------------------------------------------------------------------+ void DrawPriceLine(string name, int barIndex, double price, color lineColor, string labelText) { datetime time = iTime(NULL, 0, barIndex); datetime endTime = (barIndex - 2 * RectangleWidth < 0) ? (TimeCurrent() + (PeriodSeconds() * (-barIndex - 2 * RectangleWidth))) : iTime(NULL, 0, barIndex - 2 * RectangleWidth); // Extend line to the right if (!ObjectCreate(0, name, OBJ_TREND, 0, time, price, endTime, price)) Print("Failed to create price line: ", name); ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, name, OBJPROP_BACK, true); // Set to background // Create text label string labelName = name + "_Label"; if (ObjectFind(0, labelName) >= 0) ObjectDelete(0, labelName); if (!ObjectCreate(0, labelName, OBJ_TEXT, 0, endTime, price)) Print("Failed to create label: ", labelName); ObjectSetInteger(0, labelName, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, ANCHOR_LEFT); ObjectSetString(0, labelName, OBJPROP_TEXT, labelText); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 10); ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(0, labelName, OBJPROP_XOFFSET, 5); ObjectSetInteger(0, labelName, OBJPROP_YOFFSET, 0); }
Vamos discutir detalhadamente o desempenho do script antes de prosseguir com o desenvolvimento do Expert Advisor:
- Permitimos a personalização de aspectos-chave da estratégia de negociação definindo parâmetros de entrada. Oferecemos opções para ajustar os períodos das médias móveis rápidas e lentas, definir as dimensões e cores dos retângulos de risco e recompensa, determinar o número máximo de barras a serem processadas e escolher se os retângulos serão preenchidos com cor. Essa configuração permite que o script seja adaptado a diferentes estratégias de negociação de acordo com as preferências do usuário e formou a seção de parâmetros de entrada do nosso programa:
//---- Input Parameters input int FastMAPeriod = 14; input int SlowMAPeriod = 50; input double RiskHeightPoints = 5000.0; input double RewardHeightPoints = 15000.0; input color RiskColor = clrIndianRed; input color RewardColor = clrSpringGreen; input int MaxBars = 500; input int RectangleWidth = 10; input bool FillRectangles = true; input int FillTransparency = 128;
- Na função (OnStart), garantimos que o gráfico permanecesse limpo programando o script para primeiro excluir qualquer retângulo de risco/recompensa e linhas de preço existentes. Em seguida, fizemos com que ele calculasse as médias móveis rápidas e lentas usando a função (iMA) e armazenasse esses valores em arrays para processamento posterior. À medida que o script percorre as barras no gráfico, estabelecemos condições para detectar cruzamentos de alta, onde a média móvel rápida cruzou acima da média lenta. Quando essas condições são atendidas, o script calcula o preço de entrada, o nível de risco (stop loss) e o nível de recompensa (take profit). Ele então desenha retângulos e linhas de preço no gráfico, marcando efetivamente esses níveis críticos de negociação, como explicaremos em trechos de subcódigo abaixo:
//----Onstart Function void OnStart() { //--- delete existing rectangles and lines DeleteExistingObjects(); //--- declare and initialize variables int i, limit; double FastMA[], SlowMA[]; double closePrice, riskLevel, rewardLevel; //--- calculate moving averages if (iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0 || iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0) { Print("Error in calculating moving averages."); return; }
- Para manter a clareza no gráfico, desenvolvemos a função "Excluir Objetos Existentes", que o script usa para remover qualquer objeto desenhado anteriormente relacionado aos sinais de negociação. Ao verificar os nomes de todos os objetos no gráfico, o script garantiu que apenas as informações mais recentes e relevantes fossem exibidas, mantendo o gráfico focado e livre de desordem:
//---- DeleteAllExistingObjects Function void DeleteExistingObjects() { int totalObjects = ObjectsTotal(0, 0, -1); for (int i = totalObjects - 1; i >= 0; i--) { string name = ObjectName(0, i, 0, -1); if (StringFind(name, "Risk_") >= 0 || StringFind(name, "Reward_") >= 0 || StringFind(name, "Entry_") >= 0 || StringFind(name, "StopLoss_") >= 0 || StringFind(name, "TakeProfit_") >= 0) { ObjectDelete(0, name); } } }
- Na função "Desenhar Retângulo", garantimos que o script pudesse representar visualmente os níveis de risco e recompensa, primeiro removendo quaisquer retângulos existentes com o mesmo nome para evitar duplicação. Em seguida, fizemos o script calcular os tempos de início e fim dos retângulos com base nos índices das barras e cuidadosamente definimos as cores e os níveis de transparência. Isso permitiu que os retângulos se destacassem no gráfico sem obscurecer outros detalhes importantes:
///---Draw rectangle function void DrawRectangle(string name, int startBar, double startPrice, int endBar, double endPrice, color rectColor) { if (ObjectFind(0, name) >= 0) ObjectDelete(0, name); datetime startTime = iTime(NULL, 0, startBar); datetime endTime = (endBar < 0) ? (TimeCurrent() + (PeriodSeconds() * (-endBar))) : iTime(NULL, 0, endBar); if (!ObjectCreate(0, name, OBJ_RECTANGLE, 0, startTime, startPrice, endTime, endPrice)) Print("Failed to create rectangle: ", name); int alphaValue = FillTransparency; color fillColor = rectColor & 0x00FFFFFF | (alphaValue << 24); ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor); ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, name, OBJPROP_BACK, true); if (FillRectangles) { ObjectSetInteger(0, name, OBJPROP_COLOR, fillColor); } else { ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor & 0x00FFFFFF); } }
- Finalmente, implementamos a função "Desenhar Linha de Preço" para instruir o script a adicionar linhas horizontais nos níveis de entrada, stop loss e take profit. O script estendeu essas linhas pelo gráfico e adicionou rótulos de texto que exibiam os níveis de preço correspondentes. Isso forneceu uma referência visual, permitindo que os usuários identificassem e gerenciassem rapidamente os pontos chave para negociações com base nos sinais gerados pelas médias móveis:
///---- Draw Price Lines Function void DrawPriceLine(string name, int barIndex, double price, color lineColor, string labelText) { datetime time = iTime(NULL, 0, barIndex); datetime endTime = (barIndex - 2 * RectangleWidth < 0) ? (TimeCurrent() + (PeriodSeconds() * (-barIndex - 2 * RectangleWidth))) : iTime(NULL, 0, barIndex - 2 * RectangleWidth); if (!ObjectCreate(0, name, OBJ_TREND, 0, time, price, endTime, price)) Print("Failed to create price line: ", name); ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, name, OBJPROP_BACK, true); string labelName = name + "_Label"; if (ObjectFind(0, labelName) >= 0) ObjectDelete(0, labelName); if (!ObjectCreate(0, labelName, OBJ_TEXT, 0, endTime, price)) Print("Failed to create label: ", labelName); ObjectSetInteger(0, labelName, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 10); ObjectSetString(0, labelName, OBJPROP_TEXT, labelText); ObjectSetInteger(0, labelName, OBJPROP_BACK, true); }
Agora, como parte do kit de negociação, esse script pode ser executado regularmente para ver os níveis de negociação visualizados, tanto do passado quanto do tempo atual. Agora, vamos seguir para a criação do nosso Expert Advisor exclusivo. Vou focar em explicar todo o desenvolvimento até o EA final funcionando. Neste artigo, vamos nos concentrar apenas em fazê-lo funcionar com o indicador que fizemos anteriormente, Trend Constraint V1.09.
Criando um Expert Advisor que funcione com base em um indicador:
Para criar um Expert Advisor (EA) em MQL5 usando um indicador personalizado, precisamos garantir que o arquivo do indicador personalizado (.ex5) esteja disponível na pasta "Indicators" dentro da plataforma MetaTrader 5, neste caso, é o Trend Constraint V1.09. Usando o MetaEditor, podemos escrever nosso EA, incorporando funções MQL5 para acessar os valores dos buffers do indicador. Utilizamos a função (iCustom()) para chamar o indicador personalizado dentro do EA, especificando os parâmetros necessários, como símbolo e período.
Para extrair dados dos buffers do indicador, usamos a função (CopyBuffer()), que recupera os valores do buffer que você pretende analisar para sinais de negociação. Depois, implementamos nossa lógica de negociação com base nesses valores de buffer, definindo condições para abrir, fechar ou modificar ordens de acordo com nossa estratégia. Integramos funcionalidades de gerenciamento de risco, como stop-loss e take-profit, para um gerenciamento prudente das negociações. Testamos o EA no MetaTrader 5 usando o Strategy Tester para avaliar seu desempenho e ajustar seus parâmetros. Por fim, verificamos a funcionalidade do EA em um ambiente de conta demo antes de migrar para a negociação ao vivo, para garantir que ele opere efetivamente em condições reais de mercado.
Podemos começar lançando um modelo de Expert Advisor no MetaEditor e depois desenvolvê-lo ou modificá-lo com base no exemplo mostrado nesta imagem:
Lançando um modelo de Expert Advisor no MetaEditor
Para guiá-lo na construção do nosso Expert Advisor (EA), vamos dividir o processo em seis etapas. À medida que avançamos, recomendo digitar os trechos de código diretamente no MetaEditor. Essa abordagem prática ajudará você a entender melhor e internalizar os passos, especialmente se você for novo no desenvolvimento de EAs.
1. Cabeçalho e Metadados
Na seção de cabeçalho, definimos o nome e o objetivo do nosso Expert Advisor (EA). Incluindo informações de copyright, um link para o nosso perfil e especificando a versão, garantimos que nosso EA seja facilmente identificável e rastreável. Esses metadados nos ajudam a entender a origem e o propósito do EA, especialmente quando ele é compartilhado ou modificado:
//You can replace the author details with yours. //+------------------------------------------------------------------+ //| Trend Constraint Expert.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property strict #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "An Expert based on the buffer6 and buffer7 of Trend Constraint V1.09"
2. Parâmetros de Entrada
Aqui, definimos os principais parâmetros de entrada que nos permitem personalizar o comportamento do EA sem alterar o código em si. Ao definir parâmetros como (Lots, Slippage, Stop Loss, Take Profit e Magic Number), tornamos o EA flexível e adaptável a diferentes estratégias de negociação. O número mágico é particularmente importante, pois nos permite identificar de forma única as negociações feitas por este EA, o que é crucial quando múltiplos EAs ou negociações manuais estão envolvidos:
///----------- EA inputs parameters for customizations input double Lots = 0.1; // Lot size input int Slippage = 3; // Slippage input double StopLoss = 50; // Stop Loss in points input double TakeProfit = 100; // Take Profit in points input int MagicNumber = 123456; // Magic number for orders
3. Função de Inicialização (OnInit)
Na função OnInit, preparamos o ambiente para a operação do EA, inicializando os componentes necessários. Começamos tentando obter um identificador para o nosso indicador personalizado, "Trend Constraint V1.09". Esse identificador nos permite interagir programaticamente com o indicador. Se o identificador for obtido com sucesso, continuamos configurando os arrays de buffer (Buffer6 e Buffer7) em série, permitindo-nos armazenar e manipular os valores do indicador. Se, no entanto, o identificador não puder ser recuperado, garantimos que o EA retorne uma falha de inicialização, com uma mensagem de erro para nos ajudar a diagnosticar o problema:
////-------Initialization Function int OnInit() { //--- Get the indicator handle indicator_handle = iCustom(Symbol(), PERIOD_CURRENT, "Trend Constraint V1.09"); if (indicator_handle < 0) { Print("Failed to get the indicator handle. Error: ", GetLastError()); return(INIT_FAILED); } //--- Set the buffer arrays as series ArraySetAsSeries(Buffer6, true); ArraySetAsSeries(Buffer7, true); return(INIT_SUCCEEDED); }
4. Função de Inicialização (OnDeinit)
Quando nosso EA é removido do gráfico ou quando a plataforma é fechada, a função (OnDeinit) é executada. Aqui, tomamos cuidado para liberar o identificador do indicador, garantindo que liberamos qualquer recurso alocado durante a operação do EA. Esse passo de limpeza é crucial para manter a eficiência e estabilidade do nosso ambiente de negociação, pois evita o consumo desnecessário de recursos:
///------Deinitialization Function(OnDeinit) void OnDeinit(const int reason) { //--- Release the indicator handle IndicatorRelease(indicator_handle); }
5. Função de Execução Principal (OnTick)
A função (OnTick) é onde ocorre a verdadeira ação de negociação. Cada vez que um novo tick do mercado é recebido, essa função é chamada. Começamos verificando se já existe uma posição aberta com o mesmo número mágico, garantindo que não colocamos negociações duplicadas. Em seguida, copiamos os valores mais recentes dos buffers do indicador (Buffer6 e Buffer7) para tomar decisões de negociação. Se nossas condições para um sinal de compra ou venda forem atendidas, construímos e enviamos a solicitação de negociação apropriada. Cuidamos de especificar todos os parâmetros necessários, como o tipo de ordem, preço, stop loss, take profit e slippage, para executar nossa estratégia de negociação de forma eficaz:
///---Main Execution Function(OnTick) void OnTick() { //--- Check if there is already an open position with the same MagicNumber if (PositionSelect(Symbol())) { if (PositionGetInteger(POSITION_MAGIC) == MagicNumber) { return; // Exit OnTick if there's an open position with the same MagicNumber } } //--- Calculate the indicator if (CopyBuffer(indicator_handle, 5, 0, 2, Buffer6) <= 0 || CopyBuffer(indicator_handle, 6, 0, 2, Buffer7) <= 0) { Print("Failed to copy buffer values. Error: ", GetLastError()); return; } //--- Check for a buy signal if (Buffer7[0] != EMPTY_VALUE) { double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double sl = NormalizeDouble(ask - StopLoss * _Point, _Digits); double tp = NormalizeDouble(ask + TakeProfit * _Point, _Digits); //--- Prepare the buy order request MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = Lots; request.type = ORDER_TYPE_BUY; request.price = ask; request.sl = sl; request.tp = tp; request.deviation = Slippage; request.magic = MagicNumber; request.comment = "Buy Order"; //--- Send the buy order if (!OrderSend(request, result)) { Print("Error opening buy order: ", result.retcode); } else { Print("Buy order opened successfully! Ticket: ", result.order); } } //--- Check for a sell signal if (Buffer6[0] != EMPTY_VALUE) { double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); double sl = NormalizeDouble(bid + StopLoss * _Point, _Digits); double tp = NormalizeDouble(bid - TakeProfit * _Point, _Digits); //--- Prepare the sell order request MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = Lots; request.type = ORDER_TYPE_SELL; request.price = bid; request.sl = sl; request.tp = tp; request.deviation = Slippage; request.magic = MagicNumber; request.comment = "Sell Order"; //--- Send the sell order if (!OrderSend(request, result)) { Print("Error opening sell order: ", result.retcode); } else { Print("Sell order opened successfully! Ticket: ", result.order); } } }
6. Outras Funções
Também incluímos várias outras funções para lidar com diferentes eventos que nosso EA possa encontrar, e elas vieram como parte de um modelo de EA, mas atualmente não as usamos para simplicidade:
- (OnTrade): Aqui, podemos lidar com quaisquer ações específicas que precisem ocorrer quando um evento de negociação acontecer. Embora atualmente esteja vazio, essa função oferece um espaço para adicionar lógica, se necessário.
- (OnTester): Essa função é usada para cálculos personalizados durante o back-testing. Ao retornar um valor, podemos otimizar nossa estratégia com base em métricas específicas.
- (OnTesterInit, OnTesterPass, OnTesterDeinit): Essas funções estão envolvidas no processo de otimização dentro do Strategy Tester. Elas nos permitem inicializar configurações, realizar ações após cada passagem de otimização e limpar os recursos depois.
- (OnChartEvent): Essa função nos permite lidar com vários eventos do gráfico, como cliques do mouse ou pressionamentos de teclas. Embora esteja atualmente vazia, podemos usar esse espaço para adicionar recursos interativos ao nosso EA:
///----Other Template functions available void OnTrade() { //--- Handle trade events if necessary } double OnTester() { double ret = 0.0; //--- Custom calculations for strategy tester return (ret); } void OnTesterInit() { //--- Initialization for the strategy tester } void OnTesterPass() { //--- Code executed after each pass in optimization } void OnTesterDeinit() { //--- Cleanup after tester runs } void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handle chart events here }
Nosso programa final montado fica assim:
//+------------------------------------------------------------------+ //| Trend Constraint Expert.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property strict #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "An Expert based on the buffer6 and buffer7 of Trend Constraint V1.09" //--- Input parameters for the EA input double Lots = 0.1; // Lot size input int Slippage = 3; // Slippage input double StopLoss = 50; // Stop Loss in points input double TakeProfit = 100; // Take Profit in points input int MagicNumber = 123456; // Magic number for orders //--- Indicator handle int indicator_handle; double Buffer6[]; double Buffer7[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Get the indicator handle indicator_handle = iCustom(Symbol(), PERIOD_CURRENT, "Trend Constraint V1.09"); if (indicator_handle < 0) { Print("Failed to get the indicator handle. Error: ", GetLastError()); return(INIT_FAILED); } //--- Set the buffer arrays as series ArraySetAsSeries(Buffer6, true); ArraySetAsSeries(Buffer7, true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Release the indicator handle IndicatorRelease(indicator_handle); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Check if there is already an open position with the same MagicNumber if (PositionSelect(Symbol())) { if (PositionGetInteger(POSITION_MAGIC) == MagicNumber) { return; // Exit OnTick if there's an open position with the same MagicNumber } } //--- Calculate the indicator if (CopyBuffer(indicator_handle, 5, 0, 2, Buffer6) <= 0 || CopyBuffer(indicator_handle, 6, 0, 2, Buffer7) <= 0) { Print("Failed to copy buffer values. Error: ", GetLastError()); return; } //--- Check for a buy signal if (Buffer7[0] != EMPTY_VALUE) { double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double sl = NormalizeDouble(ask - StopLoss * _Point, _Digits); double tp = NormalizeDouble(ask + TakeProfit * _Point, _Digits); //--- Prepare the buy order request MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = Lots; request.type = ORDER_TYPE_BUY; request.price = ask; request.sl = sl; request.tp = tp; request.deviation = Slippage; request.magic = MagicNumber; request.comment = "Buy Order"; //--- Send the buy order if (!OrderSend(request, result)) { Print("Error opening buy order: ", result.retcode); } else { Print("Buy order opened successfully! Ticket: ", result.order); } } //--- Check for a sell signal if (Buffer6[0] != EMPTY_VALUE) { double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); double sl = NormalizeDouble(bid + StopLoss * _Point, _Digits); double tp = NormalizeDouble(bid - TakeProfit * _Point, _Digits); //--- Prepare the sell order request MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = Lots; request.type = ORDER_TYPE_SELL; request.price = bid; request.sl = sl; request.tp = tp; request.deviation = Slippage; request.magic = MagicNumber; request.comment = "Sell Order"; //--- Send the sell order if (!OrderSend(request, result)) { Print("Error opening sell order: ", result.retcode); } else { Print("Sell order opened successfully! Ticket: ", result.order); } } } //+------------------------------------------------------------------+ //| Trade function | //+------------------------------------------------------------------+ void OnTrade() { //--- Handle trade events if necessary } //+------------------------------------------------------------------+ //| Tester function | //+------------------------------------------------------------------+ double OnTester() { double ret = 0.0; //--- Custom calculations for strategy tester return (ret); } //+------------------------------------------------------------------+ //| TesterInit function | //+------------------------------------------------------------------+ void OnTesterInit() { //--- Initialization for the strategy tester } //+------------------------------------------------------------------+ //| TesterPass function | //+------------------------------------------------------------------+ void OnTesterPass() { //--- Code executed after each pass in optimization } //+------------------------------------------------------------------+ //| TesterDeinit function | //+------------------------------------------------------------------+ void OnTesterDeinit() { //--- Cleanup after tester runs } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handle chart events here } //+------------------------------------------------------------------+
No próximo segmento, após uma compilação bem-sucedida, vamos testar nosso programa.
Testando
No MetaEditor, podemos usar o botão "Compilar" ou "Executar" para preparar nosso programa para teste. Neste caso, a compilação foi bem-sucedida e lançamos o teste no índice Boom 500 usando o Strategy Tester.
Lançando o Tester a partir do navegador
Um painel do Strategy Tester é aberto, permitindo que você ajuste algumas configurações antes de clicar no botão "Iniciar" no canto inferior direito. Por exemplo, o tamanho do lote padrão no EA está definido para 0,1 lotes, mas para o índice Boom 500, precisei aumentá-lo para um mínimo de 0,2 lotes neste caso.
Painel Strategy Tester
Surpreendentemente, nosso sistema teve um bom desempenho no Strategy Tester, como mostrado na imagem abaixo:
Visualização do Strategy Tester: Expert Trend Constraint
Conclusão
A adição de retângulos de risco e recompensa fornece aos traders uma representação gráfica clara de suas negociações, facilitando o monitoramento e o gerenciamento das posições abertas. Essa ajuda visual é particularmente útil em mercados de rápido movimento, onde decisões rápidas são necessárias. Os retângulos servem como um lembrete constante dos resultados potenciais da negociação, ajudando os traders a manterem-se alinhados com seu plano original de negociação.
A colaboração bem-sucedida entre o indicador (Trend Constraint V1.09) e o Expert Advisor destaca a importância da sinergia entre ferramentas em uma estratégia de negociação. O indicador identifica tendências e reversões potenciais, enquanto o EA executa negociações e gerencia riscos com base nessas informações. Essa abordagem integrada leva a uma estratégia de negociação mais coesa e eficaz.
Abaixo estão os arquivos do indicador, script e EA usados. Ainda há espaço para melhorias e modificações. Espero que você tenha achado esta informação valiosa. Fique à vontade para compartilhar suas opiniões na seção de comentários. Feliz Negociação!
Arquivo Anexo | Descrição |
---|---|
(Trend_Constraint V1.09.mq5) | Código fonte do indicador para funcionar com o EA. |
(Trend Constraint R-R.mq5) | Código fonte para o Script de Retângulo de Risco-Recompensa. |
(Trend Constraint Expert.mq5) | Código fonte para o Expert Advisor que funciona estritamente com (Trend Constraint V1.09) |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15321





- 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
Olá @argatafx28