
山型或冰山型图表
概述
您如何看待往 MetaTrader 5 平台里添加新图表类型的想法? 有人说它缺少其它平台里提供的一些东西。 但事实是,MetaTrader 5 是一个非常实用的平台,因为它允许您做到在许多其它平台上无法完成(或至少不能轻松完成)的事情。
最常见的抱怨之一是 MetaTrader 5 中只有三种图表类型:蜡烛、柱线和折线。 真的是这样吗? 亦或因为有人尚不知道平台的实际工作原理,或 MQL5 语言提供了哪些可能性?
大多数情况下,抱怨的人大多是对平台了解较浅薄的人。 每个人都希望自己要用到的东西都已准备好,如果不能即刻就位,他们就开始抱怨。
在本文中 — 这次不会很长 — 我们将看到如何以不同但有用的样式创建图表。 它对于那些使用特定样式进行交易的人来说尤其有用,例如波段交易、仓位交易、甚至投资组合交易。
今天我们将看看山型或冰山型图表。 甚至,我们将更深入学习如何利用 MQL5 工作。 在本文中,我们将开发一个非常有趣的图表来有效地跟踪持仓:配合此图表,您无需再持续检查一笔交易的盈亏。 您可以简单地查看图表,就可判定您指定的持仓是盈利亦或亏损。
山型图与线性表示样式非常相似,但略有不同之处。 使用折线图(如图例 01 所示),我们所拥有的只是价格是上涨还是下跌的简单指示,仅此而已。 而山型图提供了更多的能力。 山型图如图例 02 所示。
图例 01 - 典型折线图
图例 02 - 典型山型图
图例 02 所示的图表是山型图中最常见的类型。 它有若干个变体,也许有不同的名称。 基本变体其一如图例03 所示。
图例 03 - 冰山型图多头持仓
图例 03 显示的图表类型非常易于阅读。 在这种特殊情况下,图例 03 所示的图表适用于多头持仓,但空头持仓大体相同。 这样的图表如图例 04 所示。
图例 04 - 空头持仓冰山型图
通过观察冰山图,您可以立即看出持仓是盈利亦或亏损。 图表以不同的颜色来指示交易状态(盈利/亏损)。 因此,只需简单地为山型地图涂上颜色,我们就可以实现一种不同的风格,对于那些刚开始研究行情的人来说,这种风格更容易阅读。 当您需要放置长线持仓时,它可能特别有用。
有趣的是,该系统非常简单,同时适应性很强,它不仅允许我们创建山型图或冰山型图,还可以创建更复杂的折线图,如图例 05 所示。
图例 05 - 分析持仓的折线图
线型可以更改,即它不必一定是实线。 例如,我们可以创建以下图表。
图例 06 - 分析多头持仓的折线图
您也许会想我们需要创建一些非常复杂的代码,这些代码非常难以执行或理解。 然而,我们即将创建的代码非常简单,且即便对于刚接触 MQL5 语言的人来说也很容易理解。 因此,对于那些想要更多地了解平台如何工作的人来说,这可能是一个很好的起点,之后就可继续创建更艰巨的东西。
我们的代码创建山型或冰山型图时,与 Heiken-Ashi 指标所做非常相似。 但与 Heiken-Ashi 不同的是,我们的图表系统将创建 100% 干净的图表,类似于上面显示的图表。 不会有任何额外的内容,包括 MetaTrader 5 中显示的标准默认图表。
甚而,创建自定义图表并不意味着我们无法在其上应用我们喜欢的指标:配合这种新的图表样式,您一样能够使用任何指标、智能系统、脚本、和其它任何东西,无需修改代码。 随着时间的推移,新生事情数量会增加,这真是太完美了。
现在,我们继续前进,看看如何在 MetaTrader 5 中实现新的图表系统。
实现
看看上面的图例。 图表的创建可以像什么样子,或者至少对于我们正在谈论的部分(如图例 05 和 06 所示)? 首先进入脑海的就是移动平均线。 图例 05 和 06 都显示的是移动平均线。 这与图例 01 非常相似,但由于某种原因,它具有不同的颜色。 其它形状呢?
图例 02、03 和 04 中图表的秘密是什么? 有没有办法在不重载 MetaTrader 5 平台的情况下实现相同的功能?
事实上,除图例 01(MetaTrader 5 平台中可用的默认折线图)之外,所有图表都是以移动平均线按类似的方式创建的。 甚至冰山图也是以相同的方式创建的。
若要理解这一点,请查看下面的代码。 它非常简单,以如下行开头:
#property copyright "Daniel Jose" #property icon "\\Images\\Icons\\Mountain Chart.ico" #property description "This indicator allows you to create a mountain chart" #property description "Whose average price can be indicated facilitating market analysis" #property version "1.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 1
在这一行中,我们定义系统图标的图像文件位置。 我们还指示,我们将在金融工具的主图表窗口中使用指标(嗯,是的,该图表将是一个指标)。
当前遇到的要点是:我们将用到两个缓冲区,但是(强调这个词)它们不会以您想象的方式使用,因此请注意该部分。 我们将绘制一个指标,再次,一切都与此处所示完全不符。
我们有三种可能的图表类型:多色折线图、冰山图和山型图。 因此,我们不在开头限定指示的信息。
接着遇到的是一些简单而必要的声明,来确保一切正常:
double Buff1[], Buff2[]; //+------------------------------------------------------------------+ enum eType {Fill, Contour}; //+------------------------------------------------------------------+ input double user01 = 0.0; //Analysis price input eType user02 = Fill; //Type of Mountain //+------------------------------------------------------------------+ struct st0 { long id; color CandleBear, CandleBull, CandleLine, LineUp, LineDown; }_memConfig;
在此,我们声明两个即将用到的缓冲区。 然后,创建一个枚举来帮助选择图表的类型:折线图、冰山图或山型图。 现在来到与用户交互相关的特别时刻。 我们来了解图表将如何显示,以及我们将在屏幕上看到哪种类型。 我们有以下组合:
图表类型 | 在 user01 里包含的值 | 在 user02 里包含的值 |
---|---|---|
单色折现图Single color line chart | 值为 0 | 指示轮廓值 |
多色折线图 | 价格阈值 | 指示轮廓值 |
山型图 | 值为 0 | 指示填充值 |
冰山图 | 价格水位线值 | 指示填充值 |
此表格将帮助您选择可在屏幕上显示的图表类型。
为了令一切更加清晰,在文章末尾,我加上了一个视频,演示每个设置和结果。 这令您更好地理解正在发生什么,因为仅通过观看代码可能很难理解某些内容。 请务必观看视频:它将帮助您了解所有可能的组合。 文章文字没有提供有关如何更改颜色的讲述,但视频显示了这一点。
不要担心结构,因为它仅是存储某些信息的存储器。
如此,我们已完成了这些。 我们移步图表系统中的第一个函数:
int OnInit() { IndicatorSetString(INDICATOR_SHORTNAME, "Mountain Chart"); Init_MountainChart(); return INIT_SUCCEEDED; }
此函数非常简单:指定指标的名称,并调用函数来运行图表。 我们可将被调用函数的内容放在这里,但我喜欢将事情分离,并保持代码井井有条。
下面是接着的函数:
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { for (int c0 = (prev_calculated == 0 ? 0 : prev_calculated - 1); c0 < rates_total; c0++) { Buff1[c0] = price[c0]; Buff2[c0] = (user02 == Fill ? user01 : (price[c0] > user01 ? 0 : 1)); } return rates_total; }
这是一个非常简单的函数,它真的应该非常简单,因为它将在每次跳价或每次价格变化时执行。 MetaTrader 5 将生成一个事件,结果就是调用 OnCalculate。 故此,该函数必须运行得非常迅捷。
为了避免每次函数调用时从一开始就重新计算整个数据序列,我们将使用一个简单的计算来调整以前的数值。 这将确保执行尽可能地迅速。 也许刚一开始会有略微的延迟,但所有其它计算都应当非常快速。
现在请注意以下几点:我们将从 MetaTrader 5 里只取一种数值类型,该数值在指标消息框中被选择。 可能被 MetaTrader 5 传输到指标的数值如图例 08 所示。
图例 08 - 从 MetaTrader 5 传输到指标的数值类型
该数值将在 buffer01 中实现 — 这是我们将要用到的缓冲区。 Buffer02 将根据我们所创建内容取值。 我们为什么要如此实现?
这是因为我们将用到两种不同的绘制样式。 样式其一,buffer02 将接收一个值,该值是阈值或水位线。 当水位线数值高于 0 时,发生这种情况是因为没有资产可以低于该值进行交易,因此持有的资产为负值没有意义。 通过使用填充模式,我们将得到一个如图例 02 所示的山型图。
但如果水位线数值不为零,我们则将得到如图例 03 和 04 所示的冰山图。 类似地,如果我们使用轮廓模式,并且水位线为 0,那么我们将得到一个折线图,但它将与 MetaTrader 5 中的默认折线图不同。
您可以指定线条的粗细和样式,从而获得类似于图例 05 和 06 的图表,尽管那里的水位线数值距零不同,这就是为什么它在曲线的不同部分具有不同的颜色。
以下是另一个函数:
void OnDeinit(const int reason) { ShowBars(); }
它简单地终结指标,导致图表返回到其原始状态。 现在我们来看一下另一个需要额外解释的函数。
void Init_MountainChart(void) { _memConfig.id = ChartID(); PlotIndexSetInteger(0, PLOT_DRAW_TYPE, (user02 == Fill ? DRAW_FILLING : DRAW_COLOR_LINE)); SetIndexBuffer(0, Buff1, INDICATOR_DATA); SetIndexBuffer(1, Buff2, (user02 == Fill ? INDICATOR_DATA : INDICATOR_COLOR_INDEX)); PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 2); PlotIndexSetString(0, PLOT_LABEL, "MidPoint"); PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, clrForestGreen); PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, clrFireBrick); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 0); HideBars(); }
调用此函数后,我们得到指标将附加到的图表 id。 此部分由清除和重新启动图表的函数所使用。 我们稍后将研究这些功能。 现在请注意以下几点:当用户选择填充图表时,我们将采用此设计模型,且当仅需创建轮廓时,我们会采用不同的模型。
这就是为什么代码看起来与您一开始想象的有点不同。 关键点在于一个细节:两个模型都用到两个缓冲区,但 DRAW_FILLING 模型用到两个缓冲区来处理数据,而 DRAW_COLOR_LINE 模型只用到一个缓冲区来存储数据,另一个缓冲区当作颜色缓冲区。 这就是为什么在负责显示指标的函数中正确计算很重要。
第一个数据缓冲区 buffer01 始终在使用。 Buffer02 则取决于我们想要构建的内容:它可以包含数据,或颜色索引。 请注意,我并未说 buffer02 将包含所用的颜色。 不要在那里指定颜色。 此缓冲区只需指定一个索引,而该索引将确定所用的颜色。 这就是为什么我没有在计算函数中使用任何颜色信息 — 只使用值 0 和 1,因为我们只用到两种颜色。
Buff2[c0] = (user02 == Fill ? user01 : (price[c0] > user01 ? 0 : 1));
现在让我们继续前进。 接下来我们要做的是定义双色矩阵。 我们在此用到的标签将在悬停时,以及选择和定义颜色时在水位线上可见。 我已添加了此功能,以便向您展示如何保存将来可能需要的信息。
现在,我们定义默认颜色,该值用户无法更改。 您首先必须将指标附加到图表上,然后才能更改颜色。 这些也显示在文章末尾的视频当中。
最后,指定将从哪个位置起构建图表。 实际上,这里不需要此功能,我只想展示您如何做到这一点。
之后,我们可以继续讨论微图表系统的最后两个函数。 HideBars 函数隐藏默认的 MetaTrader 5 图表布局。 这意味着我们将在 MetaTrader 5 中隐藏图表本身。 这很容易做到。 但如果出现问题,我们不想让用户生气,故此保存原始数据,以便稍后从品种图表中删除指标时恢复它。 好了,稍后我们就可以轻松地恢复到原始配色方案。
void HideBars(void) { _memConfig.CandleBear = (color) ChartGetInteger(_memConfig.id, CHART_COLOR_CANDLE_BEAR); _memConfig.CandleBull = (color) ChartGetInteger(_memConfig.id, CHART_COLOR_CANDLE_BULL); _memConfig.CandleLine = (color) ChartGetInteger(_memConfig.id, CHART_COLOR_CHART_LINE); _memConfig.LineUp = (color) ChartGetInteger(_memConfig.id, CHART_COLOR_CHART_UP); _memConfig.LineDown = (color) ChartGetInteger(_memConfig.id, CHART_COLOR_CHART_DOWN); ChartSetInteger(_memConfig.id, CHART_COLOR_CANDLE_BEAR, clrNONE); ChartSetInteger(_memConfig.id, CHART_COLOR_CANDLE_BULL, clrNONE); ChartSetInteger(_memConfig.id, CHART_COLOR_CHART_LINE, clrNONE); ChartSetInteger(_memConfig.id, CHART_COLOR_CHART_UP, clrNONE); ChartSetInteger(_memConfig.id, CHART_COLOR_CHART_DOWN, clrNONE); ChartRedraw(); } //+------------------------------------------------------------------+ void ShowBars(void) { ChartSetInteger(_memConfig.id, CHART_COLOR_CANDLE_BEAR, _memConfig.CandleBear); ChartSetInteger(_memConfig.id, CHART_COLOR_CANDLE_BULL, _memConfig.CandleBull); ChartSetInteger(_memConfig.id, CHART_COLOR_CHART_LINE, _memConfig.CandleLine); ChartSetInteger(_memConfig.id, CHART_COLOR_CHART_UP, _memConfig.LineUp); ChartSetInteger(_memConfig.id, CHART_COLOR_CHART_DOWN, _memConfig.LineDown); ChartRedraw(); }
最终,重置数据后,用户甚至不会注意到有问题。 无需再次重新设置所有内容,它始终很棒,因为在使用该系统时提供了更大的便利性。
然而,用户在删除指标后可能会有点惊讶,因为图表需要一些时间才能再次完全呈现。 结果就是,金融产品图表看起来与指标推出之前相同。
演示 (必须观看)
结束语
在本文中,我已展示了 MQL5 和 MetaTrader 5 平台本身能够创建许多东西,比许多人想象的更多。 我们在文章中只是做了一些简单的事情,但可以帮助理解更复杂的事情。
最大的问题是人们可以对平台或 MQL5 语言指手画脚,而实际上他们甚至并没有探索平台的功能,也不知道哪些可以做、哪些做不到。 他们只是不停地人云亦云,并不了解可能性。
每当您听到 MetaTrader 5 或 MQL5 受到限制,并且它们缺乏某些功能时,请向那些说这些话的人出示本文。 唯一真正有限的是他们的创造力或认知。 他们一直在说这些话,因为他们对编程一无所知,也不了解 MetaTrader 5 平台的目的,其应该是具有功能性的,安全的、和快速的,但最重要的是它应该作为一个平台。 究其根本,这是一个平台,其中的定制水平令其能够灵活适应我们所有人。
本文由MetaQuotes Ltd译自葡萄牙语
原文地址: https://www.mql5.com/pt/articles/11078


