English Русский Español Deutsch 日本語 Português
preview
构建自动运行的 EA(第 07 部分):账户类型(II)

构建自动运行的 EA(第 07 部分):账户类型(II)

MetaTrader 5交易 | 3 四月 2023, 11:33
1 206 0
Daniel Jose
Daniel Jose

概述

在上一篇文章构建自动运行的 EA(第 06 部分):账户类型(I)中,我们着手开发一种方式来确保自动 EA 正常工作,并符合其预期目的。 在那篇文章中,我们创建了 C_Manager 类,它充当管理员,以便在出现奇怪或不正确的 EA 行为时,能把 EA 从图表中删除。

我们首先解释了如何防止 EA 的挂单或市价单触发。 尽管此处显示的机制能够支持 EA,但我们还还有一些与 EA 和 C_Orders 类之间交互相关的其它问题。 该问题主要与净持结算账户有关。 这是本文要涵盖的主题之一。

然而,无论如何,您永远不应该让自动 EA 在无人监督的情况下运行。

不要指望编写 EA 仅仅运用智能编程就足够了,因为事实并非如此。 您应该始终明白自动 EA 正在做什么,如果它的动向超出了为其划定的范畴,请在它失控之前尽快将其从图表中删除。


EA 和 C_Orders 类之间交互的新例程

如果 EA 能够继续访问 C_Orders 类,则前面文章中所说的一切都将毫无价值,如下所示:

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+

请注意,即使我们尝试限制和控制事态,EA 仍会设法将订单发送到市场,并新订单发送到订单簿。 这是一个安全漏洞,因为如果在 EA 初始化期间 C_Manager 类设法强加它将遵循某些规则,那么为什么在那之后,我们又允许它能够下订单,并执行市场操作呢? 我们必须在这里设定一些限制,即使它非常简单。 一个简单的测试通常可以防止多种潜在问题。 故此,针对 EA 和 C_Orders 类中存在的订单系统之间的交互形式,我们添加一些覆盖整个区域的控制。

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                if ((m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                m_TicketPending = C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                ulong tmp;
                                
                                if (m_bAccountHedging && (m_Position.Ticket > 0)) return;
                                tmp = C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                                m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp));
                                if (PositionSelectByTicket(m_Position.Ticket)) SetInfoPositions(); else m_Position.Ticket = 0;
                        }
//+------------------------------------------------------------------+

我们已添加了一些规则,如此 EA 在使用 C_Orders 类时就没有那么多的自由。 我们来看看在此发生了什么。 我们从 CreateOrder 函数开始。如果在示意挂单单号的变量中我们得到一个有效值,则发送新订单将被拒绝;如果在对冲账户上我们若已有一笔持仓,该订单也将被拒绝。 就这么简单。 但是,如果这些条件允许,我们可以发送将挂单添加到订单簿的请求,如果请求成功,我们将获得已下订单的单号。 之后,我们就无法再发送新订单

现在遇到一个大细节,即位于 ToMarket 函数当中。 在这种情况下,订单作为市价订单下达,即按最佳可用价格执行。 现在我们来看看允许我们发送市价单的条件。 仅当在对冲账户上我们尚无持仓时,才允许发送订单 这是详细信息: 如果可以发送市价订单,则将完成此操作,但我们不能使用首次调用返回的值。 这是因为这样的事实,如果我们在净持结算账户上,该数值也许与来自持仓的单号不同。 如果直接在持仓单号中设置该值,则可能会丢失实际的单号,因为在这种情况下,返回值可能只是临时的。 这就是我们在此进行这项新检查的原因。如果这是一个对冲账户,那么返回的值可以安全地存储在持仓单号之中。 但在净持结算账户的情况下,只有当持仓单号为零时,才会保存;否则,该值将被忽略。 一旦此操作完成后,我们可以更新持仓数据,或重置持仓单号值,但这完全取决于检查结果


自动 EA 中的净持结算账户问题

