English Русский Español Deutsch 日本語 Português
山型或冰山型图表

山型或冰山型图表

MetaTrader 5指标 | 23 一月 2023, 10:05
1 403 0
Daniel Jose
Daniel Jose

概述

您如何看待往 MetaTrader 5 平台里添加新图表类型的想法? 有人说它缺少其它平台里提供的一些东西。 但事实是,MetaTrader 5 是一个非常实用的平台,因为它允许您做到在许多其它平台上无法完成(或至少不能轻松完成)的事情。

最常见的抱怨之一是 MetaTrader 5 中只有三种图表类型:蜡烛、柱线和折线。 真的是这样吗? 亦或因为有人尚不知道平台的实际工作原理,或 MQL5 语言提供了哪些可能性?

大多数情况下,抱怨的人大多是对平台了解较浅薄的人。 每个人都希望自己要用到的东西都已准备好,如果不能即刻就位,他们就开始抱怨。

在本文中 — 这次不会很长 — 我们将看到如何以不同但有用的样式创建图表。 它对于那些使用特定样式进行交易的人来说尤其有用,例如波段交易仓位交易、甚至投资组合交易。

今天我们将看看山型或冰山型图表。 甚至,我们将更深入学习如何利用 MQL5 工作。 在本文中,我们将开发一个非常有趣的图表来有效地跟踪持仓:配合此图表,您无需再持续检查一笔交易的盈亏。 您可以简单地查看图表,就可判定您指定的持仓是盈利亦或亏损。

山型图与线性表示样式非常相似,但略有不同之处。 使用折线图(如图例 01 所示),我们所拥有的只是价格是上涨还是下跌的简单指示,仅此而已。 而山型图提供了更多的能力。 山型图如图例 02 所示。


图例 01

图例 01 - 典型折线图


图例 02

图例 02 - 典型山型图


图例 02 所示的图表是山型图中最常见的类型。 它有若干个变体,也许有不同的名称。 基本变体其一如图例03 所示。


图例 03

图例 03 - 冰山型图多头持仓


图例 03 显示的图表类型非常易于阅读。 在这种特殊情况下,图例 03 所示的图表适用于多头持仓,但空头持仓大体相同。 这样的图表如图例 04 所示。


图例 04

图例 04 - 空头持仓冰山型图


通过观察冰山图,您可以立即看出持仓是盈利亦或亏损。 图表以不同的颜色来指示交易状态(盈利/亏损)。 因此,只需简单地为山型地图涂上颜色,我们就可以实现一种不同的风格,对于那些刚开始研究行情的人来说,这种风格更容易阅读。 当您需要放置长线持仓时,它可能特别有用。

有趣的是,该系统非常简单,同时适应性很强,它不仅允许我们创建山型图或冰山型图,还可以创建更复杂的折线图,如图例 05 所示。


图例 05

图例 05 - 分析持仓的折线图


线型可以更改,即它不必一定是实线。 例如,我们可以创建以下图表。


图例 06

图例 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

图例 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

附加的文件 |
Mountain_Chart.zip (12.8 KB)
DoEasy. 控件 (第 19 部分): 在 TabControl 中滚动选项卡、WinForms 对象事件 DoEasy. 控件 (第 19 部分): 在 TabControl 中滚动选项卡、WinForms 对象事件
在本文中,我将创建的功能是利用滚动按钮在 TabControl 中滚动选项卡标题。 该功能旨在将选项卡标题从控件的任一侧拖放到单行之中。
学习如何基于奥森姆(Awesome)振荡器设计交易系统 学习如何基于奥森姆(Awesome)振荡器设计交易系统
在我们系列的这篇新文章中,我们将学习一种也许对我们的交易有用的新技术工具。 它是奥森姆(Awesome)振荡器((AO)指标。 我们将学习如何基于该指标设计交易系统。
神经网络变得轻松(第三十部分):遗传算法 神经网络变得轻松(第三十部分):遗传算法
今天我想给大家介绍一种略有不同的学习方法。 我们可以说它是从达尔文的进化论中借鉴而来的。 它可能比前面所讨论方法的可控性更低,但它允许训练不可微分的模型。
神经网络变得轻松(第二十九部分):优势扮演者-评价者算法 神经网络变得轻松(第二十九部分):优势扮演者-评价者算法
在本系列的前几篇文章中,我们见识到两种增强的学习算法。 它们中的每一个都有自己的优点和缺点。 正如在这种情况下经常发生的那样,接下来的思路是将这两种方法合并到一个算法,使用两者间的最佳者。 这将弥补它们每种的短处。 本文将讨论其中一种方法。