Use the MetaTrader 5 API on Linux and macOS
Why the official MetaTrader5 Python package only works on Windows next to a running terminal, the Wine, Docker and VPS workarounds people use on Linux and macOS, and how to trade MT5 accounts over plain HTTP instead — from any OS and any language.
If you have tried pip install MetaTrader5 on a Mac or a Linux server, you have
met the problem this page is about. The official package is built for Windows
and talks to a MetaTrader 5 terminal running on the same machine. This guide
explains why, what people do about it, and how to skip the problem entirely by
trading over HTTP.
Why the official package needs Windows
MetaQuotes' own documentation describes the package as a way to obtain data "via interprocessor communication directly from the MetaTrader 5 terminal". It is not a network client for the broker: it is a bridge to a terminal process on the same computer.
Two facts follow from that:
- It needs a running MetaTrader 5 terminal.
initialize()"establishes a connection with the MetaTrader 5 terminal", and takes the path to the terminal's.exe; if required, the terminal is launched wheninitialize()is called. Every call after that —order_send,positions_get,history_deals_get— goes through that terminal. - It is published for Windows only. On PyPI, the files published for the package are Windows
x86-64 wheels (
win_amd64); there are none for Linux or macOS, sopipon those systems finds nothing it can install.
Sources, checked on 30 September 2026:
MetaTrader5 on PyPI,
Python integration — MQL5 documentation,
initialize() — MQL5 documentation.
The workarounds people use
Wine
MetaQuotes publishes instructions for running the MetaTrader 5 terminal on
Linux through Wine, with an install script for Ubuntu, Debian, Linux Mint and
Fedora, and a separate page for macOS
(MetaTrader 5 on Linux).
That runs the terminal. To use the Python package, you then also install a
Windows build of Python inside the same Wine prefix, install MetaTrader5
there, and run your script with that interpreter.
A bridge between Linux Python and Wine Python
Open-source projects such as mt5linux
automate the second half: a server runs in Wine's Windows Python next to the
terminal, and a client library in your normal Linux Python forwards each call to
it over RPyC. Your code imports a module that mirrors the MetaTrader5 API.
Docker images
Community images bundle Wine, the terminal, a Windows Python, a bridge like the one above, and often a VNC server so you can see the terminal's window. They make the setup reproducible; they do not make it smaller.
A Windows VPS
The simplest option that keeps the official package: rent a Windows machine, install the terminal, run your Python there, and expose what you need to the rest of your system yourself.
What all of them have in common
Each approach runs a full desktop trading terminal that you now operate:
- One terminal per account at a time. A terminal is logged in to one trading account; trading many accounts at once means running many terminals and keeping track of which is which.
- A GUI application on a server. It expects a display (a virtual one under Xvfb or VNC), updates itself, and can stop on a dialog nobody sees.
- Keeping it alive is your job: restarts, logins after a broker disconnect, disk and memory per terminal, and noticing when one has quietly stopped.
- Your code is tied to where the terminal runs, which is usually not where the rest of your application runs.
For one personal account on one machine, that is often fine. For a product that trades other people's accounts, it becomes an operations project.
Doing it over HTTP instead
fxapis runs the MetaTrader 5 terminals for you, in our cloud, and gives you a REST API. Your code — on macOS, Linux, Windows, a container, a serverless function, in any language — makes HTTPS requests:
- No terminal, VPS, Wine or Expert Advisor on your side.
- Many accounts at once, each connected with its login, password and server.
- An account comes online in about ten seconds in our tests when needed, and can go offline by itself when idle.
- Orders sent with an
Idempotency-Keyare safe to retry with the same key, and every order gets a recorded result; an unclear one is confirmed with the broker, not guessed.
The same trade, both ways
With the official package, on Windows, next to a terminal:
import MetaTrader5 as mt5
mt5.initialize(login=26177561, password="…", server="VantageMarkets-Demo")
tick = mt5.symbol_info_tick("EURUSD")
result = mt5.order_send({
"action": mt5.TRADE_ACTION_DEAL,
"symbol": "EURUSD",
"volume": 0.01,
"type": mt5.ORDER_TYPE_BUY,
"price": tick.ask,
"deviation": 20,
})
print(result.retcode, result.price)
mt5.shutdown()With fxapis, from anywhere:
import os, uuid, requests
API = "https://api.fxapis.com"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['FXAPIS_KEY']}"
account = s.post(f"{API}/v1/accounts", json={
"login": "26177561", "server": "VantageMarkets-Demo",
"password": os.environ["MT5_PASSWORD"], "mode": "warm_on_demand",
}).json()["data"] # once; keep account["id"]
order = s.post(f"{API}/v1/accounts/{account['id']}/orders/market",
headers={"Idempotency-Key": str(uuid.uuid4())},
json={"symbol": "EURUSD", "side": "buy", "volume": "0.01", "deviationPoints": 20},
timeout=90,
).json()["data"]
print(order["state"], order["filledPrice"], order["retcode"])The fxapis version needs no price: a market order executes at the market, and
an account in warm_on_demand mode comes online by itself for the order. For a
complete program with correct retries, see the Python guide —
or the same program in Node.js, PHP,
C#, Go, Java or Ruby.
Mapping the package's calls
MetaTrader5 package | fxapis |
|---|---|
initialize(), login() | POST /v1/accounts once, then POST /v1/accounts/{id}/warm (or let an order bring it online) |
shutdown() | POST /v1/accounts/{id}/cool, or nothing — idle accounts go offline by themselves |
order_send() with TRADE_ACTION_DEAL | POST /v1/accounts/{id}/orders/market |
order_send() with TRADE_ACTION_PENDING | POST /v1/accounts/{id}/orders/pending |
order_send() with TRADE_ACTION_SLTP | POST /v1/accounts/{id}/positions/{ticket}/modify |
order_send() with TRADE_ACTION_REMOVE | POST /v1/orders/{id}/cancel |
Closing with an opposite TRADE_ACTION_DEAL | POST /v1/accounts/{id}/positions/{ticket}/close |
positions_get() | GET /v1/accounts/{id}/positions |
history_deals_get() | GET /v1/accounts/{id}/deals |
history_orders_get() | GET /v1/orders?accountId=… |
order_calc_margin(), order_calc_profit() | POST /v1/accounts/{id}/calculate |
symbol_info_tick(), copy_rates_*(), copy_ticks_*() | No equivalent — see below |
Some differences to expect:
- Volumes and prices are strings (
"0.01"), not floats, so no size is ever rounded by a double. - Stops are absolute prices, as in MT5.
- Return codes are kept. Each order carries the broker's own
retcode; errors carry a stablecodesuch asORDER_REJECTEDorSEND_FAILED. See Errors. - Positions are a snapshot with a timestamp (
observedAt), refreshed about every 15 seconds while the account is online.
What fxapis does not replace
fxapis is for trading accounts and their history. It does not stream prices or serve bars and ticks, so if your strategy computes signals from MT5 market data, you need a data source for that part. It supports MetaTrader 5 only, not MetaTrader 4. There are no event webhooks yet; you poll.
Next steps
- Quickstart — an API key to a filled demo order in about five minutes.
- Place MT5 orders from Python — a complete, correct program.
- Connect MT5 accounts — server names, passwords and states.
Place MetaTrader 5 orders from Ruby — no MetaTrader installed
A complete Ruby program using Net::HTTP that connects an MT5 account, places a market order with an idempotency key, retries safely, never resends an unresolved order, reads positions and closes the trade — from Rails, Sidekiq or a plain script, with no terminal.
Connect MT5 accounts by login, password and server
How to connect a MetaTrader 5 account to the fxapis API: finding the exact server name, trading versus investor password, two-factor sign-in, handling credentials safely in your app, checking them immediately, needs-attention states, and disconnecting.