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

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

函数就是一段可以重复使用的代码,就像是“工具”或者“小工厂”,你只需要告诉它你要干什么,它就能帮你自动完成,函数可以提高编程效率、让程序更清晰、更易维护。

打个生活中的比喻
生活例子 对应的函数操作
榨汁机 你放进去水果后,它就自动榨汁
车间打孔机 你只要输入参数,它自动打孔
计算器 你按“2+3=”,它就返回结果 5

这些“操作”就是函数的功能,我们只需要调用函数既可。

MQL4 中的函数:
double Add(double a, double b)
{
return a + b;
}

这是一个加法函数,函数名字叫 Add(),需要两个数字 ab,函数的返回值是它们的和(a+b)。

怎么用它
double result = Add(3, 5);  // 调用函数,返回 8
函数结构
返回类型 函数名(参数1, 参数2, ...)
{
// 函数体(要执行的代码)
return 返回值;  // 可选,只有有返回值时才写
}
再举个例子:
int Multiply(int x, int y) 
{
 return x * y; 
}

这个函数:

  • 名字叫 Multiply()

  • 功能是返回 x 和 y 的乘积

  • int 是返回值类型(整数)

函数是现代编程语言的基本构造模块,一个函数就是一个被设计用来执行特定任务的代码块,例如执行交易下单或计算止损位置等等。MQL4提供了数百种内置函数,涵盖了从技术指标计算到订单管理等多种功能,我们不需要每个内置函数都掌握,只需熟悉一些核心函数既可。

函数的设计理念是可重复使用性,学习如何创建自定义函数,对于提高MQL4编程效率至关重要。本系列课程将引导您针对许多具体任务创建可复用的函数。

我们从一个简单的函数 PipPoint() 开始。该函数用于计算当前交易品种报价的小数点位数,并自动进行调整以适应 3 位小数和 5 位小数报价的经纪商,确保函数返回值始终代表一个标准点 (pip) 的价值。对于日元对(通常是 2 或 3 位小数),函数返回 0.01;对于其他所有货币对(通常是 4 或 5 位小数),函数返回 0.0001。下面演示如何在代码中调用这个函数:

double UsePoint; // 声明一个 double 类型变量,用于存储 PipPoint 函数的返回值
UsePoint = PipPoint(); // 调用 PipPoint 函数,并将结果赋值给 UsePoint 变量

首先,我们声明了一个 double 类型的变量 UsePoint。然后,调用 PipPoint() 函数,并将函数执行后返回的值存储到 UsePoint 变量中。这样,我们就可以使用 UsePoint 中存储的值(即一个标准点的大小)来进行后续计算,例如设置止损距离。

以下是 PipPoint() 函数的源代码:

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

函数代码的第一行是函数声明,与变量声明类似,函数声明也包含数据类型和标识符(函数名)。函数使用与变量相同的数据类型,其类型取决于该函数执行完毕后需要返回 (return) 给调用者的数据种类。由于 PipPoint() 函数返回的是一个小数(点值),因此我们使用了 double 作为其返回数据类型。

函数的主体代码(执行逻辑)包含在一对大括号 {} 中。在这个例子里,函数主体使用了一个 if-else if 条件语句来判断 MQL 内置变量 Digits 的值(即当前品种的小数位数),然后将相应的点值赋给局部变量 pointValue。最后,return 语句将 pointValue 变量的值作为函数的结果返回。

对于那些执行完特定任务后无需返回任何计算结果的函数,可以使用一种特殊的返回类型:voidvoid 类型表示函数不返回任何值。这种函数通常用于执行某些操作,如打印信息、修改全局状态或直接调用其他函数,它们执行完毕即可,不需要向调用它的代码传递结果。void 函数的函数体中通常不包含 return 语句(或者可以有一个不带任何值的 return; 语句来提前结束函数)。

