mt5-httpapi
REST API on top of MetaTrader 5 running inside a Windows VM. Talk to it with plain HTTP/JSON — no MT5 libraries, no Windows, no bullshit. Just curl and go.
For installation and setup, see references/setup.md.
Setup
The API should already be running. Set the base URL:
export MT5_API_URL=http://localhost:6542
Each terminal has its own port (configured in terminals.json). If running multiple terminals, set MT5_API_URL to the port for the terminal you want to talk to.
Verify: curl $MT5_API_URL/ping — should return {"status": "ok"}. If not, the API isn't up yet (may still be initializing — it retries in the background).
How It Works
GET for reading, POST for creating, PUT for modifying, DELETE for closing/canceling. All bodies are JSON.
Every error response:
{"error": "description of what went wrong"}
Pre-Trade Checks (DO NOT SKIP)
Before placing any trade:
GET /account→trade_allowedmust betrueGET /symbols/SYMBOL→trade_modemust be4(full trading)GET /symbols/SYMBOL→ checktrade_contract_size— 1 lot of EURUSD = 100,000 EUR, not 1 EURGET /terminal→connectedmust betrue
API Reference
Health
curl $MT5_API_URL/ping
# {"status": "ok"}
curl $MT5_API_URL/error
# {"code": 1, "message": "Success"}
Terminal
curl $MT5_API_URL/terminal
curl -X POST $MT5_API_URL/terminal/init
curl -X POST $MT5_API_URL/terminal/shutdown
Key fields on /terminal: connected, trade_allowed, build, company.
Account
curl $MT5_API_URL/account
{
"login": 12345678,
"balance": 10000.0,
"equity": 10000.0,
"margin": 0.0,
"margin_free": 10000.0,
"margin_level": 0.0,
"leverage": 500,
"currency": "USD",
"trade_allowed": true,
"margin_so_call": 70.0,
"margin_so_so": 20.0
}
Symbols
curl $MT5_API_URL/symbols
curl "$MT5_API_URL/symbols?group=*USD*"
curl $MT5_API_URL/symbols/EURUSD
curl $MT5_API_URL/symbols/EURUSD/tick
curl "$MT5_API_URL/symbols/EURUSD/rates?timeframe=H4&count=100"
curl "$MT5_API_URL/symbols/EURUSD/ticks?count=100"
Timeframes: M1 M2 M3 M4 M5 M6 M10 M12 M15 M20 M30 H1 H2 H3 H4 H6 H8 H12 D1 W1 MN1
Key symbol fields: bid, ask, digits, point, trade_contract_size, trade_tick_value, trade_tick_size, volume_min, volume_max, volume_step, spread, swap_long, swap_short, trade_stops_level, trade_mode.
Orders
# Place market order
curl -X POST $MT5_API_URL/orders \
-H 'Content-Type: application/json' \
-d '{"symbol": "EURUSD", "type": "BUY", "volume": 0.1, "sl": 1.08, "tp": 1.10}'
# List pending orders
curl $MT5_API_URL/orders
curl "$MT5_API_URL/orders?symbol=EURUSD"
curl $MT5_API_URL/orders/42094812
# Modify pending order
curl -X PUT $MT5_API_URL/orders/42094812 \
-H 'Content-Type: application/json' \
-d '{"price": 1.09, "sl": 1.07, "tp": 1.11}'
# Cancel pending order
curl -X DELETE $MT5_API_URL/orders/42094812
Order types: BUY, SELL, BUY_LIMIT, SELL_LIMIT, BUY_STOP, SELL_STOP, BUY_STOP_LIMIT, SELL_STOP_LIMIT
Fill policies: FOK, IOC (default), RETURN
Expiration: GTC (default), DAY, SPECIFIED, SPECIFIED_DAY
Required fields: symbol, type, volume. price auto-fills for market orders.
Trade result:
{
"retcode": 10009,
"deal": 40536203,
"order": 42094820,
"volume": 0.1,
"price": 1.0950,
"comment": "Request executed"
}
retcode 10009 = success. Anything else = something went wrong.
Positions
curl $MT5_API_URL/positions
curl "$MT5_API_URL/positions?symbol=EURUSD"
curl $MT5_API_URL/positions/42094820
# Update SL/TP
curl -X PUT $MT5_API_URL/positions/42094820 \
-H 'Content-Type: application/json' \
-d '{"sl": 1.085, "tp": 1.105}'
# Close full position
curl -X DELETE $MT5_API_URL/positions/42094820
# Partial close
curl -X DELETE $MT5_API_URL/positions/42094820 \
-H 'Content-Type: application/json' \
-d '{"volume": 0.05}'
Key position fields: ticket, type (0=buy, 1=sell), volume, price_open, price_current, sl, tp, profit, swap.
History
curl "$MT5_API_URL/history/orders?from=$(date -d '1 day ago' +%s)&to=$(date +%s)"
curl "$MT5_API_URL/history/deals?from=$(date -d '1 day ago' +%s)&to=$(date +%s)"
from and to are required, unix epoch seconds.
Deal fields: type (0=buy, 1=sell), entry (0=opening, 1=closing), profit (0 for entries, realized P&L for exits).
Position Sizing
risk_amount = balance * risk_pct
sl_distance = ATR * multiplier
ticks_in_sl = sl_distance / trade_tick_size
risk_per_lot = ticks_in_sl * trade_tick_value
volume = risk_amount / risk_per_lot
Round down to nearest volume_step, clamp to [volume_min, volume_max]. Sanity check: volume * trade_contract_size * price should make sense relative to account balance.
Tips
- Always check
retcode— 10009 = good, anything else = bad - Use
GET /errorto debug failed trades deviationon orders = max slippage in points (default 20, raise for volatile markets)type_fillingmatters — tryFOK,IOC,RETURNif orders get rejected- Candle
timeis the open time, not close time trade_stops_level= minimum SL/TP distance from current price in points- Markets have hours — check
trade_modebefore placing orders