English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
preview
Expert Advisor 개발 기초부터 (파트 12): 시간과 거래(I)

Expert Advisor 개발 기초부터 (파트 12): 시간과 거래(I)

MetaTrader 5트레이딩 시스템 | 15 12월 2022, 16:12
419 0
Daniel Jose
Daniel Jose

소개

테이프 읽기는 다양한 거래 단계에서 거래자들이 사용하는 거래 방법입니다. 이 방법은 매우 효과적이며 올바르게 사용하면 순수하게 캔들을 관찰하는 방법인 누구나 아는 Price Action을 사용할 때보다 더 안전하고 일관된 방식으로 안정적인 수익의 증가를 가져올 수 있습니다. 그러나 현재 제시된 형태의 테이프 읽기를 사용하는 것은 매우 복잡하고 지루한 과정입니다. 지속적으로 주의를 집중해야 하기 때문입니다. 시간이 지남에 따라 우리는 관찰 도중 실수를 하기 시작합니다.

테이프 읽기의 문제는 우리가 분석해야 하는 정보의 양과 관련이 있습니다. 테이프 읽기의 전형적인 사용예를 살펴보겠습니다.


문제는 분석 중에 가격에 무슨 일이 일어났는지를 살펴봐야 하는데 작은 계약에서 이러한 값을 확인하는 것은 그리 실용적이지 않다는 것입니다. 따라서 우리는 일반적으로 작은 계약에서는 어떠한 흐름인지 그 내용을 보지 않습니다. 대신 큰 계약을 관찰하는 것을 선호합니다. 큰 계약이 시장을 움직이는 것이기 때문입니다. 보통 다들 그렇게 합니다 그리고 이럴 경우 시스템은 아래와 같습니다. 해석하고 따라가기가 좀더 쉽습니다.


그러나 이 경우에도 시스템을 적용하는 것은 극도의 주의를 요하는 매우 지루한 프로세스입니다. 스탑 포지션이 활성화되면 상황은 더욱 빡빡해지며 이 경우 화면에서 정보를 스크롤 할때 매우 빨라야 하며 그렇지 않을 경우 일부 움직임을 놓칠 수 있습니다.


계획

그러나 MetaTrader 5 플랫폼에는 작은 계약을 관리하는 대체 시스템이 있어 훨씬 효율적이고 쉽게 모니터링할 수 있습니다. 작은 계약으로 작업할 때 상황이 어떻게 보이는지 봅시다:

보시다시피 해석이 훨씬 간단합니다. 그러나 앞에서 다룬 대로 전체 계약을 사용하는 것이 더 적절하므로 다음과 같이 표시됩니다.


거래 데이터는 BID 및 ASK의 움직임에 따른 노이즈로 인해 방해를 받습니다. 거래는 여기에서 원으로 표시됩니다. 빨간색 표시는 매도 거래, 파란색 표시는 매수 거래이고 녹색 표시는 직접 주문입니다. 시장을 관찰 할 때 필요하지 않은 정보가 보여진다는 사실 외에도 또 다른 문제가 있습니다: 시스템이 실제로 거래하는 차트와 분리되므로 우리는 두 개의 화면을 모니터링해야 합니다. 한편으로 이것은 장점이지만 어떤 경우에는 상황을 복잡하게 만듭니다. 그래서 여기서는 읽기 쉬우면서 동시에 거래 차트에서 이 지표를 직접 볼 수 있는 시스템을 만들어 볼 것입니다.


구현

가장 먼저 할 일은 전체 계약 자산에 액세스할 수 있도록 C_Terminal 클래스를 수정하는 것입니다. 이는 다음 코드를 추가하여 수행합니다.

void CurrentSymbol(void)
{
        MqlDateTime mdt1;
        string sz0, sz1, sz2;
        datetime dt = TimeLocal();
                
        sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, 0, 3);
        m_Infos.szFullSymbol = _Symbol;
        m_Infos.TypeSymbol = ((sz0 == "WDO") || (sz0 == "DOL") ? WDO : ((sz0 == "WIN") || (sz0 == "IND") ? WIN : OTHER));
        if ((sz0 != "WDO") && (sz0 != "DOL") && (sz0 != "WIN") && (sz0 != "IND")) return;
        sz2 = (sz0 == "WDO" ? "DOL" : (sz0 == "WIN" ? "IND" : sz0));
        sz1 = (sz2 == "DOL" ? "FGHJKMNQUVXZ" : "GJMQVZ");
        TimeToStruct(TimeLocal(), mdt1);
        for (int i0 = 0, i1 = mdt1.year - 2000;;)
        {
                m_Infos.szSymbol = StringFormat("%s%s%d", sz0, StringSubstr(sz1, i0, 1), i1);
                m_Infos.szFullSymbol = StringFormat("%s%s%d", sz2, StringSubstr(sz1, i0, 1), i1);
                if (i0 < StringLen(sz1)) i0++; else
                {
                        i0 = 0;
                        i1++;
                }
                if (macroGetDate(dt) < macroGetDate(SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_EXPIRATION_TIME))) break;
        }
}