在净持结算账户上使用自动 EA 时存在的潜在危险问题。 在上一篇文章中,我展示了对冲账户中可能发生的问题。 但现在我们来探讨一个不同的问题,它只会发生在净持结算账户上。 如果 EA 没有锁,它会在某个时候遇到这个漏洞,许多 EA 都存在这个漏洞,但它们的用户并不知晓。

问题如下:在净持结算账户上,当品种的出价发生变化时,交易服务器将自动为多头或空头创建持仓平均价格。 如果您以一种或其它方式做空,平均价格以及持仓量将发生变化。

对于手动操作的 EA,这里没有问题,因为交易者将负责向服务器发送所有请求。 问题出现于自动 EA。 在这种情况下,当其编程中存在一定的差距或漏洞时,它就容易被触发。 细节:问题不在于交易服务器,也不在于 MetaTrader 5 平台;问题出在 EA 当中。

我将尝试以每个人都能理解的方式进行解释,但理想情况下,您应该对市场如何运作有一些了解,如此才更容易理解。 但我会尽量把问题说清楚。

当自动 EA 发送买入或卖出订单意图开仓时,它会基于某种触发器进行。 虽然我们还没有讨论触发器,但我们很快就会到达那里。 但问题亦不在于触发因素,因为在绝大多数情况下,触发因素是不负责任的。

一旦开仓,并且在净持结算账户中,EA 出于某种原因可以遵循策略:关闭交易量的一部分,然后另开一笔。 按这种方式,平均价格将开始移动。 问题是,也许 EA 会开始以一种野蛮、疯狂、和幻觉般的方式来做。 如果发生这种情况,它可能会在几分钟内导致大量资金损失,有时甚至只需几秒钟,具体取决于交易量。

而这就是问题所在:EA 发起订单,然后它滞留在那里而不平仓,且向服务器发送新请求以更改平均价格。 这通常发生在没有交易者在场的情况下,交易者应该监督 EA,因为所示的持仓数量没有变化,但价格会改变,且一些交易者没有注意到这种变化。 经常发生的情况是,在交易者真正注意到那里有问题之前,持仓已经造成了巨大的损失。

尽管一些自动 EA 在编写时故意采用这种类型的策略,但有些人不知道或意识到他们的自动 EA 中存在这种类型的错误。 在某些情况下,会遇到触发因素的问题,有人也许正用一类触发器,令 EA 买入或卖出,并且在某些非常特定的市场状况下,EA 也许会遵照上述进行操作。 如果意识到这一事实,交易者会有所提防。 但如果这种行为并非预期的,那么监督 EA 的交易者最终可能会被 EA 将要做的事情吓到。

不要低估系统,无论您多么信任它,并相信您的自动 EA 是安全的。 千万不要低估它。因为任何意外都可能发生,从而令 EA 隐藏您在编程时没有预见到的漏洞。 但幸运的是,有一个相对简单的方法可以克服这个缺陷,至少可以稍微减少它的损害。 故此,我们来看看如何在编程方面做到这一点。


限制 EA 中的交易量

最简单方法是减低,至少要一点点,针对在上一个主题中讲述的问题,限制 EA 实际可取的交易量。 没有十全十美的方法,但我们可以尽可能多地尝试,产生一些可以给我们带来一些安慰的形式。 最简单的方法是限制 EA 在整个运行期间可以采用的交易量。

请注意:我不是说限制持仓的交易量,而是限制 EA 在整个期间进行交易的交易量。 也就是说,EA 可以按最小交易量的 x 倍进行交易,而一旦达到限制,EA 就无法再加仓。 如果一笔持仓的仓位仅相当于最小交易量,而限制是这个交易量的 50 倍,这无所谓;如果 EA 已达到该 50 的配额,那么它将无法再加仓。

锁定正是基于此。 但我们这里有一个细节:没有 100% 安全锁定这样的东西。 一切都取决于监督 EA 的交易者。 如果交易者无意中关停了锁定,重新启动 EA,则交易者需对可能发生的任何灾难负责。 正如可能发生的那样,EA 达到了配额,交易者重新启动图表上的 EA。 在这种情况下,锁定失效。

