在上一篇文章中:订单系统 (三) ,我提到过该系统有几个相当奇怪甚至神秘的错误。这些错误或故障是由系统内的某些交互作用造成的。尽管我们试图找出这些故障的原因以消除它们,但所有这些尝试都没有成功。其中有些情况完全不合理,例如,当我们在 C/C++ 中使用指针或递归时,程序就会崩溃。第一步就是验证这些机制。但是,在 MQL5 中,这种情况的发生与 C/C++ 中的情况不同。在做了一些小修改后,我成功地解决了其中一个缺陷。虽然这个解决方案看起来并不优雅,但它却让其中一个故障彻底消失了。
不过,我们仍然需要对代码进行稍微大一点的修改,才能彻底消除影响系统运行的错误。它们可能已经在这里存在了很长时间,因为系统早期没有某些类型的交互。一旦这些交互开始发生,这些错误就会变得很明显。
现有的故障不会对系统运行产生负面影响,但却无法实现真正正确的运行。所有这一切都让用户在使用该程序时感到相当不愉快,甚至无法接受。第一个缺陷很容易解决,我们就从它开始
解决服务繁忙(Service Busy)指示
其中第一个缺陷是最容易纠正的。它出现在以下情况:当我们在下订单时按下 CTRL 或 SHIFT 键时,会收到服务繁忙的提示。这意味着在运行过程中,即使系统运行正常,也会出现服务正在执行其他任务的迹象。这项任务是分时间段进行的。这意味着在对重放/模拟图表进行某种分析之前,需要创建好柱形图。虽然这种错误的危害不大,但它会使重放/模拟器的使用体验变得相当不愉快,因为它更容易造成混淆,而不是提供信息。
有些人认为,最好删除服务繁忙的字样。因为我们已经有一段时间没有在滚动时间时使用柱形创建显示了。但这并不能解决问题。这样做只会把问题推到幕后,把它扫到地毯下面,但其实解决方法非常简单有效。此外,我们还可以保留一些东西,这样将来我们就可以回到可视化系统,看到柱形的创建过程。因为在此之前,我们已经禁用了重放/模拟服务。因此,要解决这个问题,我们需要做出一些改变。让我们从下面的代码开始:
int OnInit()
{
#define macro_INIT_FAILED { ChartIndicatorDelete(m_id, 0, def_ShortName); return INIT_FAILED; }
u_Interprocess Info;
ulong ul = 1;
m_id = ChartID();
ul <<= def_BitShift;
IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
if ((_Symbol != def_SymbolReplay) || (!GlobalVariableCheck(def_GlobalVariableIdGraphics))) macro_INIT_FAILED;
Info.u_Value.df_Value = GlobalVariableGet(def_GlobalVariableIdGraphics);
if (Info.u_Value.IdGraphic != m_id) macro_INIT_FAILED;
if ((Info.u_Value.IdGraphic >> def_BitShift) == 1) macro_INIT_FAILED;
IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName + "Device");
Info.u_Value.IdGraphic |= ul;
GlobalVariableSet(def_GlobalVariableIdGraphics, Info.u_Value.df_Value);
if (GlobalVariableCheck(def_GlobalVariableReplay)) Info.u_Value.df_Value = GlobalVariableGet(def_GlobalVariableReplay); else Info.u_Value.df_Value = 0;
EventChartCustom(m_id, C_Controls::ev_WaitOff, 0, Info.u_Value.df_Value, "");
EventChartCustom(m_id, C_Controls::ev_WaitOff, 1, Info.u_Value.df_Value, "");
Control.Init(Info.s_Infos.isPlay);
return INIT_SUCCEEDED;
#undef macro_INIT_FAILED
}
首先应修改指标文件,修改的具体位置如上图所示。划线部分被删除,代之以新的代码。请仔细观察,因为这是唯一需要做出的改动。它涉及需要传递给 EventChartCustom 函数的 lparam 参数值。奇怪的是,这样一个简单的改变已经结出了硕果。
在同一个文件内,但在不同的函数中,我们需要做非常类似的事情:
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
static bool bWait = false;
u_Interprocess Info;
Info.u_Value.df_Value = GlobalVariableGet(def_GlobalVariableReplay);
if (!bWait)
{
if (Info.s_Infos.isWait)
{
EventChartCustom(m_id, C_Controls::ev_WaitOn, 0, 0, "");
EventChartCustom(m_id, C_Controls::ev_WaitOn, 1, 0, "");
bWait = true;
}
}else if (!Info.s_Infos.isWait)
{
EventChartCustom(m_id, C_Controls::ev_WaitOff, 0, Info.u_Value.df_Value, "");
EventChartCustom(m_id, C_Controls::ev_WaitOff, 1, Info.u_Value.df_Value, "");
bWait = false;
}
return rates_total;
}