Skip to content

πŸ—οΈ Architecture & Data Flow (PyMT5 + MT5)

A practical map of how our Python SDK, gRPC services, and the MT5 terminal talk to each other β€” with just enough humor to keep the margin level above 100%.


πŸ—ΊοΈ Big Picture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 MT5 Terminal                  β”‚
β”‚      (broker login, quotes, trades)           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ local/IPC
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      mt5_term_api.* (gRPC server)             β”‚
β”‚      Services: MarketInfo, Trade...           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ gRPC
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Python SDK (MetaRpcMT5)                  β”‚
β”‚      MT5Account (package/MetaRpcMT5/...)      β”‚
β”‚      + generated pb2/pb2_grpc stubs           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ async/await
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Your App / Examples                      β”‚
β”‚      (docs, examples, services)               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

You write: high‑level await acct.method(...) calls. SDK does: request building, metadata, deadlines, retries, unwraps .reply.data. Server does: talks to the real MT5 terminal and executes.


βš™οΈ Main Components (by folders)

πŸ”© SDK & gRPC contracts (client side)

  • package/MetaRpcMT5/mt5_account.py β€” MT5Account wrappers (public API).
  • package/MetaRpcMT5/mt5_term_api_*.py β€” pb2 messages (requests/replies/enums).
  • package/MetaRpcMT5/mt5_term_api_*_pb2_grpc.py β€” stubs (client bindings).
  • package/MetaRpcMT5/mrpc_mt5_error_pb2.py β€” errors/retcodes mapping.

🧠 App layer & helpers (optional services)

  • app/core/mt5_connect_helper.py β€” connection bootstrap, metadata.
  • app/core/mt5_service.py β€” higher‑level service orchestration.
  • app/services/streams_service.py β€” stream fan‑out (ticks/trade events).
  • app/services/trading_service.py β€” trading flows (send/modify/close).
  • app/services/history_service.py β€” history pagination & caching.
  • app/patches/*.py β€” compatibility tweaks (symbol params, market info, etc.).

πŸ“š Docs & Examples

  • docs/MT5Account/** β€” method specs & overviews (what you read now).
  • examples/quick_start_connect.py β€” minimal bootstrap.
  • examples/mt5_account_ex.py β€” end‑to‑end usage playground.

πŸ”€ Data Flow (Unary)

  1. Your call β†’ `await acct.symbol_info_double(...)
  2. Wrapper builds Request, sets metadata, computes timeout from deadline.
  3. Stub β†’ ServiceStub.Method(request, metadata, timeout).
  4. Server performs the operation via MT5 terminal.
  5. Reply β†’ SDK unwraps reply.data β†’ you get clean *.Data (or a primitive like float).
from MetaRpcMT5 import mt5_term_api_account_information_pb2 as ai_pb2
value = await acct.account_info_double(ai_pb2.AccountInfoDoublePropertyType.ACCOUNT_EQUITY)
print(f"Equity: {value:.2f}")

πŸ”„ Data Flow (Streaming)

Streams keep a channel open and push events. Use cancellation_event and keep handlers non‑blocking.

import asyncio
stop = asyncio.Event()
async for ev in acct.on_trade(cancellation_event=stop):
    queue.put_nowait(ev)  # heavy work elsewhere
    if should_stop(ev):
        stop.set()

Common streams:

  • on_symbol_tick β€” live ticks per symbol.
  • on_trade β€” high‑level deltas (orders/positions/deals) + account snapshot.
  • on_trade_transaction β€” low‑level transaction + request + result.
  • on_position_profit β€” timed P/L frames for positions.
  • on_positions_and_pending_orders_tickets β€” IDs‑only snapshots for set‑diff.

Links: Subscriptions Overview


🧩 RPC Domains & Where to Look

  • Account Info β†’ balance/equity/margins: Overview
  • Orders Β· Positions Β· History β†’ live & past trading objects: Overview
  • Symbols & Market β†’ symbol catalog, properties, sessions, DOM: Overview
  • Trading Ops β†’ send/modify/close, checks, margin calc: Overview

✨ Highlights

  • Wrappers return payloads (*.Data) already unwrapped from replies.
  • Deadlines become stub timeouts; pass them for predictable latency.
  • Retries & reconnects handled in wrappers (execute_with_reconnect(...)).
  • UTC timestamps everywhere; convert once near UI.
  • Server‑side sorting via enums; client‑side filtering for symbol lists is often cheaper.

πŸ› οΈ Developer Notes

  • Prefer enums from pb2 (no β€œmagic numbers”).
  • For Market Book use the trio: market_book_add β†’ market_book_get β†’ market_book_release.
  • Cold‑start: get a full snapshot once (OpenedOrders), then maintain via streams.
  • Cheap change detection: IDs‑only stream β†’ fetch details only on change.

πŸ“¦ Minimal Bootstrap (Example)

from MetaRpcMT5.mt5_account import MT5Account
from MetaRpcMT5 import mt5_term_api_account_helper_pb2 as ah_pb2

acct = MT5Account(...)
od = await acct.opened_orders(
    ah_pb2.BMT5_ENUM_OPENED_ORDER_SORT_TYPE.BMT5_OPENED_ORDER_SORT_BY_OPEN_TIME_ASC
)
print(len(od.opened_orders), len(od.position_infos))

πŸ§ͺ Debug & Troubleshooting

  • Log transport issues with app/utils/grpc_debug.py.
  • Keep both retcode int and string (see mrpc_mt5_error_pb2.py).
  • If a stream "goes quiet", check that your handler isn’t blocking and the release was not called prematurely (DOM).