保持敬畏之心
交易是一场持久战

​MQL4(11):EA布局的标准结构和运行流程

从这节课开始,我们正式进入实战EA的开发环节。

构建一个EA,就像是建造一栋房子,绝不是随意堆砌砖块。所有专业、稳定、高效的EA,都遵循着一个经过时间考验的、标准的建筑“蓝图”。这个蓝图,就是我们今天要掌握的EA标准结构。

一个标准的EA主要由7大模块构成,并遵循着清晰的“生命周期”:初始化 实时处理 退出清理。

EA的建筑蓝图:7大核心模块

预处理指令区:房子的“施工许可证”与“材料清单”。这部分位于代码的最顶部,是给编译器看的“施工前说明”,以#号开头。

  • #property: 声明EA的基本信息(版权、版本号、网址等),就像是房子的名牌和房产证。
  • #include: 引入外部的函数库文件,好比是把预制好的“厨房模块”、“浴室模块”整个搬进来组装。
  • #define: 定义一些全局常量,比如固定的滑点、EA的名称等。

外部输入参数区:房子的“智能控制面板”。这是我们用input(或extern)关键字定义的用户设置项。它让使用者无需修改代码,就能在EA加载时,通过参数面板灵活地调整策略,是连接代码与用户的桥梁。

全局变量区:房子的“中央信息中心”。这里存放着需要在多个函数之间共享的数据,它们的生命周期和EA一样长。比如EA的总交易次数、当前持仓状态等。这些是EA内部流转的信息,用户无法在外部面板上看到。

初始化函数 OnInit():房子的“开工仪式”

int OnInit()

这是EA的第一个“生命周期”函数。当你把EA加载到图表上时,它会被执行一次,且仅执行一次。 它的核心任务是“准备工作”和“环境检查”:

  • 初始化全局变量。
  • 检查当前账户、服务器、图表环境是否符合EA运行要求。
  • 打印EA启动日志。
  • 创建需要的图表对象(如按钮、面板)。

学长建议:OnInit()是你的第一道,也是最重要的一道“安全门”。如果环境检查失败(比如用户设置了不合理的参数),你应该在这里return(INIT_FAILED),阻止EA带着错误的设置继续运行,从而避免不必要的亏损。

主逻辑函数 OnTick():房子的“日常运作核心”

void OnTick()

这是EA的“心脏”和“大脑”。只要图表窗口在,市场每发生一次价格变动(Tick),这个函数就会被不知疲倦地调用一次。 EA 99%的工作时间都在这里度过,负责所有核心的交易逻辑:

  • 分析行情,寻找交易信号。
  • 执行开仓、平仓操作。
  • 管理已有的持仓(如追踪止损)。

学长避坑指南:在活跃的市场,OnTick()的执行频率会非常高。如果你在里面放入了复杂的计算,会导致EA处理不过来。一个非常重要的专业技巧是,在OnTick()的开头加入“新K线判断”逻辑,让EA从“每个tick都思考一次”的“高频交易员”,变成“每根K线只在开盘时思考一次”的“冷静决策者”。

清理函数OnDeinit():房子的“离场清扫”

void OnDeinit(const int reason)

当EA被卸载、图表被关闭、或者MT4软件关闭时,这个函数会被执行一次。 它的任务是“清理和收尾”,确保EA“优雅地离开”:

  • 删除在图表上创建的所有图形对象(按钮、标签、线条等)。
  • 释放占用的系统资源。
  • 打印EA的退出日志和最终的业绩总结。

一个专业的EA,一定会把自己留在图表上的“痕迹”清理得干干净净。

自定义函数区:房子的“专业功能房”。这里是你自己创建的、用来处理特定任务的函数。比如OpenBuyTrade()开仓函数、CalculateRiskLotSize()手数计算函数、ManageTrailingStop()追踪止损函数等。

把复杂的逻辑拆分到不同的自定义函数中,然后让OnTick()作为“总指挥”去调用它们。这是让代码结构保持清晰、易于维护的唯一方法。

EA的生命周期流程图

EA加载到图表 OnInit() (初始化,执行1次)

市场来一个新报价(Tick)  OnTick() (主逻辑,循环执行)

EA从图表移除 OnDeinit() (清理,执行1次)


