English Русский Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
从头开始开发智能交易系统(第 13 部分):时序与交易(II)

从头开始开发智能交易系统(第 13 部分):时序与交易(II)

MetaTrader 5交易系统 | 27 七月 2022, 08:48
1 057 0
Daniel Jose
Daniel Jose

概述

在上一篇文章时序与交易(I)当中,我们讨论了一种替代的图表组织系统,这是创建指标的先决条件,该指标能够最快速地解释市场上所执行的成交。 但我们尚未完成这个系统:它仍然缺乏显示如何访问某些信息的能力,这种访问将有助于更好地了解正在发生的事情。 此类信息不能直接显示在图表上。 实际上,这样的表达是可以实现的,然而解释起来会很混乱。 因此,最好以经典方式表达数据,即,以文本格式的数值。 我们的智能交易系统尚未拥有执行此任务的能力。 因此,我们需要实现它。

为了不让前一篇文章变得复杂,我添加了一些读者可能根本不需要的信息(因为系统可以在不深入了解这些细节的情况下使用),我决定在这里扩展系统,令其更加完整,但我没有将前一篇文章中提出的一些内容包含到新系统之中。 但有时也许需要这些信息来了解市场中实际发生的情况。


计划

此处重要的是要理解一件事。 这只是细节,但俗话说魔鬼生活在细节中。 如此,请看下图:

您是否注意到这张图片中有什么奇怪的地方吗? 也许没有什么意义,但它就在这里,所以请仔细观察。

如果您仍然没有注意到任何奇怪的事情,请参阅下面高亮显示的区域。


现在,您看到发生了什么吗? 在该点处,买卖价格发生了变化,但这里只进行了一笔交易。 即使买卖价格发生变化,也没有理由只进行一笔交易。 但事实上,有些事情比您想象的要普遍。 问题是,当您如下所示采用阅读模式时,通常看不到这种情况:

当采用这种市场分析方法时,我们看不到买卖价格的变化。 市场似乎始终处于运作,每个人都在尝试达成交易,但事实并非如此。 实际上,市场参与者会在某些点位处下单,并等待市场走势。 当触及该位置时,他们试图利获取先手,用价格运动中获利 — 因此,买入或卖出价格会在没有任何交易的情况下移动。 这是一个真实的事实,并可在平台上看到,但大多数人却忽视了这一点,他们认为这些信息并不十分重要。

下图显示了我们的“时序与交易”系统的样子:

如果您仔细观察,您会看到图表上有四种烛条配置。 应该有五种,但直接订单被排除在系统之外,因为它们实际上并未导致市场移动。 故此,我们实际上有四种配置。 这些是以下形式:

阴影有时不触及烛条的主体。 为什么会这样? 阴影是由点差值形成的,而其值又是买入和卖出之间的差值,但如果依据该点差发生操作,那么烛条会是什么样子? 这将是第五种类型,如下所示:

根据其形状类型,它是十字星(DOJI)。 这就是系统中不显示直接订单的原因。 但这并不能解释为什么主体有时不接触阴影。 这种行为与某些情况有关,即发生了导致价格移动过快的情形,主体和阴影之间存在一定间隙。 有人可能会认为这是一个系统故障,因为价格如此波动是没有意义的。 但在此它确实有意义,因为在触发止损单时就会发生这种情形。 为了看清这一点,请参见下图:

有一系列的情况下,有不少订单,但既未触及出价,也没有触及要价。 所有这些点都代表触发的是止损单。 当这种情况发生时,价格通常会跳跃,这在图表上可以很容易看到。 若采用图表模式评估走势时,同样的事实就能在”时序与交易“上看到。 如果没有这一点,您就看不到止损单的触发,也许会认为走势增强了力量,而实际上它可以很快恢复,然后您又会触发止损。

既然您知道了这一点,您就会明白,一个大系列的烛条不触及阴影则代表触发了止损单。 事实上,不可能准确地捕捉到这种走势发生的时间,因为一切都发生得突然。 但是,您可以用出价和要价的解释来找出为何会发生这种情况。 这取决于您和您的市场经验。 我不会深入细节,但如果您真的想用读盘作为指标,这是您应该关注的。