// ... Class code ...

inline string GetFullSymbol(void) const { return m_Infos.szFullSymbol; }


강조 표시된 라인을 추가하면 원하는 자산에 액세스할 수 있으며 이를 Time & Trade 프로그램에서 사용할 수 있습니다. 다음으로 Time & Trade를 지원할 객체 클래스를 생성합니다. 이 클래스에는 몇 가지 매우 흥미로운 기능이 포함됩니다. 먼저 지표를 포함할 하위 창을 만들어야 합니다. 여기서는 실용적인 이유로 이전에 사용했던 서브 윈도우 시스템을 사용하지는 않을 것입니다. 아마도 개념은 미래에 바뀔 것이지만 지금 시점에서는 Time & Trade가 지표 시스템과는 별도의 창에서 동작하도록 할 것입니다. 그러기 위해선 많은 사전 준비 작업이 필요합니다.

이제 새 지원 파일을 생성하는 것부터 시작하겠습니다. 이 파일을 생성하는 이유는 지표에 다른 이름을 지정하기 위해서 입니다. 파일 위에 파일을 만드는 대신 좀 더 우아한 작업을 수행해 보겠습니다. 더 많은 가능성을 위해 우리는 지금 지원 파일을 수정하고 있는 것입니다. 새 지원 파일은 아래와 같습니다:

#property copyright "Daniel Jose 07-02-2022 (A)"
#property version   "1.00"
#property description "This file only serves as supporting indicator for SubWin"
#property indicator_chart_window
#property indicator_plots 0
//+------------------------------------------------------------------+
input string user01 = "SubSupport";             //Short Name
//+------------------------------------------------------------------+
int OnInit()
{
        IndicatorSetString(INDICATOR_SHORTNAME, user01);
        
        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
        return rates_total;
}
//+------------------------------------------------------------------+


소스 파일에 적용해야 하는 변경 사항은 강조 표시했습니다. 이제 EA 코드를 변경해야 합니다. 새 클래스를 만듭니다.

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Terminal.mqh"
//+------------------------------------------------------------------+
class C_FnSubWin
{
        private :
                string  m_szIndicator;
                int             m_SubWin;
//+------------------------------------------------------------------+
                void Create(const string szIndicator)
                        {
                                int i0;
                                m_szIndicator = szIndicator;
                                if ((i0 = ChartWindowFind(Terminal.Get_ID(), szIndicator)) == -1)
                                        ChartIndicatorAdd(Terminal.Get_ID(), i0 = (int)ChartGetInteger(Terminal.Get_ID(), CHART_WINDOWS_TOTAL), iCustom(NULL, 0, "::" + def_Resource, szIndicator));
                                m_SubWin = i0;
                        }
//+------------------------------------------------------------------+
        public  :
//+------------------------------------------------------------------+
                C_FnSubWin()
                        {
                                m_szIndicator = NULL;
                                m_SubWin = -1;
                        }
//+------------------------------------------------------------------+
                ~C_FnSubWin()
                        {
                                Close();
                        }
//+------------------------------------------------------------------+
                void Close(void)
                        {
                                if (m_SubWin >= 0) ChartIndicatorDelete(Terminal.Get_ID(), m_SubWin, m_szIndicator);
                                m_SubWin = -1;
                        }
//+------------------------------------------------------------------+
inline int GetIdSubWinEA(const string szIndicator = NULL)
                        {
                                if ((szIndicator != NULL) && (m_SubWin < 0)) Create(szIndicator);
                                return m_SubWin;
                        }
//+------------------------------------------------------------------+
inline bool ExistSubWin(void) const { return m_SubWin >= 0; }
//+------------------------------------------------------------------+
};
//+------------------------------------------------------------------+


이 클래스는 C_SubWindow를 대체하며 차트에서 하위 창이 생성 되는 것을 지원합니다. 이 클래스의 작동 방식을 이해하려면 아래의 새로운 C_SubWindow 클래스를 간단히 살펴보십시오.

