
让新闻交易轻松上手(第3部分):执行交易
概述
此前,我们创建了一个EA,用于在我们的新闻日历数据库中存储经济数据。我们还开发了许多类,为我们的EA能够良好地运行奠定了基础。在本文中,我们将扩展这些类,以最终实现基于经济数据来进行交易的目标。我们接下来的目标将是EA的盈利能力,这将在后续文章中讨论。对于本文,我们将在数据库中添加一个新的视图,以显示来自MQL5经济日历的所有独立事件,从而提供关于不同事件的信息。我们还将为EA添加新的输入参数,以便在交易时筛选经济数据,从而提供灵活性。如果您还没有准备好,可以查看 “新闻交易轻松上手” 系列的上一篇文章,我们在其中创建了一个风险管理类,用于管理交易风险,并提供更多有用信息。
您可以期待什么?
改进后的图形简洁、现代且响应迅速,适用于当前图表。下面的图片是这些图形在浅色模式下的示例。
信息块:每次EA在图表上时, 1、2、3、4、5、6、7、8 和 9这些信息块将自动显示。
信息块: 10、(11、12、13、14 和 15 为一组)以及16,这些信息块是可选的,并且会在每次新的1分钟K线图更新时刷新(为了在回测时提高性能)。
信息块
- 10:显示终端的日期和时间。当图表处于浅色模式且发生新闻事件时,时间文本将以红色显示。
- 11:显示当前/下一个新闻事件的日期和时间。当日期和时间与终端时间相同时,文本将以红色显示。
- 12:显示新闻事件的名称。文本颜色将根据事件的重要性而变化,例如,高重要性的事件以红色显示。
- 13:显示新闻事件的国家名称。文本颜色将根据事件的重要性以及图表的颜色模式(例如浅色模式)而变化。
- 14:显示新闻事件的货币名称。文本颜色会有所不同。
- 15:显示新闻事件的重要性。文本颜色会有所不同。
- 16:显示当前交易品种的价差以及评级。该评级基于两周内1分钟K线图价差数据计算得出,并根据数据将价差分为优秀、良好、正常、较差和糟糕五个等级,每个等级用不同颜色表示,同时会根据深色模式和浅色模式进行调整。
下图展示了深色模式的实现方式。
信息块
- 17:显示当天终端上所有已发生或即将发生的事件的时间。
显示(DISPLAY)输入参数
- 图表颜色模式(CHART COLOUR MODE):此选项用于在深色模式和浅色模式之间切换。
- 显示新闻信息(DISPLAY NEWS INFO):此选项用于决定是否在图表上显示信息块(11、12、13、14和15)。
- 显示事件对象(DISPLAY EVENT OBJ):此选项用于决定是否在图表上显示信息块17。
- 显示点差评级(DISPLAY SPREAD RATING):此选项用于决定是否在图表上显示信息块16。
- 显示日期(DISPLAY DATE):此选项用于决定是否在图表上显示信息块10。
夏令时(DST)计划输入参数
- 选择夏令时选项(SELECT DST OPTION):此选项允许用户/交易者选择他们自定义的夏令时计划,或者让EA自动选择推荐的夏令时计划,以便在策略测试器中回测时正确配置事件时间。
- 选择自定义夏令时(SELECT CUSTOM DST):此选项允许用户/交易者手动配置夏令时计划。
风险管理(RISK MANAGEMENT)输入参数
- 选择风险管理选项(SELECT RISK OPTION):此选项允许用户/交易者选择不同的风险管理配置文件,例如最小手数(MINIMUM LOTSIZE)、最大手数(MAXIMUM LOTSIZE)等。
- 风险下限(RISK FLOOR):此选项用于为所有风险管理配置文件设置最小风险值。例如,如果资金不足以开设1手的交易,但足以开设最小手数0.01手,则会使用0.01手开设交易,而不是因为资金不足而不开设任何交易。这只是一个安全网,以防风险管理配置文件未正确设置。
- 最大风险(MAX-RISK):此选项的作用是在账户中没有足够资金开设正常交易时,使用账户中的可用保证金百分比开设交易。此选项仅在风险下限(RISK FLOOR)设置为最大风险(MAX-RISK)时生效。
- 风险上限(RISK CEILING):此选项用于在账户资金足够开设特定交易品种的最大手数时,设置手数上限/限制。与最大手数(MAX LOTSIZE)不同,最大手数是指特定交易品种允许的最大手数,而最大手数MAX LOTSIZE(x2)则会根据资金限制开设两笔最大手数的交易。
- [账户余额 | 可用保证金]的百分比(PERCENTAGE OF [BALANCE | FREE-MARGIN]):此选项的作用是根据可用账户余额或可用保证金的一定百分比来承担风险。
- [账户余额 | 可用保证金]的金额(AMOUNT PER [BALANCE | FREE-MARGIN]):此选项的作用是根据账户余额或可用保证金的一定金额值来承担风险。例如,如果[账户余额 | 可用保证金]设置为1000,且每份金额(EACH AMOUNT)设置为10,则表示每有1000单位的账户余额或可用保证金货币价值,就为每笔交易承担10单位的货币价值风险。因此,如果账户余额/可用保证金为1000美元,则每笔交易承担10美元的风险。,
- [账户余额 | 可用保证金]的手数(LOTSIZE PER [BALANCE | FREE-MARGIN]):此选项的作用是根据账户余额或可用保证金的一定价值来承担特定手数的风险。例如,如果[账户余额 | 可用保证金]设置为1000,且每个手数(EACH LOTS [VOLUME])设置为0.1,则表示每有1000单位的账户余额或可用保证金货币价值,就为每笔交易承担0.1手的风险。因此,如果账户余额/可用保证金为1000美元,则每笔交易承担0.1手的风险。
- 自定义手数(CUSTOM LOTSIZE):此选项的作用是为每笔交易承担预设的手数风险。
- 最大风险的百分比(PERCENTAGE OF MAX-RISK):此选项的作用是根据账户可用保证金,承担特定交易品种最大风险量的一定百分比。例如,如果AUDUSD的最大风险量为100手(账户可用保证金为10000美元),则将最大风险的百分比(PERCENTAGE OF MAX-RISK)设置为25%,那么实际使用的手数将是100手的25%,即25手。
新闻设置(NEWS SETTINGS)输入参数
新闻设置包含多种输入选项,具体如下:
- 日历重要性(CALENDAR IMPORTANCE)
- 事件频率(EVENT FREQUENCY)
- 事件行业(EVENT SECTOR)
- 事件类型(EVENT TYPE)
- 事件货币(EVENT CURRENCY)
- 日历重要性(CALENDAR IMPORTANCE):此选项的作用是将新闻数据经过筛选确定具体的新闻重要性级别。
- 事件频率(EVENT FREQUENCY):此选项的作用是根据事件发生的频率筛选新闻数据。
- 事件部门(EVENT SECTOR):此选项的作用是根据部门筛选新闻数据。
- 事件类型(EVENT TYPE):此选项的作用是根据事件的类型筛选新闻数据。例如,EVENT通常用于演讲和会议,INDICATOR用于利率、就业数据等,而HOLIDAY用于新年和其他各种假期。
- 事件货币(EVENT CURRENCY):此选项的作用是根据选定的货币选项筛选新闻数据。交易品种货币(SYMBOL CURRENCIES)会考虑来自交易品种保证金货币、交易品种基础货币和交易品种利润货币的所有货币。
交易设置(TRADE SETTINGS)输入参数
- 止损设置 [0=无](STOPLOSS[0=NONE]):此选项的作用是为所有交易设置固定的止损价位。当止损设置为零时,所有交易将不设置止损价位。
- 获利设置 [0=无](TAKEPROFIT[0=NONE]):此选项的作用是为所有交易设置固定的获利价位。当获利设置为零时,所有交易将不设置获利价位。
- 提前入场秒数(PRE-ENTRY SEC):此选项允许用户/交易者配置在事件时间之前多少秒开始开启交易。例如,如果将PRE-ENTRY SEC设置为5,这意味着在事件发生前5秒是允许开启交易的时间段。举例说明:如果事件时间是15:00,那么在事件时间之前的5秒(即14:59:45-14:59:59)将允许开启交易。
- 交易日选择(TRADING DAY OF WEEK):此选项的作用是筛选一周中的任何工作日,例如周一、周二等。
现在,我们将深入研究使我们的EA能够正常运行的代码。
有关交易品种属性的类
从第2部分中所做的更改:
- 为点差评级添加枚举声明
//Enumeration for Spread rating enum SpreadRating { SpreadRating_Terrible,//Terrible SpreadRating_Bad,//Bad SpreadRating_Normal,//Normal SpreadRating_Good,//Good SpreadRating_Excellent//Excellent };
- 声明布尔变量以配置图表颜色模式
bool isLightMode;//Variable to configure Chart color mode
- 声明布尔函数以获取点差的浮点值
bool SpreadFloat(string SYMBOL=NULL);//Retrieve Spread Float
//+------------------------------------------------------------------+ //|Retrieve Spread Float | //+------------------------------------------------------------------+ bool CSymbolProperties::SpreadFloat(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { return CSymbol.SpreadFloat(); } Print("Unable to retrieve Symbol's Spread Float"); return false;//Retrieve false when failed. }
- 声明点差评级函数以获取点差评级
SpreadRating SpreadValue(string SYMBOL=NULL);//Retrieve Spread Rating
该函数必须返回一个来自SpreadRating的枚举值。
//+------------------------------------------------------------------+ //|Retrieve Spread Rating | //+------------------------------------------------------------------+ SpreadRating CSymbolProperties::SpreadValue(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(SpreadFloat(SYMBOL))//Check if Symbol has a floating Spread { //Declarations vector Spreads; int SpreadArray[],SpreadAvg=0,SpreadMax=0,SpreadMin=0, SpreadUpper=0,SpreadLower=0,SpreadAvgUpper=0, SpreadAvgLower=0,SpreadMidUpper=0,SpreadMidLower=0; //Get Spread data from CopySpread built-in function for 2 weeks using M1 timeframe. if(CopySpread(GetSymbolName(),PERIOD_M1,iTime(GetSymbolName(),PERIOD_W1,2), iTime(GetSymbolName(),PERIOD_M1,0),SpreadArray)==-1) { Print("Error trying to retrieve spread values"); return SpreadRating_Normal;//Retrieve default value when failed. } else { Spreads.Assign(SpreadArray);//Assign spread array into Spreads vector variable SpreadMax = int(Spreads.Max());//Assign max spread SpreadMin = int(Spreads.Min());//Assign min spread SpreadAvg = int(Spreads.Median());//Assign average spread //Divide Spread into sectors based of different averages. SpreadMidUpper = int((SpreadAvg+SpreadMax)/2); SpreadMidLower = int((SpreadAvg+SpreadMin)/2); SpreadAvgUpper = int((SpreadAvg+SpreadMidUpper)/2); SpreadAvgLower = int((SpreadAvg+SpreadMidLower)/2); SpreadUpper = int((SpreadMidUpper+SpreadMax)/2); SpreadLower = int((SpreadMidLower+SpreadMin)/2); int Spread = Spread(SYMBOL);//Assign Symbol's Spread if(Spread<SpreadLower||Spread==SpreadMin)//Excellent { return SpreadRating_Excellent; } else if(Spread>=SpreadLower&&Spread<SpreadAvgLower)//Good { return SpreadRating_Good; } else if(Spread>=SpreadAvgLower&&Spread<=SpreadAvgUpper)//Normal { return SpreadRating_Normal; } else if(Spread>SpreadAvgUpper&&Spread<=SpreadUpper)//Bad { return SpreadRating_Bad; } else//Terrible { return SpreadRating_Terrible; } } } else { return SpreadRating_Normal;//Retrieve default value when spread is fixed. } } Print("Unable to retrieve Symbol's Spread Rating"); return SpreadRating_Normal;//Retrieve default value when failed. }
我们首先设置交易品种,然后检查该交易品种是否具有浮动点差,之后我们进行简单的计算,根据其平均值对点差进行评级。如果交易品种设置失败,或者该交易品种没有浮动点差,我们将返回 SpreadRating_Normal 作为默认值。
if(SetSymbolName(SYMBOL))//Set Symbol { if(SpreadFloat(SYMBOL))//Check if Symbol has a floating Spread {
如果我们成功设置了交易品种,并且该交易品种具有浮动点差,那么我们将声明一个Spreads向量变量和一些整型变量来存储点差值。在声明了变量之后,我们将使用CopySpread函数,从两周前的1分钟K线图开始,一直到当前的1分钟K线图时间,将点差值存储到我们的SpreadArray变量中。如果CopySpread函数因某种原因失败,我们将返回SpreadRating_Normal作为默认值。
//Declarations vector Spreads; int SpreadArray[],SpreadAvg=0,SpreadMax=0,SpreadMin=0, SpreadUpper=0,SpreadLower=0,SpreadAvgUpper=0, SpreadAvgLower=0,SpreadMidUpper=0,SpreadMidLower=0; //Get Spread data from CopySpread built-in function for 2 weeks using M1 timeframe. if(CopySpread(GetSymbolName(),PERIOD_M1,iTime(GetSymbolName(),PERIOD_W1,2), iTime(GetSymbolName(),PERIOD_M1,0),SpreadArray)==-1) { Print("Error trying to retrieve spread values"); return SpreadRating_Normal;//Retrieve default value when failed. }
一旦CopySpread成功,我们将把SpreadArray中的整数值赋给Spreads向量然后,我们需要从这些数组值中获取基本信息,例如在两周期间的最大点差、最小点差和平均点差,并将这些值分别存储到SpreadMax、SpreadMin和SpreadAvg 中。接下来,我们希望从这三个先前的值中获取不同的平均值。
对于SpreadMidUpper变量,我们希望得到SpreadAvg和SpreadMax之间的平均值;对于SpreadMidLower变量,我们希望得到SpreadAvg和SpreadMin之间的平均值;对于SpreadAvgUpper变量,我们希望得到SpreadAvg和 SpreadMidUpper之间的平均值;对于SpreadAvgLower变量,我们希望得到SpreadAvg和SpreadMidLower之间的平均值;对于SpreadUpper变量,我们希望得到SpreadMidUpper和SpreadMax之间的平均值;对于SpreadLower变量,我们希望得到SpreadMidLower和SpreadMin之间的平均值。我们还需要当前交易品种的点差来进行比较,以便对点差进行分类。
Spreads.Assign(SpreadArray);//Assign spread array into Spreads vector variable SpreadMax = int(Spreads.Max());//Assign max spread SpreadMin = int(Spreads.Min());//Assign min spread SpreadAvg = int(Spreads.Median());//Assign average spread //Divide Spread into sectors based of different averages. SpreadMidUpper = int((SpreadAvg+SpreadMax)/2); SpreadMidLower = int((SpreadAvg+SpreadMin)/2); SpreadAvgUpper = int((SpreadAvg+SpreadMidUpper)/2); SpreadAvgLower = int((SpreadAvg+SpreadMidLower)/2); SpreadUpper = int((SpreadMidUpper+SpreadMax)/2); SpreadLower = int((SpreadMidLower+SpreadMin)/2); int Spread = Spread(SYMBOL);//Assign Symbol's Spread
我们有5个点差分类,分别是:
- 优秀(Excellent):当当前点差小于SpreadLower变量或等于SpreadMin时。
- 良好(Good):当当前点差大于或等于SpreadLower变量,并且当前点差小于SpreadAvgLower变量时。
- 一般(Normal):当当前点差小于或等于SpreadAvgLower变量,并且当前点差小于或等于SpreadAvgUpper变量时。
- 较差(Bad):当当前点差大于SpreadAvgUpper,并且当前点差小于或等于SpreadUpper变量时。
- 极差(Terrible):当当前点差大于SpreadUpper变量时。
if(Spread<SpreadLower||Spread==SpreadMin)//Excellent { return SpreadRating_Excellent; } else if(Spread>=SpreadLower&&Spread<SpreadAvgLower)//Good { return SpreadRating_Good; } else if(Spread>=SpreadAvgLower&&Spread<=SpreadAvgUpper)//Normal { return SpreadRating_Normal; } else if(Spread>SpreadAvgUpper&&Spread<=SpreadUpper)//Bad { return SpreadRating_Bad; } else//Terrible { return SpreadRating_Terrible; }
- 声明基于点差等级获取点差颜色的函数
color SpreadColor(string SYMBOL=NULL);//Retrieve Spread Color
为了为每个点差枚举值获取相应的颜色,我们将考虑使用 switch 语句,因为枚举值是固定的。各等级颜色对应如下:
- 优秀:如果在浅色模式下,则为 clrBlue。
否则采用clrLightCyan
- 良好:如果是浅色模式,则使用clrCornflowerBlue
否则采用clrLightGreen
- 一般:如果是浅色模式则采用clrBlack
否则采用clrWheat
- 较差:clrOrange
- 极差:clrRed
- 默认:如果是浅色模式则采用clrBlack,否则clrWheat
//+------------------------------------------------------------------+ //|Retrieve Spread Color | //+------------------------------------------------------------------+ color CSymbolProperties::SpreadColor(string SYMBOL=NULL) { switch(SpreadValue(SYMBOL))//Get Spread Rating value { case SpreadRating_Excellent://Excellent Spread return (isLightMode)?clrBlue:clrLightCyan; break; case SpreadRating_Good://Good Spread return (isLightMode)?clrCornflowerBlue:clrLightGreen; break; case SpreadRating_Normal://Normal Spread return (isLightMode)?clrBlack:clrWheat; break; case SpreadRating_Bad://Bad Spread return clrOrange; break; case SpreadRating_Terrible://Terrible Spread return clrRed; break; default://failed to be identified return (isLightMode)?clrBlack:clrWheat;//Retrieve default color when failed. break; } }
- 声明获取点差描述的字符串函数
string SpreadDesc(string SYMBOL=NULL);//Retrieve Spread Description
//+------------------------------------------------------------------+ //|Retrieve Spread Description | //+------------------------------------------------------------------+ string CSymbolProperties::SpreadDesc(string SYMBOL=NULL) { switch(SpreadValue(SYMBOL))//Get Spread Rating value { case SpreadRating_Excellent://Excellent Spread return "Excellent"; break; case SpreadRating_Good://Good Spread return "Good"; break; case SpreadRating_Normal://Normal Spread return "Normal"; break; case SpreadRating_Bad://Bad Spread return "Bad"; break; case SpreadRating_Terrible://Terrible Spread return "Terrible"; break; default://failed to be identified return "Unknown";//Retrieve default value when failed. break; } }
- 声明获取交易品种描述的字符串函数
string Description(string SYMBOL=NULL);//Retrieve Symbol's Description
//+------------------------------------------------------------------+ //|Retrieve Symbol's Description | //+------------------------------------------------------------------+ string CSymbolProperties::Description(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { return CSymbol.Description(); } Print("Unable to retrieve Symbol's Description"); return "";//Retrieve an empty string when failed. }
图表属性类
这个类已经从第2部分进行了重构。图表属性类现在将从MQL5的包含类中的图表类继承。ChartProp结构将存储我们将要进行更改的所有图表属性。我们的公共ChartRefresh函数将调用我们的ChartGet函数,该函数将初始化图表属性,然后我们将调用ChartSet函数,该函数将使用ChartGet中的图表属性值来配置图表。
#include "SymbolProperties.mqh" #include <Charts/Chart.mqh> CSymbolProperties CSymbol;//Symbol Properties object //+------------------------------------------------------------------+ //|ChartProperties class | //+------------------------------------------------------------------+ class CChartProperties : public CChart { private: //Structure for chart properties struct ChartProp { ENUM_CHART_MODE mode;//Chart Mode color clrBackground;//Chart Background Color color clrForeground;//Chart Foreground Color color clrLineLast;//Chart Line Color color clrCandleBear;//Chart Bear Candle Color color clrBarDown;//Chart Down Candle Color color clrCandleBull;//Chart Bull Candle Color color clrBarUp;//Chart Up Candle Color color clrLineAsk;//Chart Ask Color color clrLineBid;//Chart Bid Color color clrChartLine;//Chart Line Color color clrStopLevels;//Chart Stop Level Color color clrVolumes;//Chart Volumes Color bool Foreground;//Chart Foreground Visibility bool ShowLineAsk;//Chart Ask Line Visibility bool ShowLineBid;//Chart Bid Line Visibility bool ShowPeriodSep;//Chart Period Separator Visibility bool ShowOHLC;//Chart Open-High-Low-Close Visibility bool ShowGrid;//Chart Grid Visibility ENUM_CHART_VOLUME_MODE ShowVolumes;//Chart Volumes Visibility bool AutoScroll;//Chart Auto Scroll Option bool Shift;//Chart Shift Option double ShiftSize;//Chart Shift Size bool ShowObjectDescr;//Chart Object Descriptions ulong CHART_SHOW_TRADE_LEVELS;//Chart Trade Levels Visibility ulong CHART_SHOW_ONE_CLICK;//Chart One Click Trading Visibility ulong CHART_SHOW_TICKER;//Chart Ticker Visibility ulong CHART_DRAG_TRADE_LEVELS;//Chart Drag Trade levels ENUM_CHART_POSITION Navigate;//Chart Navigate }; ChartProp DefaultChart,MyChart;//Used to store chart properties void ChartSet(ChartProp &Prop);//Apply Chart format void ChartGet();//Assign Chart property values public: CChartProperties();//Constructor ~CChartProperties(void);//Destructor //Configure the chart void ChartRefresh() {ChartGet();ChartSet(MyChart);} string GetChartPeriodName();//Retrieve Period name };
在构造函数中,我们将继承的变量m_chart_id分配为当前图表的ID。
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CChartProperties::CChartProperties() { m_chart_id=ChartID();//Set chart id ChartGet();//Get chart values ChartSet(MyChart);//customize chart }
对于ChartGet函数,我们将值分配给变量DefaultChart和MyChart,其中DefaultChart将存储我们在修改图表之前当前图表的属性,而MyChart将存储我们的自定义值。
//+------------------------------------------------------------------+ //|Assign Chart property values | //+------------------------------------------------------------------+ void CChartProperties::ChartGet() { DefaultChart.mode = Mode();//assign chart mode MyChart.mode = CHART_CANDLES;//assign custom chart mode DefaultChart.clrBackground = ColorBackground();//assign Background color MyChart.clrBackground = (isLightMode)?clrWhite:clrBlack;//assign custom Background color DefaultChart.clrForeground = ColorForeground();//assign foreground color MyChart.clrForeground = (isLightMode)?clrBlack:clrWhite;//assign custom foreground color DefaultChart.clrLineLast = ColorLineLast();//assign Chart Line Color MyChart.clrLineLast = clrWhite;//assign custom Chart Line Color DefaultChart.clrCandleBear = ColorCandleBear();//assign Chart Bear Candle Color MyChart.clrCandleBear = clrBlack;//assign custom Chart Bear Candle Color DefaultChart.clrBarDown = ColorBarDown();//assign Chart Down Candle Color MyChart.clrBarDown = (isLightMode)?clrBlack:CSymbol.Background();//assign custom Chart Down Candle Color DefaultChart.clrCandleBull = ColorCandleBull();//assign Chart Bull Candle Color MyChart.clrCandleBull = CSymbol.Background();//assign custom Chart Bull Candle Color DefaultChart.clrBarUp = ColorBarUp();//assign Chart Up Candle Color MyChart.clrBarUp = (isLightMode)?clrBlack:CSymbol.Background();//assign custom Chart Up Candle Color DefaultChart.clrLineAsk = ColorLineAsk();//assign Chart Ask Color MyChart.clrLineAsk = (isLightMode)?clrBlack:clrWhite;//assign custom Chart Ask Color DefaultChart.clrLineBid = ColorLineBid();//assign Chart Bid Color MyChart.clrLineBid = (isLightMode)?clrBlack:CSymbol.Background();//assign custom Chart Bid Color DefaultChart.clrChartLine = ColorChartLine();//assign Chart Line Color MyChart.clrChartLine = (isLightMode)?clrBlack:clrWhite;//assign custom Chart Line Color DefaultChart.clrStopLevels = ColorStopLevels();//assign Chart Stop Level Color MyChart.clrStopLevels = clrRed;//assign custom Chart Stop Level Color DefaultChart.clrVolumes = ColorVolumes();//assign Chart Volumes Color MyChart.clrVolumes = clrGreen;//assign custom Chart Volumes Color DefaultChart.Foreground = Foreground();//assign Chart Foreground Visibility MyChart.Foreground = false;//assign custom Chart Foreground Visibility DefaultChart.ShowLineAsk = ShowLineAsk();//assign Chart Ask Line Visibility MyChart.ShowLineAsk = true;//assign custom Chart Ask Line Visibility DefaultChart.ShowLineBid = ShowLineBid();//assign Chart Bid Line Visibility MyChart.ShowLineBid = true;//assign custom Chart Bid Line Visibility DefaultChart.ShowPeriodSep = ShowPeriodSep();//assign Chart Period Separator Visibility MyChart.ShowPeriodSep = true;//assign custom Chart Period Separator Visibility DefaultChart.ShowOHLC = ShowOHLC();//assign Chart Open-High-Low-Close Visibility MyChart.ShowOHLC = false;//assign custom Chart Open-High-Low-Close Visibility DefaultChart.ShowGrid = ShowGrid();//assign Chart Grid Visibility MyChart.ShowGrid = false;//assign custom Chart Grid Visibility DefaultChart.ShowVolumes = ShowVolumes();//assign Chart Volumes Visibility MyChart.ShowVolumes = CHART_VOLUME_HIDE;//assign custom Chart Volumes Visibility DefaultChart.AutoScroll = AutoScroll();//assign Chart Auto Scroll Option MyChart.AutoScroll = true;//assign custom Chart Auto Scroll Option DefaultChart.Shift = Shift();//assign Chart Shift Option MyChart.Shift = true;//assign custom Chart Shift Option DefaultChart.ShiftSize = ShiftSize();//assign Chart Shift Size MyChart.ShiftSize = 15;//assign custom Chart Shift Size DefaultChart.ShowObjectDescr = ShowObjectDescr();//assign Chart Object Descriptions MyChart.ShowObjectDescr = false;//assign custom Chart Object Descriptions DefaultChart.Navigate = CHART_END;//assign Chart Navigate MyChart.Navigate = CHART_END;//assign custom Chart Navigate //---assign Chart Trade Levels Visibility DefaultChart.CHART_SHOW_TRADE_LEVELS = ChartGetInteger(ChartId(),CHART_SHOW_TRADE_LEVELS); //---assign custom Chart Trade Levels Visibility MyChart.CHART_SHOW_TRADE_LEVELS = ulong(true); //---assign Chart One Click Trading Visibility DefaultChart.CHART_SHOW_ONE_CLICK = ChartGetInteger(ChartId(),CHART_SHOW_ONE_CLICK); //---assign custom Chart One Click Trading Visibility MyChart.CHART_SHOW_ONE_CLICK = ulong(false); //---assign Chart Ticker Visibility DefaultChart.CHART_SHOW_TICKER = ChartGetInteger(ChartId(),CHART_SHOW_TICKER); //---assign custom Chart Ticker Visibility MyChart.CHART_SHOW_TICKER = ulong(false); //---assign Chart Drag Trade levels DefaultChart.CHART_DRAG_TRADE_LEVELS = ChartGetInteger(ChartId(),CHART_DRAG_TRADE_LEVELS); //---assign custom Chart Drag Trade levels MyChart.CHART_DRAG_TRADE_LEVELS = ulong(false); }
我们的ChartSet函数将接受我们的ChartProp结构作为参数,以配置当前图表。
//+------------------------------------------------------------------+ //|Apply Chart format | //+------------------------------------------------------------------+ void CChartProperties::ChartSet(ChartProp &Prop) { Mode(Prop.mode);//Set Chart Candle Mode ColorBackground(Prop.clrBackground);//Set Chart Background Color ColorForeground(Prop.clrForeground);//Set Chart Foreground Color ColorLineLast(Prop.clrLineLast);//Set Chart Line Color ColorCandleBear(Prop.clrCandleBear);//Set Chart Bear Candle Color ColorBarDown(Prop.clrBarDown);//Set Chart Down Candle Color ColorCandleBull(Prop.clrCandleBull);//Set Chart Bull Candle Color ColorBarUp(Prop.clrBarUp);//Set Chart Up Candle Color ColorLineAsk(Prop.clrLineAsk);//Set Chart Ask Color ColorLineBid(Prop.clrLineBid);//Set Chart Bid Color ColorChartLine(Prop.clrChartLine);//Set Chart Line Color ColorStopLevels(Prop.clrStopLevels);//Set Chart Stop Level Color ColorVolumes(Prop.clrVolumes);//Set Chart Volumes Color Foreground(Prop.Foreground);//Set if Chart is in Foreground Visibility ShowLineAsk(Prop.ShowLineAsk);//Set Chart Ask Line Visibility ShowLineBid(Prop.ShowLineBid);//Set Chart Bid Line Visibility ShowPeriodSep(Prop.ShowPeriodSep);//Set Chart Period Separator Visibility ShowOHLC(Prop.ShowOHLC);//Set Chart Open-High-Low-Close Visibility ShowGrid(Prop.ShowGrid);//Set Chart Grid Visibility ShowVolumes(Prop.ShowVolumes);//Set Chart Volumes Visibility AutoScroll(Prop.AutoScroll);//Set Chart Auto Scroll Option Shift(Prop.Shift);//Set Chart Shift Option ShiftSize(Prop.ShiftSize);//Set Chart Shift Size Value ShowObjectDescr(Prop.ShowObjectDescr);//Set Chart Show Object Descriptions ChartSetInteger(ChartId(),CHART_SHOW_TRADE_LEVELS,Prop.CHART_SHOW_TRADE_LEVELS);//Set Chart Trade Levels Visibility ChartSetInteger(ChartId(),CHART_SHOW_ONE_CLICK,Prop.CHART_SHOW_ONE_CLICK);//Set Chart One Click Trading Visibility ChartSetInteger(ChartId(),CHART_SHOW_TICKER,Prop.CHART_SHOW_TICKER);//Set Chart Ticker Visibility ChartSetInteger(ChartId(),CHART_DRAG_TRADE_LEVELS,Prop.CHART_DRAG_TRADE_LEVELS);//Set Chart Drag Trade levels Navigate(Prop.Navigate);//Set Chart Navigate }
至于GetChartPeriodName函数,我们将通过使用switch语句来检索当前图表的时间周期名称。
//+------------------------------------------------------------------+ //|Retrieve Period name | //+------------------------------------------------------------------+ string CChartProperties::GetChartPeriodName() { switch(ChartPeriod(ChartId()))//Get chart Period with chart id { case PERIOD_M1: return("M1"); case PERIOD_M2: return("M2"); case PERIOD_M3: return("M3"); case PERIOD_M4: return("M4"); case PERIOD_M5: return("M5"); case PERIOD_M6: return("M6"); case PERIOD_M10: return("M10"); case PERIOD_M12: return("M12"); case PERIOD_M15: return("M15"); case PERIOD_M20: return("M20"); case PERIOD_M30: return("M30"); case PERIOD_H1: return("H1"); case PERIOD_H2: return("H2"); case PERIOD_H3: return("H3"); case PERIOD_H4: return("H4"); case PERIOD_H6: return("H6"); case PERIOD_H8: return("H8"); case PERIOD_H12: return("H12"); case PERIOD_D1: return("Daily"); case PERIOD_W1: return("Weekly"); case PERIOD_MN1: return("Monthly"); } return("unknown period"); }
我们的析构函数将在我们对图表进行任何更改之前恢复之前的图表配置。
//+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CChartProperties::~CChartProperties() { ChartSet(DefaultChart);//restore chart default configuration m_chart_id=-1;//reset chart id }
对象属性类
在这个类中,我们进行了一些更改,以便允许自定义对象文本颜色。在第2部分中,你只能为所有文本对象使用一种对象文本颜色。我们的解决方案是在类外部声明一个颜色变量,名为TextObj_color。
#include "ChartProperties.mqh" color TextObj_color; //+------------------------------------------------------------------+ //|ObjectProperties class | //+------------------------------------------------------------------+ class CObjectProperties:public CChartProperties { private: //Simple chart objects structure struct ObjStruct { long ChartId; string Name; } Objects[];//ObjStruct variable array //-- Add chart object to Objects array void AddObj(long chart_id,string name) { ArrayResize(Objects,Objects.Size()+1,Objects.Size()+2); Objects[Objects.Size()-1].ChartId=chart_id; Objects[Objects.Size()-1].Name=name; } protected: void DeleteObj() { for(uint i=0;i<Objects.Size();i++) { ObjectDelete(Objects[i].ChartId,Objects[i].Name); } } public: CObjectProperties(void) {}//Class constructor //-- Create Rectangle chart object void Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor); //-- Create text chart object void TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10); //-- Create Event object void EventObj(long chartID,string name,string description,datetime eventdate); //-- Class destructor removes all chart objects created previously ~CObjectProperties(void) { DeleteObj(); } };
正如我们下面可以看到的,Textobj函数的参数很多。为了避免让参数列表变得更长,我们只会使用Textobj_color来改变文本对象的颜色。
//+------------------------------------------------------------------+ //|Create text chart object | //+------------------------------------------------------------------+ void CObjectProperties::TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10) { ObjectDelete(chartID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chartID,name,OBJ_LABEL,0,0,0))//Create object label { AddObj(chartID,name);//Add object to array ObjectSetInteger(chartID,name,OBJPROP_XDISTANCE,x_coord);//Set x Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_YDISTANCE,y_coord);//Set y Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_CORNER,Corner);//Set object's corner anchor ObjectSetString(chartID,name,OBJPROP_TEXT,text);//Set object's text ObjectSetInteger(chartID,name,OBJPROP_COLOR,TextObj_color);//Set object's color ObjectSetInteger(chartID,name,OBJPROP_FONTSIZE,fontsize);//Set object's font-size } else { Print("Failed to create object: ",name); } }
我们对Square函数进行了一个小的修改,以便根据图表的颜色模式允许使用不同的背景颜色。
//+------------------------------------------------------------------+ //|Create Rectangle chart object | //+------------------------------------------------------------------+ void CObjectProperties::Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor) { const int sub_window=0; // subwindow index const int x=x_coord; // X coordinate const int y=y_coord; // Y coordinate const color back_clr=(isLightMode)?clrWhite:clrBlack;// background color const ENUM_BORDER_TYPE border=BORDER_SUNKEN; // border type const color clr=clrRed; // flat border color (Flat) const ENUM_LINE_STYLE style=STYLE_SOLID; // flat border style const int line_width=0; // flat border width const bool back=false; // in the background const bool selection=false; // highlight to move const bool hidden=true; // hidden in the object list ObjectDelete(chart_ID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0))//create rectangle object label { AddObj(chart_ID,name);//Add object to array ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);//Set x Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);//Set y Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);//Set object's width/x-size ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);//Set object's height/y-size ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);//Set object's background color ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border);//Set object's border type ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,Anchor);//Set objects anchor point ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);//Set object's color ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);//Set object's style ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width);//Set object's flat border width ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);//Set if object is in foreground or not ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);//Set if object is selectable/dragable ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);//Set if object is Selected ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);//Set if object is hidden in object list ChartRedraw(chart_ID); } else { Print("Failed to create object: ",name); } }
公共变量头文件
为了交易目的,我决定创建一个内存中的数据库。这个数据库需要一个名称,而名称将考虑经纪商的名称、当前图表的ID,以及该EA是否在策略测试器中运行。
#define NEWS_DATABASE_MEMORY StringFormat("Calendar_%s_%d_%s.sqlite",broker,ChartID(),(MQLInfoInteger(MQL_TESTER)?"TESTER":"REAL"))
枚举类型 Choice 用于个性化设置,并将作为专家输入的选项,它将替代布尔数据类型。枚举类型 DayOfTheWeek 将用于选择一周中的交易日,不包括周六和周日。而布尔函数 Answer 将把 Choice 枚举类型转换为布尔数据类型。
enum Choice { Yes,//YES No//NO }; enum DayOfTheWeek { Monday,//MONDAY Tuesday,//TUESDAY Wednesday,//WEDNESDAY Thursday,//THURSDAY Friday,//FRIDAY AllDays//ALL DAYS }; //+------------------------------------------------------------------+ //|Convert enumeration Choice into a boolean value | //+------------------------------------------------------------------+ bool Answer(Choice choose) { return (choose==Yes)?true:false; }
时间变量类
这个类的目的是存储K线图的时间数据,这些数据将用于检查是否形成了新的K线图。
//+------------------------------------------------------------------+ //|TimeVariables class | //+------------------------------------------------------------------+ class CTimeVariables { private: //---Array to store candlestick times datetime CandleTime[2000]; public: CTimeVariables(void); //---Set Array index time void SetTime(uint index,datetime time); //---Get Array index time datetime GetTime(uint index); };
在构造函数中,我们将为CandleTime数组中的所有索引设置一个默认时间。
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CTimeVariables::CTimeVariables() { for(uint i=0; i<CandleTime.Size(); i++) { CandleTime[i]=D'1970.01.01'; } }
在SetTime函数中,我们有两个参数,一个用于数组索引,另一个用于时间(datetime)。如果索引参数大于或等于零且小于CandleTime的大小,那么我们将用时间参数为数组索引赋值。
//+------------------------------------------------------------------+ //|Set Array index time | //+------------------------------------------------------------------+ void CTimeVariables::SetTime(uint index,datetime time) { if(index>=0&&index<CandleTime.Size()) { CandleTime[index] = time; } }
GetTime函数将接受一个正整数参数,用于从CandleTime中检索时间值,前提是索引参数是有效的。
//+------------------------------------------------------------------+ //|Get Array index time | //+------------------------------------------------------------------+ datetime CTimeVariables::GetTime(uint index) { return (index>=0&&index<CandleTime.Size())?CandleTime[index]:datetime(0); }
时间管理类
我们将声明DSTSchedule枚举类型,供用户/交易者在专家输入中选择“自动夏令时”或“自定义夏令时”。MySchedule变量将用于存储自定义夏令时。
//-- Enumeration for DST schedule enum DSTSchedule { AutoDst_Selection,//AUTO DST CustomDst_Selection//CUSTOM DST } MyDST; DST_type MySchedule;//Variable for custom DST schedule
下面的函数将返回特定日期的小时数,返回值为整数类型。
int ReturnHour(datetime time);//Returns the Hour for a specific date
//+------------------------------------------------------------------+ //|Returns the Hour for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnHour(datetime time) { return Time(time).hour; }
下面的函数将返回特定日期的分钟数,返回值为整数类型。
int ReturnMinute(datetime time);//Returns the Minute for a specific date
//+------------------------------------------------------------------+ //|Returns the Minute for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnMinute(datetime time) { return Time(time).min; }
下面的函数将返回特定日期的秒数,返回值为整数类型。
int ReturnSecond(datetime time);//Returns the Second for s specific date
//+------------------------------------------------------------------+ //|Returns the Second for s specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnSecond(datetime time) { return Time(time).sec; }
下面的函数将返回与时间参数对应的 MqlDateTime 类型值。
//-- Will convert datetime to MqlDateTime MqlDateTime Time(datetime Timetoformat);
//+------------------------------------------------------------------+ //|Will convert datetime to MqlDateTime | //+------------------------------------------------------------------+ MqlDateTime CTimeManagement::Time(datetime Timetoformat) { TimeToStruct(Timetoformat,timeFormat); return timeFormat; }
下面的函数将返回修改了小时、分钟和秒的时间参数的 datetime 类型值。
//-- Will return a datetime with changes to the hour,minute and second datetime Time(datetime time,int Hour,int Minute,int Second);
//+------------------------------------------------------------------+ //|Will return a datetime with changes to the hour,minute and second | //+------------------------------------------------------------------+ datetime CTimeManagement::Time(datetime time,int Hour,int Minute,int Second) { timeFormat=Time(time); timeFormat.hour=Hour; timeFormat.min=Minute; timeFormat.sec=Second; return StructToTime(timeFormat); }
下面的函数将返回经过小时和分钟修改后的时间参数对应的 datetime 类型值。
//-- Will return a datetime with changes to the hour and minute datetime Time(datetime time,int Hour,int Minute);
//+------------------------------------------------------------------+ //|Will return a datetime with changes to the hour and minute | //+------------------------------------------------------------------+ datetime CTimeManagement::Time(datetime time,int Hour,int Minute) { timeFormat=Time(time); timeFormat.hour=Hour; timeFormat.min=Minute; return StructToTime(timeFormat); }
下面的函数将在TimeTradeServer时间位于参数BeginTime和EndTime之间时,返回true。
//-- Check current time is within a time range bool TimeIsInRange(datetime BeginTime,datetime EndTime);
//+------------------------------------------------------------------+ //|Check current time is within a time range | //+------------------------------------------------------------------+ bool CTimeManagement::TimeIsInRange(datetime BeginTime,datetime EndTime) { if(BeginTime<=TimeTradeServer()&&EndTime>=TimeTradeServer()) { return true; } return false; }
下面的函数将在PreEvent时间小于或等于TimeTradeServer,且EventTime大于TimeTradeServer时,返回true。
//-- Check if current time is within preEvent time and Event time bool TimePreEvent(datetime PreEvent,datetime Event);
//+------------------------------------------------------------------+ //|Check if current time is within preEvent time and Event time | //+------------------------------------------------------------------+ bool CTimeManagement::TimePreEvent(datetime PreEventTime,datetime EventTime) { if(PreEventTime<=TimeTradeServer()&&EventTime>TimeTradeServer()) { return true; } return false; }
下面的函数将返回当前时间的 MqlDateTime 类型值,并对其进行小时和分钟的修改。
//-- Return MqlDateTime for current date time with custom hour and minute MqlDateTime Today(int Hour,int Minute);
//+------------------------------------------------------------------+ //|Return MqlDateTime for current date time with custom hour and | //|minute | //+------------------------------------------------------------------+ MqlDateTime CTimeManagement::Today(int Hour,int Minute) { TimeTradeServer(today); today.hour=Hour; today.min=Minute; return today; }
下面的函数将返回当前时间的 MqlDateTime 类型值,并对其进行小时、分钟和秒的修改。
//-- Return MqlDateTime for current date time with custom hour, minute and second MqlDateTime Today(int Hour,int Minute,int Second);
//+------------------------------------------------------------------+ //|Return MqlDateTime for current date time with custom hour, minute | //|and second | //+------------------------------------------------------------------+ MqlDateTime CTimeManagement::Today(int Hour,int Minute,int Second) { TimeTradeServer(today); today.hour=Hour; today.min=Minute; today.sec=Second; return today; }
下面的函数将在当前日期等于一周中的对应日期,或者枚举类型 DayOfTheWeek 等于 AllDays 时返回 true。
//-- Check current day of the week bool isDayOfTheWeek(DayOfTheWeek Day);
//+------------------------------------------------------------------+ //|Check current day of the week | //+------------------------------------------------------------------+ bool CTimeManagement::isDayOfTheWeek(DayOfTheWeek Day) { switch(Day) { case Monday://Monday if(DayOfWeek(TimeTradeServer())==MONDAY) { return true; } break; case Tuesday://Tuesday if(DayOfWeek(TimeTradeServer())==TUESDAY) { return true; } break; case Wednesday://Wednesday if(DayOfWeek(TimeTradeServer())==WEDNESDAY) { return true; } break; case Thursday://Thursday if(DayOfWeek(TimeTradeServer())==THURSDAY) { return true; } break; case Friday://Friday if(DayOfWeek(TimeTradeServer())==FRIDAY) { return true; } break; case AllDays://All days return true; break; default://Unknown break; } return false; }
下面的函数将返回特定日期的星期几。
//-- Return enumeration Day of week for a certain date ENUM_DAY_OF_WEEK DayOfWeek(datetime time);
//+------------------------------------------------------------------+ //|Return enumeration Day of week for a certain date | //+------------------------------------------------------------------+ ENUM_DAY_OF_WEEK CTimeManagement::DayOfWeek(datetime time) { return (ENUM_DAY_OF_WEEK)Time(time).day_of_week; }
K线属性类
在类中添加一个新的函数。
//+------------------------------------------------------------------+ //|CandleProperties class | //+------------------------------------------------------------------+ class CCandleProperties : public CChartProperties { private: CTimeManagement Time;//TimeManagement object CTimeVariables CTV;//Timevariables object public: double Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Open-Price double Close(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Close-Price double High(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle High-Price double Low(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Low-Price bool IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others bool NewCandle(int index,ENUM_TIMEFRAMES period=PERIOD_CURRENT,string SYMBOL=NULL);//Check if a new candle is present };
NewCandle 函数将在新K线形成时返回 true,然后使用 SetTime 函数将当前K线的开盘时间保存在类 Timevariables 中。将之前保存的时间与当前K线的开盘时间进行比较,以检查时间是否不同。如果时间不同,那么我们认为新K线已经形成。
//+------------------------------------------------------------------+ //|Check if a new candle is present | //+------------------------------------------------------------------+ bool CCandleProperties::NewCandle(int index,ENUM_TIMEFRAMES period=PERIOD_CURRENT,string SYMBOL=NULL) { if(CTV.GetTime(index) == iTime(((SYMBOL==NULL)?Symbol():SYMBOL),period,0)) { return false;//Candle time are equal no new candles have formed } else { //--- Candle time has changed set the new time CTV.SetTime(index,iTime(((SYMBOL==NULL)?Symbol():SYMBOL),period,0)); return true; } }
时间区间类
这个类的目的是处理交易时段。在本文中,我们不会使用这些交易时段,但稍后我们会用到这个类。这个类将从时间管理类继承,因为它将使用时间管理类中的函数。
#include "Timemanagement.mqh" //+------------------------------------------------------------------+ //|Sessions Class | //+------------------------------------------------------------------+ class CSessions:CTimeManagement { public: CSessions(void) {} ~CSessions(void) {} //--- Check if trading Session has began bool isSessionStart(int offsethour=0,int offsetmin=0); //--- Check if trading Session has ended bool isSessionEnd(int offsethour=0,int offsetmin=45); //--- Get Session End datetime datetime SessionEnd(int offsethour=0,int offsetmin=45); };
下面的函数将检查当前交易品种和星期几的所有有效交易时段。一旦找到最早的交易时段,我们将在该时间上加上一个偏移量。如果最早的交易时段是从 01:00 到 05:00,那么我们的偏移小时数是 1,偏移分钟数是 0,我们的交易时段将从 02:00 开始,持续到 05:00。了解交易时段的开始时间的目的是为了避免在交易会话开始时通常会出现的较大点差。如果当前交易时段处于活跃状态,该函数将返回 true。
//+------------------------------------------------------------------+ //|Check if trading Session has started | //+------------------------------------------------------------------+ bool CSessions::isSessionStart(int offsethour=0,int offsetmin=0) { //--- Declarations datetime datefrom,dateto,DateFrom[],DateTo[]; //--- Find all session times for(int i=0; i<10; i++) { //--- Get the session dates for the current symbol and Day of week if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto)) { //--- Check if the end date's hour is at midnight if(ReturnHour(dateto)==00||ReturnHour(dateto)==24) { //--- Adjust the date to one minute before midnight dateto = Time(TimeTradeServer(),23,59); } //--- Re-adjust DateFrom Array size ArrayResize(DateFrom,int(ArraySize(DateFrom))+1,int(ArraySize(DateFrom))+2); //--- Assign the last array index datefrom value DateFrom[int(ArraySize(DateFrom))-1] = datefrom; //--- Re-adjust DateTo Array size ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2); //--- Assign the last array index dateto value DateTo[int(ArraySize(DateTo))-1] = dateto; } } //--- Check if there are session times if(DateFrom.Size()>0) { /* Adjust DateFrom index zero date as the first index date will be the earliest date from the whole array, we add the offset to this date only*/ DateFrom[0] = TimePlusOffset(DateFrom[0],MinutesS(startoffsetmin)); DateFrom[0] = TimePlusOffset(DateFrom[0],HoursS(startoffsethour)); //--- Iterate through the whole array for(uint i=0; i<DateFrom.Size(); i++) { //--- Check if the current time is within the trading session if(TimeIsInRange(DateFrom[i],DateTo[i])) { return true; } } } else { //--- If there are no trading session times return true; } return false; }
下面的函数将在交易时段结束时返回 true。在某些经纪商那里,交易时段结束前的一个小时,点差可能会变得非常大,因此这个函数可以帮助我们避免在这些时间段内进行交易。
//+------------------------------------------------------------------+ //|Check if trading Session has ended | //+------------------------------------------------------------------+ bool CSessions::isSessionEnd(int offsethour=0,int offsetmin=45) { //--- Declarations datetime datefrom,dateto,DateTo[],lastdate=0,sessionend; //--- Find all session times for(int i=0; i<10; i++) { //--- Get the session dates for the current symbol and Day of week if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto)) { //--- Check if the end date's hour is at midnight if(ReturnHour(dateto)==00||ReturnHour(dateto)==24) { //--- Adjust the date to one minute before midnight dateto = Time(TimeTradeServer(),23,59); } //--- Re-adjust DateTo Array size ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2); //--- Assign the last array index dateto value DateTo[int(ArraySize(DateTo))-1] = dateto; } } //--- Check if there are session times if(DateTo.Size()>0) { //--- Assign lastdate a default value lastdate = DateTo[0]; //--- Iterate through the whole array for(uint i=0; i<DateTo.Size(); i++) { //--- Check for the latest date in the array if(DateTo[i]>lastdate) { lastdate = DateTo[i]; } } } else { //--- If there are no trading session times return false; } /* get the current time and modify the hour and minute time to the lastdate variable and assign the new datetime to sessionend variable*/ sessionend = Today(ReturnHour(lastdate),ReturnMinute(lastdate)); //--- Re-adjust the sessionend dates with the minute and hour offsets sessionend = TimeMinusOffset(sessionend,MinutesS(offsetmin)); sessionend = TimeMinusOffset(sessionend,HoursS(offsethour)); //--- Check if sessionend date is more than the current time if(TimeTradeServer()<sessionend) { return false; } return true; }
下面的函数将返回当前日期的交易时段结束时间。在 MQL5 中,交易时段存在一些限制。我注意到,在假期期间,某些交易品种可能会比交易时段所显示的提前很多时间关闭,因此这是需要注意的一个问题。
//+------------------------------------------------------------------+ //|Get Session End datetime | //+------------------------------------------------------------------+ datetime CSessions::SessionEnd(int offsethour=0,int offsetmin=45) { //--- Declarations datetime datefrom,dateto,DateTo[],lastdate=0,sessionend; //--- Find all session times for(int i=0; i<10; i++) { //--- Get the session dates for the current symbol and Day of week if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto)) { //--- Check if the end date's hour is at midnight if(CTV.ReturnHour(dateto)==00||CTV.ReturnHour(dateto)==24) { //--- Adjust the date to one minute before midnight dateto = Time(TimeTradeServer(),23,59); } //--- Re-adjust DateTo Array size ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2); //--- Assign the last array index dateto value DateTo[int(ArraySize(DateTo))-1] = dateto; } } //--- Check if there are session times if(DateTo.Size()>0) { //--- Assign lastdate a default value lastdate = DateTo[0]; //--- Iterate through the whole array for(uint i=0; i<DateTo.Size(); i++) { //--- Check for the latest date in the array if(DateTo[i]>lastdate) { lastdate = DateTo[i]; } } } else { //--- If there are no trading session times return 0; } /* get the current time and modify the hour and minute time to the lastdate variable and assign the new datetime to sessionend variable*/ sessionend = Today(ReturnHour(lastdate),ReturnMinute(lastdate)); //--- Re-adjust the sessionend dates with the minute and hour offsets sessionend = TimeMinusOffset(sessionend,MinutesS(offsetmin)); sessionend = TimeMinusOffset(sessionend,HoursS(offsethour)); //--- return sessionend date return sessionend; }
新闻类
这个类是整个项目中最为关键的部分,也是最大的部分,其代码量单独就超过了1000行。从第2部分开始,我们对这个类以及与公共文件夹中日历数据库交互的代码进行了重大改进。在本文中,我们将创建另一个数据库,但这次数据库将存储在内存中。
内存数据库与存储数据库的比较优势
- 速度:内存数据库直接将数据存储在RAM中,从而显著提高了读写操作的速度。这对于需要实时数据处理和分析的应用程序尤其有益。由于RAM比磁盘存储要快得多,因此从内存数据库中访问数据的速度更快。这可以减少响应时间并提高整体性能。
- 性能:减少的延迟和更快的数据访问转化为更高的吞吐量,这意味着数据库每秒可以处理更多的事务。内存数据库可以更高效地处理大量的数据,因此它们适用于大数据应用、分析和其他密集型计算任务。
我们仍然会使用存储中的数据库,我们会从存储中的数据库中收集数据,并将这些数据转移到我们新的内存数据库中,以便在回测时实现平衡的性能,因为仅使用存储中的数据库会根据你的电脑配置而大幅影响性能。
我们首先从类外部的声明开始,这些声明将用于专家的输入。DBMemoryConnection整数变量将用于保存我们内存数据库的整数连接句柄。Calendar_Importance枚举类型将用于在EA的输入参数中选择不同的事件重要性。Event_Sector枚举类型将用于在专家的输入参数中选择不同的事件领域。Event_Frequency枚举类型将用于在专家的输入参数中选择不同的事件频率。Event_Type枚举类型将用于在专家的输入参数中选择不同的事件类型。Event_Currency枚举类型将用于在专家的输入参数中选择不同的事件货币选项。UpcomingNews Calendar结构变量将存储下一个经济事件的详细信息,以便在其他类/文件中轻松访问,我们在新闻类外部声明了它。
int DBMemoryConnection;//In memory database handle //--- Enumeration for Calendar Importance enum Calendar_Importance { Calendar_Importance_None,//NONE Calendar_Importance_Low,//LOW Calendar_Importance_Moderate,//MODERATE Calendar_Importance_High,//HIGH Calendar_Importance_All//ALL } myImportance; //--- Enumeration for Calendar Sector enum Event_Sector { Event_Sector_None,//NONE Event_Sector_Market,//MARKET Event_Sector_Gdp,//GDP Event_Sector_Jobs,//JOBS Event_Sector_Prices,//PRICES Event_Sector_Money,//MONEY Event_Sector_Trade,//TRADE Event_Sector_Government,//GOVERNMENT Event_Sector_Business,//BUSINESS Event_Sector_Consumer,//CONSUMER Event_Sector_Housing,//HOUSING Event_Sector_Taxes,//TAXES Event_Sector_Holidays,//HOLIDAYS Event_Sector_ALL//ALL } mySector; //--- Enumeration for Calendar Event Frequency enum Event_Frequency { Event_Frequency_None,//NONE Event_Frequency_Week,//WEEK Event_Frequency_Month,//MONTH Event_Frequency_Quarter,//QUARTER Event_Frequency_Year,//YEAR Event_Frequency_Day,//DAY Event_Frequency_ALL//ALL } myFrequency; //--- Enumeration for Calendar Event type enum Event_Type { Event_Type_Event,//EVENT Event_Type_Indicator,//INDICATOR Event_Type_Holiday,//HOLIDAY Event_Type_All//ALL } myType; //--- Enumeration for Calendar Event Currency enum Event_Currency { Event_Currency_Symbol,//SYMBOL CURRENCIES Event_Currency_Margin,//SYMBOL MARGIN Event_Currency_Base,//SYMBOL BASE Event_Currency_Profit,//SYMBOL PROFIT Event_Currency_ALL,//ALL CURRENCIES Event_Currency_NZD_NZ,//NZD -> NZ Event_Currency_EUR_EU,//EUR -> EU Event_Currency_JPY_JP,//JPY -> JP Event_Currency_CAD_CA,//CAD -> CA Event_Currency_AUD_AU,//AUD -> AU Event_Currency_CNY_CN,//CNY -> CN Event_Currency_EUR_IT,//EUR -> IT Event_Currency_SGD_SG,//SGD -> SG Event_Currency_EUR_DE,//EUR -> DE Event_Currency_EUR_FR,//EUR -> FR Event_Currency_BRL_BR,//BRL -> BR Event_Currency_MXN_MX,//MXN -> MX Event_Currency_ZAR_ZA,//ZAR -> ZA Event_Currency_HKD_HK,//HKD -> HK Event_Currency_INR_IN,//INR -> IN Event_Currency_NOK_NO,//NOK -> NO Event_Currency_USD_US,//USD -> US Event_Currency_GBP_GB,//GBP -> GB Event_Currency_CHF_CH,//CHF -> CH Event_Currency_KRW_KR,//KRW -> KW Event_Currency_EUR_ES,//EUR -> ES Event_Currency_SEK_SE,//SEK -> SE Event_Currency_ALL_WW//ALL -> WW } myCurrency; //--- Structure variable to store Calendar next Event data Calendar UpcomingNews;
对新闻类的额外功能扩展:
- 扩展枚举类型 CalendarComponents:新增了 EventInfo_View,用于在日历存储数据库中显示事件详细信息;新增了 Currencies_View,用于显示 MQL5 经济日历中可用的所有货币。
- 结构数组 CalendarContents 的大小从 10 增加到 12,以容纳新增的两个视图:EventInfo_View 和 Currencies_View。
- 声明 DBMemory 变量,其类型为 MQL5CalendarContents 结构,用于存储数据库属性。
- 声明 CalendarData 结构和变量,用于存储公共文件夹中日历数据库中的所有数据。
- 声明函数 GetCalendar,该函数将从公共文件夹中的日历数据库中请求所有过滤后的数据,并将这些数据存储到 CalendarData 结构数组 Data 中。一旦创建了新的内存日历数据库,这些数组数据将被插入其中。
- 声明函数 GetAutoDST,用于从公共文件夹中日历数据库的 AutoDST 表中检索 DST_type 枚举。
- 声明函数 Request_Importance,用于根据 Calendar_Importance 枚举检索事件重要性的字符串请求。
- 声明函数 Request_Frequency,用于根据 Event_Frequency 枚举检索事件频率的字符串请求。
- 声明函数 Request_Sector,用于根据 Event_Sector 枚举检索事件领域的字符串请求。
- 声明函数 Request_Type,用于根据 Event_Type 枚举检索事件类型的字符串请求。
- 声明函数 Request_Currency,用于根据 Event_Currency 枚举检索事件货币的字符串请求。
- 声明函数 EconomicDetailsMemory,该函数将用特定日期的事件填充 NewsTime 日历结构数组。
- 声明函数 CreateEconomicDatabaseMemory,用于创建内存中的日历数据库。
- 声明函数 EconomicNextEvent,该函数将用下一个事件数据更新 UpcomingNews 结构变量。
- 声明函数 GetImpact,用于检索即将发生的事件的影响数据。
- 声明函数 IMPORTANCE,用于将重要性字符串转换为日历事件重要性枚举。
- 声明函数 IMPORTANCE,用于将 Calendar_Importance 枚举转换为日历事件重要性枚举。
- 声明函数 GetImportance,用于将日历事件重要性枚举转换为重要性评级字符串。
- 声明函数 GetImportance_color,用于检索每个日历事件重要性枚举的颜色。
- 声明函数 SECTOR,用于将 Event_Sector 枚举转换为日历事件领域枚举。
- 声明函数 FREQUENCY,用于将 Event_Frequency 枚举转换为日历事件频率枚举。
- 声明函数 TYPE,用于将 Event_Type 枚举转换为日历事件类型枚举。
//+------------------------------------------------------------------+ //|News class | //+------------------------------------------------------------------+ class CNews : private CCandleProperties { //Private Declarations Only accessable by this class/header file private: //-- To keep track of what is in our database enum CalendarComponents { AutoDST_Table,//AutoDST Table CalendarAU_View,//View for DST_AU CalendarNONE_View,//View for DST_NONE CalendarUK_View,//View for DST_UK CalendarUS_View,//View for DST_US EventInfo_View,//View for Event Information Currencies_View,//View for Currencies Record_Table,// Record Table TimeSchedule_Table,//TimeSchedule Table MQL5Calendar_Table,//MQL5Calendar Table AutoDST_Trigger,//Table Trigger for AutoDST Record_Trigger//Table Trigger for Record }; //-- structure to retrieve all the objects in the database struct SQLiteMaster { string type;//will store object's type string name;//will store object's name string tbl_name;//will store table name int rootpage;//will store rootpage string sql;//Will store the sql create statement } DBContents[];//Array of type SQLiteMaster //-- MQL5CalendarContents inherits from SQLiteMaster structure struct MQL5CalendarContents:SQLiteMaster { CalendarComponents Content; string insert;//Will store the sql insert statement } CalendarContents[12],DBMemory;//Array to Store objects in our database CTimeManagement CTime;//TimeManagement Object declaration CDaylightSavings_UK Savings_UK;//DaylightSavings Object for the UK and EU CDaylightSavings_US Savings_US;//DaylightSavings Object for the US CDaylightSavings_AU Savings_AU;//DaylightSavings Object for the AU bool AutoDetectDST(DST_type &dstType);//Function will determine Broker DST DST_type DSTType;//variable of DST_type enumeration declared in the CommonVariables class/header file bool InsertIntoTables(int db,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table void CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table bool CreateCalendarTable(int db,bool &tableExists);//Function for creating a table in a database bool CreateTimeTable(int db,bool &tableExists);//Function for creating a table in a database void CreateCalendarViews(int db);//Function for creating views in a database void CreateRecordTable(int db);//Creates a table to store the record of when last the Calendar database was updated/created string DropRequest;//Variable for dropping tables in the database //-- Function for retrieving the MQL5CalendarContents structure for the enumartion type CalendarComponents MQL5CalendarContents CalendarStruct(CalendarComponents Content) { MQL5CalendarContents Calendar; for(uint i=0;i<CalendarContents.Size();i++) { if(CalendarContents[i].Content==Content) { return CalendarContents[i]; } } return Calendar; } //--- To Store Calendar DB Data struct CalendarData { int EventId;//Event Id string Country;//Event Country string EventName;//Event Name string EventType;//Event Type string EventImportance;//Event Importance string EventCurrency;//Event Currency string EventCode;//Event Code string EventSector;//Event Sector string EventForecast;//Event Forecast Value string EventPreval;//Event Previous Value string EventImpact;//Event Impact string EventFrequency;//Event Frequency string DST_UK;//DST UK string DST_US;//DST US string DST_AU;//DST AU string DST_NONE;//DST NONE } DB_Data[],DB_Cal;//Structure variables //--- Will Retrieve all relevant Calendar data for DB in Memory from DB in Storage void GetCalendar(CalendarData &Data[]) { //--- Open calendar DB in Storage int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if the database was able to be opened { //if opening the database failed if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if the database Calendar exists in the common folder { return;//Returns true when the database was failed to be opened and the file doesn't exist in the common folder } } //--- Get filtered calendar DB data string SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency," "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency," "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ " "Inner Join %s TS on TS.ID=MQ.ID " "Where %s and %s and %s and %s and %s;", CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name, Request_Importance(myImportance),Request_Frequency(myFrequency), Request_Sector(mySector),Request_Type(myType),Request_Currency(myCurrency)); //--- Process Sql request int Request = DatabasePrepare(db,SqlRequest); if(Request==INVALID_HANDLE) { //--- Print details if request failed. Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); Print("SQL"); Print(SqlRequest); } else { //--- Clear data from whole array ArrayRemove(Data,0,WHOLE_ARRAY); //--- create structure variable to get data from request CalendarData data; //Assigning values from the sql query into Data structure array for(int i=0; DatabaseReadBind(Request,data); i++) { //--- Resize Data Array ArrayResize(Data,i+1,i+2); Data[i] = data; } } DatabaseFinalize(Request);//Finalize request //--- Close Calendar database DatabaseClose(db); } //--- Retrieve the AutoDST enumeration data from calendar DB in storage DST_type GetAutoDST() { string Sch_Dst; //--- open the database 'Calendar' in the common folder int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if 'Calendar' failed to be opened { if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if 'Calendar' database exists { Print("Could not find Database!"); return DST_NONE;//return default value when failed. } } //--- Sql query to get AutoDST value string request_text="SELECT DST FROM 'AutoDST'"; //--- Process sql request int request=DatabasePrepare(db,request_text); if(request==INVALID_HANDLE) { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db);//Close Database return DST_NONE;//return default value when failed. } //--- Read Sql request output data if(DatabaseRead(request)) { //-- Store the first column data into string variable Sch_Dst if(!DatabaseColumnText(request,0,Sch_Dst)) { Print("DatabaseRead() failed with code ", GetLastError()); DatabaseFinalize(request);//Finalize request DatabaseClose(db);//Closes the database 'Calendar' return DST_NONE;//return default value when failed. } } DatabaseFinalize(request);//Finalize request DatabaseClose(db);//Closes the database 'Calendar' return (Sch_Dst=="DST_UK")?DST_UK:(Sch_Dst=="DST_US")?DST_US: (Sch_Dst=="DST_AU")?DST_AU:DST_NONE;//Returns the enumeration value for each corresponding string } //--- Retrieve Sql request string for calendar event Importance string Request_Importance(Calendar_Importance Importance) { //--- Constant request prefix string const string constant="MQ.EventImportance"; //--- switch statement for Calendar_Importance enumeration switch(Importance) { case Calendar_Importance_All://String Request for all event Importance return constant+"<>'"+EnumToString(myImportance)+"'"; break; default://String Request for any event Importance return constant+"='"+EnumToString(IMPORTANCE(myImportance))+"'"; break; } } //--- Retrieve Sql request string for calendar event Frequency string Request_Frequency(Event_Frequency Frequency) { //--- Constant request prefix string const string constant="MQ.EventFrequency"; //--- switch statement for Event_Frequency enumeration switch(Frequency) { case Event_Frequency_ALL://String Request for all event frequencies return constant+"<>'"+EnumToString(myFrequency)+"'"; break; default://String Request for any event frequency return constant+"='"+EnumToString(FREQUENCY(myFrequency))+"'"; break; } } //--- Retrieve Sql request string for calendar event Sector string Request_Sector(Event_Sector Sector) { //--- Constant request prefix string const string constant="MQ.EventSector"; //--- switch statement for Event_Sector enumeration switch(Sector) { case Event_Sector_ALL://String Request for all event sectors return constant+"<>'"+EnumToString(mySector)+"'"; break; default://String Request for any event sector return constant+"='"+EnumToString(SECTOR(mySector))+"'"; break; } } //--- Retrieve Sql request string for calendar event type string Request_Type(Event_Type Type) { //--- Constant request prefix string const string constant="MQ.EventType"; //--- switch statement for Event_Type enumeration switch(Type) { case Event_Type_All://String Request for all event types return constant+"<>'"+EnumToString(myType)+"'"; break; default://String request for any event type return constant+"='"+EnumToString(TYPE(myType))+"'"; break; } } //--- Retrieve Sql request string for calendar event Currency string Request_Currency(Event_Currency Currency) { //--- Constant request prefix string and request suffix const string constant_prefix="(MQ.EventCurrency",constant_suffix="')"; //--- switch statement for Event_Currency enumeration switch(Currency) { case Event_Currency_ALL://String Request for all currencies return constant_prefix+"<>'"+EnumToString(myCurrency)+constant_suffix; break; case Event_Currency_Symbol://String Request for all symbol currencies return constant_prefix+"='"+CSymbol.CurrencyBase()+"' or MQ.EventCurrency='"+ CSymbol.CurrencyMargin()+"' or MQ.EventCurrency='"+CSymbol.CurrencyProfit()+constant_suffix; break; case Event_Currency_Margin://String Request for Margin currency return constant_prefix+"='"+CSymbol.CurrencyMargin()+constant_suffix; break; case Event_Currency_Base://String Request for Base currency return constant_prefix+"='"+CSymbol.CurrencyBase()+constant_suffix; break; case Event_Currency_Profit://String Request for Profit currency return constant_prefix+"='"+CSymbol.CurrencyProfit()+constant_suffix; break; case Event_Currency_NZD_NZ://String Request for NZD currency return constant_prefix+"='NZD' and MQ.EventCode='NZ"+constant_suffix; break; case Event_Currency_EUR_EU://String Request for EUR currency and EU code return constant_prefix+"='EUR' and MQ.EventCode='EU"+constant_suffix; break; case Event_Currency_JPY_JP://String Request for JPY currency return constant_prefix+"='JPY' and MQ.EventCode='JP"+constant_suffix; break; case Event_Currency_CAD_CA://String Request for CAD currency return constant_prefix+"='CAD' and MQ.EventCode='CA"+constant_suffix; break; case Event_Currency_AUD_AU://String Request for AUD currency return constant_prefix+"='AUD' and MQ.EventCode='AU"+constant_suffix; break; case Event_Currency_CNY_CN://String Request for CNY currency return constant_prefix+"='CNY' and MQ.EventCode='CN"+constant_suffix; break; case Event_Currency_EUR_IT://String Request for EUR currency and IT code return constant_prefix+"='EUR' and MQ.EventCode='IT"+constant_suffix; break; case Event_Currency_SGD_SG://String Request for SGD currency return constant_prefix+"='SGD' and MQ.EventCode='SG"+constant_suffix; break; case Event_Currency_EUR_DE://String Request for EUR currency and DE code return constant_prefix+"='EUR' and MQ.EventCode='DE"+constant_suffix; break; case Event_Currency_EUR_FR://String Request for EUR currency and FR code return constant_prefix+"='EUR' and MQ.EventCode='FR"+constant_suffix; break; case Event_Currency_BRL_BR://String Request for BRL currency return constant_prefix+"='BRL' and MQ.EventCode='BR"+constant_suffix; break; case Event_Currency_MXN_MX://String Request for MXN currency return constant_prefix+"='MXN' and MQ.EventCode='MX"+constant_suffix; break; case Event_Currency_ZAR_ZA://String Request for ZAR currency return constant_prefix+"='ZAR' and MQ.EventCode='ZA"+constant_suffix; break; case Event_Currency_HKD_HK://String Request for HKD currency return constant_prefix+"='HKD' and MQ.EventCode='HK"+constant_suffix; break; case Event_Currency_INR_IN://String Request for INR currency return constant_prefix+"='INR' and MQ.EventCode='IN"+constant_suffix; break; case Event_Currency_NOK_NO://String Request for NOK currency return constant_prefix+"='NOK' and MQ.EventCode='NO"+constant_suffix; break; case Event_Currency_USD_US://String Request for USD currency return constant_prefix+"='USD' and MQ.EventCode='US"+constant_suffix; break; case Event_Currency_GBP_GB://String Request for GBP currency return constant_prefix+"='GBP' and MQ.EventCode='GB"+constant_suffix; break; case Event_Currency_CHF_CH://String Request for CHF currency return constant_prefix+"='CHF' and MQ.EventCode='CH"+constant_suffix; break; case Event_Currency_KRW_KR://String Request for KRW currency return constant_prefix+"='KRW' and MQ.EventCode='KR"+constant_suffix; break; case Event_Currency_EUR_ES://String Request for EUR currency and ES code return constant_prefix+"='EUR' and MQ.EventCode='ES"+constant_suffix; break; case Event_Currency_SEK_SE://String Request for SEK currency return constant_prefix+"='SEK' and MQ.EventCode='SE"+constant_suffix; break; case Event_Currency_ALL_WW://String Request for ALL currency return constant_prefix+"='ALL' and MQ.EventCode='WW"+constant_suffix; break; default://String Request for no currencies return constant_prefix+"='"+constant_suffix; break; } } //Public declarations accessable via a class's Object public: CNews(void);//Constructor ~CNews(void);//Destructor void CreateEconomicDatabase();//Creates the Calendar database for a specific Broker datetime GetLatestNewsDate();//Gets the latest/newest date in the Calendar database void EconomicDetails(Calendar &NewsTime[],datetime date_from=0,datetime date_to=0);//Gets values from the MQL5 economic Calendar void EconomicDetailsMemory(Calendar &NewsTime[],datetime date);//Gets values from the MQL5 DB Calendar in Memory void CreateEconomicDatabaseMemory();//Create calendar database in memory void EconomicNextEvent(datetime date=0);//Will update UpcomingNews structure variable with the next event data bool UpdateRecords();//Checks if the main Calendar database needs an update or not ENUM_CALENDAR_EVENT_IMPACT GetImpact();//Will retrieve Upcoming Event Impact data //--- Convert Importance string into Calendar Event Importance Enumeration ENUM_CALENDAR_EVENT_IMPORTANCE IMPORTANCE(string Importance) { //--- Calendar Importance is High if(Importance==EnumToString(CALENDAR_IMPORTANCE_HIGH)) { return CALENDAR_IMPORTANCE_HIGH; } else //--- Calendar Importance is Moderate if(Importance==EnumToString(CALENDAR_IMPORTANCE_MODERATE)) { return CALENDAR_IMPORTANCE_MODERATE; } else //--- Calendar Importance is Low if(Importance==EnumToString(CALENDAR_IMPORTANCE_LOW)) { return CALENDAR_IMPORTANCE_LOW; } else //--- Calendar Importance is None { return CALENDAR_IMPORTANCE_NONE; } } //--- Convert Calendar_Importance Enumeration into Calendar Event Importance Enumeration ENUM_CALENDAR_EVENT_IMPORTANCE IMPORTANCE(Calendar_Importance Importance) { //--- switch statement for Calendar_Importance enumeration switch(Importance) { case Calendar_Importance_None://None return CALENDAR_IMPORTANCE_NONE; break; case Calendar_Importance_Low://Low return CALENDAR_IMPORTANCE_LOW; break; case Calendar_Importance_Moderate://Moderate return CALENDAR_IMPORTANCE_MODERATE; break; case Calendar_Importance_High://High return CALENDAR_IMPORTANCE_HIGH; break; default://None return CALENDAR_IMPORTANCE_NONE; break; } } //--- Convert Calendar Event Importance Enumeration into string Importance Rating string GetImportance(ENUM_CALENDAR_EVENT_IMPORTANCE Importance) { //--- switch statement for ENUM_CALENDAR_EVENT_IMPORTANCE enumeration switch(Importance) { case CALENDAR_IMPORTANCE_HIGH://High return "HIGH"; break; case CALENDAR_IMPORTANCE_MODERATE://Moderate return "MODERATE"; break; case CALENDAR_IMPORTANCE_LOW://Low return "LOW"; break; default://None return "NONE"; break; } } //--- Retrieve color for each Calendar Event Importance Enumeration color GetImportance_color(ENUM_CALENDAR_EVENT_IMPORTANCE Importance) { //--- switch statement for ENUM_CALENDAR_EVENT_IMPORTANCE enumeration switch(Importance) { case CALENDAR_IMPORTANCE_HIGH://High return clrRed; break; case CALENDAR_IMPORTANCE_MODERATE://Moderate return clrOrange; break; case CALENDAR_IMPORTANCE_LOW://Low return (isLightMode)?clrBlue:clrLightBlue; break; default://None return (isLightMode)?clrBlack:clrWheat; break; } } //--- Convert Event_Sector Enumeration into Calendar Event Sector Enumeration ENUM_CALENDAR_EVENT_SECTOR SECTOR(Event_Sector Sector) { //--- switch statement for Event_Sector enumeration switch(Sector) { case Event_Sector_None://NONE return CALENDAR_SECTOR_NONE; break; case Event_Sector_Market://MARKET return CALENDAR_SECTOR_MARKET; break; case Event_Sector_Gdp://GDP return CALENDAR_SECTOR_GDP; break; case Event_Sector_Jobs://JOBS return CALENDAR_SECTOR_JOBS; break; case Event_Sector_Prices://PRICES return CALENDAR_SECTOR_PRICES; break; case Event_Sector_Money://MONEY return CALENDAR_SECTOR_MONEY; break; case Event_Sector_Trade://TRADE return CALENDAR_SECTOR_TRADE; break; case Event_Sector_Government://GOVERNMENT return CALENDAR_SECTOR_GOVERNMENT; break; case Event_Sector_Business://BUSINESS return CALENDAR_SECTOR_BUSINESS; break; case Event_Sector_Consumer://CONSUMER return CALENDAR_SECTOR_CONSUMER; break; case Event_Sector_Housing://HOUSING return CALENDAR_SECTOR_HOUSING; break; case Event_Sector_Taxes://TAXES return CALENDAR_SECTOR_TAXES; break; case Event_Sector_Holidays://HOLIDAYS return CALENDAR_SECTOR_HOLIDAYS; break; default://Unknown return CALENDAR_SECTOR_NONE; break; } } //--- Convert Event_Frequency Enumeration into Calendar Event Frequency Enumeration ENUM_CALENDAR_EVENT_FREQUENCY FREQUENCY(Event_Frequency Frequency) { //--- switch statement for Event_Frequency enumeration switch(Frequency) { case Event_Frequency_None://NONE return CALENDAR_FREQUENCY_NONE; break; case Event_Frequency_Day://DAY return CALENDAR_FREQUENCY_DAY; break; case Event_Frequency_Week://WEEK return CALENDAR_FREQUENCY_WEEK; break; case Event_Frequency_Month://MONTH return CALENDAR_FREQUENCY_MONTH; break; case Event_Frequency_Quarter://QUARTER return CALENDAR_FREQUENCY_QUARTER; break; case Event_Frequency_Year://YEAR return CALENDAR_FREQUENCY_YEAR; break; default://Unknown return CALENDAR_FREQUENCY_NONE; break; } } //--- Convert Event_Type Enumeration into Calendar Event Type Enumeration ENUM_CALENDAR_EVENT_TYPE TYPE(Event_Type Type) { //--- switch statement for Event_Type enumeration switch(Type) { case Event_Type_Event://EVENT return CALENDAR_TYPE_EVENT; break; case Event_Type_Indicator://INDICATOR return CALENDAR_TYPE_INDICATOR; break; case Event_Type_Holiday://HOLIDAY return CALENDAR_TYPE_HOLIDAY; break; default://Unknown return CALENDAR_TYPE_EVENT; break; } } };
我们首先会查看 GetCalendar 函数中的 SQL 语句,该语句将从公共文件夹中的日历数据库请求所有数据,以便为我们的内存日历数据库所用。在这个请求中,我们选择 MQL5Calendar 表和 TimeSchedule 表中的所有列,并将这两个表按照它们的 ID 相同的条件进行连接。然后,我们根据交易者/用户在EA输入参数中为新闻设置所选择的枚举类型来过滤数据。
//--- Get filtered calendar DB data string SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency," "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency," "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ " "Inner Join %s TS on TS.ID=MQ.ID " "Where %s and %s and %s and %s and %s;", CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name, Request_Importance(myImportance),Request_Frequency(myFrequency), Request_Sector(mySector),Request_Type(myType),Request_Currency(myCurrency));
我们将查看针对 EURUSD 交易品种的以下新闻设置配置的 SQL 请求。
如下面所示,当我们选择“全部”作为日历重要性时,我们有意不转换我们的 Calendar_Importance 枚举变量 myImportance,因为没有任何事件的重要性值为 'Calendar_Importance_All'。因此,我们可以轻松地选择所有事件重要性不等于 'Calendar_Importance_All' 的事件。同样的逻辑也适用于所有被设置为“全部”的新闻设置输入参数。
case Calendar_Importance_All://String Request for all event Importance return constant+"<>'"+EnumToString(myImportance)+"'";
Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency,MQ.EventCode,MQ.EventSector, MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency,TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from MQL5Calendar MQ Inner Join TimeSchedule TS on TS.ID=MQ.ID Where MQ.EventImportance<>'Calendar_Importance_All' and MQ.EventFrequency<>'Event_Frequency_ALL' and MQ.EventSector<>'Event_Sector_ALL' and MQ.EventType<>'Event_Type_All' and (MQ.EventCurrency='EUR' or MQ.EventCurrency='EUR' or MQ.EventCurrency='USD');
我们将再查看一个来自 GetCalendar 函数的 SQL 请求,针对 EURUSD 交易品种的以下新闻设置配置。
如下面所示,当我们选择除“全部”之外的任何其他选项作为日历重要性时,我们会将我们的 Calendar_Importance 枚举变量 myImportance 转换为枚举类型 ENUM_CALENDAR_EVENT_IMPORTANCE。这样,字符串就可以与存储在 MQL5Calendar 表中的字符串匹配,从而正确获取特定类型事件的重要性。
default://String Request for any event Importance return constant+"='"+EnumToString(IMPORTANCE(myImportance))+"'";
Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency,MQ.EventCode,MQ.EventSector,MQ.EventForecast, MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency,TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from MQL5Calendar MQ Inner Join TimeSchedule TS on TS.ID=MQ.ID Where MQ.EventImportance='CALENDAR_IMPORTANCE_HIGH' and MQ.EventFrequency='CALENDAR_FREQUENCY_MONTH' and MQ.EventSector='CALENDAR_SECTOR_JOBS' and MQ.EventType='CALENDAR_TYPE_INDICATOR' and (MQ.EventCurrency<>'Event_Currency_ALL');
在新闻类的构造函数中,我们需要为公共文件夹中日历数据库的新视图初始化数组索引。对于“事件信息”视图,我们将按照以下方式初始化数组索引。
//--- initializing properties for the EventInfo view CalendarContents[5].Content = EventInfo_View; CalendarContents[5].name = "Event Info"; CalendarContents[5].sql = "CREATE VIEW IF NOT EXISTS 'Event Info' " "AS SELECT EVENTID as 'ID',COUNTRY as 'Country',EVENTNAME as 'Name'," "REPLACE(EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',REPLACE(EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector'," "REPLACE(EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',EVENTCURRENCY as 'Currency' " "FROM MQL5Calendar GROUP BY \"Name\" ORDER BY \"Country\" Asc," "CASE \"Importance\" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,\"Sector\" Desc;"; CalendarContents[5].tbl_name = "Event Info"; CalendarContents[5].type = "view";
让我们来分析创建“事件信息”视图的 SQL 语句。首先,我们仅在该视图尚不存在的情况下创建它。然后,我们选择 MQL5Calendar 表中的以下列: 将 'EVENTID' 列重命名为 'ID',将 'COUNTRY' 列重命名为 'Country',将 'EVENTNAME' 列重命名为 'Name',将 'EVENTTYPE' 列中的文本 'CALENDAR_TYPE_' 替换为空字符串,并将其重命名为 'Type',将 'EVENTSECTOR' 列中的文本 'CALENDAR_SECTOR_' 替换为空字符串,并将其重命名为 'Sector',将 'EVENTIMPORTANCE' 列中的文本 'CALENDAR_IMPORTANCE_' 替换为空字符串,并将其重命名为 'Importance',将 'EVENTCURRENCY' 列重命名为 'Currency'。然后,我们按照 'EVENTNAME'(现为 'Name')对查询结果进行分组,这样具有相同事件名称的事件就不会在视图中重复显示多次。接下来,我们为查询结果设置排序顺序。首先,我们按 'Country' 升序排列结果,因此以字母 A 开头的国家(如澳大利亚)将首先显示。然后,我们按 'EVENTIMPORTANCE'(现为 'Importance')排序,我的目标是显示重要性最高的事件。为此,我们需要为重要性字符串/文本值分配优先级。在这种情况下,当重要性为 'HIGH' 时,它将获得最高优先级,'MODERATE' 获得第二优先级,'LOW' 获得第三优先级,而其他任何值则获得最低优先级。此外,我们还按 'EVENTSECTOR'(现为 'Sector')降序排列查询结果。视图的示例如下所示。
CREATE VIEW IF NOT EXISTS 'Event Info' AS SELECT MQ.EVENTID as 'ID',MQ.COUNTRY as 'Country',MQ.EVENTNAME as 'Name',REPLACE(MQ.EVENTTYPE, 'CALENDAR_TYPE_','') as 'Type',REPLACE(MQ.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector',REPLACE(MQ.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',MQ.EVENTCURRENCY as 'Currency' FROM MQL5Calendar MQ INNER JOIN TimeSchedule TS on TS.ID=MQ.ID GROUP BY "Name" ORDER BY "Country" Asc,CASE "Importance" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,"Sector" Desc;
ID Country Name Type Sector Importance Currency 36030006 Australia RBA Governor Lowe Speech EVENT MONEY HIGH AUD 36030008 Australia RBA Interest Rate Decision INDICATOR MONEY HIGH AUD 36010029 Australia PPI q/q INDICATOR PRICES MODERATE AUD 36030014 Australia RBA Trimmed Mean CPI q/q INDICATOR PRICES MODERATE AUD 36030009 Australia RBA Weighted Median CPI q/q INDICATOR PRICES MODERATE AUD 36010031 Australia Wage Price Index q/q INDICATOR PRICES MODERATE AUD 36030026 Australia RBA Assistant Governor Boulton Speech EVENT MONEY MODERATE AUD 36030024 Australia RBA Assistant Governor Bullock Speech EVENT MONEY MODERATE AUD 36030025 Australia RBA Assistant Governor Ellis Speech EVENT MONEY MODERATE AUD 62 lines later... 76020002 Brazil BCB Interest Rate Decision INDICATOR MONEY HIGH BRL 76020004 Brazil BCB Inflation Report EVENT PRICES MODERATE BRL 76050001 Brazil FIPE CPI m/m INDICATOR PRICES MODERATE BRL 76010005 Brazil Mid-Month CPI m/m INDICATOR PRICES MODERATE BRL 76020001 Brazil BCB Focus Market Report EVENT MONEY MODERATE BRL 76020003 Brazil BCB MPC (Copom) Minutes EVENT MONEY MODERATE BRL 76020005 Brazil BCB National Monetary Council Meeting EVENT MONEY MODERATE BRL 76010009 Brazil Unemployment Rate 3-months INDICATOR JOBS MODERATE BRL 76020010 Brazil Nominal Budget Balance INDICATOR GOVERNMENT MODERATE BRL 76020011 Brazil Primary Budget balance INDICATOR GOVERNMENT MODERATE BRL 76010014 Brazil Services Volume m/m INDICATOR BUSINESS MODERATE BRL 98 lines later... 124040017 Canada BoC Governor Macklem Speech EVENT MONEY HIGH CAD 124040003 Canada BoC Governor Poloz Speech EVENT MONEY HIGH CAD 124040006 Canada BoC Interest Rate Decision INDICATOR MONEY HIGH CAD 124040009 Canada BoC Monetary Policy Report Press Conference EVENT MONEY HIGH CAD 124010011 Canada Employment Change INDICATOR JOBS HIGH CAD 124010021 Canada GDP m/m INDICATOR GDP HIGH CAD 124010008 Canada Core Retail Sales m/m INDICATOR CONSUMER HIGH CAD 124020001 Canada Ivey PMI INDICATOR BUSINESS HIGH CAD 124010024 Canada IPPI m/m INDICATOR PRICES MODERATE CAD 124010026 Canada RMPI m/m INDICATOR PRICES MODERATE CAD 124040001 Canada BoC Business Outlook Survey EVENT MONEY MODERATE CAD
对于我们的货币视图,我们从 MQL5Calendar 表中选择唯一的EventCurrency 和 EventCode。
//--- initializing properties for the Currencies view CalendarContents[6].Content = Currencies_View; CalendarContents[6].name = "Currencies"; CalendarContents[6].sql = "CREATE VIEW IF NOT EXISTS Currencies AS " "SELECT Distinct EventCurrency as 'Currency',EventCode as 'Code' FROM 'MQL5Calendar';"; CalendarContents[6].tbl_name = "Currencies"; CalendarContents[6].type = "view";
SELECT * FROM 'Currencies';
Currency Code NZD NZ EUR EU JPY JP CAD CA AUD AU CNY CN EUR IT SGD SG EUR DE EUR FR BRL BR MXN MX ZAR ZA HKD HK INR IN NOK NO USD US GBP GB CHF CH KRW KR EUR ES SEK SE ALL WW
现在我们将初始化将存在于我们内存数据库中的 MQL5Calendar 表的属性。这个表将是一个大表,本质上是存储数据库中各个表的组合,这些表包括 MQL5Calendar 和 TimeSchedule。
//-- initializing properties for the MQL5Calendar table for DB in System Memory DBMemory.Content = MQL5Calendar_Table; DBMemory.name = "MQL5Calendar"; DBMemory.sql = "CREATE TABLE IF NOT EXISTS MQL5Calendar(EVENTID INT NOT NULL,COUNTRY TEXT NOT NULL," "EVENTNAME TEXT NOT NULL,EVENTTYPE TEXT NOT NULL,EVENTIMPORTANCE TEXT NOT NULL," "EVENTCURRENCY TEXT NOT NULL,EVENTCODE TEXT NOT NULL,EVENTSECTOR TEXT NOT NULL," "EVENTFORECAST TEXT NOT NULL,EVENTPREVALUE TEXT NOT NULL,EVENTIMPACT TEXT NOT NULL," "EVENTFREQUENCY TEXT NOT NULL,DST_UK TEXT NOT NULL,DST_US TEXT NOT NULL," "DST_AU TEXT NOT NULL,DST_NONE TEXT NOT NULL)STRICT;"; DBMemory.tbl_name="MQL5Calendar"; DBMemory.type = "table"; DBMemory.insert = "INSERT INTO 'MQL5Calendar'(EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTCURRENCY,EVENTCODE," "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY,DST_UK,DST_US,DST_AU,DST_NONE) " "VALUES (%d,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', '%s', '%s');";
在我们的析构函数中,我们关闭与内存中数据库的连接。关闭与内存中数据库的连接将删除整个数据库。因此,我们仅在不再需要数据库时才关闭连接。
//+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CNews::~CNews(void) { if(FileIsExist(NEWS_TEXT_FILE,FILE_COMMON))//Check if the news database open text file exists { FileDelete(NEWS_TEXT_FILE,FILE_COMMON); } DatabaseClose(DBMemoryConnection);//Close DB in memory }
之前在我们的 UpdateRecords 函数中,我们经历了一系列步骤来检查是否需要更新存储中的日历数据库。这一系列步骤如下:
- 我们检查公共文件夹中是否存在日历数据库,如果数据库不存在,我们执行更新。
- 我们检查数据库中是否存在所有数据库对象,以及它们的 SQL 语句是否符合我们的预期,如果不符合,我们执行更新。
- 我们检查 Records 表中的日期是否等于当前日期,如果不等于,我们执行更新。
在本文中,我们将在这一系列步骤中新增一个步骤。新增步骤的目的是检查 Calendar_NONE 视图中的新闻数据是否准确。我注意到,有时 MQL5 日历中的新闻数据会随时间发生变化。如果我们存储的新闻数据没有变化,我们需要能够检查我们存储的数据与从 MQL5 日历更新的数据之间是否存在不一致之处。
在下面的代码中,我们使用 EconomicDetails 函数检索当天的新闻数据,并将这些数据存储到 TodayNews 数组中。一旦新闻数据存储到 TodayNews 数组中,我们遍历数组中的每个新闻事件,并检查是否在 Calendar_NONE 视图中找到匹配项。如果找不到匹配项,我们将执行更新。如果所有新闻数据在 Calendar_NONE 视图中都有匹配项,我们则不对存储中的数据库进行任何更新。
Calendar TodaysNews[]; datetime Today = CTime.Time(TimeTradeServer(),0,0,0); EconomicDetails(TodaysNews,Today,Today+CTime.DaysS()); for(uint i=0;i<TodaysNews.Size();i++) { request_text=StringFormat("SELECT ID FROM %s where Replace(Date,'.','-')=Replace('%s','.','-') and ID=%d;", CalendarStruct(CalendarNONE_View).name,TodaysNews[i].EventDate,TodaysNews[i].EventId); request=DatabasePrepare(db,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseFinalize(request); DatabaseClose(db); return perform_update; } //PrintFormat(request_text); if(!DatabaseRead(request))//Will be true if there are results from the sql query/request { DatabaseFinalize(request); DatabaseClose(db); return perform_update; } DatabaseFinalize(request); } DatabaseClose(db);//Closes the database perform_update=false; return perform_update;
的代码将负责创建内存中的数据库。首先,我们打开与数据库的连接,然后如果 MQL5Calendar 表已经存在,我们将其删除,接着创建 MQL5Calendar 表。表创建完成后,我们从 GetCalendar 函数中获取所有相关数据,然后将从该函数检索到的所有数据插入到我们内存数据库中的 MQL5Calendar 表中。此外,我们清空整个 DB_Data 数组,并在变量 MySchedule 中设置我们的夏令时(DST)计划。对于在策略测试器之外的交易,用户/交易者将无法手动更改夏令时计划,这是为了防止配置错误的夏令时计划,因为配置夏令时计划仅在策略测试器中才是必要的。
//+------------------------------------------------------------------+ //|Create calendar database in memory | //+------------------------------------------------------------------+ void CNews::CreateEconomicDatabaseMemory() { //--- Open/create the database in memory DBMemoryConnection=DatabaseOpen(NEWS_DATABASE_MEMORY,DATABASE_OPEN_MEMORY); if(DBMemoryConnection==INVALID_HANDLE)//Checks if the database failed to open/create { Print("DB: ",NEWS_DATABASE_MEMORY, " open failed with code ", GetLastError()); return;//will terminate execution of the rest of the code below } //--- Drop the table if it already exists DatabaseExecute(DBMemoryConnection,StringFormat("Drop table IF EXISTS %s",DBMemory.name)); //--- Attempt to create the table if(!DatabaseExecute(DBMemoryConnection,DBMemory.sql)) { Print("DB: create the Calendar table failed with code ", GetLastError()); return; } //--- Check if the table exists if(DatabaseTableExists(DBMemoryConnection,DBMemory.tbl_name)) { //--- Get all news data and time from the database in storage GetCalendar(DB_Data); //--- Insert all the news data and times into the table for(uint i=0;i<DB_Data.Size();i++) { string request_text=StringFormat(DBMemory.insert,DB_Data[i].EventId,DB_Data[i].Country, DB_Data[i].EventName,DB_Data[i].EventType,DB_Data[i].EventImportance, DB_Data[i].EventCurrency,DB_Data[i].EventCode,DB_Data[i].EventSector, DB_Data[i].EventForecast,DB_Data[i].EventPreval,DB_Data[i].EventImpact, DB_Data[i].EventFrequency,DB_Data[i].DST_UK,DB_Data[i].DST_US, DB_Data[i].DST_AU,DB_Data[i].DST_NONE); if(!DatabaseExecute(DBMemoryConnection, request_text))//Will attempt to run this sql request/query { //--- failed to run sql request/query Print(GetLastError()); PrintFormat(request_text); return; } } } //--- Remove all data from the array ArrayRemove(DB_Data,0,WHOLE_ARRAY); //--- Assign the DST schedule MySchedule = (MQLInfoInteger(MQL_TESTER))?(MyDST==AutoDst_Selection)?GetAutoDST():MySchedule:DST_NONE; }
好的,接下来的函数 EconomicDetailsMemory 会检索在特定日期发生的所有新闻事件,然后将新闻数据存储在通过引用传递的 NewsTime 数组中。
//+------------------------------------------------------------------+ //|Gets values from the MQL5 DB Calendar in Memory | //+------------------------------------------------------------------+ void CNews::EconomicDetailsMemory(Calendar &NewsTime[],datetime date) { //--- SQL query to retrieve news data for a certain date string request_text=StringFormat("WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name',EventType as 'Type'" ",EventImportance as 'Importance',%s as 'CTime',EventCurrency as 'Currency',EventCode as 'Code'," "EventSector as 'Sector',EventForecast as 'Forecast',EventPrevalue as 'Prevalue',EventImpact as'Impact'," "EventFrequency as 'Freq',RANK() OVER (PARTITION BY %s Order BY CASE EventPrevalue WHEN 'None' " "THEN 2 ELSE 1 END,CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END,CASE EventImportance WHEN " "'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN 'CALENDAR_IMPORTANCE_LOW'" " THEN 3 ELSE 4 END) Ranking FROM %s) SELECT Id,Country,Name,Type,Importance,CTime,Currency,Code,Sector," "Forecast,Prevalue,Impact,Freq FROM MySubQuery where Date(Replace(CTime,'.','-'))=Date(Replace('%s','.','-')) and " "Ranking<2 Group by CTime;",EnumToString(MySchedule),EnumToString(MySchedule),DBMemory.name, TimeToString(date)); int request=DatabasePrepare(DBMemoryConnection,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_MEMORY, " request failed with code ", GetLastError()); PrintFormat(request_text); } //--- Calendar structure variable Calendar ReadDB_Data; //--- Remove any data in the array ArrayRemove(NewsTime,0,WHOLE_ARRAY); for(int i=0; DatabaseReadBind(request,ReadDB_Data); i++)//Will read all the results from the sql query/request { //--- Resize array NewsTime ArrayResize(NewsTime,i+1,i+2); //--- Assign calendar structure values into NewsTime array index NewsTime[i] = ReadDB_Data; } //--- Removes a request created in DatabasePrepare() DatabaseFinalize(request); }
让我们来分解这个 SQL 查询,因为它比我们之前的任何查询都要复杂。关于 WITH 子句 和 RANK() 函数 的使用。
什么是 WITH 子句,它是如何工作的?
WITH 子句,也称为公用表表达式(CTE),用于定义临时的结果集,你可以在 SELECT、INSERT、UPDATE 或 DELETE 语句中引用这些结果集。WITH 子句通过将复杂的查询分解为更简单的部分,使查询更容易理解和维护。它还可以通过重用代价高昂的子查询的结果来提高性能。CTE 是临时的,仅在查询执行期间存在。它们不会在数据库中创建任何永久对象。
什么是 RANK() 函数,它是如何工作的?
RANK() 函数用于根据一个或多个列中的值为结果集中的每一行分配唯一的排名。根据指定的条件对行进行排序,并相应地分配排名。RANK() 函数是 SQL 中的窗口函数之一,这意味着它会在一个窗口(或行的子集)上操作,并且可以为输入集中的每一行返回多行。RANK() 函数根据窗口函数定义中的 ORDER BY 子句中指定的顺序为每一行分配排名。如果多行在指定用于排序的列中具有相同的值,它们将获得相同的排名,并且下一个排名将根据相同排名的数量跳过。可选的 PARTITION BY 会将结果集划分为分区,并且 RANK() 函数将独立应用于每个分区。
在下面突出显示的 WITH 子句中,我们选择了以下字段:EventId、Country、EventName、EventType、EventImportance、DST_NONE(用户/交易者在EA输入中设置的夏令时计划)、EventCurrency、EventCode、EventSector、EventForecast、EventPrevalue、EventImpact 和 EventFrequency。然后我们使用了一个排名函数,这个函数的目的是为每个 SELECT 结果分配一个排名。对于唯一的事件时间(DST_NONE),这个排名将始终为 1。如果我们在同一事件时间有多个事件,那么我们将应用排名。因此,如果事件的 EventPrevalue 等于 'None',它将获得排名 2,否则它将获得排名 1,其余的 ORDER BY 子句也是如此。
WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name',EventType as 'Type',EventImportance as 'Importance', DST_NONE as 'CTime',EventCurrency as 'Currency',EventCode as 'Code',EventSector as 'Sector',EventForecast as 'Forecast', EventPrevalue as 'Prevalue',EventImpact as'Impact',EventFrequency as 'Freq',RANK() OVER (PARTITION BY DST_NONE Order BY CASE EventPrevalue WHEN 'None' THEN 2 ELSE 1 END,CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END, CASE EventImportance WHEN 'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN 'CALENDAR_IMPORTANCE_LOW' THEN 3 ELSE 4 END) Ranking FROM MQL5Calendar) SELECT Id,Country,Name,Type, Importance,CTime,Currency,Code,Sector,Forecast,Prevalue,Impact,Freq FROM MySubQuery where Date(Replace(CTime,'.','-'))=Date(Replace('2024.07.30 00:00','.','-')) and Ranking<2 Group by CTime;
以下是公用表表达式(CTE,MySubQuery)结果的一个示例,我标出了那些将从结果中被排除的事件,因为它们的排名超过了 1。我们只考虑排名小于 2 的事件,然后按时间对结果进行分组。因为在图表上绘制事件对象时,我们不希望创建多个具有相同时间的事件对象,我们只想显示最重要的那个事件。
Id Country Name Type Importance CTime Currency Code Sector Forecast Prevalue Impact Freq Ranking 392030007 Japan Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 2500000 2600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 392050002 Japan Jobs to Applicants Ratio CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 1240000 1240000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 36010001 Australia Building Approvals m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 03:30 AUD AU CALENDAR_SECTOR_BUSINESS -900000 5500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 36010002 Australia Private House Approvals m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 03:30 AUD AU CALENDAR_SECTOR_BUSINESS None 2100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 250010005 France GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_GDP 200000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 250010006 France GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_GDP 1000000 1100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 250010008 France Consumer Spending m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_CONSUMER 800000 1500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 756050001 Switzerland KOF Economic Barometer CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 CHF CH CALENDAR_SECTOR_BUSINESS 101500000 102700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 724010001 Spain CPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 200000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 724010003 Spain HICP m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 300000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 724010005 Spain GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_GDP 300000 800000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 724010002 Spain CPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 3000000 3400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 724010004 Spain HICP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_PRICES 3500000 3600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 724010006 Spain GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 EUR ES CALENDAR_SECTOR_GDP 1900000 2500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 5 752020001 Sweden Business Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_BUSINESS 95500000 97300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020002 Sweden Manufacturing Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_BUSINESS 99000000 99200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020003 Sweden Consumer Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_CONSUMER 95300000 93300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020004 Sweden Inflation Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_CONSUMER 6300000 6200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 752020005 Sweden Economic Tendency Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 09:00 SEK SE CALENDAR_SECTOR_BUSINESS 94800000 96300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 5 276010008 Germany GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 10:00 EUR DE CALENDAR_SECTOR_GDP 100000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 380010020 Italy GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 10:00 EUR IT CALENDAR_SECTOR_GDP 200000 300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 276010009 Germany GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 10:00 EUR DE CALENDAR_SECTOR_GDP -400000 -900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 380010021 Italy GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 10:00 EUR IT CALENDAR_SECTOR_GDP 400000 700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 4 999030016 European Union GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_GDP 200000 300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 999030017 European Union GDP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_GDP 400000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 999040003 European Union Industrial Confidence Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS -9700000 -10100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040004 European Union Services Sentiment Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS 8300000 6500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040005 European Union Economic Sentiment Indicator CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS 95300000 95900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040006 European Union Consumer Confidence Index CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_CONSUMER -13000000 -13000000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040007 European Union Consumer Price Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_CONSUMER 14400000 13100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 999040008 European Union Industry Selling Price Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_BUSINESS 6300000 6100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 3 380020007 Italy 10-Year BTP Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 11:30 EUR IT CALENDAR_SECTOR_MARKET None 4010000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 1 380020005 Italy 5-Year BTP Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:30 EUR IT CALENDAR_SECTOR_MARKET None 3550000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 2 826130002 United Kingdom 10-Year Treasury Gilt Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 11:30 GBP GB CALENDAR_SECTOR_MARKET None 4371000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 2 724080001 Spain Business Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 12:00 EUR ES CALENDAR_SECTOR_BUSINESS -4100000 -5700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 76030002 Brazil FGV IGP-M Inflation Index m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 13:00 BRL BR CALENDAR_SECTOR_PRICES 1000000 810000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484020016 Mexico GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 14:00 MXN MX CALENDAR_SECTOR_GDP 0 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 276010020 Germany CPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES 0 100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 276010022 Germany HICP m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES -100000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 76010012 Brazil PPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 BRL BR CALENDAR_SECTOR_PRICES 700000 450000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 484020017 Mexico GDP n.s.a. y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 14:00 MXN MX CALENDAR_SECTOR_GDP 2000000 1600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 2 276010021 Germany CPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES 2200000 2200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 6 276010023 Germany HICP y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 14:00 EUR DE CALENDAR_SECTOR_PRICES 2500000 2500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 6 76010013 Brazil PPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 14:00 BRL BR CALENDAR_SECTOR_PRICES 2200000 170000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 6 840170001 United States S&P/CS HPI Composite-20 y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 6800000 7200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840110001 United States HPI m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 300000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840110002 United States HPI y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 5700000 6300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840110003 United States HPI CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 427700000 424300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840170002 United States S&P/CS HPI Composite-20 n.s.a. m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 700000 1400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840170003 United States S&P/CS HPI Composite-20 s.a. m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 200000 400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 2 840030021 United States JOLTS Job Openings CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 16:00 USD US CALENDAR_SECTOR_JOBS 7979000 8140000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840180002 United States CB Consumer Confidence Index CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 16:00 USD US CALENDAR_SECTOR_CONSUMER 108000000 100400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840060003 United States Dallas Fed Services Revenues CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 16:30 USD US CALENDAR_SECTOR_BUSINESS 3900000 1900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840060004 United States Dallas Fed Services Business Activity CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 16:30 USD US CALENDAR_SECTOR_BUSINESS -6700000 -4100000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484010001 Mexico Fiscal Balance CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 22:30 MXN MX CALENDAR_SECTOR_TRADE -900000 -174071000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1
最终结果如下所示。
Id Country Name Type Importance CTime Currency Code Sector Forecast Prevalue Impact Freq Ranking 392030007 Japan Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 2500000 2600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 36010001 Australia Building Approvals m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 03:30 AUD AU CALENDAR_SECTOR_BUSINESS -900000 5500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 250010005 France GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 07:30 EUR FR CALENDAR_SECTOR_GDP 200000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 756050001 Switzerland KOF Economic Barometer CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 09:00 CHF CH CALENDAR_SECTOR_BUSINESS 101500000 102700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 276010008 Germany GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 10:00 EUR DE CALENDAR_SECTOR_GDP 100000 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 999030016 European Union GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 11:00 EUR EU CALENDAR_SECTOR_GDP 200000 300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 380020007 Italy 10-Year BTP Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 11:30 EUR IT CALENDAR_SECTOR_MARKET None 4010000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 1 724080001 Spain Business Confidence CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 12:00 EUR ES CALENDAR_SECTOR_BUSINESS -4100000 -5700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 76030002 Brazil FGV IGP-M Inflation Index m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 13:00 BRL BR CALENDAR_SECTOR_PRICES 1000000 810000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484020016 Mexico GDP q/q CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 14:00 MXN MX CALENDAR_SECTOR_GDP 0 200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_QUARTER 1 840170001 United States S&P/CS HPI Composite-20 y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 15:00 USD US CALENDAR_SECTOR_HOUSING 6800000 7200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840030021 United States JOLTS Job Openings CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH 2024.07.30 16:00 USD US CALENDAR_SECTOR_JOBS 7979000 8140000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 840060003 United States Dallas Fed Services Revenues CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 16:30 USD US CALENDAR_SECTOR_BUSINESS 3900000 1900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1 484010001 Mexico Fiscal Balance CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW 2024.07.30 22:30 MXN MX CALENDAR_SECTOR_TRADE -900000 -174071000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1
这些结果将被保存在如下变量中:
Calendar &NewsTime[]
下面的函数 EconomicNextEvent 与之前提到的 EconomicDetailsMemory 函数类似,主要区别在于,该函数的目的是获取下一个事件,而不是检索特定日期的所有事件。
//+------------------------------------------------------------------+ //|Will update UpcomingNews structure variable with the next event | //|data | //+------------------------------------------------------------------+ void CNews::EconomicNextEvent(datetime date=0) { //--- Declare unassigned Calendar structure variable Empty Calendar Empty; //--- assign empty values to Calendar structure variable UpcomingNews UpcomingNews = Empty; //--- If date variable is zero then assign current date date = (date==0)?TimeTradeServer():date; //--- Query to retrieve next upcoming event. string request_text=StringFormat("WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name'," "EventType as 'Type',EventImportance as 'Importance',%s as 'CTime',EventCurrency as 'Currency'," "EventCode as 'Code',EventSector as 'Sector',EventForecast as 'Forecast'," "EventPrevalue as 'Prevalue',EventImpact as 'Impact',EventFrequency as 'Freq'," "RANK() OVER (PARTITION BY %s ORDER BY CASE EventPrevalue WHEN 'None' THEN 2 ELSE 1 END" ", CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END,CASE EventImportance " "WHEN 'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN" " 'CALENDAR_IMPORTANCE_LOW' THEN 3 ELSE 4 END) Ranking FROM %s) SELECT Id,Country,Name," "Type,Importance,CTime,Currency,Code,Sector,Forecast,Prevalue,Impact,Freq FROM MySubQuery " "where Replace(CTime,'.','-')>=Replace('%s','.','-') AND Ranking<2 Group by CTime LIMIT 1;", EnumToString(MySchedule),EnumToString(MySchedule),DBMemory.name,TimeToString(date)); int request=DatabasePrepare(DBMemoryConnection,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_MEMORY, " request failed with code ", GetLastError()); PrintFormat(request_text); } //--- Assign query results to Calendar structure variable UpcomingNews DatabaseReadBind(request,UpcomingNews); //--- Removes a request created in DatabasePrepare() DatabaseFinalize(request); }
下面的 EconomicNextEvent 函数的查询语句与我们之前解释过的 EconomicDetailsMemory 函数中的查询语句类似,唯一的区别在于,下面的查询语句将结果限制为1条。
WITH MySubQuery AS (SELECT EventId as 'Id',Country,EventName as 'Name',EventType as 'Type',EventImportance as 'Importance', DST_NONE as 'CTime',EventCurrency as 'Currency',EventCode as 'Code',EventSector as 'Sector',EventForecast as 'Forecast', EventPrevalue as 'Prevalue',EventImpact as'Impact',EventFrequency as 'Freq',RANK() OVER (PARTITION BY DST_NONE Order BY CASE EventPrevalue WHEN 'None' THEN 2 ELSE 1 END,CASE EventForecast WHEN 'None' THEN 2 ELSE 1 END, CASE EventImportance WHEN 'CALENDAR_IMPORTANCE_HIGH' THEN 1 WHEN 'CALENDAR_IMPORTANCE_MODERATE' THEN 2 WHEN 'CALENDAR_IMPORTANCE_LOW' THEN 3 ELSE 4 END) Ranking FROM MQL5Calendar) SELECT Id,Country,Name,Type, Importance,CTime,Currency,Code,Sector,Forecast,Prevalue,Impact,Freq FROM MySubQuery where Date(Replace(CTime,'.','-'))=Date(Replace('2024.07.30 00:00','.','-')) and Ranking<2 Group by CTime LIMIT 1;
上述查询的示例结果如下所示。
Id Country Name Type Importance CTime Currency Code Sector Forecast Prevalue Impact Freq Ranking 392030007 Japan Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE 2024.07.30 01:30 JPY JP CALENDAR_SECTOR_JOBS 2500000 2600000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 1
上述示例结果将被存储到我们在新闻类外部声明的变量 UpcomingNews 中。
//--- Assign query results to Calendar structure variable UpcomingNews DatabaseReadBind(request,UpcomingNews);
在第2部分中新闻类新增的最后一个函数是 GetImpact,如下所示。这个函数的目的是根据即将发生的事件与之前具有类似属性或值的事件,返回名为 ENUM_CALENDAR_EVENT_IMPACT 的枚举值。让我进一步解释一下。
//+------------------------------------------------------------------+ //|Will retrieve Upcoming Event Impact data | //+------------------------------------------------------------------+ ENUM_CALENDAR_EVENT_IMPACT CNews::GetImpact() { //--- Declaration of string variable string impact=NULL; //--- Query to get impact data from previous event with the same event id and matching EventPrevalue and EventForecast scenarios. string request_text=StringFormat("SELECT EventImpact FROM %s where Replace(%s,'.','-')<Replace('%s','.','-') AND EventId=%d" " %s ORDER BY %s DESC LIMIT 1;",DBMemory.name,EnumToString(MySchedule),UpcomingNews.EventDate, UpcomingNews.EventId,((UpcomingNews.EventPreval=="None"||UpcomingNews.EventForecast=="None")? "AND EventImpact='CALENDAR_IMPACT_NA'":(int(UpcomingNews.EventPreval)<int(UpcomingNews.EventForecast))? "AND EventPrevalue<EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": (int(UpcomingNews.EventPreval)>int(UpcomingNews.EventForecast))? "AND EventPrevalue>EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": "AND EventPrevalue=EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'"), EnumToString(MySchedule)); int request=DatabasePrepare(DBMemoryConnection,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_MEMORY, " request failed with code ", GetLastError()); PrintFormat(request_text); } if(DatabaseRead(request))//Will read the one record in the 'Record' table { //--- assign first column result into impact variable DatabaseColumnText(request,0,impact); } //--- Removes a request created in DatabasePrepare() DatabaseFinalize(request); //--- Return equivalent Event impact in the enumeration ENUM_CALENDAR_EVENT_IMPACT if(impact=="CALENDAR_IMPACT_POSITIVE") { return CALENDAR_IMPACT_POSITIVE; } else if(impact=="CALENDAR_IMPACT_NEGATIVE") { return CALENDAR_IMPACT_NEGATIVE; } else { return CALENDAR_IMPACT_NA; } }
根据我的观察,事件影响基本上是这样工作的:即将发生的事件或在当天发生的事件都有一个名为 CALENDAR_IMPACT_NA 的影响枚举值,这意味着该事件的影响是不可用的。事件影响只有在事件发生的日期过去之后才会更新,并且只有在事件发生之前同时具备事件的前值和预测值时才会更新。有些情况下,即使满足了所有这些条件,事件影响仍然会被记录为不可用。
为什么我们需要之前的事件影响值,以及我们如何使用它?
首先,我们需要之前的事件影响值是为了预测下一个事件的影响结果可能是什么。因此,当即将发生的事件的前值不是 'None',并且预测值也不是 'None' 时,我们将检查这些值是否相等,或者哪个值更大。一旦我们确定了哪个值更大,或者这些值是否相同,我们就会寻找具有相同配置的之前的事件,并检索该事件的影响,以预测即将发生的事件的影响。举例说明:如果即将发生的事件的前值是 3000,预测值是 10,000,我们会寻找具有相同事件ID的最后一个事件,该事件的前值小于预测值,并使用该事件的影响作为即将发生的事件的影响。
什么是事件影响,影响是基于什么的?
事件影响是对特定事件对货币的感知影响的衡量,影响是基于事件的货币的。因此,如果失业率是即将发生的事件,而具有类似前值和预测值配置的之前的事件的影响是 CALENDAR_IMPACT_NEGATIVE,并且事件货币是 USD,这意味着在之前的失业率事件中,美元受到了负面影响。因此,如果你在之前的失业率事件发生后交易 EURUSD,理论上我们会看到 EURUSD 走强,这意味着 EUR 对美元升值。
在下面的查询中,我们从内存数据库中的 MQL5Calendar 表中选择事件影响。在 WHERE 子句中,我们寻找在即将发生的事件日期之前的事件日期,并筛选出具有相同事件ID的事件。然后,我们筛选出事件前值(EventPreval)和事件预测值(EventForecast)之间具有相同关系的情况。 如果 UpcomingNews.EventPreval 等于 'None' 或 UpcomingNews.EventForecast 等于 'None',那么我们已经知道事件影响将是 'None'。如果 UpcomingNews.EventPreval 小于 UpcomingNews.EventForecast那么我们寻找之前的事件,其中 EventPrevalue < EventForecast 且事件影响不是 NA。 如果 UpcomingNews.EventPreval 大于 UpcomingNews.EventForecast,那么我们寻找之前的事件,其中 EventPreval > EventForecast 且事件影响不是 NA。否则,我们寻找 EventPrevalue = EventForecast 且事件影响不是 NA 的情况。所有结果都筛选出最近的日期,因为 ORDER BY 子句是按事件日期降序排列的,并且 LIMIT 子句将只返回/输出一条记录。
//--- Query to get impact data from previous event with the same event id and matching EventPrevalue and EventForecast scenarios. string request_text=StringFormat("SELECT EventImpact FROM %s where Replace(%s,'.','-')<Replace('%s','.','-') AND EventId=%d" " %s ORDER BY %s DESC LIMIT 1;",DBMemory.name,EnumToString(MySchedule),UpcomingNews.EventDate, UpcomingNews.EventId,((UpcomingNews.EventPreval=="None"||UpcomingNews.EventForecast=="None")? "AND EventImpact='CALENDAR_IMPACT_NA'":(int(UpcomingNews.EventPreval)<int(UpcomingNews.EventForecast))? "AND EventPrevalue<EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": (int(UpcomingNews.EventPreval)>int(UpcomingNews.EventForecast))? "AND EventPrevalue>EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'": "AND EventPrevalue=EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA'"), EnumToString(MySchedule));
下面是一个当所有变量都被数据填充后,上述查询的样子。所以正如你下面所看到的,我们从 MQL5Calendar 中选择 EventImpact,其中 DST_NONE 小于 '2024.08.01 16:30',并且 EventId 等于 124500001,同时 EventPrevalue 小于 EventForecast,并且 EventImpact 不等于 'CALENDAR_IMPACT_NA'。然后我们根据 DST_NONE 对结果进行降序排列,并最终将结果限制为一条。
SELECT EventImpact FROM MQL5Calendar where Replace(DST_NONE,'.','-')<Replace('2024.08.01 16:30','.','-') AND EventId=124500001 AND EventPrevalue<EventForecast AND EventImpact<>'CALENDAR_IMPACT_NA' ORDER BY DST_NONE DESC LIMIT 1;
通用图形类
这个类负责在图表上显示专家的视觉元素,所以到现在为止,你可能已经注意到第3部分的视觉效果比第2部分有了很大的提升,相应的,创建这些视觉元素的代码也会更加复杂。我们看一下代码。因此,这个类需要访问新闻信息、风险管理信息以及账户信息,所以这些类都被包含进来了。
#include "ObjectProperties.mqh" #include "RiskManagement.mqh" #include "CommonVariables.mqh" #include "News.mqh" //+------------------------------------------------------------------+ //|CommonGraphics class | //+------------------------------------------------------------------+ class CCommonGraphics:CObjectProperties { private: //--- GraphicText structure this structure is responsible for managing the graphical text struct GraphicText { //--- private declaration for struct GraphicText private: //--- this structure will store properties for the subtext struct subtextformat { string Label;//Store text label string Text;//Store text value }; //--- this structure inherits from subtextformat and is responsible for finding text struct found:subtextformat { bool isFound;//Check if text is found int index;//Get index for the text }; //--- structure array for subtexts subtextformat sub_text[]; //--- function to find text properties from text's label found FoundText(string label) { found find; find.Label=""; find.Text=""; find.isFound=false; find.index=-1; for(uint i=0;i<sub_text.Size();i++) { //--- If text label is found in array if(label==sub_text[i].Label) { //--- Assign text properties find.Label=sub_text[i].Label; find.Text=sub_text[i].Text; find.isFound=true; find.index=int(i); return find;//return found text properties } } return find;//return text properties } //--- public declaration for struct GraphicText public: //--- string variable string text; //--- function to set/add text properties void subtext(string label,string value) { //--- Get text properties from label found result = FoundText(label); //--- Check if text label was found/exists in array sub_text if(!result.isFound) { //--- Resize array sub_text ArrayResize(sub_text,sub_text.Size()+1,sub_text.Size()+2); //--- Add text properties for new array index sub_text[sub_text.Size()-1].Label = label; sub_text[sub_text.Size()-1].Text = value; } else { /* Set new text/override text from text label that exists in the array sub_text array */ sub_text[result.index].Text = value; } } //--- function to retrieve text from text label string subtext(string label) { return FoundText(label).Text; } };// End of struct GraphicText //--- AccountInfo object declaration CAccountInfo CAccount; //--- News object declaration CNews NewsObj; //--- TimeManagement object declaration CTimeManagement CTime; //--- Calendar structure array declaration Calendar CalendarArray[]; //--- color variable declaration color EventColor; //--- unit variable declarations uint Fontsize,X_start,Y_start; //--- void function declarations for Graphical blocks void Block_1(); void Block_2(uint SecondsPreEvent=5); CRiskManagement CRisk;//Risk management class object //--- GraphicText structure array declarations GraphicText Texts_Block1[9],Texts_Block2[7]; //--- structure to store text height and width struct Text_Prop_Size { uint Height;//store text height uint Width;//store text width }; //--- void function to retrieve sum of the texts height and the maximum width of texts from GraphicText array Texts void GetTextMaxWidthAndHeight(GraphicText &Texts[],uint &Max_Height,uint &Max_Width,uint FontSize) { //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- set variables to default value of zero Max_Height=0; Max_Width=0; //--- loop through all texts in the GraphicText array Texts for(uint i=0;i<Texts.Size();i++) { //--- temporary declarations for height and width uint Height=0,Width=0; //--- retrieve text height and width from index in Texts array TextGetSize(Texts[i].text,Width,Height); //--- sum texts height to variable Max_Height Max_Height+=Height; //--- assign width if text width is more than variable Max_Width value Max_Width=(Width>Max_Width)?Width:Max_Width; } } //--- function to retrieve text height and width properties in the structure Text_Prop_Size format Text_Prop_Size GetText(string Text,uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- retrieve text height and width from Text string variable TextGetSize(Text,Size.Width,Size.Height); //--- return structure Text_Prop_Size variable return Size; } //--- Function to get texts height sum and max width in the structure Text_Prop_Size format Text_Prop_Size GetTextMax(GraphicText &Texts[],uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- uint variable declarations for text properties uint Max_Height; uint Max_Width; //--- Retrieve sum of texts height and maximum texts width into Max_Height,Max_Width GetTextMaxWidthAndHeight(Texts,Max_Height,Max_Width,FontSize); //--- assign values into structure Text_Prop_Size variable Size.Height = Max_Height; Size.Width = Max_Width; //--- return structure Text_Prop_Size variable return Size; } //--- Boolean declarations bool is_date,is_spread,is_news,is_events; public: //--- class constructor CCommonGraphics(bool display_date,bool display_spread,bool display_news,bool display_events); ~CCommonGraphics(void) {}//class destructor void GraphicsRefresh(uint SecondsPreEvent=5);//will create/refresh the chart objects //--- will update certain graphics at an interval void Block_2_Realtime(uint SecondsPreEvent=5); //--- will create chart event objects void NewsEvent(); };
下面的结构体 GraphicText 并不是 MQL5 中普通的结构体,它包含了结构体、结构体数组、函数的私有和/或公共声明,以及一个字符串变量。在这种情况下,GraphicText 结构体表现得像一个完整的独立类。这个结构体的目的是管理和存储图形文本,结构体数组 sub_text 将存储所有文本属性,而函数 FoundText 将在 sub_text 数组 中搜索任何与文本标签匹配的内容。如果找到匹配项,我们将在一个名为 found 的结构体中返回这个匹配的详细信息,found 继承自结构体 subtextformat。在公共声明中,字符串变量 text 将存储 sub_text 结构体数组 中的完整文本内容。void 类型的函数 subtext 将把文本标签和文本/子文本添加到 sub_text 数组 中,或者如果在 数组 中找到了字符串变量 label,它将覆盖 数组 中存储的文本/子文本。名为 subtext 的字符串函数将从 sub_text 结构体数组 中检索与标签相关的文本。
//--- GraphicText structure this structure is responsible for managing the graphical text struct GraphicText { //--- private declaration for struct GraphicText private: //--- this structure will store properties for the subtext struct subtextformat { string Label;//Store text label string Text;//Store text value }; //--- this structure inherits from subtextformat and is responsible for finding text struct found:subtextformat { bool isFound;//Check if text is found int index;//Get index for the text }; //--- structure array for subtexts subtextformat sub_text[]; //--- function to find text properties from text's label found FoundText(string label) { found find; find.Label=""; find.Text=""; find.isFound=false; find.index=-1; for(uint i=0;i<sub_text.Size();i++) { //--- If text label is found in array if(label==sub_text[i].Label) { //--- Assign text properties find.Label=sub_text[i].Label; find.Text=sub_text[i].Text; find.isFound=true; find.index=int(i); return find;//return found text properties } } return find;//return text properties } //--- public declaration for struct GraphicText public: //--- string variable string text; //--- function to set/add text properties void subtext(string label,string value) { //--- Get text properties from label found result = FoundText(label); //--- Check if text label was found/exists in array sub_text if(!result.isFound) { //--- Resize array sub_text ArrayResize(sub_text,sub_text.Size()+1,sub_text.Size()+2); //--- Add text properties for new array index sub_text[sub_text.Size()-1].Label = label; sub_text[sub_text.Size()-1].Text = value; } else { /* Set new text/override text from text label that exists in the array sub_text array */ sub_text[result.index].Text = value; } } //--- function to retrieve text from text label string subtext(string label) { return FoundText(label).Text; } };// End of struct GraphicText
下面的函数被创建用于检索结构体数组 Texts 中文本高度的总和,以及数组中文本的最大宽度。
//--- void function to retrieve sum of the texts height and the maximum width of texts from GraphicText array Texts void GetTextMaxWidthAndHeight(GraphicText &Texts[],uint &Max_Height,uint &Max_Width,uint FontSize) { //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- set variables to default value of zero Max_Height=0; Max_Width=0; //--- loop through all texts in the GraphicText array Texts for(uint i=0;i<Texts.Size();i++) { //--- temporary declarations for height and width uint Height=0,Width=0; //--- retrieve text height and width from index in Texts array TextGetSize(Texts[i].text,Width,Height); //--- sum texts height to variable Max_Height Max_Height+=Height; //--- assign width if text width is more than variable Max_Width value Max_Width=(Width>Max_Width)?Width:Max_Width; } }
下面的函数被创建用于从字符串变量 Text 中检索以 Text_Prop_Size 结构格式表示的高度和宽度属性。
//--- function to retrieve text height and width properties in the structure Text_Prop_Size format Text_Prop_Size GetText(string Text,uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- set fontsize properties to get accurate text height and width sizes TextSetFont("Arial",(-1*FontSize)-100); //--- retrieve text height and width from Text string variable TextGetSize(Text,Size.Width,Size.Height); //--- return structure Text_Prop_Size variable return Size; }
下面的函数被创建用于从结构体数组 Texts 中检索以 Text_Prop_Size 结构格式表示的高度总和以及最大宽度属性。
//--- Function to get texts height sum and max width in the structure Text_Prop_Size format Text_Prop_Size GetTextMax(GraphicText &Texts[],uint FontSize) { //--- structure Text_Prop_Size variable Text_Prop_Size Size; //--- uint variable declarations for text properties uint Max_Height; uint Max_Width; //--- Retrieve sum of texts height and maximum texts width into Max_Height,Max_Width GetTextMaxWidthAndHeight(Texts,Max_Height,Max_Width,FontSize); //--- assign values into structure Text_Prop_Size variable Size.Height = Max_Height; Size.Width = Max_Width; //--- return structure Text_Prop_Size variable return Size; }
在类的构造函数中,我们将初始化之前声明的变量,这些变量包括:is_date(用于决定是否在图表上显示日期信息),is_spread(用于决定是否在图表上显示点差信息),is_news(用于决定是否在图表上显示新闻信息),is_events(用于决定是否在图表上显示事件对象信息)。NewsObject。EconomicNextEvent 函数将用下一条新闻的详细信息更新 UpcomingNews 变量。
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CCommonGraphics::CCommonGraphics(bool display_date,bool display_spread,bool display_news,bool display_events): //--- Assign variables is_date(display_date),is_spread(display_spread),is_news(display_news),is_events(display_events) { //--- get next news event NewsObject.EconomicNextEvent(); }
GraphicsRefresh 负责首先清除图表上之前创建的任何对象(如果有的话),然后调用其他函数来创建图表对象,以在当前图表上显示各种信息。
//+------------------------------------------------------------------+ //|will create/refresh the chart objects | //+------------------------------------------------------------------+ void CCommonGraphics::GraphicsRefresh(uint SecondsPreEvent=5) { //--- create graphics if outside the strategy tester or in the strategy tester and visual mode is enabled if((!MQLInfoInteger(MQL_TESTER))||(MQLInfoInteger(MQL_TESTER)&&MQLInfoInteger(MQL_VISUAL_MODE))) { //--- Delete chart objects DeleteObj();//function from Object properties class Block_1();//Create graphics for block 1 //--- Check whether to create graphics for block 2 if(is_date||is_news||is_spread) { Block_2(SecondsPreEvent);//Create graphics for block 2 } //--- creates event objects NewsEvent(); } }
下面的函数 Block_1 将负责创建图形块 1 的图形元素,其位置如下所示,包含的内容有:
- 交易品种名称
- 交易品种时间周期
- 交易品种描述
- 交易品种的合约大小
- 交易品种的最小交易量
- 交易品种的最大交易量<
- 交易品种交易量步长
- 交易品种交易量限制
- 风险选项
- 最低风险
- 最高风险
//+------------------------------------------------------------------+ //|Graphical Block 1 | //+------------------------------------------------------------------+ void CCommonGraphics::Block_1() { //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color = (isLightMode)?clrBlack:clrWheat; //--- Set text properties for Symbol name,Symbol period and Symbol description # section 1 Texts_Block1[0].text = Symbol()+", "+GetChartPeriodName()+": "+CSymbol.Description();//set main text Texts_Block1[0].subtext("Symbol Name",Symbol()+",");//set subtext - label,value Texts_Block1[0].subtext("Symbol Period",GetChartPeriodName());//set subtext - label,value Texts_Block1[0].subtext("Symbol Desc",": "+CSymbol.Description());//set subtext - label,value //--- Set text properties for Contract size # section 2 Texts_Block1[1].text = "Contract Size: "+string(CSymbol.ContractSize());//set main text Texts_Block1[1].subtext("Contract Size Text","Contract Size:");//set subtext - label,value Texts_Block1[1].subtext("Contract Size",string(CSymbol.ContractSize()));//set subtext - label,value //--- Set text properties for Minimum lot # section 3 Texts_Block1[2].text = "Minimum Lot: "+string(CSymbol.LotsMin());//set main text Texts_Block1[2].subtext("Minimum Lot Text","Minimum Lot:");//set subtext - label,value Texts_Block1[2].subtext("Minimum Lot",string(CSymbol.LotsMin()));//set subtext - label,value //--- Set text properties for Max lot # section 4 Texts_Block1[3].text = "Max Lot: "+string(CSymbol.LotsMax());//set main text Texts_Block1[3].subtext("Max Lot Text","Max Lot:");//set subtext - label,value Texts_Block1[3].subtext("Max Lot",string(CSymbol.LotsMax()));//set subtext - label,value //--- Set text properties for Volume step # section 5 Texts_Block1[4].text = "Volume Step: "+string(CSymbol.LotsStep());//set main text Texts_Block1[4].subtext("Volume Step Text","Volume Step:");//set subtext - label,value Texts_Block1[4].subtext("Volume Step",string(CSymbol.LotsStep()));//set subtext - label,value //--- Set text properties for Volume limit # section 6 Texts_Block1[5].text = "Volume Limit: "+string(CSymbol.LotsLimit());//set main text Texts_Block1[5].subtext("Volume Limit Text","Volume Limit:");//set subtext - label,value Texts_Block1[5].subtext("Volume Limit",string(CSymbol.LotsLimit()));//set subtext - label,value //--- Set text properties for Risk option # section 7 Texts_Block1[6].text = "Risk Option: "+CRisk.GetRiskOption();//set main text Texts_Block1[6].subtext("Risk Option Text","Risk Option:");//set subtext - label,value Texts_Block1[6].subtext("Risk Option",CRisk.GetRiskOption());//set subtext - label,value //--- Set text properties for Risk floor # section 8 Texts_Block1[7].text = "Risk Floor: "+CRisk.GetRiskFloor();//set main text Texts_Block1[7].subtext("Risk Floor Text","Risk Floor:");//set subtext - label,value Texts_Block1[7].subtext("Risk Floor",CRisk.GetRiskFloor());//set subtext - label,value //--- Set text properties for Risk ceiling # section 9 Texts_Block1[8].text = "Risk Ceiling: "+CRisk.GetRiskCeil();//set main text Texts_Block1[8].subtext("Risk Ceiling Text","Risk Ceiling:");//set subtext - label,value Texts_Block1[8].subtext("Risk Ceiling",CRisk.GetRiskCeil());//set subtext - label,value //--- Set basic properties Fontsize=10;//Set Fontsize X_start=2;//Set X distance Y_start=2;//Set Y distance /* Create objects # section 1*/ //-- Create the background object for width and height+3 of section 1 text Square(0,"Symbol Name background",X_start,Y_start,GetText(Texts_Block1[0].text,Fontsize).Width, GetText(Texts_Block1[0].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 1 TextObj(0,"Symbol Name",Texts_Block1[0].subtext("Symbol Name"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[0].subtext("Symbol Name"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Period",Texts_Block1[0].subtext("Symbol Period"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[0].subtext("Symbol Period"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Desc",Texts_Block1[0].subtext("Symbol Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 2*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[0].text,Fontsize).Height;//Re-adjust Y distance, add height from section 1 //-- Create the background object for width and height+3 of section 2 text Square(0,"Symbol Contract Size background",X_start,Y_start,GetText(Texts_Block1[1].text,Fontsize).Width, GetText(Texts_Block1[1].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 2 TextObj(0,"Symbol Contract Size Text",Texts_Block1[1].subtext("Contract Size Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[1].subtext("Contract Size Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Contract Size",Texts_Block1[1].subtext("Contract Size"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 3*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[1].text,Fontsize).Height;//Re-adjust Y distance, add height from section 2 //-- Create the background object for width and height+3 of section 3 text Square(0,"Symbol MinLot background",X_start,Y_start,GetText(Texts_Block1[2].text,Fontsize).Width, GetText(Texts_Block1[2].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 3 TextObj(0,"Symbol MinLot Text",Texts_Block1[2].subtext("Minimum Lot Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[2].subtext("Minimum Lot Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol MinLot",Texts_Block1[2].subtext("Minimum Lot"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 4*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[2].text,Fontsize).Height;//Re-adjust Y distance, add height from section 3 //-- Create the background object for width and height+3 of section 4 text Square(0,"Symbol MaxLot background",X_start,Y_start,GetText(Texts_Block1[3].text,Fontsize).Width, GetText(Texts_Block1[3].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 4 TextObj(0,"Symbol MaxLot Text",Texts_Block1[3].subtext("Max Lot Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[3].subtext("Max Lot Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol MaxLot",Texts_Block1[3].subtext("Max Lot"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 5*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[3].text,Fontsize).Height;//Re-adjust Y distance, add height from section 4 //-- Create the background object for width and height+3 of section 5 text Square(0,"Symbol Volume Step background",X_start,Y_start,GetText(Texts_Block1[4].text,Fontsize).Width, GetText(Texts_Block1[4].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 5 TextObj(0,"Symbol Volume Step Text",Texts_Block1[4].subtext("Volume Step Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[4].subtext("Volume Step Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Volume Step",Texts_Block1[4].subtext("Volume Step"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 6*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[4].text,Fontsize).Height;//Re-adjust Y distance, add height from section 5 //-- Create the background object for width and height+3 of section 6 text Square(0,"Symbol Volume Limit background",X_start,Y_start,GetText(Texts_Block1[5].text,Fontsize).Width, GetText(Texts_Block1[5].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 6 TextObj(0,"Symbol Volume Limit Text",Texts_Block1[5].subtext("Volume Limit Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[5].subtext("Volume Limit Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Symbol Volume Limit",Texts_Block1[5].subtext("Volume Limit"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 7*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[5].text,Fontsize).Height;//Re-adjust Y distance, add height from section 6 //-- Create the background object for width and height+3 of section 7 text Square(0,"Risk Option background",X_start,Y_start,GetText(Texts_Block1[6].text,Fontsize).Width, GetText(Texts_Block1[6].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 7 TextObj(0,"Risk Option Text",Texts_Block1[6].subtext("Risk Option Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[6].subtext("Risk Option Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Risk Option",Texts_Block1[6].subtext("Risk Option"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 8*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[6].text,Fontsize).Height;//Re-adjust Y distance, add height from section 7 //-- Create the background object for width and height+3 of section 8 text Square(0,"Risk Floor background",X_start,Y_start,GetText(Texts_Block1[7].text,Fontsize).Width, GetText(Texts_Block1[7].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 8 TextObj(0,"Risk Floor Text",Texts_Block1[7].subtext("Risk Floor Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[7].subtext("Risk Floor Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Risk Floor",Texts_Block1[7].subtext("Risk Floor"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 9*/ X_start=2;//Reset X distance Y_start+=GetText(Texts_Block1[7].text,Fontsize).Height;//Re-adjust Y distance, add height from section 8 //-- Create the background object for width and height+3 of section 9 text Square(0,"Risk Ceil background",X_start,Y_start,GetText(Texts_Block1[8].text,Fontsize).Width, GetText(Texts_Block1[8].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 9 TextObj(0,"Risk Ceil Text",Texts_Block1[8].subtext("Risk Ceiling Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block1[8].subtext("Risk Ceiling Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Risk Ceil",Texts_Block1[8].subtext("Risk Ceiling"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); }
下面的函数 Block_2 将负责创建图形块 2 的图形元素,其位置如下所示,包含的内容有:
- 当前日期和时间
- 事件日期
- 事件名称
- 事件国家
- 事件货币
- 事件重要度
- 点差等级
//+------------------------------------------------------------------+ //|Graphical Block 2 | //+------------------------------------------------------------------+ void CCommonGraphics::Block_2(uint SecondsPreEvent=5) { //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; if(is_date)//Check whether to display date information { //--- Set text properties for Date and Time # section 10 Texts_Block2[0].text = "Date:"+TimeToString(TimeTradeServer(),TIME_DATE)+"|| Time:"+TimeToString(TimeTradeServer(),TIME_MINUTES) +" ";//set main text Texts_Block2[0].subtext("Date Text","Date:");//set subtext - label,value Texts_Block2[0].subtext("Date",TimeToString(TimeTradeServer(),TIME_DATE));//set subtext - label,value Texts_Block2[0].subtext("Time Text","|| Time:");//set subtext - label,value Texts_Block2[0].subtext("Time",TimeToString(TimeTradeServer(),TIME_MINUTES));//set subtext - label,value } if(is_news)//Check whether to display news information { //--- Set text object color depending on upcoming news event's Importance EventColor = NewsObj.GetImportance_color(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)); //--- Set text properties for Event Date # section 11 Texts_Block2[1].text = "Event: @"+UpcomingNews.EventDate+" ";//set main text Texts_Block2[1].subtext("Event Date Text","Event: @");//set subtext - label,value Texts_Block2[1].subtext("Event Date",UpcomingNews.EventDate);//set subtext - label,value //--- Set text properties for Event Name # section 12 Texts_Block2[2].text = "Name: "+UpcomingNews.EventName+" ";//set main text Texts_Block2[2].subtext("Event Name Text","Name: ");//set subtext - label,value Texts_Block2[2].subtext("Event Name",UpcomingNews.EventName);//set subtext - label,value //--- Set text properties for Event Country # section 13 Texts_Block2[3].text = "Country: "+UpcomingNews.CountryName+" ";//set main text Texts_Block2[3].subtext("Event Country Text","Country: ");//set subtext - label,value Texts_Block2[3].subtext("Event Country",UpcomingNews.CountryName);//set subtext - label,value //--- Set text properties for Event Currency # section 14 Texts_Block2[4].text = "Currency: "+UpcomingNews.EventCurrency+" ";//set main text Texts_Block2[4].subtext("Event Currency Text","Currency: ");//set subtext - label,value Texts_Block2[4].subtext("Event Currency",UpcomingNews.EventCurrency);//set subtext - label,value //--- Set text properties for Event Importance # section 15 Texts_Block2[5].text = "Importance: "+NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance))+" ";//set main text Texts_Block2[5].subtext("Importance Text","Importance: ");//set subtext - label,value Texts_Block2[5].subtext("Importance",NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)));//set subtext - label,value } if(is_spread)//Check whether to display spread information { //--- Set text properties for Spread # section 16 Texts_Block2[6].text = "Spread: "+string(CSymbol.Spread())+" Rating: "+CSymbol.SpreadDesc()+" ";//set main text Texts_Block2[6].subtext("Spread Text","Spread:");//set subtext - label,value Texts_Block2[6].subtext("Spread",string(CSymbol.Spread()));//set subtext - label,value Texts_Block2[6].subtext("Rating Text"," Rating:");//set subtext - label,value Texts_Block2[6].subtext("Rating Desc",CSymbol.SpreadDesc());//set subtext - label,value } //--- Set basic properties Fontsize=10; X_start=2;//Reset X distance Y_start=GetTextMax(Texts_Block1,Fontsize).Height+29;//Re-adjust Y distance from graphical block 1 Height /* Create objects # section 10*/ if(is_date)//Check whether to display date information { //-- Create the background object for width and height+3 of section 10 text Square(0,"Datetime background",X_start,Y_start,GetText(Texts_Block2[0].text,Fontsize).Width, GetText(Texts_Block2[0].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //-- Will create the text objects for section 10 TextObj(0,"Date Text",Texts_Block2[0].subtext("Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date Text"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Date",Texts_Block2[0].subtext("Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date"),Fontsize).Width;//Re-adjust X distance TextObj(0,"Time Text",Texts_Block2[0].subtext("Time Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Time Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Time",Texts_Block2[0].subtext("Time"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(UpcomingNews.CountryName!=NULL&&is_news)//Check whether to display news information and if upcoming news is available { /* Create objects # section 11*/ Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0;//Re-adjust Y distance depending if section 10 is shown X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 11 text Square(0,"Event Date background",X_start,Y_start,GetText(Texts_Block2[1].text,Fontsize).Width, GetText(Texts_Block2[1].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 11 TextObj(0,"Event Date Text",Texts_Block2[1].subtext("Event Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[1].subtext("Event Date Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Event Date",Texts_Block2[1].subtext("Event Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 12*/ Y_start+=GetText(Texts_Block2[1].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 12 text Square(0,"Event Name background",X_start,Y_start,GetText(Texts_Block2[2].text,Fontsize).Width, GetText(Texts_Block2[2].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 12 TextObj(0,"Event Name Text",Texts_Block2[2].subtext("Event Name Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[2].subtext("Event Name Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Name",Texts_Block2[2].subtext("Event Name"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 13*/ Y_start+=GetText(Texts_Block2[2].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 13 text Square(0,"Event Country background",X_start,Y_start,GetText(Texts_Block2[3].text,Fontsize).Width, GetText(Texts_Block2[3].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 13 TextObj(0,"Event Country Text",Texts_Block2[3].subtext("Event Country Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[3].subtext("Event Country Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Country",Texts_Block2[3].subtext("Event Country"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 14*/ Y_start+=GetText(Texts_Block2[3].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 14 text Square(0,"Event Currency background",X_start,Y_start,GetText(Texts_Block2[4].text,Fontsize).Width, GetText(Texts_Block2[4].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 14 TextObj(0,"Event Currency Text",Texts_Block2[4].subtext("Event Currency Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[4].subtext("Event Currency Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Currency",Texts_Block2[4].subtext("Event Currency"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 15*/ Y_start+=GetText(Texts_Block2[4].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 15 text Square(0,"Event Importance background",X_start,Y_start,GetText(Texts_Block2[5].text,Fontsize).Width, GetText(Texts_Block2[5].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 15 TextObj(0,"Importance Text",Texts_Block2[5].subtext("Importance Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[5].subtext("Importance Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Importance",Texts_Block2[5].subtext("Importance"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=GetText(Texts_Block2[5].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 16 text Square(0,"Spread background",X_start,Y_start,GetText(Texts_Block2[6].text,Fontsize).Width, GetText(Texts_Block2[6].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 16 TextObj(0,"Symbol Spread Text",Texts_Block2[6].subtext("Spread Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } } else /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0;//Re-adjust Y distance depending if section 10 is shown X_start=2;//Reset X distance //-- Create the background object for width and height+3 of section 16 text Square(0,"Spread background",X_start,Y_start,GetText(Texts_Block2[6].text,Fontsize).Width, GetText(Texts_Block2[6].text,Fontsize).Height+3,ANCHOR_LEFT_UPPER); Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will create the text objects for section 16 TextObj(0,"Symbol Spread Text",Texts_Block2[6].subtext("Spread Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } }
下面的函数将对图形块2部分任何的更改进行更新。而不会重新创建来自Block_2函数的所有元素。
//+------------------------------------------------------------------+ //|will update certain graphics at an interval | //+------------------------------------------------------------------+ void CCommonGraphics::Block_2_Realtime(uint SecondsPreEvent=5) { if(MQLInfoInteger(MQL_TESTER)&&!MQLInfoInteger(MQL_VISUAL_MODE)) { return;//exit if in strategy tester and not in visual mode } if(is_date)//Check whether to display date information { //--- Set text properties for Date and Time # section 10 Texts_Block2[0].text = "Date:"+TimeToString(TimeTradeServer(),TIME_DATE)+"|| Time:"+TimeToString(TimeTradeServer(),TIME_SECONDS) +" ";//set main text Texts_Block2[0].subtext("Date Text","Date:");//set subtext - label,value Texts_Block2[0].subtext("Date",TimeToString(TimeTradeServer(),TIME_DATE));//set subtext - label,value Texts_Block2[0].subtext("Time Text","|| Time:");//set subtext - label,value Texts_Block2[0].subtext("Time",TimeToString(TimeTradeServer(),TIME_SECONDS));//set subtext - label,value } if(is_news)//Check whether to display news information { //--- Set text object color depending on upcoming news event's Importance EventColor = NewsObj.GetImportance_color(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)); //--- Set text properties for Event Date # section 11 Texts_Block2[1].text = "Event: @"+UpcomingNews.EventDate+" ";//set main text Texts_Block2[1].subtext("Event Date Text","Event: @");//set subtext - label,value Texts_Block2[1].subtext("Event Date",UpcomingNews.EventDate);//set subtext - label,value //--- Set text properties for Event Name # section 12 Texts_Block2[2].text = "Name: "+UpcomingNews.EventName+" ";//set main text Texts_Block2[2].subtext("Event Name Text","Name: ");//set subtext - label,value Texts_Block2[2].subtext("Event Name",UpcomingNews.EventName);//set subtext - label,value //--- Set text properties for Event Country # section 13 Texts_Block2[3].text = "Country: "+UpcomingNews.CountryName+" ";//set main text Texts_Block2[3].subtext("Event Country Text","Country: ");//set subtext - label,value Texts_Block2[3].subtext("Event Country",UpcomingNews.CountryName);//set subtext - label,value //--- Set text properties for Event Currency # section 14 Texts_Block2[4].text = "Currency: "+UpcomingNews.EventCurrency+" ";//set main text Texts_Block2[4].subtext("Event Currency Text","Currency: ");//set subtext - label,value Texts_Block2[4].subtext("Event Currency",UpcomingNews.EventCurrency);//set subtext - label,value //--- Set text properties for Event Importance # section 15 Texts_Block2[5].text = "Importance: "+NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance))+" ";//set main text Texts_Block2[5].subtext("Importance Text","Importance: ");//set subtext - label,value Texts_Block2[5].subtext("Importance",NewsObj.GetImportance(NewsObj.IMPORTANCE(UpcomingNews.EventImportance)));//set subtext - label,value } if(is_spread)//Check whether to display spread information { //--- Set text properties for Spread # section 16 Texts_Block2[6].text = "Spread: "+string(CSymbol.Spread())+" Rating: "+CSymbol.SpreadDesc()+" ";//set main text Texts_Block2[6].subtext("Spread Text","Spread:");//set subtext - label,value Texts_Block2[6].subtext("Spread",string(CSymbol.Spread()));//set subtext - label,value Texts_Block2[6].subtext("Rating Text"," Rating:");//set subtext - label,value Texts_Block2[6].subtext("Rating Desc",CSymbol.SpreadDesc());//set subtext - label,value } //--- Set basic properties Fontsize=10; X_start=2;//Reset X distance Y_start=GetTextMax(Texts_Block1,Fontsize).Height+29;//Re-adjust Y distance from section block 1 /* Create objects # section 10*/ if(is_date)//Check whether to display date information { //-- Check if the background object x-size for section 10 is the same size as section 10 text width if(ObjectGetInteger(0,"Datetime background",OBJPROP_XSIZE)!=GetText(Texts_Block2[0].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 10 text width ObjectSetInteger(0,"Datetime background",OBJPROP_XSIZE,long(GetText(Texts_Block2[0].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 10 TextObj(0,"Date Text",Texts_Block2[0].subtext("Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Date",Texts_Block2[0].subtext("Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Date"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Time Text",Texts_Block2[0].subtext("Time Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[0].subtext("Time Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Time",Texts_Block2[0].subtext("Time"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(UpcomingNews.CountryName!=NULL&&is_news)//Check whether to display news information { /* Create objects # section 11*/ Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0; X_start=2;//Reset X distance //-- Check if the background object x-size for section 11 is the same size as section 11 text width if(ObjectGetInteger(0,"Event Date background",OBJPROP_XSIZE)!=GetText(Texts_Block2[1].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 11 text width ObjectSetInteger(0,"Event Date background",OBJPROP_XSIZE,long(GetText(Texts_Block2[1].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 11 TextObj(0,"Event Date Text",Texts_Block2[1].subtext("Event Date Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[1].subtext("Event Date Text"),Fontsize).Width;//Re-adjust X distance //--- Adjust text color depending if chart color mode is LightMode and if a news event is occurring TextObj_color = CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(UpcomingNews.EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(UpcomingNews.EventDate),59))?clrRed:(isLightMode)?clrBlack:clrWheat; TextObj(0,"Event Date",Texts_Block2[1].subtext("Event Date"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 12*/ Y_start+=GetText(Texts_Block2[1].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 12 is the same size as section 12 text width if(ObjectGetInteger(0,"Event Name background",OBJPROP_XSIZE)!=GetText(Texts_Block2[2].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 12 text width ObjectSetInteger(0,"Event Name background",OBJPROP_XSIZE,long(GetText(Texts_Block2[2].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 12 TextObj(0,"Event Name Text",Texts_Block2[2].subtext("Event Name Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[2].subtext("Event Name Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Name",Texts_Block2[2].subtext("Event Name"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 13*/ Y_start+=GetText(Texts_Block2[2].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 13 is the same size as section 13 text width if(ObjectGetInteger(0,"Event Country background",OBJPROP_XSIZE)!=GetText(Texts_Block2[3].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 13 text width ObjectSetInteger(0,"Event Country background",OBJPROP_XSIZE,long(GetText(Texts_Block2[3].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 13 TextObj(0,"Event Country Text",Texts_Block2[3].subtext("Event Country Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[3].subtext("Event Country Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Country",Texts_Block2[3].subtext("Event Country"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 14*/ Y_start+=GetText(Texts_Block2[3].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 14 is the same size as section 14 text width if(ObjectGetInteger(0,"Event Currency background",OBJPROP_XSIZE)!=GetText(Texts_Block2[4].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 14 text width ObjectSetInteger(0,"Event Currency background",OBJPROP_XSIZE,long(GetText(Texts_Block2[4].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 14 TextObj(0,"Event Currency Text",Texts_Block2[4].subtext("Event Currency Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[4].subtext("Event Currency Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Event Currency",Texts_Block2[4].subtext("Event Currency"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 15*/ Y_start+=GetText(Texts_Block2[4].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 15 is the same size as section 15 text width if(ObjectGetInteger(0,"Event Importance background",OBJPROP_XSIZE)!=GetText(Texts_Block2[5].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 15 text width ObjectSetInteger(0,"Event Importance background",OBJPROP_XSIZE,long(GetText(Texts_Block2[5].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; //-- Will update the text objects for section 15 TextObj(0,"Importance Text",Texts_Block2[5].subtext("Importance Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[5].subtext("Importance Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on upcoming news event's Importance TextObj_color=EventColor; TextObj(0,"Importance",Texts_Block2[5].subtext("Importance"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=GetText(Texts_Block2[5].text,Fontsize).Height;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 16 is the same size as section 16 text width if(ObjectGetInteger(0,"Spread background",OBJPROP_XSIZE)!=GetText(Texts_Block2[6].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 16 text width ObjectSetInteger(0,"Spread background",OBJPROP_XSIZE,long(GetText(Texts_Block2[6].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //-- Will create the text object for the Symbol's name X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; //-- Will update the text objects for section 16 TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } } else /* Create objects # section 16*/ if(is_spread)//Check whether to display spread information { Y_start+=(is_date)?GetText(Texts_Block2[0].text,Fontsize).Height:0;//Re-adjust Y distance X_start=2;//Reset X distance //-- Check if the background object x-size for section 16 is the same size as section 16 text width if(ObjectGetInteger(0,"Spread background",OBJPROP_XSIZE)!=GetText(Texts_Block2[6].text,Fontsize).Width) { //-- Will re-adjust background object to any changes of section 16 text width ObjectSetInteger(0,"Spread background",OBJPROP_XSIZE,long(GetText(Texts_Block2[6].text,Fontsize).Width)); } Y_start+=3;//Re-adjust Y distance X_start+=2;//Re-adjust X distance //--- Set text object color depending on spread rating color Spread_clr=CSymbol.SpreadColor(); //-- Will create the text object for the Symbol's name X_start+=GetText(Texts_Block2[6].subtext("Spread Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; //-- Will update the text objects for section 16 TextObj(0,"Symbol Spread",Texts_Block2[6].subtext("Spread"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Spread"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending if the chart color mode is LightMode or not TextObj_color=(isLightMode)?clrBlack:clrWheat; TextObj(0,"Symbol Rating Text",Texts_Block2[6].subtext("Rating Text"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); X_start+=GetText(Texts_Block2[6].subtext("Rating Text"),Fontsize).Width;//Re-adjust X distance //--- Set text object color depending on spread rating TextObj_color=Spread_clr; TextObj(0,"Symbol Rating",Texts_Block2[6].subtext("Rating Desc"),X_start,Y_start,CORNER_LEFT_UPPER,Fontsize); } }
下面的函数将在图表上创建事件对象,并显示当天所有可用的新闻事件。
//+------------------------------------------------------------------+ //|will create chart event objects | //+------------------------------------------------------------------+ void CCommonGraphics::NewsEvent() { if(!is_events||(MQLInfoInteger(MQL_TESTER)&&!MQLInfoInteger(MQL_VISUAL_MODE))) {return;}//exit if in strategy tester and not in visual mode or is_events variable is false //--- Retrieve news events for the current Daily period into array CalendarArray NewsObj.EconomicDetailsMemory(CalendarArray,iTime(Symbol(),PERIOD_D1,0)); //--- Iterate through all events in CalendarArray for(uint i=0;i<CalendarArray.Size();i++) { //--- Create event object with the news properties EventObj(0,CalendarArray[i].EventName+" "+CalendarArray[i].CountryName+" "+CalendarArray[i].EventDate, CalendarArray[i].EventName+"["+CalendarArray[i].CountryName+"]",StringToTime(CalendarArray[i].EventDate)); } //--- Refresh the chart/ update the chart ChartRefresh(); }
交易管理类
这个类将负责为我们EA开启交易。这个类的功能可能会在后续文章中进一步扩展。交易管理类将从风险管理类继承,以配置每笔交易的手数。
#include <Trade\Trade.mqh> #include <Trade\OrderInfo.mqh> #include <Trade\SymbolInfo.mqh> #include "RiskManagement.mqh" #include "TimeManagement.mqh" //+------------------------------------------------------------------+ //|TradeManagement class | //+------------------------------------------------------------------+ class CTradeManagement:CRiskManagement { private: CTrade Trade;//Trade class object CSymbolProperties CSymbol;//SymbolProperties class object CTimeManagement CTime;//TimeManagement class object bool TradeResult;//boolean to store trade result double mySL;//double variable to store Stoploss double myTP;//double variable to store Takeprofit public: //--- Class constructor CTradeManagement(string SYMBOL=NULL) { //--- Set symbol name CSymbol.SetSymbolName(SYMBOL); } //--- Class destructor ~CTradeManagement(void) {} //--- Will retrieve if there are any open trades bool OpenTrade(ENUM_POSITION_TYPE Type,ulong Magic,string COMMENT=NULL); //--- Will retrieve if there are any deals bool OpenedDeal(ENUM_DEAL_TYPE Type,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade bool Buy(double SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade with integer SL bool Buy(int SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade with integer TP bool Buy(double SL,int TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open buy trade with integer SL & TP bool Buy(int SL,int TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade bool Sell(double SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade with integer SL bool Sell(int SL,double TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade with integer TP bool Sell(double SL,int TP,ulong Magic,string COMMENT=NULL); //--- Will attempt open sell trade with integer SL & TP bool Sell(int SL,int TP,ulong Magic,string COMMENT=NULL); };
下面的函数将检查是否存在具有特定头寸类型(买入/卖出)、Magic数字(唯一标识)和注释(头寸详情)的未平仓头寸。我们将使用这个函数来检查在新闻事件发生时我们是否已经开启了一笔交易,从而避免开启额外的/不必要的交易。
//+------------------------------------------------------------------+ //|Will retrieve if there are any open trades | //+------------------------------------------------------------------+ bool CTradeManagement::OpenTrade(ENUM_POSITION_TYPE Type,ulong Magic,string COMMENT=NULL) { //--- Iterate through all open positions for(int i=0; i<PositionsTotal(); i++) { //--- Check if Position ticket is above zero if(PositionGetTicket(i)>0) { //--- Check if the Position's Symbol,Magic,Type,Comment is correct if(PositionGetString(POSITION_SYMBOL)==CSymbol.GetSymbolName()&&PositionGetInteger(POSITION_MAGIC)==Magic &&PositionGetInteger(POSITION_TYPE)==Type&&PositionGetString(POSITION_COMMENT)==COMMENT) { //--- Return true when there is an open position return true; } } } //--- No open positions found. return false; }
OpenedDeal 函数将检查任何已开启的交易,这可能是买入或卖出的交易。我们需要这个函数来防止我们在新闻事件期间关闭一笔交易后,EA又开启新的交易。如果没有这个函数,例如在非农就业报告(NFP)即将发布时,EA可能会开启一笔买入交易。如果因为市场波动导致这笔交易被关闭,我们不希望EA再开启另一笔交易,因为我们已经交易过该事件,不需要更多的交易,这可能会导致不必要的损失。
//+------------------------------------------------------------------+ //|Will retrieve if there are any deals | //+------------------------------------------------------------------+ bool CTradeManagement::OpenedDeal(ENUM_DEAL_TYPE Type,ulong Magic,string COMMENT=NULL) { //--- Check History starting from 2 minutes ago if(HistorySelect(CTime.TimeMinusOffset(TimeTradeServer(),CTime.MinutesS(2)),TimeTradeServer())) { //--- Iterate through all history deals for(int i=0; i<HistoryDealsTotal(); i++) { //--- Assign history deal ticket ulong ticket = HistoryDealGetTicket(i); //--- Check if ticket is more than zero if(ticket>0) { //--- Check if the Deal's Symbol,Magic,Type,Comment is correct if(HistoryDealGetString(ticket,DEAL_SYMBOL)==CSymbol.GetSymbolName()&& HistoryDealGetInteger(ticket,DEAL_MAGIC)==Magic&&HistoryDealGetInteger(ticket,DEAL_TYPE)==Type &&HistoryDealGetString(ticket,DEAL_COMMENT)==COMMENT) { //--- Return true when there are any deals return true; } } } } //--- No deals found. return false; }
下面的函数负责开启所有买入/多头的市价订单。
//+------------------------------------------------------------------+ //|Will attempt open buy trade | //+------------------------------------------------------------------+ bool CTradeManagement::Buy(double SL,double TP,ulong Magic,string COMMENT=NULL) { //--- Normalize the SL Price CSymbol.NormalizePrice(SL); //--- Normalize the TP Price CSymbol.NormalizePrice(TP); //--- Set the order type for Risk management calculation SetOrderType(ORDER_TYPE_BUY); //--- Set open price for Risk management calculation OpenPrice = CSymbol.Ask(); //--- Set close price for Risk management calculation ClosePrice = SL; //--- Set Trade magic number Trade.SetExpertMagicNumber(Magic); //--- Check if there are any open trades or opened deals already if(!OpenTrade(POSITION_TYPE_BUY,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_BUY,Magic,COMMENT)) { //--- Iterate through the Lot-sizes if they're more than max-lot for(double i=Volume();i>=CSymbol.LotsMin();i-=CSymbol.LotsMax()) { //--- normalize Lot-size NormalizeLotsize(i); //--- Open trade with a Lot-size not more than max-lot TradeResult = Trade.Buy((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,CSymbol.GetSymbolName(),CSymbol.Ask(),SL,TP,COMMENT); //--- Check if trade failed. if(!TradeResult) { return TradeResult; } } } else { //--- Trade failed because there is an open trade or opened deal return false; } //--- Return trade result. return TradeResult; }
下面的函数负责开启所有卖出/空头的市价订单。
//+------------------------------------------------------------------+ //|Will attempt open sell trade | //+------------------------------------------------------------------+ bool CTradeManagement::Sell(double SL,double TP,ulong Magic,string COMMENT=NULL) { //--- Normalize the SL Price CSymbol.NormalizePrice(SL); //--- Normalize the TP Price CSymbol.NormalizePrice(TP); //--- Set the order type for Risk management calculation SetOrderType(ORDER_TYPE_SELL); //--- Set open price for Risk management calculation OpenPrice = CSymbol.Bid(); //--- Set close price for Risk management calculation ClosePrice = SL; //--- Set Trade magic number Trade.SetExpertMagicNumber(Magic); //--- Check if there are any open trades or opened deals already if(!OpenTrade(POSITION_TYPE_SELL,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_SELL,Magic,COMMENT)) { //--- Iterate through the Lot-sizes if they're more than max-lot for(double i=Volume();i>=CSymbol.LotsMin();i-=CSymbol.LotsMax()) { //--- normalize Lot-size NormalizeLotsize(i); //--- Open trade with a Lot-size not more than max-lot TradeResult = Trade.Sell((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,CSymbol.GetSymbolName(),CSymbol.Bid(),SL,TP,COMMENT); //--- Check if trade failed. if(!TradeResult) { return TradeResult; } } } else { //--- Trade failed because there is an open trade or opened deal return false; } //--- Return trade result. return TradeResult; }
新闻交易EA
我们为EA添加了新的输入参数,我们已经在引言部分看到了这些参数的说明。
//--- width and height of the canvas (used for drawing) #define IMG_WIDTH 200 #define IMG_HEIGHT 100 //--- enable to set color format ENUM_COLOR_FORMAT clr_format=COLOR_FORMAT_XRGB_NOALPHA; //--- drawing array (buffer) uint ExtImg[IMG_WIDTH*IMG_HEIGHT]; #include "News.mqh" CNews NewsObject;//Class object for News #include "TimeManagement.mqh" CTimeManagement CTM;//Class object for Time Management #include "WorkingWithFolders.mqh" CFolders Folder;//Class object for Folders #include "ChartProperties.mqh" CChartProperties Chart;//Class object for Chart Properties #include "RiskManagement.mqh" CRiskManagement CRisk;//Class object for Risk Management #include "CommonGraphics.mqh" CCommonGraphics *CGraphics;//Class pointer object for Common Graphics CCandleProperties *CP;//Class pointer object for Candle Properties #include "TradeManagement.mqh" CTradeManagement Trade;//Class object for Trade Management //--- used to separate Input Menu enum iSeparator { Delimiter//__________________________ }; //--- for chart color Mode selection enum DisplayMode { Display_LightMode,//LIGHT MODE Display_DarkMode//DARK MODE }; sinput group "+--------| DISPLAY |--------+"; sinput DisplayMode iDisplayMode=Display_LightMode;//CHART COLOUR MODE sinput Choice iDisplay_NewsInfo=Yes;//DISPLAY NEWS INFO sinput Choice iDisplay_EventObj=Yes;//DISPLAY EVENT OBJ sinput Choice iDisplay_Spread=Yes;//DISPLAY SPREAD RATING sinput Choice iDisplay_Date=Yes;//DISPLAY DATE sinput group ""; sinput group "+--------| DST SCHEDULE |--------+"; input DSTSchedule ScheduleDST=AutoDst_Selection;//SELECT DST OPTION sinput iSeparator iCustomSchedule=Delimiter;//__________________________ sinput iSeparator iCustomScheduleL=Delimiter;//CUSTOM DST input DST_type CustomSchedule=DST_NONE;//SELECT CUSTOM DST sinput group ""; sinput group "+--------| RISK MANAGEMENT |--------+"; input RiskOptions RISK_Type=MINIMUM_LOT;//SELECT RISK OPTION input RiskFloor RISK_Mini=RiskFloorMin;//RISK FLOOR input double RISK_Mini_Percent=75;//MAX-RISK [100<-->0.01]% input RiskCeil RISK_Maxi=RiskCeilMax;//RISK CEILING sinput iSeparator iRisk_1=Delimiter;//__________________________ sinput iSeparator iRisk_1L=Delimiter;//PERCENTAGE OF [BALANCE | FREE-MARGIN] input double Risk_1_PERCENTAGE=3;//[100<-->0.01]% sinput iSeparator iRisk_2=Delimiter;//__________________________ sinput iSeparator iRisk_2L=Delimiter;//AMOUNT PER [BALANCE | FREE-MARGIN] input double Risk_2_VALUE=1000;//[BALANCE | FREE-MARGIN] input double Risk_2_AMOUNT=10;//EACH AMOUNT sinput iSeparator iRisk_3=Delimiter;//__________________________ sinput iSeparator iRisk_3L=Delimiter;//LOTSIZE PER [BALANCE | FREE-MARGIN] input double Risk_3_VALUE=1000;//[BALANCE | FREE-MARGIN] input double Risk_3_LOTSIZE=0.1;//EACH LOTS(VOLUME) sinput iSeparator iRisk_4=Delimiter;//__________________________ sinput iSeparator iRisk_4L=Delimiter;//CUSTOM LOTSIZE input double Risk_4_LOTSIZE=0.01;//LOTS(VOLUME) sinput iSeparator iRisk_5=Delimiter;//__________________________ sinput iSeparator iRisk_5L=Delimiter;//PERCENTAGE OF MAX-RISK input double Risk_5_PERCENTAGE=1;//[100<-->0.01]% sinput group ""; sinput group "+--------| NEWS SETTINGS |--------+"; input Calendar_Importance iImportance=Calendar_Importance_High;//CALENDAR IMPORTANCE input Event_Frequency iFrequency=Event_Frequency_ALL;//EVENT FREQUENCY input Event_Sector iSector=Event_Sector_ALL;//EVENT SECTOR input Event_Type iType=Event_Type_Indicator;//EVENT TYPE input Event_Currency iCurrency=Event_Currency_Symbol;//EVENT CURRENCY sinput group ""; sinput group "+--------| TRADE SETTINGS |--------+"; input uint iStoploss=500;//STOPLOSS [0=NONE] input uint iTakeprofit=500;//TAKEPROFIT [0=NONE] input uint iSecondsPreEvent=5;//PRE-ENTRY SEC input DayOfTheWeek TradingDay=AllDays;//TRADING DAY OF WEEK sinput group ""; //--- to keep track of start-up time datetime Startup_date;
在下面的 OnInit 整数函数中,我们在设置EA进行交易时会经历不同的流程,无论是在策略测试器中还是不在策略测试器中。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Assign if in LightMode or not isLightMode=(iDisplayMode==Display_LightMode)?true:false; //--- call function for common initialization procedure InitCommon(); //--- store Init result int InitResult; if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester { //--- initialization procedure outside strategy tester InitResult=InitNonTester(); } else { //--- initialization procedure inside strategy tester InitResult=InitTester(); } //--- Create DB in memory NewsObject.CreateEconomicDatabaseMemory(); //--- Initialize Common graphics class pointer object CGraphics = new CCommonGraphics(Answer(iDisplay_Date),Answer(iDisplay_Spread),Answer(iDisplay_NewsInfo),Answer(iDisplay_EventObj)); CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create chart objects //--- Initialize Candle properties pointer object CP = new CCandleProperties(); //--- Store start-up time. Startup_date = TimeTradeServer(); //--- return Init result return InitResult; }
在下面的函数中,我们为策略测试器和常规交易环境初始化相关属性。
//+------------------------------------------------------------------+ //|function for common initialization procedure | //+------------------------------------------------------------------+ void InitCommon() { //Initializing CRiskManagement variable for Risk options RiskProfileOption = RISK_Type; //Initializing CRiskManagement variable for Risk floor RiskFloorOption = RISK_Mini; //Initializing CRiskManagement variable for RiskFloorMax RiskFloorPercentage = (RISK_Mini_Percent>100)?100: (RISK_Mini_Percent<0.01)?0.01:RISK_Mini_Percent;//Percentage cannot be more than 100% or less than 0.01% //Initializing CRiskManagement variable for Risk ceiling RiskCeilOption = RISK_Maxi; //Initializing CRiskManagement variable for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) Risk_Profile_1 = (Risk_1_PERCENTAGE>100)?100: (Risk_1_PERCENTAGE<0.01)?0.01:Risk_1_PERCENTAGE;//Percentage cannot be more than 100% or less than 0.01% //Initializing CRiskManagement variables for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) Risk_Profile_2.RiskAmountBoF = Risk_2_VALUE; Risk_Profile_2.RiskAmount = Risk_2_AMOUNT; //Initializing CRiskManagement variables for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) Risk_Profile_3.RiskLotBoF = Risk_3_VALUE; Risk_Profile_3.RiskLot = Risk_3_LOTSIZE; //Initializing CRiskManagement variable for Risk option (CUSTOM LOTSIZE) Risk_Profile_4 = Risk_4_LOTSIZE; //Initializing CRiskManagement variable for Risk option (PERCENTAGE OF MAX-RISK) Risk_Profile_5 = (Risk_5_PERCENTAGE>100)?100: (Risk_5_PERCENTAGE<0.01)?0.01:Risk_5_PERCENTAGE;//Percentage cannot be more than 100% or less than 0.01% //--- Initializing DST Schedule variables MyDST = ScheduleDST; MySchedule = CustomSchedule; //--- Initializing News filter variables myFrequency=iFrequency; myImportance=iImportance; mySector=iSector; myType=iType; myCurrency=iCurrency; Chart.ChartRefresh();//Load chart configurations }
下面的函数将只为常规交易环境进行初始化。
//+------------------------------------------------------------------+ //|function for initialization procedure outside strategy tester | //+------------------------------------------------------------------+ int InitNonTester() { //--- Check if in Strategy tester! if(MQLInfoInteger(MQL_TESTER)) { //--- Initialization failed. return(INIT_SUCCEEDED); } //--- create OBJ_BITMAP_LABEL object for drawing ObjectCreate(0,"STATUS",OBJ_BITMAP_LABEL,0,0,0); ObjectSetInteger(0,"STATUS",OBJPROP_XDISTANCE,5); ObjectSetInteger(0,"STATUS",OBJPROP_YDISTANCE,22); //--- specify the name of the graphical resource ObjectSetString(0,"STATUS",OBJPROP_BMPFILE,"::PROGRESS"); uint w,h; // variables for receiving text string sizes uint x,y; // variables for calculation of the current coordinates of text string anchor points /* In the Do while loop below, the code will check if the terminal is connected to the internet. If the the program is stopped the loop will break, if the program is not stopped and the terminal is connected to the internet the function CreateEconomicDatabase will be called from the News.mqh header file's object called NewsObject and the loop will break once called. */ bool done=false; do { //--- clear the drawing buffer array ArrayFill(ExtImg,0,IMG_WIDTH*IMG_HEIGHT,0); if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { //-- integer dots used as a loading animation static int dots=0; //--- set the font TextSetFont("Arial",-150,FW_EXTRABOLD,0); TextGetSize("Waiting",w,h);//get text width and height values //--- calculate the coordinates of the 'Waiting' text x=10;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically //--- output the 'Waiting' text to ExtImg[] buffer TextOut("Waiting",x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CSymbol.Background()),clr_format); //--- calculate the coordinates for the dots after the 'Waiting' text x=w+13;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically TextSetFont("Arial",-160,FW_EXTRABOLD,0); //--- output of dots to ExtImg[] buffer TextOut(StringSubstr("...",0,dots),x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CSymbol.Background()),clr_format); //--- update the graphical resource ResourceCreate("::PROGRESS",ExtImg,IMG_WIDTH,IMG_HEIGHT,0,0,IMG_WIDTH,clr_format); //--- force chart update Chart.Redraw(); dots=(dots==3)?0:dots+1; //-- Notify user that program is waiting for connection Print("Waiting for connection..."); Sleep(500); continue; } else { //--- set the font TextSetFont("Arial",-120,FW_EXTRABOLD,0); TextGetSize("Getting Ready",w,h);//get text width and height values x=20;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically //--- output the text 'Getting Ready...' to ExtImg[] buffer TextOut("Getting Ready...",x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CSymbol.Background()),clr_format); //--- update the graphical resource ResourceCreate("::PROGRESS",ExtImg,IMG_WIDTH,IMG_HEIGHT,0,0,IMG_WIDTH,clr_format); //--- force chart update Chart.Redraw(); //-- Notify user that connection is successful Print("Connection Successful!"); NewsObject.CreateEconomicDatabase();//calling the database create function done=true; } } while(!done&&!IsStopped()); //-- Delete chart object ObjectDelete(0,"STATUS"); //-- force chart to update Chart.Redraw(); //--- Initialization succeeded. return(INIT_SUCCEEDED); }
下面的函数将仅针对策略测试器环境进行初始化。
//+------------------------------------------------------------------+ //|function for initialization procedure inside strategy tester | //+------------------------------------------------------------------+ int InitTester() { //--- Check if not in Strategy tester! if(!MQLInfoInteger(MQL_TESTER)) { //--- Initialization failed. return(INIT_SUCCEEDED); } //Checks whether the database file exists if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON)) { //--- Warning messages Print("Necessary Files Do not Exist!"); Print("Run Program outside of the Strategy Tester"); Print("Necessary Files Should be Created First"); //--- Initialization failed. return(INIT_FAILED); } else { //Checks whether the latest database date includes the time and date being tested datetime latestdate = CTM.TimeMinusOffset(NewsObject.GetLatestNewsDate(),CTM.DaysS());//Day before the latest recorded time in the database if(latestdate<TimeTradeServer()) { Print("Necessary Files outdated!"); Print("To Update Files: Run Program outside of the Strategy Tester"); } Print("Database Dates End at: ",latestdate); PrintFormat("Dates after %s will not be available for backtest",TimeToString(latestdate)); } //--- Initialization succeeded. return(INIT_SUCCEEDED); }
下面的函数将在每一个新的报价(tick)到来时运行。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Run procedures Execution(); }
在下面的这个函数中,我们调用了所有使EA能够正常运行的函数。并不是每个函数都需要在每个报价到来时运行,因此我们只在新的特定K线(例如每个日K图)到来时调用某些特定的函数。这有助于提高性能,减少不必要的函数调用和资源占用。
//+------------------------------------------------------------------+ //|Execute program procedures | //+------------------------------------------------------------------+ void Execution() { //--- Update realtime Graphic every 1 min if(CP.NewCandle(1,PERIOD_M1)) { CGraphics.Block_2_Realtime(iSecondsPreEvent); } //--- function to open trades EnterTrade(); //--- Check if not start-up date if(!CTM.DateisToday(Startup_date)) { //--- Run every New Daily Candle if(CP.NewCandle(2,PERIOD_D1)) { //--- Check if not in strategy tester if(!MQLInfoInteger(MQL_TESTER)) { //--- Update/Create DB in Memory NewsObject.CreateEconomicDatabaseMemory(); } CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create/Re-create chart objects //--- Update Realtime Graphics CGraphics.Block_2_Realtime(iSecondsPreEvent); } //--- Check if not in strategy tester if(!MQLInfoInteger(MQL_TESTER)) { //--- Run every New Hourly Candle if(CP.NewCandle(3,PERIOD_H1)) { //--- Check if DB in Storage needs an update if(NewsObject.UpdateRecords()) { //--- initialization procedure outside strategy tester InitNonTester(); } } } } else { //--- Run every New Daily Candle if(CP.NewCandle(4,PERIOD_D1)) { //--- Update Event objects on chart CGraphics.NewsEvent(); } } }
下面的函数将负责根据事件影响和事件货币开启市价订单的交易。如果事件货币等于利润货币,并且影响类型是 CALENDAR_IMPACT_NEGATIVE,我们将开启一笔买入交易,因为我们假设在新闻事件期间利润货币会贬值;如果事件货币等于利润货币,并且影响类型是 CALENDAR_IMPACT_POSITIVE,我们将开启一笔卖出交易,因为我们假设在新闻事件期间利润货币会升值。
//+------------------------------------------------------------------+ //|function to open trades | //+------------------------------------------------------------------+ void EnterTrade() { //--- static variable for storing upcoming event Impact value static ENUM_CALENDAR_EVENT_IMPACT Impact=CALENDAR_IMPACT_NA; //--- Check if Upcoming news date has passed and if upcoming news is not null and if new minute candle has formed. if(datetime(UpcomingNews.EventDate)<TimeTradeServer()&&UpcomingNews.CountryName!=NULL&&CP.NewCandle(5,PERIOD_M1)) { //--- Update for next upcoming news NewsObject.EconomicNextEvent(); //--- Get impact value for upcoming news Impact=NewsObject.GetImpact(); } //--- Check if upcoming news date is about to occur and if it is the trading day of week if(CTM.TimePreEvent(CTM.TimeMinusOffset(datetime(UpcomingNews.EventDate),(iSecondsPreEvent==0)?1:iSecondsPreEvent) ,datetime(UpcomingNews.EventDate)) &&CTM.isDayOfTheWeek(TradingDay)) { //--- Check each Impact value type switch(Impact) { //--- When Impact news is negative case CALENDAR_IMPACT_NEGATIVE: //--- Check if profit currency is news event currency if(UpcomingNews.EventCurrency==CSymbol.CurrencyProfit()) { //--- Open buy trade with Event id as Magic number Trade.Buy(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } else { //--- Open sell trade with Event id as Magic number Trade.Sell(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } break; //--- When Impact news is positive case CALENDAR_IMPACT_POSITIVE: //--- Check if profit currency is news event currency if(UpcomingNews.EventCurrency==CSymbol.CurrencyProfit()) { //--- Open sell trade with Event id as Magic number Trade.Sell(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } else { //--- Open buy trade with Event id as Magic number Trade.Buy(iStoploss,iTakeprofit,ulong(UpcomingNews.EventId),"NewsTrading"); } break; //--- Unknown default: break; } } }
结论
在本文中,我们介绍了如何在内存中添加一个数据库,并创建额外的视图,以提供更多关于 MQL5 经济日历中事件的信息。我们在图表上创建了额外的图形对象,用于显示即将发生的事件的信息,并且实现了深色模式功能。此外,我们还为用户/交易者添加了相关的输入选项,以便他们根据自己的偏好筛选新闻数据,以及为交易添加了EA输入选项。同时,文章还解释了我们如何根据事件影响开启市价订单,以及事件影响如何与我们的交易策略相关。
我很乐意听取您的意见,任何分享的观点我都将不胜感激。在下一篇文章中,我们将为新闻输入添加更多功能,以满足个别经济事件的需求,并使用待处理订单进行交易,以提供更多的灵活性,同时也会介绍不需要事件影响的交易方式。感谢您的阅读!
视频
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/15359