接下来,我们看一个用于创建买入市价单的简化函数示例。这个函数需要接收一些参数,用于指定订单的细节。函数的功能是在当前图表对应的交易品种上,根据传入的手数 (LotSize)、止损价 (StopLoss) 和止盈价 (TakeProfit) 来发送一个买入市价订单 (OP_BUY)。

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

    return(Ticket); // 返回 OrderSend 函数的结果 (订单号或-1)
}

这个 OpenBuyOrder 函数有三个参数:LotSizeStopLossTakeProfit。参数是在函数定义时声明的变量,它们只在函数内部有效,其值由调用该函数时提供的输入(实参)决定。以下是使用具体的数值(常量)作为参数来调用此函数的示例:

// 调用函数开设一个 2 手的买单,止损设在 1.5550,止盈设在 1.6050
OpenBuyOrder(2.0, 1.5550, 1.6050); // 手数建议使用 double 类型

上述代码执行时,会尝试开设一个 2 手的买单,并将止损和止盈分别设置在 1.5550 和 1.6050。下面是另一个例子,这次使用变量来传递参数值。假设变量 UseLotSizeBuyStopLossBuyTakeProfit 已经被赋予了合适的数值:

int GetTicket; // 声明一个整型变量,准备接收函数返回的订单号
// 调用开仓函数,并将返回的订单号赋值给 GetTicket 变量
GetTicket = OpenBuyOrder(UseLotSize, BuyStopLoss, BuyTakeProfit);

在这个例子中,我们将 OpenBuyOrder() 函数执行后的返回值(成功开仓后的订单号)赋给了变量 GetTicket。是否需要接收并存储函数的返回值是可选的。通常,只有当您计划在后续代码中使用这个返回值(例如,用订单号来修改止损、查询订单状态等)时,才需要将其赋值给一个变量。

参数默认值

参数默认值在定义函数时,可以为参数指定默认值。这意味着如果在调用函数时没有为该参数提供值,函数将自动使用这个预设的默认值。一个重要的规则是:所有带默认值的参数必须放置在参数列表的最后面。下面是一个包含若干默认值参数的函数定义示例:

// 示例函数,包含两个带默认值的参数:Number 和 Comment
int DefaultValFunc(int Ticket, double Price, int Number = 0, string Comment = NULL)

此函数 DefaultValFunc 有两个带默认值的参数:Number 的默认值是 0,Comment 的默认值是 NULL。如果我们想让 NumberComment 都使用它们的默认值,那么在调用函数时,只需要提供前两个没有默认值的参数即可,省略掉后面带默认值的参数:

// 只提供 Ticket 和 Price 的值,Number 和 Comment 将使用默认值
DefaultValFunc(TicketNum, UsePrice);

注意,我们只传入了 TicketNumUsePrice。函数内部 Number 会自动取值 0,Comment 会自动取值 NULL

如果我们想为 Number 指定一个非默认值,但仍然让 Comment 使用其默认值 NULL,我们可以这样做:

// 提供前三个参数的值,最后一个参数 Comment 仍使用默认值
DefaultValFunc(TicketNum, UsePrice, UseNumber);

这里,因为 Comment 是最后一个参数且被省略,所以它使用了默认值 NULL

然而,如果我们想为 Comment 参数指定一个值,那么无论我们是否想让它前面的 Number 参数使用默认值,我们都必须为 Number 也提供一个值。因为参数的省略只能从右往左、连续地进行。

// 必须为 Number 提供一个值(即使是它的默认值 0),才能为 Comment 提供值
DefaultValFunc(TicketNum, UsePrice, 0, "My Custom Comment");

在这个例子中,我们为 Number 传入了值 0(这恰好是它的默认值),并为 Comment 传入了一个自定义的字符串 "My Custom Comment"

小结:当函数定义中包含多个带有默认值的参数时,您只能从参数列表的最右边开始省略参数。一旦您为某个参数(无论它是否有默认值)提供了值,那么它左边的所有参数(无论是否有默认值)也都必须提供值,你不能跳过中间的某个参数只为后面的参数提供值。

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