创建多交易品种、多周期指标
目录
概述
继续为 EA 交易和指标中的技术指标创建模板的主题,该主题从与创建仪表盘相关的文章中开始,然后在另外三篇文章中发展,其中我们探讨了振荡器、交易量指标和比尔威廉姆斯以及趋势指标,今天我们将开始创建多交易品种、多周期指标的主题。其中包括在当前图表上运行但使用其他交易品种和(或)其他图表时间框架的数据计算的指标。我们将创建一个基础多指标类和一组基于所有标准指标类型的类。我们还将为自定义指示器创建一个类,使用该类可以将任何指标“转换”为多交易品种和多周期指标。对于所有指标类,我们将创建一个统一集合类。程序中创建的所有指标都将被放入此集合中。此外,还可以使用方法访问集合中任何创建的指标,以获得相关的指标数据。最终目标是开发一种方便的工具,用于创建多指标和处理其数据。
基本原则
为了正确理解指标操作的逻辑,让我们试着了解它是如何工作的。指标分为两部分:计算和绘图。这些部分中的每一个都对另一个一无所知。当创建指标时,终端子系统在图表上查找这样的指标是否存在。在这种情况下,它会查找具有相同名称和参数的指标。如果这样的指标已经在图表上运行,或者已经为此图表以编程方式创建,则终端将使用现有指标的句柄,而不是创建新指标。指标的绘图部分使用其句柄从计算部分接收所需的数据。可能存在多个绘图部件同时访问一个计算部件的情况。
计算部分的缓冲区将计算出的指标的数据存储在具有从现在到过去排列的数据的数组中。缓冲区数组索引0处的数据对应于当前图表数据:
数组的每个单元存储一个柱形图的数据,该柱形图对应于计算指标的交易品种/周期的时间序列柱形图。因此,为了从指标计算部分的缓冲区中获得数据并将其显示在另一个交易品种/时间框架的图表上,您需要计算计算部分缓冲区数组中与柱形图的时间相对应的图表上的柱形图编号。应将获得的数据写入绘图部分缓冲区,以便将当前图表中与计算部分缓冲区中柱形图开盘价相匹配的所有柱形图添加到绘图缓冲区的相应单元格中。
例如,五分钟图表周期上的一个柱对应于一分钟图表上的五个柱。一分钟图表的所有这五个柱都必须填充与它们在时间上对应的五分钟柱的值。类似的算法用于在较高的时间框架图上呈现较低时段的数据。在这种情况下,来自计算部分缓冲器的单元格的所有柱,对应于较高TF图上的柱的时间,被绘制在绘制缓冲区的一个柱上。
当然,读数可能并不精确,因为最终该柱将仅代表最后一个较低TF柱的数据,该数据与相应较高TF柱的时间相匹配。这里的一切都取决于从较低时间段的计算部分缓冲区接收数据的方向,最后接收的数据将绘制在较高时间段图表的柱形图上。
CopyBuffer()函数从计算的指标的缓冲区中获取数据:
函数将指定数量的指定指标缓冲区的数据接收到“buffer”数组中。
复制数据的元素(具有索引buffer_num的指标缓冲区)从开始位置开始计数,从现在到过去,也就是说,等于0的开始位置表示当前柱(当前柱的指标值)。
如果事先不知道要复制的数据量,建议使用动态数组作为目标数组缓冲区,因为CopyBuffer()会尝试将接收数组的大小分配到复制的数据的量。如果接收数组缓冲区是一个指标缓冲区(之前由SetIndexBufer()函数分配的用于存储指标值的数组),则允许部分复制。
如果需要将指标值部分复制到另一个数组(而不是指标缓冲区),则应使用一个中间数组,将所需数量复制到该数组中。从这个中间数组中,逐个成员将所需数量的值复制到接收数组的所需位置。
如果需要复制预定量的数据,建议使用静态分配的缓冲区,以避免不必要的内存重新分配。
接收数组的属性,即as_series=true或as_series=false,将被忽略:在复制过程中,最旧的元素将被复制到为数组分配的物理内存的开头。有三种函数选项。
按根据初始位置和所需元素的数量的访问
int CopyBuffer( int indicator_handle, // indicator handle int buffer_num, // indicator buffer index int start_pos, // starting point int count, // amount to copy double buffer[] // array the data to be copied to );
按初始日期和所需元素数量访问
int CopyBuffer( int indicator_handle, // indicator handle int buffer_num, // indicator buffer index datetime start_time, // starting date int count, // amount to copy double buffer[] // array the data to be copied to );
按所需时间间隔的初始日期和最终日期访问
int CopyBuffer( int indicator_handle, // indicator handle int buffer_num, // indicator buffer index datetime start_time, // starting date datetime stop_time, // end date double buffer[] // array the data to be copied to );
参数
indicator_handle
[in] 通过相关指标函数获得的指标句柄。
buffer_num
[in] 指标缓冲区的编号。
start_pos
[in] 复制的第一个元素的索引。
count
[in] 复制的元素数。
start_time
[in] 第一个元素对应的柱的时间。
stop_time
[in] 最后一个元素对应的柱的时间。
buffer[]
[out] double类型的数组。
返回值
复制的数组元素数,如果出现错误,则为-1。
注意
当从指标请求数据时,如果请求的时间序列尚未构建或应该从服务器下载,则函数会立即返回-1。在这种情况下,会启动所需数据的下载或构建。
当从EA或脚本请求数据时,如果终端在本地没有适当的数据,则会启动从服务器的下载。另外,如果可以从本地历史构建数据,但尚未准备好,则开始构建必要的时间序列。该函数返回超时到期时准备好的数量。
我们将使用该函数的第一个版本,即基于起始位置(y为循环索引)和所需元素数量的访问。
对象结构如下:
- 多交易品种、多周期指标的基类,包含所有指标通用的主要函数;
- 从基本对象派生的类,这些类按其类型描述每个指标;
- 指标的集合–您可以使用此类创建任何指标并将其添加到集合中。该类将为用户提供创建指标和从中接收数据的所有工具。
使用非当前图表中的数据时,为了避免时间序列被释放,您应该至少每两分钟访问一次此时间序列。在这种情况下,时间序列将被“保留”,这将加快对它的访问(不需要每次都等待数据同步)。在类构造函数中,我们将执行构建指标的时间序列的第一次调用。这将允许我们开始下载时间序列(如果无法在本地访问)。然后,每隔90秒,在基类计时器中,我们将访问时间序列来保存它。
资源高效计算
为了计算和显示指标,我们需要资源高效的计算。第一次启动时,将计算所有历史数据的指标,然后将计算所有后续分时的一个或两个柱形。
OnCalculate()处理函数具有预定义的常量变量,这些变量存储(时间序列或数组的)输入数据大小以及在上一次OnCalculate()调用 期间计算的数据量:
基于数据数组的计算
int OnCalculate( const int rates_total, // price[] array size const int prev_calculated, // number of processed bars at the previous call const int begin, // index number in the price[] array meaningful data starts from const double& price[] // array of values for calculation );
基于当前时间段时间序列的计算
int OnCalculate( const int rates_total, // size of input timeseries const int prev_calculated, // number of processed bars at the previous call const datetime& time{}, // Time array const double& open[], // Open array const double& high[], // High array const double& low[], // Low array const double& close[], // Close array const long& tick_volume[], // Tick Volume array const long& volume[], // Real Volume array const int& spread[] // Spread array );
这种数据的存在使得能够快速、有效地计算指标。例如,让我们考虑“limit”值的计算:
//--- Number of bars for calculation int limit=rates_total-prev_calculated; //--- If limit > 1, then this is the first calculation or change in the history if(limit>1) { //--- specify all the available history for calculation limit=rates_total-1; //--- If the indicator has any buffers, initialize them here with empty values set for these buffers }
当指标首次启动时,我们有时间序列大小(rates_total)和上次调用的计算数据量(prev_calculated)。由于尚未计算指标,因此在第一次启动时先前计算的柱的值为零。因此,“limit”值将大于1(等于可用柱数减去零)。使用此值,我们将“limit”指定为rates_total-1——用于计算的整个可用历史。在这种情况下,我们还需要首先从指标缓冲区中删除所有先前绘制的数据,例如:
ArrayInitialize(Buffer,EMPTY_VALUE);
之后,将在主循环中计算整个历史,该循环从“limit”到零(包括零)运行:
for(int i=limit;i>=0;i--) { // Calculating indicator at each bar of the loop (i) }
请注意,使用此计算方法,计算中使用的所有数组和指标缓冲区本身都必须具有索引为时间序列的标志:
ArraySetAsSeries(array,true);
如果计算出的“limit”等于1,则这意味着图表上打开了一个新的柱:指标将在从1到0(包括1到0)的循环中计算时间序列的第一个和零个柱。
如果计算的“limit”等于0,则这意味着对当前分时的操作:指标将仅计算从0到0(包括0)的循环中时间序列的第零柱。
如果您需要从零柱深入历史数据进行计算(以免扩展时间序列数组和缓冲区),则循环将反转:
int i=fmax(0, prev_calculated-1); for(;i<rates_total;i++) { // Calculating indicator at each bar of the loop (i) }
在当前图表上运行资源高效计算是非常容易的。但是,如果您需要的不是当前图表中的数据,该怎么办?何时从计算部分复制整个数据数组,何时仅复制最后一个或两个条形图?
这里我们将使用函数Bars()和BarsCalculated()。这些类似于预定义的常量指标变量rates_total和prev_calculated。它们返回指定交易品种/周期的柱数以及指标计算的数据量。由于指标是为其创建时刻指定的交易品种/周期构建的,因此计算的数据量也指的是该交易品种/周期。我们通过它的句柄来获取指标。
基于我们可以计算任何交易品种/周期需要复制多少个柱(以免在每个分时处复制整个数组)的事实,我们将在指标基类中创建与当前交易品种/周期完全相同的结构:
limit=rates_total-prev_calculated;
但是变量“limit”、“rates_total”和“prev_calculated”将是类的私有成员,并将从Bars()和BarsCalculated()函数接收值。“limit”值将在每个分时上计算,如果为零,则仅复制最后两个数据柱(当前和以前的数据柱)的数据。如果“limit”等于1,则这意味着在指标交易品种/周期上打开一个新的柱,您需要将数组增加1,然后从指标缓冲区复制数据-也是两个。当“limit”大于1时,整个数组将从指标的计算部分缓冲区复制到类的接收数组缓冲区,因为这被认为是第一次启动或历史上有了更改。
此逻辑适用于交易日,即分时到达的时间。
假期需要一种不同的方式。这是一个孤立的案例。这里没有分时,Bars()函数经常返回零,并且不记录计算的指标柱数,即也为零。如果用于计算的源数据中有任何错误,则指标应返回零。这意味着它将等待到下一个分时,并尝试再次计算。但在假期,除了第一次启动外,没有其他活动。
在第一次启动时,指标将首先清除缓冲区数组,然后进行计算。但是,由于计算数据不足,或者仅仅因为prev_calculated将返回零值,计算可能会失败。指标将退出OnCalculate(),再次返回零。因此,如果您通过右键单击菜单更新图表(这被视为分时模拟),指标将再次看到它是错误计算的,并将再次初始化缓冲区,考虑到这是第一次启动。这种行为将继续,并且刚刚在图表上呈现的绘图缓冲区数据将不断被擦除。不过有一个解决方案。
如果在第一次启动时无法立即计算指标,那么您可以等待20-30秒,等待下一个分时,并以编程方式模拟分时。这可以使用ChartSetSymbolPeriod()函数来完成。如果调用它并指定当前图表交易品种/周期,将会重新计算图表上运行的指标。因此,即使没有分时,也可以计算图表上的指标。
二十秒的等待足以加载指标交易品种/周期所需的历史记录并进行计算。但我们需要一个标志,表明指标已经计算完毕(因为prev_calculated返回零),如果我们不设置计算成功标志,指标将再次清除其缓冲区。因此,我们可以通过简单地看到指标对象的计算柱数等于其交易品种/周期上的柱数来理解指标已经成功计算。如果Bars()返回零,那么我们可以用另一种方式找到所需交易品种/周期的可用柱数(不要忘记,我们谈论的是在当前图表上运行的另一个指标或 EA 交易中计算的多交易品种、多周期指标)。在SeriesInfoInteger()函数中,我们可以获得交易品种/周期的可用历史记录的开始和结束日期:
SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE); // The very first date for a period and symbol at the moment SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE); // Time of opening the last bar for the period and symbol
根据这两个日期和时间序列图表周期,即使Bars(symbol,period)或SeriesInfoInteger(symbol,period,SERIES_BARS_COUNT)返回零,我们也可以轻松计算可用柱的数量。
在已经接收到所有数据并且已经正确地计算出指标之后,设置计算成功标志。在limit>1的条件下检查此标志(在这种情况下,需要使用“空”值初始化指示器缓冲区数组)。在第一次启动时,成功标志被重置,数组被初始化,并尝试计算非当前图表交易品种/周期上的指标。如果计算失败,请等待20秒(根据计时器),等待下一个分时。
如果是周末,则不会有分时,20秒后会发送一个命令,设置图表的当前交易品种和周期,以模拟分时。当重新启动计时器中的指标时(20秒后),数据应该已经加载,并且指标的计算应该没有错误。在这种情况下,将设置计算成功标志。下一次激活计时器时,会检查此标志,如果已设置,则不会模拟分时。有三种这样的尝试来绘制指标缓冲区。在三次尝试之后,成功标志被强制设置,并且模拟分时的尝试被停止。如果指示器无法计算三个模拟分时,则只能手动操作:使用右键菜单刷新,或者来回切换图表时间框架,以完成整个分时模拟过程,并再次加载数据。
这就是理论。让我们继续练习:创建多指标类。
MSTF 指标的基类
在终端文件夹\MQL5\Include\IndMSTF\中,让我们为CIndMSTF类创建一个新文件IndMSTF.mqh。类必须从标准库基本对象CObject继承。基本对象文件必须连接到创建的新类文件:
//+------------------------------------------------------------------+ //| IndMSTF.mqh | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Object.mqh> //+------------------------------------------------------------------+ //| Base class of the multi-symbol multi-period indicator | //+------------------------------------------------------------------+ class CIndMSTF : public CObject { private: protected: public: //--- Constructor/destructor CIndMSTF(); ~CIndMSTF(); };
在我们将方法添加到类的各个部分之前,让我们添加一些宏替换、枚举和指标缓冲区的结构。
我们将需要第二个计时器来跟踪两个时间段:
- 90秒计时器,之后我们将转到不在当前交易品种/周期上计算的指标的时间序列;
- 20秒计时器,我们将在周末模拟分时来绘制指标。
//--- includes #include <Object.mqh> //--- defines #define TIMER_COUNT_1 (90) // Timer 1 size. Must not be more than two minutes (120) #define TIMER_COUNT_2 (20) // Timer 2 size. 值太小会迅速触发分时模拟,这在活跃的市场中是不可取的
客户端中的不同标准指标属于不同的类别。为了让我们按类别对创建的指标进行排序或创建与任何类别相关的指标列表,让我们写一个不同指标类别的枚举:
//--- defines #define TIMER_COUNT_1 (90) // Timer 1 size. Must not be more than two minutes (120) #define TIMER_COUNT_2 (20) // Timer 2 size. Too small values quickly trigger tick emulation, which is not desirable in an active market //--- enums enum ENUM_IND_CATEGORY // Indicator categories { IND_CATEGORY_NONE, // Not set IND_CATEGORY_TREND, // Trend IND_CATEGORY_OSCILLATOR, // Oscillators IND_CATEGORY_VOLUME, // Volume IND_CATEGORY_WILLIAMS, // Bill Williams IND_CATEGORY_CUSTOM, // Custom };
关于排序、搜索和筛选
每个指标对象都具有可用于查找所需指标的属性。为了理解指标是一致的,我们需要比较它们的关键属性:交易品种、图表周期和所有输入参数的值。如果所比较的属性中至少有一个值不同,则指标不相同。如果指标相等,则不会创建新的指标,但会返回一个指向先前创建的具有相同参数的指标的指针。这涉及指标集合。关于属性,我们需要创建一个枚举,该枚举将包含一些属性的常量,这些常量可以设置为成功创建的指标,然后可以用于查找该指标:
enum ENUM_COMPARE_MODE // Comparison mode { // By default, the comparison mode is set to zero, which compares all properties COMPARE_MODE_HANDLE=1, // Compare by handle COMPARE_MODE_SYMBOL, // Compare by symbol COMPARE_MODE_TIMEFRAME, // Compare by chart period COMPARE_MODE_ID, // Compare by ID COMPARE_MODE_DESCRIPTION, // Compare by custom description COMPARE_MODE_CATEGORY, // Compare by category };
每个成功创建的指标都有一个句柄,通过该句柄可以访问它。这是分配给指标计算部分的唯一编号。创建的指标的句柄值从10开始,每个后续值增加1。
其余的属性不是唯一的,可能是不同指标所固有的。此处提供使用这些值进行搜索只是为了方便。例如,可以为指标设置唯一的描述,然后通过此描述引用它。
指标线状态的描述在前面关于指标的文章中已经讨论过。在这里,我们还将使用此枚举:
enum ENUM_LINE_STATE // Indicator line state { LINE_STATE_NONE, // Undefined LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_BELOW, // Below value LINE_STATE_CROSS_UP, // Upward value crossing LINE_STATE_CROSS_DOWN, // Downward value crossing LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touching value from above LINE_STATE_EQUALS, // Equal to value };
有关更多详细信息,请参阅关于振荡器指标的文章,在ATR指标参数部分。
每个指标将使用错误代码发出其计算结果的信号:
enum ENUM_ERR_TYPE // Indicator calculation error type { ERR_TYPE_NO_ERROR, // No error ERR_TYPE_NO_CYNC, // Data not synchronized ERR_TYPE_NO_DATA, // Data not loaded ERR_TYPE_NO_CALC, // Calculation not completed };
使用此代码,可以从外部确定处理错误所需的操作。
指标缓冲区
在这里,我们需要决定缓冲区属于哪里。
- 计算部分的缓冲区。当我们创建一个指标时,它是在内存中创建的。这是指标的计算部分。它有自己的缓冲区,由终端子系统管理。您可以使用句柄访问计算部分,该句柄在成功创建指标后返回。成功创建和计算的指标的缓冲区始终包含与计算指标的时间序列相对应的数据。该缓冲区中的数据的位置使得零索引对应于计算指标的时间序列的当前柱。
要从指标计算部分的缓冲区复制数据,我们使用CopyBuffer()函数 - 指示器对象的缓冲区。每个创建的多指标类对象都将根据该指标的缓冲区数量拥有自己的缓冲区数组。来自计算部分缓冲区的数据将被放置在这些数组中。指标对象的缓冲区将在类对象内部进行管理,在类对象中对它们进行初始化,根据创建指标的时间序列的大小增加大小,并在每个新的分时上更新。当使用CopyBufer()将数据从计算部分缓冲区复制到指标对象数组时,数据将被排列,使当前柱位于数组的末尾(ArraySize()-1)。
- 指标绘图部分的缓冲区。每个指标对象都可以在EA交易和自定义指标中创建。在EA交易中创建多个指标时,为了计算指标,我们调用计算指标的方法,为了获得计算出的数据,我们访问所需的指标对象缓冲区索引。在自定义指标的情况下,我们还需要绘制图表上多个指标的数据。这就是为什么这里还有一个绘图缓冲区。此缓冲区指定为在自定义指标中绘图。它将显示存储在指标对象缓冲区中的数据。要在图表上显示线条,只需从计算指标的自定义指标中调用指标集合类的方法就足够了,然后,如果计算成功,则调用将指标对象的缓冲区数据放置在自定义指标的绘图缓冲区中的方法。
在指标对象中,一个缓冲区将由一个结构表示,该结构包含动态数组本身和该数组的控制方法:
//--- struct struct SBuffer // Structure of the indicator buffer { double array[]; // Indicator buffer array double init_value; // Initializing value int shift; // Horizontal shift of the buffer string descript; // Buffer description //--- (1) Sets, (2) returns the initializing value, void SetInitValue(const double value) { init_value=value; } double InitValue(void) { return init_value; } //--- (1) Sets, (2) returns the buffer offset void SetShift(const int value) { shift=value; } int Shift(void) { return shift; } //--- (1) Resizes the buffer array, (2) returns the size of the buffer array, //--- (3) initializes the array with the set "empty" value bool BuffResize(const int new_size) { return(ArrayResize(array,new_size)==new_size);} uint BufferSize(void) { return array.Size(); } int InitBuffer(void) { return ArrayInitialize(array,init_value); } };
一些值是在外部设置的,例如,在创建指标时,需要保存在某个位置,以便以后知道这些值是什么。最简单的方法是将它们直接写入结构中。这就是我们在这里所做的:调用程序设置的“空”缓冲区值保存在init_value变量的缓冲区结构中。在创建指标的计算部分时设置的指标线的偏移也可以保存在这里,以便以后您可以在类对象内部了解它;它保存在“shift”变量中。缓冲区的描述也保存在此处。此描述是在创建指标的计算部分时自动设置的,与同一标准指标的缓冲区名称相对应。此描述稍后可以更改。
只有在初始化和计算期间记录指标线和错误的状态或在信息面板上显示时,才需要返回指标线状态和错误说明的函数:
//+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string BufferLineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_NONE : return "None"; case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_BELOW : return "Below level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } } //+------------------------------------------------------------------+ //| Return error description in indicator calculation | //+------------------------------------------------------------------+ string TypeErrorcDescription(ENUM_ERR_TYPE error_type) { switch(error_type) { case ERR_TYPE_NO_CYNC : return "Data is not synchronized"; case ERR_TYPE_NO_DATA : return "Data not loaded"; case ERR_TYPE_NO_CALC : return "Calculation not completed"; default : return "No error"; } }
所需的准备工作已经完成。让我们转到多交易品种多周期指标的对象类。
让我们在类的主体中写下类工作所需的所有私有、受保护和公共变量和方法,然后考虑它们的目的和实现:
//+------------------------------------------------------------------+ //| Base class of the multi-symbol multi-period indicator | //+------------------------------------------------------------------+ class CIndMSTF : public CObject { private: ENUM_PROGRAM_TYPE m_program; // Program type ENUM_INDICATOR m_type; // Indicator type ENUM_TIMEFRAMES m_timeframe; // Chart timeframe string m_symbol; // Chart symbol int m_handle; // Indicator handle int m_id; // Identifier bool m_success; // Successful calculation flag ENUM_ERR_TYPE m_type_err; // Calculation error type string m_description; // Custom description of the indicator string m_name; // Indicator name string m_parameters; // Description of indicator parameters protected: ENUM_IND_CATEGORY m_category; // Indicator category MqlParam m_param[]; // Array of indicator parameters string m_title; // Title (indicator name + description of parameters) SBuffer m_buffers[]; // Indicator buffers int m_digits; // Digits in indicator values int m_limit; // Number of bars required to calculate the indicator on the current tick int m_rates_total; // Number of available bars for indicator calculation int m_prev_calculated; // Number of calculated bars on the previous indicator call //--- (1) Sets indicator name, (2) description of parameters void SetName(const string name) { this.m_name=name; } void SetParameters(const string str) { this.m_parameters=str; } //--- Resizes the (1) specified, (2) all indicator buffers bool BufferResize(const uint buffer_num,const int new_buff_size); bool BuffersResize(const int new_buff_size); //--- Initializes the (1) specified, (2) all indicator buffers bool BufferInitialize(const uint buffer_num,const int new_buff_size); bool BuffersInitialize(const int new_buff_size); //--- Returns the flag indicating equality of the structure of one parameter of two objects bool IsEqualParameters(const MqlParam &this_param,const MqlParam &compared_param) const { if(this_param.type==compared_param.type && this_param.integer_value==compared_param.integer_value && this_param.string_value==compared_param.string_value && ::NormalizeDouble(this_param.double_value-compared_param.double_value,8)==0 ) return true; return false; } //--- Return the result of comparison on one parameter of two objects int CompareParams(const MqlParam &this_param,const MqlParam &compared_param) { if(this.IsEqualParameters(this_param,compared_param)) return 0; else if(this_param.type>compared_param.type || this_param.integer_value>compared_param.integer_value || this_param.string_value>compared_param.string_value || this_param.double_value>compared_param.double_value ) return 1; else if(this_param.type<compared_param.type || this_param.integer_value<compared_param.integer_value || this_param.string_value<compared_param.string_value || this_param.double_value<compared_param.double_value ) return -1; else return -1; } public: //--- Creates the calculation part of the indicator, returns the handle int CreateIndicator(void); //--- (1) Calculates the indicator, (2) fills the passed buffer array (taking into account the chart period/symbol) with data from the indicator calculation buffer of this class bool Calculate(void); bool DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int limit,double &buffer[]); //--- (1) Sets (2) returns the initializing value for the specified buffer void SetBufferInitValue(const uint buffer_num,const double value); double BufferInitValue(const uint buffer_num) const; //--- (1) Sets (2) returns the offset value for the specified buffer void SetBufferShift(const uint buffer_num,const int value); double BufferShift(const uint buffer_num) const; //--- Returns data of the specified buffer (1) as is, (2) relative to the specified symbol/timeframe, //--- (3) amount of data in the specified buffer, (4) the state of the indicator line as it is in the calculation part buffer, //--- (5) indicator line state taking into account the chart symbol/period, description of the line state (6) as is in the buffer (7) taking into account the chart symbol/period double GetData(const uint buffer_num,const int index) const; double GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const; uint DataTotal(const uint buffer_num) const; ENUM_LINE_STATE BufferLineState(const uint buffer_num,const int index) const; ENUM_LINE_STATE BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const int index) const; ENUM_LINE_STATE BufferLineStateRelative(const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); ENUM_LINE_STATE BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); //--- Returns (1) success flag, (2) calculation error type bool IsSuccess(void) const { return this.m_success; } ENUM_ERR_TYPE TypeError(void) const { return this.m_type_err; } //--- Sets (1) identifier, (2) Digits, (3) custom description, (4) description of the specified buffer void SetID(const int id) { this.m_id=id; } void SetDigits(const uint digits) { this.m_digits=(int)digits; } void SetDescription(const string descr) { this.m_description=descr; } void SetBufferDescription(const uint buffer_num,const string descr); //--- Sets the indexing of buffer arrays of the calculation part not as in the timeseries void SetAsSeriesOff(void); //--- Returns flag of whether the buffer is set as series, (2) historical data for symbol/period is synchronized bool IsSeries(const uint buffer_num) const; bool IsSynchronized(void) const { return (bool)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_SYNCHRONIZED); } //--- Returns (1) timeframe, (2) symbol, (3) name, (4) list of parameters, (5) handle, (6) Digits //--- number of (7) buffers, (8) bars, (9) identifier, (10) description, (11) title, (12) category, //--- (13) number of parameters, (14) program type, description of (15) category, (16) indicator buffer ENUM_TIMEFRAMES Timeframe(void) const { return this.m_timeframe; } string Symbol(void) const { return this.m_symbol; } string Name(void) const { return this.m_name; } string Parameters(void) const { return this.m_parameters; } int Handle(void) const { return this.m_handle; } int Digits(void) const { return this.m_digits; } uint BuffersTotal(void) const { return this.m_buffers.Size(); } uint RatesTotal(void) const { return this.m_rates_total; } int ID(void) const { return this.m_id; } string Description(void) const { return this.m_description; } string Title(void) const { return this.m_title; } ENUM_IND_CATEGORY Category(void) const { return this.m_category; } uint ParamsTotal(void) const { return this.m_param.Size(); } ENUM_PROGRAM_TYPE Program(void) const { return this.m_program; } string CategoryDescription(void); string BufferDescription(const uint buffer_num); //--- Returns (1) structure of parameters by index from array, (2) flag of indicator program, (3) timeframe description MqlParam GetMqlParam(const int index) const { return this.m_param[index]; } bool IsIndicator() const { return(this.Program()==PROGRAM_INDICATOR); } string TimeframeDescription(void) const { return ::StringSubstr(::EnumToString(this.m_timeframe),7); } //--- Returns amount of calculated data int Calculated(void) const { return ::BarsCalculated(this.m_handle); } //--- Virtual method returning the type of object (indicator) virtual int Type(void) const { return this.m_type; } //--- Virtual method for comparing two objects virtual int Compare(const CObject *node,const int mode=0) const { const CIndMSTF *compared=node; switch(mode) { case COMPARE_MODE_ID : return(this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : 0); case COMPARE_MODE_HANDLE : return(this.Handle()>compared.Handle() ? 1 : this.Handle()<compared.Handle() ? -1 : 0); case COMPARE_MODE_CATEGORY : return(this.Category()>compared.Category() ? 1 : this.Category()<compared.Category() ? -1 : 0); case COMPARE_MODE_SYMBOL : return(this.Symbol()>compared.Symbol() ? 1 : this.Symbol()<compared.Symbol() ? -1 : 0); case COMPARE_MODE_TIMEFRAME : return(this.Timeframe()>compared.Timeframe() ? 1 : this.Timeframe()<compared.Timeframe() ? -1 : 0); case COMPARE_MODE_DESCRIPTION : return(this.Description()>compared.Description() ? 1 : this.Description()<compared.Description() ? -1 : 0); //--- Equality of all object parameters default : return(this.IsEqualIndicators(compared) ? 0 : -1); } } //--- Returns the flag of equality of parameters of two indicator objects bool IsEqualIndicators(const CIndMSTF *compared) const { if(this.Type()!=compared.Type() || this.ParamsTotal()!=compared.ParamsTotal()) return false; bool res=true; int total=(int)this.ParamsTotal(); for(int i=0;i<total;i++) res &=this.IsEqualParameters(this.m_param[i],compared.GetMqlParam(i)); res &=(this.Timeframe()==compared.Timeframe()); res &=(this.Symbol()==compared.Symbol()); return res; } //--- Timer void OnTimer(void); //--- Constructor/destructor CIndMSTF(){} CIndMSTF(const ENUM_INDICATOR type,const uint buffers,const string symbol,const ENUM_TIMEFRAMES timeframe); ~CIndMSTF(); };
类代码中对每个变量和方法的用途进行了注释。让我们考虑一下方法的实现。
类的构造函数:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CIndMSTF::CIndMSTF(const ENUM_INDICATOR type,const uint buffers,const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Start the timer ::ResetLastError(); if(!::EventSetTimer(1)) ::PrintFormat("%s: EventSetTimer failed. Error %lu",__FUNCTION__,::GetLastError()); //--- Set properties to the values passed to the constructor or to default values this.m_program=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE); this.m_type=type; this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe); this.m_handle=INVALID_HANDLE; this.m_digits=::Digits(); this.m_success=true; this.m_type_err=ERR_TYPE_NO_ERROR; //--- Set the size of the buffer structure array to the number of indicator buffers ::ResetLastError(); if(::ArrayResize(this.m_buffers,buffers)!=buffers) ::PrintFormat("%s: Buffers ArrayResize failed. Error %lu"__FUNCTION__,::GetLastError()); //--- Set the "empty" value for each buffer by default (can be changed it later) for(int i=0;i<(int)this.m_buffers.Size();i++) this.SetBufferInitValue(i,EMPTY_VALUE); //--- Set initial values of variables involved in resource-efficient calculation of the indicator this.m_prev_calculated=0; this.m_limit=0; this.m_rates_total=::Bars(this.m_symbol,this.m_timeframe); //--- If the indicator is calculated on non-current chart, request data from the required chart //--- (the first access to data starts data pumping) datetime array[]; if(symbol!=::Symbol() || timeframe!=::Period()) ::CopyTime(this.m_symbol,this.m_timeframe,0,this.m_rates_total,array); }
指标的类型、缓冲区的数量、交易品种的名称和图表的时间框架被传递给类构造函数。接下来,设置变量的默认值,设置缓冲区数组的大小,并且给缓冲区数组以EMPTY_VALUE赋值进行初始化。如果指标对象是在非当前图表上计算的,那么在构造函数的末尾,我们调用一个函数,该函数开始从服务器下载计算指标的时间序列数据。
类的析构函数:
//+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CIndMSTF::~CIndMSTF() { //--- Delete timer ::EventKillTimer(); //--- Release indicator handle ::ResetLastError(); if(this.m_handle!=INVALID_HANDLE && !::IndicatorRelease(this.m_handle)) ::PrintFormat("%s: %s, handle %ld IndicatorRelease failed. Error %ld",__FUNCTION__,this.Title(),m_handle,::GetLastError()); //--- Free up the memory of buffer arrays for(int i=0;i<(int)this.BuffersTotal();i++) ::ArrayFree(this.m_buffers[i].array); }
在类析构函数中,我们销毁计时器,释放指标句柄并释放缓冲区数组的内存。
计时器函数:
//+------------------------------------------------------------------+ //| Timer | //+------------------------------------------------------------------+ void CIndMSTF::OnTimer(void) { //--- If the indicator symbol and timeframe match those of the current chart, exit if(this.Symbol()==::Symbol() && this.Timeframe()==::Period()) return; //--- Declare time counter variable static int count1=0; static int count2=0; //--- If the counter of timer 1 has reached the specified value, if(count1>=TIMER_COUNT_1) { //--- call the CopyTime function (timeseries hold) and reset the counter datetime array[1]; ::CopyTime(this.m_symbol,this.m_timeframe,0,1,array); count1=0; } //--- If the counter of timer 2 has reached the specified value if(count2>=TIMER_COUNT_2) { static int count=0; //--- if the previous indicator calculation failed, emulate a tick and print the relevant log if(!this.m_success) { if(::ChartSetSymbolPeriod(0,::Symbol(),::Period())) { count++; ::PrintFormat("%s::%s: Tick emulation. Attempt %ld of 3 ...",__FUNCTION__,this.Title(),count); if(count>2) { count=0; this.m_success=true; } } } //--- reset the counter count2=0; } //--- Increase timer counters count1++; count2++; }
类计时器包含两个:一个用于维护指标的时间序列,另一个用于模拟周末的分时。如果使用当前图表交易品种/时间框架的数据计算指标,则不使用计时器。
指标对象本身不是指标,它只是指标计算部分的包装器,允许您管理它,从中接收数据并将数据传递给程序。在多指标对象中,我们需要创建指标本身。为此,我们使用创建指标的计算部分的方法,该方法返回创建过程中收到的句柄:
//+------------------------------------------------------------------+ //| Creates an indicator, returns a handle | //+------------------------------------------------------------------+ int CIndMSTF::CreateIndicator(void) { //--- Create indicator name to print to logs string name=::StringFormat("%s(%s,%s)",::StringSubstr(::EnumToString(this.m_type),4),this.m_symbol,this.TimeframeDescription()); //--- Create the calculation part of the indicator ::ResetLastError(); this.m_handle=::IndicatorCreate(this.m_symbol,this.m_timeframe,this.m_type,this.m_param.Size(),this.m_param); //--- If the calculation part is not created, log a message about the failed creation of the indicator if(this.m_handle==INVALID_HANDLE) ::PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,name,::GetLastError()); //--- If the indicator is created, set non-timeseries indexing of indicator arrays else this.SetAsSeriesOff(); //--- Return the handle of the created indicator or -1 if unsuccessful return this.m_handle; }
指标对象的缓冲区是我们上面讨论的缓冲区结构内的动态数组。应该更改它们的大小以适应不断增长的新数据量。有两种方法:一种是更改指定缓冲区数组的大小,另一种是同时更改指标对象的所有缓冲区的大小。
调整指定指标缓冲区大小的方法:
//+------------------------------------------------------------------+ //| Resize the specified indicator buffer | //+------------------------------------------------------------------+ bool CIndMSTF::BufferResize(const uint buffer_num,const int new_buff_size) { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and return 'false' if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- Resize the buffer ::ResetLastError(); bool res=this.m_buffers[buffer_num].BuffResize(new_buff_size); //--- If unsuccessful, print a message to the log if(!res) ::PrintFormat("%s::%s: Buffer(%lu) resize failed. Error %lu",__FUNCTION__,this.Title(),buffer_num,::GetLastError()); //--- Return the result of resizing the buffer array return res; }
该方法在参数中接收缓冲区的编号,该缓冲区的数组应根据传递给该方法的值调整大小。如果缓冲区编号指定不正确,则会记录相关消息,并且该方法返回false。
如果数组调整大小失败,则会在日志中打印一条消息。最终返回缓冲区数组大小调整结果
调整所有指示器缓冲区大小的方法:
//+------------------------------------------------------------------+ //| Resize all indicator buffers | //+------------------------------------------------------------------+ bool CIndMSTF::BuffersResize(const int new_buff_size) { //--- In a loop through all indicator buffers, add to the 'res' variable the resizing result of each next buffer bool res=true; int total=(int)this.BuffersTotal(); for(int i=0;i<total;i++) res &=this.m_buffers[i].BuffResize(new_buff_size); //--- Return the result of resizing all arrays of indicator buffers return res; }
这里,在遍历指标对象的所有缓冲区的循环中,调整下一个缓冲区数组大小的结果被添加到“res”变量中,该变量的值最终从该方法返回。
以类似的方式组织用于初始化指示符对象缓冲区的数组的方法。
初始化指定的指标缓冲区的方法:
//+------------------------------------------------------------------+ //| Initialize the specified indicator buffer | //+------------------------------------------------------------------+ bool CIndMSTF::BufferInitialize(const uint buffer_num,const int new_buff_size) { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and return 'false' if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- resizing the buffer array bool res=this.BufferResize(buffer_num,new_buff_size); //--- If successfully resized, initialize the buffer with the set initializing value if(res) this.m_buffers[buffer_num].InitBuffer(); //--- Return the result return res; }
这里还检查初始化缓冲区的编号的正确性。然后将缓冲区设置为新的大小,如果调整大小成功,则将数组初始化为此缓冲区设置的值。
初始化所有指示器缓冲区的方法:
//+------------------------------------------------------------------+ //| Initialize all indicator buffers | //+------------------------------------------------------------------+ bool CIndMSTF::BuffersInitialize(const int new_buff_size) { //--- In a loop through all indicator buffers, add to the 'res' variable the resizing result of each next buffer //--- If successfully resized, initialize the buffer with the set initializing value bool res=true; int total=(int)this.BuffersTotal(); for(int i=0;i<total;i++) { res &=this.m_buffers[i].BuffResize(new_buff_size); if(res) this.m_buffers[i].InitBuffer(); } //--- Return the overall result return res; }
在遍历指标对象的所有缓冲区的循环中,调整下一个缓冲区数组大小的结果将添加到“res”变量中。成功调整大小后,将缓冲区初始化为为其设置的初始化值。该方法返回“res”变量的最终状态,如果至少有一个缓冲区未能初始化,该变量将具有false值。
用于设置和返回缓冲区值的其余方法与上面讨论的方法相同:
//+------------------------------------------------------------------+ //| Set the initializing value for the specified buffer | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferInitValue(const uint buffer_num,const double value) { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and exit if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Set a new initializing value for the specified buffer this.m_buffers[buffer_num].SetInitValue(value); } //+------------------------------------------------------------------+ //| Return the initialization value of the specified buffer | //+------------------------------------------------------------------+ double CIndMSTF::BufferInitValue(const uint buffer_num) const { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- If the indicator has buffers, return the initializing value of the first one, otherwise EMPTY_VALUE return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE); } //--- Return the initializing value of the requested buffer return this.m_buffers[buffer_num].InitValue(); } //+------------------------------------------------------------------+ //| Sets the offset value for the specified buffer | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferShift(const uint buffer_num,const int value) { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and exit if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Set the offset value for the buffer this.m_buffers[buffer_num].SetShift(value); } //+------------------------------------------------------------------+ //| Return the offset value of the specified buffer | //+------------------------------------------------------------------+ double CIndMSTF::BufferShift(const uint buffer_num) const { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- If the indicator has buffers, return the shift value of the very first one, otherwise 0 return(this.BuffersTotal()>0 ? this.m_buffers[0].Shift() : 0); } //--- Return the offset value of the requested buffer return this.m_buffers[buffer_num].Shift(); }
这些方法的逻辑在代码的注释中有详细描述。
计算指标数据的方法。计算指标(其计算部分)具有一个包含所有计算指标数据的缓冲区。我们需要将数据从计算部分缓冲区复制到指标对象的缓冲区数组中。对于此操作,我们需要组织一个资源高效的计算:我们将仅在第一次启动时或历史数据发生变化时复制整个缓冲区。
我们在上面讨论了这样一个计算,它应该被应用在指标对象的计算方法中。如果出现错误,该方法将返回false,并且调用程序将在下一个分时到达之前响应退出处理程序(EA交易中的OnTick和指标中的OnCalculate)。需要该方法返回的错误将被视为下载历史数据的开始、历史下载不完整、指标计算不完整以及将数据从计算部分缓冲区复制到指标对象缓冲区的错误。该方法将把错误代码写入变量,以便调用方能够正确读取并处理它。
使用计算部件缓冲区中的数据填充指标对象缓冲区的方法:
//+------------------------------------------------------------------+ //| Fill object buffers with data from the calculation part buffer | //+------------------------------------------------------------------+ bool CIndMSTF::Calculate(void) { //--- Set the success flag to true, and the error type to no error this.m_success=true; this.m_type_err=ERR_TYPE_NO_ERROR; //--- If the data is not yet synchronized with the trade server, if(!this.IsSynchronized()) { //--- Log a message about non-synchronized data, ::PrintFormat("%s::%s: Waiting for data to sync...",__FUNCTION__,this.Title()); //--- set the error type, add 'false' to the error flag and return 'false' this.m_type_err=ERR_TYPE_NO_CYNC; this.m_success &=false; return false; } //--- If the Calculated method returned -1, this means the start of data downloading if(this.Calculated()==WRONG_VALUE) { //--- Log a message about the start of data downloading, ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription()); //--- set the error type, add 'false' to the error flag and return 'false' this.m_type_err=ERR_TYPE_NO_DATA; this.m_success &=false; return false; } //--- If the Calculated method returned 0, this means that the indicator has not yet been calculated if(this.Calculated()==0) { //--- Log a message about waiting for the indicator to be calculated, ::PrintFormat("%s::%s: Waiting for a new tick and when the indicator will be calculated...",__FUNCTION__,this.Title()); //--- set the error type, add 'false' to the error flag and return 'false' this.m_type_err=ERR_TYPE_NO_CALC; this.m_success &=false; return false; } //--- Get the number of data bars for the indicator symbol/period int bars=::Bars(this.m_symbol,this.m_timeframe); //--- If the Bars function returned a zero value, which often happens on weekends, calculate the available number of bars if(bars==0) { //--- Get the date of the very first available bar in history for the symbol/period datetime firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_FIRSTDATE); //--- Get the date of the last (current) bar in history for the symbol/period datetime lastdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE); //--- Calculate the number of bars between the first and last dates of history int sec=::PeriodSeconds(this.m_timeframe); ulong date_bars=(((ulong)lastdate-(ulong)firstdate)/(sec>0 ? sec : 1))+1; //--- Write to the 'bars' variable the smaller value of the calculated number of bars and the maximum number of bars available in the terminal bars=(int)fmin(date_bars,::TerminalInfoInteger(TERMINAL_MAXBARS)); } //--- Write the resulting number of available bars to m_rates_total if(this.m_rates_total!=bars) this.m_rates_total=bars; //--- If the number of available bars is received, and it is 2 or less, if(this.m_rates_total>=0 && this.m_rates_total<3) { //--- Log a message about the number of available bars being too small ::PrintFormat("%s::%s: Not enough data for calculation: %ld bars. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_rates_total); //--- set the error type, add 'false' to the error flag and return 'false' this.m_type_err=ERR_TYPE_NO_DATA; this.m_success &=false; return false; } //--- Calculate the number of bars required to calculate the indicator //--- Either the entire available history, or 1 when a new bar opens, or 0 on the current tick this.m_limit=this.m_rates_total-this.m_prev_calculated; this.m_prev_calculated=this.Calculated(); //--- Declare an array of size 2 to receive data into it from the indicator's calculation part buffer //--- We always get two bars: previous and current double array[2]; //--- Get the number of indicator buffers int total=(int)this.BuffersTotal(); //--- If the calculated m_limit is greater than 1, it means either the first launch or changes in historical data //--- In this case, a complete recalculation of the indicator is necessary if(this.m_limit>1) { //--- In a loop over the number of indicator buffers for(int i=0;i<total;i++) { //--- resize the indicator buffer array and initialize it to the "empty" value set for this buffer this.BufferInitialize(i,this.m_rates_total); ::ResetLastError(); //--- Copy all available historical data from indicator's calculation part array to buffer array of indicator object int copied=::CopyBuffer(this.m_handle,i,-this.m_buffers[i].Shift(),this.m_rates_total,this.m_buffers[i].array); //--- If not all data is copied if(copied!=this.m_rates_total) { //--- If CopyBuffer returned -1, this means the start of historical data downloading //--- print a message about this to the log if(copied==WRONG_VALUE) ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription()); //--- In any other case, not all data has been copied yet //--- print a message about this to the log else ::PrintFormat("%s::%s: Not all data was copied. Data available: %lu, total copied: %ld",__FUNCTION__,this.Title(),this.m_rates_total,copied); //--- Write the absence of data to the error type this.m_type_err=ERR_TYPE_NO_DATA; //--- Add 'false' to the result and return 'false' to exit the method and wait for the next tick this.m_success &=false; return false; } } //--- If we exited the loop of copying all indicator buffers, then everything was successful - return 'true' return true; } //--- If calculated m_limit is less than or equal to 1, this means either opening of a new bar (m_limit==1) or current tick (m_limit==0) //--- In this case, it is necessary to calculate two bars - the first and the current if(this.m_limit<=1) { //--- In a loop over the number of indicator buffers for(int i=0;i<total;i++) { //--- If this is the opening of a new bar and resizing the indicator buffer failed, if(this.m_limit==1 && !this.BufferResize(i,this.m_rates_total)) { //--- add 'false' to the m_success variable and return 'false' //--- Here, an error message will be printed to log from the BufferResize method this.m_success &=false; return false; } //--- If failed to copy two bars from the indicator's calculation part buffer, ::ResetLastError(); if(::CopyBuffer(this.m_handle,i,-this.m_buffers[i].Shift(),2,array)!=2) { //--- report this via the log, add 'false' to the m_success variable and return 'false' ::PrintFormat("%s::%s: CopyBuffer(%lu) failed. Error %lu",__FUNCTION__,this.Title(),i,::GetLastError()); this.m_success &=false; return false; } //--- If got here, it means copying was successful - //--- copy data from array[], into which the last two bars were copied, to the indicator object buffer this.m_buffers[i].array[this.DataTotal(i)-1]=array[1]; this.m_buffers[i].array[this.DataTotal(i)-2]=array[0]; } //--- Success return true; } //--- Undefined 'limit' option - return 'false' return false; }
在每个代码块的注释中详细描述了该方法的整个逻辑。该方法从程序中调用,如果返回false,则在下一次分时之前退出OnTick或OnCalculate。
如果该方法完成时没有出现错误,那么指标对象的缓冲区将包含可供使用的数据。可以使用下面将讨论的方法来访问这些数据。
指标具有特殊的方法,用于将由该方法填充的指标对象缓冲区中的数据输出到指标绘图缓冲区中。这些方法以将数据写入指标对象缓冲区的相同形式,或考虑图表交易品种/周期,将数据输出到绘图缓冲区。这些方法可用于在当前图表的指标对象中显示计算数据。
用类缓冲区中的数据填充传递的数组的方法:
//+------------------------------------------------------------------+ //| Fill the passed array with data from the class buffer | //+------------------------------------------------------------------+ bool CIndMSTF::DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int limit,double &buffer[]) { //--- Set the success flag this.m_success=true; //--- Get the indexing direction of the buffer array passed to the method and, //--- if non-timeseries indexing, set timeseries indexing bool as_series=::ArrayGetAsSeries(buffer); if(!as_series) ::ArraySetAsSeries(buffer,true); //--- Set the symbol name and timeframe value passed to the method string symbol=(symbol_to=="" || symbol_to==NULL ? ::Symbol() : symbol_to); ENUM_TIMEFRAMES timeframe=(timeframe_to==PERIOD_CURRENT ? ::Period() : timeframe_to); datetime array[2]; //--- If this is the first launch or history changes, initialize the buffer array passed to the method if(limit>1 && this.m_limit>1) { ::PrintFormat("%s::%s First start, or historical data has been changed. Initialize Buffer(%lu)",__FUNCTION__,this.Title(),buffer_num); ::ArrayInitialize(buffer,this.BufferInitValue(buffer_num)); } //--- Set the value of the loop counter (no more than the maximum number of bars in the terminal on the chart) int count=(limit<=1 ? 2 : ::fmin(::TerminalInfoInteger(TERMINAL_MAXBARS),limit)); //--- In a loop from the zero bar to the value of the loop counter for(int i=0;i<count;i++) { //--- If the chart timeframe matches the class object timeframe, fill the buffer directly from the class object array if(timeframe==::Period() && this.m_timeframe==::Period()) buffer[i]=this.GetData(buffer_num,i); //--- Otherwise, if the chart timeframe is not equal to the timeframe of the class object else { //--- Find out which time of this class the bar of the current chart timeframe, corresponding to the loop index, belongs to ::ResetLastError(); if(::CopyTime(symbol,timeframe,i,2,array)!=2) { //--- If there is no data in the terminal, move on if(::GetLastError()==4401) continue; //--- Error in obtaining existing data - return false this.m_success &=false; return false; } //--- Using time of bar of current chart timeframe, find corresponding index of bar of class object's chart period ::ResetLastError(); int bar=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar==WRONG_VALUE) { this.m_success &=false; continue; } //--- If this is historical data (not the first or zero bar) - //--- in the indicator buffer at the loop index, write the value obtained from the calculation part buffer if(i>1) buffer[i]=this.GetData(buffer_num,bar); //--- If this is the current (zero) or previous (first) bar else { //--- Get the time of bars 0 and 1 by symbol/timeframe of the class object if(::CopyTime(this.m_symbol,this.m_timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Using time, get indexes of current and previous bars on the chart whose symbol/period was passed to method int bar0=::iBarShift(symbol,timeframe,array[1]); int bar1=::iBarShift(symbol,timeframe,array[0]); if(bar0==WRONG_VALUE || bar1==WRONG_VALUE) { this.m_success &=false; return false; } //--- If the chart timeframe is lower than the timeframe of the class object, if(timeframe<this.m_timeframe) { //--- in a loop from bar with smaller time to current chart bar, fill the buffer with data from the last 2 cells of the indicator buffer array for(int j=bar1;j>=0;j--) buffer[j]=this.GetData(buffer_num,(j>bar0 ? 1 : 0)); } //--- If the chart timeframe is higher than the timeframe of the class object, else { //--- Get the time of the current and previous bars by symbol/timeframe of the current chart if(::CopyTime(symbol,timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Using time, get indexes of bars in indicator's calculation part buffer, corresponding to time of current and previous bars on the chart int bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[1]); int bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Write into indicator buffer, at indexes 1 and 0, values from corresponding indexes of calculation part buffer buffer[1]=this.GetData(buffer_num,bar1); buffer[0]=this.GetData(buffer_num,bar0); } } } } //--- Set initial indexing of the buffer array passed to the method ::ArraySetAsSeries(buffer,as_series); //--- Successful return true; }
方法逻辑在其列表中进行了详细描述。该方法的思想是正确计算当前图表的柱形,这些柱需要填充在不同时间段上计算的指标缓冲区数组中的数据。传递给该方法的最后一个参数是自定义指标绘图缓冲区的数组,该数组应呈现在不同交易品种/周期上计算的指标。
按如下方式返回指定缓冲区数据的方法:
//+------------------------------------------------------------------+ //| Return the data of the specified buffer as is | //+------------------------------------------------------------------+ double CIndMSTF::GetData(const uint buffer_num,const int index) const { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- If the indicator has buffers, return "empty" value of the first one, otherwise EMPTY_VALUE return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE); } //--- If an incorrect index is specified, return the "empty" value of the specified buffer if(index<0 || index>(int)this.DataTotal(buffer_num)-1) return this.BufferInitValue(buffer_num); //--- Calculate the real index in the buffer array and return the value at this index int n=int(this.DataTotal(buffer_num)-1-index); return this.m_buffers[buffer_num].array[n]; }
该方法只是在指定索引处从指标对象缓冲区返回数据。
返回指定交易品种/时间框架的指定缓冲区数据的方法:
//+-------------------------------------------------------------------+ //| Returns data from specified buffer for specified symbol/timeframe | //+-------------------------------------------------------------------+ double CIndMSTF::GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const { //--- If current symbol/period of the chart is specified if(timeframe_to==::Period() && this.m_timeframe==::Period() && symbol_to==::Symbol() && this.m_symbol==::Symbol()) return this.GetData(buffer_num,index); //--- Find out which time of this class the current chart timeframe's bar, corresponding to the loop index, belongs to datetime array[]; if(::CopyTime(symbol_to,timeframe_to,index,1,array)!=1) return this.BufferInitValue(buffer_num); //--- Using time of bar of current chart timeframe, find corresponding bar index of bar this class chart period int bar=iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- If the bar is not found, return the "empty" value set for the buffer if(bar==WRONG_VALUE) return this.BufferInitValue(buffer_num); //--- Return value from the indicator object buffer at the found index return this.GetData(buffer_num,bar); }
该方法查找时间序列的柱的索引,在该时间序列上计算与传递给该方法的图表交易品种/周期相对应的指标,并在找到的索引处从指标对象缓冲区返回数据。
返回指标线状态的方法:
//+------------------------------------------------------------------+ //| Return the state of the indicator line as is | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineState(const uint buffer_num,const int index) const { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=this.GetData(buffer_num,index); const double value1=this.GetData(buffer_num,index+1); const double value2=this.GetData(buffer_num,index+2); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; }
该方法根据指标对象缓冲区中的数据确定指标对象的线状态,并返回找到的值。
返回特定交易品种/周期的指标状态的方法:
//+------------------------------------------------------------------+ //| Return indicator line state for the specific symbol/period | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const int index) const { //--- Determine the chart symbol/period passed to the method string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from); ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from); //--- If we get data from symbol/period equal to current chart, return state from the buffer "as is" if(symbol==::Symbol() && symbol==this.m_symbol && timeframe==::Period() && timeframe==this.m_timeframe) return this.BufferLineState(buffer_num,index); //--- Declare variables to search for the required bars on the current chart datetime array[1]; int bar0=WRONG_VALUE; int bar1=WRONG_VALUE; int bar2=WRONG_VALUE; //--- Get the time of the first bar on the chart ::ResetLastError(); if(::CopyTime(symbol,timeframe,index,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index,::GetLastError()); return LINE_STATE_NONE; } //--- Get index of the first bar in indicator object buffer based on bar opening time on the chart bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar0==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Get the time of the second bar on the chart ::ResetLastError(); if(::CopyTime(symbol,timeframe,index+1,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+1,::GetLastError()); return LINE_STATE_NONE; } //--- Get index of the second bar in indicator object buffer based on bar opening time on the chart bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar1==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Get the time of the third bar on the chart ::ResetLastError(); if(::CopyTime(symbol,timeframe,index+2,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+2,::GetLastError()); return LINE_STATE_NONE; } //--- Get index of the third bar in indicator object buffer based on bar opening time on the chart bar2=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar2==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=this.GetData(buffer_num,bar0); const double value1=this.GetData(buffer_num,bar1); const double value2=this.GetData(buffer_num,bar2); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; }
该方法用于获取指标对象线相对于当前图表的状态。如果指标对象是使用相对于当前图表的较高时间段的数据计算的,则其直线将在当前图表的条形图上“拉伸”。该方法允许您正确地获取当前图表指定柱上指标线的状态。
返回相对于指定水平的线状态的方法:
//+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=this.GetData(buffer_num,index); const double value1=this.GetData(buffer_num,index+1); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_BELOW; //--- The line is above the level (value1>level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; }
返回相对于指定图表交易品种/周期上指定水平的线状态的方法:
//+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //| on the specified chart symbol/period | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Determine the chart symbol/period passed to the method string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from); ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from); //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=this.GetDataTo(symbol,timeframe,buffer_num,index); const double value1=this.GetDataTo(symbol,timeframe,buffer_num,index+1); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_BELOW; //--- The line is above the level (value1>level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; }
您可以在关于将振荡器连接到EA的文章中读到更多关于获取指标线状态的方法。
其它的类方法:
//+------------------------------------------------------------------+ //| Return category description | //+------------------------------------------------------------------+ string CIndMSTF::CategoryDescription(void) { //--- Create a category name from ENUM_IND_CATEGORY and return the resulting text string category=::StringSubstr(::EnumToString(this.m_category),13); if(category.Lower()) category.SetChar(0,ushort(category.GetChar(0)-0x20)); return category; } //+------------------------------------------------------------------+ //| Return the description of the indicator buffer | //+------------------------------------------------------------------+ string CIndMSTF::BufferDescription(const uint buffer_num) { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and return empty string if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return ""; } //--- If indicator has buffers, return description of the specified buffer, otherwise description of the indicator return(this.BuffersTotal()>0 ? this.m_buffers[buffer_num].descript : this.m_title); } //+------------------------------------------------------------------+ //| Set indicator buffer description | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferDescription(const uint buffer_num,const string descr) { //--- If the indicator has no buffers, exit if(this.BuffersTotal()==0) return; //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and exit if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Write the description passed to the method into the specified buffer this.m_buffers[buffer_num].descript=descr; } //+------------------------------------------------------------------+ //| Disable timeseries indexing of buffer arrays | //+------------------------------------------------------------------+ void CIndMSTF::SetAsSeriesOff(void) { //--- In a loop through all indicator buffers, disable the array as timeseries flag for(int i=0;i<(int)this.BuffersTotal();i++) ::ArraySetAsSeries(this.m_buffers[i].array,false); } //+------------------------------------------------------------------+ //| Returns the timeseries flag of the given buffer | //+------------------------------------------------------------------+ bool CIndMSTF::IsSeries(const uint buffer_num) const { //--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and return 'false' if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- Return the timeseries flag of the array of the specified buffer return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array); } //+------------------------------------------------------------------+ //| Returns the amount of data in the specified buffer | //+------------------------------------------------------------------+ uint CIndMSTF::DataTotal(const uint buffer_num) const { //--- Validate the buffer number passed to method and, if number is incorrect, print a message to log and return zero if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return 0; } //--- Return the array size of the specified buffer return this.m_buffers[buffer_num].array.Size(); }
多交易品种多周期指标对象的基类已准备就绪。该类包含使用不属于当前图表的时间序列数据构建的指标所需的所有功能。
要创建不同类型的技术指标,请从新创建的基本类创建派生类。在派生类的构造函数中,指示特定类型的指标所固有的参数和属性。
按类型划分的指标类
从基类派生的类将是最简单的,并且只包含一个构造函数。类构造函数将被传递用于计算指标的图表的交易品种/周期,以及特定于此类型指标的输入参数。在构造函数初始化行中,参数将传递给父类的构造函数。
一个类创建不包含任何参数的指标对象的示例:
//+------------------------------------------------------------------+ //| Accelerator Oscillator indicator class | //+------------------------------------------------------------------+ class CIndAC : public CIndMSTF { public: //--- Constructor CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AC,1,symbol,timeframe) { //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("AC"); this.SetDescription("Accelerator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } };
应把其上计算指标的指标类型、缓冲区数量、图表交易品种和图表周期在初始化字符串中传递给父类。在类主体中创建一个包含指标参数描述的字符串。在这种情况下,如果在当前图表的数据上创建指标,则参数字符串将为空。否则,它将以“(EURUSD,H1)”的形式包含图表的交易品种和周期。接下来,在构造函数的主体中设置这种类型的指标(这里是加速振荡指标)所固有的所有参数。
对于每个指标,可以设置数据窗口和交易品种图表中显示的小数位数。该类构造函数没有“Digits”设置,因为该值等于计算指标的交易品种的小数位数,是在父类的构造函数中设置的。如果有必要为指标设置不同的小数位数,则应在数字与交易品种不同的指标类的构造函数中完成,或者可以在使用SetDigits()方法创建指标对象后更改。
具有参数的指标类:
//+------------------------------------------------------------------+ //| Accumulation/Distribution indicator class | //+------------------------------------------------------------------+ class CIndAD : public CIndMSTF { public: //--- Constructor CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // used volume ) : CIndMSTF(IND_AD,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("A/D"); this.SetDescription("Accumulation/Distribution"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } };
这里我们有一些参数,它们应该注册在指标输入参数MqlParam的数组结构中。在这里,我们还设置了指标的Digits值,该值是为标准累积/分布指标设置的。
从多交易品种多周期指标的基类派生的所有类的完整列表:
//+------------------------------------------------------------------+ //| Accelerator Oscillator indicator class | //+------------------------------------------------------------------+ class CIndAC : public CIndMSTF { public: //--- Constructor CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AC,1,symbol,timeframe) { //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("AC"); this.SetDescription("Accelerator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Accumulation/Distribution indicator class | //+------------------------------------------------------------------+ class CIndAD : public CIndMSTF { public: //--- Constructor CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // used volume ) : CIndMSTF(IND_AD,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("A/D"); this.SetDescription("Accumulation/Distribution"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Average Directional Movement Index indicator class | //+------------------------------------------------------------------+ class CIndADX : public CIndMSTF { public: //--- Constructor CIndADX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int adx_period // averaging period ) : CIndMSTF(IND_ADX,3,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("ADX"); this.SetDescription("Average Directional Movement Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=2; //--- write descriptions of MAIN_LINE, PLUSDI_LINE and MINUSDI_LINE line buffers this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(PLUSDI_LINE,"+DI"); this.SetBufferDescription(MINUSDI_LINE,"-DI"); } }; //+------------------------------------------------------------------+ //| Average Directional Movement Index Wilder indicator class | //+------------------------------------------------------------------+ class CIndADXW : public CIndMSTF { public: //--- Constructor CIndADXW(const string symbol,const ENUM_TIMEFRAMES timeframe, const int adx_period // averaging period ) : CIndMSTF(IND_ADXW,3,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("ADX Wilder"); this.SetDescription("Average Directional Movement Index Wilder"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=2; //--- write descriptions of MAIN_LINE, PLUSDI_LINE and MINUSDI_LINE line buffers this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(PLUSDI_LINE,"+DI"); this.SetBufferDescription(MINUSDI_LINE,"-DI"); } }; //+------------------------------------------------------------------+ //| Alligator indicator class | //+------------------------------------------------------------------+ class CIndAlligator : public CIndMSTF { public: //--- Constructor CIndAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, // period for calculating jaws const int jaw_shift, // horizontal shift of jaws const int teeth_period, // period for calculating teeth const int teeth_shift, // horizontal shift of teeth const int lips_period, // period for calculating lips const int lips_shift, // horizontal shift of lips const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_ALLIGATOR,3,symbol,timeframe) { // Buffer indexes: 0 - GATORJAW_LINE, 1 - GATORTEETH_LINE, 2 - GATORLIPS_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,8)==8) { ::ZeroMemory(this.m_param); //--- period for jaw line calculation this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period); //--- horizontal shift of the jaw line this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=jaw_shift; //--- period for teeth line calculation this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period); //--- horizontal shift of teeth line this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=teeth_shift; //--- period for lip line calculation this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period); //--- horizontal shift of lips line this.m_param[5].type=TYPE_INT; this.m_param[5].integer_value=lips_shift; //--- smoothing type this.m_param[6].type=TYPE_UINT; this.m_param[6].integer_value=ma_method; //--- price type or handle this.m_param[7].type=TYPE_UINT; this.m_param[7].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("Alligator"); this.SetDescription("Alligator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Write descriptions of GATORJAW_LINE, GATORTEETH_LINE and GATORLIPS_LINE line buffers this.SetBufferDescription(GATORJAW_LINE,::StringFormat("Jaws(%s%lu)", (current ? "" : symbol_period+":"),jaw_period)); this.SetBufferDescription(GATORTEETH_LINE,::StringFormat("Teeth(%s%lu)",(current ? "" : symbol_period+":"),teeth_period)); this.SetBufferDescription(GATORLIPS_LINE,::StringFormat("Lips(%s%lu)", (current ? "" : symbol_period+":"),lips_period)); //--- Write offsets to buffers GATORJAW_LINE, GATORTEETH_LINE and GATORLIPS_LINE this.SetBufferShift(GATORJAW_LINE,jaw_shift); this.SetBufferShift(GATORTEETH_LINE,teeth_shift); this.SetBufferShift(GATORLIPS_LINE,lips_shift); } }; //+------------------------------------------------------------------+ //| Adaptive Moving Average indicator class | //+------------------------------------------------------------------+ class CIndAMA : public CIndMSTF { public: //--- Constructor CIndAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ama_period, // AMA period const int fast_ma_period, // fast MA period const int slow_ma_period, // slow MA period const int ama_shift, // horizontal shift of the indicator const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_AMA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- AMA period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ama_period<1 ? 9 : ama_period); //--- fast MA period this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(fast_ma_period<1 ? 2 : fast_ma_period); //--- slow MA period this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(slow_ma_period<1 ? 30 : slow_ma_period); //--- horizontal shift of the indicator this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=ama_shift; //--- price type or handle this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),ama_period,fast_ma_period,slow_ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("AMA"); this.SetDescription("Adaptive Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ama_shift); } }; //+------------------------------------------------------------------+ //| Awesome Oscillator indicator class | //+------------------------------------------------------------------+ class CIndAO : public CIndMSTF { public: //--- Constructor CIndAO(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AO,1,symbol,timeframe) { //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("AO"); this.SetDescription("Awesome Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Average True Range indicator class | //+------------------------------------------------------------------+ class CIndATR : public CIndMSTF { public: //--- Constructor CIndATR(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // averaging period ) : CIndMSTF(IND_ATR,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("ATR"); this.SetDescription("Average True Range"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Bears Power indicator class | //+------------------------------------------------------------------+ class CIndBears : public CIndMSTF { public: //--- Constructor CIndBears(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // averaging period ) : CIndMSTF(IND_BEARS,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Bears"); this.SetDescription("Bears Power"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Bulls Power indicator class | //+------------------------------------------------------------------+ class CIndBulls : public CIndMSTF { public: //--- Constructor CIndBulls(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // averaging period ) : CIndMSTF(IND_BULLS,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Bulls"); this.SetDescription("Bulls Power"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Bollinger Bands® indicator class | //+------------------------------------------------------------------+ class CIndBands : public CIndMSTF { public: //--- Constructor CIndBands(const string symbol,const ENUM_TIMEFRAMES timeframe, const int bands_period, // central line calculation period const int bands_shift, // horizontal shift of the indicator const double deviation, // number of standard deviations const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_BANDS,3,symbol,timeframe) { // Buffer indexes: 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- central line calculation period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(bands_period<1 ? 20 : bands_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=bands_shift; //--- number of standard deviations this.m_param[2].type=TYPE_DOUBLE; this.m_param[2].double_value=deviation; //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),bands_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Bands"); this.SetDescription("Bollinger Bands"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Description of line buffers BASE_LINE, UPPER_BAND and LOWER_BAND this.SetBufferDescription(BASE_LINE,this.m_title+" Middle"); this.SetBufferDescription(UPPER_BAND,this.m_title+" Upper"); this.SetBufferDescription(LOWER_BAND,this.m_title+" Lower"); //--- Write offsets to the BASE_LINE, UPPER_BAND and LOWER_BAND buffers this.SetBufferShift(BASE_LINE,bands_shift); this.SetBufferShift(UPPER_BAND,bands_shift); this.SetBufferShift(LOWER_BAND,bands_shift); } }; //+------------------------------------------------------------------+ //| Commodity Channel Index indicator class | //+------------------------------------------------------------------+ class CIndCCI : public CIndMSTF { public: //--- Constructor CIndCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_CCI,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- price type or handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("CCI"); this.SetDescription("Commodity Channel Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Chaikin Oscillator indicator class | //+------------------------------------------------------------------+ class CIndCHO : public CIndMSTF { public: //--- Constructor CIndCHO(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ma_period, // fast period const int slow_ma_period, // slow period const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_VOLUME applied_volume // used volume ) : CIndMSTF(IND_CHAIKIN,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- fast period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ma_period<1 ? 3 : fast_ma_period); //--- slow period this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ma_period<1 ? 10 : slow_ma_period); //--- smoothing type this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- used volume this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),slow_ma_period,fast_ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("CHO"); this.SetDescription("Chaikin Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=0; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Double Exponential Moving Average indicator class | //+------------------------------------------------------------------+ class CIndDEMA : public CIndMSTF { public: //--- Constructor CIndDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const int ma_shift, // horizontal indicator shift const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_DEMA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- price type or handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("DEMA"); this.SetDescription("Double Exponential Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| DeMarker indicator class | //+------------------------------------------------------------------+ class CIndDeM : public CIndMSTF { public: //--- Constructor CIndDeM(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // averaging period ) : CIndMSTF(IND_DEMARKER,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("DeM"); this.SetDescription("DeMarker"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=3; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Envelopes indicator class | //+------------------------------------------------------------------+ class CIndEnvelopes : public CIndMSTF { public: //--- Constructor CIndEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // middle line calculation period const int ma_shift, // horizontal shift of the indicator const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_PRICE applied_price, // price type or handle const double deviation // deviation of envelope borders from the middle line ) : CIndMSTF(IND_ENVELOPES,2,symbol,timeframe) { // Buffer indexes: 0 - UPPER_LINE, 1 - LOWER_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- central line calculation period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- smoothing type this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; //--- deviation of envelope borders from the muddle line this.m_param[4].type=TYPE_UINT; this.m_param[4].double_value=deviation; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Envelopes"); this.SetDescription("Envelopes"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Description of UPPER_LINE and LOWER_LINE line buffers this.SetBufferDescription(UPPER_LINE,this.m_title+" Upper"); this.SetBufferDescription(LOWER_LINE,this.m_title+" Lower"); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Force Index indicator class | //+------------------------------------------------------------------+ class CIndForce : public CIndMSTF { public: //--- Constructor CIndForce(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_VOLUME applied_volume // volume type for calculation ) : CIndMSTF(IND_FORCE,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); //--- smoothing type this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=ma_method; //--- volume type for calculation this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Force"); this.SetDescription("Force Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Fractals indicator class | //+------------------------------------------------------------------+ class CIndFractals : public CIndMSTF { public: //--- Constructor CIndFractals(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_FRACTALS,2,symbol,timeframe) { // Buffer indexes: 0 - UPPER_LINE, 1 - LOWER_LINE //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("Fractals"); this.SetDescription("Fractals"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Description of UPPER_LINE and LOWER_LINE line buffers this.SetBufferDescription(UPPER_LINE,this.m_title+" Up"); this.SetBufferDescription(LOWER_LINE,this.m_title+" Down"); } }; //+------------------------------------------------------------------+ //| Fractal Adaptive Moving Average indicator class | //+------------------------------------------------------------------+ class CIndFrAMA : public CIndMSTF { public: //--- Constructor CIndFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const int ma_shift, // horizontal shift of the indicator const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_FRAMA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- price type or handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("FRAMA"); this.SetDescription("Fractal Adaptive Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Gator Oscillator indicator class | //+------------------------------------------------------------------+ class CIndGator : public CIndMSTF { public: //--- Constructor CIndGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, // period for jaw line calculation const int jaw_shift, // horizontal shift of jaw line const int teeth_period, // period for calculating teeth line const int teeth_shift, // horizontal shift of teeth line const int lips_period, // period for calculating lip line const int lips_shift, // horizontal shift of lip line const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_GATOR,4,symbol,timeframe) { // Buffer indexes: 0 - UPPER_HISTOGRAM, 1 - color buffer of the upper histogram, 2 - LOWER_HISTOGRAM, 3 - color buffer of the lower histogram //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,8)==8) { ::ZeroMemory(this.m_param); //--- period for jaw line calculation this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period); //--- horizontal shift of the jaw line this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=jaw_shift; //--- period for teeth line calculation this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period); //--- horizontal shift of teeth line this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=teeth_shift; //--- period for lip line calculation this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period); //--- horizontal shift of lips line this.m_param[5].type=TYPE_INT; this.m_param[5].integer_value=lips_shift; //--- smoothing type this.m_param[6].type=TYPE_UINT; this.m_param[6].integer_value=ma_method; //--- price type or handle this.m_param[7].type=TYPE_UINT; this.m_param[7].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Gator"); this.SetDescription("Gator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+1; //--- Description of line buffers UPPER_HISTOGRAM, upper histogram color buffer, LOWER_HISTOGRAM and lower histogram color buffer this.SetBufferDescription(UPPER_HISTOGRAM,this.m_title+" Up"); this.SetBufferDescription(1,this.m_title+" Colors Up"); this.SetBufferDescription(LOWER_HISTOGRAM,this.m_title+" Down"); this.SetBufferDescription(3,this.m_title+" Colors Down"); //--- Записываем смещения в буферы UPPER_HISTOGRAM, 1, LOWER_HISTOGRAM и 2 this.SetBufferShift(UPPER_HISTOGRAM,teeth_shift); this.SetBufferShift(1,teeth_shift); this.SetBufferShift(LOWER_HISTOGRAM,lips_shift); this.SetBufferShift(3,lips_shift); } }; //+------------------------------------------------------------------+ //| Ichimoku Kinko Hyo indicator class | //+------------------------------------------------------------------+ class CIndIchimoku : public CIndMSTF { public: //--- Constructor CIndIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen, // period of Tenkan-sen const int kijun_sen, // period of Kijun-sen const int senkou_span_b // period of Senkou Span B ) : CIndMSTF(IND_ICHIMOKU,5,symbol,timeframe) { // Buffer indexes: 0 - TENKANSEN_LINE, 1 - KIJUNSEN_LINE, 2 - SENKOUSPANA_LINE, 3 - SENKOUSPANB_LINE, 4 - CHIKOUSPAN_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- period of Tenkan-sen this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(tenkan_sen<1 ? 9 : tenkan_sen); //--- period of Kijun-sen this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(kijun_sen<1 ? 26 : kijun_sen); //--- period of Senkou Span B this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(senkou_span_b<1 ? 52 : senkou_span_b); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),tenkan_sen,kijun_sen,senkou_span_b); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Ichimoku"); this.SetDescription("Ichimoku Kinko Hyo"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Description of line buffers TENKANSEN_LINE, KIJUNSEN_LINE, SENKOUSPANA_LINE, SENKOUSPANB_LINE and CHIKOUSPAN_LINE this.SetBufferDescription(TENKANSEN_LINE,::StringFormat("Tenkan-sen(%lu)",tenkan_sen)); this.SetBufferDescription(KIJUNSEN_LINE,::StringFormat("Kijun-sen(%lu)",kijun_sen)); this.SetBufferDescription(SENKOUSPANA_LINE,"Senkou Span A"); this.SetBufferDescription(SENKOUSPANB_LINE,::StringFormat("Senkou Span B(%lu)",senkou_span_b)); this.SetBufferDescription(CHIKOUSPAN_LINE,"Chikou Span"); //--- Write shifts to buffers SENKOUSPANA_LINE, SENKOUSPANB_LINE and CHIKOUSPAN_LINE //this.SetBufferShift(SENKOUSPANA_LINE,kijun_sen); //this.SetBufferShift(SENKOUSPANB_LINE,kijun_sen); //this.SetBufferShift(CHIKOUSPAN_LINE,kijun_sen-senkou_span_b); } }; //+------------------------------------------------------------------+ //| Market Facilitation Index indicator class | //+------------------------------------------------------------------+ class CIndBWMFI : public CIndMSTF { public: //--- Constructor CIndBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // volume type for calculation ) : CIndMSTF(IND_BWMFI,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- volume type for calculation this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("BW MFI"); this.SetDescription("Market Facilitation Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Momentum indicator class | //+------------------------------------------------------------------+ class CIndMomentum : public CIndMSTF { public: //--- Constructor CIndMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe, const int mom_period, // averaging period const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_MOMENTUM,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(mom_period<1 ? 14 : mom_period); //--- price type or handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),mom_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Momentum"); this.SetDescription("Momentum"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Money Flow Index indicator class | //+------------------------------------------------------------------+ class CIndMFI : public CIndMSTF { public: //--- Constructor CIndMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const ENUM_APPLIED_VOLUME applied_volume // volume type for calculation ) : CIndMSTF(IND_MFI,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- volume type for calculation this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("MFI"); this.SetDescription("Money Flow Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Moving Average indicator class | //+------------------------------------------------------------------+ class CIndMA : public CIndMSTF { public: //--- Constructor CIndMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const int ma_shift, // horizontal shift of the indicator const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_MA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- smoothing type this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("MA"); this.SetDescription("Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Moving Average of Oscillator indicator class | //+------------------------------------------------------------------+ class CIndOsMA : public CIndMSTF { public: //--- Constructor CIndOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, // fast MA period const int slow_ema_period, // slow MA period const int signal_period, // difference averaging period const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_OSMA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- fast MA period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period); //--- slow MA period this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period); //--- difference averaging period this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period<2 ? 2 : signal_period); //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("OsMA"); this.SetDescription("Moving Average of Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+2; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Moving Averages Convergence/Divergence indicator class | //+------------------------------------------------------------------+ class CIndMACD : public CIndMSTF { public: //--- Constructor CIndMACD(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, // fast MA period const int slow_ema_period, // slow MA period const int signal_period, // difference averaging period const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_MACD,2,symbol,timeframe) { // Buffer indexes: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- fast MA period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period); //--- slow MA period this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period); //--- difference averaging period this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period); //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("MACD"); this.SetDescription("Moving Averages Convergence/Divergence"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Description of MAIN_LINE and SIGNAL_LINE line buffers this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); } }; //+------------------------------------------------------------------+ //| On Balance Volume indicator class | //+------------------------------------------------------------------+ class CIndOBV : public CIndMSTF { public: //--- Constructor CIndOBV(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // volume type for calculation ) : CIndMSTF(IND_OBV,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- volume type for calculation this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("OBV"); this.SetDescription("On Balance Volume"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Parabolic Stop and Reverse system indicator class | //+------------------------------------------------------------------+ class CIndSAR : public CIndMSTF { public: //--- Constructor CIndSAR(const string symbol,const ENUM_TIMEFRAMES timeframe, const double step, // price change step — acceleration factor const double maximum // maximum step ) : CIndMSTF(IND_SAR,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- price change step — acceleration factor this.m_param[0].type=TYPE_DOUBLE; this.m_param[0].double_value=step; //--- maximum step this.m_param[1].type=TYPE_DOUBLE; this.m_param[1].double_value=maximum; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%.2f,%.2f)",symbol_period,(current ? "" : ":"),step,maximum); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("SAR"); this.SetDescription("Parabolic SAR"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Класс индикатора Relative Strength Index | //+------------------------------------------------------------------+ class CIndRSI : public CIndMSTF { public: //--- Constructor CIndRSI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_RSI,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- price type or handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("RSI"); this.SetDescription("Relative Strength Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Relative Vigor Index indicator class | //+------------------------------------------------------------------+ class CIndRVI : public CIndMSTF { public: //--- Constructor CIndRVI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // averaging period ) : CIndMSTF(IND_RVI,2,symbol,timeframe) { // Buffer indexes: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("RVI"); this.SetDescription("Relative Vigor Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=3; //--- Description of MAIN_LINE and SIGNAL_LINE line buffers this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); } }; //+------------------------------------------------------------------+ //| Standard Deviation indicator class | //+------------------------------------------------------------------+ class CIndStdDev : public CIndMSTF { public: //--- Constructor CIndStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const int ma_shift, // horizontal shift of the indicator const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_STDDEV,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 20 : ma_period<2 ? 2 : ma_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- smoothing type this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("StdDev"); this.SetDescription("Standard Deviation"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Stochastic Oscillator indicator class | //+------------------------------------------------------------------+ class CIndStoch : public CIndMSTF { public: //--- Constructor CIndStoch(const string symbol,const ENUM_TIMEFRAMES timeframe, const int Kperiod, // K-period (number of bars for calculations) const int Dperiod, // D-period (primary smoothing period) const int slowing, // final smoothing const ENUM_MA_METHOD ma_method, // smoothing type const ENUM_STO_PRICE price_field // Stochastic calculation method ) : CIndMSTF(IND_STOCHASTIC,2,symbol,timeframe) { // Buffer indexes: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- K period (number of bars for calculation) this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(Kperiod<1 ? 5 : Kperiod); //--- D period (primary smoothing period) this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(Dperiod<1 ? 3 : Dperiod); //--- final smoothing this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(slowing<1 ? 3 : slowing); //--- smoothing type this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=ma_method; //--- Stochastic calculation method this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=price_field; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),Kperiod,Dperiod,slowing); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Stoch"); this.SetDescription("Stochastic Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Description of MAIN_LINE and SIGNAL_LINE line buffers this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); } }; //+------------------------------------------------------------------+ //| Triple Exponential Moving Average indicator class | //+------------------------------------------------------------------+ class CIndTEMA : public CIndMSTF { public: //--- Constructor CIndTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const int ma_shift, // horizontal shift of the indicator const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_TEMA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- horizontal shift of the indicator this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- price type or handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("TEMA"); this.SetDescription("Triple Exponential Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Triple Exponential Moving Averages Oscillator indicator class | //+------------------------------------------------------------------+ class CIndTriX : public CIndMSTF { public: //--- Constructor CIndTriX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // averaging period const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_TRIX,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- price type or handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName("TRIX"); this.SetDescription("Triple Exponential Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Larry Williams' Percent Range indicator class | //+------------------------------------------------------------------+ class CIndWPR : public CIndMSTF { public: //--- Constructor CIndWPR(const string symbol,const ENUM_TIMEFRAMES timeframe, const int calc_period // averaging period ) : CIndMSTF(IND_WPR,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- averaging period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(calc_period<1 ? 14 : calc_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),calc_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("%R"); this.SetDescription("Williams' Percent Range"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Variable Index Dynamic Average indicator class | //+------------------------------------------------------------------+ class CIndVIDyA : public CIndMSTF { public: //--- Constructor CIndVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int cmo_period, // the Chande Momentum period const int ema_period, // period of the smoothing factor const int ma_shift, // horizontal shift of the indicator const ENUM_APPLIED_PRICE applied_price // price type or handle ) : CIndMSTF(IND_VIDYA,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- Chande Momentum period this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(cmo_period<1 ? 9 : cmo_period); //--- smoothing factor period this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(ema_period<1 ? 12 : ema_period); //--- horizontal shift of the indicator this.m_param[2].type=TYPE_INT; this.m_param[2].integer_value=ma_shift; //--- price type or handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),cmo_period,ema_period); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("VIDYA"); this.SetDescription("Variable Index Dynamic Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); //--- Write shift to buffer 0 this.SetBufferShift(0,ma_shift); } }; //+------------------------------------------------------------------+ //| Volumes indicator class | //+------------------------------------------------------------------+ class CIndVolumes : public CIndMSTF { public: //--- Constructor CIndVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // volume type ) : CIndMSTF(IND_VOLUMES,1,symbol,timeframe) { //--- Set the size of the parameter array and fill it ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- volume type this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title, category and Digits this.SetParameters(param); this.SetName("Volumes"); this.SetDescription("Volumes"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Write description of line buffers this.SetBufferDescription(0,this.m_title); } }; //+------------------------------------------------------------------+ //| Custom indicator class | //+------------------------------------------------------------------+ class CIndCustom : public CIndMSTF { public: //--- Constructor CIndCustom(const string symbol,const ENUM_TIMEFRAMES timeframe, const string path, // path to the indicator (for example, "Examples\\MACD.ex5") const string name, // name of the custom indicator const uint buffers, // number of indicator buffers const MqlParam ¶m[] // array of custom indicator parameters ) : CIndMSTF(IND_CUSTOM,buffers,symbol,timeframe) { //--- If an empty array of parameters is passed, print this to log int total=(int)param.Size(); if(total==0) ::PrintFormat("%s Error. Passed an empty array",__FUNCTION__); //--- If the array is not empty and its size is increased by 1 (the first string parameter must contain the indicator name) ResetLastError(); if(total>0 && ::ArrayResize(this.m_param,total+1)==total+1) { //--- Reset data in the array and enter name (path to file and name of .ex5 file) ::ZeroMemory(this.m_param); //--- name of the custom indicator this.m_param[0].type=TYPE_STRING; this.m_param[0].string_value=path; //--- fill the array of indicator parameters for(int i=0;i<total;i++) { this.m_param[i+1].type=param[i].type; this.m_param[i+1].double_value=param[i].double_value; this.m_param[i+1].integer_value=param[i].integer_value; this.m_param[i+1].string_value=param[i].string_value; } //--- Create description of parameters //--- If non-current chart symbol or period, their descriptions are added to parameters bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Write description of parameters, indicator name, its description, title and category this.SetParameters(param); this.SetName(name); this.SetDescription(name); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_CUSTOM; //--- Write a description of the first line buffer this.SetBufferDescription(0,this.m_title); } } };
所呈现的列表包含用于创建客户端终端中可用的所有技术指标的所有类,并且另外提供用于创建自定义指标的类。所有类都是相同的,它们的要点都在类代码中注释。
请注意,测试涵盖了上述一些指标的创建和运行。也就是说,只有基于在主图表上绘制一条线的移动平均线的指标才测试过。在接下来的文章中,我们将编写用于创建所有类型技术指标的多交易品种、多周期版本的模板。
事实上,创建多指标,一切都已经准备好了。但我们将超越这一想法,创建一个方便的工具,用于自动创建和使用多交易品种、多周期指标。这将是一个指标的集合类,允许您轻松创建基于标准或自定义指标的任何指标,将其转换为多交易品种、多周期的指标。
指标集合类
指标集合类本质上是指向对象的指针的常规列表。在此列表中,我们将添加用于方便地创建指标和将新创建的指标添加到集合的方法。还可以容易地获得指向所需指标的指针,并使用其中的必要数据。将新指标添加到集合时,将首先检查集合中是否存在完全相同的指标。如果集合中已经存在相同的指标,则将删除新创建的对象,并返回指向集合中存在的对象的指针。这避免了两个不同对象引用同一计算部分的情况。
集合类的结构将重复基本的多交易品种多周期指标类的结构。唯一的区别是,大多数方法必须首先通过其句柄找到所需的指标,然后调用相关方法来设置或获取其值或操作结果。
我们将使用相同的文件\MQL5\Include\IndMSTF\IndMSTF.mqh,并将继续添加一个新类。对于它的操作,您将需要包括类的文件以及指向CObject类实例及其派生类的指针的动态数组CArrayObj:
//+------------------------------------------------------------------+ //| Indicator collection class | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> class CMSTFIndicators { private: public: }
在类主体中,添加列表对象用于类操作的方法:
//+------------------------------------------------------------------+ //| Indicator collection class | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> class CMSTFIndicators { private: CArrayObj m_list; //--- Creates an indicator for the passed object bool CreateIndicator(CIndMSTF *ind_obj); //--- Adds the specified indicator to the collection int AddNewIndicator(CIndMSTF *ind_obj,const string source); public: //--- Returns (1) indicator object by handle, (2) number of indicators in the collection CIndMSTF *GetIndicatorObj(const int ind_handle,const string source) const; uint IndicatorsTotal(void) const { return this.m_list.Total(); } //--- Populates buffers of (1) the indicator by handle, (2) all indicators in the collection bool Calculate(const int ind_handle); bool Calculate(void); //--- Sets the (1) specified, (2) default description of the indicator buffer line void SetPlotLabel(const uint plot_index,const string descript); void SetPlotLabelFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num); //--- Sets the shift to the specified plotting buffer void SetPlotShift(const uint plot_index,const int shift); //--- (1) Sets (2) returns the initializing value of the given buffer specified by the indicator handle void SetBufferInitValue(const int ind_handle,const uint buffer_num,const double value); double BufferInitValue(const int ind_handle,const uint buffer_num) const; //--- Returns indicator data by handle from the specified buffer at index (1) as is, (2) for the specified symbol/timeframe double GetData(const int ind_handle,const uint buffer_num,const uint index); double GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index); //--- (1) Copies data of the specified calculation part buffer of the indicator by handle into the indicator buffer, taking into account chart symbol/period, //--- (2) returns the amount of data in the specified buffer of the indicator by handle bool DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const int limit,double &buffer[]); uint DataTotal(const int ind_handle,const uint buffer_num) const; //--- Returns (1) buffer description, (2) state of the line data of given buffer of indicator specified by handle on the specified bar //--- (3) indicator line state for the specific chart symbol/period, (4) indicator line state relation to the specified level, //--- (5) state of relation of indicator line with specified level for certain chart symbol/period, (6) indicator category description string BufferDescription(const int ind_handle,const uint buffer_num); ENUM_LINE_STATE BufferLineState(const int ind_handle,const uint buffer_num,const int index); ENUM_LINE_STATE BufferLineState(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const uint buffer_num,const int index); ENUM_LINE_STATE BufferLineStateRelative(const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); ENUM_LINE_STATE BufferLineStateRelative(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE); string CategoryDescription(const int ind_handle); //--- Sets (1) identifier, (2) Digits, (3) user description, (4) buffer description void SetID(const int ind_handle,const int id); void SetDigits(const int ind_handle,const int digits); void SetDescription(const int ind_handle,const string descr); void SetBufferDescription(const int ind_handle,const uint buffer_num,const string descr); //--- Returns flag of whether the buffer is set as series, (2) historical data for symbol/period is synchronized bool IsSeries(const int ind_handle,const uint buffer_num) const; bool IsSynchronized(const int ind_handle) const; //--- Returns (1) timeframe, (2) symbol, (3) name, (4) list of parameters, (5) handle, (6) Digits //--- number of (7) buffers, (8) bars, (9) identifier, (10) description, (11) title, (12) category, //--- (13) number of parameters, (14) program type, description of (15) category, (16) indicator buffer ENUM_TIMEFRAMES Timeframe(const int ind_handle) const; string Symbol(const int ind_handle) const; string Name(const int ind_handle) const; string Parameters(const int ind_handle) const; int Digits(const int ind_handle) const; uint BuffersTotal(const int ind_handle) const; uint RatesTotal(const int ind_handle) const; int ID(const int ind_handle) const; string Description(const int ind_handle) const; string Title(const int ind_handle) const; ENUM_IND_CATEGORY Category(const int ind_handle) const; uint ParamsTotal(const int ind_handle) const; //--- Returns (1) structure of parameters by index from array, (2) timeframe description MqlParam GetMqlParam(const int ind_handle,const int index) const; string TimeframeDescription(const int ind_handle) const; //--- Returns amount of calculated data int Calculated(const int ind_handle) const; //--- Virtual method returning the type of object (indicator) ENUM_INDICATOR Type(const int ind_handle) const; //--- Methods for adding indicators to the collection int AddNewAC(const string symbol,const ENUM_TIMEFRAMES timeframe); int AddNewAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14); int AddNewADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14); int AddNewAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe,const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN); int AddNewAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ama_period=9, const int fast_ma_period=2, const int slow_ma_period=30, const int ama_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewAO(const string symbol,const ENUM_TIMEFRAMES timeframe); int AddNewATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14); int AddNewBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13); int AddNewBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13); int AddNewBands(const string symbol,const ENUM_TIMEFRAMES timeframe,const int bands_period=20, const int bands_shift=0, const double deviation=2.0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewCCI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_TYPICAL); int AddNewChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe,const int fast_ma_period=3, const int slow_ma_period=10, const ENUM_MA_METHOD ma_method=MODE_EMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14); int AddNewEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE, const double deviation=0.1); int AddNewForce(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewFractals(const string symbol,const ENUM_TIMEFRAMES timeframe); int AddNewFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewGator(const string symbol,const ENUM_TIMEFRAMES timeframe,const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN); int AddNewIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe,const int tenkan_sen=9, const int kijun_sen=26, const int senkou_span_b=52); int AddNewBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe,const int mom_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=10, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewMACD(const string symbol,const ENUM_TIMEFRAMES timeframe,const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewSAR(const string symbol,const ENUM_TIMEFRAMES timeframe,const double step=0.02, const double maximum=0.2); int AddNewRSI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=10); int AddNewStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=20, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe,const int Kperiod=5, const int Dperiod=3, const int slowing=3, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_STO_PRICE price_field=STO_LOWHIGH); int AddNewTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const int ma_shif=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewTriX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period=14); int AddNewVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe,const int cmo_period=9, const int ema_period=12, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE); int AddNewVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK); int AddNewCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,const string path, // path to the indicator (for example, "Examples\\MACD.ex5") const string name, // name of custom indicator (for example, "Custom MACD") const uint buffers, // number of buffers const MqlParam ¶m[]);// array of parameters //--- Timer void OnTimer(void) { //--- In a loop through all indicators form the collection int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- get a pointer to the next indicator object //--- and call its timer CIndMSTF *obj=this.m_list.At(i); if(obj!=NULL) obj.OnTimer(); } } //--- Constructor/destructor CMSTFIndicators(void){ this.m_list.Clear(); } ~CMSTFIndicators(void){;} };
操作列表中指标的方法的实现:
//+------------------------------------------------------------------+ //| Creates indicator calculation part for the passed object | //+------------------------------------------------------------------+ bool CMSTFIndicators::CreateIndicator(CIndMSTF *ind_obj) { //--- If the calculation part of the indicator could not be created if(!ind_obj.CreateIndicator()) { //--- look for the index of the indicator object in the collection list //--- using the index, delete the indicator object from the collection list this.m_list.Sort(); int index=this.m_list.Search(ind_obj); this.m_list.Delete(index); //--- Return false return false; } //--- The calculation part has been successfully created - return true return true; } //+------------------------------------------------------------------+ //| Returns indicator object by the calculation part handle | //+------------------------------------------------------------------+ CIndMSTF *CMSTFIndicators::GetIndicatorObj(const int ind_handle,const string source) const { //--- If an invalid handle is passed to the method, report this and return NULL if(ind_handle==INVALID_HANDLE) { ::PrintFormat("%s: Error handle",source); return NULL; } //--- In a loop through all indicator objects in the collection list int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- get a pointer to the next indicator object CIndMSTF *obj=this.m_list.At(i); if(obj==NULL) continue; //--- If the indicator handle is equal to that passed to the method - //--- return a pointer to the found indicator object if(obj.Handle()==ind_handle) return obj; } //--- Nothing is found - return NULL return NULL; } //+------------------------------------------------------------------+ //| Populate buffers of the indicator at the handle | //+------------------------------------------------------------------+ bool CMSTFIndicators::Calculate(const int ind_handle) { //--- Get a pointer to an indicator object using the handle CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) return false; //--- Return the result of the Calculate method obtained from the handle of the indicator object return obj.Calculate(); } //+------------------------------------------------------------------+ //| Populate buffers of all indicators in the collection | //+------------------------------------------------------------------+ bool CMSTFIndicators::Calculate(void) { //--- Declare the variable for storing the result bool res=true; //--- In a loop through all indicator objects in the collection list int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- get a pointer to the next indicator object CIndMSTF *obj=this.m_list.At(i); if(obj==NULL) continue; //--- Add to the 'res' variable the result of calling the Calculate method of the next indicator object res &=obj.Calculate(); //--- If the method worked with an error, inform that in the journal if(!res) ::PrintFormat("%s::%s: Error in indicator calculation: %s",__FUNCTION__,obj.Title(),TypeErrorcDescription(obj.TypeError())); } //--- If the overall result is false, inform of that in the journal if(!res) ::PrintFormat("%s: Not all indicators have been calculated successfully. It is necessary to recalculate the buffers of all indicators",__FUNCTION__); //--- Return the result of calling the Calculate methods of all indicators in the collection return res; } //+------------------------------------------------------------------+ //| Returns data of the indicator at the handle | //| from the specified buffers by index as is | //+------------------------------------------------------------------+ double CMSTFIndicators::GetData(const int ind_handle,const uint buffer_num,const uint index) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Return data from the specified indicator buffer at the index passed to the method return obj.GetData(buffer_num,index); } //+------------------------------------------------------------------+ //| Returns data of the indicator at the handle | //| from the specified buffer at index for this symbol/timeframe | //+------------------------------------------------------------------+ double CMSTFIndicators::GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Return data from the specified indicator buffer at the index passed to the method return obj.GetDataTo(symbol_to,timeframe_to,buffer_num,index); } //+------------------------------------------------------------------+ //| Fills the passed indicator buffer with data | //+------------------------------------------------------------------+ bool CMSTFIndicators::DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const int limit,double &buffer[]) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Fill the buffer array passed to the method from the specified indicator buffer return obj.DataToBuffer(symbol_to,timeframe_to,buffer_num,limit,buffer); } //+------------------------------------------------------------------+ //| Set the specified description for the buffer line | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotLabel(const uint plot_index,const string descript) { ::PlotIndexSetString(plot_index,PLOT_LABEL,descript); } //+------------------------------------------------------------------+ //| Set default description for the buffer line | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotLabelFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Set the description of the specified indicator buffer to the specified plotting buffer ::PlotIndexSetString(plot_index,PLOT_LABEL,obj.BufferDescription(buffer_num)); } //+------------------------------------------------------------------+ //| Set the shift for the specified plotting buffer | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotShift(const uint plot_index,const int shift) { ::PlotIndexSetInteger(plot_index,PLOT_SHIFT,shift); } //+------------------------------------------------------------------+ //| Return the description of the given buffer | //| of the indicator specified by handle | //+------------------------------------------------------------------+ string CMSTFIndicators::BufferDescription(const int ind_handle,const uint buffer_num) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If pointer to object received, return description of the specified buffer from it. Otherwise error text return(obj!=NULL ? obj.BufferDescription(buffer_num) : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Set the initializing value for the specified buffer | //| of the indicator specified by handle | //+------------------------------------------------------------------+ void CMSTFIndicators::SetBufferInitValue(const int ind_handle,const uint buffer_num,const double value) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Set the specified initializing "empty" value for the specified buffer obj.SetBufferInitValue(buffer_num,value); } //+------------------------------------------------------------------+ //| Return the initialization value of the specified buffer | //| of the indicator specified by handle | //+------------------------------------------------------------------+ double CMSTFIndicators::BufferInitValue(const int ind_handle,const uint buffer_num) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Return the initializing "empty" value set for the specified buffer return obj.BufferInitValue(buffer_num); } //+------------------------------------------------------------------+ //| Returns the line data state of the given buffer | //| specified by indicator handle at the specified bar | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineState(const int ind_handle,const uint buffer_num,const int index) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Return the state of the line of the specified buffer at the specified index return obj.BufferLineState(buffer_num,index); } //+------------------------------------------------------------------+ //| Returns the line data state of the given buffer | //| specified by indicator handle at the symbol/timeframe bar | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineState(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const uint buffer_num,const int index) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Get the time of the passed to the method datetime array[1]; if(::CopyTime(symbol,timeframe,index,1,array)!=1) { ::PrintFormat("%s::%s: Failed to get the time of the bar with index %ld. Error %lu",__FUNCTION__,obj.Title(),index,::GetLastError()); return LINE_STATE_NONE; } //--- Get the bar index in the indicator object buffer corresponding to the found time int bar=::iBarShift(obj.Symbol(),obj.Timeframe(),array[0]); //--- If a bar is found, return the line state on the found bar, otherwise an undefined state return(bar!=WRONG_VALUE ? obj.BufferLineState(buffer_num,bar) : LINE_STATE_NONE); } //+------------------------------------------------------------------+ //| Return the line data ratio for the given buffer | //| specified by indicator handle at the specified bar | //| with specified valiues | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineStateRelative(const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Return the ratio of the indicator line and the level in the specified buffer at the specified index return obj.BufferLineStateRelative(buffer_num,index,level0,level1); } //+------------------------------------------------------------------+ //| Return the line data ratio for the given buffer | //| specified by indicator handle at the specified bar | //| with the specified values on the specified chart symbol/period | //+------------------------------------------------------------------+ ENUM_LINE_STATE CMSTFIndicators::BufferLineStateRelative(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const int buffer_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return LINE_STATE_NONE; } //--- Return the ratio of the indicator line and the level in the specified buffer at the specified index return obj.BufferLineStateRelative(symbol,timeframe,buffer_num,index,level0,level1); } //+------------------------------------------------------------------+ //| Return category description | //+------------------------------------------------------------------+ string CMSTFIndicators::CategoryDescription(const int ind_handle) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return the description of the category Otherwise error text return(obj!=NULL ? obj.CategoryDescription() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Set identifier | //+------------------------------------------------------------------+ void CMSTFIndicators::SetID(const int ind_handle,const int id) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Set the identifier for the received object obj.SetID(id); } //+------------------------------------------------------------------+ //| Set Digits of the indicator | //+------------------------------------------------------------------+ void CMSTFIndicators::SetDigits(const int ind_handle,const int digits) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Set Digits for the received object obj.SetDigits(digits); } //+------------------------------------------------------------------+ //| Set a custom description | //+------------------------------------------------------------------+ void CMSTFIndicators::SetDescription(const int ind_handle,const string descr) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Set a description for the received object obj.SetDescription(descr); } //+------------------------------------------------------------------+ //| Set a description of the specified buffer | //+------------------------------------------------------------------+ void CMSTFIndicators::SetBufferDescription(const int ind_handle,const uint buffer_num,const string descr) { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Set a description for the specified buffer of the received object obj.SetBufferDescription(buffer_num,descr); } //+------------------------------------------------------------------+ //| Returns the timeseries flag of the given buffer | //+------------------------------------------------------------------+ bool CMSTFIndicators::IsSeries(const int ind_handle,const uint buffer_num) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Return the timeseries flag of the specified buffer of the received object return obj.IsSeries(buffer_num); } //+------------------------------------------------------------------+ //| Returns the synchronization flag for | //| historical data for the symbol/period | //+------------------------------------------------------------------+ bool CMSTFIndicators::IsSynchronized(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Return the synchronization flag of the received object return obj.IsSynchronized(); } //+------------------------------------------------------------------+ //| Return the timeframe of the specified indicator | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES CMSTFIndicators::Timeframe(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Return the timeframe of the received object return obj.Timeframe(); } //+------------------------------------------------------------------+ //| Returns the symbol of the specified indicator | //+------------------------------------------------------------------+ string CMSTFIndicators::Symbol(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return the name of the symbol Otherwise error text return(obj!=NULL ? obj.Symbol() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Return the name of the specified indicator | //+------------------------------------------------------------------+ string CMSTFIndicators::Name(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return the name of the indicator Otherwise error text return(obj!=NULL ? obj.Name() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Returns a list of parameters of the specified indicator | //+------------------------------------------------------------------+ string CMSTFIndicators::Parameters(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return a list of indicator parameters Otherwise error text return(obj!=NULL ? obj.Parameters() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Return Digits of the specified indicator | //+------------------------------------------------------------------+ int CMSTFIndicators::Digits(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Return Digits of the received object return obj.Digits(); } //+------------------------------------------------------------------+ //| Return the number of buffers of the specified indicator | //+------------------------------------------------------------------+ uint CMSTFIndicators::BuffersTotal(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return 0; } //--- Return the number of buffers of the received object return obj.BuffersTotal(); } //+------------------------------------------------------------------+ //| Return the number of timeseries bars for specified the indicator | //+------------------------------------------------------------------+ uint CMSTFIndicators::RatesTotal(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return 0; } //--- Return the number of bars in the timeseries of the received object return obj.RatesTotal(); } //+------------------------------------------------------------------+ //| Return the identifier of the specified indicator | //+------------------------------------------------------------------+ int CMSTFIndicators::ID(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Return the identifier of the received object return obj.ID(); } //+------------------------------------------------------------------+ //| Return a description of the specified indicator | //+------------------------------------------------------------------+ string CMSTFIndicators::Description(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return the indicator description Otherwise error text return(obj!=NULL ? obj.Description() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Return the title of the specified indicator | //+------------------------------------------------------------------+ string CMSTFIndicators::Title(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return the indicator title Otherwise error text return(obj!=NULL ? obj.Title() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Return the category of the specified indicator | //+------------------------------------------------------------------+ ENUM_IND_CATEGORY CMSTFIndicators::Category(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return IND_CATEGORY_NONE; } //--- Return the category of the received object return obj.Category(); } //+------------------------------------------------------------------+ //| Return the number of parameters of the specified indicator | //+------------------------------------------------------------------+ uint CMSTFIndicators::ParamsTotal(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return 0; } //--- Return the number of parameters of the received object return obj.ParamsTotal(); } //+------------------------------------------------------------------+ //| Return the structure of parameters by index from the array | //| for the specified indicator | //+------------------------------------------------------------------+ MqlParam CMSTFIndicators::GetMqlParam(const int ind_handle,const int index) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); MqlParam null; ::ZeroMemory(null); return null; } //--- Return the structure of parameters of the received object by index from the array of parameters return obj.GetMqlParam(index); } //+------------------------------------------------------------------+ //| Return a timeframe description for the specified indicator | //+------------------------------------------------------------------+ string CMSTFIndicators::TimeframeDescription(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); //--- If the object is received, return a description of the indicator timeframe Otherwise error text return(obj!=NULL ? obj.Description() : ::StringFormat("%s: Failed to get indicator object",__FUNCTION__)); } //+------------------------------------------------------------------+ //| Return the amount of calculated data of the specified indicator | //+------------------------------------------------------------------+ int CMSTFIndicators::Calculated(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Return the amount of calculated data of the received object return obj.Calculated(); } //+------------------------------------------------------------------+ //| Return the type of the specified indicator | //+------------------------------------------------------------------+ ENUM_INDICATOR CMSTFIndicators::Type(const int ind_handle) const { //--- Get a pointer to the indicator object using the handle passed to the method CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return (ENUM_INDICATOR)WRONG_VALUE; } //--- Return the indicator type of the received object return (ENUM_INDICATOR)obj.Type(); }
所有方法的逻辑都在方法列表中进行了注释。首先,我们获取一个指向列表中所需指标的指针,然后设置或返回其属性,或者执行计算并返回结果。以上所有调用的方法都在讨论多交易品种、多周期指标的基类时讨论了。
创建新指标对象的方法的实现:
//+------------------------------------------------------------------+ //| Add the specified indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewIndicator(CIndMSTF *ind_obj,const string source) { //--- Set the sorted list flag to the collection list this.m_list.Sort(); //--- Search the list for an index matching the indicator object passed to the method int index=this.m_list.Search(ind_obj); //--- If such an indicator with the same parameters is already in the list, if(index>WRONG_VALUE) { //--- report this to journal and delete the new indicator object ::PrintFormat("%s: The %s indicator with such parameters %s is already in the collection",source,ind_obj.Name(),ind_obj.Parameters()); delete ind_obj; //--- Get a pointer to an already existing indicator object in the list and return its handle ind_obj=this.m_list.At(index); return(ind_obj!=NULL ? ind_obj.Handle() : INVALID_HANDLE); } //--- If such an indicator is not in the list, but it could not be placed in the list if(!this.m_list.Add(ind_obj)) { //--- report the error in the journal, delete the indicator object and return INVALID_HANDLE ::PrintFormat("%s: Error. Failed to add %s indicator to collection",source,ind_obj.Name()); delete ind_obj; return INVALID_HANDLE; } //--- If indicator is placed in list, but creating a calculation part for it failed, return INVALID_HANDLE //--- (if there is an error creating a calculation part, the indicator object is deleted in the CreateIndicator method) if(!this.CreateIndicator(ind_obj)) return INVALID_HANDLE; //--- Successful - inform about addition of a new indicator to collection and return its handle ::PrintFormat("%s: %s indicator (handle %ld) added to the collection",source,ind_obj.Title(),ind_obj.Handle()); return ind_obj.Handle(); } //+------------------------------------------------------------------+ //| Add the Accelerator Oscillator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAC(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndAC *ind_obj=new CIndAC(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AC indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Accumulation/Distribution indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndAD *ind_obj=new CIndAD(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create A/D indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+--------------------------------------------------------------------+ //| Add Average Directional Movement Index to the collection | //+--------------------------------------------------------------------+ int CMSTFIndicators::AddNewADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndADX *ind_obj=new CIndADX(symbol,timeframe,adx_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create ADX indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add to the collection the indicator | //| Average Directional Movement Index by Welles Wilder | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period=14) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndADXW *ind_obj=new CIndADXW(symbol,timeframe,adx_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create ADX Wilder indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Alligator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndAlligator *ind_obj=new CIndAlligator(symbol,timeframe,jaw_period,jaw_shift,teeth_period,teeth_shift,lips_period,lips_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Alligator indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Adaptive Moving Average indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ama_period=9, const int fast_ma_period=2, const int slow_ma_period=30, const int ama_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndAMA *ind_obj=new CIndAMA(symbol,timeframe,ama_period,fast_ma_period,slow_ma_period,ama_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Awesome Oscillator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAO(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndAO *ind_obj=new CIndAO(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AO indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Average True Range indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndATR *ind_obj=new CIndATR(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create ATR indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Bears Power indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndBears *ind_obj=new CIndBears(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Bears indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Bulls Power indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=13) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndBulls *ind_obj=new CIndBulls(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Bulls indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Bollinger Bands® indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBands(const string symbol,const ENUM_TIMEFRAMES timeframe, const int bands_period=20, const int bands_shift=0, const double deviation=2.0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndBands *ind_obj=new CIndBands(symbol,timeframe,bands_period,bands_shift,deviation,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Bands indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Commodity Channel Index indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_TYPICAL) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndCCI *ind_obj=new CIndCCI(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create CCI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Chaikin Oscillator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ma_period=3, const int slow_ma_period=10, const ENUM_MA_METHOD ma_method=MODE_EMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndCHO *ind_obj=new CIndCHO(symbol,timeframe,fast_ma_period,slow_ma_period,ma_method,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Chaikin indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+-------------------------------------------------------------------+ //| Add Double Exponential Moving Average to the collection | //+-------------------------------------------------------------------+ int CMSTFIndicators::AddNewDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndDEMA *ind_obj=new CIndDEMA(symbol,timeframe,ma_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create DEMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the DeMarker indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=14) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndDeM *ind_obj=new CIndDeM(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create DeMarker indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Envelopes indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE, const double deviation=0.1) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndEnvelopes *ind_obj=new CIndEnvelopes(symbol,timeframe,ma_method,ma_shift,ma_method,applied_price,deviation); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Envelopes indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Force Index indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewForce(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=13, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndForce *ind_obj=new CIndForce(symbol,timeframe,ma_period,ma_method,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Force indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Fractals indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewFractals(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndFractals *ind_obj=new CIndFractals(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Fractals indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Fractal Adaptive Moving Average indicator to collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndFrAMA *ind_obj=new CIndFrAMA(symbol,timeframe,ma_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create FrAMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Gator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period=13, const int jaw_shift=8, const int teeth_period=8, const int teeth_shift=5, const int lips_period=5, const int lips_shift=3, const ENUM_MA_METHOD ma_method=MODE_SMMA, const ENUM_APPLIED_PRICE applied_price=PRICE_MEDIAN) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndGator *ind_obj=new CIndGator(symbol,timeframe,jaw_period,jaw_shift,teeth_period,teeth_shift,lips_period,lips_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Gator indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Ichimoku Kinko Hyo indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen=9, const int kijun_sen=26, const int senkou_span_b=52) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndIchimoku *ind_obj=new CIndIchimoku(symbol,timeframe,tenkan_sen,kijun_sen,senkou_span_b); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Ichimoku indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Market Facilitation Index indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndBWMFI *ind_obj=new CIndBWMFI(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create BW MFI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Momentum indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe, const int mom_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndMomentum *ind_obj=new CIndMomentum(symbol,timeframe,mom_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Momentum indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Money Flow Index indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndMFI *ind_obj=new CIndMFI(symbol,timeframe,ma_period,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create MFI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Moving Average indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=10, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndMA *ind_obj=new CIndMA(symbol,timeframe,ma_period,ma_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create MA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Moving Average of Oscillator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndOsMA *ind_obj=new CIndOsMA(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create OsMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add to the collection the indicator | //| Moving Averages Convergence/Divergence | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewMACD(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period=12, const int slow_ema_period=26, const int signal_period=9, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndMACD *ind_obj=new CIndMACD(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create MACD indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the On Balance Volume indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndOBV *ind_obj=new CIndOBV(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create OBV indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+-------------------------------------------------------------------+ //| Add Parabolic Stop and Reverse system to the collection | //+-------------------------------------------------------------------+ int CMSTFIndicators::AddNewSAR(const string symbol,const ENUM_TIMEFRAMES timeframe, const double step=0.02, const double maximum=0.2) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndSAR *ind_obj=new CIndSAR(symbol,timeframe,step,maximum); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create SAR indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Relative Strength Index indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewRSI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndRSI *ind_obj=new CIndRSI(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create RSI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Relative Vigor Index indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period=10) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndRVI *ind_obj=new CIndRVI(symbol,timeframe,ma_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create RVI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Standard Deviation indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=20, const int ma_shift=0, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndStdDev *ind_obj=new CIndStdDev(symbol,timeframe,ma_period,ma_shift,ma_method,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create StdDev indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Stochastic Oscillator indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe, const int Kperiod=5, const int Dperiod=3, const int slowing=3, const ENUM_MA_METHOD ma_method=MODE_SMA, const ENUM_STO_PRICE price_field=STO_LOWHIGH) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndStoch *ind_obj=new CIndStoch(symbol,timeframe,Kperiod,Dperiod,slowing,ma_method,price_field); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Stochastic indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+-------------------------------------------------------------------+ //| Add Triple Exponential Moving Average indicator to the collection | //+-------------------------------------------------------------------+ int CMSTFIndicators::AddNewTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndTEMA *ind_obj=new CIndTEMA(symbol,timeframe,ma_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create TEMA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add to the collection the indicator | //| Triple Exponential Moving Averages Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewTriX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndTriX *ind_obj=new CIndTriX(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create TriX indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add Larry Williams' Percent Range to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period=14) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndWPR *ind_obj=new CIndWPR(symbol,timeframe,calc_period); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create WPR indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add Variable Index Dynamic Average to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int cmo_period=9, const int ema_period=12, const int ma_shift=0, const ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndVIDyA *ind_obj=new CIndVIDyA(symbol,timeframe,cmo_period,ema_period,ma_shift,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create VIDyA indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add the Volumes indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume=VOLUME_TICK) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndVolumes *ind_obj=new CIndVolumes(symbol,timeframe,applied_volume); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create Volumes indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); } //+------------------------------------------------------------------+ //| Add a custom indicator to the collection | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,const string path,const string name,const uint buffers,const MqlParam ¶m[]) { //--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE CIndCustom *ind_obj=new CIndCustom(symbol,timeframe,path,name,buffers,param); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create %s custom indicator object",__FUNCTION__,name); return INVALID_HANDLE; } //--- Return the result of adding the created indicator object to the collection list return this.AddNewIndicator(ind_obj,__FUNCTION__); }
指标集合类的所有代码都已准备就绪。每个方法都提供了描述其逻辑的注释,以便它们易于理解。
测试
要测试多指标的类及其集合,让我们创建一个简单的指标。该指标将从几个移动平均线中选出一个。这些测试的目的是检查具有指标的类的操作,这些指标从主图表窗口中的一个缓冲区中绘制一条线。此目的最好使用来自客户端终端中的趋势指标集合的移动平均值来实现。在接下来的文章中,我们将创建模板,用于快速创建和使用终端中提供的标准集中的任何指标+使用自定义指标。渐渐地,我们将完全完成今天创建的类,以便正确使用任何类型的指标。
测试指标将在图表上绘制创建的多个指标的线条。相关数据将显示在仪表板上。该仪表板的创建在本系列的第一篇文章中进行了描述。
我们将在一个指标中创建两个相同的指标。其中一个将使用当前图表数据进行计算,第二个将使用在设置中选择的交易品种/周期的数据进行计算。这样,我们将始终看到当前图表上的移动平均线和使用不同图表周期的数据创建的同样的移动平均线。可以从另一个图表中选择一个交易品种,但线条将与价格水平不匹配。
创建一个名为TestMSTFMovingAverages.mq5的新指标文件:
选择OnTimer和OnChartEvent处理函数:
在主图表窗口中选择要绘制为线条的两个缓冲区:
您可以使用任何缓冲区名称,因为它们将在代码中重命名。点击“完成”,获得一个指标模板:
//+------------------------------------------------------------------+ //| TestMSTFMovingAverages.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 //--- plot MA1 #property indicator_label1 "MA1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot MA2 #property indicator_label2 "MA2" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- indicator buffers double MA1Buffer[]; double MA2Buffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,MA1Buffer,INDICATOR_DATA); SetIndexBuffer(1,MA2Buffer,INDICATOR_DATA); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- //--- return value of prev_calculated for the next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- }
在全局区域中,添加一个枚举以选择移动平均线的类型,连接多交易品种多周期指标类文件和仪表板类文件,并且声明输入变量。
重命名缓冲区以提供更有意义的表示,并声明全局指标变量:
//+------------------------------------------------------------------+ //| TestMSTFMovingAverages.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 //--- enums enum ENUM_USED_MA { USED_MA_AMA = IND_AMA, // Adaptive Moving Average USED_MA_DEMA = IND_DEMA, // Double Exponential Moving Average USED_MA_FRAMA = IND_FRAMA, // Fractal Adaptive Moving Average USED_MA_MA = IND_MA, // Moving Average USED_MA_TEMA = IND_TEMA, // Triple Exponential Moving Average USED_MA_VIDYA = IND_VIDYA, // Variable Index Dynamic Average }; //--- plot MA1 #property indicator_label1 "MA1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot MA2 #property indicator_label2 "MA2" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input ENUM_USED_MA InpIndicator = USED_MA_MA; /* Used MA */ // Type of moving average to use input string InpSymbol = NULL; /* Symbol */ // Moving average symbol input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Moving average timeframe input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ // Price used for calculations input ENUM_MA_METHOD InpMethod = MODE_SMA; /* MA Method */ // Moving Average calculation method input int InpShift = 0; /* MA Shift */ // Moving average shift input bool InpAsSeries = true; /* As Series flag */ // Timeseries flag of indicator buffer arrays //--- indicator buffers double BufferMA1[]; double BufferMA2[]; //--- global variables int handle_ma1; int handle_ma2; CMSTFIndicators indicators; // An instance of the indicator collection object //--- variables for the panel CDashboard *panel=NULL; // Pointer to the panel object int mouse_bar_index; // Index of the bar the data is taken from
在OnInit()处理函数中,输入计时器的创建,分配绘图缓冲区,为所选指标创建句柄,并创建仪表板:
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Set a timer with an interval of 1 second EventSetTimer(1); //--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively SetIndexBuffer(0,BufferMA1,INDICATOR_DATA); SetIndexBuffer(1,BufferMA2,INDICATOR_DATA); //--- sets indicator shift //PlotIndexSetInteger(0,PLOT_SHIFT,InpShift); // analog in line 116 //PlotIndexSetInteger(1,PLOT_SHIFT,InpShift); // analog in line 117 //--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference) ArraySetAsSeries(BufferMA1,InpAsSeries); ArraySetAsSeries(BufferMA2,InpAsSeries); //--- For different indicators, the dashboard width will be individual (due to the number of parameters in the description) int width=0; //--- According on the indicator selected in the settings, create two indicators of the same type //--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings switch(InpIndicator) { case USED_MA_AMA : handle_ma1=indicators.AddNewAMA(NULL,PERIOD_CURRENT,9,2,30,InpShift); handle_ma2=indicators.AddNewAMA(InpSymbol,InpTimeframe,9,2,30,InpShift); width=269; break; case USED_MA_DEMA : handle_ma1=indicators.AddNewDEMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice); handle_ma2=indicators.AddNewDEMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice); width=255; break; case USED_MA_FRAMA : handle_ma1=indicators.AddNewFrAMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice); handle_ma2=indicators.AddNewFrAMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice); width=259; break; case USED_MA_TEMA : handle_ma1=indicators.AddNewTEMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice); handle_ma2=indicators.AddNewTEMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice); width=253; break; case USED_MA_VIDYA : handle_ma1=indicators.AddNewVIDyA(NULL,PERIOD_CURRENT,9,12,InpShift,InpPrice); handle_ma2=indicators.AddNewVIDyA(InpSymbol,InpTimeframe,9,12,InpShift,InpPrice); width=267; break; default: handle_ma1=indicators.AddNewMA(NULL,PERIOD_CURRENT,10,InpShift,InpMethod,InpPrice); handle_ma2=indicators.AddNewMA(InpSymbol,InpTimeframe,10,InpShift,InpMethod,InpPrice); width=231; break; } //--- If failed to create indicator handles, return initialization error if(handle_ma1==INVALID_HANDLE || handle_ma2==INVALID_HANDLE) return INIT_FAILED; //--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators indicators.SetPlotLabelFromBuffer(0,handle_ma1,0); indicators.SetPlotLabelFromBuffer(1,handle_ma2,0); //--- Set "empty" values for calculation part buffers of the created indicators indicators.SetBufferInitValue(handle_ma1,0,EMPTY_VALUE); indicators.SetBufferInitValue(handle_ma2,0,EMPTY_VALUE); //--- Set shifts for indicator lines indicators.SetPlotShift(0,InpShift); indicators.SetPlotShift(1,InpShift); //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,width,264); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the dashboard background panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Create a table with ID 1 to display the data of indicator 1 panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the dashboard background panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Create a table with ID 2 to display the data of indicator 2 panel.CreateNewTable(2); //--- Get the Y2 coordinate of the table with ID 1 and //--- set the Y1 coordinate for the table with ID 2 int y2=panel.TableY2(1)+3; //--- Draw a table with ID 2 on the background of the dashboard panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the dashboard DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
添加OnDeinit()处理函数:
//+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Delete the timer EventKillTimer(); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; //--- Delete all comments Comment(""); }
在OnCalculate()处理函数中,调用所有多交易品种多周期指标的计算。如果计算失败,请退出处理函数并返回零以在下一个分时重新计算指标。
计算成功后,指标对象的数组缓冲区中的数据已经存在,并且可以显示在仪表板中。在仪表板上显示数据后,将数据从计算的缓冲区输出到指标的绘图缓冲区:
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- Number of bars for calculation int limit=rates_total-prev_calculated; //--- If limit > 1, then this is the first calculation or change in the history if(limit>1) { //--- specify all the available history for calculation limit=rates_total-1; /* // If the indicator has any buffers that display other calculations (not multi-indicators), // initialize them here with the "empty" value set for these buffers */ } //--- Calculate all created multi-symbol multi-period indicators if(!indicators.Calculate()) return 0; //--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard DrawData(mouse_bar_index,time[mouse_bar_index]); //--- From buffers of calculated indicators, output data to indicator buffers if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ma1,0,limit,BufferMA1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ma2,0,limit,BufferMA2)) return 0; //--- return value of prev_calculated for the next call return(rates_total); }
在指标计时器中,调用指标集合对象的计时器:
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Call the indicator collection timer indicators.OnTimer(); }
在OnChartEvent()处理函数中,调用仪表板对象事件处理函数并处理光标移动以确定其所在的柱:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
在仪表板上显示多指标数据的函数:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to dashboard | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlRates rates[1]; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Output the data of indicator 1 from the specified bar into table 1 panel.DrawText(indicators.Title(handle_ma1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_ma1,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ma1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110); //--- Display a description of the indicator 1 line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ma1,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110); //--- Output the data of indicator 2 from the specified bar into table 2 panel.DrawText(indicators.Title(handle_ma2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ma2,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ma2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110); //--- Display a description of the indicator 2 line state panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ma2,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110); //--- Display description of relationship between indicator 1 line relative to indicator 2 line double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ma2,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_ma1,0,index,value2,value21); string ma1=indicators.Name(handle_ma1); string ma2=indicators.Name(handle_ma2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
正如您所看到的,我们可以通过简单地调用指标集合类的 Calculate()方法来计算多交易品种、多周期的指标。计算成功后,所有数据都已可用。这些数据可以从 EA 交易中访问和处理。在指标中,计算成功后,可以使用指标集合类的 DataToBuffer()方法将数据以线的形式显示在图表上。这就是计算和在图表上显示多个指标所需的全部内容。
编译测试指标后,我们将在周期为M1的图表上启动它,在设置中我们将选择指标M5的当前交易品种和计算周期。在这种情况下,将创建在指标设置中选择的两个移动平均线。其中一个将使用当前图表数据进行计算,第二个将基于五分钟图表周期的数据。通过切换图表时间框架,您可以看到M1上画了两条线:一条线对应M1上计算的移动平均线,第二条线对应M5上计算的移动平均线。如果将图表切换到M5,则只会创建一个指标,因为第二个指标与第一个指标相同,并且不会创建。如果将图表切换到M15,则将为M15计算一个指标,为M5计算第二个指标,并且该指标也将显示在图表上。
正如您所看到的,声明的功能是有效的,我们可以在主图表窗口中看到指标。可以使用一个缓冲区创建多个指标。
附件中提供了所有类的文件和测试指标。
结论
今天,我们已经创建了快速创建多交易品种多周期指标、接收指标中的数据以及在主图表窗口中绘制计算指标的功能。在下面的文章中,我们将创建用于创建其他多交易品种、多周期标准指标的模板,这些指标在主图表窗口中绘制数据,而不仅仅是使用一个缓冲区。因此,我们将获得一个方便的工具,可以快速将任何指标转换为多交易品种、多周期版本。随着我们将创建其他标准和自定义指标,多指标类可能会得到进一步发展。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/13578