English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
preview
Expert Advisor 개발 기초부터(29부): 대화형 플랫폼

Expert Advisor 개발 기초부터(29부): 대화형 플랫폼

MetaTrader 5 | 7 10월 2024, 12:31
181 0
Daniel Jose
Daniel Jose

소개

Expert Advisor를 더 재미있게 만들면 어떨까요? 금융 시장 트레이딩은 너무 지루하고 단조로운 경우가 많지만 우리는 덜 지루하게 만들 수 있습니다. 이 프로젝트는 중독 증세가 있는 사람들에게는 위험할 수 있다는 점에 유의하세요. 하지만 일반적인 경우에는 지루함을 덜 느끼게 해줄 것입니다.

경고: 시장이 도박과 같은 것이라고 생각하신다면 이 문서에 제공된 수정 방법을 사용하지 마세요. 매우 큰 손실이 발생할 위험이 있습니다.

위의 경고가 농담처럼 들리실지 모르지만 사실 EA를 일부 수정하는 것이 도박에 중독된 사람들을 위험하게 할 수 있습니다.

이번에 변경되는 사항 중 일부는 EA의 전반적인 안정성과 성능을 개선하기 위한 것입니다. 만약 여러분이 이 글에서 삭제되는 내용 중 일부를 유지하고 싶다면 어렵지 않습니다. EA에 생성되어 있는 주문 시스템 덕분에 일부 항목은 손상 없이 제거될 수 있습니다. 따라서 어느 것을 수락하고 사용할지 아니면 삭제할지는 전적으로 회원님의 선택에 달려 있습니다.


2.0. 차트 트레이드 삭제

차트 트레이드는 EA에서 사용하는 것보다 덜 복잡한 간단한 주문 시스템에서 여전히 의미가 있는 기능입니다. 그러나 현재 개발 단계에 있는 EA의 경우 차트에 차트 트레이드가 있는 것이 말이 되지 않으므로 우리는 제거할 것입니다. 원하는 경우 명령어 하나만 편집하여 유지할 수 있습니다. 사실 저는 변경이 필요할 때 나중에 매우 빠르게 변경(또는 변경하지 않음)하기 위해 작업을 단순하게 유지하는 것을 좋아합니다. 변경으로 인해 중요한 지점에서 문제나 치명적인 실패와 같은 스트레스가 발생하지 않도록 말입니다.

EA를 매우 빠르고 안전하게 제어하기 위해 EA 코드에 다음과 같은 정의가 추가되었습니다:

#define def_INTEGRATION_CHART_TRADER            // Chart trader integration with the EA ...

이 정의가 존재하지 않거나 주석이 되면 차트 트레이드는 EA와 함께 컴파일 되지 않습니다. 이 정의의 영향을 받는 지점을 살펴보겠습니다. 첫 번째 이자 가장 확실한 것은 다음과 같습니다:

#ifdef def_INTEGRATION_CHART_TRADER
        #include <NanoEA-SIMD\SubWindow\C_TemplateChart.mqh>
#endif 

위의 코드는 EA 파일이 아니라 C_IndicatorTradeView.mqh 파일에 있지만 컴파일러는 코드의 모든 곳에서 정의를 볼 수 있으므로 코드 수정에 대해 걱정할 필요가 없습니다. 우리는 쉽게 액세스할 수 있는 위치(이 경우 EA 코드)에 정의를 생성하고 필요한 곳에 사용하기만 하면 됩니다.

C_IndicatorTradeView.mqh 파일로 계속 진행하겠습니다. 우리는 차트 트레이드 없이 EA를 컴파일할 수 있으므로 아래 이미지에서 볼 수 있는 EA 초기화 메시지 상자에 정의된 데이터에 대한 액세스를 구현해야 합니다:

이 데이터에 액세스해야 한다는 점을 기억하세요. 이전에는 차트 트레이드에 전달했고 정보가 필요할 때는 차트 트레이드에 알아봤습니다. 하지만 이제 차트 트레이드가 없을 경우 우리는 동일한 데이터에 액세스하려면 다른 방법을 사용해야 합니다.

