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

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

语法基础已经了解的差不多了,从这节开始,我们进入EA开发环节。

一个标准的EA结构包含7大模块,在EA执行的过程中遵循清晰的生命周期:初始化 实时处理 退出(清理资源)

预处理指令区

位置在代码最顶部,#property:声明EA的基本信息(版权、网站、版本等);#include:引入库文件、头文件;#define:定义常量(可重复使用)。

#property copyright   "Your Name"
#property link        "https://www.eamql5.com"
#include <stdlib.mqh>
#define SLIPPAGE 3

外部输入参数区

关键字:extern。作用:定义用户可修改 的策略参数(在EA参数面板中显示),无需改代码即可灵活调参,实现策略模块化。

extern double LotSize   = 0.1;
extern int    Slippage  = 3;

全局变量区

位置:extern 后、主函数前。作用:用于函数之间共享的数据,生命周期 = EA整段运行周期,所有函数均可读取或修改

int    GlobalTradeCount = 0;
double GlobalRiskValue  = 0.02;

初始化函数 OnInit()

声明方式:

int OnInit()

触发时机:EA加载到图表时,只执行一次。主要用于初始化变量、加载资源、校验账户类型、图表品种、创建图形对象、输出日志。

Print("EA初始化完成!");

返回值:返回 INIT_SUCCEEDED (0) 表示成功;也可以返回 INIT_FAILED 等错误码。

主逻辑函数 OnTick()

声明方式:

void OnTick()

触发:每一个Tick(报价变动)都会调用一次。EA的核心功能,生成交易信号、执行下单、平仓、管理已有订单、控制风险(如止损、止盈)、更新图表或信息面板。OnTick() 是EA的 主引擎,也是判断行情、发单的核心入口。

清理函数 OnDeinit(const int reason)

声明方式:

void OnDeinit(const int reason)

触发:卸载EA、关闭图表或MT4、参数变更、重新编译等。用途:清除图形对象、释放资源(如句柄)、输出退出日志。

Print("EA已关闭,释放资源。");

reason 参数代表退出原因(如 REASON_REMOVE、REASON_RECOMPILE 等)


自定义函数区

作用:将复杂逻辑拆分为可复用的小函数,提升可读性与维护性

void CheckOrderStatus()
{
// 检查订单是否成交
}

建议:给每类功能编写函数,如下单函数、信号函数、风险控制函数,函数内部保持简洁,逻辑清晰。


🔄 EA运行流程(生命周期)

EA挂上图表 ➜ 调用 OnInit()
每来一个Tick ➜ 调用 OnTick()
EA被移除 ➜ 调用 OnDeinit()

在此过程中:extern 参数由用户在界面设置、全局变量在多个函数中共享、自定义函数在 OnInit()OnTick() 中被调用

总结

模块名 关键词/函数名 执行时机 主要用途
预处理指令 #property, #include 编译时 设置EA信息、导入库
外部参数区 extern 编译后 → 用户设定参数 调整策略参数
全局变量区 无关键字 整个生命周期 各函数共享数据
初始化函数 int OnInit() EA加载时 初始化数据、检查环境
主逻辑函数 void OnTick() 每个Tick到达时 判断行情、管理交易
清理函数 void OnDeinit(int reason) EA卸载或图表关闭时 清除资源、释放对象
自定义函数区 void MyFunction() 被其他函数调用 模块化处理逻辑、提高复用性

结构清晰,执行流畅,功能稳定 —— 这是所有优秀EA的共同特点。

下面是一个EA布局示例
// --- 1. 预处理器指令(编译前处理区) ---
#property copyright "作者名 (Andrew Young)" // 声明版权信息
#property link "https://www.eamql5.com" // 指定相关网站链接
#define MYCONSTANT "这是一个常量值" // 定义一个编译期常量

// --- 2. 外部输入参数(可在EA参数设置界面修改) ---
extern int Parameter1 = 1; // 示例:整数输入参数,默认值为1
extern double Parameter2 = 0.01; // 示例:浮点型输入参数,默认值为0.01

// --- 3. 全局变量(程序内部共享变量) ---
int GlobalVariable1; // 示例:全局变量,贯穿EA生命周期

// --- 4. 初始化函数(EA加载图表时执行一次) ---
int OnInit()
 {
  Print("EA ", WindowExpertName(), " 初始化成功!");
  GlobalVariable1 = 0; // 初始化全局变量
  return(INIT_SUCCEEDED); // 返回成功状态
 }

// --- 5. 清理函数(EA移除或MT4关闭时执行一次) ---
void OnDeinit(const int reason)
 {
  Print("EA ", WindowExpertName(), " 停止运行,执行清理...");
  // ObjectsDeleteAll(); 
  // 如有图表对象,可在此删除
 }

// --- 6. Tick主逻辑函数(每次新报价触发执行) ---
void OnTick()
 {
  // 示例逻辑:每次报价时增加计数器
  GlobalVariable1++;
  Comment("运行次数: ", GlobalVariable1);
  // TODO:可添加交易信号识别、订单管理等具体策略逻辑
 }