为了实现锁定,我们需要在 C_Manager 类中定义一个静态、全局和私密的变量。 如在下面的代码中所示:

static uint m_StaticLeverage;

然而,为了初始化类中的静态变量,我们不能使用类构造函数。 在这种情况下,初始化将在类主体外部实现,但通常在源文件中的 C_Manager.mqh 头文件中实现。 如此,在类主体之外,我们有以下代码:

uint C_Manager::m_StaticLeverage = 0;

不必害怕,它只是一个正在初始化的静态变量。 对于那些不知道的人,该初始化甚至在实际引用类构造函数之前就发生了。 故此,在某些类型的代码中,这非常有用。 但变量在类主体外部初始化的事实,并不表示它可以从类外部访问。 请记住:原因是封装,所有变量都必须声明为私密。 这会令该类尽可能健壮。 因此,我们避免了该类工作中的安全漏洞、或可靠性的损失。

但这里又出现了另一个重要的问题:为什么我们在 C_Manager 类中使用私密和静态的全局变量? 我们不能使用非静态的变量吗? 答案是否定的。 原因在于:在任何情况下,如果 MetaTrader 5 平台重新启动 EA,存储在静态变量之外的所有数据都将丢失。 您应当注意这一点。 我的意思是 MetaTrader 5 可能自动重启 EA,而非您删除它,然后在图表上再次运行。 这是两种不同的情况。 如果 EA 从图表中删除,然后重新启动,那么所有信息,甚至静态变量的有关信息,都将丢失。 在这些情况下,唯一的方法是将数据存储在文件之中,然后通过读取该文件来还原它。 重新启动并不意味着 EA 已被删除。 在若干种情况下这些可能发生,所有这些情况都与 DeInit 事件的触发有关,其在代码中调用 OnDeInit 函数。 此重置不仅影响 EA,还影响指标。 所以,如果激活了 DeInit 事件,那么在图表上运行的脚本即被删除。 因为脚本不会重置(它们没有此属性),所以它们只是“退出”图表,而 MetaTrader 5 不会自动重置它们

现在我们需要在类的代码中添加一个定义,从而确定 EA 可采用最小交易量进行交易的最大倍数。 此定义如下所示:

#define def_MAX_LEVERAGE       10

我们已有了一个地方来存储 EA 交易的最小交易量,并且我们还有了一个可用的最大交易量的定义。 由此,现在我们可以产生一种方式来计算这个交易量,这是工作中最有趣的部分。 然而,在此之前,我们需要对上一篇文章中的代码进行一些修改:

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                m_TicketPending = C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                ulong tmp;
                                
                                if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                tmp = C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                                m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp));
                                if (PositionSelectByTicket(m_Position.Ticket)) SetInfoPositions(); else m_Position.Ticket = 0;
                        }
//+------------------------------------------------------------------+

通过添加这些测试,我是说如果放置的交易量超过指定的最大交易量,那么 EA 就无法执行该操作。 未来仍有一些细节需要解决,但现在像这样完成即可。 另请注意,有一行代码已被删除,因为它会干扰会计核算。

好了,现在我们需要一些例程来帮助我们与 EA 进行通信,以便 C_Manager 类能够接管 EA 将要执行的操作。 为此,我们首先创建一个非常精巧但急需的函数,如以下代码所示:

inline void UpdatePosition(const bool bSwap = false)
                        {
                                int ret;
                                
                                if ((m_bAccountHedging) && (m_Position.Ticket > 0) && (bSwap)) SetUserError(ERR_Unknown);
                                m_Position.Ticket = ((m_Position.Ticket == 0) && (bSwap) ? m_TicketPending : m_Position.Ticket);
                                m_TicketPending = (bSwap ? 0 : m_TicketPending);
                                if (PositionSelectByTicket(m_Position.Ticket))
                                {
                                        ret = SetInfoPositions();
                                        m_StaticLeverage += (ret > 0 ? ret : 0);
                                }
                        }

