MT5 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).
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"
"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:
- Abra o MetaEditor e compile o arquivo.Open MetaEditor and compile the file.
- Em Tools → Options → Expert Advisors, adicione a URL do servidor em Allow WebRequest (
http://127.0.0.1:8000no Windows nativo, ouhttp://<IP-LAN>:8000sob Linux/Wine — loopback falha sob Wine).In Tools → Options → Expert Advisors, add the server URL under Allow WebRequest (http://127.0.0.1:8000on native Windows, orhttp://<IP-LAN>:8000under Linux/Wine — loopback fails under Wine). - Ajuste
InpServerURLnos parâmetros do EA para a mesma URL liberada.SetInpServerURLin the EA parameters to the same allowed URL. - Arraste o EA
LLM_Traderpara o gráfico do símbolo configurado. O timeframe do gráfico não importa —OnTick()dispara em todo tick.Drag theLLM_TraderEA 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_VERSION | v1.8.0 | Tag de versão nos logs.Version tag in logs. |
OPENAI_API_KEY | — | Chave da OpenAI.OpenAI API key. |
OPENAI_MODEL | gpt-4o | Modelo OpenAI (suporta json_schema strict).OpenAI model (supports strict json_schema). |
SYMBOL | EURUSD | Símbolo no broker (MT5).Broker symbol (MT5). |
YF_SYMBOL | EURUSD=X | Símbolo no yfinance.yfinance symbol. |
DATA_SOURCE | yfinance | mt5 | yfinance |
MT5_HOST / MT5_PORT | localhost / 18812 | Bridge mt5linux.mt5linux bridge. |
VOL_ESTIMATOR | garch | garch | har_rv | atr |
PIP_SIZE | 0.0001 | Tamanho do pip (EURUSD).Pip size (EURUSD). |
ANALYSIS_INTERVAL | 300 | Segundos 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_POSITIONS | 3 | Teto de posições simultâneas (uma por horizonte/lado).Concurrent positions cap (one per horizon/side). |
MIN_CONFIDENCE | 0.6 | Confiança mínima para agir.Minimum confidence to act. |
RISK_PER_TRADE_PCT | 1.0 | Risco-alvo por trade (% do equity).Target risk per trade (% of equity). |
PIP_VALUE_PER_LOT | 10.0 | USD por pip por 1 lote (EURUSD/USD).USD per pip per 1 lot (EURUSD/USD). |
MIN_LOT / MAX_LOT / LOT_STEP | 0.01 / 1.0 / 0.01 | Bounds e passo do broker.Broker bounds and step. |
DAILY_DRAWDOWN_PCT | 2.0 | Circuit breaker — % do equity perdível por dia.Circuit breaker — % of equity loss-able per day. |
MAX_CONSECUTIVE_LOSSES | 3 | Circuit breaker — perdas seguidas no dia.Circuit breaker — consecutive losses in a day. |
Perfis de horizonte (SL/TP, time exit, cadência) ficam emconfig.HORIZON_PROFILESno 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 inconfig.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.