股票量化:赫兹量化系统定量和可视化分析测试器报告
为了能够执行该项目,我们首先需要改进之前在第二部分里研究的图形用户界面。 第三部分里执行的所有代码改进,都直接与 OLAP 引擎有关。 但可视化相关部分却并未执行升级。 这就是我们要做的工作,用来自第二篇文章里的 OLAPGUI 交易报告分析器作为本文的测试任务。 我们还将统一图形部分,如此便可以轻松地将其应用到任何新的其他应用领域,尤其是计划中的优化结果分析器。
因为 Y 轴显示的不是选择器(其值四舍五入到立方单元大小),而显示的是以秒为单位的汇总持续值,所以这么大的数字难以理解。 为了解决此问题,我们尝试把秒数除以当前时间帧柱线的持续时间。 在此情况下,这些值将代表柱线的数量。 为此,我们需要将某个标志传递给 CGraphicInPlot 类,进而会传递给处理坐标轴的 CAxis 类。 改变操作模式的标志可能很多。 因此,在文件 Plot.mqh 中为它们保留一个名为 AxisCustomizer 的特殊新类。
class AxisCustomizer { public: const CGraphicInPlot *parent; const bool y; // true for Y, false for X const bool periodDivider; const bool hide; AxisCustomizer(const CGraphicInPlot *p, const bool axisY, const bool pd = false, const bool h = false): parent(p), y(axisY), periodDivider(pd), hide(h) {} };
潜在地,要把各种标签显示功能添加到该类之中。 但于此刻,它仅存储坐标轴类型(X 或 Y)的符号,和少数逻辑选项,例如 periodDivider 和 '隐藏'。 第一个选项意味着值应除以 PeriodSeconds()。 第二个选项将在以后讲述。
该类的对象通过特殊方法注入 CGraphicInPlot 当中:
class CGraphicInPlot: public CGraphic { ... void InitAxes(CAxis &axe, const AxisCustomizer *custom = NULL); void InitXAxis(const AxisCustomizer *custom = NULL); void InitYAxis(const AxisCustomizer *custom = NULL); }; void CGraphicInPlot::InitAxes(CAxis &axe, const AxisCustomizer *custom = NULL) { if(custom) { axe.Type(AXIS_TYPE_CUSTOM); axe.ValuesFunctionFormat(CustomDoubleToStringFunction); axe.ValuesFunctionFormatCBData((AxisCustomizer *)custom); } else { axe.Type(AXIS_TYPE_DOUBLE); } } void CGraphicInPlot::InitXAxis(const AxisCustomizer *custom = NULL) { InitAxes(m_x, custom); } void CGraphicInPlot::InitYAxis(const AxisCustomizer *custom = NULL) { InitAxes(m_y, custom); }
若此类对象尚未创建且未传递给图形类时,标准库将按常规方式显示为 AXIS_TYPE_DOUBLE 数字。
在此,我们用标准库的方式来自定义坐标轴上的标签:轴类型设置为等于 AXIS_TYPE_CUSTOM,且通过 ValuesFunctionFormatCBData 传递指向 AxisCustomizer 的指针。 进而,它由 CGraphic 基类传递给 CustomDoubleToStringFunction 标签绘制函数(在上述代码中调用 ValuesFunctionFormat 设置)。 当然,我们需要 CustomDoubleToStringFunction 函数,该函数早前曾以简化形式实现,没有 AxisCustomizer 类对象(CGraphicInPlot 图表充当设置对象)。
string CustomDoubleToStringFunction(double value, void *ptr) { AxisCustomizer *custom = dynamic_cast<AxisCustomizer *>(ptr); if(custom == NULL) return NULL; // check options if(!custom.y && custom.hide) return NULL; // case of X axis and "no marks" mode // in simple cases return a string if(custom.y) return (string)(float)value; const CGraphicInPlot *self = custom.parent; // obtain actual object with cache if(self != NULL) { ... // retrieve selector mark for value } }
AxisCustomizer 定制对象存储在 CPlot 类中,CPlot 类是一个 GUI 控件(继承自 CWndClient),且是 CGraphicInPlot 的容器:
class CPlot: public CWndClient { private: CGraphicInPlot *m_graphic; ENUM_CURVE_TYPE type; AxisCustomizer *m_customX; AxisCustomizer *m_customY; ... public: void InitXAxis(const AxisCustomizer *custom = NULL) { if(CheckPointer(m_graphic) != POINTER_INVALID) { if(CheckPointer(m_customX) != POINTER_INVALID) delete m_customX; m_customX = (AxisCustomizer *)custom; m_graphic.InitXAxis(custom); } } ... };