MQL5 编程基础:字符串(基础篇)
MQL5 里的字符串到底怎么存
MQL5 里字符串用 string 类型表达,本质是双字节 Unicode(UTF-16)字符序列,单引号或双引号包裹都能被编译器接受,但社区惯例用双引号避免与 char 字面量混淆。 声明时可以直接赋值:string sym = "XAUUSD"; 这样在 EA 里拿到的是只读副本,若从指标缓冲区取文字标签则需走 StringSubstr 之类的函数切分。 实操上,字符串拼接用加号,但大循环里反复 + 会产生临时对象,十万次以上回测能明显拖慢 MT5 策略测试器;需要高频拼串时倾向先用 string 数组缓存再 StringConcatenate 一次性合并。 开 MT5 敲一段 string a="EUR"; string b="USD"; Print(a+b); 就能在专家日志看到 EURUSD,验证编译器对小写的货币对字符串不做任何语义检查,纯当字节流处理。
「字符串在 EA 与指标里的实际分工」
MQL5 里字符串变量专门装字符数据也就是文本,语言层给了不少顺手的内置函数。写 EA 或指标时,它主要用来拼信息消息:指标里可能是触发交易条件的提示,EA 里则是成交结果的回报。运行时程序还能检查用户输入参数,不合法就弹通知,顺带给点设置建议,这一层用户友好基本靠字符串顶着。
碰上文件读写,字符串也绕不开。量不大时直接用文本文件加字符串比二进制省心,文件里的内容和程序里看着一致,调试时能即时盯数据。原文示例把多手数累积写进一个分号分隔串:0.1; 0.2; 0.3; 0.5,初始化时再拆成数组。
但这类串参有个硬伤:优化器没法按步长扫初始值到终值,真要优化还不如堆数值变量。不过变量堆多了属性窗口就难用了。像通知开关这种不需优化的,用单个字符串替掉 4 个布尔量就很划算——写 "s" 开声音、加 "e" 开邮件,组合随意。
指标侧要克制外部参数总数,因为被 iCustom() 或 IndicatorCreate() 调用时上限卡得死:前者仅 64 个参数,后者参数数组只有 60 个元素。用字符串压缩输入,往往能救场。外汇与贵金属波动剧烈、杠杆高风险大,参数设计别只顾自己方便,也要防调用方接不住。
class="type">class="kw">string str="Any text"; input class="type">class="kw">string Lots="class="num">0.1; class="num">0.2; class="num">0.3; class="num">0.5";
◍ 字符串变量的声明坑与判空写法
在 MQL5 里声明字符串变量和其他类型没两样,可以先声明再赋值,也能在声明时直接初始化。字符串长度没有上限,写长文本时可以用连续双引号把内容拆成多行子串,编译器会拼成一条完整字符串。
有个容易踩的雷:只写 string str1; 不做初始化,它的值是 NULL,而不是空串 ""。下面这段代码跑起来会弹窗显示 false,因为未初始化的 str1 和赋了空串的 str2 并不相等。
Alert(str1==str2); // 弹出 false
做字符串处理前必须判空,否则 NULL 参与运算容易出意料外的 bug。两种写法都行:要么养成声明时全初始化成 "" 的习惯,要么在条件里同时排除 "" 和 NULL。前者更省事,判断条件更短。
量字符串大小用 StringLen() 函数,返回字符数;和 !=0 搭配就能确认里面有没有内容。对外汇或贵金属 EA 开发来说,字符串多用于品种名、日志拼接,MT5 上高频调用时这种判空习惯能少掉不少诡异报错,但交易本身仍属高风险,字符串逻辑错误不会让你爆仓,信号逻辑错才会。
class="type">class="kw">string str; class="type">class="kw">string str="Any text"; class="type">class="kw">string str= "A class="type">long class="type">class="kw">string can be " "split into several " "substrings"; class=class="str">"cmt">//--- output the results Alert(str); class="type">class="kw">string str=""; class="type">class="kw">string str1; class="type">class="kw">string str2=""; class=class="str">"cmt">//--- output the comparison results Alert(str1==str2); if(str!="" && str!=NULL) { class=class="str">"cmt">//--- some operation with a class="type">class="kw">string } if(StringLen(str)!=class="num">0) { class=class="str">"cmt">//--- some operation with a class="type">class="kw">string }
字符串拼接的几种写法与坑
在 MT5 里写 EA 或指标,字符串拼接是最基础也最容易想当然的操作。直接用「+」号就能把两段文本并起来:str4 = str1 + " " + str2 之后,str4 里就是「Programming in MQL5」,str5 则是「Programming for MetaTrader 5」。 往已有主串后面续内容,除了写 str1 = str1 + " " + str2,更省事的是用 += 缩写:str1 += str2 效果完全一致。若想把附加串放到主串开头,做法是把主串接在后面再整体赋回原变量,例如 str3 = str2 + " " + str3 然后再 str3 = str1 + " " + str3。 调用 Alert()、Print()、Comment() 时可以用逗号分隔参数,看起来像拼接,实际只是函数参数分隔符,这些函数最多吞 64 个参数。最终显示效果和「+」一样,但写文件时差别就出来了。 用 FileWrite() 落盘能看清区别:以 FILE_CSV 模式开文件,逗号位置会被分隔符(默认制表符)替换;1.txt 写 FileWrite(h,"1","2","3") 得到「1\t2\t3」,而 2.txt 用「+」连成 "123" 则真写入「123」。FILE_TXT 模式下逗号与「+」结果相同,3.txt 和 4.txt 都是「123」。外汇与贵金属脚本涉及文件输出时,这个差异可能导致日志解析错位,属于高风险细节。 除了运算符,MQL5 给了专用函数 StringAdd() 和 StringConcatenate()。参考描述称它们更省内存、更快。StringAdd(str1, str2) 直接把 str2 追加进 str1;StringConcatenate() 第一个参数是目标变量,后面最多跟 63 个源串,一次性拼好。开 MT5 按 F4 建个脚本,把下面代码贴进去跑一遍,就能确认自己环境里的拼接行为。
class="type">class="kw">string str1,str2,str3,str4,str5; class=class="str">"cmt">//--- assign values str1="Programming"; str2="in MQL5"; str3="for MetaTrader class="num">5"; class=class="str">"cmt">//--- add up the strings str4=str1+" "+str2; str5=str1+" "+str3; class=class="str">"cmt">//--- output the results Alert(str4); Alert(str5); class="type">class="kw">string str1,str2,str3; class=class="str">"cmt">//--- assign values str1="Programming"; str2="in MQL5"; str3="for MetaTrader class="num">5"; class=class="str">"cmt">//--- add up the strings to the main class="type">class="kw">string str1=str1+" "+str2; str1=str1+" "+str3; class=class="str">"cmt">//--- output the results Alert(str1); str1+=str2; str1+=str3; str1+=str2+str3; class="type">class="kw">string str1,str2,str3; class=class="str">"cmt">//--- assign values str1="Programming"; str2="in MQL5"; str3="for MetaTrader class="num">5"; class=class="str">"cmt">//--- concatenate strings, with a class="type">class="kw">string being added to the beginning str3=str2+" "+str3; str3=str1+" "+str3; class=class="str">"cmt">//--- output the results Alert(str3); str3=str1+" "+str2+" "+str3; Print(str1," ",str2," ",str3); Print(str1+" "+str2+" "+str3); class=class="str">"cmt">//--- write to the first file class="type">int h=FileOpen("class="num">1.txt",FILE_WRITE|FILE_ANSI|FILE_CSV); FileWrite(h,"class="num">1","class="num">2","class="num">3"); FileClose(h); class=class="str">"cmt">//--- write to the second file h=FileOpen("class="num">2.txt",FILE_WRITE|FILE_ANSI|FILE_CSV); FileWrite(h,"class="num">1"+"class="num">2"+"class="num">3"); FileClose(h); class=class="str">"cmt">//--- write to the third file h=FileOpen("class="num">3.txt",FILE_WRITE|FILE_ANSI|FILE_TXT); FileWrite(h,"class="num">1","class="num">2","class="num">3"); FileClose(h); class=class="str">"cmt">//--- write to the fourth file h=FileOpen("class="num">4.txt",FILE_WRITE|FILE_ANSI|FILE_TXT); FileWrite(h,"class="num">1"+"class="num">2"+"class="num">3"); FileClose(h); class="type">class="kw">string str1,str2,str3; class=class="str">"cmt">//--- assign values str1="Programming"; str2="in MQL5"; str3="for MetaTrader class="num">5"; class=class="str">"cmt">//--- call the function to concatenate strings StringAdd(str1," "); StringAdd(str1,str2); StringAdd(str1," "); StringAdd(str1,str3); class=class="str">"cmt">//--- output the results Alert(str1); class="type">class="kw">string str1,str2,str3; class=class="str">"cmt">//--- assign values str1="Programming"; str2="in MQL5";
「拼字符串时别漏了空格」
在 MQL5 里用 StringConcatenate 把多个片段合成一个字符串时,片段之间不会自动补空格。上面这段把 str1 自身、空格、str2、空格、str3 依次传入,str3 固定为 "for MetaTrader 5",最终 str1 会变成原内容拼接后的长串。 如果漏写那两个 " " 参数,str2 和 str3 会直接贴在一起,Alert 弹出的内容可读性很差。开 MT5 新建脚本粘下面代码跑一遍,就能看到带空格和不含空格的差异。 外汇与贵金属行情受杠杆影响波动剧烈,用脚本做字符串处理虽不直接交易,但日志错乱可能误导后续信号判断,属高风险环境下的辅助环节。
str3="for MetaTrader class="num">5"; class=class="str">"cmt">//--- call the function for combining several strings StringConcatenate(str1,str1," ",str2," ",str3); class=class="str">"cmt">//--- output the results Alert(str1);
◍ 把各类变量拼进提示字符串的几种写法
在 MT5 里写 EA 或脚本时, alert 弹窗、日志、文件输出都依赖把数值塞进一段可读文本。整数系(int、long、datetime 等)用 IntegerToString() 最直白:布尔量得到 "0" 或 "1",clrYellow 会返回 "65535",2012.01.01 00:00 的 datetime 则是 "1325376000"。 双精度与浮点走 DoubleToString(),第二个参数卡小数位。给 1.23456 分别传 2 和 3,得到 "1.23" 与 "1.235",按数学舍入截断,不是简单截尾。 时间格式化用 TimeToString()。不传参得到自 1970-01-01 以来的秒数表达式;传 TIME_DATE|TIME_SECONDS 则拼出 "2012.11.02 22:00:00" 这类人类格式。枚举变量可用 EnumToString() 直接出 "Mode1" 这样的条目名,下拉参数排错很省事。 颜色有两条路:ColorToString(clrRed,true) 存 "clrRed",传 false 则存 "255,0,0" 分量串;非标准色无论第二项填什么都会回分量值。 另一种偷懒法是强制类型转换 (string)x。布尔变 "true"/"false",浮点尽可能保精度且仅去尾部零——0.1 与 0.123 分别得 "0.1"、"0.123"。外汇与贵金属波动剧烈、杠杆风险高,任何字符串拼接出的信号都只是辅助,实盘前请在策略测试器里跑一遍确认输出符合预期。
<span class="keyword">class="type">int</span> x=<span class="number">class="num">1</span>; <span class="keyword">class="type">class="kw">string</span> str=<span class="class="type">class="kw">string">"x = "</span>+<span class="functions">IntegerToString</span>(x); <span class="keyword">class="type">class="kw">double</span> x=<span class="number">class="num">1.23456</span>; <span class="keyword">class="type">class="kw">string</span> str1=<span class="class="type">class="kw">string">"x = "</span>+<span class="functions">DoubleToString</span>(x,<span class="number">class="num">2</span>); <span class="keyword">class="type">class="kw">string</span> str2=<span class="class="type">class="kw">string">"x = "</span>+<span class="functions">DoubleToString</span>(x,<span class="number">class="num">3</span>); <span class="keyword">class="type">class="kw">datetime</span> tm=<span class="functions">TimeCurrent</span>(); <span class="comment">class=class="str">"cmt">// Current time </span> <span class="keyword">class="type">class="kw">string</span> str1=<span class="functions">IntegerToString</span>(tm); <span class="keyword">class="type">class="kw">string</span> str2=<span class="functions">TimeToString</span>(tm); <span class="keyword">class="type">class="kw">string</span> str1=<span class="class="type">class="kw">string">"Date and time with minutes: "</span>+<span class="functions">TimeToString</span>(tm); <span class="keyword">class="type">class="kw">string</span> str2=<span class="class="type">class="kw">string">"Date only: "</span>+<span class="functions">TimeToString</span>(tm,TIME_DATE); <span class="keyword">class="type">class="kw">string</span> str3=<span class="class="type">class="kw">string">"Time with minutes only: "</span>+<span class="functions">TimeToString</span>(tm,TIME_MINUTES); <span class="keyword">class="type">class="kw">string</span> str4=<span class="class="type">class="kw">string">"Time with seconds only: "</span>+<span class="functions">TimeToString</span>(tm,TIME_SECONDS); <span class="keyword">class="type">class="kw">string</span> str5=<span class="class="type">class="kw">string">"Date and time with seconds: "</span>+<span class="functions">TimeToString</span>(tm,TIME_DATE|TIME_SECONDS); <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| Create an enumeration |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="keyword">enum</span> EMode { OFF=<span class="number">class="num">0</span>, Mode1 = <span class="number">class="num">1</span>, Mode2 = <span class="number">class="num">2</span>, Mode3 = <span class="number">class="num">3</span> }; <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| Start the script |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="keyword">class="type">void</span> <span class="functions">OnStart</span>() { EMode Value=<span class="number">class="num">1</span>; <span class="comment">class=class="str">"cmt">//--- join strings together</span> <span class="keyword">class="type">class="kw">string</span> str=<span class="class="type">class="kw">string">"The "</span>+<span class="functions">IntegerToString</span>(Value)+<span class="class="type">class="kw">string">" value"</span>+<span class="functions">EnumToString</span>(Value)+<span class="class="type">class="kw">string">" entry of the Emode enumeration"</span>; <span class="comment">class=class="str">"cmt">//--- output the results</span> <span class="functions">Alert</span>(str); } <span class="keyword">class="type">class="kw">color</span> ColorValue=<span class="macro">clrRed</span>; <span class="keyword">class="type">class="kw">string</span> str=<span class="functions">ColorToString</span>(ColorValue,<span class="keyword">true</span>); <span class="keyword">class="type">class="kw">color</span> ColorValue=<span class="macro">clrRed</span>; <span class="keyword">class="type">class="kw">string</span> str=<span class="functions">ColorToString</span>(ColorValue,<span class="keyword">class="kw">false</span>); <span class="keyword">class="type">int</span> x=<span class="number">class="num">123</span>; <span class="keyword">class="type">class="kw">string</span> str=(<span class="keyword">class="type">class="kw">string</span>)x; <span class="keyword">class="type">bool</span> x=<span class="keyword">true</span>; <span class="keyword">class="type">class="kw">string</span> str=(<span class="keyword">class="type">class="kw">string</span>)x; <span class="keyword">class="type">class="kw">double</span> x1=<span class="number">class="num">0.1</span>; <span class="keyword">class="type">class="kw">double</span> x2=<span class="number">class="num">0.123</span>; <span class="keyword">class="type">class="kw">string</span> str1=(<span class="keyword">class="type">class="kw">string</span>)x1; <span class="keyword">class="type">class="kw">string</span> str2=(<span class="keyword">class="type">class="kw">string</span>)x2;