C_IndicatorTradeView.mqh 파일에서 이 값들은 펜딩 주문의 위치를 표시하는 인디케이터 0을 생성할 때 한 곳에서만 사용됩니다. 이 위치는 DispatchMessage 함수 안에 있습니다. 아래 코드에 표시되어 있습니다:

// ... Previous code ...

                                        case CHARTEVENT_MOUSE_MOVE:
                                                Mouse.GetPositionDP(dt, price);
                                                mKeys   = Mouse.GetButtonStatus();
                                                bEClick  = (mKeys & 0x01) == 0x01;    //Left mouse click
                                                bKeyBuy  = (mKeys & 0x04) == 0x04;    //SHIFT pressed
                                                bKeySell = (mKeys & 0x08) == 0x08;    //CTRL pressed
                                                if (bKeyBuy != bKeySell)
                                                {
                                                        if (!bMounting)
                                                        {
#ifdef def_INTEGRATION_CHART_TRADER
                                                                m_Selection.bIsDayTrade = Chart.GetBaseFinance(m_Selection.vol, valueTp, valueSl);
#else 
                                                                m_Selection.vol = EA_user20 * Terminal.GetVolumeMinimal();
                                                                valueTp = EA_user21;
                                                                valueSl = EA_user22;
                                                                m_Selection.bIsDayTrade = EA_user23;
#endif 
                                                                valueTp = Terminal.AdjustPrice(valueTp * Terminal.GetAdjustToTrade() / m_Selection.vol);
                                                                valueSl = Terminal.AdjustPrice(valueSl * Terminal.GetAdjustToTrade() / m_Selection.vol);
                                                                m_Selection.it = IT_PENDING;
                                                                m_Selection.pr = price;
                                                        }

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

강조 표시된 줄에 주목하세요. 파일 내부에서 이 EA_userXX 값을 검색할 필요가 없습니다 왜냐하면 다음과 같이 EA 코드에서 나온 값이기 때문입니다:

#ifdef def_INTEGRATION_CHART_TRADER
        input group "Chart Trader"
#else 
        input group "Base Operacional do EA"
#endif 
input int       EA_user20   = 1;     //Levering factor
input double    EA_user21   = 100;   //Take Profit (financial)
input double    EA_user22   = 81.74; //Stop Loss (financial)
input bool      EA_user23   = true;  //Day Trade ?

이것만으로도 차트에 차트 트레이드가 있는 것과 유사한 제어 기능을 제공합니다. 실제로는 우리가 코드에서 아무것도 변경하지 않는다는 점에 유의하세요. 우리는 정의한 필수 데이터를 올바른 위치로 이동하기만 하면 됩니다. 어떤 사람들은 EA를 로드 할 때 트레이더로서 보면 이러한 구성이 불필요하다고 생각할 수 있습니다. 주문 시스템에서 모든 변수를 어려움 없이 구성할 수 있기 때문에 어떤 측면에서 이는 사실입니다. 따라서 우리는 레버리지 계수의 최소값과 손절매 및 이익실현을 0으로 설정하고 초기 작업은 데이 트레이드로 설정하면 됩니다 - C_IndicatorTradeView 클래스의 DispatchMessage 함수에서 이 작업을 수행하면 됩니다. 이는 시스템에는 전혀 영향을 미치지 않습니다. 왜냐하면 트레이더가 차트에서 주문을 변경한 다음 서버로 전송할 수 있기 때문입니다. 이러한 유형의 수정은 매우 개인에 따라 재각각이므로 여러분의 선택에 달려 있습니다.


2.0.1. 일부 조정 사항

차트 트레이드를 제거하는 부분으로 돌아가기 전에 EA 전체의 안정성을 개선하기 위해 한 가지 더 해야 할 일이 있습니다.

다음을 수행해 보겠습니다. C_IndicatorTradeView 클래스에서 우리는 아래와 같이 비공개 데이터 구조를 정의합니다:

struct st01
{
        bool    ExistOpenPosition,
                SystemInitilized;
}m_InfoSystem;

이 부분은 다음 코드에서 초기화해야 합니다:

void Initilize(void)
{
        static int ot = 0, pt = 0;
                                
        m_InfoSystem.ExistOpenPosition = false;
        m_InfoSystem.SystemInitilized = false;
        ChartSetInteger(Terminal.Get_ID(), CHART_SHOW_TRADE_LEVELS, false);
        ChartSetInteger(Terminal.Get_ID(), CHART_DRAG_TRADE_LEVELS, false);                             
        if ((ot != OrdersTotal()) || (pt != PositionsTotal()))
        {
                ObjectsDeleteAll(Terminal.Get_ID(), def_NameObjectsTrade);
                ChartRedraw();
                for (int c0 = ot = OrdersTotal(); c0 >= 0; c0--)  IndicatorAdd(OrderGetTicket(c0));
                for (int c0 = pt = PositionsTotal(); c0 >= 0; c0--) IndicatorAdd(PositionGetTicket(c0));
        }
        m_InfoSystem.SystemInitilized = true;
}

이 데이터를 여기에서 생성하고 초기화하는 이유는 무엇일까요? MetaTrader 5는 EA에 이벤트를 전송하며 이들 이벤트 중 하나가 OnTick이라는 것을 기억하세요. 간단한 시스템에는 문제가 많지 않습니다. 하지만 시스템이 더 복잡해지게 되면 우리는 모든 것이 제대로 작동하는지 확인해야 합니다. EA가 이러한 이벤트를 처리할 준비가 되기 전에 MetaTrader 5가 이벤트를 EA로 전송하는 경우가 발생할 수 있습니다. 따라서 우리는 EA가 준비되었는지 확인해야 합니다/ 우리는 EA의 준비 상태를 나타내는 몇 가지 변수를 만들 것입니다. 아직 준비되지 않은 경우 EA가 이벤트에 적절히 대응할 수 있을 때까지 MetaTrader 5의 이벤트는 무시되어야 합니다.

가장 중요한 포인트는 아래 코드에서 확인할 수 있습니다:

inline double SecureChannelPosition(void)
                        {
                                static int nPositions = 0;
                                double Res = 0;
                                ulong ticket;
                                int iPos = PositionsTotal();
                                
                                if (!m_InfoSystem.SystemInitilized) return 0;
                                if ((iPos != nPositions) || (m_InfoSystem.ExistOpenPosition))
                                {
                                        m_InfoSystem.ExistOpenPosition = false;
                                        for (int i0 = iPos - 1; i0 >= 0; i0--) if (PositionGetSymbol(i0) == Terminal.GetSymbol())
                                        {
                                                m_InfoSystem.ExistOpenPosition = true;
                                                ticket = PositionGetInteger(POSITION_TICKET);
                                                if (iPos != nPositions) IndicatorAdd(ticket);
                                                SetTextValue(ticket, IT_RESULT, PositionGetDouble(POSITION_VOLUME), Res += PositionGetDouble(POSITION_PROFIT), PositionGetDouble(POSITION_PRICE_OPEN));
                                        }
                                        nPositions = iPos;
                                }
                                return Res;
                        };

강조 표시된 포인트는 이전에는 존재하지 않았기 때문에 가끔 에러가 발생할 수 있었습니다. 하지만 이제는 비정상적인 일이 발생하지 않도록 필요한 점검을 하고 있습니다.

여러 번 확인하면 시스템이 매우 안정적일 수 있지만 코드 유지 관리 및 수정 작업이 복잡해질 수 있기 때문에 모든 것을 확인하는 것은 매우 복잡합니다. 일부 검사는 논리적인 순서로 수행해야 실제로 효과적이기 때문에 비용이 다소 많이 드는 작업입니다.

하지만 EA가 모니터링하는 종목의 포지션이 있는지 여부를 확인하면 어느 정도 민첩성을 발휘할 수 있습니다. 더구나 여러 자산을 거래할 때 각각 특정 수의 포지션이 EA에 표시되는 경우 더욱 그렇습니다. 우리는 필터링을 통해 루프를 제거하여 EA가 실제로 필요할 때만 루프 내부의 코드를 실행하도록 할 것입니다. 그렇지 않으면 EA가 소비하는 처리 시간이 약간 줄어듭니다. 큰 차이는 아니지만 매우 극단적인 경우에는 큰 차이를 만들 수 있습니다.


2.0.2. EA에서 차트 트레이드 제거하기

우리는 C_IndicatorTradeView 클래스를 변경했습니다. 이제 EA 코드에 집중하고 차트 트레이드를 삭제할 수 있습니다. 가장 먼저 해야 할 일은 OnInit 코드에서 삭제하는 것입니다:

int OnInit()
{       
        Terminal.Init();

#ifdef def_INTEGRATION_WITH_EA
        WallPaper.Init(user10, user12, user11);
        VolumeAtPrice.Init(user32, user33, user30, user31);
        TimesAndTrade.Init(user41);
        EventSetTimer(1);
#endif 

        Mouse.Init(user50, user51, user52);
        
#ifdef def_INTEGRATION_CHART_TRADER
        static string   memSzUser01 = "";
        if (memSzUser01 != user01)
        {
                Chart.ClearTemplateChart();
                Chart.AddThese(memSzUser01 = user01);
        }
        Chart.InitilizeChartTrade(EA_user20 * Terminal.GetVolumeMinimal(), EA_user21, EA_user22, EA_user23);
        TradeView.Initilize();
        OnTrade();
#else 
        TradeView.Initilize();
#endif 
   
        return INIT_SUCCEEDED;
}

녹색 코드가 파란색 코드로 바뀝니다. 차트 트레이드를 사용하지 않으면 차이가 작아 보일수도 있습니다. 실행 파일 크기만 변경된 것처럼 보일 수 있습니다. 하지만 그 뿐만이 아닙니다. 차트 트레이드 코드와 더불어 OnTrade 이벤트도 삭제되었습니다. EA는 더 이상 이 이벤트를 처리하지 않습니다.

여러분은 제가 무언가 잘못하고 있다고 생각할 수도 있습니다. EA에서 OnTrade 이벤트를 제거할 수 있었을까요? 이제 거래 이벤트는 어떻게 처리하나요? 이러한 이벤트는 OnTradeTransaction 이벤트에 의해 처리됩니다. 처리 방식이 OnTrade보다 효율적이므로 EA가 더 간단하고 안정적입니다.

또 다른 변경이 일어나는 부분이 있습니다:

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
        Mouse.DispatchMessage(id, lparam, dparam, sparam);
#ifdef def_INTEGRATION_WITH_EA
        switch (id)
        {
                case CHARTEVENT_CHART_CHANGE:
                        Terminal.Resize();
                        WallPaper.Resize();
                        TimesAndTrade.Resize();
        break;
        }
        VolumeAtPrice.DispatchMessage(id, sparam);
#endif 

#ifdef def_INTEGRATION_CHART_TRADER
        Chart.DispatchMessage(id, lparam, dparam, sparam);
#endif 

        TradeView.DispatchMessage(id, lparam, dparam, sparam);  
}