不要低估上面的这段代码。 尽管就复杂性而言,它似乎是一段低价值的代码,但对于 C_Manager 类能够接管 EA 正在做的事情是非常必要的。 为了理解这段代码,有必要了解 EA 如何、以及何时调用它。 但我们稍后再会看到这一点,因为 EA 内部的程序与许多人所做的完全不同。

只需查看上面的代码,我们就可以注意到一些事情。 如果我们是在一个有持仓的对冲账户上,并且 bSwap 是 “true”,那这就是一个错误。 在这种情况下,我们只报告错误,因为它将在其它位置被处理。 如果持仓单号的变量为空,且 bSwap 为 “true”,则意味着挂单已转变为持仓。 但如果我们已有一笔持仓,那么挂单(在净持结算账户上)将改变持仓的仓量,并很可能改变入场价格。 这种情形会在这一行中进行分析

如果 bSwap 设为 true,这意味着挂单已不复存在,且已在此处调整。 现在,我们进行以下检查:我们检查是否有持仓。 如果有,那么我们运行一个更新数据的过程。 此过程计算更新前后交易量之间的差异,并返回此交易量如果返回的数据为正值,则表明交易量或手数因子已增加。这种情况在净持结算账户上很常见,但在对冲账户上,返回值将始终是当前手数。 我们将此返回值保存到之前的静态变量当中。 故此,我们可以考虑该交易量是 EA 在其操作期间将采用、或已采用的数值。

但是不用想太多,您很快就会意识到我们需要另一个例程。 它将作用于删除或平仓。 它如下所示:

inline void RemovePosition(void)
                        {
                                if (m_Position.Ticket == 0) return;
                                if (PositionSelectByTicket(m_Position.Ticket)) ClosePosition(m_Position.Ticket);
                                ZeroMemory(m_Position);
                        }

此处并未出错:EA 将持仓平仓,或简单地通知 C_Manager 类服务器已平仓,要么是因为已触及限价(止盈或止损),要么是因为发生了导致平仓的事情,这没关系。 但如果 EA 错误地调用了此函数,而没有持仓,我们只需回滚即可如果有持仓,它将被平仓,而且最后我们将清除内存区域中存储仓位数据的所有数据

尽管上述这两个函数运行良好,但在许多不同的情况下,它们不太适合我们实际所需做的事情。 故此,当您看到这些函数时,请不要太兴奋。 不要想象它们适合具有高度稳健性的自动化 EA,因为正如我刚才所说,它们虽有效,但还不够。 我们还需要其它,更好的函数来构建我们在此所需的东西。 不过,我们不会在本文中看到这些,因为我需要展示为什么还要用到其它类型的函数。 为了能够正确理解,有必要展示 EA 代码 — 这将在下一篇文章中完成。

基于所有这些工作,我们终于拥有一个理论上健壮、且非常可靠的系统,以至于我们终于可以开始将其自动化,如此它就可以在仅由人类交易者监督的情况下运行。 但请注意我是说在理论上使用,因为系统中仍然可能发生故障。 但现在这些问题可用 _LastError 变量进行检查,如此我们即可查看是否出了问题。 如果故障很严重,例如,在用上一篇文章中讨论的自定义错误枚举时,我们必须从图表中删除 EA。

从图表中删除 EA 并非困难的任务。 实际上,可以通过调用 ExpertMove 函数轻松完成此操作。但这项任务并不是我们最大的问题所在。 真正的难处是如何处理持仓和挂单,它们可能仍然存在。

在最糟糕的情况下,您只需将它们平仓、或手工删除它们。 但如果您在对冲类型账户中,针对同一资产运行 2 个或更多自动 EA,并且其中一个 EA 只是决定脱离这条线,这就是它从图表中删除的地方。 现在,您必须在“工具箱”窗口的“交易”选项卡(图例 01)中检查订单和持仓,并尝试关闭由已删除的“坏” EA 所开立的交易。 在这种情况下,“”并不意味着 EA 编程不佳好。 我认为这个想法很清楚。

