English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
preview
Expert Advisor 개발 기초부터 (파트 13): Time and Trade (II)

Expert Advisor 개발 기초부터 (파트 13): Time and Trade (II)

MetaTrader 5트레이딩 시스템 | 17 1월 2023, 10:03
258 0
Daniel Jose
Daniel Jose

소개

이전 기사 "Times & Trade (I)"에서 우리는 차트 구성 시스템에 대해 알아보았습니다. 이 시스템은 시장에서 실행된 거래에 대해 가능한 가장 빠른 해석을 가능하게 하는 지표를 생성하게 해 줍니다. 그러나 우리는 이 시스템을 아직 완성하지 못했습니다. 특정 정보에 액세스하는 방법을 보여줄 수 있는 능력이 여전히 부족합니다. 이러한 액세스는 무슨 일이 일어나고 있는지 더 잘 이해하는 데 도움이 될 것임에도 불고하고 말입니다. 이러한 정보는 차트에 직접 표시할 수 없습니다. 실제로 그러한 표시는 구현될 수는 있지만 그에 대한 해석은 매우 혼란스러울 것입니다. 따라서 고전적인 방법, 즉 텍스트 형식의 값으로 데이터를 표현하는 것이 가장 좋습니다. 우리의 Expert Advisor에는 이 작업을 수행할 수 있는 시스템이 없습니다. 따라서 우리는 이를 구현해야 합니다.

일부 독자에게는 전혀 필요하지 않을 수 있는 정보를 추가하여 이전 기사를 복잡하게 만들지 않기 위해(이러한 세부 사항에 깊이 들어가지 않고 시스템을 사용할 수 있으므로) 이전 기사에서 제안한 일부 내용을 시스템에 포함하지 않으면서 시스템을 더 확장하고 더 완전하게 만들기로 했습니다. 정보는 시장에서 실제로 일어나고 있는 일을 이해하는 데 필요할 수 있습니다.


계획

여기서 한 가지를 이해하는 것이 중요합니다. 디테일은 디테일 뿐이라 생각 할 수 있지만 속담처럼 단순해 보이는 것에 더 많은 시간과 노력이 필요할수 있습니다. 다음 이미지를 살펴보시기 바랍니다:

이 이미지에서 이상한 점을 발견하셨나요? 별 의미가 없어 보일 수도 있지만 자세히 살펴보십시오.

여전히 이상한 점을 발견하지 못했다면 아래 강조 표시된 영역을 참조하십시오.


무슨 일이 일어나고 있는지 보이십니까? BID 및 ASK 값에 변화가 있었지만 여기서는 한 번의 거래만 수행되었습니다. BID 또는 ASK 값이 변경되더라도 한 번의 거래만 있었다는 것이 말이 되지 않습니다. 그러나 그러한 일은 실제로 생각보다 더 일반적입니다. 문제는 일반적으로 아래와 같은 읽기 모드를 사용할 때 이러한 것을 볼 수 없다는 것입니다:

이러한 시장 분석 방법을 사용하면 BID 및 ASK 값의 움직임을 볼 수 없습니다. 시장은 항상 작동하는 것 같고 모두가 거래를 성사시키려고 하는 것 같지만 이것은 사실이 아닙니다. 실제로 마켓 플레이어는 특정 지점에 포지션을 놓고 시장의 움직임을 기다립니다. 포지션이 맞게 되면 그들은 움직임을 최대한 이용하고 이익을 얻으려고 합니다. 이로 인해 BID 또는 ASK 값은 거래가 없이 움직입니다. 이러한 현상은 우리가 플랫폼에서 볼 수 있는 실제 사실이지만 대부분의 사람들은 이를 무시합니다.

아래 그림은 Times & Trade 시스템이 어떻게 생겼는지 보여줍니다:

자세히 보면 차트에 4개의 캔들로 구성되어 있음을 알 수 있습니다. 5개의 캔들이 있어야 하는데 다이렉트 주문은 실제로 시장을 움직이지 않기 때문에 시스템에서 제외됩니다. 따라서 실제로 우리는 네 가지의 구성이 있는 것입니다. 이들은 다음과 같은 유형이 될 것입니다:

그림자는 때때로 캔들의 몸체에 닿지 않습니다. 왜 이런 일이 발생할까요? 그림자는 BID와 ASK의 차이인 스프레드 값에 의해 형성되지만 이 스프레드 내에서 일이 발생하면 캔들은 어떻게 될까요? 이럴 경우 아래에 표시된 다섯 번째 유형입니다:

유형에 따라 DOJI입니다. 이것이 직접 주문이 시스템에 표시되지 않는 이유입니다. 그러나 이것이 몸통이 때때로 그림자에 닿지 않는 이유를 설명하지 못합니다. 이러한 상황은 몸통과 그림자 사이에 거리가 있는 가격이 너무 빨리 움직이는 상황과 관련이 있습니다. 가격이 이렇게 움직인다는 것이 말이 되지 않으므로 시스템 오류라고 생각할 수 있습니다. 그러나 그렇지 않습니다. 이러한 상황은 스탑 주문이 발동될 때 발생하기 때문에 이상할 것이 없습니다. 이를 보려면 아래 이미지를 살펴보십시오:

주문은 있으나 BID도 Ask도 건드리지 않는 경우가 잇따르고 있습니다. 이 모든 포인트는 스탑 주문이 실행된 것을 나타냅니다. 이런 일이 발생하면 일반적으로 가격이 급등하며 이는 차트에서 볼 수 있습니다. Times & Trade에서는 움직임을 평가하기 위해 차트 모드를 사용하는 경우에만 이러한 현상을 볼 수 있습니다. 그렇지 않으면 여러분은 스탑 주문이 발동되는 것을 볼 수 없으며 움직임이 실제로는 빨르게 원상 복구하는데도 불구하고 힘을 얻었다고 생각할 수 있으며 결국 스탑에 걸리게 될 것입니다.

이제 이것을 알았으므로 그림자에 닿지 않는 큰 일련의 캔들이 형성된 경우 이는 스탑 주문이라는 것을 이해하게 될 것입니다. 실제로 모든 것이 매우 빠르게 발생하기 때문에 이 움직임이 발생하는 시점을 정확하게 포착하는 것은 불가능합니다. 그러나 BID 및 ASK 값을 해석하여 이것이 발생한 이유를 찾을 수 있습니다. 이것은 귀하와 귀하의 시장 경험에 달려 있습니다. 자세한 내용은 다루지 않겠지만 실제로 Tape Reading을 지표로 사용하고 싶다면 집중해야 할 사항입니다.

이제 세부적인 내용을 다룰 때입니다: 이러한 정보를 캔들을 통해서만 볼 수 있고 정보는 충분함에도 왜 더 많은 데이터가 필요할까요?

시장은 순간적으로 나오는 정보를 기다리며 더디게 움직이는 때가 음에도 단순히 Times & Trade에서 캔들을 보고 있는 것만으로는 이것을 알 수 없습니다. 우리는 그 이상이 필요합니다. 이 정보는 시스템 자체에 존재하지만 들어오는 대로 해석하기 어렵습니다. 데이터는 보다 쉽게 분석할 수 있도록 모델링되어야 합니다.

이 모델링이 이 기사를 작성하는 이유입니다. 이 모델링이 완료되면 Times & Trade는 다음과 같이 변경됩니다:

즉 우리는 무슨 일이 일어나고 있는지에 대한 완전한 그림을 갖게 되는 것입니다. 또한 모든 것이 빨라질 것이며 이는 테이프 읽기를 거래 방법으로 사용하려는 사람들에게 중요합니다.


구현

이 시스템을 구현하려면 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 클래스에 4개의 서브루틴을 추가해야 합니다. 이러한 서브루틴은 아래 코드에 나와 있습니다:

// ... 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)));
}

Times & Trade의 교체 루틴에도 추가 변경이 필요했습니다. 변경 사항은 다음과 같습니다:

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 카운터는 테스트하지 않습니다. 새로운 정보를 사용할 수 있게 되면 그 값을 높일 것입니다. 이것은 때때로 사용할 수 있는 트릭입니다. 이부분은 처리 측면에서 효율적이기 때문에 되도록이면 사용을 합니다. 거래 시스템이 실시간으로 사용되도록 설계되어야 합니다. 여러분은 조금이라도 가능한 한 계속해서 시스템을 최적화하려고 노력해야 합니다. 결국에는 큰 차이를 만듭니다.

모든 것이 구현된 후 Expert Advisor를 컴파일하고 다음과 같은 결과를 얻게 됩니다:


Times & Trade 차트에서 위에서 설명한 움직임을 확인해 보면 Times & Trade 자체에 미세한 부분이 나타나기 시작하는 것을 볼 수 있습니다. 그러나 저는 이러한 미세한 부분을 알아낸 후에도 이러한 부분이 존재한다는 사실을 전혀 활용할 수 없었습니다. 저는 거래 경험이 많지 않지만 경험이 더 많은 사람이라면 할 수 있는 것을 찾아 낼지 누가 알겠습니까?

이 지표는 매우 강력하고 유익하기 때문에 이 지표의 값과 자산이 보여주는 실제 데이터 사이의 작은 비교를 보여주는 비디오를 만들기로 했습니다. 저는 그것이 많은 정보를 필터링하여 데이터를 훨씬 더 빨리 읽고 무슨 일이 일어나고 있는지 더 잘 이해할 수 있게 해준다는 것을 보여주고 싶습니다. 이 환상적이고 강력한 지표를 즐기고 활용하시기 바랍니다.




결론

여기서 제안하는 시스템은 MetaTrader 5 플랫폼에서 사용할 수 있는 차트 시스템을 수정한 것입니다. 수정된 것은 데이터 모델링 방식입니다. 청산한 거래가 플랫폼에서 사용할 수 있는 가장 낮은 차트 주기인 1분에서 미세한 구조를 형성하여 가격 방향에 어떤 영향을 미치는지 보는 것은 흥미로울 것입니다. 많은 사람들은 분 단위로 거래한다는 것이 높은 수준의 시장 지식을 가지고 있다는 것을 의미하는 것처럼 말합니다. 하지만 자세히 살펴보고 거래 프로세스를 이해하게 되면 1분 안에 많은 일이 발생한다는 것이 분명해집니다. 따라서 이것은 짧은 시간처럼 보이지만 이로 인해 잠재적으로 수익성 있는 많은 거래를 놓칠 수 있습니다. 이 Times & Trade 시스템에서 우리는 1분 안에 일어나는 일을 보고 있지 않다는 것을 기억하십시오 — 화면에 나타나는 값은 밀리초 단위입니다.


MetaQuotes 소프트웨어 사를 통해 포르투갈어가 번역됨
원본 기고글: https://www.mql5.com/pt/articles/10412

파일 첨부됨 |
EA_-_Times_m_Trade.zip (5983.76 KB)
Expert Advisor 개발 기초부터 (파트 14): 가격에 볼륨 추가 (II) Expert Advisor 개발 기초부터 (파트 14): 가격에 볼륨 추가 (II)
오늘 우리는 EA에 더 많은 리소스를 추가할 것입니다. 이 흥미로운 기사는 정보를 표시하는 새로운 아이디어와 방법을 제공합니다. 동시에 프로젝트의 사소한 결함을 수정하는 데에도 도움이 될 수 있습니다.
볼륨으로 거래 시스템을 설계하는 방법 알아보기 볼륨으로 거래 시스템을 설계하는 방법 알아보기
이 글은 인기 있는 기술 지표를 기반으로 거래 시스템을 설계하는 방법과 관련한 시리즈의 새로운 글입니다. 이 기사에서는 볼륨 지표에 대해 설명합니다. 볼륨의 개념은 금융 시장 거래에서 매우 중요한 요소 중 하나이며 우리 모두 주의를 기울여야 할 요소입니다. 이 글을 통해 볼륨 지표로 간단한 거래 시스템을 설계하는 방법에 대해서 알아보겠습니다.
MFI로 거래 시스템을 설계하는 방법 알아보기 MFI로 거래 시스템을 설계하는 방법 알아보기
가장 인기 있는 기술 지표를 기반으로 거래 시스템을 설계하는 방법에 대한 시리즈 중 이번 기사에서는 새로운 기술 지표인 MFI(Money Flow Index)를 사용할 것입니다. 우리는 MFI에 대해 자세히 알아보고 MetaTrader 5에서 실행할 수 있도록 MQL5로 간단한 거래 시스템을 개발할 것입니다.
데이터 과학 및 머신 러닝(파트 05): 의사 결정 트리 데이터 과학 및 머신 러닝(파트 05): 의사 결정 트리
의사 결정 트리는 인간이 데이터를 분류하기 위해 생각하는 방식을 모방합니다. 트리를 구축하고 트리를 사용하여 데이터를 분류하고 예측하는 방법에 대해 알아보겠습니다. 의사 결정 트리 알고리즘의 주요 목표는 불순물이 있는 데이터를 순수한 것으로 분리하거나 노드에 가깝게 분리하는 것입니다.