使用 MetaTrader 5 Python 构建类似 MQL5 的交易类·综合运用
把交易动作收进一个构造函数
做 MT5 自动化,真正下单那一步靠的是交易类,而不是只读行情和账户信息的那些工具类。把开仓、挂单、平仓都封装到同一个类里,调用时才不会东漏一个参数西忘一个偏差值。 原生写法里,幻数、成交类型、点偏差往往要分别调函数去设。一旦某个设置函数被漏掉,运行期就可能因为空值直接报错。把这几个参数全部塞进类构造函数,初始化即定型,后面每次发单都自动带上去,人为失误的概率会降下来。 这个类能覆盖的操作用法很直接:OrderOpen / OrderModify / OrderDelete 管挂单,PositionOpen / PositionModify / PositionClose 管持仓,外加 Buy、Sell 以及四种止损限价变体做快捷入口。下面这段 Python 封装把上述方法一次列清,复制进 IDE 就能改参数跑。 [CODE] 中的 __init__ 接收 magic_number(订单幻数)、filling_type_symbol(成交类型对应的品种标识)、deviation_points(允许的点差偏差)三个参数,后续 order_open 的默认 sl/tp 为 0.0,type_time 默认 ORDER_TIME_GTC 表示挂单永久有效直到成交或删除。position_close 的 deviation 默认值为 float('nan'),意味着不显式传偏差时就走终端默认。 外汇与贵金属保证金交易杠杆高,实盘前务必在策略测试器用极小仓位验证下单逻辑,避免参数错配导致意外敞口。
class CTrade: def __init__(self, magic_number: class="type">int, filling_type_symbol: str, deviation_points: class="type">int): order_open(self, symbol: str, volume: class="type">float, order_type: class="type">int, price: class="type">float, sl: class="type">float = class="num">0.0, tp: class="type">float = class="num">0.0, type_time: class="type">int = mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime = None, comment: str = "") -> class="type">bool order_modify(self, ticket: class="type">int, price: class="type">float, sl: class="type">float, tp: class="type">float, type_time: class="type">int = mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime = None, stoplimit: class="type">float = class="num">0.0) -> class="type">bool: order_delete(self, ticket: class="type">int) -> class="type">bool position_open(self, symbol: str, volume: class="type">float, order_type: class="type">int, price: class="type">float, sl: class="type">float, tp: class="type">float, comment: str="") -> class="type">bool position_modify(self, ticket: class="type">int, sl: class="type">float, tp: class="type">float) -> class="type">bool position_close(self, ticket: class="type">int, deviation: class="type">float=class="type">float("nan")) -> class="type">bool buy(self, volume: class="type">float, symbol: str, price: class="type">float, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, comment: str="") -> class="type">bool sell(self, volume: class="type">float, symbol: str, price: class="type">float, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, comment: str="") -> class="type">bool buy_limit(self, volume: class="type">float, price: class="type">float, symbol: str, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, type_time: class="type">float=mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime=None, comment: str="") -> class="type">bool sell_limit(self, volume: class="type">float, price: class="type">float, symbol: str, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, type_time: class="type">float=mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime=None, comment: str="") -> class="type">bool buy_stop(self, volume: class="type">float, price: class="type">float, symbol: str, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, type_time: class="type">float=mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime=None, comment: str="") -> class="type">bool sell_stop(self, volume: class="type">float, price: class="type">float, symbol: str, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, type_time: class="type">float=mt5.ORDER_TIME_GTC,
「用封装类一口气挂完六种订单」
在 MT5 的 Python 环境里,把市价单和挂单拆成统一接口能省掉大量重复代码。上面这段演示了 CTrade 类如何把 buy / sell / buy_limit / sell_limit / buy_stop / sell_stop / buy_stop_limit / sell_stop_limit 全部收成一行调用,返回布尔值告诉你下单是否成功。 注意 buy_stop_limit 的 price 参数实际是触发后的限价位,而触发止损价(stop price)在类内部另算,EURUSD 示例中触发价设在 ask+0.0020、限价位贴近触发价,属于典型的突破回接逻辑。外汇与贵金属杠杆高,这类单子若碰上跳空可能不成交或滑点,实盘前务必在策略测试器跑一遍。 例子中挂单统一用 ORDER_TIME_SPECIFIED,过期时间设为 datetime.now()+timedelta(minutes=1),也就是 1 分钟后失效。deviation_points=100 代表允许 10 个点(按多数券商 1 point=0.00001)的成交偏移,mini lot 用 lots_min() 动态取,避免手填导致 reject。
buy_stop_limit(self, volume: class="type">float, price: class="type">float, symbol: str, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, type_time: class="type">float=mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime=None, comment: str="") -> class="type">bool sell_stop_limit(self, volume: class="type">float, price: class="type">float, symbol: str, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, type_time: class="type">float=mt5.ORDER_TIME_GTC, expiration: class="type">class="kw">datetime=None, comment: str="") -> class="type">bool class="kw">import MetaTrader5 as mt5 from Trade.Trade class="kw">import CTrade from Trade.SymbolInfo class="kw">import CSymbolInfo from class="type">class="kw">datetime class="kw">import class="type">class="kw">datetime, timedelta 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() symbol = "EURUSD" m_symbol = CSymbolInfo(symbol=symbol) m_trade = CTrade(magic_number=class="num">1001, deviation_points=class="num">100, filling_type_symbol=symbol) m_symbol.refresh_rates() ask = m_symbol.ask() bid = m_symbol.bid() lotsize = m_symbol.lots_min() # === Market Orders === m_trade.buy(volume=lotsize, symbol=symbol, price=ask, sl=class="num">0.0, tp=class="num">0.0, comment="Market Buy Pos") m_trade.sell(volume=lotsize, symbol=symbol, price=bid, sl=class="num">0.0, tp=class="num">0.0, comment="Market Sell Pos") # expiration time for pending orders expiration_time = class="type">class="kw">datetime.now() + timedelta(minutes=class="num">1) # === Pending Orders === # Buy Limit - price below current ask m_trade.buy_limit(volume=lotsize, symbol=symbol, price=ask - class="num">0.0020, sl=class="num">0.0, tp=class="num">0.0, type_time=mt5.ORDER_TIME_SPECIFIED, expiration=expiration_time, comment="Buy Limit Order") # Sell Limit - price above current bid m_trade.sell_limit(volume=lotsize, symbol=symbol, price=bid + class="num">0.0020, sl=class="num">0.0, tp=class="num">0.0, type_time=mt5.ORDER_TIME_SPECIFIED, expiration=expiration_time, comment="Sell Limit Order") # Buy Stop - price above current ask m_trade.buy_stop(volume=lotsize, symbol=symbol, price=ask + class="num">0.0020, sl=class="num">0.0, tp=class="num">0.0, type_time=mt5.ORDER_TIME_SPECIFIED, expiration=expiration_time, comment="Buy Stop Order") # Sell Stop - price below current bid m_trade.sell_stop(volume=lotsize, symbol=symbol, price=bid - class="num">0.0020, sl=class="num">0.0, tp=class="num">0.0, type_time=mt5.ORDER_TIME_SPECIFIED, expiration=expiration_time, comment="Sell Stop Order") # Buy Stop Limit - stop price above ask, limit price slightly lower(near it) m_trade.buy_stop_limit(volume=lotsize, symbol=symbol, price=ask + class="num">0.0020, sl=class="num">0.0, tp=class="num">0.0, type_time=mt5.ORDER_TIME_SPECIFIED, expiration=expiration_time, comment="Buy Stop Limit Order") # Sell Stop Limit - stop price below bid, limit price slightly higher(near it)
◍ 用 sell_stop_limit 挂双向触发卖单
在 MT5 的 Python 环境里,想同时吃“先破位、再反弹”的节奏,可以用 sell_stop_limit 一步挂好。它和单纯 sell_stop 不同:价格要先触到挂单价(本例为 bid - 0.0020),订单才转为限价卖单等待成交,不是一触碰就市价丢出去。 参数里 sl 和 tp 都设成 0.0,代表这单暂时不绑止损止盈,纯粹用价格结构进场;type_time 用 ORDER_TIME_SPECIFIED 并给 expiration_time,意味着挂单过了指定时间还没触发就自动作废,避免隔夜未知风险堆积。 外汇与贵金属杠杆高,这类未成交挂单也可能因点差跳空直接滑到不利价位,实盘前请在策略测试器用历史数据跑一遍确认触发逻辑。 最后调完参数记得 mt5.shutdown() 断开连接,否则 Python 会话残留会占着终端端口。
m_trade.sell_stop_limit(volume=lotsize, symbol=symbol, price=bid - class="num">0.0020, sl=class="num">0.0, tp=class="num">0.0, type_time=mt5.ORDER_TIME_SPECIFIED, expiration=expiration_time, comment="Sell Stop Limit Order") mt5.shutdown()
别急着下结论
把 MetaTrader 5 的 python 包扩展成语法贴近 MQL5 的自定义模块后,老交易员不必重学一套 API 就能写 Python 端应用。CTrade、CAccountInfo 这些类在 VS Code 里配上 docstring,参数高亮和自动补全就回来了,编码出错的概率倾向下降。 附件里 Trade 目录有 8 个类文件,测试脚本 9 个,main.py 是直接能跑的 Python 版交易机器人雏形。下载的 ZIP 约 43.78 KB,解压后先用 symbolinfo_test.py 验证一下行情接口再动真金白银。 下面这段 buy 方法的定义,就是 docstring 缓解 Intellisense 问题的实例,开 VS Code 挂上这个注释就能看到参数提示: 外汇与贵金属杠杆高,这类 Python 封装只解决开发效率,不替你管风险,回测通过也不代表实盘能复制。
class CTrade: # .... def buy(self, volume: class="type">float, symbol: str, price: class="type">float, sl: class="type">float=class="num">0.0, tp: class="type">float=class="num">0.0, comment: str="") -> class="type">bool: """ Opens a buy(market) position. Args: volume: Trade volume(lot size) symbol: Trading symbol(e.g., "EURUSD") price: Execution price sl: Stop loss price(optional, class="kw">default=class="num">0.0) tp: Take profit price(optional, class="kw">default=class="num">0.0) comment: Position comment(optional, class="kw">default="") Returns: class="type">bool: True if order was sent successfully, False otherwise """