
交易机器人在实际交易中的自动优化
简介
据推测,获得已根据历史记录调整的输入的 Expert Advisor 在首次(在相当短的时间内)交易中能够盈利。在我观看2006 自动交易锦标赛之后,这一推测得到了间接的证明。锦标赛刚开始时能盈利的智能交易系统很多,之后就大大减少,一些智能交易系统变得毫无竞争力。这就是我认为这些没能笑到最后的智能交易系统大部分都根据历史记录进行过调整的原因。
在实践中验证这一假设的想法源于此网站的俄语论坛中的理想的自动交易系统版块。主要的想法是每天自动优化一次 EA,然后分析获得的优化结果,并将它们记录到 EA 的变量中。为了实施这一想法,我们决定采用 MetaTrader 4 客户终端中的现成 Expert Advisor(即 MACD 样本),并把我们自己的自动优化函数插入到该 Expert Advisor 中。稍后,该自动优化器的代码就编写完毕并上传到同一论坛中的自动优化器版块中。再过了一段时间,自动优化器的子版块中出现了对该想法的第一条确认消息。后来,此优化器被转变为一个 mqh 库以提高其可用度。
安装自动优化程序
以下是执行此任务的必要流程:
- 将 MACD Sample_1.mq4 复制到已初步安装并连接到互联网的 MetaTrader 4 客户终端的“expert”文件夹中;并
- 将该文件夹与已安装的 MetaTrader 4 客户终端一同复制到一个新位置上。
为方便起见,下文中我们将把原始终端称为“终端”,将副本称为“终端测试程序”。我们将使用起初由终端提供,后经略微更改的 Expert Advisor(MACD Sample_1.mq4)对时间范围 H1 内的 EURUSD 执行一次检查性测试。

终端测试程序
请勿忘记在终端测试程序中编译 MACD Sample_1.mq4。首先我们启动客户终端,然后启动策略测试程序,并按下方的屏幕截图进行设置。

优化将执行三天。这已足够检查自动优化程序了。我们将根据以下公式选择优化日期“开始日期”:当前日期减去三天。优化期间,必须下载选定交易品种(本案例中为 EURUSD)的必要历史记录。
首次执行优化的用户会在 MetaTrader 4 客户终端的“帮助”菜单中找到必要程序的说明:<帮助 - 帮助主题 F1 - 自动交易 - Expert 优化 - 设置>。或者可以阅读文章在 MetaTrader 4 客户终端中测试 Expert Advisor:外部一览。
然后我们检查要优化的变量,如下方屏幕截图中所示。

