介绍
这是连续向前优化系列中的下一个。在这里,我介绍创建的程序,该程序实现了编程的自动优化。先前的文章描述了在终端端和库端的程序实现的详细信息,它们用于处理生成的优化报告。您可以通过以下链接查看这些文章:
本文显示了所创建产品的概况,并作为指南。可以扩展创建的自动优化的功能。因此,我们将进一步讨论的算法可以轻松地替换为您自己的优化算法,以便您可以实现任何期望的想法。进一步的描述还揭示了所创建程序的内部结构。本文的主要目的是描述处理结果应用程序的机制及其功能。事实是,有时我的同事很难理解他。但是,自动优化非常容易设置和使用-我将进一步说明。因此,本文可以视为该应用程序的说明手册,涵盖所有可能的陷阱和设置细节。
说明自动优化的工作方式
为了继续分析所创建的程序,我们必须首先定义该项目的目的。我们采用科学的方法进行交易,并开始创建编程良好的交易算法(无论我们是在处理基于指标的机器人还是使用模糊逻辑和神经网络的机器人-所有这些都是执行特定任务的编程算法跑步)。因此,选择优化结果的方法也应形式化。换句话说,如果在拒绝将随机性应用于交易过程中,那么准备交易的过程也应该是自动化的。否则,我们可以随机选择自己喜欢的结果,这比系统交易更直观。这个想法是促使我创建此应用程序的第一个动机。接下来是通过优化算法来测试算法的能力-使用下图所示的连续漫游优化。
连续的前移优化在给定的时间间隔内在历史(黄色)优化和前瞻(绿色)优化之间切换。假设您有10年的历史。我们确定优化期应由一年的间隔和四分之一(或3个月)的向前间隔组成。结果,我们的优化运行+正向测试的间隔时间为1.25年(1年+ 1个季度)。在图中,每行代表该时间间隔。
接下来,我们产生相同类型的过程:
- 我们在选定的历史记录周期(1年)内进行优化。
- 我们使用固定方法在优化间隔的结果中选择最佳参数。
- 如果我们切换到前进时间间隔并执行测试,则返回到第一步-现在是间隔时间。让我们重复此过程,直到达到当前时间段。
- 收集每个季度的测试结果后,我们将对该算法的可行性进行最终评估。
- 可以发布最后的优化通过(没有正向测试)以进行交易。
通过这种方式,我们获得了一种通过优化来测试算法可持续性的方法。但是,在这种情况下,我们必须在每个正向期满后重新优化算法。换句话说,我们为算法的重新优化设置了一定的时间间隔,为参数的选择设置了方法,我们首先对历史记录执行此过程,并在以后的每个交易周期内重复此过程。测试期到期。
首先,这种优化技术使我们拥有定义明确的优化逻辑,从而使我们可以获得不受人工干预的结果。
其次,通过使用类似技术对新资产或新算法进行优化,我们可以全面了解算法的压力测试。如果参数选择方法和优化参数在所有正向优化中都是固定不变的,则我们将接受持续的压力测试,可以确定市场是否不再适合我们的策略。
第三,我们在相当短的时间内获得了许多优化框架,从而提高了所执行测试的可靠性。例如,将上述划分为1年优化和1个季度正向优化,则2年间隔提供4次压力测试和最终优化。
开始设置优化
现在,我们已经讨论了应用程序执行的过程,让我们看看它的用途。本系列文章是我先前有关图形界面管理优化过程的文章的逻辑延续:
这些文章描述了如何在终端中进行优化或测试作为受控过程。本系列中使用相同的方法。但是,基本区别之一是控制过程不是作为终端的附加实现的,而是作为独立程序实现的。这种方法可以使用计算机上安装的所有终端。在前面的系列文章中,我们创建了一个可以从工作终端启动的扩展。该扩展程序可以使用计算机上安装的所有终端,而不是从其启动的终端。当前应用程序还可以访问计算机上安装的所有终端,但是一次只能使用一个终端,并且可以启动任何终端。
为确保自动优化器成功运行,请在启动应用程序之前确保已关闭所选终端。
该应用程序的工作方式如下:
- 下次启动该过程时,无论是优化还是测试,应用程序都将启动一个终端,并将整个测试过程委托给该终端。一旦测试或优化完成,终端就会关闭。
- 经过测试或优化后,机器人将生成包含优化结果的报告(有关更多详细信息,请阅读本系列中的先前文章)。
- 自动优化器知道报告在哪里,因此可以读取和处理报告。处理完成后,将开始新的优化和测试阶段,或者将完成优化并将结果显示在“结果”选项卡中。
稍后将考虑实现的优化机制,而本部分的目的是用最少的技术细节来描述程序流程。不要忘记,您可以将自己的算法添加到负责优化的代码部分。自动优化器是启动优化过程的控制程序,但是这些过程的逻辑可以不同。这是生成的应用程序的主选项卡的屏幕截图。
如果仔细看一下屏幕截图,该区域中的第一个名为“ Select Optimiser”的组合框 绿色 在程序中实现的优化类型的选择。
该应用程序的图形用户界面位于 2个主要标签 分为。主选项卡显示设置。当我们需要开始或停止优化时,便是在这里开始工作。该选项卡在第二部分中进行了详细描述。 另一个“结果”选项卡是显示优化结果的选项卡。
首先,在启动自动优化器时,我们需要选择要使用的终端。终端选择的原理与用于启动优化的先前图形界面相同。换句话说,自动优化器将查找此计算机上安装的所有终端(但仅查找那些使用标准安装而不是便携式安装的终端)。
“设置”选项卡分为4个部分。可以拖动屏幕各部分的边缘。当您使用具有许多输入参数的算法时,这特别有用。
- 屏幕的第一部分包含来自MetaTrader优化器的参数列表。每次更改所选终端时,都会更新“可用专家”列表。该列表包含位于所选终端的相应目录中的所有Expert Advisor。指定EA时要考虑嵌套目录。
- 屏幕的第二部分包含所选算法的参数列表。参数列表可在“ MQL5 / Profiles / 测试仪 / {Expertname} .set”下的相应文件中找到。如果没有用于所选EA的文件,则在第一个屏幕区域中选择EA后,将打开带有测试仪的终端。然后,将使用默认设置创建请求的文件。然后关闭终端。每次从“可用专家”列表中选择其他专家顾问时,该列表都会更改。如果要更新加载的参数列表,只需单击 “更新(* .set)文件”,然后通过打开然后关闭终端来更新列表。在此之前,将删除现有文件,并在同一目录中创建一个新文件。
- 屏幕的第三部分包含极其重要的参数:用于排列卸载数据的过滤器和排序标准列表。本系列的第一篇文章详细讨论了排序过程。如第一篇文章所述,使用“>=", "<=", "< ||| >”等可以指定。
- 屏幕的第四部分包含一系列向前和向后的运行。间隔的逻辑如上所述。在此循环的第一篇文章中介绍了排序的实现以及遍历之间的交互。确保在开始不进行优化的测试时(参数优化模型=停用),该字段应具有历史时间间隔或两个时间间隔(历史和向前)。由于每次启动自动优化器时都会输入数据,这很无聊(根据我的经验验证),因此已经实现了将数据保存到文件的机制。单击“保存/加载”,在参数列表中检查先前输入数据的可用性。列表填满后,将接收到的参数保存到文件中。如果列表为空,则选择一个文件,从该文件中加载带有优化数据的列表。内部文件结构将在其他文章中介绍。像该程序生成的所有其他文件一样,该文件的格式为xml。请注意,日期输入格式为“ DD.MM.YYYYY”,而数据显示格式为“ MM.DD.YYYY”。这是因为日期会自动转换为字符串。这对我来说不是很关键,这就是为什么我决定不更改此行为。
同样,由于设置文件的文本格式,我们将无法区分算法参数的格式。例如,所有Enum参数都显示为int,因此,决定在屏幕的第二部分中以字符串形式显示参数列表。如果您不方便直接在自动优化器中配置优化步骤和其他机器人参数,则可以在终端中进行所有必要的设置。更改测试仪中的选项卡后(或关闭端子后),然后将设置写入所需的文件。您只需要在自动优化器中选择所需的算法-它将随您的设置立即加载。
需要以下字段的设置才能从自动优化器开始优化或测试:
- 选择一个EA。
- 检查参数以优化并选择范围(如在终端中)。
- 选择至少一个排序标准:这会影响由机器人生成的数据的排序,并且最好的结果是在正向间隔中开始(可以在测试运行中省略)
- 选择要进行前向调整的日期(如果要进行测试运行,请选择测试日期)。
- 运行优化时,选择所需的优化器(“选择优化器:”下拉列表)。
- 指定“资产名称”-将在其上执行请求的操作的交易品种的名称。发生错误时,终端将无法运行测试或优化。
- 您可以使用“目录前缀”来另外指定要保存的优化通道的名称。优化结束后,将在一个特殊的内部程序目录中创建一个包含优化结果的文件夹。文件夹名称设置如下:“ {目录前缀} {选择的优化程序} {专家名称} {资产名称}”。这些是“优化:”列表中显示的名称,可以从这些名称上载它们以进行查看和进一步分析。
- 带有参数的下拉列表 “重写”或“追加” 也是可选的。它指定了自动优化器在已保存文件中找到具有相同名称的结果时应采取的操作。如果选择“重写”,则所有文件将被新文件重写。如果选择“追加”,则匹配的优化数据将被覆盖。如果在当前优化间隔列表和先前保存的间隔列表中找到相同的间隔,则保存的结果将被新的覆盖。如果间隔是新间隔,则将它们添加到现有间隔中。
设置完成后,单击“开始/停止”以开始该过程。再次单击此按钮将中断优化过程。在优化过程中,其状态将显示在进度指示器和自动优化窗口底部的文本标签中。优化结束后,优化结果将上传到“结果”选项卡,并且进度指示器将重置为初始状态。但是,如果通过单击“开始/停止”运行测试,则终端不会自动关闭。这样做是为了方便起见,并允许用户检查所有必要的数据。检查完所需数据后,请手动关闭终端以继续自动优化过程。请不要忘记应该始终关闭终端,因为应用程序必须能够独立管理终端。
您还应该在开始优化之前自行配置优化器。这不是强制性要求,但是优化管理器的结构允许创建用户定义的优化器以及为每个这些优化器设置单独的参数。可以通过单击按钮进行设置 “ GUI” 优化器选择器的组合框旁边。已实现的优化器的设置如下:
- 测试滴答 -表示历史和正向测试数据的测试方法。优化方法在设置窗口的第一部分中指定,而测试方法在优化器设置中指定。如果该选项被激活,则在刻度线的帮助下进行测试。禁用后,将在1分钟OHLC模式下执行测试。
- 将实际日期替换为已设置-指定是否要使用传输的数据替换优化的实际开始日期和结束日期。优化的开始和结束时间使用1分钟的时间范围存储。有时当没有交易或公共假期时,实际的开始和结束日期可能与给定的日期和日期不同。如果激活此选项,那么优化器将设置更多的已知日期,并确定知道结果属于哪个间隔。但是,如果您想查看真实的交易数据,请关闭此功能。
- 对滴答测试使用不同的移位-我们在第二篇文章中讨论了滑移和移位可以添加到结果中。当使用刻度线进行测试时,滑点可以被禁用或完全减少。仅在这种情况下添加了此选项。仅在激活“ Ticks 上 Ticks”时激活。要使用该选项,请指定负责指定佣金和滑点的算法参数,并为其分配新值。通过指定负责滑动的机器人参数并将其设置为0,可以在滴答测试模式下从结果中删除滑动。指定参数及其值后,请使用“添加”(Add)参数将此参数添加到表中以保存该参数。
不需要保存输入的参数(没有“保存”按钮),因为它们是自动保存的。在开始优化之前,请关闭此窗口,以防止在优化过程中意外更改参数。
处理优化结果
优化开始后,请勿干预该过程。另外,在优化程序停止EA之前,请勿从图表中删除EA。否则,优化器将认为这种情况是错误的,因为数据将不匹配。该过程完成并且终端关闭后,优化器将优化报告加载到选项卡上 结果 高,您可以从中评估完成的工作。标签结构显示在以下标签中:
“结果”选项卡也分为多个部分,为便于说明已编号。第一部分包含优化过程,优化过程分为选项卡(选定过程和优化)。第一个容器选项卡称为“选定的通道”,其中包含选定的优化通道。这些运行分为两个选项卡(“前进”和“历史记录”)。让我们看看优化参数如何在这些寄存器之间分配。例如,提供以下数据:
- 2012年1月1日-2012年7月12日-历史
- 2012年12月10日-2012年3月7日-转发
优化是在历史时期内进行的。然后通过过滤和排序选择最佳参数(请参阅上一章中的描述)。选择后,将执行两项测试:一项针对历史记录,另一项针对正向时间间隔。同样,最佳参数的测试结果将添加到“选择的通过”选项卡中,在“历史记录”和“前进”选项卡之间进行划分。优化过程将添加到“优化”选项卡中,您可以在其中查看每个历史间隔的整个优化列表。详细检查“优化”选项卡。
表格结构(“优化”选项卡的第一部分)类似于“转发”和“历史记录”选项卡的结构。但是此表显示了在请求的时间间隔内的所有优化过程。可以从组合框中选择所需的时间间隔 “优化日期” 被选择。选择新的时间间隔后,将使用优化过程更新整个表。该选项卡的第二部分类似于“设置”窗口的第三部分,并且在这些选项卡中所做的任何更改都将被同步。
标签“优化”和“ “选定的通行证” 包含“保存到(* .csv)”按钮。单击“选定的通行证”按钮时,将创建一个* .csv文件,其中包含历史和正向优化通行证的列表。单击“优化”按钮时,有关所有已执行优化的信息将下载到相应的* .csv文件中。按钮 “排序”和“过滤器” 仅在“优化”选项卡中可用。其目的是允许根据“优化”选项卡的第二部分中指定的设置对生成的优化过程进行过滤和排序。实际上,由于自动优化使用相同的机制,因此不需要此选项。但是,该选项允许使用任何自定义过滤。
两个表都是交互式的。单击表格行会根据所选的优化遍历更新“结果”选项卡的第二部分和第三部分。双击将在终端中启动测试。在这种情况下,测试完成后将不会关闭端子。因此,在研究结果之后,您应该手动将其关闭。在开始测试之前,可以配置一些测试仪参数:“结果”选项卡的第二部分。
测试开始和结束日期 会根据选定的时间间隔自动更新。但是,可以通过双击所需的行来更改它们。您还可以使用执行延迟和 测试类型 (滴答声,OHLC等)。默认情况下设置为“无延迟,理想执行”和“每个滴答”。
该选项卡的第三部分显示了所选优化回合的交易统计信息(每日PL和最大PL / DD)以及所选回合的机器人参数(“批处理参数”选项卡)。 “最大PL / DD”选项卡不显示最终的损益值,仅显示总利润(所有获胜头寸的总和)和总亏损(所有亏损头寸的总和)。表格中显示了交易时记录的利润和最大跌幅以及优化和测试结果。 Daily PL选项卡显示平均每日利润和平均每日亏损,类似于终端中可用的报告。
用于自动优化器的另一种最简单算法
让我们考虑一下使用自动优化器的机器人的最终示例。我们已经在本系列的第三篇文章中介绍了算法模板。现在,让我们为C风格算法修改模板。首先,让我们看一下算法本身,它是2移动平均算法。通过固定的止损或固定的获利来平仓。从下面的代码中删除了描述EA逻辑的功能的实现,因为这不是示例的目的。
//+------------------------------------------------------------------+ //| SimpleMA.mq5 | //| Copyright 2019, MetaQuotes Software Corp. | //| //www.tbxfkj.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "//www.tbxfkj.com" #property version "1.00" #include <Trade/Trade.mqh> #define TESTER_ONLY input int ma_fast = 10; // MA fast input int ma_slow = 50; // MA slow input int _sl_ = 20; // SL input int _tp_ = 60; // TP input double _lot_ = 1; // Lot size int ma_fast_handle,ma_slow_handle; const double tick_size = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); CTrade trade; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- #ifdef TESTER_ONLY if(MQLInfoInteger(MQL_TESTER)==0 && MQLInfoInteger(MQL_OPTIMIZATION)==0) { Print("This expert was created for demonstration! It is not enabled for real trading !"); ExpertRemove(); return(INIT_FAILED); } #endif ma_fast_handle = iMA(_Symbol,PERIOD_CURRENT,ma_fast,0,MODE_EMA,PRICE_CLOSE); ma_slow_handle = iMA(_Symbol,PERIOD_CURRENT,ma_slow,0,MODE_EMA,PRICE_CLOSE); if(ma_fast_handle == INVALID_HANDLE || ma_slow_handle == INVALID_HANDLE) { ExpertRemove(); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(ma_fast_handle != INVALID_HANDLE) IndicatorRelease(ma_fast_handle); if(ma_slow_handle != INVALID_HANDLE) IndicatorRelease(ma_slow_handle); } enum 方向 { 方向_Long, 方向_Short, 方向_None }; //+------------------------------------------------------------------+ //| Calculate stop | //+------------------------------------------------------------------+ double get_sl(const double price, const 方向 direction) { ... } //+------------------------------------------------------------------+ //| Calculate take | //+------------------------------------------------------------------+ double get_tp(const double price, const 方向 direction) { ... } //+------------------------------------------------------------------+ //| Open position according to direction | //+------------------------------------------------------------------+ void 开仓(const double price,const 方向 direction) { ... } //+------------------------------------------------------------------+ //| Get direction | //+------------------------------------------------------------------+ Direction get_direction() { ... } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(!PositionSelect(_Symbol)) { Direction direction = get_direction(); if(direction != 方向_None) 开仓(iClose(_Symbol,PERIOD_CURRENT,0),direction); } } //+------------------------------------------------------------------+
EA代码部分至关重要。为了使EA在自动优化器中可用,需要分析我们必须进行的更改。
请注意,该任务不需要高效的EA,因此该机器人最有可能产生损失。 EA有一个 限制以避免其在真实交易中的意外启动。要删除限制(并能够在交易中启动它),请注释掉以下定义: TESTER_ONLY.
在OnOnit中 实例化 我们的移动平均线指标。因此,OnDeinit中的指标 已删除 将。代码中声明的枚举用于确定方向 方向 用过的。位置由函数中的CTrade类设置 开仓 打开。所有逻辑均在OnTick中用四行代码编写。现在,将所需功能的连接添加到机器人。
//+------------------------------------------------------------------+ //| SimpleMA.mq5 | //| Copyright 2019, MetaQuotes Software Corp. | //| //www.tbxfkj.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "//www.tbxfkj.com" #property version "1.00" #include <Trade/Trade.mqh> #include <History manager/AutoLoader.mqh> // Include CAutoUploader #define TESTER_ONLY input int ma_fast = 10; // MA fast input int ma_slow = 50; // MA slow input int _sl_ = 20; // SL input int _tp_ = 60; // TP input double _lot_ = 1; // Lot size // Comission and price shift (Article 2) input double _comission_ = 0; // Comission input int _shift_ = 0; // Shift int ma_fast_handle,ma_slow_handle; const double tick_size = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); CTrade trade; CAutoUploader * auto_optimiser; // Pointer to CAutoUploader class (Article 3) CCCM _comission_manager_; // Comission manager (Article 2) //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- #ifdef TESTER_ONLY if(MQLInfoInteger(MQL_TESTER)==0 && MQLInfoInteger(MQL_OPTIMIZATION)==0) { Print("This expert was created for demonstration! It is not enabled for real trading !"); ExpertRemove(); return(INIT_FAILED); } #endif ma_fast_handle = iMA(_Symbol,PERIOD_CURRENT,ma_fast,0,MODE_EMA,PRICE_CLOSE); ma_slow_handle = iMA(_Symbol,PERIOD_CURRENT,ma_slow,0,MODE_EMA,PRICE_CLOSE); if(ma_fast_handle == INVALID_HANDLE || ma_slow_handle == INVALID_HANDLE) { ExpertRemove(); return(INIT_FAILED); } // Set Commission and shift _comission_manager_.add(_Symbol,_comission_,_shift_); // Add robot params BotParams params[]; APPEND_BOT_PARAM(ma_fast,params); APPEND_BOT_PARAM(ma_slow,params); APPEND_BOT_PARAM(_sl_,params); APPEND_BOT_PARAM(_tp_,params); APPEND_BOT_PARAM(_lot_,params); APPEND_BOT_PARAM(_comission_,params); APPEND_BOT_PARAM(_shift_,params); // Add Instance CAutoUploader class (Article3) auto_optimiser = new CAutoUploader(&_comission_manager_,"SimpleMAMutex",params); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(ma_fast_handle != INVALID_HANDLE) IndicatorRelease(ma_fast_handle); if(ma_slow_handle != INVALID_HANDLE) IndicatorRelease(ma_slow_handle); // Delete CAutoUploaderclass (Article 3) delete auto_optimiser; } enum 方向 { 方向_Long, 方向_Short, 方向_None }; //+------------------------------------------------------------------+ //| Calculate stop | //+------------------------------------------------------------------+ double get_sl(const double price, const 方向 direction) { ... } //+------------------------------------------------------------------+ //| Calculate take | //+------------------------------------------------------------------+ double get_tp(const double price, const 方向 direction) { ... } //+------------------------------------------------------------------+ //| Open position according to direction | //+------------------------------------------------------------------+ void 开仓(const double price,const 方向 direction) { ... } //+------------------------------------------------------------------+ //| Get direction | //+------------------------------------------------------------------+ Direction get_direction() { ... } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { auto_optimiser.OnTick(); // Save current date (Article 3) if(!PositionSelect(_Symbol)) { Direction direction = get_direction(); if(direction != 方向_None) 开仓(iClose(_Symbol,PERIOD_CURRENT,0),direction); } } //+------------------------------------------------------------------+
所有新人都是 绿色 已标记。让我们按它们出现的顺序考虑它们。首先,我们包含AutoLoader头文件,该文件在第3条中进行了介绍。该文件包含CAutoUploader类,其任务是下载累积的交易历史记录。在OnInit中,我们将佣金添加到相应的CCCM类中,这在第2条中进行了描述。在向其添加EA参数之后,我们还实例化了CAutoUploader类。在OnDeinit中删除CAutoUploader类的实例,该实例将初始化对析构函数的调用,在该析构函数中,交易报告保存在xml文件中(第1条)。
EA逻辑保持不变,但OnTick除外。在这里,我们调用了CAutoUploader类的OnTick方法。该调用可以正确保存测试开始和结束。 CAutoUploader类仅在测试器中起作用,并且在实际交易中不执行任何操作。
结论
本文介绍了创建的优化管理器的功能。如本文开头所提到的,该文章应被视为最终应用程序的一种指南。进一步的文章中介绍了应用程序实现的技术方面。以下是文章的附件:
- 自动优化项目
- 所描述的EA代码
要运行自动优化程序,请使用Visual Studio IDE进行编译。请注意,MQL5 / Include / Libraries目录应包含第一篇文章中描述的“ ReportManager.dll”库。它在随附的自动优化项目中也可用(需要编译)。
由MetaQuotes Software Corp.从俄语翻译而来。
来源文章: //www.tbxfkj.com/ru/articles/7538