欢迎光临散文网 会员登陆 & 注册

股票量化软件:从头开始开发智能交易系统24--提供系统健壮性

2023-07-17 17:16 作者:大牛啊呢  | 我要投稿

这里的最大问题是设计一个兼具两个品质的系统:速度可靠性。 在某些类型的系统中,这很困难,甚至不可能实现兼顾两者。 如此这般,在许多情况下,我们试图平衡事态。 但由于它涉及资金,我们的血汗钱,我们不想冒险去得到一个不具备这些品质的系统。 必须要牢记的是,我们正在与一个实时操作的系统打交道,这是开发人员遭遇的最困难的场景,因为我们应该始终尝试拥有一个极端快捷的系统:它必须立即对事件做出反应,且当我们尝试改进它时能表现出足够的可靠性,不至于崩溃。 因此,这项任务显然相当困难。赫兹量化交易软件


确保以最合适的方式调用和执行函数,避免不必要的调用,尤其是不必要的次数,如此可以达成速度提升。 这将在语言范围内提供尽可能快速的系统。 不过,如果我们想要某方面更快,那么我们必须下沉到机器语言级别,在这种情况下,我们指的是汇编语言。 但这往往是不必要的,我们能用 C 语言得到同样好的结果。赫兹量化交易软件

实现所需健壮性的途径之一是尝试尽可能多地重用代码,从而能在不同情况下不断对其进行测试。 但这只是其中一种方式。 另一种方式是使用 OOP(面向对象编程)。 如果每个对象类不直接操作对象类数据(继承除外),就能正确且恰如其分地完成操作,那么它就足以作为一个十分健壮的系统了。 有时,这样做会降低执行速度,但这种降低是如此之微弱,以至于比之类封装提供的指数性增长,可以被忽略不计。 这种封装提供了我们所需的健壮性。赫兹量化交易软件

如您所见,达成速度和稳健性双赢并不是那么简单。 但其伟大之处在于,我们不必牺牲太多东西,如同您乍眼一看那样。 我们能够简单地检查系统文档,看看哪些修改可以改进内容。 简单的事实,我们没有试图重新发明轮子,这就已经是一个良好的开端。 但请记住,程序和系统在持续改进。 故此,我们应该始终尝试尽可能多地利用可用的东西,只有在最后的无奈情况下,才去真正重新发明轮子。赫兹量化交易软件

之前,有些人发现没有必要在文中介绍所做的更改,或者认为我正在大量更改代码而并没实际移动它,我要解释一下:当我们编写代码时,我们真的无法想象最终代码将如何工作。 我们所拥有的全部只是要实现的目标。 一旦这个目标达成了,我们开始研究如何实现这个目标,并试图加以改进,从而令它们变得更好。赫兹量化交易软件

对于商业系统的情况,无论是可执行文件还是库文件,我们都会持续进行修改,并将其作为更新补丁发布。 用户实际上并不需要知道实现目标所涉及的路径,因为它是一个商业系统。 他不知道这些实际上是件好事。 但由于它是一个开放的系统,我不想让您误以为可以立即研发出一个非常高效的系统,所以从一开始就这样的。 以这种方式思考是不妥当的,它甚至是一种侮辱,因为程序员或开发人员对所用的语言无论了解多寡,总有一些东西会随时间推移而改进。赫兹量化交易软件

如此,不要把这个系列当作可以在 3 或 4 篇文章中总结的东西,因为如果是这样的话,最好是简单地创建代码,保持我认为最合适的方式,并将其商业化。 这并非我的本意。 我通过观摩其他更有经验的程序员的代码来学习编程,我知道这有什么价值。 了解事物如何随着时间的推移而发展,比简单地套用完成的解决方案,并尝试了解其工作原理要重要得多。

在观摩这些之后,我们继续研发。


2.0. 实现

2.0.1. 新的仓位指标建模

在新代码格式中要留意的第一件事就是函数已改为宏替换。

