使用内置指标
作为使用内置指标的简单入门示例,我们将使用iStochastic调用。该指标函数的原型如下:
int iStochastic(const string symbol, ENUM_TIMEFRAMES timeframe,
int Kperiod, int Dperiod, int slowing,
ENUM_MA_METHOD method, ENUM_STO_PRICE price)
如我们所看到的,除了标准参数 symbol和 time frame 外,随机指标还有几个特定参数:
- Kperiod ― 计算 % K 线的柱线数量
- Dperiod ― % D 线的主平滑周期
- slowing ― 二次平滑周期(减速因子)
- method ― 平均(平滑)方法
- price ― 随机指标计算方法
让我们尝试创建一个自己的指标UseStochastic.mq5,该指标会将随机指标的值复制到其缓冲区中。由于随机指标有两个缓冲区,我们同样预留两个缓冲区:分别是“主线”和“信号线”。
#property indicator_separate_window
|
在输入变量中,我们会提供所有必需的参数。
input int KPeriod = 5;
|
接下来,我们将介绍用于指标缓冲区的数组以及用于描述符的全局变量。
double MainBuffer[];
|
我们将在 OnInit中进行初始化。
int OnInit()
|
现在,在 OnCalculate中,一旦句柄准备就绪,我们就需要使用 CopyBuffer 函数读取数据。
int OnCalculate(const int rates_total,
|
请注意,我们要调用两次CopyBuffer:分别针对每个缓冲区(第二个参数中的 0 和 1)。尝试读取一个不存在的缓冲区索引(例如 2),将会生成错误,且我们不会收到任何数据。
我们的指标并非特别有用,因为它没有为原始随机指标添加任何内容,也没有对其读数进行分析。另一方面,我们可以确保标准终端指标的线条与在 MQL5 中创建的指标线条完全一致(正如我们在完全自定义指标中所做的那样,也可以轻松添加水平位和精度设置,但这样一来就很难区分复制指标与原始指标)。
标准随机指标与基于 iStochastic 函数的自定义指标
为了演示终端对指标的缓存机制,在 OnInit函数中添加了几行代码。
double array[];
|
在这里,我们使用了一个与已知特性相关的技巧:在指标创建后需要一定时间进行计算,因此在获取句柄后无法立即从缓冲区读取数据。这种情况适用于“冷启动”,即当终端内存的缓存中尚未存在指定参数的指标时。如果存在现成的指标,则我们可以立即访问缓冲区。
编译新指标后,应在同一交易品种和时间范围的两个图表上加载该指标的两个副本。第一次加载时,日志中将显示标志为 true的消息(这是第一个副本),而第二次(以及后续多次,如果有多个图表)则会显示为false.。你也可以在图表上手动添加标准“Stochastic Oscillator”指标(使用默认设置或后续将在 Use Stochastic中应用的设置),然后再运行 Use Stochastic:此时我们同样应获得 false。
现在让我们尝试基于标准指标开发一些原创性内容。以下UseM1MA.mq5指标用于在 M5 及更高时间范围(主要面向日间交易)上计算每根柱线的平均价格。它会累加在工作(更高)时间范围上中每根特定柱线时间戳范围内的 M1 柱线价格。这使得你能够比标准价格类型(Close、Open、Median、Typical、Weighted 等)更准确地估算柱线的有效价格。此外,我们还将提供在特定周期内对这些价格进行平均的可能性,但需做好心理准备,生成的线条可能不会特别平滑。
该指标将显示在主窗口中,且包含一个单独的缓冲区。可以通过 3 个参数更改设置:
input uint _BarLimit = 100; // BarLimit
|
BarLimit 设置用于计算的最近历史柱线数量。这一点很重要,因为与分钟级 M1 相比,时间范围很大的图表可能需要处理大量柱线(例如,在 24/7 交易中,一根日线 D1 包含 1440 根 M1 柱线)。这可能导致需要下载额外数据并等待同步完成。先用保守的默认设置(工作时间范围的 100 根柱线)进行测试,再将该参数设为 0,即表示无限制处理。
然而,即使将BarLimit设置为 0,指标也可能不会针对更早时间范围的全部可见历史进行计算:如果终端对图表中的柱线数量设有限制,则这也会影响对 M1 柱线的请求。换言之,分析深度取决于历史数据中允许的最大 M1 柱线数量所对应的时间范围。
BarPeriod 设置进行平均计算的更大时间范围的柱线数量。此处默认值为 1,这使得能够单独查看每根柱线的有效价格。
M1Price参数指定用于 M1 柱线计算的价格类型。
在全局范围内,为缓冲区、描述符和自更新标志定义数组,我们需要这些来等待构建“外部”M1 时间范围的时间序列。
double Buffer[];
|
此外,还会在此处生成指标名称和平均周期P。PeriodSeconds函数可返回当前时间范围中单根柱线内的秒数,使用该函数能够计算当前柱线内包含的 M1 柱线数量: PeriodSeconds() / 60 (60 秒为 M1 柱线的时长)。
通常通过 OnInit执行初始化操作。
int OnInit()
|
为获取更高时间范围柱线的平均价格,我们采用简单移动平均线,调用 iMA并设置为 MODE_SMA 模式。
下面给出的OnCalculate函数已进行简化处理。在第一次运行或历史数据发生更改时,我们会清空缓冲区并填充BarLimit变量(这是必需的,因为输入变量无法编辑,而我们希望将值 0 解释为可用于计算的最大柱线数量)。在后续调用中,仅从 prev_calculated位置开始的最后几根柱线(数量不超过 BarLimit)清除缓冲区元素。
int OnCalculate(ON_CALCULATE_STD_FULL_PARAM_LIST)
|
在从创建的 iMA指标读取数据之前,需要等待数据准备就绪:为此我们将 BarsCalculated 与 M1 柱线数量进行比较。
if(BarsCalculated(Handle) != iBars(_Symbol, PERIOD_M1))
|
如果数据尚未就绪,我们将启动一个计时器,在 1 秒后再次尝试读取。
接下来,进入算法的主要计算部分,因此如果计时器仍在运行,则必须停止计时器。如果下一个分时报价事件的发生速度快于 1 秒,而iMAM1 已经完成,则可能出现这种情况。此时,合理的做法是调用相应的函数 EventKillTimer。但它的行为存在一个细微差别:它不会清空指标类型 MQL 程序的事件队列,如果队列中已经存在一个计时器事件,则OnTimer处理程序仍会被调用一次。为避免图表的不必要更新,我们使用自己的变量 Pending Refresh控制这一过程,在此处将其赋值为 false。
...
|
以下是 OnTimer处理程序中的实现方式:
void OnTimer()
|
让我们回到 OnCalculate并展示主要工作流程。
for(int i = fmax(prev_calculated - 1, (int)(rates_total - BarLimit));
|
该指标的操作通过以下 EURUSD,H1 图表展示:蓝色线条对应默认设置。每个值通过对 60 根柱线 M1 的 PRICE_CLOSE 进行平均计算得出。橙色线条额外采用 5 根 H1 柱线的平滑处理,且基于 M1 PRICE_TYPICAL 计算得出。
EURUSD,H1 上的 UseM1MA 指标的两个实例
本书展示了UseM1MASimple.mq5的简化版。我们将以下细节留在后台处理:对最后一根(未完成的)柱线进行平均计算、空柱线(即没有对应 M1 数据的柱线)的处理、PLOT_DRAW_BEGIN 特性的正确设置,以及对新柱形出现时平均值计算短期延迟现象的控制。完整版可在文件 UseM1MA.mq5中获取。
作为基于标准指标构建指标的最后一个示例,我们来分析对 IndUnityPercent.mq5指标的改进,该指标曾在 多货币和多时间范围指标章节中介绍过。第一个版本使用 Close价格进行计算,通过CopyBuffer 获取这些价格。在新版 UseUnityPercentPro.mq5中,让我们将该方法替换为读取iMA 指标数据。这将允许我们实现以下新功能:
- 某个给定周期的平均价格
- 选择平均值计算方法
- 选择用于计算的价格类型
源代码的改动是最小的。我们为 iMA句柄添加了 3 个新参数和一个全局数组:
input ENUM_APPLIED_PRICE PriceType = PRICE_CLOSE;
|
在辅助函数 InitSymbols中(该函数从 OnInit 调用,用于解析包含工作交易品种列表的字符串),我们为新数组添加了内存分配(其 SymbolCount 大小由该列表确定)。
string InitSymbols()
|
在同一函数末尾,我们将创建所需附属指标的描述符。
在执行主要计算的 Calculate函数中,我们会将以下形式的调用:
CopyClose(Symbols[j], _Period, time0, time1, w); |
替换为:
CopyBuffer(Handles[j], 0, time0, time1, w); // j-th handle, 0-th buffer |
为清晰起见,我们还为指标的简称补充了三个新参数。
IndicatorSetString(INDICATOR_SHORTNAME,
|
结果如下:
适用于主要外汇货币对的 UseUnityPercentPro 多交易品种指标
此处显示的是一篮子 8 种主要外汇货币(默认设置),采用 11 根柱线并基于typical价计算出的平均值。两条粗线对应当前图表中货币的相对价值:欧元以蓝色标示,美元以绿色标示。