函数就是一段可以重复使用的代码,就像是“工具”或者“小工厂”,你只需要告诉它你要干什么,它就能帮你自动完成,函数可以提高编程效率、让程序更清晰、更易维护。
打个生活中的比喻
生活例子 | 对应的函数操作 |
---|---|
榨汁机 | 你放进去水果后,它就自动榨汁 |
车间打孔机 | 你只要输入参数,它自动打孔 |
计算器 | 你按“2+3=”,它就返回结果 5 |
这些“操作”就是函数的功能,我们只需要调用函数既可。
MQL4 中的函数:
这是一个加法函数,函数名字叫 Add()
,需要两个数字 a
和 b
,函数的返回值是它们的和(a+b)。
怎么用它
函数结构
再举个例子:
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
变量的值作为函数的结果返回。
对于那些执行完特定任务后无需返回任何计算结果的函数,可以使用一种特殊的返回类型:void
。void
类型表示函数不返回任何值。这种函数通常用于执行某些操作,如打印信息、修改全局状态或直接调用其他函数,它们执行完毕即可,不需要向调用它的代码传递结果。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
函数有三个参数:LotSize
、StopLoss
和 TakeProfit
。参数是在函数定义时声明的变量,它们只在函数内部有效,其值由调用该函数时提供的输入(实参)决定。以下是使用具体的数值(常量)作为参数来调用此函数的示例:
// 调用函数开设一个 2 手的买单,止损设在 1.5550,止盈设在 1.6050
OpenBuyOrder(2.0, 1.5550, 1.6050); // 手数建议使用 double 类型
上述代码执行时,会尝试开设一个 2 手的买单,并将止损和止盈分别设置在 1.5550 和 1.6050。下面是另一个例子,这次使用变量来传递参数值。假设变量 UseLotSize
、BuyStopLoss
和 BuyTakeProfit
已经被赋予了合适的数值:
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
。如果我们想让 Number
和 Comment
都使用它们的默认值,那么在调用函数时,只需要提供前两个没有默认值的参数即可,省略掉后面带默认值的参数:
// 只提供 Ticket 和 Price 的值,Number 和 Comment 将使用默认值
DefaultValFunc(TicketNum, UsePrice);
注意,我们只传入了 TicketNum
和 UsePrice
。函数内部 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"
。
小结:当函数定义中包含多个带有默认值的参数时,您只能从参数列表的最右边开始省略参数。一旦您为某个参数(无论它是否有默认值)提供了值,那么它左边的所有参数(无论是否有默认值)也都必须提供值,你不能跳过中间的某个参数只为后面的参数提供值。