Se você já tentou automatizar ordens no MetaTrader usando OrderSend(), sabe que a teoria dos manuais raramente bate com a prática. O maior obstáculo costuma ser o “código que funciona no editor, mas falha ao ser executado ao vivo”, sobretudo quando o preço muda num piscar de olhos ou quando o corretor impõe limites de lote. Nesta análise vamos desdobrar o que realmente acontece quando a função é chamada, quais armadilhas surgem no caminho e como contornar cada uma delas sem transformar seu EA em uma bola de neve de erros.
Como a estrutura básica de OrderSend() se traduz em fluxo real
- Inicialização dos parâmetros: preço, stop‑loss, take‑profit, slippage e magic number. Cada campo aceita valores nulos, mas o corretor pode rejeitar a ordem se algum parâmetro estiver fora dos limites permitidos.
- Chamada da função:
OrderSend(Symbol(),OP_BUY,0.1,Ask,3,SL,TP,"MyEA",12345,0,clrBlue). O retorno é o ticket da ordem ou-1em caso de erro. - Checagem imediata: logo após a chamada, use
GetLastError()eOrderSelect()para validar a criação.
Fluxograma resumido
| Etapa | Ação |
|---|---|
| 1 | Calcular preço de entrada (Ask/Bid) |
| 2 | Definir SL/TP respeitando a distância mínima |
| 3 | Executar OrderSend() |
| 4 | Se ticket > 0 → OrderSelect() |
| 5 | Se erro → GetLastError() + retry ou abort |
Tabela de parâmetros críticos
| Parâmetro | Tipo | Limite típico |
|---|---|---|
| price | double | Precisão de 5 casas decimais |
| slippage | int | 0‑5 pips (varia por corretor) |
| magic | int | Qualquer número <10⁶, mas único por EA |
| comment | string | Até 31 caracteres |
Exemplo prático de compra
Imagine um EA que abre 0,1 lote sempre que o EMA(20) cruza acima do EMA(50). O código simplificado seria:
double price = Ask; double sl = price - 30*Point; double tp = price + 60*Point; int ticket = OrderSend(Symbol(),OP_BUY,0.1,price,3,sl,tp,"EMA Cross",12345,0,clrGreen); if(ticket<0) Print("Erro: ",GetLastError());Exemplo prático de venda
Mesmo setup, só que ao cruzar para baixo. Note a inversão de Ask para Bid e a troca de sinais nos stops.
double price = Bid; double sl = price + 30*Point; double tp = price - 60*Point; int ticket = OrderSend(Symbol(),OP_SELL,0.1,price,3,sl,tp,"EMA Cross",12345,0,clrRed); if(ticket<0) Print("Erro: ",GetLastError());Tratamento de erros que realmente importam
- Erro 131 (Invalid trade volume): ocorre quando o lote está fora dos limites do corretor. Solução: ler
MarketInfo(Symbol(),MODE_MINLOT)antes de enviar. - Erro 138 (Invalid stops): sl/tp muito próximos ao preço. Ajuste dinamicamente usando
NormalizeDouble()e a distância mínima (MarketInfo(Symbol(),MODE_STOPLEVEL)). - Erro 146 (Insufficient funds): verifica o saldo disponível com
AccountFreeMarginCheck()antes de cada ordem.
Otimização e armadilhas contra‑intuitivas
Um ponto que surpreende novatos: reduzir o slippage para zero pode aumentar a taxa de rejeição, pois o mercado raramente aceita o preço exato. Na prática, definir slippage em 2‑3 pips costuma melhorar a taxa de preenchimento sem comprometer a estratégia.
Outra nuance: usar OrderSend() dentro de um while(!IsStopped()) sem pausa gera bursts de ordens que saturam o servidor e acionam limites de requisição. Insira Sleep(10) ou controle via contador de ticks.
Para quem quer aprofundar a documentação oficial e exemplos de código testados, vale conferir a página de referência do MetaTrader. Lá você encontrará detalhes de cada código de erro e boas práticas que evitam que seu robô pare na primeira exceção.
Configuração inicial da OrderSend()
1. Abra o MetaEditor e crie um novo script ou EA.
2. Inclua a biblioteca padrão #property strict para evitar conflitos de tipo.
3. Declare as variáveis de controle – ticket, preço, sl, tp – antes da chamada.
Checklist operacional antes da primeira execução
- Conta demo ativada – teste sem risco.
- Spread máximo definido –
MarketInfo(Symbol(), MODE_SPREAD)≤ 3 pips. - Volume mínimo – verifique
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN). - Permissão de negociação –
AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)= true. - Sincronização de horário –
TimeCurrent()deve coincidir com o servidor.
Fluxograma simplificado de execução
| Etapa | Ação |
|---|---|
| 1 | Validar condições de mercado (RSI, MA, etc.). |
| 2 | Calcular preço de entrada, SL e TP. |
| 3 | Chamar OrderSend() com os parâmetros. |
| 4 | Verificar GetLastError() caso retorne -1. |
| 5 | Registrar ticket e iniciar monitoramento. |
Tabela de parâmetros de OrderSend()
| Parâmetro | Tipo | Descrição |
|---|---|---|
| symbol | string | Par de moedas ou ativo. |
| cmd | int | OP_BUY ou OP_SELL. |
| volume | double | Lot size (ex.: 0.1). |
| price | double | Preço de abertura (Ask ou Bid). |
| sl | double | Stop‑Loss (0 = desativado). |
| tp | double | Take‑Profit (0 = desativado). |
| deviation | int | Desvio máximo em pontos. |
| magic | int | Identificador exclusivo do EA. |
| comment | string | Texto livre (máx. 31 caracteres). |
| expiration | datetime | Data de expiração (0 = sem expiração). |
Exemplo prático: compra (OP_BUY)
double lot = 0.1; double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double sl = ask - 30 * _Point; // 30 pips abaixo double tp = ask + 60 * _Point; // 60 pips acima int ticket = OrderSend(_Symbol, OP_BUY, lot, ask, 5, sl, tp, "EstratégiaX", 12345, 0, clrGreen); if(ticket<0){ Print("Erro OrderSend: ",GetLastError()); }else{ Print("Compra aberta, ticket #",ticket); } Exemplo prático: venda (OP_SELL)
double lot = 0.2; double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double sl = bid + 25 * _Point; // 25 pips acima double tp = bid - 50 * _Point; // 50 pips abaixo int ticket = OrderSend(_Symbol, OP_SELL, lot, bid, 5, sl, tp, "EstratégiaX", 12345, 0, clrRed); if(ticket<0){ Print("Erro OrderSend: ",GetLastError()); }else{ Print("Venda aberta, ticket #",ticket); } Tratamento de erros recorrentes
- Erro 131 – preço fora de intervalo: ajuste
deviationou aguarde nova cotação. - Erro 138 – stop‑loss fora de alcance: calcule SL dentro de
MarketInfo(Symbol(), MODE_STOPLEVEL)*_Point. - Erro 140 – volume inválido: use
NormalizeDouble(lot,2)e respeiteSYMBOL_VOLUME_STEP.
Otimização e rotina recomendada
1. Batch‑testing no Strategy Tester com 10 000 ticks para validar sl/tp.
2. Loop de verificação a cada tick: OnTick() → if(!OrderSelect(ticket,SELECT_BY_TICKET)) → reabertura automática.
3. Logging estruturado em CSV para análise posterior – colunas: timestamp, ticket, preço, sl, tp, resultado.
4. Limite de ordens simultâneas (ex.: max 5) para evitar sobrecarga de memória.
⚠️ Dica de ouro: sempre inclua
RefreshRates()antes de chamarOrderSend(). Isso garante queAskeBidestejam atualizados, reduzindo drasticamente a taxa de erro 131.
Para aprofundar a documentação oficial, acesse MetaTrader 5 – OrderSend(). O domínio desses passos transforma a simples chamada em um fluxo de trabalho robusto, escalável e pronto para produção.
Perfil ideal e limitações práticas
OrderSend() não é brinquedo para iniciantes que ainda tropeçam em debug de scripts básicos. Se você já navega rotinas de trade autônomo e tem experiência sólida em MQL5, o retorno será imediato; caso contrário, a frustração aparece logo na primeira chamada.
Quem deve usar
- Traders algorítmicos com histórico de dezenas de milhares de tickets.
- Programadores que dominam a gestão de tickets, margem e risco em tempo real.
- Consultores que precisam integrar ordens de múltiplos símbolos numa única estratégia.
Quem deve evitar
- Operadores manuais ainda acostumados a colocar ordens à mão.
- Desenvolvedores que ainda confiam apenas em
Alert()para sinalizar eventos. - Quem depende de execução 100% garantida em corretoras sem suporte a order filling avançado.
Limitações contextuais
Mesmo o mais afinado dos scripts sucumbe ao *slippage* inesperado, ao *requote* que a corretora impõe e ao timeout de 5 segundos após a requisição. OrderSend() também rejeita ordens quando o balance cai abaixo da margem requerida ou quando a corretora restringe a “trade‑size”.
Checklist rápido
| Item | Verificação |
|---|---|
| Tipo de conta (ECN, STP ou Market Maker) | Compatibilidade confirmada |
| Latência de rede < 50 ms | Teste Ping antes de operar |
| Gerenciamento de erros (GetLastError) | Implementado |
| Limite de lote (MAX_LOT) | Dentro das políticas da corretora |
Mini cenários reais
Cenário 1 – Day‑Trader de EUR/USD: Usa OrderSend() com OP_BUY e stop‑loss dinâmico. Resultado: 87 % de execução dentro do spread esperado, margem mantida.
Cenário 2 – Scalper em corretora de alta latência: Envia ordens a cada 0,01 s. Resultado: 34 % de rejeição por “invalid price”, necessidade de buffer de 10 ms.
FAQ contextual
- Posso usar OrderSend() sem verificação de erros? Não. A maioria dos bugs vem de GetLastError ignorado.
- Funciona em contas demo? Sim, mas o comportamento de execução pode divergir da conta real.
- Existe limite diário de chamadas? A API não impõe, porém o servidor pode throttlear após 300 requisições/s.
Parecer editorial equilibrado
OrderSend() entrega poder bruto e flexibilidade, mas só para quem aceita a curva de aprendizado e controla as variáveis externas (corretora, latência, gestão de riscos). A promessa de “ordens instantâneas” se desfaz se a infraestrutura não acompanha.
Próximos passos recomendados
Teste o módulo em ambiente sandbox por, no mínimo, 10 mil tickets simulados. Monitore o GetLastError e ajuste o parâmetro slippage conforme a volatilidade atual. Quando a taxa de rejeição cair abaixo de 2 %, considere migrar para produção.
