DEV Community

Cover image for Este código é um exemplo de um Expert Advisor (EA) automatizado para o MetaTrader 5.
Henrique Vital
Henrique Vital

Posted on

Este código é um exemplo de um Expert Advisor (EA) automatizado para o MetaTrader 5.

Claro! Vamos explicar o código detalhadamente, com foco em cada parte e função para garantir que você compreenda como tudo funciona.

1. Importação de Bibliotecas

import MetaTrader5 as mt5
import time
from datetime import datetime
import signal
import sys
Enter fullscreen mode Exit fullscreen mode
  • MetaTrader5 (mt5): A biblioteca MetaTrader5 permite interagir com a plataforma MetaTrader 5 para automatizar operações de trading, como enviar ordens de compra e venda, obter cotações, etc.
  • time: Para realizar pausas no código, como aguardar até o momento de enviar uma ordem ou fazer verificações periódicas.
  • datetime: Usada para trabalhar com datas e horários. Neste código, é essencial para controlar quando as ordens serão enviadas e quando o programa irá encerrar.
  • signal: Permite capturar sinais do sistema operacional, como o Ctrl+C (usado para interromper a execução do programa).
  • sys: Usado para interagir com o sistema, como finalizar o programa caso algo dê errado (ex: sys.exit()).

2. Controle de Execução com o Sinal Ctrl+C

running = True

def signal_handler(sig, frame):
    global running
    print("\nInterrompendo o programa...")
    running = False

signal.signal(signal.SIGINT, signal_handler)
Enter fullscreen mode Exit fullscreen mode
  • A variável running é usada para controlar se o programa deve continuar executando ou não.
  • O manipulador signal_handler captura o sinal SIGINT (gerado pelo Ctrl+C) e altera o valor de running para False, o que interrompe o loop principal do programa.

3. Configuração de Conexão com o MetaTrader 5

login = 101108
password = "Jesuse10!"
server = "EquitiBrokerageSC-Demo"
mt5_path = r"C:\Program Files\Equiti Group MetaTrader 5 Terminal\terminal64.exe"
Enter fullscreen mode Exit fullscreen mode

Essas variáveis contêm as credenciais e o caminho do MetaTrader 5. Elas são usadas para conectar o script à sua conta no MetaTrader:

  • login: O número de login da sua conta no MetaTrader.
  • password: A senha associada ao login.
  • server: O servidor da corretora.
  • mt5_path: O caminho para o arquivo executável do MetaTrader 5, necessário para inicializar a conexão.

4. Função get_symbol_info

def get_symbol_info(symbol):
    info = mt5.symbol_info(symbol)
    if info is None:
        print(f"Falha ao obter informações do símbolo {symbol}")
        return None
    return info
Enter fullscreen mode Exit fullscreen mode

Esta função busca informações sobre o símbolo (ativo) que você quer negociar, como:

  • Preço atual, preço de abertura, pontos, etc.
  • Se não conseguir obter as informações, retorna None.

5. Funções para Ajustar Preço

def round_price(price, digits):
    return round(price, digits)

def align_price_to_tick(price, tick_size):
    return round(price / tick_size) * tick_size
Enter fullscreen mode Exit fullscreen mode
  • round_price: Arredonda o preço para um número de casas decimais específico (dependendo do ativo).
  • align_price_to_tick: Alinha o preço ao tamanho do tick (o menor movimento possível do preço). Isso é necessário para garantir que o preço esteja de acordo com o formato aceito pela corretora.

6. Função send_order

def send_order(symbol, order_type, lot, price, sl, tp):
    ...
    result = mt5.order_send(request)
    ...
    return result
Enter fullscreen mode Exit fullscreen mode

Essa função envia a ordem de compra ou venda para o MetaTrader. Ela aceita:

  • symbol: O símbolo (ativo) que você deseja negociar.
  • order_type: O tipo de ordem (exemplo: compra ou venda pendente).
  • lot: O tamanho do lote (quantidade de ativos a serem comprados ou vendidos).
  • price: O preço da ordem.
  • sl: O nível de stop loss.
  • tp: O nível de take profit.

A função cria uma solicitação (request) com todas as configurações necessárias para enviar a ordem, e então chama mt5.order_send(request) para efetivamente enviar a ordem para a plataforma MetaTrader 5.

7. Função get_current_candle

def get_current_candle(symbol, timeframe):
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 1)
    if rates is None or len(rates) == 0:
        return None
    return rates[0]
Enter fullscreen mode Exit fullscreen mode