EA 내에 다른 관련 부분이 없는 경우 컴파일 되는 줄은 강조 표시된 줄 뿐입니다. 이러한 이벤트는 상당히 일정한 경향이 있기 때문에(이벤트 처리가 효율적일수록 좋습니다) MetaTrader 5에서 EA가 처리하도록 트리거하는 다른 이벤트와 경쟁하는 경우가 많습니다. 이 다른 이벤트는 아래와 같습니다:

void OnTick()
{
#ifdef def_INTEGRATION_CHART_TRADER
        Chart.DispatchMessage(CHARTEVENT_CHART_CHANGE, 0, TradeView.SecureChannelPosition(), C_Chart_IDE::szMsgIDE[C_Chart_IDE::eRESULT]);
#else 
        TradeView.SecureChannelPosition();
#endif 

#ifdef def_INTEGRATION_WITH_EA
        TimesAndTrade.Update();
#endif 
}

이러한 이벤트는 일반적으로 여러 번 호출되고 경우에 따라 1초 이내에 여러 번 호출될 수 있기 때문에 정말 악몽과도 같습니다. 하지만 C_IndicatorTradeView 클래스의 코드를 변경한 덕분에 이 이벤트의 처리가 조금 더 효율적이 되었습니다. 나중에 우리는 효율성을 더욱 개선할 예정이지만 지금은 이 정도면 충분합니다.

