简介:《MT4的MQL4编程入门》是一份面向外汇交易者与编程初学者的入门教程,重点讲解如何在MetaTrader 4平台使用MQL4编写交易策略、自定义指标和Expert Advisors,以推进交易自动化。压缩包内含1个doc文档,体积约197KB,内容以教程讲义形式组织,便于按章节阅读和检索。资料围绕自定义变量、附加变量、自定义函数、函数类型与自定义数组等基础语法展开,并用整型、双精度、字符串、逻辑型等示例说明变量定义、参数设置和函数返回值;同时涉及市场数据取值等MT4常见场景,有助于读者理解指标与EA的代码结构。已有391人学习,适合希望从零掌握MQL4基础、为后续编写个性化交易工具打底的读者。
1. 先别急着写代码:MQL4 到底是什么东西
很多人第一次听到「MT4 的 MQL4 编程入门」,脑子里立刻浮现满屏代码和看不懂的曲线,觉得自己英语不好、数学也一般,肯定学不会。其实换个角度就通了:MT4 是一个看行情、画图表的软件,MQL4 则是它自带的一门「说话方式」,你用这门语言告诉软件「价格碰到某个位置就提醒我一声」「把两条均线的差值画成一根线」。它不是让你从头造一个软件,而是让你在已经能用的软件里加一点自己的小功能,性质上更接近给手机装个快捷指令,而不是学一门正经的计算机专业课程。所以适合学它的人,恰恰不是程序员,而是天天盯着图表、心里反复嘀咕「这个位置要是能自动提醒我就好了」的普通使用者。
2. 先搞懂变量:四种类型和那个能让用户改参数的 extern
学 MQL4 编程入门,第一关不是指标也不是下单,而是变量。原因很简单:程序要记住东西。记住当前价格、记住有没有报过警、记住用户设的周期是 9 还是 12,这些都得有地方存。变量就是那个「地方」。这一关过了,后面函数、数组、指标全都是在这个基础上搭起来的,所以别贪快,把这一章老老实实敲一遍。
2.1 变量为什么必须先定义:给数据一个带门牌号的盒子
在 MQL4 里,变量不是想用就能用的,用之前必须先创建,也就是定义。定义的时候要做两件事:说明它是什么类型,给它起一个名字。这就像往仓库里放东西之前,先摆一个盒子,贴上标签写明「这里面放整数」,再写上盒子的名字。等你以后喊这个名字,程序才知道你说的是哪个盒子。
创建的时候可以直接放东西进去,也可以先空着。空着的盒子在程序里就是一个「还没有值」的状态,后面再赋值。写法是这样的:
int mark; // 创建一个整型变量,名字叫 mark,暂时没有值 bool 是否报警 = true; // 创建一个逻辑型变量,创建时直接给初值 true double 手数 = 0.1; // 创建一个双精度变量,初值 0.1 string 备注 = "价格提醒"; // 创建一个字符串变量,初值是一段文字四行代码对应四个盒子。第一行只创建不赋值,程序运行到这儿,mark就是个空盒子;第二行创建的同时塞进去true;后面两行同理。这里有个对新手特别友好的地方:MQL4 的变量名可以用中文,是否报警、周期、快线这些名字直接写进代码完全合法,读起来像写笔记。我第一次看到别人代码里写着extern int 周期=9;的时候愣了一下,后来发现中文名对新手理解逻辑的帮助非常大,前期完全可以用,等写长了再考虑混用英文。
有一点要提前说清楚,免得后面卡住:类型定义词,也就是int、double、string、bool这几个词,只在你创建变量的那一句用一次。后面再用这个变量,直接喊名字就行,不能再带上类型。写mark = 1;是对的,写int mark = 1;放在已经定义过之后就是重复定义,编译会报错。
2.2 MQL4 的四种基本类型,够用就行
入门阶段其实只需要认识四种类型,把这四个用熟,八成的小程序都能写出来。
| 类型定义词 | 中文叫法 | 存什么 | 典型写法 |
|---|---|---|---|
int | 整型 | 整数,包括负整数 | int 周期 = 9; |
double | 双精度小数 | 带小数位的数 | double 手数 = 0.1; |
string | 字符串型 | 一段文字 | string 名字 = "快线"; |
bool | 逻辑型 | 真或假 | bool 是否报警 = true; |
整型就是整数,9、-3、1000都是整型,写int 周期 = 9.5;这种会出问题,因为它装不下小数部分。双精度小数可以简单理解成「带小数点的数」,行情价格、均线值、账户余额都是这一类,所以在 MQL4 里double出现的频率最高。
逻辑型只有两个值:true和false,也就是「真」和「假」。这两个词也可以写成1和0,1 代表真,0 代表假。这一点在写报警逻辑的时候特别好用,比如你想记住「这次已经报过警了,别再报第二遍」,就可以用一个逻辑变量当开关。
字符串型存文字,写的时候要用双引号把内容包起来。像Alert("价格到了");这句里的"价格到了"就是一个字符串。要注意中文引号和英文引号在代码里不是一回事,必须用英文双引号,这个坑新手几乎人人踩过一次。
2.3 extern:让参数露在界面上的那层窗户纸
普通变量是写给自己看的,程序里怎么变,用户完全不知道。但有一类变量不一样,它要在程序投入使用后,允许用户在软件界面上自己改,这类变量叫附加变量,写法就是在定义语句前面加一个extern。
extern int 周期 = 9; // 整型附加变量,默认值 9,用户可在界面修改 extern int 快线 = 12; extern int 慢线 = 26; extern double 偏差 = 0.5;加了这个词之后,会发生一件很直观的事:把指标挂到图表上时,会弹出一个参数输入框,里面列着周期、快线、慢线、偏差这几项,后面跟着默认值,用户点一下就能改成别的数字。你平时用 MACD 时看到的 (12,26,9) 那三个可以调的框,本质上就是三个附加变量,12、26、9 分别是它们的默认值。
理解了这一点,你对「写指标」这件事的心理距离会一下子缩短很多。所谓指标参数可调,不是什么高深机制,就是作者在代码里用extern声明了几个变量,软件自动帮你把它们摆到界面上。反过来说,如果你某个数字忘了加extern,用户就只能用你写死的那个值,改不了,这在实际使用中会很难受。
2.4 变量什么时候失效:作用域这层关系
刚上手时容易忽略的一点是,变量在哪儿定义,决定了它在哪儿活着。在函数外面定义的变量,通常叫全局变量,整个程序都能用;在某个函数的大括号里面定义的变量,只在这个函数运行期间存在,函数一结束,这个变量就自动注销了,外面根本找不到它。
这个规则听起来抽象,实际影响很具体。比如你在start()函数里面写了int count = 0;,那么每次start()被触发,这个count都是从头开始新建的,值又变回 0,它不会帮你累计。要让一个值跨多次运行还在,就得把它定义到函数外面去。新手写的「计数器不涨」「报警重复报」这类问题,一半以上都跟这一点有关。
3. 函数与数组:把重复的活打包,把一堆数排好队
变量解决了「记住一个数」,接下来要解决「记住一堆数」和「反复算同一个东西」。这两个需求分别对应数组和函数。MQL4 编程入门里最容易被跳过、又最容易在后面翻车的,就是这一章。跳过它直接抄指标代码,短期能跑,一旦要改就完全动不了手。
3.1 自定义函数:把一段计算装进一个名字里
自定义函数和数学里的函数本质上是一回事。数学上写 f(x,y) = 3x + 2y,意思是你给我两个数,我按这个规则算一个结果给你。写成 MQL4 就是:
int ft(int x, int y) // int 是返回值类型,(x,y) 是参数,ft 是函数名 { int temp; // 函数内部自己的变量,外面看不见 temp = 3 * x + 2 * y; // 按公式算 return(temp); // 结束函数,把 temp 的值交回给调用它的地方 }逐块看。函数头int ft(int x, int y)交代了三件事:int说明这个函数算完会还给你一个整数;ft是函数名,以后你就靠这个名字喊它;(x, y)是参数清单,每个参数后面都必须带类型定义词,因为参数也是变量,用之前同样要定义。这一点新手经常漏,写成ft(x, y)就编译不过。
大括号里面是函数体,也就是真正干活的几句。return是结束语句,它后面的括号里放的就是运算结果,也叫返回值。程序跑到return这一行,就把结果带回调用处,然后接着往下走。
这个函数可以写得更短,效果完全一样:
int ft(int x, int y) { return(3 * x + 2 * y); }因为不需要中间变量,直接算完就返回。
调用的时候非常简单,只要函数名对、参数个数对得上、类型能对上,就能用。写ft(4, 5),程序按顺序把 4 传给 x、把 5 传给 y,算出 3×4 + 2×5 = 22,把 22 送回来,然后继续执行下面的语句。你完全不需要知道里面是怎么算的,只要知道「扔进去两个数,出来一个数」,这就是函数最大的价值:把复杂挡在名字后面。
3.2 没有返回值的情况,用 void
不是所有函数都为了算出一个数。有些函数就是为了做一件事,比如发一封邮件、弹一个提示框、画一条线,做完就完,没有结果要交回来。这种函数的类型写成void,中文叫无值型。
void 打个招呼() { Alert("程序开始运行"); // 弹窗提示,做完就结束 return; // 可以写 return; 不带值,也可以直接省略 }对比一下就清楚了:int、double、string、bool这四种类型的函数,必须用return交回一个对应类型的值;void类型的函数不需要交值,return后面不跟括号内容,或者干脆不写。选哪种取决于你这段代码的目的,是要算出一个东西,还是要执行一个动作。
还有一条很关键的规则:在函数内部定义的变量,只在这个函数运行时存在,函数一结束就自动消失,跟外面互不影响。上面ft里的x、y、temp三个变量,运行期间被创建,运行结束就被注销。这意味着你在两个不同函数里都写int temp;完全没问题,它们各过各的,不会打架。等哪天你觉得「为什么我在这儿改了值,那边没变」,先想想是不是跨函数了。
3.3 数组:一排带编号的格子
一个变量只能存一个数。可行情图上有几千根 K 线,每根都有开盘价、最高价、最低价、收盘价,这就不是几个变量能解决的了。数组就是干这个的:它是一系列同类型变量的集合,可以一次存很多个数。
int aa[4] = {4, 3, 2, 1}; // 4 个元素的整型数组,名字叫 aa,同时赋初值这行的意思是:建一个叫aa的盒子排,一共 4 个格子,从前往后依次放 4、3、2、1。注意编号规则,数组第一个格子的编号是 0,不是 1。所以aa[0]是 4,aa[1]是 3,aa[2]是 2,aa[3]是 1。方括号里的数字叫索引,中文习惯叫下标。这个「从 0 开始数」的规则一定要刻进脑子里,后面取行情数据全靠它,数错一位结果就全错。
创建数组时,元素个数可以写死,也可以不写,初值也可以给也可以不给:
int bb[]; // 建数组 bb,不指定元素个数,后面再定 int cc[8]; // 建数组 cc,8 个格子,暂时都不赋值 int dd[3] = {9, 8, 7}; // 建数组 dd,3 个格子,全部赋初值 int ee[9] = {0,1,2,3}; // 建数组 ee,9 个格子,只给前 4 个赋初值第三行和第四行的区别值得停一下。dd声明 3 个格子又给了 3 个值,刚好装满。ee声明 9 个格子却只给了 4 个值,剩下 5 个格子没有初值,数值型数组默认会是 0,但你心里要清楚「我并没有主动给它们赋值」。这种「声明得多、赋值得少」的写法在实际代码里很常见,尤其在预先开一块缓存的时候。
3.4 赋值和引用:一次只能碰一个格子
新手最容易误解的一点是:数组不能整体操作。除了创建的那一句可以批量赋值之外,后面想改内容,必须一个一个格子来。
dd[2] = 1; // 把 dd 的第 3 个格子改成 1,原来它是 7这一句执行完,dd里的三个值就从{9, 8, 7}变成了{9, 8, 1}。注意这一行前面没有int,因为dd早就定义过了,这里只是改内容。如果写成int dd[2] = 1;就变成重新定义一个数组,编译器会不高兴。
引用也一样,一次只能取一个格子的值。数组aa里是{4,3,2,1},你写aa[i],当i等于 0 时取到 4,i等于 1 时取到 3,依此类推。想处理一整排数据,就得靠循环,让i从 0 一路加上去。这也是为什么循环和数组永远是一起出现的:
int aa[4] = {4, 3, 2, 1}; int 总和 = 0; for(int i = 0; i < 4; i++) // i 从 0 开始,只要小于 4 就继续 { 总和 = 总和 + aa[i]; // 每次把当前格子的值加到总和里 }这段跑完,总和就是 4+3+2+1 = 10。循环条件写i < 4而不是i <= 4,因为最大下标是 3,写成小于等于 4 就会去访问aa[4],那个格子根本不存在,程序会直接出错。这类「差一」的问题在后面处理 K 线数据时会反复出现,先把这里的手感练出来。
4. 行情数据怎么取:预定义数组、指标函数和第一个能画线的指标
前面三章都是在练基本功,这一章开始接触真正有用的东西:把图表上的价格和指标值取出来。MQL4 编程入门之所以让人觉得「学完就能用」,很大程度上就是因为软件已经把行情数据准备好了,你只要知道去哪儿拿。
4.1 六个预定义数组:开盘、最高、最低、收盘、成交量、时间
每根 K 线蜡烛都有开盘价、最高价、最低价、收盘价、成交量、所属时间这六项,一根 K 线一套,几千根 K 线就是几千套。所以这些数据必然用数组来存,而且软件已经替你定义好了,拿来就能用,不用自己创建。
| 数组名 | 含义 | 类型 |
|---|---|---|
Open[] | 开盘价 | double |
High[] | 最高价 | double |
Low[] | 最低价 | double |
Close[] | 收盘价 | double |
Volume[] | 成交量 | double |
Time[] | 所属时间 | datetime |
这里有个和普通数组不一样、但对新手特别重要的地方:编号是从右往左倒着数的。屏幕上最右边那根、也就是最新的一根 K 线,编号是 0;往左一根是 1,再往左是 2。所以Close[0]是最新一根的收盘价,Close[1]是上一根的收盘价。这个规则刚开始会别扭,因为人看图习惯从左往右,但代码里必须从右往左想。写多了就顺了,我当初在纸上画了几次「右 0 左 1」的示意才彻底记住。
用的时候是方括号,不是圆括号。Close[0]对,Close(0)错。方括号代表「取数组里的第几个」,圆括号代表「调用函数」,这两个符号在 MQL4 里分得很清楚,混用直接编译报错。
4.2 五个现成变量:Ask、Bid、Bars、Digits、Point
除了数组,还有几个常用的预定义变量,随取随用,不用定义。
Ask是买入价,Bid是卖出价,都是实时价格,类型是双精度小数。你想在提示框里显示当前价格,直接写Alert(Close[0]);或者Alert(Ask);都行。
Bars是当前图表里的 K 线总数,类型是整数。这个变量在写循环的时候几乎必用,因为你要知道一共处理多少根。
Digits是当前品种的小数位数,整数型。不带日元的品种一般是 4,带日元的一般是 2,黄金、原油这类一般是 2。Point是当前品种的点值,双精度,不带日元一般是 0.0001,带日元一般是 0.01。这两个刚好相反,Digits是几位小数,Point是最小变动单位。写价格显示的时候经常要把数字转成字符串并按Digits保留小数位,这一步不做,弹出来的价格会带一长串尾巴。
4.3 iMA 这七个参数怎么填
预定义数组只能拿当前图表、当前周期的数据。如果你想在 1 小时图上取日线的均线,或者取别的品种的数据,就要用指标函数。最典型的是取移动平均线:
double iMA(symbol, timeframe, period, ma_shift, ma_method, applied_price, shift)七个参数,一个个说清楚:
| 位置 | 参数 | 填什么 |
|---|---|---|
| 1 | symbol | 品种名,如"EURUSD";填NULL表示当前图表品种 |
| 2 | timeframe | 周期常量,如PERIOD_H1;填0表示当前周期 |
| 3 | period | 均线周期,20 日均线就填 20 |
| 4 | ma_shift | 均线整体左右偏移量,一般不偏移填 0 |
| 5 | ma_method | 平均模式,MODE_SMA简单、MODE_EMA指数、MODE_SMMA平滑、MODE_LWMA线性加权 |
| 6 | applied_price | 用哪个价格算,PRICE_CLOSE收盘价、PRICE_OPEN开盘价、PRICE_HIGH最高价、PRICE_LOW最低价等 |
| 7 | shift | 位置序号,0 是最新一根,1 是上一根 |
周期常量常用的有PERIOD_M1、PERIOD_M5、PERIOD_M15、PERIOD_M30、PERIOD_H1、PERIOD_H4、PERIOD_D1、PERIOD_W1、PERIOD_MN1,分别对应 1 分钟、5 分钟、15 分钟、30 分钟、1 小时、4 小时、日线、周线、月线。
看两个例子就懂了。iMA("EURUSD", PERIOD_H1, 20, 0, MODE_SMA, PRICE_CLOSE, 0)意思是:欧元兑美元 1 小时图上,用收盘价算的 20 周期简单移动平均线,最新一根 K 线位置的值。iMA(NULL, 0, 20, 0, MODE_EMA, PRICE_CLOSE, 2)意思是:当前图表、当前周期,用收盘价算的 20 周期指数移动平均线,倒数第 3 根 K 线位置的值。
NULL和0这两个「偷懒写法」在实际写指标时用得最多,因为大部分时候你就是在当前图表上算当前品种的指标,没必要把品种和周期写死。写死了反而麻烦,换一个图表就不对了。
其他指标也是一个套路,MACD、RSI、威廉指标、布林线都有对应的取值函数,参数思路大同小异。入门阶段先把iMA这一个吃透,其他的看一眼手册就能上手。
4.4 动手:第一个能画线的指标
现在把前面所有东西拼起来,做一个能真正跑的东西:在副图画一根线,这根线是快慢两条均线的差。写完之后你会有个明确的感受——原来指标就是这么来的。
打开软件的指标编辑器,新建一个自定义指标,把下面这段贴进去:
#property indicator_separate_window // 指标画在副图 #property indicator_color1 White // 第一条指标线用白色 #property indicator_level1 0 // 在数值 0 的位置画一条水平虚线 extern int FMA = 12; // 快线周期,默认 12,用户可改 extern int SMA = 26; // 慢线周期,默认 26,用户可改 double buf[]; // 用来存这根线每个位置的值 int init() // 初始化函数,指标加载时运行一次 { SetIndexBuffer(0, buf); // 把数组 buf 绑定为第 1 条指标线 SetIndexStyle(0, DRAW_LINE); // 第 1 条线画成连续曲线 return(0); } int start() // 主函数,数据一变就触发 { int limit = Bars - IndicatorCounted(); // 只算还没算过的那些 K 线 for(int i = 0; i < limit; i++) // 从最新一根往回算 { buf[i] = iMA(NULL, 0, FMA, 0, MODE_EMA, PRICE_CLOSE, i) - iMA(NULL, 0, SMA, 0, MODE_EMA, PRICE_CLOSE, i); } return(0); }一段一段解释。
开头三行#property是文件头部,也叫预处理语句。它们以#开头,行尾不加分号,作用是在指标加载前就告诉软件一些设定。indicator_separate_window表示画在副图,如果换成indicator_chart_window就画在主图,均线那类指标一般用主图。indicator_color1 White定第一条线的颜色。indicator_level1 0在数值 0 的位置横着画一条虚线,方便你看出正负分界。
两个extern是给用户调的参数,快线 12、慢线 26,挂到图表上会在参数框里出现,可以改成别的数。
double buf[];是在函数外面定义的全局数组,用来存这根线在每个位置上的值。它必须定义在外面,因为init()和start()两个函数都要用它。
init()在指标加载时只跑一次,专门做设置。SetIndexBuffer(0, buf)把数组buf和第一条指标线绑在一起,意思是「这条线画什么,全看 buf 里存了什么」。SetIndexStyle(0, DRAW_LINE)把第一条线设成连续曲线。括号里的 0 是线的编号,第一条线编号为 0,这个从 0 开始数的规矩和数组一样。
start()是主函数,数据一变动就被触发一次,变动多少次就跑多少次。第一句int limit = Bars - IndicatorCounted();是个很实用的小技巧。Bars是图上总共有多少根 K 线,IndicatorCounted()是已经算过、有值的根数,两者一减,就是这次需要新算的根数。这样程序不会每次都把几千根 K 线重算一遍,图越跑越卡的问题基本就是漏了这一句。
for循环里,i从 0 开始,一直加到limit为止,每次把第i个位置上的快线值减慢线值,塞进buf[i]。因为buf已经绑到指标线上,所以数组一赋值,图上就自动出线。这就是全部的秘密:所谓画指标线,本质就是给一个绑定好的数组逐位赋值。
编译通过后挂到图表上,副图就会出现一根白线,形状和你熟悉的 MACD 里的那根快线一样。改一改参数框里的数字,线会跟着变。到这一步,你就算是真正跑通过第一个 MQL4 程序了。
5. 新手常见问题与排查:这几个坑我基本都踩过
刚跑通第一个指标就兴冲冲改代码,然后碰到一堆莫名其妙的错误,这是所有人的必经之路。下面五条是新手阶段出现频率最高的状况,每条都按「现象、原因、解决」说清楚,碰上了直接对照查。
5.1 现象:编译报错说某一行少了分号,可我明明加了
原因:MQL4 里只有语句后面才需要分号。if、for、while后面的条件括号后面不能加分号,函数头后面也不能加,大括号后面同样不用。而#property这类预处理语句行尾也不加分号。新手的习惯是「每行结尾敲个分号」,结果把if(a == 1);这么一写,条件后面多了个分号,程序就变成「条件判断完什么也不做」,后面的语句无论如何都会执行,逻辑全乱。
解决:记住一条判断标准——这一行是在做一件事(赋值、调用函数、return),结尾加;这一行是在描述条件或结构(if(...)、for(...)、int ft(...)、{、}),结尾不加。写完一段代码从上往下扫一遍,专挑那几行看。
5.2 现象:报错说变量重复定义,可我只有一句
原因:类型定义词用重复了。变量第一次创建时用int、double这类词,之后再提到它就不能再带。同一个变量在不同的大括号里各定义一次是合法的,但在同一层里定义两次就冲突。
解决:把代码里所有带类型定义词的行挑出来,确认每个名字只出现一次。改值的时候直接写名字 = 值;,不带类型。同理,函数的参数已经带了类型,函数体里不要再给参数加类型定义。
5.3 现象:程序跑到一半直接停了,或者结果离谱
原因:数组越界。声明了 4 个元素的数组,你去访问第 5 个,那个格子不属于你,程序可能取到乱七八糟的数,也可能直接崩。最常见的写法是把i < 4写成i <= 4,或者在用Bars做循环上界时忘了减一。
解决:循环上界一律用小于,不用小于等于。用Bars时记住最大有效下标是Bars - 1。另外,画指标线时用limit = Bars - IndicatorCounted()已经帮你避开了大部分越界情况,别自作聪明改成固定数字。
5.4 现象:指标挂上去一片空白,编译明明通过了
原因:常见有四种。一是SetIndexBuffer忘了写,数组没绑到指标线,赋值了也没地方显示;二是buf定义在了start()里面,函数一结束就消失了;三是#property写成了主图,但你以为在副图,其实线画在了价格区域被 K 线盖住;四是循环根本没跑起来,limit算出来是 0 或负数。
解决:从这四处挨个查。先看init()里有没有SetIndexBuffer和SetIndexStyle;再看数组是不是定义在函数外面;然后核对#property那一行;最后在start()里临时加一句Print(limit);,把值打到日志里看一眼,比盯着屏幕猜快得多。
5.5 现象:改了参数,指标完全没反应
原因:参数变量没有加extern,或者加了但名字和你在别处引用的不是同一个。还有一种情况是参数加了extern,但函数里用的仍然是写死的数字,比如上面那个例子里,如果循环里写成iMA(NULL,0,12,...) - iMA(NULL,0,26,...),那FMA、SMA两个参数就成了摆设,改多少都没用。
解决:检查所有需要在界面上调的变量,前面有没有extern;再把函数体里的数字挨个看一遍,凡是本该用参数的地方都换成变量名。这个错误特别隐蔽,因为程序不报错,跑起来也正常,只是参数失效,很容易让人误以为是自己改错了位置。
6. 下一步学什么:从「能跑」到「能改」的三步走
第一个指标跑通之后,很多人会立刻想去看更复杂的代码。我的建议是先别急,按下面三个阶段走,每一步都有明确的验收标准,走完你会发现自己已经能改别人写的东西了。
| 阶段 | 目标 | 练手任务 |
|---|---|---|
| 第一阶段 | 基本功不查资料也能写 | 不看任何参考,手写一遍四种类型的变量定义、一个求和函数、一个装 5 个数的数组并用循环求和 |
| 第二阶段 | 能改现成指标 | 找一段简单的公开指标源码,改它的颜色、线型、参数默认值,再把主图改成副图 |
| 第三阶段 | 能加自己的逻辑 | 在指标里加一句价格触碰某个位置就弹提示,用if判断,用变量做「只报一次」的标记 |
第一阶段看起来笨,但它是分水岭。变量、函数、数组这三样,如果你每次写都要翻资料,后面看什么代码都是天书;如果能在空白编辑器里默写出来,那基本所有 MQL4 代码你都能读个大概。
第二阶段要挑「短」的代码。几十行的简单指标比几百行的复杂指标更适合改,因为你能一眼看完整个结构,知道哪一行改颜色、哪一行接线型。改完一定要挂到图上验证,改颜色成功、改线型成功、改参数成功,这三个都过,你对指标结构的理解就落地了。
第三阶段才是真正开始写自己的东西。先写最简单的判断:如果最新收盘价高于某个值,就Alert("价格到了");。跑通之后加一个变量当标记,让它只报一次,这个「标记」的写法我在前面第 2 章的报警例子里用过,你回头看一眼就明白为什么需要它。等这一层稳了,再去碰循环优化、iCustom取自定义指标、K 线周期切换这些进阶内容,最后才是下单相关的部分。
顺便说一句iCustom,它是用来读别人写的自定义指标值的,参数里要依次填品种、周期、指标名、若干指标参数、指标线编号、位置。线编号从 0 开始,只有一根线就填 0。这个函数新手用得不多,但一旦你想把两个指标组合起来判断,它就是必经之路。
最后讲讲我自己的一条教训。刚开始那阵子,我特别喜欢直接复制别人的源码,改两个参数就挂上去,觉得跑起来了就是学会了。结果有一次图上的线怎么都不对,我查了整整一晚上,最后发现是我把指标挂到了错误的周期上,而代码里用的是NULL, 0,跟随当前图表,所以我改任何参数都没效果。那种翻车的感觉到现在还记得。从那以后我每次改完代码,都会强制走一遍:先确认挂在哪张图、哪个周期,再确认每个extern参数在界面上真的出现了,最后在start()里打一行Print看值对不对,三步都过才去调图形。慢是慢了点,但再没有白白熬过夜。希望帮到你。
本文还有配套的精品资源,点击获取