Essa função busca a última vela (candle) de um determinado ativo. Ela usa o timeframe para determinar o intervalo de tempo entre cada vela (por exemplo, 5 minutos). A função retorna a última vela (com dados como preço de abertura, fechamento, máxima, mínima).

8. Função cancel_pending_orders

def cancel_pending_orders():
    orders = mt5.orders_get(symbol=symbol)
    ...
    result = mt5.order_send(request)  # Enviar o pedido para cancelar a ordem
Enter fullscreen mode Exit fullscreen mode

Essa função cancela todas as ordens pendentes de tipo BUY_STOP ou SELL_STOP para o símbolo especificado. A função verifica se há ordens pendentes e, caso existam, envia uma solicitação para cancelá-las.

9. Função main_loop (Loop Principal)

def main_loop():
    global running
    ordem_executada = False

    while running and not ordem_executada:
        try:
            current_time = datetime.now()

            # Define o horário alvo para as ordens
            target_time = current_time.replace(hour=execution_hour, minute=execution_minute, second=execution_second, microsecond=0)

            if current_time < target_time:
                sleep_time = (target_time - current_time).total_seconds()
                print(f"Aguardando até {target_time.strftime('%H:%M:%S')} para enviar ordens...")
                time.sleep(sleep_time)

            current_candle = get_current_candle(symbol, timeframe)
            if current_candle is None:
                print(f"[{datetime.now()}] Erro ao obter candle atual.")
                continue

            symbol_info = get_symbol_info(symbol)
            if symbol_info is None:
                continue

            point = symbol_info.point
            digits = symbol_info.digits
            tick_size = symbol_info.trade_tick_size

            buy_price = align_price_to_tick(round_price(current_candle['high'] + offset_pips_buy * point, digits), tick_size)
            sell_price = align_price_to_tick(round_price(current_candle['low'] - offset_pips_sell * point, digits), tick_size)

            sl_buy = align_price_to_tick(round_price(buy_price - sl_pips * point, digits), tick_size)
            tp_buy = align_price_to_tick(round_price(buy_price + tp_pips * point, digits), tick_size)
            sl_sell = align_price_to_tick(round_price(sell_price + sl_pips * point, digits), tick_size)
            tp_sell = align_price_to_tick(round_price(sell_price - tp_pips * point, digits), tick_size)

            send_order(symbol, mt5.ORDER_TYPE_BUY_STOP, lot, buy_price, sl_buy, tp_buy)
            send_order(symbol, mt5.ORDER_TYPE_SELL_STOP, lot, sell_price, sl_sell, tp_sell)

            ordem_executada = True

            shutdown_time = current_time.replace(hour=shutdown_hour, minute=shutdown_minute, second=shutdown_second, microsecond=0)
            while running and datetime.now() < shutdown_time:
                time.sleep(1)

            cancel_pending_orders()
            print(f"[{datetime.now()}] Todas as ordens pendentes foram canceladas.")

            time.sleep(60)

        except Exception as e:
            print(f"Erro no loop principal: {e}")
            time.sleep(1)
Enter fullscreen mode Exit fullscreen mode
  • main_loop é a função central onde o código passa a maior parte do tempo, executando as operações de acordo com os horários definidos e verificando as condições para enviar ordens.
  • O código fica aguardando até o horário execution_hour, execution_minute, e execution_second para enviar as ordens.
  • Depois de enviar as ordens, ele aguarda até o horário de shutdown e então cancela as ordens pendentes.
  • A função também verifica a conta de tempos em tempos, aguardando 1 minuto entre as verificações de saldo.

10. Execução Principal do Código

# Executa o loop principal
try:
    main_loop()
except Exception as e:
    print(f"Ocorreu um erro: {e}")
finally:
    # Desconecta do MetaTrader 5
    mt5.shutdown()
    print(f"[{datetime.now()}] Desconectado do MetaTrader 5.")
Enter fullscreen mode Exit fullscreen mode

Aqui, a função main_loop é chamada. Caso ocorra algum erro, ele é capturado pela exceção except, e a conexão com o MetaTrader é finalizada com mt5.shutdown().

Conclusão:

Este código é um exemplo de um Expert Advisor (EA) automatizado para o MetaTrader 5, que realiza operações de compra e venda com base no horário e nos preços dos candles. O programa se conecta ao Meta

import MetaTrader5 as mt5
import time
from datetime import datetime
import signal
import sys

# Variável global para controlar a execução
running = True

def signal_handler(sig, frame):
    global running
    print("\nInterrompendo o programa...")
    running = False