이러한 모든 변경 사항 이후에는 차트 트레이드가 EA에 통합되지 않습니다. 차트 트레이드를 지표로 전환하면 EA는 주문 시스템 처리, 포지셔닝 및 지원이라는 주요 기능에 집중하게 됩니다. 하지만 차트 트레이드를 지표로 옮기려면 몇 가지 추가적인 변경이 필요합니다. 이 부분은 여기서 설명하지 않고 나중에 다시 설명하겠습니다. 하지만 일반적으로 차트 트레이드를 지표로 이동하고 이를 통해 주문을 보낼 수 있습니다.


3.0. 사운드 추가하기

종종 우리는 차트를 보지 않으면서 현재 무슨 일이 일어나고 있는지 알고 싶어합니다. 알림을 받는 방법 중 하나는 소리로 알림을 받는 것입니다. 이 알림은 즉시 주의를 끌기 때문에 가장 좋은 알림 유형 중 하나입니다. 때로는 다른 메시지를 확인할 필요 없이 알림을 듣는 것만으로도 어떠한 행동을 해야 할지 결정할 때가 있습니다.

이제 몇 가지 기본적인 소리 알림을 설정하는 방법을 배워보겠습니다. 경우에 따라서는 알림에 대한 구체적인 내용을 알려주는 내용이 될 수도 있습니다. 지금 보여드리는 내용과 첨부 파일에 있는 내용은 기본적인 기능만 제공하지만 기존 알림 및 경고의 양을 늘려서 메시지를 읽는 데 시간을 낭비하지 않도록 할 수 있습니다. 소리는 특정 거래 순간에 우리의 민첩성을 높일 수 있는 특정 이벤트를 알려줄 수 있습니다. 정말 많은 차이가 있습니다.