inline string MountName(ulong ticket, eIndicatorTrade it, eEventType ev, bool isGhost = false)
{
        return StringFormat("%s%c%c%c%llu%c%c%c%s", def_NameObjectsTrade, def_SeparatorInfo, (char)it, def_SeparatorInfo, ticket, def_SeparatorInfo, (char)(isGhost ? ev + 32 : ev), def_SeparatorInfo, (isGhost ? def_IndicatorGhost : def_IndicatorReal));
}

即使编译器在每处引用点都用到了此代码(这要归功于保留字 “inline”),您也不应将其视为理所当然,因为该函数在代码中被多次调用。 我们需要确保它在实际中能尽可能快速地运行,因此我们的新代码将如下所示:

#define macroMountName(ticket, it, ev, Ghost) \ StringFormat("%s%c%llu%c%c%c%c%c%c%c", def_NameObjectsTrade, def_SeparatorInfo,          \                                                                                                                                                                                                                                                                                                
                                                       ticket, def_SeparatorInfo,                        \                                                                                                                                                                                                                                        
                                                       (char)it, def_SeparatorInfo,                      \ 
                                                       (char)(Ghost ? ev + 32 : ev), def_SeparatorInfo,  \ 
                                                       (Ghost ? def_IndicatorGhost : def_IndicatorReal))

请注意,旧版本的宏替换中的数据和此版本中的数据有所不同。 如此更改是有原因的,我们稍后将在文中讨论。

但是由于这个修改,我们还必须对另一个函数的代码略微进行修改。

inline bool GetIndicatorInfos(const string sparam, ulong &ticket, eIndicatorTrade &it, eEventType &ev)
                        {
                                string szRet[];
                                char szInfo[];
                                
                                if (StringSplit(sparam, def_SeparatorInfo, szRet) < 2) return false;
                                if (szRet[0] != def_NameObjectsTrade) return false;
                                ticket = (ulong) StringToInteger(szRet[1]);
                                StringToCharArray(szRet[2], szInfo);
                                it = (eIndicatorTrade)szInfo[0];
                                StringToCharArray(szRet[3], szInfo);
                                ev = (eEventType)szInfo[0];

                                return true;
                        }

此处的更改仅针对索引,该索引将指明哪个是单号,哪个是指标。 这没什么复杂的。 只需完成一个简单的细节,否则在调用该函数时,我们将得到不一致的数据。

您也许会惊讶:“为什么我们需要这些修改? 系统运行不正常吗?” 是的,它能工作了。 但有些事情我们无法控制。 例如,当赫兹量化交易软件 开发人员改进了一些 EA 中未用到的函数时,我们从中并未受益。 规则是避免重新发明轮子,取而代之的是可用资源的再生。 因此,我们应该始终尝试利用语言提供的函数,在我们的例子中是 MQL5,并避免自行创建函数。 这也许看起来很荒谬,但实际上,如果您冷静思考,您会发现平台不时在为某些函数提供改进,如果您恰好用到了这些相同的函数,则无需付出任何额外的努力,即可在程序中获得更好的性能和更高的安全性。

因此,结局证明这是合理的。 然而,上述变更是否有助于 EA 从 MQL5 函数库的任何改进中受益? 这个问题的答案是 否定的。上述变更对于确保对象名称建模正确性是必要的,如此我们就能够有效地利用来自 MQL5 和 赫兹量化交易软件 开发人员未来可能的改进。 以下是可能有用的项目之一:

inline void RemoveIndicator(ulong ticket, eIndicatorTrade it = IT_NULL)
{
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
        if ((it == IT_NULL) || (it == IT_PENDING) || (it == IT_RESULT))
                ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, (ticket > 1 ? '*' : def_SeparatorInfo)));
        else ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, def_SeparatorInfo, (char)it));
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
        m_InfoSelection.bIsMovingSelect = false;
        ChartRedraw();
}



股票量化软件:从头开始开发智能交易系统24--提供系统健壮性的评论 (共 条)

分享到微博请遵守国家法律