pymt5
Python client for the MT5 Web Terminal via reverse-engineered WebSocket binary protocol.
Requirements
- Python 3.11+ (3.11, 3.12, 3.13)
- Platforms: Linux, macOS, Windows
- Dependencies:
websockets,aiohttp,cryptography
Features
Core Protocol
- WebSocket transport to
wss://web.metatrader.app/terminal - AES-CBC encryption with zero IV and PKCS7 padding
- Bootstrap handshake (cmd=0) with automatic key exchange
- Login (cmd=28) with UTF-16LE encoded fields
ping,logout,change_password,trader_paramsverify_code(cmd=27) — two-factor authenticationrequest_opening_verification/submit_opening_verification(cmd=27/40)open_demo_account(cmd=30) andopen_real_account(cmd=39)enable_otp/disable_otp(cmd=43)open_demo(cmd=30) — legacy init-style wrapper kept for compatibilitysend_notification(cmd=42) — server notifications
Account Data
get_account(cmd=3) — account metadata and balance state: balance, credit, currency, leverage, account/server/company names, timezone, rights flags, trade settings, leverage rules, commission tablesget_account_summary()—AccountInfodataclass (uses cmd=3 + positions)get_positions_and_orders(cmd=4) — open positions and pending ordersget_positions()— convenience: open positions onlyget_orders()— convenience: pending orders onlyget_trade_history(cmd=5) — closed deals and historical ordersget_deals()— convenience: closed deals only
Market Data
get_symbols(cmd=34, zlib compressed) — full symbol list with metadataget_symbol_groups(cmd=9) — category tree (Forex, Crypto, Indexes, etc.)get_full_symbol_info(cmd=18) — detailed contract specs (tick size, margins, volumes, bond face value/accrued interest, trade schedule, subscription flags)get_spreads(cmd=20) — spread data with proper schema parsingget_rates(cmd=11) — historical OHLCV bars (M1 to MN1), auto-detects extended format withreal_volumesubscribe_ticks(cmd=7) — real-time tick push (cmd=8) with callbacksubscribe_symbols— name-based tick subscription (resolves names via symbol cache)subscribe_book(cmd=22) — order book / depth-of-market subscriptionsubscribe_book_by_name— name-based order book subscription
Official MetaTrader5-style Helpers
- Session/account:
initialize,shutdown,account_info,terminal_info,version - Compatibility state:
last_error - Symbols/history:
symbols_total,symbols_get,symbol_info,positions_total,positions_get,orders_total,orders_get,history_orders_*,history_deals_* - Bars/trading:
copy_rates_range,copy_rates_from,copy_rates_from_pos,copy_ticks_from,copy_ticks_range,order_send,order_check - Local formula helpers:
order_calc_profit,order_calc_margin(best-effort for forex/CFD/futures/stock/bond modes that the current Web Terminal computes client-side) - DOM/cache helpers:
market_book_add,market_book_get,market_book_release,symbol_select,symbol_info_tick terminal_infoandversionare best-effort Web Terminal views derived fromcmd=3plus observed public build metadatacopy_ticks_*are cached views over observedcmd=8pushes, andorder_checkis a local compatibility-layer pre-flight rather than a server RPC
Trading
- Raw:
trade_request— full control over all trade fields, returnsTradeResult TradeResultincludes:deal,order,volume,price,bid,ask,comment,request_id- High-level helpers (auto-resolve digits from symbol cache):
buy_market/sell_market— market orders with optional SL/TPbuy_limit/sell_limit— limit pending ordersbuy_stop/sell_stop— stop pending ordersbuy_stop_limit/sell_stop_limit— stop-limit pending ordersclose_position— close by opposite market order (auto-detects BUY/SELL direction)close_position_by— close by opposite position (hedge netting)modify_position_sltp— modify SL/TP of open positionmodify_pending_order— modify pending order price/SL/TPcancel_pending_order— remove a pending order
Symbol Cache & Info
load_symbols()— fetch and cache all symbols for fast name→id/digits lookupget_symbol_info(name)— lookupSymbolInfoby nameget_symbol_id(name)— lookup symbol ID by namesymbol_names— list all cached symbol names
Miscellaneous Commands
get_corporate_links(cmd=44) — broker links (support, education, social)send_raw_command— send any command with raw payloadsend_bootstrap_command_52— experimental wrapper for reserved bootstrap-onlycmd=52
Push Notifications
on_tick(callback)— real-time tick pushes (cmd=8)on_position_update(callback)— position change pusheson_order_update(callback)— order change pusheson_trade_update(callback)— combined position+order push in single callbackon_trade_transaction(callback)— order add/update/delete + balance updates (cmd=10)on_symbol_update(callback)— symbol change pushes (cmd=13)on_account_update(callback)— account balance/equity/margin pushes (cmd=14)on_login_status(callback)— login status pushes (cmd=15)on_symbol_details(callback)— extended quote data with options greeks (cmd=17)on_trade_result(callback)— async trade execution results (cmd=19)on_book_update(callback)— order book / DOM pushes (cmd=23)
Reliability
- Async context manager (
async with MT5WebClient() as client:) - Auto heartbeat — periodic ping after login (configurable interval)
- Auto reconnect — optional reconnect on disconnect with exponential backoff
- Disconnect callback —
on_disconnect()for custom handling - Python logging — structured logging via
pymt5.clientandpymt5.transportloggers
Constants & Enums
TradeResultdataclass withretcode,description,success,deal,order,volume,pricefields- 33 MT5 return codes with human-readable descriptions
- Complete trade constants:
TRADE_ACTION_*(includingCLOSE_BY),ORDER_TYPE_*(includingSTOP_LIMIT),ORDER_FILLING_*,ORDER_TIME_* - Position/deal enums:
POSITION_TYPE_*,DEAL_TYPE_*(all 15 types),DEAL_ENTRY_* - Order states:
ORDER_STATE_*(all 7 states) - Symbol trade modes:
SYMBOL_TRADE_MODE_* - Command IDs exported:
CMD_GET_ACCOUNT,CMD_GET_SYMBOL_GROUPS,CMD_TRADE_UPDATE_PUSH,CMD_ACCOUNT_UPDATE_PUSH,CMD_SYMBOL_DETAILS_PUSH,CMD_TRADE_RESULT_PUSH,CMD_SUBSCRIBE_BOOK,CMD_BOOK_PUSH,CMD_GET_CORPORATE_LINKS
Tests
- 206 offline unit tests: protocol, schemas, roundtrip parsing, trade constants, symbol cache, volume conversion, reconnect logic, compatibility helpers, onboarding/OTP flows, local formula logic, full symbol schema, push handler registration, and extended rate/tick parsing
Live-verified against MetaQuotes-Demo on 2026-03-16. The current official Web Terminal reports build 5687, built on 2026-03-15. Verified features include: 6,104 symbols, 6 symbol groups, account info, positions, 60 M1 bars, deals, orders, tick push, all 9 order types, order book subscription, corporate links, notifications, verify code, trader params, and the current onboarding / OTP flows.
Install
pip install mt5-web-client
Or install from source:
git clone https://github.com/cloudQuant/pymt5.git
cd pymt5
pip install -e .
For development (tests + type checking):
pip install -e ".[dev]"
make check
Quick Start
import asyncio
from pymt5 import MT5WebClient
async def main():
async with MT5WebClient(auto_reconnect=True) as client:
await client.login(login=12345678, password="your-password")
# Load symbol cache
await client.load_symbols()
print(f"Loaded {len(client.symbol_names)} symbols")
# Full account info (balance, equity, margin, leverage)
acct = await client.get_account()
print(f"Balance: {acct['balance']}, Currency: {acct['currency']}, Leverage: 1:{acct['leverage']}")
# Symbol groups
groups = await client.get_symbol_groups()
print(f"Groups: {groups}")
# Subscribe to ticks
def on_ticks(ticks):
for t in ticks:
print(f"TICK {t.get('symbol', t['symbol_id'])}: bid={t['bid']} ask={t['ask']}")
client.on_tick(on_ticks)
await client.subscribe_symbols(["EURUSD", "GBPUSD"])
# Register for all push notifications
client.on_trade_update(lambda d: print(f"Positions: {len(d['positions'])}"))
client.on_account_update(lambda d: print(f"Balance: {d.get('balance')}"))
client.on_trade_transaction(lambda d: print(f"Transaction: type={d.get('update_type')}"))
client.on_trade_result(lambda d: print(f"Trade result: {d.get('result', {})}"))
# Place a market buy
result = await client.buy_market("EURUSD", 0.01, sl=1.0800, tp=1.1200)
print(f"Trade: {result}")
await asyncio.sleep(10)
asyncio.run(main())
Trading Examples
from pymt5 import (
MT5WebClient, ORDER_TYPE_BUY, ORDER_TYPE_SELL,
TRADE_RETCODE_DONE, ORDER_FILLING_IOC,
)
# Market orders
result = await client.buy_market("XAUUSD", 0.1, sl=2300.0, tp=2400.0)
result = await client.sell_market("EURUSD", 0.05, deviation=30)
# Pending orders
result = await client.buy_limit("EURUSD", 0.1, price=1.0800, sl=1.0750, tp=1.0900)
result = await client.sell_stop("GBPUSD", 0.1, price=1.2500)
# Stop-limit orders (trigger at price, then place limit at stop_limit_price)
result = await client.buy_stop_limit("EURUSD", 0.1, price=1.1000,
stop_limit_price=1.0950, sl=1.0900, tp=1.1100)
result = await client.sell_stop_limit("GBPUSD", 0.1, price=1.2400,
stop_limit_price=1.2450)
# Close position (auto-detects BUY/SELL direction)
result = await client.close_position("EURUSD", position_id=123456, volume=0.1)
# Close by opposite position (hedge netting)
result = await client.close_position_by("EURUSD", position_id=123456,
position_by=789012)
# Modify SL/TP
result = await client.modify_position_sltp("EURUSD", position_id=123456,
sl=1.0850, tp=1.0950)
# Cancel pending order
result = await client.cancel_pending_order(order=789012)
Push Notifications
# Combined position+order updates in one callback
def on_trade_change(data):
print(f"Positions: {len(data['positions'])}, Orders: {len(data['orders'])}")
client.on_trade_update(on_trade_change)
# Trade transaction (order add/update/delete, balance updates)
def on_transaction(data):
if data.get('update_type') == 2:
print(f"Balance update: {data['balance_info']}")
else:
print(f"Order transaction: type={data.get('transaction_type')}")
client.on_trade_transaction(on_transaction)
# Account balance/equity changes
client.on_account_update(lambda d: print(f"Balance: {d.get('balance')}"))
# Extended symbol data with options greeks
client.on_symbol_details(lambda d: print(f"Delta: {d[0].get('delta')}"))
# Async trade execution results
client.on_trade_result(lambda d: print(f"Retcode: {d.get('result', {}).get('retcode')}"))
# Order book (DOM) updates
client.on_book_update(lambda entries: print(f"Book: {len(entries)} symbols"))
# Login status changes (e.g. forced logout)
client.on_login_status(lambda r: print(f"Login status: code={r.code}"))
Protocol Flow
connect()— opens WebSocket, sends bootstrap (cmd=0), receives new AES keylogin()— sends credentials (cmd=28), receives session token, starts heartbeat- Data commands (get_account, get_symbols, get_rates, get_positions_and_orders, etc.)
close()— stops heartbeat, sends logout (cmd=2), closes WebSocket
Important: Do NOT call init_session() (cmd=29) after login — that command is for demo/real account creation, not session initialization.
Logging
import logging
logging.basicConfig(level=logging.DEBUG)
# Loggers: pymt5.client, pymt5.transport
Examples
Run any example from the project root:
pip install -e .
python examples/01_connect_and_account.py
| Example | Description |
|---|---|
01_connect_and_account.py |
Login, full account info (cmd=3), positions/orders/deals, ping |
02_market_data.py |
Symbol groups (cmd=9), symbol cache, spreads (cmd=20), OHLCV rates |
03_realtime_ticks.py |
Tick subscription, account/symbol details/login status push handlers |
04_trading.py |
Market/limit/stop orders, modify SL/TP, position close |
05_order_book.py |
Order book (DOM) subscription (cmd=22/23) |
06_all_push_notifications.py |
All 9 push notification types in one example |
07_all_order_types.py |
All 9 order types + modify + cancel + close + raw trade_request |
08_misc_features.py |
Corporate links, notifications, trader params, verify code, reconnect |
Command Coverage
| CMD | Name | Status |
|---|---|---|
| 0 | Bootstrap | Implemented |
| 2 | Logout | Implemented |
| 3 | Get Account | NEW — balance, credit, currency, leverage, name |
| 4 | Get Positions/Orders | Implemented |
| 5 | Get Trade History | Implemented |
| 6 | Get Symbols | Implemented |
| 7 | Subscribe Ticks | Implemented |
| 8 | Tick Push | Implemented |
| 9 | Get Symbol Groups | NEW — Forex, Metals, Indexes, etc. |
| 10 | Trade Update Push | NEW — order add/update/delete + balance updates |
| 11 | Get Rates | Implemented |
| 12 | Trade Request | Implemented |
| 13 | Symbol Update Push | Implemented |
| 14 | Account Update Push | NEW — real-time balance/equity changes |
| 15 | Login Status Push | Implemented |
| 17 | Symbol Details Push | NEW — extended quotes with options greeks |
| 18 | Get Full Symbols | Implemented |
| 19 | Trade Result Push | NEW — async trade execution results |
| 20 | Get Spreads | IMPROVED — proper schema parsing |
| 22 | Subscribe Book | NEW — order book / DOM subscription |
| 23 | Book Push | NEW — order book push with bid/ask levels |
| 24 | Change Password | Implemented |
| 27 | Verify Code | Implemented |
| 28 | Login | Implemented |
| 29 | Init Session | Implemented |
| 30 | Open Demo | Implemented |
| 39 | Open Real Account | Implemented |
| 40 | Send Verification Codes | Implemented |
| 34 | Get Symbols (gzip) | Implemented |
| 41 | Trader Params | Implemented |
| 42 | Notify | Implemented |
| 43 | OTP Setup / Disable | Implemented |
| 44 | Get Corporate Links | NEW — broker links |
| 51 | Ping | Implemented |
| 52 | Reserved Bootstrap Command | EXPERIMENTAL — bootstrap-only helper with unknown business meaning |
Commands 21, 25, 33, 37, 50, 52, 100-112 are still accepted by the transport allowlist but have no direct usage in the current public Web Terminal JavaScript source. Live probing on 2026-03-16 showed that 21, 25, 33, 37, 50, 100-112 time out with an empty payload, while 52 only returns an empty ACK on a pristine bootstrap-only socket and causes the server to drop the connection after cmd=29 or cmd=28. Commands 39, 40, and 43 are now implemented in pymt5.
Documentation
Full API documentation is available at pymt5.readthedocs.io/en/latest.
To build docs locally:
pip install -e ".[docs]"
cd docs && make html
CI/CD
This project uses GitHub Actions for continuous integration, testing across:
| Python 3.11 | Python 3.12 | Python 3.13 | |
|---|---|---|---|
| Linux (ubuntu-latest) | ✅ | ✅ | ✅ |
| macOS (macos-latest) | ✅ | ✅ | ✅ |
| Windows (windows-latest) | ✅ | ✅ | ✅ |
The CI pipeline also runs mypy type checking and builds the Sphinx documentation. For a local pre-push pass, run:
make check
Notes
- This package is experimental and tracks the MT5 Web Terminal protocol as observed in the public Web Terminal build 5687 (built on 2026-03-15)
- MetaQuotes may change the protocol at any time
- Volume encoding: MT5 uses integer volumes where
volume = lots × 10^precision. The MetaQuotes demo server uses precision=8, so 1.0 lot = 100,000,000 and 0.01 lot = 1,000,000 get_account()(cmd=3) returns balance, credit, currency, leverage, and name. Equity, margin, and profit are computed from positions- The Symbol Details push (cmd=17) schema may produce approximate values — the exact byte layout for options greeks varies by server
- Order book (cmd=22/23) may not produce pushes on all servers — depends on broker configuration
- Some commands like
trader_params(cmd=41) may cause the server to close the connection on rapid successive calls
License
MIT License — see LICENSE for details.
Metadata
Release files for mt5-web-client 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mt5_web_client-1.0.3.tar.gz | 162.4 kB | With provenance | Details for mt5_web_client-1.0.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mt5_web_client-1.0.3-py3-none-any.whl | Python 3 | none | any | Details for mt5_web_client-1.0.3-py3-none-any.whl |
Total release size: 239.8 kB
Release files / mt5_web_client-1.0.3.tar.gz
| Download URL | mt5_web_client-1.0.3.tar.gz |
|---|---|
| Size | 162.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
44f3e9edd300142a8e956f91a24ad60e6f07f27657d4cfbfaa5ffd0de743d36d
|
|
BLAKE2b-256 checksum How to use checksums |
f96e67a1d7941c9d3f2a756bafc0a2713ec32ccda4e085e78f985dffe8bd3dbe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logRelease files / mt5_web_client-1.0.3-py3-none-any.whl
| Download URL | mt5_web_client-1.0.3-py3-none-any.whl |
|---|---|
| Size | 77.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a0560cc636ddaad87c343322046cb3ed9b36225857a33fd5cc6ed80e1be48148
|
|
BLAKE2b-256 checksum How to use checksums |
6a456e836afcbf48dce99833c3ef76c0c3e075aab549f75928535a38cf60b3d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logSecurity for mt5-web-client 1.0.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for mt5_web_client-1.0.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.