Skip to content

MT5 + Python architecture

ExpertDuration 35 minTools Python 3, MetaTrader5 package (pip), An MT5 demo account, Windows or a Windows VPS

You have validated a strategy on net costs. To run it, Python has to reach a broker — and at retail CFD brokers there is no REST order API the way there is for US equities (the industry contrast is real). Your two realistic paths are the native MetaTrader5 package and an EA bridge. They are not interchangeable: one is Windows-bound and in-process, the other is platform-agnostic and file/socket-based, and the choice quietly decides your VPS, your latency budget, and how you debug at 3am. This lesson makes you fluent in both and gets working code onto a demo terminal.

Watch for: The order_send open/close cycle (around 14:50–20:30). Notice this is happy-path only — no error handling, no reconnect, no reconciliation. That is exactly what Lesson 3.2 has to add.

Segment: 20:21–25:55 — When NOT to use DWX Connectwatch full video

Watch for: Why Darwinex dropped ZeroMQ in 2021, the ~25ms file-poll latency budget, and the blunt rule: if you are latency-sensitive, use a FIX API, not any MetaTrader bridge.

Two architectures, one decision. Both approaches end with Python deciding and MetaTrader executing. They differ in how the two processes talk.

Path A — the native MetaTrader5 package. You pip install MetaTrader5, and your Python process makes in-process calls to a running MT5 terminal on the same machine through local inter-process communication (IPC), not a network API. mt5.initialize() attaches to the terminal; copy_rates_range and copy_ticks_range pull history into pandas; order_send places and closes orders; positions_get and orders_get read live state (official API reference). The walkthrough above demonstrates the whole surface against an IC Markets demo. The catch is stated plainly in the package docs: it is Windows-only and needs the terminal alive next to it. Linux and macOS have only workarounds — Wine, or the community mt5linux RPC shim — neither of which you want under real money. So the native path dictates a Windows VPS. That is the whole reason the architecture question is not academic.

Path B — the EA bridge. Here an Expert Advisor runs inside the terminal and exchanges messages with your Python “brain” — historically over ZeroMQ sockets, now more often over files. DWX Connect is the reference implementation: one client codebase covering both MT4 and MT5, with reference clients in Python, Java, and C#, handling every order type, modification, closing by ticket/symbol/magic, and market-data subscription. The team that built it explains why they abandoned their own ZeroMQ series in 2021: subscribing to many symbols made it too CPU-hungry, and average users could not debug socket connectivity. File-based IPC replaced it with a default ~25ms poll interval — and they are refreshingly explicit that if your strategy is genuinely latency-sensitive, you should not use any MetaTrader bridge; you should use their separate FIX API. The older ZeroMQ videos (still instructive as architecture history) show the pattern in the raw, including the classic gotcha that stops are specified in points, not pips.

The fork, decided: the native package is simpler, in-process, and Windows-bound — best when your system is one Python process on a Windows VPS beside its terminal. The EA bridge is platform-agnostic and lets your brain run anywhere (including Linux) while the EA does the broker-facing work — best when you want language or OS freedom, or you already run MT4. Neither is “faster” in a way that matters for intraday-to-swing systems; both are the wrong tool for true low-latency trading.

Why VPS choice follows from this. The tuning folklore you will read — “trade context busy” error 146, pinning terminals to CPU cores, “buy fewer, faster cores” — is MetaTrader 4 lore: MT4 is a 32-bit single-threaded app with one terminal-wide trade context. The presenter’s own closing caveat (near 31:30) is the load-bearing sentence: MT5 is multi-threaded and resolves most of those issues. So on the native MT5 path you inherit far less of that pain — but you still inherit Windows. Size the VPS for reliability and a low, stable latency to the broker’s server, not for core count.

The honest posture the rest of Level 3 builds on: the demo code you are about to run is the easy 20%. It has no reconnection, no state check on restart, no idempotency. Lessons 3.2 and 3.3 exist because that missing 80% is what actually kills bot accounts.

Run this against a demo MT5 terminal that is open and logged in. It pulls 1000 bars and the current tick, then places and cancels a far-away pending order so nothing can fill.

import MetaTrader5 as mt5
import pandas as pd
# 1. Attach to the already-running, logged-in DEMO terminal.
if not mt5.initialize():
raise SystemExit(f"initialize() failed: {mt5.last_error()}")
symbol = "EURUSD"
mt5.symbol_select(symbol, True)
# 2. Pull the last 1000 M15 bars into a DataFrame.
rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M15, 0, 1000)
bars = pd.DataFrame(rates)
bars["time"] = pd.to_datetime(bars["time"], unit="s")
print(bars.tail(3)[["time", "open", "high", "low", "close"]])
# 3. Read the current tick (live bid/ask).
tick = mt5.symbol_info_tick(symbol)
print(f"bid={tick.bid} ask={tick.ask} spread={round((tick.ask - tick.bid) / mt5.symbol_info(symbol).point)} points")
# 4. Place a BUY LIMIT far below market so it will NOT fill, then cancel it.
price = round(tick.bid - 0.0200, mt5.symbol_info(symbol).digits) # 200 pips under
request = {
"action": mt5.TRADE_ACTION_PENDING,
"symbol": symbol,
"volume": 0.01,
"type": mt5.ORDER_TYPE_BUY_LIMIT,
"price": price,
"magic": 424242, # our client tag — remember this for 3.2
"comment": "course-3.1-demo",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_RETURN,
}
sent = mt5.order_send(request)
print("placed:", sent.retcode, "ticket:", sent.order)
# 5. Cancel it by ticket.
cancel = mt5.order_send({"action": mt5.TRADE_ACTION_REMOVE, "order": sent.order})
print("cancelled:", cancel.retcode)
mt5.shutdown()

Verify in the terminal’s Trade tab that the pending order appeared and vanished. Note the magic number — that tag is how, in Lesson 3.2, you will tell your orders apart from everything else on the account.

Check yourself

  1. Why is the native MetaTrader5 Python package effectively Windows-only in production?

  2. Darwinex replaced its ZeroMQ Python-to-MetaTrader bridge with the file-based DWX Connect in 2021 mainly because ZeroMQ was…

  3. The single-terminal 'trade context busy' problem and the single-thread core limits discussed for VPS tuning are…

  4. When is a MetaTrader bridge (native package OR EA bridge) the wrong tool, per the people who build them?

You can move on when you can… stand up the MetaTrader5 package against a demo terminal, pull bars and a tick into pandas, place and cancel a pending order by ticket, and argue the native-package-vs-EA-bridge fork — including why the native path forces a Windows VPS and when neither belongs anywhere near your strategy.