资源
在MQL5程序中使用图形和声音
MQL5程序允许使用声音和图形文件:
PlaySound()
调用 PlaySound() 函数的示例:
//+------------------------------------------------------------------+
//| 调用标准OrderSend() 并播放一段音频 |
//+------------------------------------------------------------------+
void OrderSendWithAudio(MqlTradeRequest &request, MqlTradeResult &result)
{
//--- 发送一个请求到服务器
OrderSend(request,result);
//--- 如果请求被采纳,播放音频Ok.wav
if(result.retcode==TRADE_RETCODE_PLACED) PlaySound("Ok.wav");
//--- 如果失败,播放文件timeout.wav的警告音
else PlaySound("timeout.wav");
}
|
该示例表达了如何播放来自文件 'Ok.wav' 和 'timeout.wav'的音频,这些文件包含在标准程序包中。这些文件位于 terminal_directory\Sounds文件夹。 在这里 terminal_directory 是文件夹,MetaTrader 5 客户端在这里启动。程序端目录的位置可以通过以下方式,从mql5程序找到:
//--- 文件夹,存储程序端数据的地方
string terminal_path=TerminalInfoString(TERMINAL_PATH);
|
您不仅可以使用来自terminal_directory\Sounds文件夹的音频文件,还可以使用位于子文件夹terminal_data_directory\MQL5的任何音频文件。 您可以通过程序端菜单“文件”->"打开”程序端数据或使用编程方式找到程序端数据目录的位置:
//--- 文件夹,存储程序端数据的地方
string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);
|
例如,如果Demo.wav音频文件位于terminal_data_directory\MQL5\Files,那么调用PlaySound() 应该按以下方式编写:
//--- 播放来自terminal_directory_data\MQL5\Files\Demo.wav文件夹的Demo.wav
PlaySound("\\Files\\Demo.wav");
|
请注意在评论中,文件路径使用“\”反斜杠编写,而在函数中使用“\\"。
当指定路径时,通常使用双反斜杠作为分隔符,因为单反斜杠是处理程序源代码中的字符串常数和字符常数时,编译器的控制符号。
用NULL参数调用 PlaySound() 函数以停止回放:
//--- 用NULL参数调用PlaySound()来停止回放
PlaySound(NULL);
|
ObjectCreate()
EA交易的示例,使用ObjectCreate()函数创建一个图形标签 (OBJ_BITMAP_LABEL) 。
string label_name="currency_label"; // OBJ_BITMAP_LABEL 对象的名称
string euro ="\\Images\\euro.bmp"; // 文件terminal_data_directory\MQL5\Images\euro.bmp的路径
string dollar ="\\Images\\dollar.bmp"; // 文件terminal_data_directory\MQL5\Images\dollar.bmp的路径
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 如果还未创建按钮OBJ_BITMAP_LABEL,请创建
if(ObjectFind(0,label_name)<0)
{
//--- 尝试创建对象OBJ_BITMAP_LABEL
bool created=ObjectCreate(0,label_name,OBJ_BITMAP_LABEL,0,0,0);
if(created)
{
//--- 连接图表左上角的按钮
ObjectSetInteger(0,label_name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
//--- 现在设置对象属性
ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,100);
ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,50);
//--- 重置过去错误的代码为0
ResetLastError();
//--- 下载图片显示按钮的”按键“状态
bool set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,0,euro);
//--- 测试结果
if(!set)
{
PrintFormat("Failed to download image from file %s. Error code %d",euro,GetLastError());
}
ResetLastError();
//--- 下载图片显示按钮的”无按键“状态
set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,1,dollar);
if(!set)
{
PrintFormat("Failed to download image from file %s. Error code %d",dollar,GetLastError());
}
//--- 发送图表评论刷新,以便于无需标记即可立即显示按钮
ChartRedraw(0);
}
else
{
//--- 创建对象失败,公告
PrintFormat("Failed to create object OBJ_BITMAP_LABEL. Error code %d",GetLastError());
}
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 专家去初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- 删除图表对象
ObjectDelete(0,label_name);
}
|
创建和设置名为currency_label的图形对象通过currency_label函数实行。图形文件的路径设置在全局变量 euro 和 dollar, 用双反斜杠作为分隔符:
string euro ="\\Images\\euro.bmp"; // terminal_dara_directory\MQL5\Images\euro.bmp文件的路径
string dollar ="\\Images\\dollar.bmp"; // terminal_dara_directory\MQL5\Images\dollar.bmp文件的路径
|
文件位于文件夹 terminal_data_directory\MQL5\Images。
对象 OBJ_BITMAP_LABEL 实际上是一个按钮,根据按钮的状态(已按或未按)展示两个图像中的一个:euro.bmp 或 dollar.bmp。

