私募

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz

期货量化软件:MVC 设计范式及其可能的应用

[复制链接]
发表于 2023-6-29 08:11:01 | 显示全部楼层 |阅读模式
我推测许多开发人员都经历过一个阶段,当项目推进时,变得更加复杂并需求新功能,故此代码开始与某种意大利面条类似。 项目尚未完工,但已经很难记住这个或那个方法于何处被调用了,为什么这个调用要位于这里,以及它是如何操作的。随着时间的推移,即使代码的作者,理解代码也变得越发困难。 当另一个开发人员尝试理解这段代码时,情况就更糟了。 如果代码作者此时出于某些原因无法联络,则该任务实际上变得无解。 非结构化代码十分难以维护和修改,修改任何代码都比 “Hello, world” 更难。 这也是设计范式应运而生的原因之一。 它们为项目引入了确定的结构,令其更清晰,且直观更易于理解。9 v1 ?- j+ b* G1 Q  U
MVC 范式及其目的这种范式出现在很久以前(1978 年),但它的首次阐述出现在更晚的 1988 年。 自那时起,该范式一直在深入发展,提升到新的方式。在本文中,赫兹期货量化们将研究“经典 MVC”,没有任何复杂性或附加功能。 这个思路是将现有代码拆分为三个独立的组件:模型、视图和控制器。 根据 MVC 范式,这三个组件可以独立开发和维护。 每个组件都可由单独的开发团队开发,他们承担创建新版本,并修复错误。 显然,这可令整个项目的管理更加容易。 甚而,它能够帮助其他人理解代码。我们来看看每个组件。7 E7 m) _& ^1 f5 Z. ]
视图。 视图负责信息的可视化呈现。 在一般情况下,它向用户发送数据。 向用户呈现相同的数据,可以有不同的方式。 例如,数据可以同时用表格、图形或图表来呈现。 换言之,一个基于 MVC 的应用程序可以包含多种视图。 视图从模型接收数据,无需知道模型内部发生了什么。
5 ~) W; O. [% g2 f模型。 模型包含数据。 它管理与数据库的连接、发送请求、并在不同的资源间进行通信。 如有必要,它会修改数据、验证数据、存储和删除数据。 模型无需知道视图如何操作,以及存在多少视图,但它拥有必要接口,能响应视图请求数据。 视图不能做任何强迫模型更改其状态的事情。 这部分是由控制器来执行。 在内部,一个模型可由若干其他模型组成,它们或按层次结构、或按等同操作来排列。 除了前面提到的限制之外,模型在这方面没有极限 — 模型的内部结构相对于视图和控制器始终保密。3 X3 j/ g5 v2 d# ]/ t
控制器。 控制器实现用户和模型之间的通信。 控制器不知道模型如何处理数据,但它可以告诉模型更新内容的时间。 通常,控制器通过其接口操控模型,不必尝试了解其内部发生的事情。
) q( U( e4 i7 w尽管如此,运用 MVC 并没有特别严格的规则和限制。 开发者要注意不要在控制器里加入模型操作逻辑,以及操控视图的接口。 控制器本身应该轻量化;您你不应该让它超载。 MVC 规划图也用于其他设计范式,例如观察者和策略。现在,赫兹期货量化来看看如何在 MQL 中运用 MVC 模板,以及是否需要采用它。! E) ]/ U+ H1 T7 ~7 p* S* _0 D# \
从 MVC 的角度来看最简单的指标我们来创建一个简单的指标,其用最简单的计算绘制一条线。 该指标非常短小,其代码可以放在一个文件当中。 这是它的样子:.......#property indicator_chart_window#property indicator_buffers 1#property indicator_plots   1//--- plot Label1#property indicator_label1  "Label1"#property indicator_type1   DRAW_LINE#property indicator_color1  clrDarkSlateBlue#property indicator_style1  STYLE_SOLID#property indicator_width1  2//--- indicator buffersdouble         lb[];//+------------------------------------------------------------------+//| Custom indicator initialization function                         |//+------------------------------------------------------------------+int OnInit()  {   SetIndexBuffer(0, lb, INDICATOR_DATA);   ArraySetAsSeries(lb, true);   IndicatorSetString(INDICATOR_SHORTNAME, "Primitive1");   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);   return(INIT_SUCCEEDED);  }//+------------------------------------------------------------------+//| Custom indicator iteration function                              |//+------------------------------------------------------------------+int OnCalculate(const int rates_total,                const int prev_calculated,                const datetime &time[],                const double &open[],                const double &high[],                const double &low[],                const double &close[],                const long &tick_volume[],                const long &volume[],                const int &spread[])  {   if(rates_total <= 4)      return 0;   ArraySetAsSeries(close, true);   ArraySetAsSeries(open, true);   int limit = rates_total - prev_calculated;   if(limit == 0)     {     }   else      if(limit == 1)        {         lb[1] = (open[1] + close[1]) / 2;         return(rates_total);        }      else         if(limit > 1)           {            ArrayInitialize(lb, EMPTY_VALUE);            limit = rates_total - 4;            for(int i = limit; i >= 1 && !IsStopped(); i--)              {               lb = (open + close) / 2;              }            return(rates_total);           }   lb[0] = (open[0] + close[0]) / 2;   return(rates_total);  }//+------------------------------------------------------------------+该指标计算 open + close 的平均值。 源代码在随附的 zip 文档 MVC_primitive_1.zip 中提供。该指标编写得很糟糕,有经验的开发人员很容易就能看出来。 假设需要改变计算方法:只用 close 来替代 open + close。 该指标有三个地方需要我们进行修改。 如果赫兹期货量化需要进行更多修改,或计算更复杂时该怎么办? 显然,最好在单独的函数中实现计算。 如此,在必要的时候,我们能够只需在这个函数中进行相关的逻辑修正。此处是处理程序和函数现在的样子:double Prepare(const datetime &t[], const double &o[], const double &h[], const double &l[], const double &c[], int shift) {      ArraySetAsSeries(c, true);   ArraySetAsSeries(o, true);      return (o[shift] + c[shift]) / 2;}//+------------------------------------------------------------------+//| Custom indicator iteration function                              |//+------------------------------------------------------------------+int OnCalculate(const int rates_total,                const int prev_calculated,                const datetime &time[],                const double &open[],                const double &high[],                const double &low[],                const double &close[],                const long &tick_volume[],                const long &volume[],                const int &spread[]) {                   if(rates_total <= 4) return 0;      int limit = rates_total - prev_calculated;      if (limit == 0)        {   } else if (limit == 1) {         lb[1] = Prepare(time, open, high, low, close, 1);            return(rates_total);   } else if (limit > 1)  {         ArrayInitialize(lb, EMPTY_VALUE);            limit = rates_total - 4;      for(int i = limit; i >= 1 && !IsStopped(); i--) {         lb = Prepare(time, open, high, low, close, i);      }      return(rates_total);         }   lb[0] = Prepare(time, open, high, low, close, 0);   return(rates_total);}请注意,几乎所有得时间序列都要传递到新函数当中。 为什么呢? 它其实并非必要,因为只用到了两个时间序列:开盘价和收盘价。 然而,赫兹期货量化预计未来该指标可能会有更多变化和改进,其中可能会用到其余的时间序列。 实际上,我们为将来的潜在版本打下了坚实的基础。现在赫兹期货量化从 MVC 范式的角度研究当前代码。7 m. @5 |! b2 b  u+ o! U! S2 B+ A
视图。 由于该组件向用户呈现数据,因此它应该包含与指标缓冲区相关的代码。 这还应该包括来自 OnInit() 的代码 — 在我们的例子中是整个代码。( b7 [- ?2 k: t0 e  ~
模型。 我们的指标只有一个非常简单的单线模型,在其中赫兹期货量化计算开盘价和收盘价之间的平均值。 然后,视图务须我们的干预被更新。 因此,模型组件将只包含 Prepare 函数,它是针对潜在的未来发展而编写的。
7 V8 L( |- y8 ?  d; {1 N1 I, c: M9 S0 w控制器。 该组件负责两个其他组件之间的通信,以及用户交互。 据此,该组件将包括事件处理程序,和指标输入参数。 此外,控制器调用 Prepare 函数作为模型输入。 这样的调用将迫使模型在新的即时报价到达,和品种价格历史发生变化时,改变其状态。8 g5 z4 i* }' }
我们来尝试基于上述解释重构我们的指标。 我们在实现组件的代码时,不仅可在不同的文件当中,而且可在不同的文件夹当中。 这是一个合理的解决方案,因为可以有多个视图,而模型可以包含其他模型,且控制器也许会非常复杂。 此处是主要指标文件现在的样子://+------------------------------------------------------------------+//|                                              MVC_primitive_2.mq5 |//|                                Copyright 2021, Andrei Novichkov. |//|                    https://www.mql5.com/en/users/andreifx60/news |//+------------------------------------------------------------------+#property copyright "Copyright 2021, Andrei Novichkov."#property link      "https://www.mql5.com/en/users/andreifx60/news"#property version   "1.00"#property indicator_chart_window#property indicator_buffers 1#property indicator_plots   1#include "View\MVC_View.mqh"#include "Model\MVC_Model.mqh"//+------------------------------------------------------------------+//| Custom indicator initialization function                         |//+------------------------------------------------------------------+int OnInit() {   return Initialize();}//+------------------------------------------------------------------+//| Custom indicator iteration function                              |//+------------------------------------------------------------------+int OnCalculate(const int rates_total,                const int prev_calculated,                const datetime &time[],                const double &open[],                const double &high[],                const double &low[],                const double &close[],                const long &tick_volume[],                const long &volume[],                const int &spread[]) {                   if(rates_total <= 4) return 0;      int limit = rates_total - prev_calculated;      if (limit == 0)        {   } else if (limit == 1) {         lb[1] = Prepare(time, open, high, low, close, 1);            return(rates_total);   } else if (limit > 1)  {         ArrayInitialize(lb, EMPTY_VALUE);            limit = rates_total - 4;      for(int i = limit; i >= 1 && !IsStopped(); i--) {         lb = Prepare(time, open, high, low, close, i);      }      return(rates_total);         }   lb[0] = Prepare(time, open, high, low, close, 0);   return(rates_total);}//+------------------------------------------------------------------+
http://www.simu001.cn/x278686x1x1.html
最好的私募社区 | 第一私募论坛 | http://www.simu001.cn

精彩推荐

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Archiver| ( 桂ICP备12001440号-3 )|网站地图

GMT+8, 2024-11-27 14:25 , Processed in 2.416910 second(s), 31 queries .

Powered by www.simu001.cn X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表