가장 먼저 할 일은 새 클래스를 포함하고 사운드 시스템을 지원 및 격리할 새 파일을 만드는 것입니다. 이 작업이 완료되면 매우 안정적인 방식으로 개발을 시작할 수 있습니다. 전체 클래스는 아래 코드에서 확인할 수 있습니다:

class C_Sounds
{
        protected:
                enum eTypeSound {TRADE_ALLOWED, OPERATION_BEGIN, OPERATION_END};
        public  :
//+------------------------------------------------------------------+
inline bool PlayAlert(const int arg)
                {
                        return PlaySound(StringFormat("NanoEA-SIMD\\RET_CODE\\%d.wav", arg));
                }
//+------------------------------------------------------------------+
inline bool PlayAlert(const eTypeSound arg)
                {
                        string str1;
        
                        switch (arg)
                        {
                                case TRADE_ALLOWED   : str1 = def_Sound00; break;
                                case OPERATION_BEGIN : str1 = def_Sound01; break;
                                case OPERATION_END   : str1 = def_Sound02; break;
                                defaultreturn false;
                        }
                        PlaySound("::" + str1);
                        
                        return true;
                }
//+------------------------------------------------------------------+
};

이 코드의 극도의 단순함에도 불구하고 흥미로운 점이 있습니다. 우리는 PlayAlert 함수를 재작성 하고 있으므로 우리에게는 동일한 함수의 두 가지 버전이 있습니다. 무엇을 위해서일까요? 사운드 시스템이 작동하는 방식에는 두 가지 변형이 필요합니다. 첫 번째 버전의 함수의 경우 파일에서 사운드를 재생하고 두 번째 버전에서는 EA의 일부인 사운드 즉 사운드 함수를 활용합니다. 이제 많은 사람들이 어떻게 해야 할지 모르는 부분이 있습니다: 오디오 파일에서 직접 소리를 재생하는 방법입니다. 방법을 알려드릴 테니 걱정하지 마세요. 첫 번째 버전을 사용하는 이유는 일부 사용자가 자신의 목소리나 다른 소리를 알림으로 설정하고 EA를 다시 컴파일할 필요 없이 언제든지 변경하고 싶을 수 있기 때문입니다. 실제로 EA가 MetaTrader 5에서 실행 중일 때도 이러한 사운드를 변경할 수 있습니다. 사운드가 재생되는 순간부터 EA는 최신 버전을 사용하므로 한 오디오 파일을 다른 파일로 교체하기만 하면 되며 EA는 그 차이를 알아차리지 못합니다. 그러나 EA 코드에서 알 수 있는 또 다른 이유가 있습니다.