自动优化仅限四个变量,不过用三个变量就足以达成我们的目的了,还能节省时间。选择这些变量后,将优化设置存储到名为 MACD Sample_1.set 的设置文件中。此文件必须保存到终端测试程序的“测试程序”文件夹内。然后启动预优化并记住开始时间。必须计算使用预设参数进行自动优化所需的时间。完成优化后,我们将计算必要的等待时间。然后必须关闭此终端,否则我们将无法用程序启动它。
终端中 Expert Advisor 的设置
要进行设置,让我们在 MetaEditor 中打开测试用 Expert Advisor MACD Sample_1.mq4,然后执行以下步骤:
- 设置自动优化的启动时间,例如设在每天的 00:01:
datetime SetHour = 0; // Optimization starting hour; datetime SetMinute = 1; // Optimization starting minute.
- 设置进行优化的天数(必须与预优化的设置天数相同):
int TestDay = 3;
- 设置我们之前计算出的优化结束等待时间(以分钟为单位),例如 4 分钟:
int TimeOut = 4;
- 键入 Expert Advisor 名称:
string NameMTS = "MACD Sample_1"; // EA's name
- 键入设置文件名称和设置:
// Set-file name with the settings string NameFileSet = "MACD Sample_1.set";
- 键入包含已安装终端测试程序的文件夹路径,例如:
// Path to the tester string PuthTester = "D:\Program Files\Forex Best Trade Station";
- 设置过滤优先级:
// Sorting by Maximal profit int Gross_Profit = 1; // Sorting by Maximal profit factor int Profit_Factor = 2; // Sorting by Maximal expected payoff int Expected_Payoff = 3;
- 写入用于优化的变量名称:
string Per1 = "FastEMA"; string Per2 = "SlowEMA"; string Per3 = "SignalSMA"; string Per4 = "";
- 将随附文件 auto_optimization.mqh 复制到“include”文件夹中;
- 在 Expert Advisor 中包括此库文件:
//--- Including the auto optimizer's library #include <auto_optimization.mqh>
- 剩下的就是将下方的代码复制到您 Expert Advisor 的 start() 函数的开头。MACD Sample_1.mq4 中已包含该代码。
// Not to be launched at testing and optimizing if(!IsTesting() && !IsOptimization()) { // Compare the current hour with that preset for launching if(TimeHour(TimeLocal()) == SetHour) { // Protection against restarting if(!StartTest) { // Compare the minute range to the minute // preset for launching if(TimeMinute(TimeLocal()) > SetMinute - 1) { // the range is necessary, in case that for some reasons // no new tick is available for a long time if(TimeMinute(TimeLocal()) < SetMinute + 1) { // Flag of tester launching StartTest = true; TimeStart = TimeLocal(); Tester(TestDay, NameMTS, NameFileSet, PuthTester, TimeOut, Gross_Profit, Profit_Factor, Expected_Payoff, Per1, Per2, Per3, Per4); } } } } } FastEMA = GlobalVariableGet(Per1); SlowEMA = GlobalVariableGet(Per2); SignalSMA = GlobalVariableGet(Per3); TrailingStop = GlobalVariableGet(Per4); // If the tester launching is flagged if(StartTest) { // If more time has elapsed the launching than it was set // to be the test waiting time if(TimeLocal() - TimeStart > TimeOut*60) { // Zeroize the flag StartTest = false; } }
这就完成了。重新编译自动优化程序之后可以启动它,但它仅适用于执行预优化时所用的交易品种和时间范围。在我们的案例中,是 H1 时间范围上的 EURUSD 交易品种。要检查自动优化程序,可将下方给出的代码插入到 int init () 函数中,之后将在 Expert Advisor 启动时启动自动优化程序。
Tester(TestDay,NameMTS,NameFileSet,PuthTester,TimeOut, Gross_Profit,Profit_Factor, Expected_Payoff, Per1,Per2,Per3,Per4);
自动优化程序如何工作
自动优化程序的工作原理是使用终端测试程序在终端中优化连接到图表的 Expert Advisor 的参数。为此,程序向终端测试程序发送一个包含优化参数 (optimise.ini) 的文件,并在优化模式下启动终端测试程序。然后,它将获取的结果 "FileReport........htm" 复制回终端,从获取的结果中筛选最佳值。

