MQL5 编程基础:字符串(基础篇)
📘

MQL5 编程基础:字符串(基础篇)

第 1/3 篇

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 个元素。用字符串压缩输入,往往能救场。外汇与贵金属波动剧烈、杠杆高风险大,参数设计别只顾自己方便,也要防调用方接不住。

MQL5 / C++
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 上高频调用时这种判空习惯能少掉不少诡异报错,但交易本身仍属高风险,字符串逻辑错误不会让你爆仓,信号逻辑错才会。

MQL5 / C++
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 建个脚本,把下面代码贴进去跑一遍,就能确认自己环境里的拼接行为。

MQL5 / C++
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 新建脚本粘下面代码跑一遍,就能看到带空格和不含空格的差异。 外汇与贵金属行情受杠杆影响波动剧烈,用脚本做字符串处理虽不直接交易,但日志错乱可能误导后续信号判断,属高风险环境下的辅助环节。

MQL5 / C++
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"。外汇与贵金属波动剧烈、杠杆风险高,任何字符串拼接出的信号都只是辅助,实盘前请在策略测试器里跑一遍确认输出符合预期。

MQL5 / C++
<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&nbsp;</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&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|</span>
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="keyword">enum</span> EMode
&nbsp;&nbsp;{
&nbsp;&nbsp; OFF=<span class="number">class="num">0</span>,
&nbsp;&nbsp; Mode1 = <span class="number">class="num">1</span>,
&nbsp;&nbsp; Mode2 = <span class="number">class="num">2</span>,
&nbsp;&nbsp; Mode3 = <span class="number">class="num">3</span> 
&nbsp;&nbsp;};
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//| Start the script&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |</span>
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="keyword">class="type">void</span> <span class="functions">OnStart</span>()
&nbsp;&nbsp;{
&nbsp;&nbsp; EMode Value=<span class="number">class="num">1</span>;
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- join strings together</span>
&nbsp;&nbsp; <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>;
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- output the results</span>
&nbsp;&nbsp; <span class="functions">Alert</span>(str);
&nbsp;&nbsp;} 
<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;

常见问题

字符串以动态长度存在堆区,只在赋值时分配,不用时自动回收;普通短提示占用极小,无需手动管理。
名称类固定文本用字符串常量,数值用 double/int 变量,最后再拼成一条提示,避免把数字当文本硬存。
小布可以读取你的策略代码,标出拼接缺空格、空字符串误判等常见写法,并给出修正建议。
未初始化就调用 StringLen 可能拿到空引用,应先赋空串 "" 或用 StringIsEmpty 判空再操作。
用 StringFormat("%d %.2f", a, b) 比加号拼接稳,能控制小数位且避免类型隐式转换导致的显示异常。