以经济方式计算指标的原则

18 十一月 2013, 09:59
0
1 470

于经典指标中在尚未计算的新指标柱的每一次价格变动时重新计算指标

```   if (prev_calculated == 0) // 如果是第一次计算,重新计算所有已存在的柱
first = MAPeriod - 1 + begin;
else first = prev_calculated - 1; // 在之后的计算中, 只计算新出现的柱
```

`   first = MAPeriod -  1  + Begin;  / / 有订单时重新计算全部柱 `

```//+------------------------------------------------------------------+
//|                                                     SMA_Test.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property version   "1.00"
int Handle;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//----+
//----+ 取得指标句柄
Handle = iCustom(Symbol(), 0, "SMA");
if (Handle == INVALID_HANDLE)
Print(" 无法获得SMA指标句柄");
//----+
return(0);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//----+
//--- 释放指标句柄
IndicatorRelease(Handle);
//----+
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//----+
double SMA[1];
//----+ 使用指标句柄把指标
// 缓冲区的值复制到特别准备好的静态数组中
CopyBuffer(Handle, 0, 0, 1, SMA);
//----+
}
//+------------------------------------------------------------------+

```

在某些不是很经典的指标中反复重新计算当前已收盘的指标柱

SomeVariable(bar) = Function(SomeVariable(bar - 1))

• SomeVariable() — 某指标柱的某个变量的值；
• bar - 在其上进行计算的指标柱的编号。

```   e1 = w1 * series + w2 * e1;
e2 = w1 * e1 + w2 * e2;
e3 = w1 * e2 + w2 * e3;
e4 = w1 * e3 + w2 * e4;
e5 = w1 * e4 + w2 * e5;
e6 = w1 * e5 + w2 * e6;
//----
T3 = c1 * e6 + c2 * e5 + c3 * e4 + c4 * e3;
```

```   //---- 声明用于存储系数有效值的静态变量
static double e1_, e2_, e3_, e4_, e5_, e6_;
```

```     //---- 在运行至当前柱之前记录变量值
if (rates_total != prev_calculated && bar == rates_total - 1)
{
e1_ = e1;
e2_ = e2;
e3_ = e3;
e4_ = e4;
e5_ = e5;
e6_ = e6;
}
```

```   //---- 恢复变量值
e1 = e1_;
e2 = e2_;
e3 = e3_;
e4 = e4_;
e5 = e5_;
e6 = e6_;
```

```//---- 首先计算用于重新计算柱的起始编号
if (prev_calculated == 0) // 确认这是指标的第一次计算
{
first = begin; // 计算所有柱的起始编号
//---- 开始所计算系数的初始化
e1_ = price[first];
e2_ = price[first];
e3_ = price[first];
e4_ = price[first];
e5_ = price[first];
e6_ = price[first];
}
```

可能导致 MQL5 代码异常缓慢的指标调用的特点

```   if (CopyBuffer(AMA_Handle, 0, 0, rates_total, Array) <= 0) return(0);
ArrayCopy(AMA_Buffer, Array, 0, 0, WHOLE_ARRAY);
```

（指标 dAMA !!!!!!. mq5）或如下所示

```   if (CopyBuffer(AMA_Handle, 0, 0, rates_total, Array) <= 0) return(0);

for(bar = 0; bar < rates_total; bar++)
{
AMA_Buffer[bar] = Array[bar];
/*
这里是指标计算的代码
*/
}
```

• 从新出现的指标柱
• 从已收盘的指标柱
• 从当前未收盘的指标柱

```//--- 计算所需复制数据的数量
int to_copy;
if(prev_calculated > rates_total || prev_calculated <= 0)// 确认第一次进行指标计算
to_copy = rates_total - begin; // 计算全部柱的数量
else to_copy = rates_total - prev_calculated + 1; // 仅计算新柱的数量

//--- 把重新出现的数据复制到指标缓冲区 AMA_Buffer[]
if (CopyBuffer(AMA_Handle, 0, 0, to_copy, AMA_Buffer) <= 0)
return(0);
```

