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

​MQL4(10):局部变量与全局变量

在我们的EA程序这栋“房子”里,每一份需要储存的数据,都需要一个“家”(变量)。现在,我们需要做出一个最基础也最重要的建筑决策:是给这份数据一间私密的、用完就走的“客房”(局部变量),还是把它放在一个谁都能看到的“公共大厅”(全局变量)?

这个决策,将直接影响你的EA代码的清晰度、稳定性和未来维护的难易度。

局部变量:EA的“私人客房”与“草稿纸”

局部变量,是定义在某一个函数或代码块{}内部的变量。

它最核心的特点就是“阅后即焚”,生命周期极短:

  • “出生”:当程序执行到它所在的函数时,它才被创建。
  • “活动”:它的活动范围仅限于这个函数内部,别的函数根本不知道它的存在。
  • “死亡”:函数一旦执行完毕,这个局部变量就会被立刻销毁,其占用的内存也会被完全释放。

示例1:函数内的局部变量

void OnTick()
{
    int x = 5; // 局部变量x,只在OnTick函数这个“房间”里有效
    Print("x=", x);
}

void SomeOtherFunction()
{
    // Print(x); // ❌ 错误!这里是另一个房间,看不见x
}

示例2:代码块里的“临时”局部变量

它的作用范围甚至可以更小,只在一个iffor循环的{}代码块里有效。

void OnStart() 
{
    for (int i = 0; i < 5; i++)
    {
        Print("i=", i);  // 变量i是局部变量,只在这个for循环中有效
    }
    // Print(i); // ❌ 错误!离开了for循环的范围,i已经“死亡”了
}

我们为什么偏爱局部变量?

局部变量的“健忘”和“短命”不是缺点,反而是巨大的优点。它保证了每个函数都是一个“无菌实验室”。函数每次被调用,都像是在一张全新的草稿纸上进行计算,用完就扔。这可以确保上一次的计算结果,绝对不会意外地污染到下一次的计算,极大地提升了代码的安全性和稳定性。

核心原则:能用局部的,就绝不用全局的。这是专业程序员的铁律。

全局变量:EA的“中央公告板”

全局变量,是定义在所有函数之外的变量,我们通常把它放在代码文件的最顶部。

它的特点与局部变量正好相反——“坚韧不拔”:

  • “出生”:EA程序一开始加载,它就被创建。
  • “活动”:它的活动范围覆盖整个EA文件,任何函数都可以随时读取和修改它。
  • “死亡”:直到EA程序从图表上被移除,它才会被销毁。

它就像是房子大厅里的一块公共白板,任何房间的人都能在上面写字,也都能看到别人写了什么。

// 全局变量,定义在所有函数之外,推荐以g_开头
int g_tradeCount = 0; 

void OnTick()
{
    // OnTick函数可以读取并修改它
    if (some_trade_condition)
    {
        g_tradeCount++;
        Print("这是本EA的第 ", g_tradeCount, " 笔交易。");
    }
}

void OnDeinit(const int reason)
{
    // EA退出时,OnDeinit函数也可以读取它,用于最终总结
    Print("EA退出,总计交易次数: ", g_tradeCount);
}

什么时候“必须”使用全局变量?

当我们需要一个数据来记录整个EA程序的宏观状态,并且这个状态需要被多个、不同功能的函数共享时。最典型的场景就是:

  • 统计EA的总交易次数、总盈亏。
  • 记录EA的初始化是否成功。
  • 保存需要在多个函数之间流转的、重要的程序状态信息。

从技术上说,我们上一节课讲的input(或extern)外部变量,也是全局变量的一种,因为它们也具有全局的活动范围。

学长避坑指南:全局变量是“双刃剑”,请谨慎使用

全局变量的便利性背后,隐藏着巨大的风险。新手最容易犯的错误就是为了图方便,大量使用全局变量,这会迅速让你的代码变成一团难以维护的“意大利面”。

  • 逻辑混乱:当一个全局变量的值不对时,你很难追踪到底是哪个函数在哪个环节把它改错了。
  • 命名冲突:不同功能的代码块可能会无意中用到同名的全局变量,互相覆盖,导致莫名其妙的BUG。

强制建议:为所有全局变量加上g_前缀(g是global的缩写)。 例如:g_magicNumber, g_totalProfit。这不是语法要求,而是代码江湖里一条保命的“军规”。当你在函数的代码深处看到一个g_开头的变量时,你的大脑会立刻响起警报:“注意!这是一个全局变量,修改它可能会影响到其他地方!”

实战总结:跟踪交易次数与总盈利

下面这个例子,完美地展示了全局变量的正确用法。

// === 全局状态追踪 ===
int    g_tradeCount  = 0;      // 全局变量:用于累计交易次数
double g_totalProfit = 0.0;    // 全局变量:用于累计总盈利

// OnTrade函数会在每次交易活动时被MT4自动调用
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
{
    // 当一笔交易从持仓列表中被移除时 (平仓或止损止盈)
    if(trans.type == TRADE_TRANSACTION_DEAL_REMOVE)
    {
        // 我们可以查询这笔历史订单的盈利
        if(HistorySelect(trans.deal))
        {
           double profit = HistoryDealGetDouble(trans.deal, DEAL_PROFIT);

           // 更新我们的全局变量
           g_tradeCount++;
           g_totalProfit += profit;

           Print("一笔交易完成。累计交易次数: ", g_tradeCount, ", 累计盈利: ", g_totalProfit);
        }
    }
}

在这个场景里,交易次数和总盈利是整个EA的宏观状态,必须使用全局变量来贯穿始终地追踪,这就是全局变量最适合发挥作用的地方。

赞(0)
未经允许不得转载:图道交易 » ​MQL4(10):局部变量与全局变量
分享到

评论 抢沙发