MT5 LLM Agent

Python FastAPI OpenAI MetaTrader 5 GARCH HAR-RV Quant Finance LLM Agent

O MT5 LLM Agent é um agente de trading stateful que utiliza LLMs para tomar decisões em tempo real no MetaTrader 5. A cada ANALYSIS_INTERVAL segundos, o pipeline coleta dados multi-timeframe, computa indicadores técnicos, testes estatísticos e modelos de volatilidade (GARCH/HAR-RV), injeta o estado da posição aberta no prompt e consulta a OpenAI — que responde com uma ação: OPEN_LONG, OPEN_SHORT, HOLD, CLOSE (sair antes de SL/TP) ou TIGHTEN_STOP (apertar SL para travar lucro). The MT5 LLM Agent is a stateful trading agent that uses LLMs for real-time decisions on MetaTrader 5. Every ANALYSIS_INTERVAL seconds, the pipeline collects multi-timeframe data, computes technical indicators, statistical tests, and volatility models (GARCH/HAR-RV), injects the open position state into the prompt, and queries OpenAI — which responds with an action: OPEN_LONG, OPEN_SHORT, HOLD, CLOSE (exit before SL/TP), or TIGHTEN_STOP (tighten SL to lock profit).

Ver no GitHubView on GitHub
Aviso: use conta demo apenas. Projeto experimental, sem garantias de performance. Disclaimer: use demo accounts only. Experimental project, no performance guarantees.

Como funcionaHow it works

