使用 MetaTrader 5 Python 构建类似 MQL5 的交易类(基础篇)
「用 Python 在 MT5 里搭一套交易信息类」
想在 MT5 外部用 Python 做策略监控或回测预处理,第一步是把 MQL5 里那套内置信息类搬过来。官方 Python 包 metaquotes.metatrader5 只给底层函数,不直接提供 CAccountInfo、CSymbolInfo 这类封装,得自己按字段对齐写类。 原文列了 9 个核心类:账户、品种、当前订单、历史订单、持仓、成交、终端、交易执行。实际工程里最常先写 CAccountInfo 和 CSymbolInfo,因为开仓前必查杠杆与 Tick 精度。 这套结构在 2026 年 1 月发布的示例里被归为「交易系统」分类,原始讨论帖显示有 559 次浏览、2 条跟帖,说明社区对跨语言复用 MQL5 对象模型有真实需求。外汇与贵金属杠杆高,任何账户或品种参数读取错误都可能触发异常下单,实盘前务必在策略测试器用历史数据跑通。
裸写下单与 CTrade 的差距
在 MT5 的 MQL5 环境里,标准库把算法交易系统的搭建门槛压低了一大截。开仓、校验、平仓这些动作,官方已经封装成现成函数和类,直接调用就能跑。 如果不依赖这些模块,连「脚本里开一个买入仓」这种最基础的需求都会变得笨重。下面两段代码都可以在 MetaTrader 5 里发出买入指令,但第一段走的是原生 MqlTradeRequest 结构,第二段用 CTrade 类。 原生写法要手动填 15 个以上的请求字段,从 action、symbol 到 deviation、type_filling 一个都不能漏;CTrade 版本只需 Set 几个参数再调 Buy(),代码行数少了一半多。字段越多,手误概率越高,对 MT5 下单全流程的理解要求也更强。 Python 侧有个 MetaTrader 5 包,能取行情、查持仓、发交易指令,能力上接近 MQL5。但它没有等效的内置交易类,写个简单程序也得堆不少行;更麻烦的是和 VS Code 等 IDE 的 Intellisense 兼容差,写着写着就得切去翻文档,开发体验明显打折。本文后续会基于这个包在 Python 里造一个交易类,把效率拉到接近 MQL5 的水平。外汇与贵金属杠杆高,任何下单封装都只是降低编码成本,不降低持仓风险。
class="type">void OnStart() { class="type">MqlTradeRequest request; class="type">MqlTradeResult result; class="type">MqlTick ticks; SymbolInfoTick(Symbol(), ticks); class=class="str">"cmt">//--- setting a trade request ZeroMemory(request); request.action =TRADE_ACTION_DEAL; request.symbol =Symbol(); request.magic =class="num">2025; request.volume =class="num">0.01; request.type =ORDER_TYPE_BUY; request.price =ticks.ask; request.sl =class="num">0; request.tp =class="num">0; request.deviation = class="num">10; class=class="str">"cmt">// Max price slippage in points request.magic = class="num">2025; request.comment = "Buy Order"; request.type_filling= ORDER_FILLING_IOC; class=class="str">"cmt">// or ORDER_FILLING_IOC, ORDER_FILLING_RETURN request.type_time = ORDER_TIME_GTC; class=class="str">"cmt">// Good till canceled class=class="str">"cmt">//--- action and class="kw">return the result if(!OrderSend(request, result)) { Print("OrderSend failed retcode: ", result.retcode); } } class="macro">#include <Trade\Trade.mqh> CTrade m_trade; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">//--- class="type">MqlTick ticks; SymbolInfoTick(Symbol(), ticks); m_trade.SetTypeFillingBySymbol(Symbol()); m_trade.SetExpertMagicNumber(class="num">2025); m_trade.SetDeviationInPoints(class="num">10); class=class="str">"cmt">//Slippage m_trade.Buy(class="num">0.01, Symbol(), ticks.ask,class="num">0,class="num">0,"Buy Order"); }
◍ 用 Python 接管 MT5 账户属性读取
MQL5 里的 CAccountInfo 类把经纪商账户的所有属性封装成方法,开 MT5 做风控或仓位计算时经常要调。把它在 Python 端重写一遍,配合 MetaTrader5 包,就能在本地脚本里随时抓账户状态,不必依赖 EA 内部逻辑。 这个类覆盖三类属性:整数与字符串类(如 login、leverage、trade_mode_description)、双精度类(balance、equity、margin_level 等)、文本类(server、company、currency)。额外还有 margin_check、max_lot_check 这类方法,能在下单前算 Required Margin 和最大可开手数。 下面这段是可直接跑的调用示例,初始化时填你自己的 terminal64.exe 路径。Demo 账户回测跑出来一组真实值:杠杆 400、余额 928.42、净值 926.21、保证金水平 32961.21%、Margin Call 线 90.0、StopOut 线 20.0。外汇和贵金属杠杆高,保证金水平掉到 StopOut 附近时平台会强平,用这类接口做实时预警比肉眼看终端更稳。 代码逐行拆解: import MetaTrader5 as mt5 —— 引入 MT5 官方 Python 接口 from Trade.AccountInfo import CAccountInfo —— 引入自写的账户信息类 if not mt5.initialize(r"c:\Users\...\terminal64.exe"): —— 按指定客户端路径初始化,失败则打印错误并退出 acc = CAccountInfo() —— 实例化账户对象 print(f"""...{acc.login()}...""") —— 用 f-string 把各方法返回值填进报告模板 mt5.shutdown() —— 断开 MT5 连接释放资源
class="kw">import MetaTrader5 as mt5 from Trade.AccountInfo class="kw">import CAccountInfo if not mt5.initialize(r"c:\Users\Omega Joctan\AppData\Roaming\Pepperstone MetaTrader class="num">5\terminal64.exe"): print("Failed to initialize Metatrader5 Error = ",mt5.last_error()) quit() acc = CAccountInfo() print(f""" Account Information ------------------- Login: {acc.login()} Name: {acc.name()} Server: {acc.server()} Company: {acc.company()} Currency: {acc.currency()} Trade Mode: {acc.trade_mode()} ({acc.trade_mode_description()}) Leverage: {acc.leverage()} Stopout Mode: {acc.stopout_mode()} ({acc.stopout_mode_description()}) Margin Mode: {acc.margin_mode()} ({acc.margin_mode_description()}) Trade Allowed: {acc.trade_allowed()} Trade Expert: {acc.trade_expert()} Limit Orders: {acc.limit_orders()} ------------------- Balance: {acc.balance()} Credit: {acc.credit()} Profit: {acc.profit()} Equity: {acc.equity()} Margin: {acc.margin()} Free Margin: {acc.free_margin()} Margin Level: {acc.margin_level()} Margin Call: {acc.margin_call()} Margin StopOut: {acc.margin_stopout()} ------------------- """) mt5.shutdown()
「用 CSymbolInfo 把品种属性一次拉全」
在 MT5 的 Python 环境里,CSymbolInfo 类把交易品种的属性访问封装成了一套方法,覆盖报价、成交量、点差、合约规模、库存费、时段数据等维度。比起逐个调 mt5.symbol_info(),这个类把 Bid/Ask/Last 的当日高低、StopsLevel、FreezeLevel、SwapLong/Short 这些容易漏掉的项都归到了一处。 外汇与贵金属品种的属性差异很大,例如 EURUSD 的 digits 通常是 5,point 为 1e-5,而 XAUUSD 常见 digits 为 2、point 为 0.01;不先读这些字段,止损距离和保证金计算都可能算错。开 MT5 终端后,用下面这段代码可以直接把 EURUSD 的核心属性打印出来验证。 别把 select 和 is_synchronized 当摆设 很多脚本一上来就读 bid,却没确认品种是否已加入市场报价且完成服务器同步。select(True) 保证品种在终端可见,is_synchronized() 返回 False 时读到的可能是陈旧数据,下单请求会被拒。 完整方法列表在 SymbolInfo.py 中,上面代码里的调用只是常用子集;想做分笔深度或时段持仓摘要,再去翻 session_* 那一组。
class="kw">import MetaTrader5 as mt5 from Trade.SymbolInfo class="kw">import CSymbolInfo if not mt5.initialize(r"c:\Users\Omega Joctan\AppData\Roaming\Pepperstone MetaTrader class="num">5\terminal64.exe"): print("Failed to initialize Metatrader5 Error = ",mt5.last_error()) quit() m_symbol = CSymbolInfo("EURUSD") print(f""" Symbol Information --------------------- Name: {m_symbol.name()} Selected: {m_symbol.select()} Synchronized: {m_symbol.is_synchronized()} --- Volumes --- Volume: {m_symbol.volume()} Volume High: {m_symbol.volume_high()} Volume Low: {m_symbol.volume_low()} --- Time & Spread --- Time: {m_symbol.time()} Spread: {m_symbol.spread()} Spread Float: {m_symbol.spread_float()} Ticks Book Depth: {m_symbol.ticks_book_depth()} --- Trade Levels --- Stops Level: {m_symbol.stops_level()} Freeze Level: {m_symbol.freeze_level()} --- Bid Parameters --- Bid: {m_symbol.bid()} Bid High: {m_symbol.bid_high()} Bid Low: {m_symbol.bid_low()} --- Ask Parameters --- Ask: {m_symbol.ask()} Ask High: {m_symbol.ask_high()} Ask Low: {m_symbol.ask_low()} --- Last Parameters --- Last: {m_symbol.last()} Last High: {m_symbol.last_high()} Last Low: {m_symbol.last_low()} --- Order & Trade Modes --- Trade Calc Mode: {m_symbol.trade_calc_mode()} ({m_symbol.trade_calc_mode_description()}) Trade Mode: {m_symbol.trade_mode()} ({m_symbol.trade_mode_description()}) Trade Execution Mode: {m_symbol.trade_execution()} ({m_symbol.trade_execution_description()}) --- Swap Terms --- Swap Mode: {m_symbol.swap_mode()} ({m_symbol.swap_mode_description()}) Swap Rollover class="num">3 Days: {m_symbol.swap_rollover_3days()} ({m_symbol.swap_rollover_3days_description()}) --- Futures Dates --- Start Time: {m_symbol.start_time()}
从 EURUSD 实例看品种属性怎么读
在 MT5 的 Python 接口里,symbol_info() 返回的是一整张品种参数表,但真要做风控和仓位计算,只有其中几行是天天要盯的。上面这份 EURUSD 实时快照(2025-05-21 20:30:36 取数)能直接当模板对照。 Digits=5、Point=1e-05 说明这是五位数报价,最小价格变动就是 0.00001;Contract Size=100000 代表标准手每手 10 万基础货币,Lots Step=0.01 意味着你最小能下 0.01 手(微仓)。这些数不核对,EA 里的手数算法可能直接越界报错。 保证金和掉期是隐性成本大头:Initial Margin=100000.0 表示开 1 标准手要冻结 10 万保证金(账户货币 EUR),Swap Long=-8.99 点、Swap Short=4.5 点,周三 rollover 3 天——拿隔夜多单会被收 8.99 点,空单反而返 4.5 点。外汇和贵金属杠杆高,掉期在震荡市会吃掉不少利润,下单前务必在终端「规格」里复算一遍。 Trade Execution Mode=2 是市价执行,Stops Level=0 和 Freeze Level=0 代表止损挂单没有最小距离限制;但 Spread 显示 0 只是取样时刻流动性重叠的瞬像,实盘欧美点差常态在 0.5~1.5 点浮动,不能拿这个当交易成本假设。
◍ 从盘后会话字段读 EURUSD 多空失衡
一段交易会话结束,MT5 后台吐出的统计字段比图表上的影线更直白。上面这组样本里,Session Sell Orders 只有 2 笔,但 Session Sell Volume 干到 13.0,Session Buy Volume 才 3.0——卖单少、卖量重,是少数账户在集中倒货。 价格端 Session Open 1.12817、Session Close 1.12842,收盘比开盘高 2.5 点,看似多头收尾;但买量仅为卖量的约 23%,这种量价背离在外汇 EURUSD 上往往暗示上行缺乏广度,后续回吐概率偏高。贵金属与外汇均属高杠杆品种,此类会话数据只作微观结构参考,不构成方向定论。 Session Interest、AW、Price Settlement 及 Limit Min/Max 全为 0.0,说明该会话无隔夜利息累积、无加权偏移、也未触发限价边界——纯日内脉冲。开 MT5 用自定义脚本抓这几项,连跑一周就能看出你常做的时段里谁在控盘。