# Use the MetaTrader 5 API on Linux and macOS

URL: https://docs.fxapis.com/guides/linux-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…



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 [#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 when `initialize()` 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, so `pip` on those systems finds
  nothing it can install.

Sources, checked on 30 September 2026:
[MetaTrader5 on PyPI](https://pypi.org/project/MetaTrader5/),
[Python integration — MQL5 documentation](https://www.mql5.com/en/docs/python_metatrader5),
[`initialize()` — MQL5 documentation](https://www.mql5.com/en/docs/python_metatrader5/mt5initialize_py).

## The workarounds people use [#the-workarounds-people-use]

### Wine [#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](https://www.metatrader5.com/en/terminal/help/start_advanced/install_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 [#a-bridge-between-linux-python-and-wine-python]

Open-source projects such as [mt5linux](https://pypi.org/project/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 [#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 [#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 [#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 [#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-Key` are 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 [#the-same-trade-both-ways]

With the official package, on Windows, next to a terminal:

```python
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:

```python
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](/guides/python) —
or the same program in [Node.js](/guides/nodejs), [PHP](/guides/php),
[C#](/guides/csharp), [Go](/guides/go), [Java](/guides/java) or [Ruby](/guides/ruby).

### Mapping the package's calls [#mapping-the-packages-calls]

| `MetaTrader5` package                                    | fxapis                                                                                                                                                                                               |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `initialize()`, `login()`                                | [`POST /v1/accounts`](/api-reference/accounts/connect-an-mt5-account) once, then [`POST /v1/accounts/{id}/warm`](/api-reference/lifecycle/bring-an-account-online) (or let an order bring it online) |
| `shutdown()`                                             | [`POST /v1/accounts/{id}/cool`](/api-reference/lifecycle/take-an-account-offline), or nothing — idle accounts go offline by themselves                                                               |
| `order_send()` with `TRADE_ACTION_DEAL`                  | [`POST /v1/accounts/{id}/orders/market`](/api-reference/trading/place-a-market-order)                                                                                                                |
| `order_send()` with `TRADE_ACTION_PENDING`               | [`POST /v1/accounts/{id}/orders/pending`](/api-reference/trading/place-a-limit-stop-or-stop-limit-order)                                                                                             |
| `order_send()` with `TRADE_ACTION_SLTP`                  | [`POST /v1/accounts/{id}/positions/{ticket}/modify`](/api-reference/trading/move-a-positions-stop-loss-or-take-profit)                                                                               |
| `order_send()` with `TRADE_ACTION_REMOVE`                | [`POST /v1/orders/{id}/cancel`](/api-reference/trading/cancel-a-pending-order)                                                                                                                       |
| Closing with an opposite `TRADE_ACTION_DEAL`             | [`POST /v1/accounts/{id}/positions/{ticket}/close`](/api-reference/trading/close-a-position)                                                                                                         |
| `positions_get()`                                        | [`GET /v1/accounts/{id}/positions`](/api-reference/trading/positions-on-an-account)                                                                                                                  |
| `history_deals_get()`                                    | [`GET /v1/accounts/{id}/deals`](/api-reference/history/an-accounts-full-deal-history)                                                                                                                |
| `history_orders_get()`                                   | [`GET /v1/orders?accountId=…`](/api-reference/history/list-orders)                                                                                                                                   |
| `order_calc_margin()`, `order_calc_profit()`             | [`POST /v1/accounts/{id}/calculate`](/api-reference/trading/margin-required-or-profit-at-a-price)                                                                                                    |
| `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 stable
  `code` such as `ORDER_REJECTED` or `SEND_FAILED`. See [Errors](/errors).
* **Positions are a snapshot with a timestamp** (`observedAt`), refreshed about every 15 seconds
  while the account is online.

### What fxapis does not replace [#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 [#next-steps]

* [Quickstart](/quickstart) — an API key to a filled demo order in about five minutes.
* [Place MT5 orders from Python](/guides/python) — a complete, correct program.
* [Connect MT5 accounts](/guides/connect-accounts) — server names, passwords and states.