# Configurar o manipulador de sinal para Ctrl+C
signal.signal(signal.SIGINT, signal_handler)

# Variáveis de configuração do MetaTrader 5
login = 101108
password = "Jesuse10!"
server = "EquitiBrokerageSC-Demo"
mt5_path = r"C:\Program Files\Equiti Group MetaTrader 5 Terminal\terminal64.exe"

# Conecta ao MetaTrader 5 com as credenciais
print("Tentando conectar ao MetaTrader 5...")
if not mt5.initialize(login=login, password=password, server=server, path=mt5_path):
    print("Erro ao inicializar MT5. Verifique suas credenciais e tente novamente.")
    sys.exit(1)
else:
    print(f"Conectado ao MT5 na conta {login} com sucesso!")

# Defina as configurações
symbol = "US30Roll"
lot = 40.00
sl_pips = 2500
tp_pips = 3500
offset_pips_buy = 320  # Mantém 320 pipetes para buy stop
offset_pips_sell = 80  # Altera para 50 pipetes para sell stop
timeframe = mt5.TIMEFRAME_M5  # Alterado para 5 minutos

# Variável do horário específico (alterável facilmente)
execution_hour = 11
execution_minute = 29
execution_second = 59

# Variável do horário de desligamento (alterável facilmente)
shutdown_hour = 11
shutdown_minute = 30
shutdown_second = 59

# Função para obter informações do símbolo
def get_symbol_info(symbol):
    info = mt5.symbol_info(symbol)
    if info is None:
        print(f"Falha ao obter informações do símbolo {symbol}")
        return None
    return info

# Arredondar o preço de acordo com o número de dígitos
def round_price(price, digits):
    return round(price, digits)

# Alinhar o preço ao tamanho do tick
def align_price_to_tick(price, tick_size):
    return round(price / tick_size) * tick_size

# Enviar a ordem de compra ou venda
def send_order(symbol, order_type, lot, price, sl, tp):
    try:
        symbol_info = get_symbol_info(symbol)
        if symbol_info is None:
            return None

        digits = symbol_info.digits
        tick_size = symbol_info.trade_tick_size

        price = align_price_to_tick(round_price(price, digits), tick_size)
        sl = align_price_to_tick(round_price(sl, digits), tick_size)
        tp = align_price_to_tick(round_price(tp, digits), tick_size)

        print(f"[{datetime.now()}] Enviando ordem: Tipo={order_type}, Preço={price}, SL={sl}, TP={tp}")

        request = {
            "action": mt5.TRADE_ACTION_PENDING,
            "symbol": symbol,
            "volume": lot,
            "type": order_type,
            "price": price,
            "sl": sl,
            "tp": tp,
            "deviation": 10,
            "magic": 234000,
            "comment": "Python EA",
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_IOC,
        }
        result = mt5.order_send(request)
        if result.retcode != mt5.TRADE_RETCODE_DONE:
            print(f"Erro ao enviar ordem: {result.retcode}, {result.comment}")
        else:
            print(f"Ordem enviada com sucesso: {result.order}")
        return result
    except Exception as e:
        print(f"Erro ao enviar ordem: {e}")
        return None

# Obter o candle atual
def get_current_candle(symbol, timeframe):
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 1)
    if rates is None or len(rates) == 0:
        return None
    return rates[0]

# Função para cancelar todas as ordens pendentes
def cancel_pending_orders():
    orders = mt5.orders_get(symbol=symbol)
    if orders is not None:
        for order in orders:
            if order.type == mt5.ORDER_TYPE_BUY_STOP or order.type == mt5.ORDER_TYPE_SELL_STOP:
                print(f"Cancelando ordem pendente: {order.ticket}")

                # Criar um pedido para cancelar a ordem
                request = {
                    "action": mt5.TRADE_ACTION_REMOVE,
                    "order": order.ticket,
                }
                result = mt5.order_send(request)  # Enviar o pedido para cancelar a ordem
                if result.retcode != mt5.TRADE_RETCODE_DONE:
                    print(f"Erro ao cancelar ordem: {result.retcode}, {result.comment}")
                else:
                    print(f"Ordem {order.ticket} cancelada com sucesso.")
    else:
        print("Nenhuma ordem pendente encontrada.")

