MT5 Python下单报错Invalid stops问题排查与解决
问题场景
在Windows 11系统下使用Python 3.7对接RoboMarkets的MT5接口,调用自定义卖单函数时无法成功下单,返回retcode=10016且提示Invalid stops,同时出现symbol_info_tick() failed, error code = (1, 'Success')的异常提示。
自定义下单函数代码
def open_trade_sell2(action, symbol, lot, tp, deviation, ea_magic_number,comment): '''https://www.mql5.com/en/docs/integration/python_metatrader5/mt5ordersend_py ''' # prepare the buy request structure symbol_info = get_info(symbol) print("symbol info",symbol_info) #symbol_info_tick_dict = mt5.symbol_info_tick(symbol)._asdict() #for prop in symbol_info_tick_dict: # print(" {}={}".format(prop, symbol_info_tick_dict[prop])) if not mt5.initialize(): print("initialize() failed, error code =",mt5.last_error()) quit() # display the last GBPUSD tick lasttick=mt5.symbol_info_tick(symbol) print(lasttick) if action == 'buy': trade_type = mt5.ORDER_TYPE_BUY price = mt5.symbol_info_tick(symbol).ask pass elif action =='sell': trade_type = mt5.ORDER_TYPE_SELL price = mt5.symbol_info_tick(symbol).bid print(price) pass #point = mt5.symbol_info(symbol).point if tp< price: print("el precio mt5 es:", price) tp=str(tp) tp=tp[:8] tp=float(tp) now = time.time() if comment == "5min": el_tiempo = int(now + 300) if comment == "15min": el_tiempo = int(now + 900) if comment == "30min": el_tiempo = int(now + 1800) if comment == "1hour": el_tiempo = int(now + 3600) buy_request = { "action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": lot, "type": trade_type, "price": price, "sl": price + (price -tp), "tp": tp, "deviation": deviation, "magic": ea_magic_number, "comment": comment, "type_time": mt5.ORDER_TIME_SPECIFIED , # good till cancelled "expiration": el_tiempo, "type_filling": mt5.ORDER_FILLING_IOC, } # send a trading request result = mt5.order_send(buy_request) print("¿orden enviada?") print("resultado de la orden", result) else: print("no puede vender") result = "no posible comprar" buy_request = "no posible comprar nene" return result, buy_request
错误返回结果
OrderSendResult(retcode=10016, deal=0, order=0, volume=0.0, price=0.0, bid=0.0, ask=0.0, comment='Invalid stops', request_id=0, retcode_external=0, request=TradeRequest(action=1, magic=4494609, order=0, symbol='EURCHF', volume=0.1, price=0.97846, stoplimit=0.0, sl=0.978479, tp=0.978441, deviation=100, type=1, type_filling=1, type_time=2, expiration=1682463619, comment='1hour', position=0, position_by=0))
问题原因
止损计算逻辑错误+未满足平台最小止损距离要求
卖单的止损(SL)应设置在当前报价上方,但你的计算方式sl = price + (price - tp)虽然数值方向正确,但计算出的SL与当前价格的差值(0.000019)远低于RoboMarkets对EURCHF要求的最小止损距离,平台直接判定止损无效。MT5初始化时机错误
你在调用get_info(symbol)(推测内部调用了mt5.symbol_info_tick)之后才执行mt5.initialize(),未初始化就调用MT5 API会导致奇怪的错误返回(1, 'Success'),同时可能影响后续报价获取的准确性。手动截断TP精度破坏价格格式
通过字符串截断处理TP的方式(tp=str(tp); tp=tp[:8]; tp=float(tp))会强制修改价格精度,不符合EURCHF的报价精度要求(通常为5位小数),进一步导致止损止盈参数无效。
修复方案
1. 修正止损止盈计算逻辑,遵守平台规则
先获取品种的点值和最小止损距离,再计算符合要求的SL/TP:
# 在初始化后添加以下代码获取品种关键参数 symbol_info = mt5.symbol_info(symbol) point = symbol_info.point min_stop_distance = symbol_info.trade_stops_level * point # 平台要求的最小止损距离 # 替换原卖单逻辑中的SL计算 elif action =='sell': trade_type = mt5.ORDER_TYPE_SELL price = mt5.symbol_info_tick(symbol).bid print(price) # 确保SL距离不小于最小要求,TP方向正确 sl = price + min_stop_distance # 严格遵循平台最小止损 # 如果传入的TP符合要求则使用,否则按规则生成 if tp < price and (price - tp) >= min_stop_distance: tp = round(tp, symbol_info.digits) else: tp = price - 50 * point # 示例:默认50点止盈,可按需调整
2. 调整MT5初始化时机
将mt5.initialize()移至所有MT5 API调用之前,避免未初始化调用:
def open_trade_sell2(action, symbol, lot, tp, deviation, ea_magic_number,comment): '''下单函数''' # 优先初始化MT5 if not mt5.initialize(): print("initialize() failed, error code =",mt5.last_error()) return None, None # 用返回替代quit(),避免终止整个程序 # 之后再执行其他API调用 symbol_info = get_info(symbol) print("symbol info",symbol_info) lasttick=mt5.symbol_info_tick(symbol) print(lasttick) # 后续逻辑...
3. 移除手动截断TP的代码,用精度对齐替代
# 替换原TP截断代码 digits = symbol_info.digits tp = round(tp, digits) # 按品种精度对齐价格
4. 可选:调整订单有效期参数
若IOC订单配合指定有效期仍有问题,可尝试改用无限有效期:
buy_request = { # ... 其他参数 "type_time": mt5.ORDER_TIME_GTC, # 取消有效期限制 # "expiration": el_tiempo, # 注释或删除该行 # ... }
验证步骤
- 调用
print(symbol_info)查看trade_stops_level、digits、point参数,确认平台规则。 - 下单前打印SL、TP、Price的值,检查:卖单SL > Price,TP < Price,且SL-Price >= 最小止损距离。
内容的提问来源于stack exchange,提问作者jjjjj

