使用 MetaTrader 5 Python 构建类似 MQL5 的交易类·综合运用
📘

使用 MetaTrader 5 Python 构建类似 MQL5 的交易类·综合运用

第 3/3 篇

把交易动作收进一个构造函数

做 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'),意味着不显式传偏差时就走终端默认。 外汇与贵金属保证金交易杠杆高,实盘前务必在策略测试器用极小仓位验证下单逻辑,避免参数错配导致意外敞口。

MQL5 / C++
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。

MQL5 / C++
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 会话残留会占着终端端口。

MQL5 / C++
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 封装只解决开发效率,不替你管风险,回测通过也不代表实盘能复制。

MQL5 / C++
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
        """

常见问题

在类初始化时传入账户连接对象和品种参数,把下单、撤单方法定义为类函数,调用时只需实例化一次即可重复使用。
在封装类里写个批量下单方法,循环传入 buy_limit、sell_limit、buy_stop、sell_stop 等类型与价格,一次调用完成六种订单提交。
可以,小布盯盘的 AIGC 已内置常见订单诊断与提醒,把重复劳动交给小布,你专注决策即可。
当价格跌破某支撑后可能反弹又继续跌时,用它可在触发止损卖价后限价挂卖,适合震荡转跌场景,但外汇贵金属高风险需严控仓位。
不能急下结论,实盘滑点、流动性与回测假设不同,建议先开模拟账户验证至少两周再考虑实盘。