실제로 첫 번째 옵션은 아래 강조 표시된 클래스 코드에서 볼 수 있듯이 다소 구체적인 위치에서 사용됩니다:

class C_Router
{
        protected:
        private  :
                MqlTradeRequest TradeRequest;
                MqlTradeResult  TradeResult;
//+------------------------------------------------------------------+
inline bool Send(void)
        {
                if (!OrderSend(TradeRequest, TradeResult))
                {
                        if (!Sound.PlayAlert(TradeResult.retcode))Terminal.MsgError(C_Terminal::FAILED_ORDER, StringFormat("Error Number: %d", TradeResult.retcode));
                        
                        return false;
                }
                return true;
        }

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

거래 서버에서 반환되는 모든 오류를 처리하는 데 필요한 작업량을 상상해 보세요. 그러나 오디오 파일을 녹음하고 거래 서버가 반환하는 값에 따라 이름을 지정하면 EA가 어떤 파일을 재생할지 알 수 있으므로 이 과정이 크게 간소화됩니다. 여기서 우리는 서버가 반환한 값에 따라 사용할 파일만 지정하면 되므로 EA가 이 파일을 찾아서 재생하고 경고음이나 음성 메시지를 표시하여 줍니다 멋지지 않나요? 이제 예를 들어 주문이 거부되면 플랫폼에서 어떤 일이 발생했는지 또는 무엇이 잘못되었는지 매우 명확한 방식으로 알려주게 되는 것입니다. 이는 시장에서 나만의 무언가를 고유하게 나타내는 매우 적절한 방식입니다. 오디오 파일을 통해 여러분은 문제를 해결하는 방법을 명확하게 알 수 있습니다. 이를 통해 우리가 얼마나 민첩하게 대응할 수 있는지 확인해 보세요.

또한 실행 가능한 EA 파일 안에 사운드가 저장되는 두 번째 작동 방식도 있습니다. 이것은 동일한 함수의 두 번째 버전으로 이 단계에서는 3가지 다른 유형의 이벤트를 나타내기 위해 함수가 3가지 다른 위치에서 사용됩니다. 첫 번째 위치는 아래 코드에서 확인할 수 있습니다:

int OnInit()
{
        if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
        {
                Sound.PlayAlert(C_Sounds::TRADE_ALLOWED);
                return INIT_FAILED;
        }
        
        Terminal.Init();

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

이 코드는 플랫폼에서 알고 트레이딩이 활성화되어 있는지 확인합니다. 우리가 EA를 활성화하는 것을 잊어버린 경우 EA에서 거래할 수 없다는 메시지가 표시됩니다. 옵션이 활성화되어 있는지 확인하려면 다음 이미지와 같이 플랫폼에서 마커를 확인하면 됩니다:


보조 사운드를 사용할 두 번째 위치는 아래와 같습니다:

void CreateIndicator(ulong ticket, eIndicatorTrade it)
{
        string sz0;
                                
        switch (it)
        {
                case IT_TAKE    : macroCreateIndicator(it, clrForestGreen, clrDarkGreen, clrNONE); break;
                case IT_STOP    : macroCreateIndicator(it, clrFireBrick, clrMaroon, clrNONE); break;
                case IT_PENDING:
                        macroCreateIndicator(it, clrCornflowerBlue, clrDarkGoldenrod, def_ColorVolumeEdit);
                        m_BtnCheck.Create(ticket, sz0 = macroMountName(ticket, it, EV_CHECK), def_BtnCheckEnabled, def_BtnCheckDisabled);
                        m_BtnCheck.SetStateButton(sz0, true);
                        macroInfoBase(IT_PENDING);
                        break;
                case IT_RESULT  :
                        macroCreateIndicator(it, clrSlateBlue, clrSlateBlue, def_ColorVolumeResult);
                        macroInfoBase(IT_RESULT);
                        Sound.PlayAlert(C_Sounds::OPERATION_BEGIN);
                        m_InfoSystem.ExistOpenPosition = true;
                        break;
        }
        m_BtnClose.Create(ticket, macroMountName(ticket, it, EV_CLOSE), def_BtnClose);
}

포지션 지표가 생성될 때마다 소리가 재생됩니다. 이렇게 하면 우리는 펜딩 중인 주문이 진입이 되었음을 알 수 있고 주의를 기울여야 한다는 것을 알 수 있으므로 우리의 트레이딩은 훨씬 쉬워집니다.

보조 사운드가 나오는 세 번째 이자 마지막 시점은 어떤 이유로든 포지션이 청산될 때입니다. 이것은 매우 특정한 위치에서 이루어집니다:

inline void RemoveIndicator(ulong ticket, eIndicatorTrade it = IT_NULL)
{
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
        if ((it == IT_NULL) || (it == IT_PENDING) || (it == IT_RESULT))
        {
                if (macroGetPrice(ticket, IT_RESULT, EV_LINE) > 0) Sound.PlayAlert(C_Sounds::OPERATION_END);
                ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, (ticket > 1 ? '*' : def_SeparatorInfo)));
        } else ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, def_SeparatorInfo, (char)it));
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
        m_Selection.ticket = 0;
        Mouse.Show();
        ChartRedraw();
}