// --- 7. 自定义函数(可在主逻辑或初始化函数中调用) ---
int MyCustomFunction()
 {
  Print("调用了自定义函数 MyCustomFunction");
  // 执行具体功能
  return(0);
 }

小结一下整体流程,下面是整个EA结构的流程图思维:

编译前处理 (#property, #include, #define)

定义输入参数 (extern)

定义全局变量 (int, double, string等)

OnInit() 初始化环境 (只执行一次)

OnTick() 每次Tick执行核心逻辑

OnDeinit() 卸载EA时清理资源

自定义函数 提供支持模块

EA文件就是一个有明确模块分区的自动交易程序,从编译到运行到结束,每一步都非常规范,有标准的入口(OnInit)、执行(OnTick)、出口(Deinit)。
下面给大家在写一个更规范一点的EA结构模板,同时加上详细注释,大家可以多琢磨琢磨,有助于你理解每一部分用途:

// === 1. 预处理指令区 === 
#property strict // 严格模式(强烈建议) 
#property copyright "tudaojiaoyi" 
#property link "http://www.eamql5.com" 
#property version "1.00" // EA版本号

// === 2. 外部输入参数区 (用户可调节) === 
extern double LotSize = 0.1; // 下单手数 
extern int Slippage = 3; // 最大滑点 
extern int TakeProfit = 50; // 止盈点数 
extern int StopLoss = 30; // 止损点数 
extern bool UseTrailing = true; // 是否启用移动止盈 
extern int MagicNumber = 123456; // 识别订单用的魔术编号 

// === 3. 全局变量区 (程序内部用,不对外暴露) === 
int g_Ticket = -1; // 当前订单号 
bool g_HasOpenPosition = false; // 是否已有持仓 
datetime g_LastOrderTime = 0; // 上次开单时间 

//+------------------------------------------------------------------+ 
//| 初始化函数 (EA加载时执行一次) | 
//+------------------------------------------------------------------+ 
int OnInit() 
 {
  Print("EA初始化完成: ", WindowExpertName()); 
  g_HasOpenPosition = false; 
  return(INIT_SUCCEEDED); // 返回初始化成功
 } 

//+------------------------------------------------------------------+ 
//| 去初始化函数 (EA被卸载时执行一次) | 
//+------------------------------------------------------------------+ 
void OnDeinit(const int reason)
 {
  Print("EA卸载,原因代码: ", reason);
 } 

//+------------------------------------------------------------------+ 
//| 核心执行函数 (每个新的Tick执行) | 
//+------------------------------------------------------------------+ 
void OnTick()
 {
  // 核心逻辑流程
  if(!IsNewBar())
  return;
  // 非新K线,不处理
  if(!g_HasOpenPosition)
   {
    if(CheckEntryCondition())
     {
      OpenOrder();
     }
   }
  else
   {
    ManageOpenOrders(); // 持仓管理,比如移动止盈
   }
 } 

//+------------------------------------------------------------------+ 
//| 辅助函数:检测是否形成新K线 | 
//+------------------------------------------------------------------+ 
bool IsNewBar()
 {
 static datetime lastTime = 0; 
 if (Time[0] != lastTime)
  {
   lastTime = Time[0]; 
   return true; 
  }
  return false; 
 } 

//+------------------------------------------------------------------+ 
//| 辅助函数:检查入场条件 | 
//+------------------------------------------------------------------+ 
bool CheckEntryCondition()
 { 
 // 这里填写你自己的交易信号逻辑 
 if (iRSI(NULL, 0, 14, PRICE_CLOSE, 0) < 30)
  {
  return true; // RSI低位,买入信号 
  } 
 return false; 
 } 

//+------------------------------------------------------------------+ 
//| 辅助函数:开仓函数 | 
//+------------------------------------------------------------------+ 
void OpenOrder()
 {
  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; 
    g_LastOrderTime = TimeCurrent(); 
    Print("开仓成功,订单号: ", ticket); 
   } 
  else 
   {
 Print("开仓失败,错误代码: ", GetLastError()); 
   } 
} 

//+------------------------------------------------------------------+ 
//| 辅助函数:管理已有持仓 (如移动止盈) | 
//+------------------------------------------------------------------+ 
void ManageOpenOrders() 
 {
  for(int i=OrdersTotal()-1; i>=0; i--) 
   { 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
     if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol()) 
      { 
       if(UseTrailing)
       ApplyTrailingStop(); 
      } 
    } 
  } 
} 

//+------------------------------------------------------------------+ 
//| 辅助函数:应用移动止盈功能 | 
//+------------------------------------------------------------------+ 
void ApplyTrailingStop()
 {
  double trailingStop = 30; // 自定义移动止盈点数 
  double newStopLoss = Bid - trailingStop * Point; 
  if(OrderType() == OP_BUY) 
   { 
    if(newStopLoss > OrderStopLoss())
     {
      OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, clrBlue); 
      Print("移动止盈更新!"); 
     } 
   } 
} 

//+------------------------------------------------------------------+
赞(0)
未经允许不得转载:图道交易 » ​MQL4(11):EA布局的标准结构和运行流程
分享到