现在,细节来了:如果这些信息只能用烛条看到,且它们本身就足以学到一些信息,那为什么还需要更多的数据呢?

最重要的细节是,有时市场会疲软,在等待某些时刻带来的一些信息,但我们无法通过简单地查看”时序与交易“的烛条来知晓这些。 我们还需要比这更多的东西。 这些信息存在于系统本身,但很难在出现时对其进行解释。 数据理应建模,从而能够更容易地分析。

建模是撰写本文的原因:建模完成后,”时序与交易“将如下所示变化:

换句话说,我们对正在发生的事情将有一个完整的全貌。 甚而,一切都会很快,对于那些想采用读盘作为交易方式的人来说很重要。


实现

为了实现该系统,我们需要向 C_TimesAndTrade 类添加几个新变量。 代码如下所示:

#include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh>
#include <NanoEA-SIMD\Auxiliar\C_Canvas.mqh>
//+------------------------------------------------------------------+
class C_TimesAndTrade : private C_FnSubWin
{
//+------------------------------------------------------------------+
#define def_SizeBuff 
2048 
#define macro_Limits(A) (A & 0xFF)
#define def_MaxInfos 257
//+------------------------------------------------------------------+
        private :
                string          m_szCustomSymbol,
                                m_szObjName;
                char            m_ConnectionStatus;
                datetime        m_LastTime;
                ulong           m_MemTickTime;
                int             m_CountStrings;
                struct st0
                {
                        string  szTime;
                        int     flag;
                }m_InfoTrades[def_MaxInfos];
                struct st1
                {
                        C_Canvas Canvas;
                        int      WidthRegion,
                                 PosXRegion,
                                 MaxY;
                        string   szNameCanvas;
                }m_InfoCanvas;


加到源代码中的部分以高亮显示。 如您所见,我们需要用到 C_Canvas 类,但它并未拥有我们所需的全部元素。 事实上,我们不得不往这个 C_Canvas 类里添加四个子例程。 这些子例程如以下代码所示:

// ... C_Canvas class code

inline void FontSet(const string name, const int size, const uint flags = 0, const uint angle = 0)
{
        if(!TextSetFont(name, size, flags, angle)) return;
        TextGetSize("M", m_TextInfos.width, m_TextInfos.height);
}
//+------------------------------------------------------------------+
inline void TextOutFast(int x, int y, string text, const uint clr, uint alignment = 0)
{
        TextOut(text, x, y, alignment, m_Pixel, m_width, m_height, clr, COLOR_FORMAT_ARGB_NORMALIZE);
}
//+------------------------------------------------------------------+
inline int TextWidth(void) const { return m_TextInfos.width; }
//+------------------------------------------------------------------+
inline int TextHeight(void) const { return m_TextInfos.height; }
//+------------------------------------------------------------------+

// ... The rest of the code ...

这些行创建文本。 很简单,没什么特别好看的。

该类中值得一提的下一个函数是 C_TimesAndTrade:

void PrintTimeTrade(void)
{
        int ui1;
        
        m_InfoCanvas.Canvas.Erase(clrBlack, 220);
        for (int c0 = 0, c1 = m_CountStrings - 1, y = 2; (c0 <= 255) && (y < m_InfoCanvas.MaxY); c0++, c1--, y += m_InfoCanvas.Canvas.TextHeight())
        if (m_InfoTrades[macro_Limits(c1)].szTime == NULL) break; else
        {
                ui1 = m_InfoTrades[macro_Limits(c1)].flag;
                m_InfoCanvas.Canvas.TextOutFast(2, y, m_InfoTrades[macro_Limits(c1)].szTime, macroColorRGBA((ui1 == 0 ? clrLightSkyBlue : (ui1 > 0 ? clrForestGreen : clrFireBrick)), 220));
        }
        m_InfoCanvas.Canvas.Update();
}

该函数将在为其保留的特殊区域中显示数值。 此外,初始化过程也略微发生了变化,可以在下面高亮显示的部分中看到:

void Init(const int iScale = 2)
{
        if (!ExistSubWin())
        {
                m_InfoCanvas.Canvas.FontSet("Lucida Console", 13);
                m_InfoCanvas.WidthRegion = (18 * m_InfoCanvas.Canvas.TextWidth()) + 4;
                CreateCustomSymbol();
                CreateChart();
                m_InfoCanvas.Canvas.Create(m_InfoCanvas.szNameCanvas, m_InfoCanvas.PosXRegion, 0, m_InfoCanvas.WidthRegion, TerminalInfoInteger(TERMINAL_SCREEN_HEIGHT), GetIdSubWinEA());
                Resize();
                m_ConnectionStatus = 0;
        }
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale)));
}