#include "C_ChartFloating.mqh"
#include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh>
//+------------------------------------------------------------------+
class C_SubWindow : public C_ChartFloating
{
//+------------------------------------------------------------------+
        private :
                C_FnSubWin      m_fnSubWin;
//+------------------------------------------------------------------+
        public  :
//+------------------------------------------------------------------+
                ~C_SubWindow()
                        {
                                Close();
                        }       
//+------------------------------------------------------------------+
                void Close(void)
                        {
                                m_fnSubWin.Close();
                                CloseAlls();
                        }
//+------------------------------------------------------------------+
inline int GetIdSubWinEA(void)
                        {
                                return m_fnSubWin.GetIdSubWinEA("SubWinSupport");
                        }
//+------------------------------------------------------------------+
inline bool ExistSubWin(void) const { return m_fnSubWin.ExistSubWin(); }
//+------------------------------------------------------------------+
};
//+------------------------------------------------------------------+


클래스에는 템플릿을 지원하는 데 사용할 지표의 정의가 포함되어 있다는 점을 유념하십시오. 이 부분은 위의 코드에서 강조 표시됩니다. 이제 까다로운 부분에 왔습니다. SubWinSupport대신 다른 이름을 사용하면 C_FnSubWin 클래스는 다른 지표를 검색합니다. 이러한 트릭을 사용하여 지표 파일이 생성 되는 것을 방지합니다. 원하는 지표의 숏 네임이 무엇인지 C_FnSubWin 클래스에 알려 주기만 하면 됩니다. 따라서 그저 Expert Advisor의 하위창을 만드는데 사용되는 불필요한 하위 창이나 지표 파일의 수에 제한을 받지 않게 됩니다.

그런 다음 C_TimeAndTrade 클래스를 생성하기 위한 과정으로 넘어갈 수 있습니다.


C_TimesAndTrade 클래스

C_TimesAndTrade 객체 클래스는 각각의 특정한 작업을 담당하는 몇 개의 작은 조각으로 구성됩니다. 아래 표시된 코드는 EA가 이 클래스를 호출하는 첫 번째 코드입니다:

void Init(const int iScale = 2)
{
        if (!ExistSubWin())
        {
                CreateCustomSymbol();
                CreateChart();
        }
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale)));
}

이 코드는 지원하는 하위 창이 있는지를 확인합니다. 하위창이 아직 존재하지 않는 경우 코드에서 생성합니다. 이제 클래스에 대한 다음 초기의 지원 코드를 살펴보십시오:

inline void CreateCustomSymbol(void)
{
        m_szCustomSymbol = "_" + Terminal.GetFullSymbol();
        SymbolSelect(Terminal.GetFullSymbol(), true);
        SymbolSelect(m_szCustomSymbol, false);
        CustomSymbolDelete(m_szCustomSymbol);
        CustomSymbolCreate(m_szCustomSymbol, StringFormat("Custom\\Robot\\%s", m_szCustomSymbol), Terminal.GetFullSymbol());
        CustomRatesDelete(m_szCustomSymbol, 0, LONG_MAX);
        CustomTicksDelete(m_szCustomSymbol, 0, LONG_MAX);
        SymbolSelect(m_szCustomSymbol, true);
};

이 코드는 사용자 지정 심볼을 만들고 해당 심볼 내의 모든 데이터를 재설정합니다. 우리가 만들려는 창에 심볼의 내용을 표시하려면 먼저 이 심볼이 시장 심도에 추가되어야 합니다. 이는 다음 라인에서 수행됩니다:

SymbolSelect(m_szCustomSymbol, true);

커스텀 심볼은Custom\Robot <Symbol name>에 생성됩니다.. 초기 데이터는 원래 심볼로부터 제공됩니다. 이는 다음 코드로 구현됩니다:

CustomSymbolCreate(m_szCustomSymbol, StringFormat("Custom\\Robot\\%s", m_szCustomSymbol), Terminal.GetFullSymbol());

기본적으로 그게 다입니다. EA에 클래스를 추가하고 다음과 같이 실행합니다:

// ... Expert Advisor code

#include <NanoEA-SIMD\Tape Reading\C_TimesAndTrade.mqh>

// ... Expert Advisor code