很自然，在这种情形中的最终代码将有点复杂（指标 dAMA.mq5），但是现在我们能够使用我在本文开头提出的方法在两种情形中进行测试，并得出相应的结论。这一次，让我们将测试周期增加到一年。

```//---- 声明局部数组
double dAMA_Array[], StdDev_Array[];
//---- 数组的元素指数类似时间序列
ArraySetAsSeries(dAMA_Array, true);
ArraySetAsSeries(StdDev_Array, true);

//--- 计算所需复制的数据数量
int to_copy;
if(prev_calculated > rates_total || prev_calculated <= 0)// 确认进行第一次指标计算
to_copy = rates_total - begin; // 计算全部柱的数量
else to_copy = rates_total - prev_calculated + 1; // 仅计算新柱的数量

//--- 把新出现的数据复制到指标缓冲区和局部动态数组中
if(CopyBuffer(dAMAHandle,   1, 0, to_copy, AMABuffer   ) <= 0) return(0);
if(CopyBuffer(dAMAHandle,   0, 0, to_copy, dAMA_Array  ) <= 0) return(0);
if(CopyBuffer(StdDevHandle, 0, 0, to_copy, StdDev_Array) <= 0) return(0);
```

作为优化方式之一，在指标内实施所有指标计算

```   //---- 计算 AMkA 指标的主循环
for(bar = first; bar < rates_total; bar++)
{
//---- 把AMA指标的增量载入数组用于中间计算
for(iii = 0; iii < ama_period; iii++)
dAMA[iii] = AMABuffer[bar - iii - 0] - AMABuffer[bar - iii - 1];
```

```     //---- 计算AMA增量的简单平均数
Sum = 0.0;
for(iii = 0; iii < ama_period; iii++)
Sum += dAMA[iii];

//---- 计算增量的平方差的和以及平均数
Sum = 0.0;
for(iii = 0; iii < ama_period; iii++)
Sum += MathPow(dAMA[iii] - SMAdif, 2);

//---- 从 AMA 增量计算 StDev 均方差的最终值
StDev = MathSqrt(Sum / ama_period);
```

从 EA 交易程序调用指标的某些特点

```bool IsNewBar
(
int Number, // 在EA交易程序代码中调用 IsNewBar 函数的编号
string symbol, // 进行数据计算的图表交易品种
ENUM_TIMEFRAMES timeframe // 进行数据计算的图表时间框架
)
```

```    //---- 声明静态变量 - 用于储存 AMA 指标值的数组
static double AMA_Array[3];

//---- 调用AMA指标,复制其数据到AMA_Array数组
if (IsNewBar(0, Symbol(), 0))
{
CopyBuffer(AMA_Handle, 0, 1, 3, AMA_Array);
}
```

```   //---- 声明静态变量- 用于储存AMA指标值的数组
static double AMA_Array[3];

//---- 声明静态变量用于保存从AMA指标复制数据的结果
static bool Recount;

//---- 调用AMA指标,复制其数据到AMA_Array数组
if (IsNewBar(0, Symbol(), 0) || Recount)
{
if (CopyBuffer(AMA_Handle, 0, 1, 3, AMA_Array) < 0)
{
Recount = true; // 复制数据的尝试没有成功
return; // 退出 OnTick() 函数
}

//---- 所有从指标缓冲区复制数据的操作都成功完成
// 直到下一次柱改变都无需回到此区块
Recount = false;
}
```

```   //---- 指标计算主循环
for(bar = first; bar < rates_total; bar++)
```

```   //---- 指标计算主循环
for(bar = first; bar < rates_total - 1; bar++)
```

总结

mql5.zip (27.7 KB)

“市场概况”由真正才华横溢的思想家 Peter Steidlmayer 所提出。他建议使用有关“水平”和“垂直”市场动态信息的替代表示法，从而给出一套完全不同的模型。他认为存在市场深层次的摆动或称之为平衡和失衡周期的基本模式。在本文中，我将会探讨价格直方图（市场概况的一种简化模型）以及它在 MQL5 中的实施。