EA를 제거하면 포지션 청산음이 재생될 것이라고 생각할 수 있지만 그렇지 않습니다. 가격선은 여전히 시스템에 존재하기 때문에 이런 일은 일어나지 않습니다. 그러나 포지션이 청산되면 다른 상황이 발생하고 포지션 가격선은 가격 레벨 0이 되며 이 때 포지션이 청산되었음을 알리는 소리가 재생됩니다.

EA의 리소스인 사운드는 실행 파일이 어디로 이동하든 따라다니며 코드를 다시 컴파일하지 않고는 수정할 수 없기 때문에 더 제한적이지만 동시에 오디오 파일을 가져갈 필요 없이 EA를 다른 곳으로 이식하는 데 도움이 됩니다.

그러나 장애나 오류를 알리는 데 사용되는 사운드의 경우 로직이 다르므로 별도로 이동하여 필요할 때 작동할 수 있도록 미리 정해진 위치에 배치해야 합니다.

첨부 파일에는 SOUNDS라는 폴더가 있습니다. 이 폴더에 포함된 사운드는 재생되지 않으므로 이 폴더를 코드가 있는 폴더에 두지 마세요. 쉽게 찾을 수 있는 다른 위치로 옮겨야 합니다. 위치를 모르더라도 걱정하지 마세요. 나중에 알려드리겠습니다:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
void OnStart()
{
        Print(TerminalInfoString(TERMINAL_PATH));
}
//+------------------------------------------------------------------+

이 스크립트를 실행하면 툴바에 사용할 위치를 나타내는 정보가 표시됩니다. 실행 결과의 예는 아래 이미지에 나와 있습니다:

여러분은 다음을 수행해야 합니다:

  1. 첨부 파일 열기
  2. 파일 탐색기 열기
  3. 위 그림에 표시된 폴더로 이동합니다.
  4. 첨부된 파일에서 위에 표시된 폴더로 SOUNDS 폴더의 내용을 복사합니다.
  5. 원하는 경우 이 세 파일(WARRING, BEGIN, END)은 EA와 함께 컴파일 되므로 삭제할 수 있습니다.
  6. 원하는 경우 .WAV의 내용을 여러분이 원하는 것으로 변경할 수 있지만 이름을 변경하지 않도록 주의하세요.
  7. MetaTrader 5 플랫폼에서 EA를 사용하세요 그리고 행복하세요!