图形界面的按钮大小会根据图像大小自动调整。通过在OBJ_BITMAP_LABEL对象上点击鼠标左键来改变图像( 属性中必须设置"禁用选择")。OBJ_BITMAP对象以相同方式创建 - 它用于创建必要的背景图像。
OBJPROP_BMPFILE 属性的值,负责对象OBJ_BITMAP 和 OBJ_BITMAP_LABEL的外表,可以动态地变化。这允许为mql5程序创建各种交互式用户界面。
包括mql5程序编译期间的可执行文件资源 #
mql5程序可能需要许多图像和音频文件格式的不同下载资源。为了消除移动MQL5可执行文件时转移所有这些文件的需要,应该会使用到编译器#resource指令:
#resource path_to_resource_file
|
#resource 指令告诉编译器指定路径path_to_resource_file的资源应该被包括到可执行EX5 文件。因此,所有这些必要的图像和音频文件可以直接放在EX5文件,以便在您想要在不同程序端运行程序时,无需分别转移其中使用的文件。任何EX5文件都可以包含资源,而任何EX5程序都可以使用来自其他EX5程序的资源。
BMP 和 WAV 格式的文件在包含到EX5文件之前自动压缩。这表示除了创建完整的MQL5程序外,与通常的MQL5编程方式相比较,使用资源还允许在使用图形和音频时,减少所需文件的总大小。
资源文件大小一定不要超过16Mb。
通过编译器搜索指定的资源
插入资源使用命令 #resource "<path to the resource file>"
#resource "<path_to_resource_file>"
|
常量字符串<path_to_resource_file> 的长度不得超过63个字符。
编译器根据以下顺序在指定路径搜索资源:
- 如果单反斜杠"\"分隔符(写成"\\")放在路径前面,它搜索目录terminal_data_directory\MQL5\涉及的资源。
- 如果没有反斜杠,则搜索资源编写所在的源文件的位置涉及的资源。
资源路径不能包括子字符串"..\\" 和 ":\\"。
资源包含的示例:
//--- 正确的资源规范
#resource "\\Images\\euro.bmp" // euro.bmp 位于 terminal_data_directory\MQL5\Images\
#resource "picture.bmp" // picture.bmp 位于与源文件相同的目录
#resource "Resource\\map.bmp" // 资源位于source_file_directory\Resource\map.bmp
//--- 错误的资源规范
#resource ":picture_2.bmp" // 不能包括 ":"
#resource "..\\picture_3.bmp" // 不能包括 ".."
#resource "\\Files\\Images\\Folder_First\\My_panel\\Labels\\too_long_path.bmp" //超过 63 个交易品种
|
使用资源
资源名称
当资源使用#resource指令声明后,它可以用于程序的任何部分。资源的名称是在行开始没有反斜杠的路径,来设置资源的路径。若要在代码中使用您自己的资源,特殊符号 "::" 应该添加在资源名称的前面。
示例:
//--- 评论中资源规范和其名称的示例
#resource "\\Images\\euro.bmp" // 资源名称 - Images\euro.bmp
#resource "picture.bmp" // 资源名称 - picture.bmp
#resource "Resource\\map.bmp" // 资源名称 - Resource\map.bmp
#resource "\\Files\\Pictures\\good.bmp" // 资源名称 - Files\Pictures\good.bmp
#resource "\\Files\\Demo.wav"; // 资源名称 - Files\Demo.wav"
#resource "\\Sounds\\thrill.wav"; // 资源名称 - Sounds\thrill.wav"
...
//--- 资源利用
ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\euro.bmp");
...
ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::picture.bmp");
...
set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\good.bmp");
...
PlaySound("::Files\\Demo.wav");
...
PlaySound("::Sounds\\thrill.wav");
|
请注意,当设置资源到OBJ_BITMAP 和 OBJ_BITMAP_LABEL对象的图像时,OBJPROP_BMPFILE 属性的值不能手动更改。例如,为了创建OBJ_BITMAP_LABEL,我们只有资源 euro.bmp 和 dollar.bmp。
#resource "\\Images\\euro.bmp"; // euro.bmp位于terminal_data_directory\MQL5\Images\
#resource "\\Images\\dollar.bmp"; // dollar.bmp位于terminal_data_directory\MQL5\Images\
|
当查看该对象属性时,我们将看到属性BitMap 文件 (On) 和 BitMap 文件 (Off) 无效,不能手动更改:

使用其他mql5程序的资源
资源使用方面还有另一个优势 - 在任何mql5程序中,也可以使用另一个EX5文件的资源。因此,来自一个EX5文件的资源可以用在许多其他mql5程序。
若要使用来自另一个文件的资源名称,它应该被指定为 <path_EX5_file_name>::<resource_name>。例如,假设Draw_Triangles_Script.mq5 脚本在文件triangle.bmp中包含一个图像资源:
#resource "\\Files\\triangle.bmp"
|
然后脚本本身使用的其名称将类似"Files\triangle.bmp",并且若要使用它, "::" 应该添加到资源名称。
//--- 使用脚本资源
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"::Files\\triangle.bmp");
|
若要使用另一个程序的相同资源,例如EA交易,我们需要添加资源名称路径到terminal_data_directory\MQL5\相对的EX5文件和脚本EX5文件的名称 - Draw_Triangles_Script.ex5。假设脚本位于标准文件夹 terminal_data_directory\MQL5\Scripts\, 那么应该按照以下方式调用:
//--- 使用EA中的脚本资源
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"\\Scripts\\Draw_Triangles_Script.ex5::Files\\triangle.bmp");
|
如果从另一个EX5调用资源时没有指定可执行文件的路径,那么可执行文件在包括调用资源程序的相同文件夹中搜索。这意味着如果EA交易调用来自Draw_Triangles_Script.ex5的资源而没有指定路径,就像这样:
//--- 调用未指定路径的EA脚本资源
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"Draw_Triangles_Script.ex5::Files\\triangle.bmp");
|
那么如果EA位于terminal_data_directory\MQL5\Experts\,则文件将在文件夹terminal_data_directory\MQL5\Experts\中搜索。
使用包括资源的自定义指标
一个或多个自定义指标对于MQL5应用程序操作可能是必需的。所有这些都包含在可执行MQL5程序的代码中。包含作为资源的指标简化了应用程序的分布。
下面就是包含和使用位于terminal_data_folder\MQL5\Indicators\目录的SampleIndicator.ex5自定义指标的示例:
//+------------------------------------------------------------------+
//| SampleEA.mq5 |
//| Copyright 2013, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#resource "\\Indicators\SampleIndicator.ex5"
int handle_ind;
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//---
handle_ind=iCustom(_Symbol,_Period,"::Indicators\\SampleIndicator.ex5");
if(handle_ind==INVALID_HANDLE)
{
Print("Expert: iCustom call: Error code=",GetLastError());
return(INIT_FAILED);
}
//--- ...
return(INIT_SUCCEEDED);
}
|
OnInit() 函数自定义指标创建一个或多个副本时,这种情况需要特别考虑。请谨记资源应该按照以下方式指明:<path_EX5_file_name>::<resource_name>。
例如,如果SampleIndicator.ex5指标作为资源包含在SampleEA.ex5 EA交易,在自定义指标初始化函数调用iCustom()指定的路径如下: "\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5"。当该路径明确设置时,SampleIndicator.ex5自定义指标严格连接到SampleEA.ex5 EA交易,失去独立工作的能力。
路径本身可以使用GetRelativeProgramPath() 函数接收。用法示例如下:
//+------------------------------------------------------------------+
//| SampleIndicator.mq5 |
//| Copyright 2013, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_plots 0
int handle;
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 提供自身链接的错误方式
//--- 字符串路径="\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5";
//--- 接收自身链接的正确方式
string path=GetRelativeProgramPath();
//--- 指标缓冲映射
handle=iCustom(_Symbol,_Period,path,0,0);
if(handle==INVALID_HANDLE)
{
Print("Indicator: iCustom call: Error code=",GetLastError());
return(INIT_FAILED);
}
else Print("Indicator handle=",handle);
//---
return(INIT_SUCCEEDED);
}
///....
//+------------------------------------------------------------------+
//| GetRelativeProgramPath |
//+------------------------------------------------------------------+
string GetRelativeProgramPath()
{
int pos2;
//--- 接收应用程序的绝对路径
string path=MQLInfoString(MQL_PROGRAM_PATH);
//--- 找出 "\MQL5\" 字符串的位置
int pos =StringFind(path,"\\MQL5\\");
//--- 子字符串未找到 - 错误
if(pos<0)
return(NULL);
//--- 跳过 "\MQL5" 目录
pos+=5;
//--- 跳过多余的 '\' 交易品种
while(StringGetCharacter(path,pos+1)=='\\')
pos++;
//--- 如果这是一个资源,返回MQL5目录的相对路径
if(StringFind(path,"::",pos)>=0)
return(StringSubstr(path,pos));
//--- 为第一个MQL5子目录找到一个分隔符 (例如,MQL5\Indicators)
//--- 如果没找到,返回MQL5目录相对的路径
if((pos2=StringFind(path,"\\",pos+1))<0)
return(StringSubstr(path,pos));
//--- 返回子目录相对的路径(例如, MQL5\Indicators)
return(StringSubstr(path,pos2+1));
}
//+------------------------------------------------------------------+
//| 自定义指标重复函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double& price[])
{
//--- 返回prev_calculated值用于下次调用
return(rates_total);
}
|
资源变量 #
资源可以使用资源变量来声明并被当做适当类型的变量。声明格式:
#resource path_to_the_resource_file as resource_variable_type resource_variable_name
|
示例声明:
#resource "data.bin" as int ExtData[] // 声明包含data.bin 文件数据的数字数组
#resource "data.bin" as MqlRates ExtData[] // 声明包含data.bin文件数据的 示例结构数组
//--- 字符串
#resource "data.txt" as string ExtCode // 声明包含data.txt文件数据的字符串(支持ANSI,UTF-8 和 UTF-16 编码)
#resource "data.txt" as string ExtCode[] // 声明包含data.txt文件字符串的数组(支持ANSI,UTF-8 和 UTF-16 编码)
//--- 图形资源
#resource "image.bmp" as bitmap ExtBitmap[] // 声明包含BMP位图文件的一维数组,数组大小 = 高 * 宽
#resource "image.bmp" as bitmap ExtBitmap2[][] // 声明包含BMP位图文件的二维数组,数组大小 [高][宽]
|
这种声明情况下,资源数据只能通过变量来解决,通过"::<rsource name>"的自动解决 无法工作。
#resource "\\Images\\euro.bmp" as bitmap euro[][]
#resource "\\Images\\dollar.bmp"
//+------------------------------------------------------------------+
//| OBJ_BITMAP_LABEL 对象使用资源创建函数 |
//+------------------------------------------------------------------+
void Image(string name,string rc,int x,int y)
{
ObjectCreate(0,name,OBJ_BITMAP_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
ObjectSetString(0,name,OBJPROP_BMPFILE,rc);
}
//+------------------------------------------------------------------+
//| 脚本程序起始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 输出存储在欧元资源变量的图像大小[宽,高]
Print(ArrayRange(euro,1),", ",ArrayRange(euro,0));
//--- 改变欧元图像 - 在中间绘制红色横纹
for(int x=0;x<ArrayRange(euro,1);x++)
euro[ArrayRange(euro,1)/2][x]=0xFFFF0000;
//--- 使用资源变量创建图形资源
ResourceCreate("euro_icon",euro,ArrayRange(euro,1),ArrayRange(euro,0),0,0,ArrayRange(euro,1),COLOR_FORMAT_ARGB_NORMALIZE);
//--- 创建欧元图形标签对象,并在此设置euro_icon资源图像
Image("Euro","::euro_icon",10,40);
//--- 应用资源的另一个方法,我们不能绘制
Image("USD","::Images\\dollar.bmp",15+ArrayRange(euro,1),40);
//--- 不提供解决euro.bmp资源的直接方法,因为它已经通过欧元资源变量进行声明
Image("E2","::Images\\euro.bmp",20+ArrayRange(euro,1)*2,40); // 将会发生执行时间错误
}
|
脚本执行结果 三个对象中只能创建两个OBJ_BITMAP_LABEL对象。第一个对象的图像在中间有红色条纹。

