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

​MQL4(6):什么是函数 (Functions)

如果说变量和常量是建造EA的“砖块”,那么函数就是我们的“施工图纸”和“电动工具”,掌握函数,是区别一个编程新手和初级程序员的最重要标志。

函数是什么?我们为什么要自找麻烦写函数?

函数,本质上就是一段可以被重复呼叫和使用的独立代码块。它就像一个功能专一的“小工厂”:

  • 榨汁机函数:你把水果(参数)放进去,它就吐出果汁(返回值)。
  • 计算器函数:你输入23(参数),它就给你结果5(返回值)。
  • 下单函数:你告诉它手数、止损、止盈(参数),它就帮你完成下单的动作。

我们之所以要不厌其烦地学习和创建函数,核心目的有三个:

  1. 提高效率:同样一段逻辑(比如根据风险计算手数),写成函数后,以后每次用只需要“呼叫”一下函数名就行了,再也不用重复复制粘贴那几十行代码。
  2. 代码清晰:把不同功能的代码封装进不同的函数里,主程序就会变得非常简短、清晰。读代码就像读目录,而不是一头扎进上千行的细节里。
  3. 便于维护:当一个功能的逻辑需要修改时(比如优化止损算法),你只需要去修改那一个函数就行了,其他地方完全不受影响。

函数的结构:认识我们的小工厂

一个MQL4函数的基本构造如下:

返回类型 函数名(参数1, 参数2, ...) { // 函数体(这里是具体的施工代码) return 返回值; // 可选,如果函数需要“产出”结果,就用return }

  • 函数名:给你的工厂起个名字,比如CalculateLotSize
  • 参数:工厂加工需要的“原材料”,可以没有,也可以有多个。
  • 函数体:工厂内部的“生产线”,也就是具体的代码逻辑。
  • 返回类型与返回值:工厂最终的“产出品”。如果不需要产出品,只是完成一个动作,那么返回类型就是void

MQL4已经内置了上百个函数供我们使用(比如我们最常用的OrderSend()下单函数),但编程的精髓在于学会创建符合我们自己交易策略的自定义函数

我们的第一个自定义函数:PipPoint()

一个非常实际的交易问题:不同的经纪商、不同的货币对,小数点位数都不同(有4位/2位报价,也有5位/3位报价)。这导致我们计算止损点数时非常混乱。

我们可以写一个函数来智能地解决这个问题。这个函数不需要任何“原材料”(参数),它的任务就是自动检测当前品种的小数点位数,然后“产出”(返回)一个标准点对应的值。

// 函数功能:计算当前交易品种一个标准点(pip)对应的价格数值
// 返回值:double类型,例如 0.01 或 0.0001
double PipPoint()
{
    double pointValue;
    // 'Digits'是MQL4内置变量,表示当前品种价格的小数位数
    if(Digits == 2 || Digits == 3) // JPY货币对
    {
        pointValue = 0.01;
    }
    else if(Digits == 4 || Digits == 5) // 非JPY货币对
    {
        pointValue = 0.0001;
    }
    // 注意:此基础版本未处理指数/商品等其他情况
    return(pointValue);
}

写好这个函数后,在代码的任何地方,我们想知道一个标准点的值,只需要这样调用它:

double UsePoint = PipPoint(); // 调用函数,把返回的结果存入UsePoint变量

从此,你的EA就具备了自动适应不同经纪商报价环境的能力。

更进一步:创建带参数的下单函数

现在我们来创建一个更实用的函数:开一个市价买单。这个“工厂”需要我们提供“原材料”(参数):手数、止损价和止盈价。它最终会“产出”(返回)一个订单号。

// 函数:开市价买单
// 参数:手数(LotSize), 止损价(StopLoss), 止盈价(TakeProfit)
// 返回:成功则返回订单号(Ticket),失败则返回-1
int OpenBuyOrder(double LotSize, double StopLoss, double TakeProfit)
{
    int Ticket = OrderSend(Symbol(),       // 交易品种 (当前图表品种)
                           OP_BUY,         // 操作类型 (买入)
                           LotSize,        // 交易手数
                           Ask,            // 下单价格 (买入价)
                           3,              // 滑点 (Slippage)
                           StopLoss,       // 止损价格
                           TakeProfit,     // 止盈价格
                           NULL,           // 订单注释
                           0,              // 魔术数字 (Magic Number)
                           0,              // 订单有效期
                           clrNONE);       // 箭头颜色

    return(Ticket);
}

学长避坑指南: 上面这个函数是一个教学简化版。在实战中,像滑点(3)魔术数字(0)这些重要参数,绝对不能像这样写“死”在函数内部。专业的做法是把它们也作为函数的参数传进来,或者在程序顶部定义为全局常量。这是区分业余和专业代码的重要细节。

如何使用这个下单函数?

你可以直接提供具体的数值来调用它:

// 开一个2手的买单,止损在1.5550,止盈在1.6050
OpenBuyOrder(2.0, 1.5550, 1.6050);

更常见的用法是,接收它返回的订单号,以便后续操作:

int GetTicket = OpenBuyOrder(UseLotSize, BuyStopLoss, BuyTakeProfit);
if(GetTicket > 0)
{
    Print("下单成功!订单号是: ", GetTicket);
}
else
{
    Print("下单失败!错误代码: ", GetLastError());
}

一个非常重要的好习惯,调用一个有返回值的函数后,一定要检查它的返回值,判断操作是否成功,并进行相应的处理。

高级技巧:给参数设置“默认值”

有时候,我们希望函数更灵活一些,某些参数如果调用者不提供,就自动使用一个预设的默认值。

// 示例函数,后两个参数带有默认值
int DefaultValFunc(int Ticket, double Price, int Number = 0, string Comment = NULL)

这个函数定义了Number的默认值是0,Comment的默认值是NULL

使用规则:省略参数只能从右往左、连续地省略。

// 正确:省略最后两个,Number和Comment将使用默认值
DefaultValFunc(TicketNum, UsePrice);

// 正确:省略最后一个,Comment将使用默认值
DefaultValFunc(TicketNum, UsePrice, UseNumber);

// 错误:不能跳过中间的Number去给Comment赋值
// DefaultValFunc(TicketNum, UsePrice, "My Comment"); // 这样是错的!

// 正确:如果想给Comment赋值,必须也给它前面的所有参数赋值
DefaultValFunc(TicketNum, UsePrice, 0, "My Custom Comment");

这个技巧能让你的函数在保持强大功能的同时,也变得更易于调用。

掌握函数,就是掌握了MQL4编程的灵魂。它能让你的代码从一堆杂乱的砖块,变成一座结构清晰、坚固可靠、易于扩展的自动化交易大厦。

赞(0)
未经允许不得转载:图道交易 » ​MQL4(6):什么是函数 (Functions)
分享到

评论 抢沙发