有关自动优化程序如何工作的更多详情
在预设时间(例如 00.01),自动优化程序应会启动。变量应填写值。
// Path to the terminal string PuthTerminal = TerminalPath() + "\experts\files"; // Name of the ini file for the tester string FileOptim = "optimise.ini"; string FileOptim1 = "\optimise.ini"; // Calculation of the starting date datetime DayStart = TimeLocal()-86400*TestDay; // Optimization starting date string DateStart = TimeToStr(DayStart,TIME_DATE); // Optimization ending date string DateStop = TimeToStr(TimeLocal(),TIME_DATE); // Tester report file name string FileReport = "FileReport_" + Symbol() + "_" + DateStop + ".htm"; string FileReport1 = "\FileReport_" + Symbol() + "_" + DateStop + ".htm"; // Limitation for the minimum amount of trades per day double MinTr = TestDay - 2; // Limitation for maximal amount of trades per day double MaxTr = (60 / Period()*TestDay) + 2; // The amount of attempts to copy the report file int KvoPptk = 10; // The amount of lines for sorting int StepRes = 12;
然后在字符串数组中写入 ini 文件的参数:
// Prepare the ini file for optimization ArrayOpttim[0] = ";optimise strategy tester"; // Enable/Disable Expert Advisors ArrayOpttim[1] = "ExpertsEnable = false"; // Name of the EA file ArrayOpttim[2] = "TestExpert=" + NameMTS; // Name of the file containing parameters ArrayOpttim[3] = "TestExpertParameters=" + NameFileSet; // Symbol ArrayOpttim[4] = "TestSymbol=" + Symbol(); // Timeframe ArrayOpttim[5] = "TestPeriod=" + Period(); // Modeling mode ArrayOpttim[6] = "TestModel=" + 0; // Recalculate ArrayOpttim[7] = "TestRecalculate=false"; // Optimization ArrayOpttim[8] = "TestOptimization=true"; // Use date ArrayOpttim[9] = "TestDateEnable=true"; // From ArrayOpttim[10] = "TestFromDate=" + DateStart; // To ArrayOpttim[11] = "TestToDate=" + DateStop; // Report file name ArrayOpttim[12] = "TestReport=" + FileReport; // Rewrite the report file ArrayOpttim[13] = "TestReplaceReport=true"; // Shut down the terminal upon completion ArrayOpttim[14] = "TestShutdownTerminal=true";
从数组中将优化参数记录到 ini 文件中。也可阅读 MetaTrader 4 客户终端“帮助”中有关如何创建 ini 文件的内容,详见 <帮助 - 帮助主题 F1 - 工具 - 启动时的配置>。
// Write data into the ini file // Find out about the array size OptimArraySize = ArraySize(ArrayOpttim); // Open a file to write opttim = FileOpen(FileOptim, FILE_CSV|FILE_WRITE, 0x7F); if(opttim > 0) { for(int i = 0; i < OptimArraySize; i++) { // from the array into the variable ini = ArrayOpttim[i]; // from the variable into the file FileWrite(opttim, ini); } // close the file FileClose(opttim); } else { Print("Failed writing data into the ini file. Error No ", GetLastError()); return(0); }
将参数记录到 ini 文件后,连接 Windows 标准交付内容中包含的 shell32.dll,并启动函数 ShellExecuteA。
#import "shell32.dll" //Connect a dll (provided with Windows) int ShellExecuteA(int hwnd,string Operation,string File,string Parameters,string Directory,int ShowCmd); #import
包含这些参数的文件将被发送到“终端测试程序”文件夹中。
// copy the ini file into the tester folder copyini = ShellExecuteA(0,"Open","xcopy", "\"" + PuthTerminal + FileOptim1 + "\" \"" + PuthTester + "\" /y", "", 3); // wait until the file is copied Sleep(1200); if(copyini < 0) { Print("Failed copying ini file"); return(0); }
然后启动测试程序,开始优化预定义变量。优化期间,Expert Advisor 处于暂停状态。
// Start Tester start = ShellExecuteA(0, "Open", "terminal.exe", FileOptim, PuthTester, 3); if(start < 0) { Print("Failed starting Tester"); return(0); } Comment("Wait until optimization is complete"); // wait until optimization is complete Sleep(60000*TimeOut);
优化完成后,测试程序将自动把结果记录到报告文件中。该文件将被复制到包含终端的文件夹中。
for(Pptk = 0; Pptk < KvoPptk; Pptk++) { //Start a cycle attempting to compy the resport file Comment("Attempt # " + Pptk + " to copy the report file"); ShellExecuteA(0, "Open", "xcopy", "\"" + PuthTester + FileReport1 + "\" \"" + PuthTerminal + "\" /y", "", 3); // wait until the file is copied Sleep(1200); // Try to open the report file file = FileOpen(FileReport, FILE_READ, 0x7F); if(file < 0) { // if it fails to open, wait some more and try again Sleep(60000); } else break; } if(file < 0) { Print("Failed copying the report file"); return(0); }
然后该报告文件中的数据将被放到字符串数组中,进行进一步的处理。
// Read from file into the array // Cycle, until the file ends while(FileIsEnding(file) == false) { // Read a string from the report file FileLine = FileReadString(file); // Find the necessary string and set the reference point there index = StringFind(FileLine, "title", 20); if(index > 0) { // Increase the array in size ArrayResize(ArrayStrg, NumStr + 1); // Record the strings from the file in the array ArrayStrg[NumStr] = FileLine; NumStr++; } } // Close the file FileClose(file); // Delete the file in order not to produce too many copies FileDelete(FileReport); // Set the array size by the amount of data read from the file ArrayResize(ArrayData, NumStr);
之后,在数组中选择必要的值:
for(text = 0; text < NumStr; text++) { select = ArrayStrg[text]; //------------------------------------------------------------------------- // Reporting text processing (These are apples and oranges) | //------------------------------------------------------------------------- // Position Pass ClStep=StringFind(select, "; \">",20)+4; // Find the end of position ClStepRazm = StringFind(select, "td>", ClStep); // Read the value CycleStep = StringSubstr(select, ClStep, ClStepRazm - ClStep); // Position Profit // Find the beginning of the position GrProf = StringFind(select, "", ClStepRazm); // Find the end of position GrProfRazm = StringFind(select, "td>", GrProf); // Read value GrossProfit = StringSubstr(select, GrProf+4, GrProfRazm - (GrProf + 4)); // Position Total Trades // Find the beginning of position TotTrad = StringFind(select, "", GrProfRazm); // Find the end of position TotTradRazm = StringFind(select, "td>", TotTrad); // Read the value TotalTrades = StringSubstr(select, TotTrad+4, TotTradRazm - (TotTrad + 4)); // Position Profitability // Find the beginning of position ProfFact = StringFind(select, "", TotTradRazm); // Find the end of position ProfFactRazm = StringFind(select, "td>", ProfFact); // Read the value ProfitFactor = StringSubstr(select, ProfFact + 4, ProfFactRazm - (ProfFact + 4)); // Position Expected Payoff // Find the beginning of position ExpPay = StringFind(select, "", ProfFactRazm); // Find the dn of position ExpPayRazm=StringFind(select, "td>", ExpPay); // Read the value ExpectedPayoff = StringSubstr(select, ExpPay+4, ExpPayRazm - (ExpPay + 4)); // Variables' positions starting with the second one // Find the beginning of position P1 = StringFind(select, Per1, 20); // Find the end of position P1k = StringFind(select, ";", P1); // Read the Variable Perem1 = StringSubstr(select, P1 + StringLen(Per1) + 1, P1k - (P1 + 1 + StringLen(Per1))); // Find the beginning of position P2 = StringFind(select, Per2, 20); // Find the end of position P2k = StringFind(select, ";", P2); // Read the Variable Perem2 = StringSubstr(select, P2 + StringLen(Per2) + 1, P2k - (P2 + 1 + StringLen(Per2))); // Find the beginning of position P3 = StringFind(select, Per3, 20); // Find the end of position P3k = StringFind(select, ";", P3); // Read the Variable Perem3 = StringSubstr(select, P3 + StringLen(Per3) + 1, P3k - (P3 + 1 + StringLen(Per3))); // Find the beginning of position P4 = StringFind(select, Per4, 20); // Find the end of position P4k = StringFind(select, ";", P4); // Read the Variable Perem4 = StringSubstr(select, P4 + StringLen(Per4) + 1, P4k - (P4 + 1 + StringLen(Per4))); Comment("The obtained results are being analyzed");
之后,获取的结果在被转变为数字格式之前,已按最小和最大交易金额进行了筛选。Profit_Factor 值中的 0 替换为 1000,以便进行正确的排序和后续的筛选。
// Transform into number format TotalTradesTransit = StrToDouble(TotalTrades); GrossProfitTransit = StrToDouble(GrossProfit); ExpectedPayoffTran = StrToDouble(ExpectedPayoff); nodubl = true; if(MinTr < TotalTradesTransit && MaxTr > TotalTradesTransit) { // Filter by the amount of trades PrFactDouble = StrToDouble(ProfitFactor); // Replace 0 in the Profit_Factor for proper analysis if(PrFactDouble == 0) { PrFactDouble = 1000; }
然后检查这些值,以进行复制和筛除。
// Filter data having identical values for(Dubl = 0; Dubl <= ResizeArayNew; Dubl++) { // Start the loop searching for identical values if(GrossProfitTransit == ArrayData[Dubl][1]) { // check whether the results for maximal profit coincide if(TotalTradesTransit == ArrayData[Dubl][2]) { // check whether the results for the amount of trades coincide if(PrFactDouble == ArrayData[Dubl][3]) { // check whether the results for Profit Factor coincide if(ExpectedPayoffTran == ArrayData[Dubl][4]) { // check whether the results for expected payoff coincide nodubl=false; // If everything coincides, flag it as coincided } } } } }
在数组中写入用于排序的值。
// Write the filtered data in the array if(nodubl) { ArrayData[text][1] = GrossProfitTransit; ArrayData[text][2] = TotalTradesTransit; ArrayData[text][3] = PrFactDouble; ArrayData[text][4] = ExpectedPayoffTran; ArrayData[text][5] = StrToDouble(Perem1); ArrayData[text][6] = StrToDouble(Perem2); ArrayData[text][7] = StrToDouble(Perem3); ArrayData[text][8] = StrToDouble(Perem4); ResizeArayNew++; }
然后开始以预设优先顺序分析数据。分析程序如下:
- 循环启动,在第一遍时,按第一个参数对值进行排序,例如按最大利润排序;选择一些(默认为 12 个)最佳值,其他的被删除;
- 在第二遍时,按第二个参数对值进行排序,例如按获利因子排序;选择一些最佳值,数量是第一次排序后数量的一半,其他的被删除。
- 在第三遍时,对第三个参数进行最后一次排序,例如按预期收益排序;取第二次排序后一半数量的值,其他的被删除。
// Analyzer // Analyzing principle is the sequential checking of maximal // values according to the predefined filtering priority ArrayResize(ArrayTrans, ResizeArayNew - 1); for(int PrioStep = 1; PrioStep < 4; PrioStep++) { for(PrCycle = 0; PrCycle < ResizeArayNew; PrCycle++) { Sort = ArrayData[PrCycle][0]; Prior1 = ArrayData[PrCycle][1]; transit = ArrayData[PrCycle][2]; Prior2 = ArrayData[PrCycle][3]; Prior3 = ArrayData[PrCycle][4]; transit1 = ArrayData[PrCycle][5]; transit2 = ArrayData[PrCycle][6]; transit3 = ArrayData[PrCycle][7]; transit4 = ArrayData[PrCycle][8]; if(PrioStep == 1) { //Prepare for the 1st sorting if(Gross_Profit ==1) { SortTrans = Prior1; } if(Profit_Factor == 1) { SortTrans = Prior2; } if(Expected_Payoff == 1) { SortTrans = Prior3; } } if(PrioStep == 2) { // Restore if(Gross_Profit ==1) { Prior1 = Sort; } if(Profit_Factor == 1) { Prior2 = Sort; } if(Expected_Payoff == 1) { Prior3 = Sort; } //Prepare for the 2nd sorting if(Gross_Profit == 2) { SortTrans = Prior1; } if(Profit_Factor == 2) { SortTrans = Prior2; } if(Expected_Payoff == 2) { SortTrans = Prior3; } } if(PrioStep == 3) { // Restore if(Gross_Profit == 2) { Prior1 = Sort; } if(Profit_Factor == 2) { Prior2 = Sort; } if(Expected_Payoff == 2) { Prior3 = Sort; } //Prepare for the 3rd sorting if(Gross_Profit ==3) { SortTrans = Prior1; } if(Profit_Factor == 3) { SortTrans = Prior2; } if(Expected_Payoff == 3) { SortTrans = Prior3; } } ArrayTrans[PrCycle][0] = SortTrans; ArrayTrans[PrCycle][1] = Prior1; ArrayTrans[PrCycle][2] = transit; ArrayTrans[PrCycle][3] = Prior2; ArrayTrans[PrCycle][4] = Prior3; ArrayTrans[PrCycle][5] = transit1; ArrayTrans[PrCycle][6] = transit2; ArrayTrans[PrCycle][7] = transit3; ArrayTrans[PrCycle][8] = transit4; } ArraySort(ArrayTrans,StepRes, 0, MODE_DESCEND); // Sort the array ArrayResize(ArrayTrans, StepRes); // Cut off the unnecessary things for(int CopyAr = 0; CopyAr < StepRes; CopyAr++) { ArrayData[CopyAr][0] = ArrayTrans[CopyAr][0]; ArrayData[CopyAr][1] = ArrayTrans[CopyAr][1]; ArrayData[CopyAr][2] = ArrayTrans[CopyAr][2]; ArrayData[CopyAr][3] = ArrayTrans[CopyAr][3]; ArrayData[CopyAr][4] = ArrayTrans[CopyAr][4]; // Per1 Variable 1 ArrayData[CopyAr][5] = ArrayTrans[CopyAr][5]; // Per2 Variable 2 ArrayData[CopyAr][6] = ArrayTrans[CopyAr][6]; // Per3 Variable 3 ArrayData[CopyAr][7] = ArrayTrans[CopyAr][7]; // Per4 Variable 4 ArrayData[CopyAr][8] = ArrayTrans[CopyAr][8]; } StepRes = StepRes / 2; }
以这种方式过滤后的值被写入到全局变量中。全局变量中的值将在 EA 中被替换。
// Write the obtained results in variables double Peremen1 = ArrayTrans[0][5]; double Peremen2 = ArrayTrans[0][6]; double Peremen3 = ArrayTrans[0][7]; double Peremen4 = ArrayTrans[0][8]; // If the variable name is specified, write the result in // global variables if(Per1 != "") { GlobalVariableSet(Per1, Peremen1); } if(Per2 != "") { GlobalVariableSet(Per2,Peremen2); } if(Per3 != "") { GlobalVariableSet(Per3,Peremen3); } if(Per4 != "") { GlobalVariableSet(Per4,Peremen4); } Comment(Per1, " ", Peremen1, " | ", Per2, " ", Peremen2, " | ", Per3, " ", Peremen3, " | ", Per4, " ", Peremen4); Print(Per1, " ", Peremen1, " | ", Per2, " ", Peremen2, " | ", Per3, " ", Peremen3," | ",Per4," ",Peremen4); } // Function ends. That's all, automated optimization is complete.
自动优化程序运行结果
可通过图表左上角显示的消息查看自动优化程序的运行结果,如下方的屏幕截图中所示:
如果消息中显示了优化结果,则表示优化已完成并已收到数据。
要独立估算自动优化程序的工作,用户需要浏览所有包含中间数据的文件以及在工作流程期间保存的文件。测试程序将数据存储在名称为 "FileReport_EURUSD_2007.03.12. htm" 的文件中,此文件名中的交易品种和日期就是根据选定交易品种和当前优化日期进行替换的。可在“终端测试程序”文件夹中找到此文件。这些文件和报告不会被自动删除,因此用户可以用它们检查参数的更改情况。

下一个文件 FileTest1.csv 是在按交易金额过滤值并删除了副本之后保存的。此文件的保存路径:D:\Program Files\terminal_folder_ame\experts\files

然后,每次筛选操作后得到的值被保存到 FileTest2.csv。此文件也保存到上述路径:D:\Program Files\terminal_folder_name\experts\files

上表显示所获值的过滤方法。过滤顺序默认设置为:1- Gross_Profit,2- Profit_Factor,3- Expected_Payoff。
自动优化程序的代码包含详细注释,必要时可以填入最合适的变量参数。例如,您要针对非最近日期的一段时间优化您的 EA,或是您计划在优化时段内增加/减少交易金额。要达到这个目的,您只需在 auto_optimization.mqh 中直接更改对应的变量。
// Limitation of minimal amount of trades per day double MinTr = TestDay - 2; // Limitation on maximal amount of trades per day double MaxTr = (60 / Period()*TestDay) + 2; // The amount of attempts to copy the report file int KvoPptk = 10; // The amount of strings to be sorted int StepRes = 12;
总结
本文并非用于让新手学习优化元素,因此强烈建议在设置您的 Expert Advisor 的自动优化之前先了解正常的优化方式。最好在选择了可在不同时间以不同方式影响您的 Expert Advisor 的基本变量之后,再使用自动优化程序。即,最好使用此自动优化程序以匹配一些变量参数,这些变量的变化对 EA 操作产生的影响比其他变量的变化大,具体要看市场波幅。
除此之外,最好不要设置很长的自动优化时段。假设 Expert Advisor 总是每天要优化 6-12 个小时。那么就会出现一个问题:什么时候进行交易?换句话说,优化自身并不是必要的。建议根据 EA 要进行交易的时间范围设置优化时段(即优化程序启动的时段)。这意味着必须考虑到,一旦启动测试程序终端,就将汲取历史数据,并且有可能出现经纪人并没有指定时间段的必要历史数据。要验证本文开头的假设,您需要 24 小时稳定的互联网连接。
已开发的自动优化程序位于以下随附文件中:auto_optimization.mqh - 库自身、MACD Sample_1.mq4 - MetaTrader 4 客户终端标准交付内容中略有更改的 Expert Advisor。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1467
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.