그러나 사운드(경고, 시작, 종료)가 EA에서 컴파일 되려면 MQL5 코드 디렉터리에 동일한 사운드가 있는 SOUNDS 폴더가 있어야 하며 그렇지 않으면 사운드는 EA 코드에 통합되지 않는다는 점을 기억하세요.


결론

이 문서에서는 EA 시스템에 사용자 지정 사운드를 추가하는 방법을 배웠습니다. 여기에서 저는 매우 간단한 시스템을 사용하여 이 작업을 수행하는 방법을 보여드렸지만 EA에만 국한되지 않고 지표나 스크립트에서도 사용할 수 있습니다.

여기서 살펴본 것과 같은 개념과 아이디어를 사용하면 무언가에 대해 경고하는 음성 메시지를 녹음할 수 있다는 점이 가장 큰 장점입니다. 그리고 EA 또는 MetaTrader 5에서 실행 중이고 사운드 시스템을 사용하는 다른 프로세스가 이글에서 살펴본 트리거를 통해 활성화되면 우리는 이미 정해진 방식에 따라 정해진 어떤 종류의 작업에 대해 알려주거나 경고하는 사운드 메시지를 받게 됩니다.

그리고 이것은 텍스트가 아니라 음성 메시지이므로 시스템을 사용하는 모든 사람에게 무엇을 해야 하는지 또는 그러한 메시지를 생성한 원인이 무엇인지 신속하게 설명할 수 있습니다. 그러므로 훨씬 더 효과적입니다.

이 시스템은 이러한 사용 예에 국한되지 않으며 여기에 설명된 것 이상으로 확장할 수 있습니다. 사용자가 플랫폼에서 동맹을 맺을 수 있도록 하는 것이 바로 이 아이디어의 핵심입니다. 트레이더와 음성으로 대화하면 일반 텍스트보다 이해하기 쉬운 메시지를 전달할 수 있습니다. 여러분의 창의력을 더욱 발휘해 보세요.
   


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

파일 첨부됨 |
EA_-_h_Parte_29_6.zip (14465.62 KB)
Expert Advisor 개발 기초부터(30부): 차트 트레이드(Chart Trade)를 지표로 사용하시나요? Expert Advisor 개발 기초부터(30부): 차트 트레이드(Chart Trade)를 지표로 사용하시나요?
오늘 우리는 차트 트레이드(Chart Trade)를 다시 사용하겠습니다. 그러나 이번에는 차트 트레이드가 차트에 표시되거나 표시되지 않을 수도 있는 차트상의 지표가 될 것입니다.
빌 윌리엄스의 MFI로 트레이딩 시스템을 설계하는 방법 알아보기 빌 윌리엄스의 MFI로 트레이딩 시스템을 설계하는 방법 알아보기
이번 글은 인기 있는 보조지표를 기반으로 트레이딩 시스템을 설계하는 방법을 알아보는 시리즈의 새로운 글입니다. 이번에는 빌 윌리엄스의 시장 촉진 지수(BW MFI)를 다뤄보겠습니다.
Expert Advisor 개발 기초부터(31부): 미래를 향해(IV) Expert Advisor 개발 기초부터(31부): 미래를 향해(IV)
이제 EA에서 별도의 부분을 계속 제거합니다. 이 글은 이 시리즈의 마지막 글입니다. 마지막으로 제거해야 할 것은 사운드 시스템입니다. 이 시리즈를 읽지 않은 분이라면 다소 혼란스러울 수 있습니다.
게이토 오실레이터로 트레이딩 시스템을 설계하는 방법 알아보기 게이토 오실레이터로 트레이딩 시스템을 설계하는 방법 알아보기
인기 보조지표를 기반으로 트레이딩 시스템을 설계하는 방법을 알아보는 시리즈의 새로운 글, 게이터 오실레이터 보조지표와 간단한 전략을 통해 트레이딩 시스템을 만드는 방법