前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MQL5从入门到精通【第五章】函数function

MQL5从入门到精通【第五章】函数function

作者头像
程序员小助手
发布2020-04-08 11:20:03
1.4K0
发布2020-04-08 11:20:03
举报
文章被收录于专栏:程序员小助手

讲完了数据类型,操作语句,接着我们把这些元素组合在一起使用。封装起来,成为函数。可供程序内调用,减少冗余代码,提高代码可维护性,降低程序复杂度。

function是一组代码块,用于完成特定动作,比如处理一个订单,调整止损价位等。我们的教程中,会讲到不少自建的函数,用于完成交易相关的动作。MQL5也提供了许多内置函数,从简单的获取订单信息,到复杂的数学运算,都可信手拈来,直接使用。

好比积木,函数精简为一个一个独立的积木块,然后我们使用程序,将独立的积木块搭建成复杂的结构。

抽象出来的函数,一定要精简,要获取订单信息,那好了,我根据需要的传入参数,传入该函数,它给我返回订单信息便是。程序的任意位置,均可调用。

函数一般要有返回值,当然没有返回值也可以,声明的时候冠以void关键字即可。下面举例:

代码语言:javascript
复制
double BuyStopLoss(string pSymbol, int pStopPoints, double pOpenPrice)
{
    // 代码块
}

函数要求传入三个参数,返回一个double类型数据。按照规则写就OK了。注意三个参数都必须填写,是必填项,不能缺省。字符类型的 pSymbol,整型的 pStopPoints,实数 pOpenPrice。

下面我们实现一个功能,根据三个参数,给函数计算返回值。补充函数代码块部分:

代码语言:javascript
复制
double BuyStopLoss(string pSymbol, int pStopPoints, double pOpenPrice)
{
    double stopLoss = pOpenPrice - (pStopPoints * _Point);
    stopLoss = NormalizeDouble(stopLoss,_Digits);
    return(stopLoss);
}

逐句分析。

double stopLoss = pOpenPrice - (pStopPoints * _Point);

使用开盘价格,减去 止损点与货币报价中当前交易品种的大小点的成绩,计算出来的就是止损价格。注意使用了_Point预定义常量。

stopLoss = NormalizeDouble(stopLoss,_Digits);

此处_Digits也是系统预定义常量。定义当前图表交易品种的价格精确度。使用NormalizeDouble格式化小数保留相应的精度。

return(stopLoss);

返回计算后的值stopLoss。这就是函数的返回值。函数执行到此,直接返回,如果后面还有语句,并不执行。

所以您看到了,函数体内,也有提前终端执行,跳出函数的方法,就是使用return返回。这与上一章循环中的break与异曲同工之处。

准备好这个函数,我们可以在程序中用一用,体现一下其价值。我们定义一个输入变量,用于与用户交互,让用户输入止损价,然后在onTick事件处理中调用此函数。

onTick 当NewTick事件发生时在EA中调用这个函数,来处理一个新报价。

也就是报价有更新时,调用此事件内的程序。

代码语言:javascript
复制
// 定义输入变量
input int StopLoss = 500;

// onTick事件
double orderPrice = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double useStopLoss = BuyStopLoss(_Symbol,StopLoss,orderPrice);

注意,函数要先定义再使用。可以在头部定义,如果是公用函数,单独写出来,在顶部引入即可。

## 默认值

如果一个函数,接收5个参数,但是有些并不是经常变化的参数,或者在函数调用的时候,是否能够选填呢,作为可选参数?可以的。在声明函数的形参中,给其默认值,那么在调用的时候,就可以不给这个位置传参。

代码语言:javascript
复制
double BuyStopLoss(string pSymbol, int pStopPoints, double pOpenPrice = 0)
{
    double stopLoss = pOpenPrice - (pStopPoints * _Point);
    stopLoss = NormalizeDouble(stopLoss,_Digits);
    return(stopLoss);
}

上述同样的函数定义,我们在形参中声明pOpenPrice默认=0。那么如果调用BuyStopLoss时,这个位置的参数如果不传,函数体内,pOpenPrice就用0.0这个默认值了。

代码语言:javascript
复制
BuyStopLoss(_Symbol,StopLoss);

就想上面这个一样。

那是不是我只要声明了默认值的参数位置,就可以不填了呢?不可以!可选参数列表放在形参的尾部,这样可变参数在前,不变参数在后,写的时候,你就可以像下面这样用:

代码语言:javascript
复制
double grad(int x1=1,int y1=2,int x2=3,int y2=4){
    return (y2-y1)/(x2-x1);
}

上述函数计算两个点的斜率。坐标点都有默认值,调用的时候,下面的使用方法都是正确的:

代码语言:javascript
复制
grad();
grad(1);
grad(1,2);
grad(1,2,3);
grad(1,2,3,4);

我们再看必选参数在中间的。

代码语言:javascript
复制
double grad(int x1 = 1, int y1, int x2 = 3, int y2 = 4){
    return (y2-y1)/(x2-x1);
}

那么调用的时候,只能有以下写法:

代码语言:javascript
复制
grad(1,2);
grad(7,3,3,5);

也就是第二个参数,是必填的。无论前面的是否可选,前面的也得填。所以,最佳实践就是把可选参数放后面去。

## return 操作符

像上面所说的,如果提前终结函数运行,可以直接return。函数运行到return这个位置,就跳出了。

代码语言:javascript
复制
int ga(double price, bool is_half){
    if(is_half== false) return(price * price);
    else return(price / 2);
    Print('Never exec');
    return(0);
}

因为if-else把两种情况均考虑了,一定会返回一个数值。那么下面的print根本没有机会执行。

## void类型

有时候我们写一个函数,仅仅为了一段功能和动作,可能不不期望有返回值。那么就可以在函数声明前冠以void。

代码语言:javascript
复制
void TradeEmail()
{
    string subject = "Trade placed";
    string text = "A trade was placed on " + _Symbol;
    SendMail(subject,text);
}

这段代码,使用标题和内容发送一封邮件,不期望有返回值,使用void就可以了。函数内大可不必有return操作符。

## 引用传递参数

一般,我们把参数传递给函数,传递的是这个参数的值。参数的值也保持不变。

那么,如果是某个变量,我们想要其在函数处理中改变其数值,怎么办呢?可以使用引用传递。MQL5程序中,数组和结构体,经常用到引用传递reference。

下面的例子,我们引用传递一个结构体给系统函数SymbolInfoTick()。

代码语言:javascript
复制
bool SymbolInfoTick(
    string symbol,
    MqlTick& tick // 引用结构体MqlTick
);

下面是代码中我们的用法:

代码语言:javascript
复制
MqlTick myTick;
SymbolInfoTick(_Symbol,myTick);
Print(myTick.bid);

第一行,使用系统内置结构体声明一个变量myTick。

第二行,系统函数调用后将返回值更改了变量myTick。

第三行,值更改后的myTick打印属性。

下面再举一个例子,我们接收一个空数组,将其进行填充。这个函数就需要引用传递。

代码语言:javascript
复制
void fill(int &a[]){
    ArrayResize(a,3);
    a[0] = 1;
    a[1] = 2;
    a[2] = 3;
}

这样做的好处是,不用返回值了,再赋值给原始函数,省去一大段代码。

调用的时候这样用:

代码语言:javascript
复制
int f[];
fill(f);
Print(f[0]); // = 1

有没有对引用传递有个质的理解了呢?

## 函数重载

面向对象编程中,我们用到很多概念,如接口,抽象类,继承。那么,在继承层级比较深的类内,有些继承的方法在该类内会有特殊的用法,这时候我们需要重写该方法,也称为“重载”。MQL5函数也可使用重载。说白话就是,同一个函数名,参数不同,写两次。你用的时候,编译器根据传入的参数匹配相应的函数。

代码语言:javascript
复制
bool TrailingStop(string pSymbol, int pTrailPoints, int pMinProfit = 0, int pStep = 10);
bool TrailingStop(string pSymbol, double pTrailPrice, int pMinProfit = 0, int pStep = 10);

更改一个参数,函数名保持不变。像下面这样用

代码语言:javascript
复制
bool b;
b = TrailingStop(_Symbol, 549);

系统会判定使用第一个函数,因为第二个参数很显然,int型。像下面这样用

代码语言:javascript
复制
bool b;
b = TrailingSop(_Symbol, 125.89);

系统判定是访问第二个函数,因为第二个参数位置是double型。

这就是重载。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员小助手 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ## 默认值
  • ## return 操作符
  • ## void类型
  • ## 引用传递参数
  • ## 函数重载
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档