”时序与交易“的替补程序也需要进行额外的修改。 变化如下:

void Resize(void)
{
        static int MaxX = 0;
        int x = (int) ChartGetInteger(Terminal.Get_ID(), CHART_WIDTH_IN_PIXELS, GetIdSubWinEA());
        
        m_InfoCanvas.MaxY = (int) ChartGetInteger(Terminal.Get_ID(), CHART_HEIGHT_IN_PIXELS, GetIdSubWinEA());
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_YSIZE, m_InfoCanvas.MaxY);
        if (MaxX != x)
        {
                MaxX = x;
                x -= m_InfoCanvas.WidthRegion;
                ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_XSIZE, x);
                ObjectSetInteger(Terminal.Get_ID(), m_InfoCanvas.szNameCanvas, OBJPROP_XDISTANCE, x);
        }
        PrintTimeTrade();
}

该系统几乎准备就绪,但我们仍然需要位于系统核心的子例程。 它也经过了修改:

inline void Update(void)
{
        MqlTick Tick[];
        MqlRates Rates[def_SizeBuff];
        int i0, p1, p2 = 0;
        int iflag;
        long lg1;
        static int nSwap = 0;
        static long lTime = 0;

        if (m_ConnectionStatus < 3) return;
        if ((i0 = CopyTicks(Terminal.GetFullSymbol(), Tick, COPY_TICKS_ALL, m_MemTickTime, def_SizeBuff)) > 0)
        {
                for (p1 = 0, p2 = 0; (p1 < i0) && (Tick[p1].time_msc == m_MemTickTime); p1++);
                for (int c0 = p1, c1 = 0; c0 < i0; c0++)
                {
                        lg1 = Tick[c0].time_msc - lTime;
                        nSwap++;
                        if (Tick[c0].volume == 0) continue;
                        iflag = 0;
                        iflag += ((Tick[c0].flags & TICK_FLAG_BUY) == TICK_FLAG_BUY ? 1 : 0);
                        iflag -= ((Tick[c0].flags & TICK_FLAG_SELL) == TICK_FLAG_SELL ? 1 : 0);
                        if (iflag == 0) continue;
                        Rates[c1].high = Tick[c0].ask;
                        Rates[c1].low = Tick[c0].bid;
                        Rates[c1].open = Tick[c0].last;
                        Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag);
                        Rates[c1].time = m_LastTime;
                        m_InfoTrades[macro_Limits(m_CountStrings)].szTime = StringFormat("%02.d.%03d ~ %02.d <>%04.d", ((lg1 - (lg1 % 1000)) / 1000) % 60 , lg1 % 1000, nSwap, Tick[c0].volume);
                        m_InfoTrades[macro_Limits(m_CountStrings)].flag = iflag;
                        m_CountStrings++;
                        nSwap = 0;
			lTime = Tick[c0].time_msc;
                        p2++;
                        c1++;
                        m_LastTime += 60;
                }
                CustomRatesUpdate(m_szCustomSymbol, Rates, p2);
                m_MemTickTime = Tick[i0 - 1].time_msc;
        }
        PrintTimeTrade();
}

高亮显示的行表示添加到子例程的代码,可令我们针对需要的数据进行建模。 以下代码

lg1 = Tick[c0].time_msc - lTime;
nSwap++;