图例 01

图例 01 - 在 MetaTrader 5 平台中查找订单和持仓的所在

在此,编程可以帮助我们一点,但不要指望奇迹。 它仅在其可能的范围内帮助我们。 故此,我们来看看我们如何在这种特定情况下编程,一个“坏” EA决定自行其是,犯下疯狂的事情,最终因其坏习惯和不当行为而被从图表上踢出。


使用析构函数

析构函数是类中的一个函数,在任何时间点都不会真正由代码调用。 事实上,构造函数与其“同事”析构函数一样,在类的生存期内只会被调用一次。 构造函数在类诞生时调用,而析构函数则在类消亡时调用。 在这两种情况下,您作为一个程序员,很难说明一个类什么时候诞生,什么时候消亡。 通常这是由编译器完成的,但在特定情况下,程序员可以通过在代码中运用一些东西来说明一个类何时诞生,何时消亡。 但因为我们在构造函数中所用的参数,调用甚至可赋予它生命。 对于消亡时会发生什么,说来并非如此。

不过,现在无需担心,当我们进入 EA 代码时,您就会更好地理解它。

无论类何时消亡,我们都可以告之它,当发生这种情况时该怎么做。 以这种方式,我们可以告诉 C_Manager 类,当要从图表中删除 EA 时,它应该这样做,并且应该剔除 EA 所完成和遗留的任何内容,即持仓平仓,并删除订单簿中的挂单。 但请记住需查看工具箱(图例 01)来确认这一点,因为 EA 可能被强制踢出图表,此刻析构函数无法执行其任务。

为此,我们往错误枚举里添加一个新值:

class C_Manager : private C_Orders
{
        enum eErrUser {ERR_Unknown, ERR_Excommunicate};
        private :

此值将告诉析构函数 EA 已从图表中删除,并且必须撤消 EA 负责的所有操作。 若要了解析构函数无法通过参数获取任何值时,如何实际上获取此值,请查看下面的代码:

                ~C_Manager()
                {
                        if (_LastError == (ERR_USER_ERROR_FIRST + ERR_Excommunicate))
                        {
                                if (m_TicketPending > 0) RemoveOrderPendent(m_TicketPending);
                                if (m_Position.Ticket > 0) ClosePosition(m_Position.Ticket);
                                Print("EA was kicked off the chart for making a serious mistake.");
                        }
                }

代码非常简单。 我们将检查 _LastError 值来了解可能发生的情况。 因此,如果错误值等于我们刚刚添加到枚举中的错误值,则原因出于因 EA 的不良行为被从图表中删除。 在这种情况下,如果有挂单,删除将发送到服务器的订单请求。 此外,如果有持仓,则会向服务器发送平仓请求。 最后,我们将在终端中通知您发生了什么

但请记住,这根本不保险。 我们只是想通过编程获得某种帮助。 您作为交易者,必须注意并删除 EA 从图表中删除时可能遗留的任何订单或持仓。 至此,我们结束这个非常简短的话题,但我希望它足够清楚。 但在结束本文之前,我们再看一件事,我们将在下一个主题中研究。


创建容错级别

如果您查看了本文和上一篇文章中的所有代码,并设法理解了我所解释的内容,那么您一定是在想象 C_Manager 类对 EA 非常苛刻,不容忍任何类型的故障,即使是很微小的。 是的,这确实正在发生,但我们可以稍微改变一下。 有一些类型的错误,以及不那么严重、或并非由 EA 引发的错误。

一个这样的错误是当服务器报告 TRADE_RETCODE_MARKET_CLOSED 时,发生这种情况是因为市场休市。 这种类型的错误是可以容忍的,因为它不是 EA 的过错。 另一种类型是 TRADE_RETCODE_CLIENT_DISABLES_AT,这是因为算法交易在平台中被禁用。

有各种可能因 EA 的过错而发生的错误类型,即它们可能由于各种原因而发生。 所以,对 EA 过于苛刻,将可能出错的所有事情归咎于它,并不完全公平。 因此,我们需要创建一些机制来控制和容忍某些类型的错误。 如果错误看起来并不严重,我们可以忽略它,并容许 EA 保留在图表上。 然而,如果这是一个非常严重的错误,我们可以根据错误的严重程度做出一些决定。

那好,在 C_Manager 类中,我们创建了一个公开函数,如此 EA 对于可能的错误严重程度有疑问时可以调用它。 该函数代码如下所示:

