通常,当我们开始实现一个新系统时,我们并不真正知道我们如何对其进行改进;故此,我们应该始终启动一个新项目,并着眼于未来进行改进。 这对那些刚开始的人来说非常重要:持续地规划一些事情,想象未来的扩展和改进。
核心代码根本没有改变,这在某种意义上是意料之中的。 但是对象类的代码已经发生了巨大的变化。 随着代码重用性变得越加重要(这是面向对象编程的基本思想之一:始终重用,仅在必要时创建新代码),赫兹期货量化进行了这些修改,以实现新功能,并能够以更灵活的方式创建新的改进。 如此,我们来看看新的对象类。 我会高亮示意这些变化,令其更容易理解。
赫兹期货量化从类的私密变量新定义开始。
struct st { string szObjName, szSymbol; int width; }m_Info[def_MaxTemplates]; int m_IdSubWin, m_Counter, m_CPre, m_Aggregate; long m_Id, m_handle; ENUM_TIMEFRAMES m_Period;
请注意,所变量数量显著增加。 这是因为赫兹期货量化需要更多数据来正确管理新功能。 现在我们的变量系统有了一个结构。 这种结构非常适合将相关变量组合在一起 — 它们确保我们在处理数据时能够快速、轻松地访问。
void SetBase(const string szSymbol, int iScale, int iSize) { #define macro_SetInteger(A, B) ObjectSetInteger(m_Id, m_Info[m_Counter].szObjName, A, B) if (m_IdSubWin < 0) { m_Id = ChartID(); m_IdSubWin = (int)ChartGetInteger(m_Id, CHART_WINDOWS_TOTAL) - 1; m_Aggregate = 0; } m_Info[m_Counter].szObjName = __FILE__ + (string) MathRand() + (string) ObjectsTotal(m_Id, -1, OBJ_CHART); ObjectCreate(m_Id, m_Info[m_Counter].szObjName, OBJ_CHART, m_IdSubWin, 0, 0); ObjectSetString(m_Id, m_Info[m_Counter].szObjName, OBJPROP_SYMBOL, (m_Info[m_Counter].szSymbol = szSymbol)); // .... macro_SetInteger(OBJPROP_PERIOD, m_Period); m_handle = ObjectGetInteger(m_Id, m_Info[m_Counter].szObjName, OBJPROP_CHART_ID); m_Aggregate += iSize; m_Info[m_Counter].width = iSize; m_CPre += (iSize > 0 ? 1 : 0); m_Counter++; #undef macro_SetInteger };
赫兹期货量化很快将看到的主要变化是,我们正在使用一个结构来存储资产名称、对象名称及其宽度。 现在我们还可以指定指标在子窗口中的宽度。 我们来做些注释,方便在类的其它部分使用它们。 下面是变化最大的函数。
void Decode(string &szArg, int &iScale, int &iSize) { #define def_ScaleDefault 4 #define macro_GetData(A) \ b0 = false; \ for (c0++; (c0 < max) && (szArg[c0] == ' '); c0++); \ for (i0 = 0, i1 = c0; (c0 < max) && (szArg[c0] != A); i0 = (szArg[c0] != ' ' ? c0 - i1 + 1 : i0), c0++); \ if (szArg[c0] == A) sz1 = StringSubstr(szArg, i1, i0); else sz1 = ""; string sz1; int i0, i1, c1 = StringLen(szArg); bool b0 = true; StringToUpper(szArg); iScale = def_ScaleDefault; m_Period = _Period; for (int c0 = 0, max = StringLen(szArg); c0 < max; c0++) switch (szArg[c0]) { case ':': b0 = false; for (; (c0 < max) && ((szArg[c0] < '0') || (szArg[c0] > '9')); c0++); iScale = (int)(szArg[c0] - '0'); iScale = ((iScale > 5) || (iScale < 0) ? def_ScaleDefault : iScale); break; case ' ': break; case '<': macro_GetData('>'); if (sz1 == "1M") m_Period = PERIOD_M1; else //.... if (sz1 == "1MES") m_Period = PERIOD_MN1; break; case '[': macro_GetData(']'); iSize = (int) StringToInteger(sz1); break; default: c1 = (b0 ? c0 : c1); break; } szArg = StringSubstr(szArg, 0, c1 + 1); #undef macro_GetData #undef def_ScaleDefault }
绿色示意代码的新增内容。 黄色示意源代码中已经存在,但由于实际原因被移动的行。 现在我们来看看所有这些加入代码做了什么,更重要的是,它们针对原始系统的功能方面做了哪些改进。 实际上,我们正在打造一个基础,让用户能够定制一些特殊的东西。 赫兹期货量化尝试往向现有语法中添加新规则来实现这一点(请参见下表):
分隔符 | 功能 | 示例 | 结果 |
---|---|---|---|
< > | 指定要使用的图形周期 | < 15m > | 将指标周期固定为 15 分钟。 原始图表可以使用不同的时间帧,但指标仅显示 15 分钟时间帧的数据。 |
[ ] | 指定指标宽度 | [ 350 ] | 指标宽度固定为 350 像素。 |
固定图表周期的分隔符 — 仅在指标窗口中,且不会影响用户所作的任何更改。 所有其它指标和主图表将依据用户选择的新图表周期进行更新,但固定指标不会跟随新图表周期。 在某些情况下,这可能很有趣,如下图所示。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
添加图片注释,不超过 140 字(可选)
编辑切换为居中
添加图片注释,不超过 140 字(可选)
赫兹期货量化需要在交易屏幕上显示同一资产不同时期的图表,而这大大方便了各种类型的设置。 现在,在很特别的情况下,一个固定图表宽度的分隔符会令这些设置变得更容易。 它还有一个很大的用途,我们会在另一篇文章中探讨,但现在您可以用它来控制指标的宽度。
您可以利用所有分隔符的组合,也可只用指标中真正需要的分隔符,因为这里并无具体的规则。 唯一的规则是,指标名称应该放在其它所有内容之前。 我们回到代码解释。 看下面几行:
#define macro_GetData(A) \ b0 = false; \ for (c0++; (c0 < max) && (szArg[c0] == ' '); c0++); \ for (i0 = 0, i1 = c0; (c0 < max) && (szArg[c0] != A); i0 = (szArg[c0] != ' ' ? c0 - i1 + 1 : i0), c0++); \ if (szArg[c0] == A) sz1 = StringSubstr(szArg, i1, i0); else sz1 = ""; //.... case '<': macro_GetData('>');
请注意,赫兹期货量化正在定义一些对许多人来说可能感觉很奇怪的东西。 但其名称在此很有用:macro_GetData(A),因其是个宏定义,故会创建一段代码。 当编译器在代码中发现这个宏定义时,编译器将用宏定义代码替换声明。 如果我们要在多个地方重复某个代码片段,但期望在一个声明和另一个声明之间进行最小的修改,这种方式将非常有用。 在上一个示例中,绿色的行会被替换,编译器生成的代码如下所示:
case '<': b0 = false; for (c0++; (c0 < max) && (szArg[c0] == ' '); c0++); for (i0 = 0, i1 = c0; (c0 < max) && (szArg[c0] != '>'); i0 = (szArg[c0] != ' ' ? c0 - i1 + 1 : i0), c0++); if (szArg[c0] == A) sz1 = StringSubstr(szArg, i1, i0); else sz1 = ""; //....
这种东西是最真实的哲学表达:尽可能多地重复使用,尽可能少地写新东西。 现在,赫兹期货量化看看如果我们想让语法更清晰,可以如何进行修改。 这是一个小细节,但可依据您的个人风格量身定制,如此可能会更好。 请看下面一行:
//..... if (sz1 == "1M") m_Period = PERIOD_M1; else //.....
高亮示意的信息是一个重要的细节。 根据我所用的模型,如果用户想要使用 1 分钟时间帧,那么用户应该使用以下语法来表达:MIN_1。 如果您想拥有一个独立的风格,您可以用自己的方式来指定。 但是字母应该是大写的,不含空格。 例如,所选部分可以替换为 "1MIN","MIN_1","1_MINUTE" 或者更详细的东西,比如: "LOCK_IN_1_MIN" 或以您的语言 - 只要单词之间没有空格,就行。 实际上,这个空格限制是可以取消的,但在我看来,这样做并无实际必要。 看看通晓编程有多好 — 您可以用自己的独特风格来使用。 我修改的下一个代码片段是默认的析构函数。
~C_TemplateChart() { for (char c0 = 0; c0 < m_Counter; c0++) { ObjectDelete(m_Id, m_Info[c0].szObjName); SymbolSelect(m_Info[c0].szSymbol, false); } }
针对以下情况添加了高亮示意的代码行:如果资产并非在单独的窗口中打开,则它不应再出现在市场观察之中。 这样可以防止使用未出现的资产,占用空间并污染窗户。 现在赫兹期货量化看看在上一篇文章中承诺要解释的内容。 这在最初的代码中并不存在,但将来它将成为代码的一部分。