input group "Times & Trade"
input   int     user041 = 2;    //Escala
//+------------------------------------------------------------------+
C_TemplateChart Chart;
C_WallPaper     WallPaper;
C_VolumeAtPrice VolumeAtPrice;
C_TimesAndTrade TimesAndTrade;
//+------------------------------------------------------------------+
int OnInit()
{
// ... Expert Advisor code

        TimesAndTrade.Init(user041);
        
        OnTrade();
        EventSetTimer(1);
   
        return INIT_SUCCEEDED;
}


결과는 다음과 같습니다:


그러면 정확히 예상했던 대로입니다. 이제 수행된 거래의 값들을 _DOLH22 차트에 추가해 보겠습니다. 이 차트는 수행된 모든 거래를 반영한 Times & Trade이 그래픽으로 나타나도록 합니다. 그래픽은 일본식 캔들 패턴의 형태로 진행됩니다. 이 패턴이 사용하기 쉽기 때문입니다. 이에 앞서 몇 가지 작업, 특히 심볼을 연결하고 동기화해야 합니다. 이는 다음 코드에서 수행됩니다:

inline void Connect(void)
{
        switch (m_ConnectionStatus)
        {
                case 0:
                        if (!TerminalInfoInteger(TERMINAL_CONNECTED)) return; else m_ConnectionStatus = 1;
                case 1:
                        if (!SymbolIsSynchronized(Terminal.GetFullSymbol())) return; else m_ConnectionStatus = 2;
                case 2:
                        m_LastTime = TimeLocal();
                        m_MemTickTime = macroMinusMinutes(60, m_LastTime) * 1000;
                        m_ConnectionStatus = 3;
                default:
                        break;
        }
}

이 함수는 터미널이 연결되어 있는지 확인한 다음 심볼을 동기화합니다. 이후 우리는 값을 캡처하기 시작할 수 있고 화면에 표시할 수 있습니다. 하지만 이를 위해서는 초기화 코드를 약간 변경해야 합니다. 변경 사항은 다음 코드에서 강조 표시되어 있습니다:

void Init(const int iScale = 2)
{
        if (!ExistSubWin())
        {
                CreateCustomSymbol();
                CreateChart();
                m_ConnectionStatus = 0;
        }
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale)));
}

그 후 캡처 함수를 볼 수 있습니다.

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

        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++)
                {
                        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;
                        p2++;
                        c1++;
                        m_LastTime += 60;
                }
                CustomRatesUpdate(m_szCustomSymbol, Rates, p2);
                m_MemTickTime = Tick[i0 - 1].time_msc;
        }
}

위의 함수를 사용하면 하나의 빠짐도 없는 모든 거래 틱을 캡처하고 이들이 매도 틱인지 또는 매수 틱인지를 확인할 수 있습니다. 이러한 틱이 BID 또는 ASK의 변경과 관련된 경우 즉 거래량이 없게 되는 경우 정보가 저장되지 않습니다. 이러한 현상은 직접 주문인 경우에도 발생합니다. 가격을 특정 값으로 강제하여 내어 직접 주문이 체결되도록 하는 시장 참가자가 내는 직접 주문인 경우에는 이들 주문이 가격 움직임에 영향을 미치지 않습니다. 그러나 이들 주문이 체결된 후 얼마 지나지 않아 가격이 자유롭게 움직이게 됩니다. BID 및 ASK를 변경 시키는 이러한 틱은 전체 시스템을 고려 할 때 역시 중요하기 때문에 다음 기사에서 다룰 다른 버전에서 사용됩니다. 트랜잭션 유형을 확인한 후 매우 중요한 일련의 라인이 있습니다. 아래 코드의 이러한 줄은 분석 시스템을 통과하고 저장되는 각 틱당 하나의 캔들을 만듭니다.

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;

캔들의 고가와 저가는 거래 시점의 스프레드를 나타냅니다. 즉 BID와 ASK 사이에 존재하는 값은 생성된 캔들의 그림자가 되고 캔들의 시가는 거래가 발생한 가격입니다. 실제로 완료되었습니다. 이제 강조 표시된 코드 라인을 자세히 살펴보십시오. 거래 틱의 경우 거래량이 있습니다. 이 선은 스케일 오버플로우 되지 않도록 하기 위해 해당 거래량을 약간 조정합니다. 여러분 마음대로 자산에 따른 여러분의 자체 분석에 따라 값을 조정할 수 있습니다.