O agente combina três camadas: (i) extração de features a partir de múltiplos timeframes (RSI, MACD, ATR, Bollinger, EMA), além de testes estatísticos (ADF, Ljung-Box, Hurst, VRT) e estimadores de volatilidade plugáveis (GARCH(1,1), HAR-RV de Corsi ou ATR); (ii) decisão via LLM usando um prompt builder hierárquico que injeta o contexto técnico, o estado da posição aberta e o histórico recente; (iii) gestão de risco com sizing dinâmico (confiança × volatilidade inversa), guardrails state-aware, circuit breakers de drawdown diário e perdas consecutivas. The agent combines three layers: (i) feature extraction from multiple timeframes (RSI, MACD, ATR, Bollinger, EMA), plus statistical tests (ADF, Ljung-Box, Hurst, VRT) and pluggable volatility estimators (GARCH(1,1), Corsi's HAR-RV, or ATR); (ii) LLM decision via a hierarchical prompt builder that injects technical context, open position state, and recent history; (iii) risk management with dynamic sizing (confidence × inverse volatility), state-aware guardrails, daily drawdown circuit breakers and consecutive-loss limits.

Um Expert Advisor em MQL5 roda no MetaTrader 5 e consulta o servidor FastAPI local via WebRequest a cada tick. A fonte de dados é configurável: yfinance por padrão, ou o próprio broker via mt5linux (bridge Python no Wine). An MQL5 Expert Advisor runs on MetaTrader 5 and queries the local FastAPI server via WebRequest on every tick. The data source is configurable: yfinance by default, or the broker itself via mt5linux (Python bridge in Wine).

Instalação rápidaQuick install

$ pip install -r requirements.txt
$ cp .env.example .env
$ uvicorn main:app --host 0.0.0.0 --port 8000

--host 0.0.0.0 é necessário se o MT5 roda no Wine — o EA não consegue acessar 127.0.0.1 sob Wine. Em Windows nativo, 127.0.0.1 funciona normalmente. Após subir, abra http://localhost:8000/ no navegador para o dashboard de runtime (equity curve, distribuição de ações, win rate por regime, latência do LLM, última decisão ao vivo — atualiza a cada 10 s). --host 0.0.0.0 is required if MT5 runs under Wine — the EA cannot reach 127.0.0.1 under Wine. On native Windows, 127.0.0.1 works normally. Once up, open http://localhost:8000/ in the browser for the runtime dashboard (equity curve, action distribution, win rate per regime, LLM latency, live last decision — refreshes every 10 s).

Configuração MT5 no Linux (opcional)MT5 setup on Linux (optional)

Para usar dados diretos do broker em vez do yfinance, o pacote mt5linux cria uma ponte entre o Python Linux e o MT5 rodando no Wine/Bottles. É necessário instalar Python dentro do ambiente Wine e executar um servidor bridge. To use broker data directly instead of yfinance, the mt5linux package bridges Python on Linux and MT5 running under Wine/Bottles. You need Python inside the Wine environment plus a bridge server.

Passo 1 — Python no Wine/BottlesStep 1 — Python inside Wine/Bottles

Baixe o instalador python-3.11.9-amd64.exe e instale-o no bottle do MT5 (marque "Add to PATH"). Recomendado: drive_c\Python311. Download the python-3.11.9-amd64.exe installer and install it inside the MT5 bottle (check "Add to PATH"). Recommended path: drive_c\Python311.

Passo 2 — Dependências dentro do WineStep 2 — Dependencies inside Wine

drive_c\users\steamuser\AppData\Local\Programs\Python\Python311\python.exe -m pip install MetaTrader5 mt5linux "numpy<2"
Importante: o "numpy<2" é necessário. NumPy 2.x usa funções C99 do Universal CRT (crealf, cimagf, etc) que o ucrtbase.dll do Wine ainda não implementa — o bridge crasha com ucrtbase.dll.crealf, aborting. Alternativa: instalar vcredist2019/2022 via Bottles → Dependencies (substitui o ucrtbase do Wine pelo da Microsoft). Important: "numpy<2" is required. NumPy 2.x uses C99 functions from the Universal CRT (crealf, cimagf, etc) that Wine's ucrtbase.dll doesn't implement yet — the bridge crashes with ucrtbase.dll.crealf, aborting. Alternative: install vcredist2019/2022 via Bottles → Dependencies (replaces Wine's ucrtbase with Microsoft's).

Passo 3 — mt5linux no Python LinuxStep 3 — mt5linux on Linux Python

$ pip install mt5linux

Passo 4 — Iniciar o bridgeStep 4 — Start the bridge

No terminal cmd do Bottles, com o MT5 aberto e conectado ao broker: In the Bottles cmd terminal, with MT5 open and connected to the broker:

drive_c\users\steamuser\AppData\Local\Programs\Python\Python311\python.exe -m mt5linux --host 127.0.0.1 -p 18812

Deve aparecer: INFO SLAVE/18812[MainThread]: server started on [127.0.0.1]:18812. You should see: INFO SLAVE/18812[MainThread]: server started on [127.0.0.1]:18812.

Passo 5 — Ativar no .envStep 5 — Enable in .env

DATA_SOURCE=mt5
MT5_HOST=localhost
MT5_PORT=18812

O agente tenta MT5 primeiro. Se o bridge não estiver rodando, cai automaticamente para yfinance sem quebrar. The agent tries MT5 first. If the bridge isn't running, it automatically falls back to yfinance without breaking.

Deploy do Expert AdvisorExpert Advisor deployment

$ bash deploy_mql5.sh

O script copia mql5/LLM_Trader.mq5 para o diretório Experts do MT5. Em seguida: The script copies mql5/LLM_Trader.mq5 to MT5's Experts directory. Then:

  1. Abra o MetaEditor e compile o arquivo.Open MetaEditor and compile the file.
  2. Em Tools → Options → Expert Advisors, adicione a URL do servidor em Allow WebRequest (http://127.0.0.1:8000 no Windows nativo, ou http://<IP-LAN>:8000 sob Linux/Wine — loopback falha sob Wine).In Tools → Options → Expert Advisors, add the server URL under Allow WebRequest (http://127.0.0.1:8000 on native Windows, or http://<IP-LAN>:8000 under Linux/Wine — loopback fails under Wine).
  3. Ajuste InpServerURL nos parâmetros do EA para a mesma URL liberada.Set InpServerURL in the EA parameters to the same allowed URL.
  4. Arraste o EA LLM_Trader para o gráfico do símbolo configurado. O timeframe do gráfico não importa — OnTick() dispara em todo tick.Drag the LLM_Trader EA onto the configured symbol's chart. The chart timeframe doesn't matter — OnTick() fires on every tick.

Variáveis de ambienteEnvironment variables

VariávelVariable PadrãoDefault DescriçãoDescription
MODEL_VERSIONv1.8.0Tag de versão nos logs.Version tag in logs.
OPENAI_API_KEY—Chave da OpenAI.OpenAI API key.
OPENAI_MODELgpt-4oModelo OpenAI (suporta json_schema strict).OpenAI model (supports strict json_schema).
SYMBOLEURUSDSímbolo no broker (MT5).Broker symbol (MT5).
YF_SYMBOLEURUSD=XSímbolo no yfinance.yfinance symbol.
DATA_SOURCEyfinancemt5 | yfinance
MT5_HOST / MT5_PORTlocalhost / 18812Bridge mt5linux.mt5linux bridge.
VOL_ESTIMATORgarchgarch | har_rv | atr
PIP_SIZE0.0001Tamanho do pip (EURUSD).Pip size (EURUSD).
ANALYSIS_INTERVAL300Segundos entre análises (flat). Com posição, cadência vira min(cadence_s) entre horizontes ativos.Seconds between analyses (flat). With an open position, cadence becomes min(cadence_s) across active horizons.
MAX_POSITIONS3Teto de posições simultâneas (uma por horizonte/lado).Concurrent positions cap (one per horizon/side).
MIN_CONFIDENCE0.6Confiança mínima para agir.Minimum confidence to act.
RISK_PER_TRADE_PCT1.0Risco-alvo por trade (% do equity).Target risk per trade (% of equity).
PIP_VALUE_PER_LOT10.0USD por pip por 1 lote (EURUSD/USD).USD per pip per 1 lot (EURUSD/USD).
MIN_LOT / MAX_LOT / LOT_STEP0.01 / 1.0 / 0.01Bounds e passo do broker.Broker bounds and step.
DAILY_DRAWDOWN_PCT2.0Circuit breaker — % do equity perdível por dia.Circuit breaker — % of equity loss-able per day.
MAX_CONSECUTIVE_LOSSES3Circuit breaker — perdas seguidas no dia.Circuit breaker — consecutive losses in a day.
Perfis de horizonte (SL/TP, time exit, cadência) ficam em config.HORIZON_PROFILES no código, com defaults para scalp/intraday/swing. Edite lá para tunar; não estão expostos no .env. Horizon profiles (SL/TP, time exit, cadence) live in config.HORIZON_PROFILES, with defaults for scalp/intraday/swing. Edit there to tune; not exposed via .env.

Zerar logsReset logs

Para começar uma nova janela de coleta (por ex. depois de resetar o equity da conta demo): To start a fresh collection window (e.g. after resetting demo account equity):

$ python reset_logs.py            # interativo — exige digitar "SIM"interactive — requires typing "SIM"
$ python reset_logs.py --yes      # pula confirmaçãoskips confirmation

Apaga signals.jsonl, trades.jsonl e trades_state.json. Não toca em código, .env, paper ou posições do MT5. Reinicie o uvicorn em seguida para limpar o current_signal em memória. Wipes signals.jsonl, trades.jsonl and trades_state.json. Doesn't touch code, .env, paper, or MT5 positions. Restart uvicorn afterwards to clear the in-memory current_signal.

EstruturaStructure

mt5_llm_agent/
├── main.py                    # entry point FastAPI
├── config.py                  # settings via .env
├── agent/
│   ├── llm_manager.py         # OpenAI client (json_schema strict)
│   └── prompt_builder.py      # prompt hierárquico + estado da posição
├── api/
│   ├── server.py              # endpoints /signal /health /analyze
│   └── dashboard.py           # GET / (HTML) + /api/dashboard (JSON)
├── data/
│   ├── fetcher.py             # interface unificada MT5 + yfinance
│   ├── mt5_source.py          # OHLCV via MT5 (mt5linux | MetaTrader5)
│   ├── yf_source.py           # fonte yfinance (fallback)
│   ├── positions.py           # posição aberta para o prompt stateful
│   └── trades.py              # lifecycle real de trades fechados
├── features/
│   ├── context_builder.py     # contexto multi-TF
│   ├── indicators.py          # RSI, MACD, ATR, Bollinger, EMA
│   ├── statistics.py          # ADF, Ljung-Box, Hurst, VRT
│   ├── garch.py               # GARCH(1,1) — σ_{t+1} em pips
│   └── har_rv.py              # HAR-RV (Corsi) — σ_{t+1} em pips
├── risk/
│   ├── manager.py             # Signal + guardrails state-aware
│   ├── volatility.py          # estimador plugável GARCH > HAR-RV > ATR
│   ├── sizing.py              # sizing dinâmico (confiança × vol inversa)
│   └── circuit_breaker.py     # DD diário / perdas seguidas
├── analytics/
│   ├── simulator.py           # simulação post-hoc de TP/SL hit
│   └── metrics.py             # métricas por MODEL_VERSION
├── mql5/
│   └── LLM_Trader.mq5         # Expert Advisor MT5
├── paper/
│   └── paper.tex              # artigo acadêmico (WIP)
└── logs/
    ├── signals.jsonl
    └── trades.jsonl

MotivaçãoMotivation

O projeto explora se um LLM, devidamente contextualizado com features quantitativas e estado de carteira, consegue tomar decisões úteis em mercados intradiários — tratando o modelo de linguagem como um policy de alta abstração sobre features estatísticas, ao invés de tentar prever preço diretamente. Toda a infraestrutura ao redor (sizing, circuit breakers, logging por MODEL_VERSION) existe para tornar a hipótese testável de forma honesta, com lifecycle real de trades e simulação post-hoc para isolar a contribuição do LLM. The project explores whether an LLM, properly contextualized with quantitative features and portfolio state, can make useful decisions in intraday markets — treating the language model as a high-level policy over statistical features, rather than trying to predict price directly. All the surrounding infrastructure (sizing, circuit breakers, MODEL_VERSION-stamped logging) exists to make the hypothesis honestly testable, with real trade lifecycle data and post-hoc simulation isolating the LLM's contribution.