                void CheckToleranceLevel(void)
                        {
                                switch (_LastError)
                                {
                                        case ERR_SUCCESSreturn;
                                        case ERR_USER_ERROR_FIRST + ERR_Unknown:
                                                Print("A serious error has occurred in the EA system. This one cannot continue on the chart.");
                                                SetUserError(ERR_Excommunicate);
                                                ExpertRemove();
                                                break;
                                        default:
                                                Print("A low severity error has occurred in the EA system. Your code is:", _LastError);
                                                ResetLastError();
                                }
                        }

我在这里没有提供最终解决方案,且它也不是 100% 正确的。 我只是在演示如何处理,以便创建一种容忍 EA 出错的途径。 上面的代码展示了 2 种不同的容错示例。

可能会出现更严重的错误,在此情况下,EA 将被从图表中删除。 执行此操作的正确方式是调用两个函数,其中一个函数配置 EA 异常错误另一个设置命令将其删除。 因此,C_Manager 类的析构函数将尝试删除或撤消 EA 正在执行的操作。 还有第二种方式,其中错误更轻微。 在这种情况下,我们只需向交易者显示警告,并删除错误指示,并清理该值,如此若调用未发生错误,则函数简单地返回

理想情况下,我们应该逐个定义哪些错误是有效的,哪些不是,来精准促进此处的错误处理。 另一件事是,我们在 C_Manager 类中没有用到调用,故其容错能力会非常高。 您实际上不应该这样做。 您应当在特定时间添加调用上述函数,如此您就不会忘记在 EA 里添加调用。 但就目前而言,此调用仅在 EA 非常特定的代码点进行。


结束语

本文是对前一篇文章的补充,因此其内容阅读时不难,且易理解。 我认为这里有足够的素材来完成任务。

我知道很多人已经希望查看 EA 代码,以便使用此处展示的内容,但当涉及到自动 EA 时,事情就并非那么简单了。 故此,在下一篇文章中,我将尝试分享我在做这些事上的一些经验,我们将研究与 EA 编码相关的预防措施、问题和风险。 我们将只关注 EA 代码,因为基于最后两篇文章,我在本系列的下一篇里会展示一些东西。 因此,冷静地学习,并尝试了解这个类系统是如何工作的,因为下一篇文章会涌现更多的素材。


本文由MetaQuotes Ltd译自葡萄牙语
原文地址: https://www.mql5.com/pt/articles/11256

非线性指标 非线性指标
在本文中,我将尝试研究一些构建非线性指标的方法,并探索其在交易中的用处。 MetaTrader 交易平台中有相当多的指标采用非线性方式。
DoEasy. 控件 (第 27 部分): 继续致力 ProgressBar(进度条)WinForms 对象 DoEasy. 控件 (第 27 部分): 继续致力 ProgressBar(进度条)WinForms 对象
在本文中,我将继续开发进度条(ProgressBar)控件。 特别是,我将创建管理进度条和视觉效果的功能。
种群优化算法:人工蜂群(ABC) 种群优化算法:人工蜂群(ABC)
在本文中,我们将研究人工蜂群的算法,并用研究函数空间得到的新原理来补充我们的知识库。 在本文中,我将陈列我对经典算法版本的解释。
神经网络变得轻松(第三十三部分):分布式 Q-学习中的分位数回归 神经网络变得轻松(第三十三部分):分布式 Q-学习中的分位数回归
我们继续研究分布式 Q-学习。 今天我们将从另一个角度来看待这种方式。 我们将研究使用分位数回归来解决价格预测任务的可能性。