이제 마지막 세부 사항 - 시간. 각 캔들은 1분에 해당합니다. 그 아래 값을 표시할 수 없기 때문입니다. 그런 다음 각각의 캔들은 매분 해당 위치에 유지됩니다. 이것은 실시간이 아니라 가상의 시간입니다. 거래 시간을 그래픽 시간과 혼동하지 마십시오: 작업은 밀리초 단위로 발생할 수 있지만 그래픽 정보는 매분 그래픽 스케일로 표시됩니다. 우리는 다른 값을 사용할 수 있지만 가능한 가장 작은 값으로 할 것이므로 프로그래밍을 크게 단순화합니다. 이 시스템의 결과는 다음과 같습니다:

이제 읽기가 가능하고 따라서 이를 해석하는 것도 간단해진다는 것을 알 수 있습니다. 캡쳐 당시 주문테이프가 엄청 느렸지만 아이디어를 얻기에는 충분하다고 생각합니다.

이 시스템에 대한 최종 정보는 아래 그림에서 볼 수 있습니다:

시스템에서 볼 수 있는 네 가지의 구성이 있다는 점에 유의하십시오. 이들 구성이 무엇을 위해 필요할까요? 다음번 기사는 Times & Trade의 구성이 4개인 이유를 이해하는 데 도움이 되는 기사입니다. 어쨌든 우리는 사용하기에 충분한 작동하는 시스템을 이미 가지고 있습니다. 그러나 진행 상황과 4개의 캔들 패턴이 생성되는 원인을 이해하면 이 시스템에서 더 많은 것을 얻을 수 있으며 누가 알겠습니까? 이것이 주요 지표가 될 지도 모릅니다.....


결론

우리는 테이프 읽기를 분석하기 위해 EA에서 사용할 Times & Trade 시스템을 만들었습니다. 이 시스템은 MetaTrader 5에 있는 시스템과 동일한 분석 속도를 제공해야 합니다. 우리는 엄청난 양의 숫자와 값을 읽고 이해하려고 노력하는 대신 차트 시스템을 만들어서 이를 달성했습니다. 다음 기사에서는 시스템에 누락된 정보를 구현합니다. Expert Advisor의 코드에 몇 가지 새로운 요소를 추가해야 할 것입니다.



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

파일 첨부됨 |
EA_-_Times_e_Trade.zip (5982.95 KB)
MQL5에서 행렬 및 벡터 MQL5에서 행렬 및 벡터
특수한 데이터 유형인 '매트릭스' 및 '벡터'를 사용하여 수학적 표기법에 매우 가까운 코드를 생성할 수 있습니다. 이러한 메서드를 사용하면 중첩된 루프를 만들거나 계산시 배열의 올바른 인덱싱을 염두에 둘 필요가 없습니다. 따라서 행렬 및 벡터 메서드를 사용하면 복잡한 프로그램을 개발할 때 안정성과 속도가 향상됩니다.
MQL5에서 행렬 및 벡터 연산 MQL5에서 행렬 및 벡터 연산
효율적인 연산을 위해 수학적인 솔루션과 함께 행렬과 벡터가 MQL5에 도입되었습니다. 새로운 유형은 수학적인 표기법에 가까운 간결하고 이해하기 쉬운 코드를 생성하도록 하는 기본 메서드를 제공합니다. 배열은 광범위한 기능을 제공하지만 행렬이 훨씬 더 효율적인 경우가 많습니다.
데이터 과학 및 머신 러닝(파트 04): 현재 주식 시장 붕괴 예측 데이터 과학 및 머신 러닝(파트 04): 현재 주식 시장 붕괴 예측
이 기사에서는 로지스틱 모델을 사용하여 미국 경제의 펀더멘털을 기반으로 주식 시장 폭락을 예측하려고 합니다. NETFLIX와 APPLE은 우리가 집중해서 볼 주식입니다. 이전의 2019년과 2020년의 시장 폭락을 통해 우리 모델이 현재의 암울한 상황에서 어떻게 작동하는지를 알아 봅시다.
누적/분배(Accumulation/Distribution (AD))에 기반한 거래 시스템을 설계하는 방법 누적/분배(Accumulation/Distribution (AD))에 기반한 거래 시스템을 설계하는 방법
이 글은 가장 인기 있는 기술 지표를 기반으로 거래 시스템을 설계하는 방법에 대한 시리즈의 새로운 글입니다. 이 글에서는 누적/분배 지표라는 새로운 기술 지표에 대해 배우고 간단한 AD 거래 전략을 기반으로 하여 MQL5 거래 시스템을 설계하는 방법에 대해 알아봅니다.