Building with fxapis

Trade MetaTrader 5 from Python with the fxapis SDK

pip install fxapis: connect an MT5 account, place orders that never double-fill, and let the SDK retry only what is safe — from Python on Linux, macOS or Windows.

The fxapis team2 min read

In short

  • pip install fxapis gives you sync and async clients for the hosted MT5 API, fully typed, on Python 3.10 or newer — with no MetaTrader terminal on your machine.
  • Orders get an idempotency key automatically, so a retried order returns the first answer instead of opening a second position.
  • Each failure is its own exception. OrderUnresolvedError is never retried — wait_until_resolved() polls it; codes that prove nothing was done are retried for you.
  • It runs anywhere Python runs, including Linux and macOS, unlike the official MetaTrader5 package.
On this page
  1. Install it
  2. From an MT5 login to a closed trade
  3. Orders that never double-fill
  4. Handling each outcome
  5. Async, pages and many accounts
  6. Where to go next

The official Python SDK for fxapis is a typed client for the hosted MetaTrader 5 REST API: sync and async clients on httpx, idempotency keys added for you, and one exception class per error code. It needs Python 3.10 or newer and is open source at github.com/FXapis/fxapis-python.

Unlike the official MetaTrader5 package, it does not drive a terminal on your machine. The terminals run in fxapis's cloud; the SDK makes HTTPS requests — so it runs on Linux, macOS, Windows, a container or a scheduled job. The MetaTrader5 package vs a REST API compares the two in detail.

Install it

cURL
pip install fxapis
export FXAPIS_API_KEY="fx_test_…"   # create one at fxapis.com/dashboard/keys

Use a broker demo account while you build: every fxapis key, fx_test_ keys included, reaches a real broker. There is no simulated market.

From an MT5 login to a closed trade

Python
from fxapis import Fxapis

client = Fxapis()  # reads FXAPIS_API_KEY

# 1. Connect the account once. The trading password, not the investor password.
account = client.accounts.connect(
    login="26177561",
    server="VantageMarkets-Demo",
    password="your-mt5-trading-password",
    mode="warm_on_demand",  # online when needed, offline after 15 idle minutes
)

# 2. Bring it online and wait for `ready` — about ten seconds for a typical broker.
client.accounts.warm(account["id"])
client.accounts.wait_until_ready(account["id"])

# 3. Trade. Volumes and prices are strings: "0.01", not 0.01.
order = client.orders.market(account["id"], symbol="EURUSD", side="buy", volume="0.01")
print(order["state"], order["filledPrice"])

# 4. Read the positions, then close them.
for position in client.positions.list(account["id"]):
    print(position["symbol"], position["volume"], position["profit"])
    client.positions.close(account["id"], position["brokerPositionId"])

with Fxapis() as client: closes the connection pool for you. Connecting does not log in: it stores the account and encrypts its password, and warm starts the login. wait_until_ready() raises if the account needs a person — a wrong password, 2FA, a certificate — instead of waiting forever.

Orders that never double-fill

client.orders.market() sends an Idempotency-Key on every order, generated for you. If the connection drops after the order was sent, the SDK resends it with the same key, and fxapis answers with the first result instead of opening a second position. When the key should mean something in your system — a signal and a member, a copied deal — pass your own:

Python
key = f"signal_{signal_id}:member_{member_id}"
order = client.orders.market(account_id, symbol="XAUUSD", side="buy", volume="0.05", idempotency_key=key)

A member who taps twice, or a job that runs twice, gets the same order back. Idempotent orders explains why this matters.

Handling each outcome

Python
from fxapis import OrderRejectedError, OrderUnresolvedError, SendFailedError, AccountNotReadyError

try:
    order = client.orders.market(account_id, symbol="XAUUSD", side="buy", volume="0.05", idempotency_key=key)
except OrderRejectedError as err:
    print("rejected:", err.message)        # nothing opened; a new attempt needs a NEW key
except OrderUnresolvedError as err:
    order = client.orders.wait_until_resolved(err.order_id)   # never resend: wait for the answer
except (SendFailedError, AccountNotReadyError) as err:
    print("not sent:", err.code)           # already retried with the same key; safe to try later

The SDK retries only what is provably safe: codes that mean nothing was done are resent with the same key, and server errors and lost connections are retried on reads and on requests carrying a key. ORDER_UNRESOLVED is never retried — the order may be live at the broker — and fxapis confirms an opening order against the broker's own deal history.

Async, pages and many accounts

Python
import asyncio
from fxapis import AsyncFxapis

async def main() -> None:
    async with AsyncFxapis() as client:
        async for order in client.orders.iter(state="unknown"):
            print(order["id"], order["symbol"])

asyncio.run(main())

iter() walks a paginated list for you. For one trade on many accounts — a copier, a signal service — client.multi_account_orders.create() sends a single order to up to 1,000 accounts, within your plan's limit, with a volume per account.

Where to go next

FAQ

Questions people also ask

How is this different from the MetaTrader5 Python package?

The MetaTrader5 package drives a terminal installed on the same Windows machine. The fxapis SDK calls a hosted REST API instead: the terminal runs in fxapis's cloud, so your code runs on any OS and nothing has to stay logged in on your side.

Which Python versions are supported?

Python 3.10 or newer. The package is fully typed (py.typed) and checked with mypy --strict; httpx is its only dependency.

Does it retry orders automatically?

Only when it is provably safe: codes that mean nothing was done (SEND_FAILED, ACCOUNT_NOT_READY, RATE_LIMITED and similar) are retried with the same idempotency key. ORDER_UNRESOLVED and broker rejections are never retried.

Is there an async client?

Yes — AsyncFxapis has the same methods, awaited, and async iterators for paginated lists.

All articles
> Connect. Execute. Scale.

Trade MT5 from your own code.

Connect accounts by login, password and server, and place orders over HTTPS. We run MetaTrader 5; you install nothing.