应用资源的重要优势就是资源文件在编译成EX5可执行文件之前自动解压。因此,使用资源变量可以使您将全部必要数据直接放入可执行文件EX5以及减少相较于MQL5程序传统编写方式的文件的数量和总大小。
使用资源变量可以非常方便在市场发布产品。
特点
- 特殊的位图资源变量类型告诉编译者资源使一个图像。 这种变量接收uint类型。
- 位图类型数组资源变量可以有两种维度。在这种情况下,数组大小定义为[image_height ][ image_width ]。如果指定了一维数组,那么元素数量则等于image_height*image_width。
- 下载24-位图像时,阿尔法通道组件的全部图像像素设置为255.
- 下载没有阿尔法通道的32-位图时,阿尔法通道组件的全部图像像素设置为255。
- 下载有阿尔法通道的32-位图时,不以任何方式处理像素。
- 资源文件大小不能超过128 Mb。
- 通过存在的BOM(标题)自动编码检测执行字符串文件。如果没有BOM,则通过文件内容定义编码。支持ANSI,UTF-8和UTF-16编码文件。当阅读文件数据时,全部字符串转换为Unicode。
OpenCL程序
使用资源字符串变量可以极大的促进一些程序的开发。例如,您可以在独立的CL文件内编写一个OpenCL 程序的编码,然后将其包含为一个字符串放入您的MQL5程序资源。
#resource "seascape.cl" as string cl_program
...
int context;
if((cl_program=CLProgramCreate(context,cl_program)!=INVALID_HANDLE)
{
//--- 通过OpenCL程序执行进一步操作
}
|
在这个示例中,如果没有使用cl_program资源变量,那么您需要编写整个代码作为一个大的字符串。
另见
ResourceCreate(), ResourceSave(), PlaySound(), ObjectSetInteger(), ChartApplyTemplate(), 文件函数