首页 / 交易学院 / 小布知识库 / 如何向程序员定制 EA:需求、协作与防坑指南
如何向程序员定制 EA:需求、协作与防坑指南
🤝

如何向程序员定制 EA:需求、协作与防坑指南

从想要个能赚钱的机器人到可验收的算法说明书——交易者与技术之间的正确打开方式。

EA 开发实战 难度 · 入门 2026-02-08 13 分钟阅读
EA定制需求文档程序员协作防坑验收

一、EA 下单的两种 API

MQL5 下单有两条路:旧式的 OrderSend() 直接发交易请求,参数多、需自己拼 MqlTradeRequest;新式的 CTrade 类(标准库 Trade.mqh)把常用操作封装成 Buy()/Sell()/BuyLimit() 等方法,内部处理好请求结构。新手强烈建议用 CTrade,少踩一半坑。

无论哪条路,下单本质都是「构造请求 → 发给交易服务器 → 检查返回结果」。理解这个流程,比背函数签名更重要:你发的不是指令,而是一份可能被拒绝的申请书。

二、下单前的准备:句柄与品种检查

下单前务必确认品种已选中和可交易:SymbolSelect(_Symbol,true) 把品种加入市场报价窗口,SymbolInfoInteger(_Symbol,SYMBOL_TRADE_MODE) 检查是否允许交易。跳过这步,EA 在冷门品种上一下单就报「品种未选中」或「禁止交易」。

if(!SymbolSelect(_Symbol, true)) { Print("symbol select failed"); return; }
long tradeMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);
if(tradeMode == SYMBOL_TRADE_MODE_DISABLED) { Print("trading disabled"); return; }

三、市价单 Market

CTrade::Buy(lots, _Symbol, price, sl, tp, comment) 发买市价单;price 传 0 表示用当前最优价。注意市价单的成交价由服务器决定,可能和你看到的略有偏差(滑点)。在跳空行情里,这个偏差会被放大,所以重仓时尤其要控制单笔风险。

CTrade trade;
trade.Buy(0.1, _Symbol, 0, 0, 0, "test buy");
if(trade.ResultRetcode() != TRADE_RETCODE_DONE)
   Print("buy failed: ", trade.ResultRetcodeDescription());

四、挂单 Limit / Stop

限价单在更优价格成交,适合「等回踩再进」;止损单在突破价格成交,适合「突破跟随」。两者都用 CTrade 的 BuyLimit/SellStop 等方法,价格必须对齐 TickSize 网格(见价格离散性一文),否则会被拒。

挂单还有一个常被忽略的细节:有效期。MT5 的挂单默认在达到条件前一直有效(除非设了到期),你要清楚它会不会在不利的时点自动触发,尤其是在你不在电脑前的时候。

五、止损与止盈怎么挂

市价单可以在下单时一并带上 sl/tp;已持仓则要调用 PositionModify 或用 CTrade 修改。止损价同样要对齐网格,且不能在市价「太近」——很多券商对止损距市价有最小距离限制(StopLevel),太近会被拒。

double sl = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID) - 200*_Point, _digits);
trade.Buy(0.1, _Symbol, 0, sl, 0, "with SL");

六、错误处理:永远看 Retcode

下单后第一件事是检查返回码 trade.ResultRetcode()。常见拒绝如 TRADE_RETCODE_INVALID_PRICE(价格非法)、_INVALID_VOLUME(手数非法)、_NO_MONEY(保证金不足)、_MARKET_CLOSED(市场休市)。不检查就假设成功,是 EA 半夜偷偷不交易却没人知道的根源。

⚠ 别假设下单一定成功
网络抖动、服务器拒绝、保证金不够都会让下单失败。每个下单后都必须用 ResultRetcode 判断,并在失败时记录原因,否则你以为在跑策略,其实一单没成。

七、常见坑清单

八、实战下单模板

把上面几点收敛成一个可复用的下单函数:先检查品种与手数合法性,再算对齐后的 sl/tp,调 CTrade,最后根据 Retcode 记录成功或失败原因。这样一个函数用在所有信号上,既少错又易排查。

bool SafeBuy(double lots, double sl, double tp)
{
   if(lots < SymbolInfoInteger(_Symbol, SYMBOL_VOLUME_MIN)) return false;
   double p = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   trade.Buy(lots, _Symbol, p, sl, tp, "SafeBuy");
   if(trade.ResultRetcode() != TRADE_RETCODE_DONE)
      { Print("SafeBuy fail: ", trade.ResultRetcodeDescription()); return false; }
   return true;
}

九、把下单封装成可复用库

实战项目里,把 SafeBuy/SafeSell 这类带校验与日志的下单函数抽成独立的 .mqh 函数库,让所有 EA 共用。好处是风控逻辑只有一份、改一处全生效,且每次下单都留下统一格式的记录,便于事后审计「那天空单到底为什么没成」。这也是团队协作时避免各 EA 各写一套、互相矛盾的关键。

10、小结

✦ 下单是工程,不是咒语
EA 下单的可靠性,取决于你对请求结构、网格对齐、返回码检查这三件事的严谨。把下单当成需要被验证的工程模块,而不是一行咒语,EA 才活得久。

常见问题

新手直接用 CTrade(标准库 Trade.mqh),它封装了请求结构,少踩一半参数坑;需要精细控制请求字段时再回到 OrderSend。
大多是价格没对齐 TickSize 网格,或止损距市价小于 StopLevel。下单前用 SymbolInfoInteger 取步长并归一化,并按交易所最小止损距离校验。
检查 trade.ResultRetcode() 是否等于 TRADE_RETCODE_DONE,失败时用 ResultRetcodeDescription() 打印原因。绝不假设成功。