检查交易之间经历了多少以毫秒为单位的时间,以及发生了多少未引起价格变化的交易。 如果这些数字很大,您可以理解换手正在下降。 使用此功能,您会比其他人更早注意到这一点。

以下部分

m_InfoTrades[macro_Limits(m_CountStrings)].szTime = StringFormat("%02.d.%03d ~ %02.d <>%04.d", ((lg1 - (lg1 % 1000)) / 1000) % 60 , lg1 % 1000, nSwap, Tick[c0].volume);
m_InfoTrades[macro_Limits(m_CountStrings)].flag = iflag;
m_CountStrings++;
nSwap = 0;                                      
lTime = Tick[c0].time_msc;

将为所要呈现的数值建模。 请注意,由于使用限制,我们不会测试 m_CountStrings 计数器。 随着新信息的出现,我们将简单地增加其数值。 有时这是一个可以使用的技巧。 我自己也在可能的情况下会用到它,因为它在处理方面很高效,这一点很重要,因为交易系统是为实时使用而设计的。 您理应尽可能地优化系统,哪怕只是一点点 — 最终它会产生很大的影响。

在所有事情都实现后,编译智能交易系统,并获得如下内容:


观察“时序与交易”图表上的上述走势,您可看到微观结构开始出现在“时许与交易”本身。 然而,即使在研究了这些微观结构之后,我也无法利用它们存在的事实获取好处。 然而,我不是一个经验丰富的交易者,所以谁知道呢,也许拥有更多经验的人可以做到这一点。

该指标功能强大,信息量大,因此我决定制作一期视频,展示编写时资产显示的真实数据与其数值之间的小规模比较。 我打算演示一下,它过滤了大量信息,令您能够更快地读取数据,更好地了解正在发生的事情。 我希望你们喜欢并能利用这款神奇而强大的指标。




结束语

此处提出的系统只是针对 MetaTrader 5 平台本身可用的图表系统的改良。 改良的重点是数据建模方法。 有趣的是,在平台上查看成交如何在可用的最低时间帧(即 1 分钟)内形成微结构,并影响价格方向。 许多人喜欢炫耀说,他们按分钟交易,好像这意味着他们拥有很高深的市场知识水平。 但如果您仔细观察并理解交易过程,就会发现很多事情都是在一分钟内发生的。 因此,尽管这看起来时间很短,但这可能会导致我们错过许多潜在的盈利交易机会。 请记住,在该“时序与交易”系统中,我们并非在看 1 分钟内发生了什么 — 屏幕上出现的数值是以毫秒为单位报价的。


本文由MetaQuotes Ltd译自葡萄牙语
原文地址: https://www.mql5.com/pt/articles/10412

附加的文件 |
EA_-_Times_m_Trade.zip (5983.76 KB)
从头开始开发智能交易系统(第 14 部分):添加价格成交量(II) 从头开始开发智能交易系统(第 14 部分):添加价格成交量(II)
今天,我们要将更多资源加入 EA。 这篇有趣的文章可以提供一些展示信息的新思路和方法。 与此同时,它能帮助修复项目中的小缺陷。
学习如何基于 ADX 设计交易系统 学习如何基于 ADX 设计交易系统
在本文中,我们将继续有关基于最流行指标设计交易系统的系列文章,这次我们将讨论平均方向指数(ADX)指标。 我们将详细学习该指标,从而能够更好地理解它,并将学习如何在简单策略里运用它。 通过深入学习,我们可以获得更多的认知,可以更好地运用它。
学习如何基于 ATR 设计交易系统 学习如何基于 ATR 设计交易系统
在本文中,我们将学习一款可在交易中运用的新技术工具,作为我们学习如何设计简单交易系统系列的延续。 这次我们将选取另一个流行的技术指标:平均真实范围(ATR)。
学习如何基于 Stochastic 设计交易系统 学习如何基于 Stochastic 设计交易系统
在本文中,我们继续我们的研究系列 — 这次,我们将学习如何基于最流行的技术指标之一 Stochastic 振荡器指标设计交易系统。