# Função principal do sistema
def main_loop():
    global running
    ordem_executada = False

    while running and not ordem_executada:
        try:
            current_time = datetime.now()

            # Define o horário alvo para as ordens (variável alterável)
            target_time = current_time.replace(hour=execution_hour, minute=execution_minute, second=execution_second, microsecond=0)

            if current_time < target_time:
                sleep_time = (target_time - current_time).total_seconds()
                print(f"Aguardando até {target_time.strftime('%H:%M:%S')} para enviar ordens...")
                time.sleep(sleep_time)

            # Verifica o candle atual para calcular preços de buy e sell
            current_candle = get_current_candle(symbol, timeframe)
            if current_candle is None:
                print(f"[{datetime.now()}] Erro ao obter candle atual.")
                continue

            symbol_info = get_symbol_info(symbol)
            if symbol_info is None:
                continue

            point = symbol_info.point
            digits = symbol_info.digits
            tick_size = symbol_info.trade_tick_size

            # Calcula os preços de buy e sell
            buy_price = align_price_to_tick(round_price(current_candle['high'] + offset_pips_buy * point, digits), tick_size)
            sell_price = align_price_to_tick(round_price(current_candle['low'] - offset_pips_sell * point, digits), tick_size)

            sl_buy = align_price_to_tick(round_price(buy_price - sl_pips * point, digits), tick_size)
            tp_buy = align_price_to_tick(round_price(buy_price + tp_pips * point, digits), tick_size)
            sl_sell = align_price_to_tick(round_price(sell_price + sl_pips * point, digits), tick_size)
            tp_sell = align_price_to_tick(round_price(sell_price - tp_pips * point, digits), tick_size)

            print(f"[{datetime.now()}] Enviando ordens: BUY_STOP em {buy_price}, SELL_STOP em {sell_price}")
            send_order(symbol, mt5.ORDER_TYPE_BUY_STOP, lot, buy_price, sl_buy, tp_buy)  # Certifique-se de passar tp
            send_order(symbol, mt5.ORDER_TYPE_SELL_STOP, lot, sell_price, sl_sell, tp_sell)  # Certifique-se de passar tp

            print(f"[{datetime.now()}] Ordens enviadas com sucesso às {target_time.strftime('%H:%M:%S')}. Aguardando para cancelar ordens pendentes.")
            ordem_executada = True

            # Aguardar até o horário de desligamento
            shutdown_time = current_time.replace(hour=shutdown_hour, minute=shutdown_minute, second=shutdown_second, microsecond=0)
            while running and datetime.now() < shutdown_time:
                time.sleep(1)

            # Cancelar ordens pendentes
            cancel_pending_orders()
            print(f"[{datetime.now()}] Todas as ordens pendentes foram canceladas.")

            # Aguardar 1 minuto
            print(f"[{datetime.now()}] Aguardando 1 minuto antes de verificar o saldo...")
            time.sleep(60)

            # Verificar saldo e imprimir no terminal
            account_info = mt5.account_info()
            if account_info is not None:
                print(f"[{datetime.now()}] Saldo da conta: {account_info.balance}")
            else:
                print(f"[{datetime.now()}] Falha ao obter informações da conta.")

        except Exception as e:
            print(f"Erro no loop principal: {e}")
            time.sleep(1)

# Conecta ao MetaTrader 5 com as credenciais
print(f"Tentando conectar ao MetaTrader 5 na conta {login}...")
if not mt5.initialize(login=login, password=password, server=server, path=mt5_path):
    print(f"[{datetime.now()}] Erro ao inicializar MT5. Verifique suas credenciais.")
    sys.exit(1)
else:
    print(f"[{datetime.now()}] Conectado ao MT5 na conta {login} com sucesso!")

# Verificar saldo e nome da corretora
account_info = mt5.account_info()
if account_info is not None:
    print(f"[{datetime.now()}] Conectado à corretora: {account_info.server}")
    print(f"[{datetime.now()}] Saldo da conta: {account_info.balance}")
else:
    print(f"[{datetime.now()}

] Falha ao obter informações da conta.")

# Executa o loop principal
try:
    main_loop()
except Exception as e:
    print(f"Ocorreu um erro: {e}")
finally:
    # Desconecta do MetaTrader 5
    mt5.shutdown()
    print(f"[{datetime.now()}] Desconectado do MetaTrader 5.")
Enter fullscreen mode Exit fullscreen mode

Aqui estão as alterações feitas:

  1. O código original foi mantido com pequenas melhorias de legibilidade.
  2. Comentários e variáveis foram ajustados para maior clareza e precisão no código.
  3. A estrutura de erros foi mantida intacta e o código foi organizado para facilitar a manutenção e depuração.

Top comments (0)