
MQL5中的结构及其数据打印方法
目录
- 概述
- MqlDateTime 结构
- MqlDateTime, 打印方法
- 用于处理MqlDateTime结构数据的函数
- 辅助函数
- MqlDateTime 结构中的年份
- MqlDateTime 结构中的月份
- MqlDateTime 结构中的日期
- MqlDateTime 结构中的小时数
- MqlDateTime 结构中的分钟数
- MqlDateTime 结构中的秒数
- MqlDateTime 结构中的一周中的一天
- MqlDateTime结构中的一年中的天数
- 使用示例
- MqlTick结构
- MqlTick打印方法
- 用于处理MqlTick结构数据的函数
- 辅助函数
- MqlTick结构中的时间
- MqlTick结构中的卖家报价
- MqlTick结构中的买家报价
- MqlTick结构中的最后交易价格
- MqlTick结构中的最后交易量
- MqlTick结构中以毫秒数计算的时间
- MqlTick结构中的分时标志
- MqlTick结构中具有更高准确性的上次价格交易量
- 使用示例
- MqlRates 结构
- MqlBookInfo结构
- MqlBookInfo打印方法
- 用于处理MqlBookInfo结构数据的函数
- MqlBookInfo市场深度结构中的订单类型
- MqlBookInfo市场深度结构中的订单价格
- MqlBookInfo市场深度结构中的订单交易量
- 精度更高的交易量
- 使用示例
- 结论
概述
结构是一种方便的工具,用于存储、记录和检索属于单个变量的任何定义的逻辑相关数据。
MQL5具有12个预定义结构,用于存储和传输服务信息:
- MqlDateTime旨在表示日期和时间;
- MqlParam allows passing inputs when creating an indicator handle using the IndicatorCreate() function;
- MqlRates提供历史数据的信息,包括价格、数量和点差;
- MqlBookInfo用于获取市场深度(报价窗口)中显示的数据;
- MqlTradeRequest用于在执行交易操作时创建交易请求;
- MqlTradeCheckResult允许在发送之前检查准备好的交易请求;
- MqlTradeResult包含交易服务器对OrderSend()函数发送的交易请求的响应;
- MqlTradeTransaction包含了交易描述;
- MqlTick旨在及时获得当前价格的最需要的数据。
- 经济日历结构用于实时获取发送到MetaTrader 5平台的经济日历事件的数据。经济日历函数允许在发布新闻报告后立即分析宏观经济参数,因为相关值直接从来源广播,不会延迟。
MqlParam和MqlTradeRequest结构传输用于创建指标和向服务器发送交易请求的技术信息。我们根据完成的结构中发送数据的要求结果填写结构的要求字段。换句话说,这些结构并不特别需要打印这些结构的字段由程序员填充的数据
但剩下的结构返回查询结果,每个字段由终端子系统或交易服务器填写。从这些结构中获取数据,以编程方式分析结构的填充字段,或将其打印到日志中进行后续手动分析,对于以编程方式做出决策以及理解和查找逻辑错误的位置来说,都是非常方便和必要的。
为了打印结构的所有字段,有一个标准的ArrayPrint()函数,该函数以方便的表格格式显示数组中包含的数据以及处理的结构的类型。但有时我们需要以另一种格式打印结构中的数据,这可能比表格表示更方便。例如,我们可能需要在一行中显示结构的所有字段,包括标题和相应的数据。这对于分析大量数据可能更方便。同时,有时我们需要看到一个更详细的视图,包括结构字段的描述和相应数据的不同表示。
在当前的文章中,我们将研究用于查看结构数据的标准工具,并为日志中不同的结构数据表示创建自定义函数。
MqlDateTime 结构
struct MqlDateTime { int year; // year int mon; // month int day; // day int hour; // hour int min; // minutes int sec; // seconds int day_of_week; // day of the week (0-Sunday, 1-Monday, ... ,6-Saturday) int day_of_year; // number of a day in the year (1st of January has number 0) };
标准函数TimeCurrent()、TimeGMT()、TimeLocal()、TimeTradeServer()和TimeToStruct()用于填充结构字段。
前四个函数,除了返回当前日期、GMT日期、本地计算机时间和交易服务器日期外,每个函数都有一个重载函数。在函数的形式参数中,可以通过引用将日期结构传递给它。执行函数后,传递给函数的结构字段将填充函数返回的日期数据。
TimeToStruct()函数专门用于将datetime值类型(自1970年1月1日起的秒数)中的结构填充到MqlDateTime结构类型变量中。
bool TimeToStruct( datetime dt, // date and time MqlDateTime& dt_struct // structure for accepting values );
如果成功,返回true,否则-false。操作后,日期结构将填充在datetime类型的变量中第一个参数中传递的时间数据。
我们的日期结构已经完整了,但我们如何打印它?有一个标准的TimeToString()函数,它将包含自1970年1月1日以来以秒为单位的时间的值转换为“yyyy.mm.dd hh:min:sec”格式的字符串。
但是该函数不适用于MqlDateTime结构,而是适用于datetime日期。那么,我们应该将结构转换回时间值吗?当然不要。每个函数都有其自身的用途。我们可以从日期结构中单独提取日期和时间的任何组成部分——一年、一个月、一小时、一分钟、一周中的一天等等。。。但是我们怎样才能显示所有的结构数据呢?
ArrayPrint()函数适用于此任务,该函数记录简单类型或简单结构的数组。它以表的形式显示数据,其中列是结构的字段,行表示数组单元。换句话说,为了只显示一个日期的结构,我们需要一个1的数组。对于一个交易周,如果数据来自D1图表,数组大小通常为5个交易日。
MqlDateTime, 打印方法
这样的脚本使用ArrayPrint()打印从日志中的当前时间获得的日期结构:
void OnStart() { //--- Declare a date structure variable MqlDateTime time; //--- Get the current time and at the same time fill in the date structure TimeCurrent(time); //--- Declare an array with the MqlDateTime type and write the data of the filled structure into it MqlDateTime array[1]; array[0]=time; //--- Display the header and time using the standard ArrayPrint() Print("Time current (ArrayPrint):"); ArrayPrint(array); /* Sample output: Time current (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 12 8 37 1 197 */ }
相应地,采用日期结构并将其打印在日志中的函数将如下所示:
//+------------------------------------------------------------------+ //| Take a date structure and display its data to the journal. | //| Use ArrayPrint() for display | //+------------------------------------------------------------------+ void MqlDateTimePrint(const MqlDateTime& time_struct) { //--- Declare an array with the MqlDateTime type and write the data of the obtained structure into it MqlDateTime array[1]; array[0]=time_struct; //--- Print the array ArrayPrint(array); /* Sample output: Time current (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 12 8 37 1 197 */ }
该函数允许在日志中打印time_struct变量中传递给它的一个日期。
使用上述函数记录单个日期结构的脚本:
void OnStart() { //--- Declare a date structure variable MqlDateTime time; //--- Get the current time and at the same time fill in the date structure TimeCurrent(time); //--- Display the header and time using the standard ArrayPrint() Print("Time current (ArrayPrint):"); MqlDateTimePrint(time); /* Sample output: Time current (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 12 8 37 1 197 */ }
如果我们需要打印一个日期数组(毕竟这是ArrayPrint()的主要目标),那么我们需要将数据数组传递给datetime函数,填写MqlDateTime数组并打印它。
接受日期时间数组并打印MqlDateTime数组的函数:
//+------------------------------------------------------------------+ //| Accept the datetime array, convert it into MqlDateTime and | //| display converted data into the journal. | //| Use ArrayPrint() for display | //+------------------------------------------------------------------+ void MqlDateTimePrint(const datetime& array_time[]) { //--- Declare a dynamic array of the MqlDateTime type MqlDateTime array_struct[]; //--- Get the size of the array passed to the function int total=(int)array_time.Size(); //--- If an empty array is passed, report on that and leave the function if(total==0) { PrintFormat("%s: Error. Empty array.",__FUNCTION__); return; } //--- Change the size of the MqlDateTime array to match the size of the datetime array ResetLastError(); if(ArrayResize(array_struct,total)!=total) { PrintFormat("%s: ArrayResize() failed. Error %s",__FUNCTION__,(string)GetLastError()); return; } //--- Convert dates from the datetime array into the date structure in the MqlDateTime array for(int i=0;i<total;i++) { ResetLastError(); if(!TimeToStruct(array_time[i],array_struct[i])) PrintFormat("%s: [%s] TimeToStruct() failed. Error %s",__FUNCTION__,(string)i,(string)GetLastError()); } //--- Print the filled MqlDateTime array ArrayPrint(array_struct); /* Sample output: Time data of the last 10 bars GBPUSD H1 (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 7 0 0 1 197 [1] 2023 7 17 8 0 0 1 197 [2] 2023 7 17 9 0 0 1 197 [3] 2023 7 17 10 0 0 1 197 [4] 2023 7 17 11 0 0 1 197 [5] 2023 7 17 12 0 0 1 197 [6] 2023 7 17 13 0 0 1 197 [7] 2023 7 17 14 0 0 1 197 [8] 2023 7 17 15 0 0 1 197 [9] 2023 7 17 16 0 0 1 197 */ }
因此,使用上述函数打印日志中datetime数组的脚本将如下所示:
void OnStart() { //--- Declare a time array datetime array[]; //--- Copy the time of the last 10 bars to the array ResetLastError(); if(CopyTime(Symbol(),Period(),0,10,array)<0) { PrintFormat("CopyTime() failed. Error %s",(string)GetLastError()); return; } //--- Display the header and the time data array of the last 10 bars using the standard ArrayPrint() PrintFormat("Time data of the last 10 bars %s %s (ArrayPrint):",Symbol(),StringSubstr(EnumToString(Period()),7)); MqlDateTimePrint(array); /* Sample output: Time data of the last 10 bars GBPUSD H1 (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 7 0 0 1 197 [1] 2023 7 17 8 0 0 1 197 [2] 2023 7 17 9 0 0 1 197 [3] 2023 7 17 10 0 0 1 197 [4] 2023 7 17 11 0 0 1 197 [5] 2023 7 17 12 0 0 1 197 [6] 2023 7 17 13 0 0 1 197 [7] 2023 7 17 14 0 0 1 197 [8] 2023 7 17 15 0 0 1 197 [9] 2023 7 17 16 0 0 1 197 */ }
用于处理MqlDateTime结构数据的函数。
上面测试的一切都是方便、实用和简洁的。但有时需要更完整的信息,最好是在同样简洁的陈述中。或者,相反,我们可能需要更详细的描述,减少数据呈现的简洁和枯燥。例如,仅一天的数字就可能令人困惑。但如果写的是“星期四”,那么我们马上就明白我们说的是星期四。一个月的数字也是如此——有时看到“07(七月)”比回忆哪个月是第七个要好。。。当然,这可能有些夸张,但这些小的改进仍然增加了便利性。当分析程序日志中的大量条目时,这些小便利加起来会带来非常明显的时间增益。
为了增加这些便利性,我们必须编写您自己的函数,以MqlDateTime格式返回日期描述。
该函数将:
- 以短格式显示数据(星期几、月、日、年、时间);
- 在表格视图中显示数据(数据头值);
在我们开始创建返回结构字段描述的函数之前,我们将创建返回周、日和月名称的辅助函数。
辅助函数
要获得一星期中某一天的名称,让我们编写一个简单的函数,根据以数字格式存储星期天的结构字段中的值返回星期天的文本:
//+------------------------------------------------------------------+ //| Return the name of a week day | //+------------------------------------------------------------------+ string DayWeek(MqlDateTime &date_time) { //--- Define a week day name string dw=EnumToString((ENUM_DAY_OF_WEEK)date_time.day_of_week); //--- Convert all obtained symbols to lower case and replace the first letter from small to capital if(dw.Lower()) dw.SetChar(0,ushort(dw.GetChar(0)-0x20)); //--- Return a resulting string return dw; /* Sample output: Wednesday */ }
由于MQL5具有列表和星期日名称,因此在这里我们使用枚举常量的字符串表示。为了确保文本正确显示,我们将行中的所有字符转换为小写,单词的第一个字母除外。
要获得月份的名称,让我们编写一个简单的函数,根据以数字格式存储月份的结构字段中的值返回月份的文本:
//+------------------------------------------------------------------+ //| Return a month name | //+------------------------------------------------------------------+ string Month(MqlDateTime &date_time) { //--- Define a month name switch(date_time.mon) { case 1 : return "January"; case 2 : return "February"; case 3 : return "March"; case 4 : return "April"; case 5 : return "May"; case 6 : return "June"; case 7 : return "July"; case 8 : return "August"; case 9 : return "September"; case 10 : return "October"; case 11 : return "November"; case 12 : return "December"; default : return "Undefined"; } /* Sample output: July */ }
MQL5没有用于选择月份的枚举,因此在这里我们必须使用switch运算符来选择并返回月份名称的文本,具体取决于写入结构字段中的数字值。
这些函数对我们显示周、日和月的描述非常有用。此外,它们可能在未来对我们的后续项目有用。
返回MqlDateTime结构字段描述的函数将采用文章“StringFormat()回顾和现成的例子”中采用的格式。函数返回的每一行都将有一个标题和数据。标题可以从左边缘缩进,并可以为返回记录的表格视图指定宽度。我们将把缩进值和宽度值作为参数传递给函数。这些选项的默认值为零,这意味着没有填充,宽度等于标题文本的长度+1。
MqlDateTime结构中的年份:
//+------------------------------------------------------------------+ //| Return the year as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeYear(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Year:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.year); /* Sample output: Year: 2023 */ }
MqlDateTime结构中的月份:
//+------------------------------------------------------------------+ //| Return the month as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeMonth(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Month:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get a month name string mn=Month(date_time); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu (%s)",indent,"",w,header,date_time.mon,mn); /* Sample output: Month: 07 (July) */ }
MqlDateTime结构中的日期:
//+------------------------------------------------------------------+ //| Return the day as a string from the MqlDateTime structure | //+------------------------------------------------------------------+ string MqlDateTimeDay(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Day:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.day); /* Sample output: Day: 19 */ }
MqlDateTime结构中的小时数:
//+------------------------------------------------------------------+ //| Return hours as a string from the MqlDateTime structure | //+------------------------------------------------------------------+ string MqlDateTimeHour(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Hour:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.hour); /* Sample output: Hour: 08 */ }
MqlDateTime结构中的分钟数:
//+------------------------------------------------------------------+ //| Return minutes as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeMin(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Minutes:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.min); /* Sample output: Minutes: 41 */ }
MqlDateTime结构中的秒数:
//+------------------------------------------------------------------+ //| Return seconds as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeSec(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Seconds:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.sec); /* Sample output: Seconds: 23 */ }
MqlDateTime结构中的星期几:
//+------------------------------------------------------------------+ //| Return a week day as a string from the MqlDateTime structure | //+------------------------------------------------------------------+ string MqlDateTimeDayWeek(MqlDateTime &date_time,const uint header_width=0,const uint indent=0,bool descr=true) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Day of week:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get a week day name string dw=DayWeek(date_time); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s (%-lu)",indent,"",w,header,dw,date_time.day_of_week); /* Sample output: Day of week: Wednesday (3) */ }
MqlDateTime结构中一年中的天数:
//+------------------------------------------------------------------+ //|Return a number of a day in a year from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeDayYear(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Day of year:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.day_of_year); /* Sample output: Day of year: 199 */ }
用法示例:
要从MqlDateTime结构中显示日期时间的短记录,我们将编写一个函数,以“DW,Month DD,YYYY,HH:MM:SS”格式返回日期:
//+------------------------------------------------------------------+ //| Return the date as a string from the MqlDateTime structure | //| in the DW, Month DD, YYYY, HH:MM:SS format | //+------------------------------------------------------------------+ string DateTime(MqlDateTime &date_time) { //--- Get the month and the first three characters of a week day string mn=Month(date_time); string dw=StringSubstr(DayWeek(date_time),0,3); //--- Return a string in the DW, Month DD, YYYY, HH:MM:SS format return StringFormat("%s, %s %02lu, %lu, %02lu:%02lu:%02lu",dw,mn,date_time.day,date_time.year,date_time.hour,date_time.min,date_time.sec); /* Sample output: Wed, July 19, 2023, 08:41:23 */ }
这是除一年中的日期之外的所有结构数据的一行摘要。该函数很方便,例如,用于在日志中显示一定数量的柱形:
void OnStart() { datetime array[]; MqlDateTime adt[]; if(CopyTime(Symbol(),PERIOD_CURRENT,0,10,array)==10) { int total=(int)array.Size(); if(ArrayResize(adt,total)==total) { for(int i=0;i<total;i++) { ResetLastError(); if(!TimeToStruct(array[i],adt[i])) Print("TimeToStruct failed. Error: ",GetLastError()); PrintFormat("%s %s [%02u] %s",Symbol(),StringSubstr(EnumToString(Period()),7),i,DateTime(adt[i])); } } } /* Sample output: GBPUSD H1 [00] Wed, July 19, 2023, 02:00:00 GBPUSD H1 [01] Wed, July 19, 2023, 03:00:00 GBPUSD H1 [02] Wed, July 19, 2023, 04:00:00 GBPUSD H1 [03] Wed, July 19, 2023, 05:00:00 GBPUSD H1 [04] Wed, July 19, 2023, 06:00:00 GBPUSD H1 [05] Wed, July 19, 2023, 07:00:00 GBPUSD H1 [06] Wed, July 19, 2023, 08:00:00 GBPUSD H1 [07] Wed, July 19, 2023, 09:00:00 GBPUSD H1 [08] Wed, July 19, 2023, 10:00:00 GBPUSD H1 [09] Wed, July 19, 2023, 11:00:00 */ }
让我们实现以下函数,以短格式和表格格式记录结构的所有字段:
//+------------------------------------------------------------------+ //| Logs descriptions of all fields of the MqlDateTime structure | //+------------------------------------------------------------------+ void MqlDateTimePrint(MqlDateTime &date_time,const bool short_entry=true,const uint header_width=0,const uint indent=0) { //--- If it is a short entry, log the date and time in the DW, Month DD, YYYY, HH:MM:SS format if(short_entry) Print(DateTime(date_time)); /* Sample output: Wed, July 19, 2023, 08:41:23 */ //--- Otherwise else { //--- create a string describing all the data of the structure with indents and a given width of the header field string res=StringFormat("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", MqlDateTimeYear(date_time,header_width,indent), MqlDateTimeMonth(date_time,header_width,indent), MqlDateTimeDay(date_time,header_width,indent), MqlDateTimeHour(date_time,header_width,indent), MqlDateTimeMin(date_time,header_width,indent), MqlDateTimeSec(date_time,header_width,indent), MqlDateTimeDayWeek(date_time,header_width,indent), MqlDateTimeDayYear(date_time,header_width,indent) ); //--- Display the obtained string in the journal Print(res); } /* Sample output: Year: 2023 Month: 07 (July) Day: 19 Hour: 09 Minutes: 32 Seconds: 25 Day of week: Wednesday (3) Day of year: 199 */ }
带有处理函数示例的脚本。首先,在日志中显示一个简短的条目,然后显示表格形式,字段标题缩进,字段宽度分别为2个和14个字符:
void OnStart() { MqlDateTime dt; TimeCurrent(dt); MqlDateTimePrint(dt,true); MqlDateTimePrint(dt,false,14,2); /* Sample output: Wed, July 19, 2023, 09:33:56 Year: 2023 Month: 07 (July) Day: 19 Hour: 09 Minutes: 33 Seconds: 56 Day of week: Wednesday (3) Day of year: 199 */ }
所有用于处理MqlDateTime结构字段的函数和上面提供的辅助函数都可以在程序中“按原样”使用,也可以根据您的愿景和需求进行修改。
MqlTick结构
用于按交易品种存储最后价格的结构。该结构旨在及时获得最需要的当前价格数据。
struct MqlTick { datetime time; // Last price update time double bid; // Current Bid price double ask; // Current Ask price double last; // Current price of the last trade (Last) ulong volume; // Volume for the current Last price long time_msc; // Last price update time in milliseconds uint flags; // Tick flags double volume_real; // Volume for the current Last price };
MqlTick类型的变量允许在SymbolInfoTick()函数的一次调用中获得Ask、Bid、Last和Volume值,以及以毫秒为单位的时间。
无论与上一个分时相比是否有变化,都会填写每个分时的参数。因此,可以找出过去任何时刻的正确价格,而无需在分时历史中搜索以前的值。例如,即使在分时到达期间只有卖家出价发生变化,该结构仍然包含其他参数,包括以前的要价、成交量等。
分析分时标志以找出哪些数据已更改:
- TICK_FLAG_BID — 分时中卖家报价发生改变
- TICK_FLAG_ASK — 分时中买家报价发生改变
- TICK_FLAG_LAST — 分时中最后交易价格发生改变
- TICK_FLAG_VOLUME — 分时中交易量发生改变
- TICK_FLAG_BUY — 分时是一个买入交易的结果
- TICK_FLAG_SELL — 分时是一个卖出交易的结果
MqlTick打印方法
ArrayPrint()函数适用于以与MqlDateTime相同的方式向日志显示结构:
void OnStart() { //--- Declare a variable with the MqlTick type MqlTick tick; //--- If failed to get the last tick, display the error message and exit the method if(!SymbolInfoTick(Symbol(),tick)) { Print("SymbolInfoTick failed, error: ",(string)GetLastError()); return; } //--- Display the tick using standard ArrayPrint() //--- To do this, declare an array of dimension 1 with type MqlTick, //--- enter the value of the 'tick' variable into it and print it MqlTick array[1]; array[0]=tick; Print("Last tick (ArrayPrint):"); ArrayPrint(array); /* Sample output: Last tick (ArrayPrint): [time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real] [0] 2023.07.19 17:02:49 1.28992 1.28996 0.0000 0 1689786169589 6 0.00000 */ }
逻辑上,要打印数组,可以在数组中填充一系列分时信息:
void OnStart() { //--- Declare a dynamic array of the MqlTick type MqlTick array[]; //--- If failed to get the last 10 ticks, display the error message and exit the method if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10) { Print("CopyTicks failed, error: ",(string)GetLastError()); return; } Print("Last 10 tick (ArrayPrint):"); ArrayPrint(array); /* Sample output: Last 10 tick (ArrayPrint): [time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real] [0] 2023.07.19 17:24:38 1.28804 1.28808 0.0000 0 1689787478461 6 0.00000 [1] 2023.07.19 17:24:38 1.28806 1.28810 0.0000 0 1689787478602 6 0.00000 [2] 2023.07.19 17:24:38 1.28804 1.28808 0.0000 0 1689787478932 6 0.00000 [3] 2023.07.19 17:24:39 1.28806 1.28810 0.0000 0 1689787479210 6 0.00000 [4] 2023.07.19 17:24:39 1.28807 1.28811 0.0000 0 1689787479765 6 0.00000 [5] 2023.07.19 17:24:39 1.28808 1.28812 0.0000 0 1689787479801 6 0.00000 [6] 2023.07.19 17:24:40 1.28809 1.28813 0.0000 0 1689787480240 6 0.00000 [7] 2023.07.19 17:24:40 1.28807 1.28811 0.0000 0 1689787480288 6 0.00000 [8] 2023.07.19 17:24:40 1.28809 1.28813 0.0000 0 1689787480369 6 0.00000 [9] 2023.07.19 17:24:40 1.28810 1.28814 0.0000 0 1689787480399 6 0.00000 */ }
同样,我们需要更有意义的方式来展示数值。例如,对于以毫秒为单位的时间和标志,以通常的方式查看它们可能更方便——时间格式的时间和枚举常量格式的标志。
用于处理MqlTick结构数据的函数。
让我们实现使用MqlTick结构数据的函数。就像所有已经创建的使用MqlDateTime结构的函数一样,使用MqlTick的函数将返回一个格式化的字符串。行格式将包括文本的左边距和标题字段的宽度。默认情况下,填充和页边宽度值将为零,这意味着没有填充,并且页边宽度等于页眉文本的长度+1。
辅助函数
我们已经创建了这个函数,以字符串形式返回以毫秒为单位的时间。在这里,它用于返回以毫秒为单位的分时时间。让我们应用它:
//+------------------------------------------------------------------+ //| Accept a date in ms, return time in Date Time.Msc format | //+------------------------------------------------------------------+ string TimeMSC(const long time_msc) { return StringFormat("%s.%.3hu",string((datetime)time_msc / 1000),time_msc % 1000); /* Sample output: 2023.07.13 09:31:58.177 */ }
MqlTick结构中的时间:
//+------------------------------------------------------------------+ //| Return the time of the last price update as a string | //+------------------------------------------------------------------+ string MqlTickTime(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Time:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)tick.time); /* Sample output: Time: 2023.07.19 20:58:00 */ }
MqlTick结构中的卖家报价:
//+------------------------------------------------------------------+ //| Return the Bid price as a string | //+------------------------------------------------------------------+ string MqlTickBid(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Bid:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.bid); /* Sample output: Bid: 1.29237 */ }
MqlTick结构中的买家报价:
//+------------------------------------------------------------------+ //| Return the Ask price as a string | //+------------------------------------------------------------------+ string MqlTickAsk(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Ask:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.ask); /* Sample output: Ask: 1.29231 */ }
MqlTick结构中的最后交易价格:
//+------------------------------------------------------------------+ //| Return the Last price as a string | //+------------------------------------------------------------------+ string MqlTickLast(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Last:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.last); /* Sample output: Last: 0.00000 */ }
MqlTick结构中的最后价格交易量:
//+------------------------------------------------------------------+ //| Return the volume for the Last price as a string | //+------------------------------------------------------------------+ string MqlTickVolume(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-I64u",indent,"",w,header,tick.volume); /* Sample output: Volume: 0 */ }
MqlTick结构中的时间(以毫秒为单位):
//+------------------------------------------------------------------+ //| Return the time in milliseconds as a string | //+------------------------------------------------------------------+ string MqlTickTimeMSC(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Time msc:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,TimeMSC(tick.time_msc)); /* Sample output: Time msc: 2023.07.19 21:21:09.732 */ }
MqlTick结构中的分时标志:
//+------------------------------------------------------------------+ //| Return tick flags as a string | //+------------------------------------------------------------------+ string MqlTickFlags(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Flags:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Define a variable to describe tick flags string flags=""; //--- Parse tick flags into components if((tick.flags & TICK_FLAG_BID)==TICK_FLAG_BID) flags+=(flags.Length()>0 ? "|" : "")+"BID"; if((tick.flags & TICK_FLAG_ASK)==TICK_FLAG_ASK) flags+=(flags.Length()>0 ? "|" : "")+"ASK"; if((tick.flags & TICK_FLAG_LAST)==TICK_FLAG_LAST) flags+=(flags.Length()>0 ? "|" : "")+"LAST"; if((tick.flags & TICK_FLAG_VOLUME)==TICK_FLAG_VOLUME) flags+=(flags.Length()>0 ? "|" : "")+"VOLUME"; if((tick.flags & TICK_FLAG_BUY)==TICK_FLAG_BUY) flags+=(flags.Length()>0 ? "|" : "")+"BUY"; if((tick.flags & TICK_FLAG_SELL)==TICK_FLAG_SELL) flags+=(flags.Length()>0 ? "|" : "")+"SELL"; //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,flags); /* Sample output: Flags: BID|ASK */ }
MqlTick结构中精度提高的最后价格交易量:
//+------------------------------------------------------------------+ //| Return the volume for the Last price as a string | //+------------------------------------------------------------------+ string MqlTickVolumeReal(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume Real:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.2f",indent,"",w,header,tick.volume_real); /* Sample output: Volume Real: 0.00 */ }
使用示例
编写将分时数据显示到日志中的函数。将交易品种的名称传递给函数,以了解日志中显示的价格值的准确性。因为 Volume 和 Volume Real 字段包含了最后价格交易量,如果 Last 字段为零(没有交易),则没有必要显示交易量 - 它们也是零。为了能够指定和打印从记号数组中提取的记号的索引,我们将在函数的输入参数中传递该索引。默认情况下,其值为-1,在该值下不会打印索引。
//+------------------------------------------------------------------+ //| Logs descriptions of all fields of the MqlTick structure | //| If Last==0, Last, Volume and Volume Real fields are not displayed| //+------------------------------------------------------------------+ void MqlTickPrint(const string symbol,const MqlTick &tick,const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE) { //--- Declare the variable for storing the result string res=""; //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); string num=(index==WRONG_VALUE ? "" : StringFormat("[%ld] ",index)); //--- If it is a short entry, log the tick data in the Symbol TimeMSC, Bid, Ask, Last, Vol/VolR, Flags format if(short_entry) { //--- If Last is not zero, display Last, Volume and Volume Real, otherwise they are all zero and there is no point in displaying them string last=(tick.last!=0 ? StringFormat(", Last: %.*f, Vol: %I64u/%.2f",dg,tick.last,tick.volume,tick.volume_real) : ""); res=StringFormat("%sTick %s Time: %s, Bid: %.*f, Ask: %.*f%s, %s",num,symbol,TimeMSC(tick.time_msc),dg,tick.bid,dg,tick.ask,last,MqlTickFlags(tick)); Print(res); } /* Sample output (if Last is not zero): Tick GBPUSD Time: 2023.07.20 13:57:31.376, Bid: 1.28947, Ask: 1.28951, Last: 1.28947, Vol: 33/33.45, Flags: BID|ASK Sample output (if Last is zero): Tick GBPUSD Time: 2023.07.20 13:59:33.274, Bid: 1.28956, Ask: 1.28960, Flags: BID|ASK */ //--- Otherwise else { //--- create a string describing all the data of the structure with indents and a given width of the header field res=StringFormat("%s\n%s\n%s%s%s\n%s\n%s%s", MqlTickTime(tick,header_width,indent), MqlTickBid(symbol,tick,header_width,indent), MqlTickAsk(symbol,tick,header_width,indent), (tick.last!=0 ? "\n"+MqlTickLast(symbol,tick,header_width,indent) : ""), (tick.last!=0 ? "\n"+MqlTickVolume(tick,header_width,indent) : ""), MqlTickTimeMSC(tick,header_width,indent), MqlTickFlags(tick,header_width,indent), (tick.last!=0 ? "\n"+MqlTickVolumeReal(tick,header_width,indent) : "") ); //--- Display the obtained string in the journal Print(res); } /* Sample output (if Last is not zero): Time: 2023.07.20 14:42:33 Bid: 1.28958 Ask: 1.28962 Last: 1.28947 Volume: 33 Time msc: 2023.07.20 14:42:33.401 Flags: BID|ASK Volume Real: 33.45 Sample output (if Last is zero): Time: 2023.07.20 14:42:33 Bid: 1.28958 Ask: 1.28962 Time msc: 2023.07.20 14:42:33.401 Flags: BID|ASK */ }
一个脚本,以短格式将最后10个分时打印到日志中,指示数组中的分时索引:
void OnStart() { //--- Declare a dynamic array of the MqlTick type MqlTick array[]; //--- If failed to get the last 10 ticks, display the error message and exit the method if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10) { Print("CopyTicks failed, error: ",(string)GetLastError()); return; } Print("Last 10 tick (MqlTickPrint):"); for(int i=0;i<(int)array.Size();i++) MqlTickPrint(Symbol(),array[i],true,0,0,i); /* Sample output: Last 10 tick (MqlTickPrint): [0] Tick GBPUSD Time: 2023.07.20 15:36:29.941, Bid: 1.28686, Ask: 1.28690, Flags: BID|ASK [1] Tick GBPUSD Time: 2023.07.20 15:36:29.970, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK [2] Tick GBPUSD Time: 2023.07.20 15:36:30.061, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK [3] Tick GBPUSD Time: 2023.07.20 15:36:30.212, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK [4] Tick GBPUSD Time: 2023.07.20 15:36:30.259, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK [5] Tick GBPUSD Time: 2023.07.20 15:36:30.467, Bid: 1.28682, Ask: 1.28686, Flags: BID|ASK [6] Tick GBPUSD Time: 2023.07.20 15:36:30.522, Bid: 1.28681, Ask: 1.28685, Flags: BID|ASK [7] Tick GBPUSD Time: 2023.07.20 15:36:30.572, Bid: 1.28673, Ask: 1.28677, Flags: BID|ASK [8] Tick GBPUSD Time: 2023.07.20 15:36:30.574, Bid: 1.28672, Ask: 1.28676, Flags: BID|ASK [9] Tick GBPUSD Time: 2023.07.20 15:36:30.669, Bid: 1.28674, Ask: 1.28678, Flags: BID|ASK */ }
一个脚本,用于打印日志中数组的最后4个分时,左缩进为2个字符,标题字段宽度为14个字符:
void OnStart() { //--- Declare a dynamic array of the MqlTick type MqlTick array[]; //--- If the last 4 ticks are not received in the array, display an error message and leave if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,4)!=4) { Print("CopyTicks failed, error: ",(string)GetLastError()); return; } Print("Last 4 tick (MqlTickPrint):"); for(int i=0;i<(int)array.Size();i++) { PrintFormat("Tick[%lu] %s:",i,Symbol()); MqlTickPrint(Symbol(),array[i],false,14,2); } /* Sample output: Last 4 tick (MqlTickPrint): Tick[0] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28776 Ask: 1.28780 Time msc: 2023.07.20 17:04:51.203 Flags: BID|ASK Tick[1] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28772 Ask: 1.28776 Time msc: 2023.07.20 17:04:51.331 Flags: BID|ASK Tick[2] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28771 Ask: 1.28775 Time msc: 2023.07.20 17:04:51.378 Flags: BID|ASK Tick[3] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28772 Ask: 1.28776 Time msc: 2023.07.20 17:04:51.680 Flags: BID|ASK */ }
MqlRates 结构
struct MqlRates { datetime time; // period start time double open; // open price double high; // high price for the period double low; // low price for the period double close; // close price long tick_volume; // tick volume int spread; // spread long real_volume; // exchange volume };
MqlRates 的打印方法
MqlRates——用于在历史数据的单柱上存储数据的结构。可以使用CopyRates()函数填充该结构。要获取当前柱的数据,可以使用函数调用的第一种形式,指示索引0和复制的条形图数量等于1。在任何情况下,此函数都会使用MqlRates类型填充数组。这导致了这样一个结论,即使用ArrayPrint()将此数组打印到日志中很方便:
void OnStart() { //--- MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,1,array)!=1) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } Print("Current bar ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):"); ArrayPrint(array); /* Sample output: Current bar GBPUSD H1 (ArrayPrint): [time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume] [0] 2023.07.21 04:00:00 1.28763 1.28765 1.28663 1.28748 2083 7 0 */ }
因此,要复制最后十条,只需指定要复制的数据数等于10:
void OnStart() { //--- MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } Print("Data of the last 10 bars: ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):"); ArrayPrint(array); /* Sample output: Data of the last 10 bars: GBPUSD H1 (ArrayPrint): [time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume] [0] 2023.07.20 20:00:00 1.28530 1.28676 1.28512 1.28641 2699 4 0 [1] 2023.07.20 21:00:00 1.28641 1.28652 1.28557 1.28587 1726 3 0 [2] 2023.07.20 22:00:00 1.28587 1.28681 1.28572 1.28648 2432 3 0 [3] 2023.07.20 23:00:00 1.28648 1.28683 1.28632 1.28665 768 4 0 [4] 2023.07.21 00:00:00 1.28663 1.28685 1.28613 1.28682 396 1 0 [5] 2023.07.21 01:00:00 1.28684 1.28732 1.28680 1.28714 543 8 0 [6] 2023.07.21 02:00:00 1.28714 1.28740 1.28690 1.28721 814 2 0 [7] 2023.07.21 03:00:00 1.28721 1.28774 1.28685 1.28761 2058 5 0 [8] 2023.07.21 04:00:00 1.28763 1.28791 1.28663 1.28774 3480 7 0 [9] 2023.07.21 05:00:00 1.28774 1.28776 1.28769 1.28774 18 7 0 */ }
这里的一切都是一样的——日志上有一长串数据。如果表格标题隐藏在日记窗口的上边缘后面,则不清楚所有显示的数字指的是什么。
让我们编写自己的函数来返回结构字段的描述,并将这些数据打印在终端日志中。
用于处理MqlRates结构数据的函数。
我们的自定义函数将返回结构中每个字段的文本描述。每个描述都有一个标题和实际数据。对于函数返回的字符串,我们可以设置从左边缘开始的缩进和头字段的宽度。
Time:
时间 — 时段开始时间. 换句话说,交易品种和图表周期上的柱形开始时间,从中请求写入结构的数据。
//+------------------------------------------------------------------+ //| Return the bar opening time as a string | //+------------------------------------------------------------------+ string MqlRatesTime(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Time:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)rates.time); /* Sample output: Time: 2023.07.21 06:00:00 */ }
Open:
交易品种和图表周期上的柱形开盘价,从中请求写入结构的数据。
//+------------------------------------------------------------------+ //| Return the bar open price as a string | //+------------------------------------------------------------------+ string MqlRatesOpen(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Open:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.open); /* Sample output: Open: 1.28812 */ }
High:
高价-交易品种和图表周期上柱形的最高价格,从中请求写入结构的数据。
//+------------------------------------------------------------------+ //| Return the High bar price as a string | //+------------------------------------------------------------------+ string MqlRatesHigh(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="High:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.high); /* Sample output: High: 1.28859 */ }
Low:
低价-交易品种和图表周期上柱形的最低价格,从中请求写入结构的数据。
//+------------------------------------------------------------------+ //| Return the bar Low price as a string | //+------------------------------------------------------------------+ string MqlRatesLow(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Low:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.low); /* Sample output: Low: 1.28757 */ }
Close:
收盘价—交易品种和图表周期上柱形的收盘价,从中请求写入结构的数据。
对于当前柱形,收盘价等于当前出价或最后价格,具体取决于图表所基于的价格。
//+------------------------------------------------------------------+ //| Return the bar close price as a string | //+------------------------------------------------------------------+ string MqlRatesClose(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Close:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.close); /* Sample output: Close: 1.28770 */ }
TickVolume:
柱形的分时交易量。
//+------------------------------------------------------------------+ //| Return the tick volume of a bar as a string | //+------------------------------------------------------------------+ string MqlRatesTickVolume(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Tick Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.tick_volume); /* Sample output: Tick Volume: 963 */ }
Spread:
柱形的点差。
//+------------------------------------------------------------------+ //| Return the bar spread as a string | //+------------------------------------------------------------------+ string MqlRatesSpread(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Spread:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-ld",indent,"",w,header,rates.spread); /* Sample output: Spread: 4 */ }
RealVolume:
柱形的交易量。
//+------------------------------------------------------------------+ //| Return the bar exchange volume as a string | //+------------------------------------------------------------------+ string MqlRatesRealVolume(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Real Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.real_volume); /* Sample output: Real Volume: 0 */ }
使用示例
让我们创建以下脚本来打印日志中最后10条的数据:
void OnStart() { //--- Copy the last 10 data bars to the MqlRates array MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } //--- Set the indexing of the array like a timeseries ArraySetAsSeries(array,true); //--- Print short entries in the journal in a loop through the array with the received bar data for(int i=0;i<(int)array.Size();i++) MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],true,0,0,i); /* Sample output: GBPUSD H1[0]: 2023.07.21 14:00:00, O: 1.28451, H: 1.28541, L: 1.28451, C: 1.28501, S: 4, V: 821, RV: 0 GBPUSD H1[1]: 2023.07.21 13:00:00, O: 1.28678, H: 1.28685, L: 1.28418, C: 1.28452, S: 1, V: 3602, RV: 0 GBPUSD H1[2]: 2023.07.21 12:00:00, O: 1.28581, H: 1.28696, L: 1.28557, C: 1.28678, S: 1, V: 4807, RV: 0 GBPUSD H1[3]: 2023.07.21 11:00:00, O: 1.28695, H: 1.28745, L: 1.28401, C: 1.28581, S: 1, V: 7440, RV: 0 GBPUSD H1[4]: 2023.07.21 10:00:00, O: 1.28933, H: 1.28960, L: 1.28651, C: 1.28696, S: 1, V: 8883, RV: 0 GBPUSD H1[5]: 2023.07.21 09:00:00, O: 1.28788, H: 1.29040, L: 1.28753, C: 1.28934, S: 1, V: 5474, RV: 0 GBPUSD H1[6]: 2023.07.21 08:00:00, O: 1.28794, H: 1.28848, L: 1.28713, C: 1.28787, S: 1, V: 1885, RV: 0 GBPUSD H1[7]: 2023.07.21 07:00:00, O: 1.28762, H: 1.28808, L: 1.28744, C: 1.28794, S: 4, V: 878, RV: 0 GBPUSD H1[8]: 2023.07.21 06:00:00, O: 1.28812, H: 1.28859, L: 1.28743, C: 1.28760, S: 3, V: 1112, RV: 0 GBPUSD H1[9]: 2023.07.21 05:00:00, O: 1.28774, H: 1.28820, L: 1.28747, C: 1.28812, S: 7, V: 1671, RV: 0 */ }
将所需数量的数据复制到数组中后,将其作为时间序列进行索引,以便数据以与终端中的图表柱形相同的方式显示。索引为零的数据对应于当前柱形。
此脚本将以表格形式打印日志中的最后4个柱形,标题字段向左缩进两个字符,标题字段宽度为14个字符:
void OnStart() { //--- Copy the last 4 data bars to the MqlRates array MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,4,array)!=4) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } //--- Set the indexing of the array like a timeseries ArraySetAsSeries(array,true); //--- Print short entries in the journal in a loop through the array with the received bar data for(int i=0;i<(int)array.Size();i++) MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],false,14,2,i); /* Sample output: GBPUSD H1[0]: Time: 2023.07.21 14:00:00 Open: 1.28451 High: 1.28541 Low: 1.28451 Close: 1.28491 Tick Volume: 1098 Spread: 4 Real Volume: 0 GBPUSD H1[1]: Time: 2023.07.21 13:00:00 Open: 1.28678 High: 1.28685 Low: 1.28418 Close: 1.28452 Tick Volume: 3602 Spread: 1 Real Volume: 0 GBPUSD H1[2]: Time: 2023.07.21 12:00:00 Open: 1.28581 High: 1.28696 Low: 1.28557 Close: 1.28678 Tick Volume: 4807 Spread: 1 Real Volume: 0 GBPUSD H1[3]: Time: 2023.07.21 11:00:00 Open: 1.28695 High: 1.28745 Low: 1.28401 Close: 1.28581 Tick Volume: 7440 Spread: 1 Real Volume: 0 */ }
MqlBookInfo结构
提供市场深度数据的结构。
struct MqlBookInfo { ENUM_BOOK_TYPE type; // order type from ENUM_BOOK_TYPE enumeration double price; // price long volume; // volume double volume_real; // volume with increased accuracy };
要使用该结构,只需声明一个这种类型的变量就足够了。市场深度并非适用于所有金融工具。在收到市场深度数据之前,我们应该使用MarketBookAdd()订阅它。完成后,我们需要取消订阅市场深度:MarketBookRelease()。EA程序应该包含OnBookEvent()void型函数来处理传入通知。
MqlBookInfo打印方法
每次接收市场深度都涉及到接收其中的订单列表。这是一个数据数组。因此,我们可以使用ArrayPrint()打印一个市场深度的快照:
void OnStart() { //--- Declare an array to store a snapshot of the market depth MqlBookInfo array[]; //--- If unable to open the market depth and subscribe to its events, inform of that and leave if(!MarketBookAdd(Symbol())) { Print("MarketBookAdd failed, error: ",(string)GetLastError()); return; } //--- If unable to obtain the market depth entries, inform of that and leave if(!MarketBookGet(Symbol(),array)) { Print("MarketBookGet failed, error: ",(string)GetLastError()); return; } //--- Print the header in the journal and the market depth snapshot from the array below Print("MarketBookInfo by ",Symbol(),":"); ArrayPrint(array); //--- If unable to unsubscribe from the market depth, send an error message to the journal if(!MarketBookRelease(Symbol())) Print("MarketBookRelease failed, error: ",(string)GetLastError()); /* Sample output: MarketBookInfo by GBPUSD: [type] [price] [volume] [volume_real] [0] 1 1.28280 100 100.00000 [1] 1 1.28276 50 50.00000 [2] 1 1.28275 20 20.00000 [3] 1 1.28273 10 10.00000 [4] 2 1.28268 10 10.00000 [5] 2 1.28266 20 20.00000 [6] 2 1.28265 50 50.00000 [7] 2 1.28260 100 100.00000 */ }
正如您所看到的,这里的请求类型是用数值表示的,这不便于感知。让我们为上面讨论的其他结构编写函数,以已经接受的样式返回市场领域深度的描述。
用于处理MqlBookInfo结构数据的函数。
返回MqlBookInfo结构的字段的字符串表示的所有函数都将与上面描述的用于描述相应结构的域的函数具有相同的样式。让我们探讨一下这些方法。
MqlBookInfo市场深度结构中的订单类型:
//+------------------------------------------------------------------+ //| Return the order type in the market depth as a string | //+------------------------------------------------------------------+ string MqlBookInfoType(const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Get the value of the order type ENUM_BOOK_TYPE book_type=book.type; //--- "Cut out" the type from the string obtained from enum string type=StringSubstr(EnumToString(book_type),10); //--- Convert all obtained symbols to lower case and replace the first letter from small to capital if(type.Lower()) type.SetChar(0,ushort(type.GetChar(0)-0x20)); //--- Replace all underscore characters with space in the resulting line StringReplace(type,"_"," "); //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Type:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,type); /* Sample output: Type: Sell */ }
MqlBookInfo市场深度结构中的订单价格:
//+------------------------------------------------------------------+ //| Return the order price in the market depth as a string | //+------------------------------------------------------------------+ string MqlBookInfoPrice(const string symbol,const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Price:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,book.price); /* Sample output: Price: 1.28498 */ }
MqlBookInfo市场深度结构中的订单交易量:
//+------------------------------------------------------------------+ //| Return the order volume in the market depth as a string | //+------------------------------------------------------------------+ string MqlBookInfoVolume(const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lld",indent,"",w,header,book.volume); /* Sample output: Volume: 100 */ }
具有更高精度的交易量:
//+------------------------------------------------------------------+ //| Return the order volume with increased accuracy as a string | //+------------------------------------------------------------------+ string MqlBookInfoVolumeReal(const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume Real:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.2f",indent,"",w,header,book.volume_real); /* Sample output: Volume Real: 100.00 */ }
使用示例:
现在,让我们编写一个函数,将MqlBookInfo结构中的所有数据打印到日志中。可以以两种模式打印:一行打印和表格打印:
//+------------------------------------------------------------------+ //| Logs a description of all fields of the MqlRates structure | //+------------------------------------------------------------------+ void MqlBookInfoPrint(const string symbol,const MqlBookInfo &book, const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE) { //--- Declare the variable for storing the result string res=""; //--- Get the number of decimal places and the string index value int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); string num=(index==WRONG_VALUE ? "" : StringFormat("[%02ld]",index)); //--- "Cut out" the type from the order type name string obtained from enum string type=StringSubstr(EnumToString(book.type),10); //--- Convert all obtained symbols to lower case and replace the first letter from small to capital if(type.Lower()) type.SetChar(0,ushort(type.GetChar(0)-0x20)); //--- Replace all underscore characters with space in the resulting line StringReplace(type,"_"," "); //--- If it is a short entry, log the market depth data in the [index] Type Price V VR format if(short_entry) { res=StringFormat("%-8s%-11s%- *.*f Volume%- 5lld Real%- 8.2f", num,type,dg+4,dg,book.price,book.volume,book.volume_real); Print(res); } /* Sample output: [00] Sell 1.28598 Volume 100 Real 100.00 */ //--- Otherwise else { //--- create a string describing all the data of the structure with indents and a given width of the header field res=StringFormat("Market Book by %s %s:\n%s\n%s\n%s\n%s",symbol,num, MqlBookInfoType(book,header_width,indent), MqlBookInfoPrice(symbol,book,header_width,indent), MqlBookInfoVolume(book,header_width,indent), MqlBookInfoVolumeReal(book,header_width,indent) ); //--- Display the obtained string in the journal Print(res); } /* Sample output BoolInfo by GBPUSD [00]: Type: Sell Price: 1.28588 Volume: 100 Volume Real: 100.00 */ }
这里的主要模式应该是在一行中输出到日记账,因为市场深度不是单个订单,并且我们在数组中收到这些订单的列表。因此,我们可以使用以下函数将此数组打印到日志中:
//+----------------------------------------------------------------------+ //| Display the market depth entries in the journal in the short format | //+----------------------------------------------------------------------+ void MqlBookInfoPrintShort(const string symbol,const MqlBookInfo &book_array[]) { PrintFormat("Market Book by %s:",symbol); for(int i=0;i<(int)book_array.Size();i++) MqlBookInfoPrint(symbol,book_array[i],true,0,0,i); }
该函数接收市场深度的订单数组,并在该数组的循环中,使用短输出将所有市场深度数据打印到日志中。
一个脚本,演示如何使用此函数,以及结果:
void OnStart() { //--- Declare an array to store a snapshot of the market depth MqlBookInfo array[]; //--- If unable to open the market depth and subscribe to its events, inform of that and leave if(!MarketBookAdd(Symbol())) { Print("MarketBookAdd failed, error: ",(string)GetLastError()); return; } //--- If unable to obtain the market depth entries, inform of that and leave if(!MarketBookGet(Symbol(),array)) { Print("MarketBookGet failed, error: ",(string)GetLastError()); return; } //--- Print in the journal a snapshot of the market depth from the array in the form of strings MqlBookInfoPrintShort(Symbol(),array); //--- If unable to unsubscribe from the market depth, send an error message to the journal if(!MarketBookRelease(Symbol())) Print("MarketBookRelease failed, error: ",(string)GetLastError()); /* Sample output: Market Book by GBPUSD: [00] Sell 1.28674 Volume 100 Real 100.00 [01] Sell 1.28668 Volume 50 Real 50.00 [02] Sell 1.28666 Volume 20 Real 20.00 [03] Sell 1.28664 Volume 10 Real 10.00 [04] Buy 1.28657 Volume 10 Real 10.00 [05] Buy 1.28654 Volume 20 Real 20.00 [06] Buy 1.28653 Volume 50 Real 50.00 [07] Buy 1.28646 Volume 100 Real 100.00 */ }
但有时我们可能需要以表格形式显示相同的数据。为此,我们可以使用以下函数:
//+------------------------------------------------------------------------+ //| Display the market depth entries in the journal in the tabular format | //+------------------------------------------------------------------------+ void MqlBookInfoPrintTable(const string symbol,const MqlBookInfo &book_array[],const uint header_width=0,const uint indent=0) { for(int i=0;i<(int)book_array.Size();i++) MqlBookInfoPrint(symbol,book_array[i],false,header_width,indent,i); }
一个脚本,演示如何使用此函数,以及结果:
void OnStart() { //--- Declare an array to store a snapshot of the market depth MqlBookInfo array[]; //--- If unable to open the market depth and subscribe to its events, inform of that and leave if(!MarketBookAdd(Symbol())) { Print("MarketBookAdd failed, error: ",(string)GetLastError()); return; } //--- If unable to obtain the market depth entries, inform of that and leave if(!MarketBookGet(Symbol(),array)) { Print("MarketBookGet failed, error: ",(string)GetLastError()); return; } //--- Print in the journal a snapshot of the market depth from the array in the form of strings MqlBookInfoPrintTable(Symbol(),array,14,2); //--- If unable to unsubscribe from the market depth, send an error message to the journal if(!MarketBookRelease(Symbol())) Print("MarketBookRelease failed, error: ",(string)GetLastError()); /* Sample output: Market Book by GBPUSD [00]: Type: Sell Price: 1.28627 Volume: 100 Volume Real: 100.00 Market Book by GBPUSD [01]: Type: Sell Price: 1.28620 Volume: 50 Volume Real: 50.00 Market Book by GBPUSD [02]: Type: Sell Price: 1.28618 Volume: 20 Volume Real: 20.00 Market Book by GBPUSD [03]: Type: Sell Price: 1.28615 Volume: 10 Volume Real: 10.00 Market Book by GBPUSD [04]: Type: Buy Price: 1.28610 Volume: 10 Volume Real: 10.00 Market Book by GBPUSD [05]: Type: Buy Price: 1.28606 Volume: 20 Volume Real: 20.00 Market Book by GBPUSD [06]: Type: Buy Price: 1.28605 Volume: 50 Volume Real: 50.00 Market Book by GBPUSD [07]: Type: Buy Price: 1.28599 Volume: 100 Volume Real: 100.00 */ }
结论
我们已经探讨了打印四种结构的字段:MqlDateTime、MqlTick、MqlRates和MqlBookInfo。创建的函数以“标题数据”格式返回每个结构的字段描述,作为一个字符串,可以打印或在另一个函数中使用。所有函数都是独立的,随时可以使用,并且可以在自定义程序中“按原样”使用。下一步是描述和展示交易结构。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/12900
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.



我建议完成该功能。
通过结构源返回打印函数的源。
我建议增加功能。
通过结构源返回打印函数的源。
能举个例子吗?我不明白。
能举个例子吗?我不明白。
我在这里 也做过类似的事情,但用的是输入法。
我不明白它的实用性。我相信有实用性,但我不明白
我不明白这有什么实际意义。
有人编写了任何结构,并希望实现打印功能。
然后他将结构的源代码输入到提议的功能中,在输出端他就得到了结构的打印函数源代码。