一个更规范的EA结构模板

下面的模板结构更清晰,并包含了详细的中文注释。这是你未来所有EA项目的一个绝佳起点,请仔细理解每一部分的用途。

// === 1. 预处理指令区 ===
#property strict                 // 开启严格模式 (强烈建议所有新代码都加上)
#property copyright              "Your Name"
#property link                   "Your Website"
#property version                "1.00"         // EA版本号,方便管理

// === 2. 外部输入参数区 (input比extern更安全) ===
input group      "交易核心参数"
input double     LotSize          = 0.1;       // 交易手数
input int        Slippage         = 3;         // 最大允许滑点
input int        TakeProfit       = 500;       // 止盈点数 (5位平台)
input int        StopLoss         = 300;       // 止损点数 (5位平台)
input int        MagicNumber      = 123456;    // EA魔术号 (身份证)

input group      "功能开关"
input bool       UseTrailingStop  = true;      // 功能开关:是否启用追踪止损?

// === 3. 全局变量区 (程序内部状态) ===
int      g_ticket          = -1;   // 全局变量: 保存当前持仓的订单号
bool     g_hasOpenPosition = false; // 全局变量: 标记是否已有持仓

//+------------------------------------------------------------------+
//| 4. 初始化函数 (EA加载时执行一次)                                 |
//+------------------------------------------------------------------+
int OnInit()
{
   Print("EA初始化完成: ", MQLInfoString(MQL_PROGRAM_NAME));
   g_hasOpenPosition = false; // 初始化持仓状态
   return(INIT_SUCCEEDED);     // 返回初始化成功
}

//+------------------------------------------------------------------+
//| 5. 清理函数 (EA被卸载时执行一次)                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print("EA卸载,原因代码: ", reason);
   // 如果有创建图表对象,在这里清理
   // ObjectsDeleteAll(0, "prefix_");
}

//+------------------------------------------------------------------+
//| 6. 核心执行函数 (每个新的Tick执行)                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // --- 核心逻辑流程 ---

   // 1. 新K线判断 (避免重复执行)
   if(!IsNewBar())
      return; // 如果不是新K线,则直接退出本次OnTick,等待下一根

   // 2. 检查持仓状态
   if(!g_hasOpenPosition)
   {
      // 2.1 如果没有持仓,则检查入场条件
      if(CheckEntrySignal())
      {
         OpenNewOrder(); // 如果信号成立,开仓
      }
   }
   else
   {
      // 2.2 如果有持仓,则执行持仓管理
      ManageOpenPositions();
   }
}

//+------------------------------------------------------------------+
//| 7. 自定义函数区 (所有辅助功能)                                  |
//+------------------------------------------------------------------+

// 函数:检测是否形成新K线
bool IsNewBar()
{
   static datetime lastBarTime = 0; // 静态变量,有记忆功能
   if(Time[0] != lastBarTime)
   {
      lastBarTime = Time[0];
      return true;
   }
   return false;
}

// 函数:检查入场信号
bool CheckEntrySignal()
{
   // --- 在这里替换为你自己的交易信号逻辑 ---
   // 示例:RSI低于30,产生买入信号
   if(iRSI(NULL, 0, 14, PRICE_CLOSE, 0) < 30)
   {
      return true;
   }
   return false;
}

// 函数:执行开仓
void OpenNewOrder()
{
   double price = Ask;
   double sl = price - StopLoss * _Point;
   double tp = price + TakeProfit * _Point;
   int ticket = OrderSend(Symbol(), OP_BUY, LotSize, price, Slippage, sl, tp, "EA Order", MagicNumber, 0, clrBlue);

   if(ticket > 0)
   {
      g_ticket = ticket;
      g_hasOpenPosition = true;
      Print("开仓成功,订单号: ", ticket);
   }
   else
   {
      Print("开仓失败,错误代码: ", GetLastError());
   }
}

// 函数:管理已有持仓 (例如追踪止损)
void ManageOpenPositions()
{
   if(UseTrailingStop)
   {
      // ApplyTrailingStop(); // 在这里调用追踪止损函数
   }
}
//+------------------------------------------------------------------+
赞(0)
未经允许不得转载:图道交易 » ​MQL4(11):EA布局的标准结构和运行流程
分享到

评论 抢沙发