English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
여러 상품을 거래하는 Expert Advisor 생성

여러 상품을 거래하는 Expert Advisor 생성

MetaTrader 5 | 5 7월 2021, 15:21
73 0
Nikolay Kositsin
Nikolay Kositsin

소개

단일 차트에서 시작된 단일 Expert Advisor가 동시에 다른 금융 자산과 거래 할 수 있도록 프로그램 코드를 구현하는 것이 바로 그 기술적인 측면입니다. 일반적으로 이것은 MQL4에서도 문제가 되지 않았습니다. 그러나 MetaTrader 5 클라이언트 터미널의 출현으로 트레이더는 마침내 전략 테스터를 사용하여 이러한 자동화 작업에 대한 전체 분석을 수행 할 기회를 얻게 되었습니다.

따라서 이제 다중 통화 자동화는 그 어느 때 보다 대중화 될 것이며 그러한 거래 시스템의 구축에 대한 관심이 급증 할 것으로 예상 할 수 있습니다. 그러나 이러한 로봇 구현의 주요 문제는 프로그램 코드의 크기가 산술적 진행으로 확장된다는 사실에 있으며, 이를 일반적인 프로그래머가 수용하기란 쉽지 않습니다.

이 글에서 우리는 구조 결함이 존재하지 않더라도 최소한 최소화되는 간단한 다중 통화 Expert Advisor를 작성할 것입니다.


1. 간단한 추세 추종 시스템 구현

사실, 우리는 기술 인디케이터인 Triple Exponential Moving Average의 내장 터미널을 기반으로 한 추세에 따라 최대한 간단한 거래 시스템으로 시작할 수 있습니다. 이건 아주 간단한 알고리즘으로 특별한 코멘트가 필요하지 않으며 이제 프로그램 코드에 구현할 것입니다.

하지만 무엇보다 먼저 Expert Advisor에 대해 가장 일반적인 결론을 내리고 싶습니다. 글로벌 수준에서 선언된 들어오는 Expert Advisor 매개 변수 블록으로 시작하는 것이 좋습니다.

따라서 우선 우리는 함께 일할 금융 자산을 선택해야 합니다. 이는 자산 기호를 저장할 수 있는 라인 입력 변수를 사용하여 수행 할 수 있습니다. 이제 각 금융 자산에 대한 거래 금지 스위치를 사용하면 자산에 의한 거래 작업을 비활성화 할 수 있습니다.

당연히 각 자산은 손절매, 이익 실현, 오픈 포지션의 볼륨, 불이행이라는 개별 거래 매개 변수와 연관되어야 합니다. 그리고 분명한 이유로 각 거래 칩에 대한 인디케이터 Triple Exponential Moving Average의 입력 매개 변수는 개별적이어야 합니다.

다음은 이러한 인수에 따라 수행되는 단 하나의 칩에 대한 입력 변수의 마지막 블록입니다. 나머지 블록은 Expert Advisor의 입력 매개 변수 이름에 있는 숫자만 다릅니다. 이 예에서는 12개의 금융 자산으로 제한했지만 이상적으로는 그러한 블록의 수에 소프트웨어 제한이 없습니다.

우리는 거래 할 것이 필요합니다! 그리고 가장 중요한 것은 PC에 이 문제를 해결하기 위한 충분한 리소스가 있어야 한다는 것입니다.

input string                Symb0 = "EURUSD";
input  bool                Trade0 = true; 
input int                    Per0 = 15; 
input ENUM_APPLIED_PRICE ApPrice0 = PRICE_CLOSE;
input int                 StLoss0 = 1000;
input int               TkProfit0 = 2000;
input double                Lots0 = 0.1;
input int               Slippage0 = 30;

이제 전역 수준에서 변수를 알아 냈으므로 OnTick() 함수 내에서 코드 구성을 진행할 수 있습니다. 여기서 가장 합리적인 옵션은 거래 신호를 수신하는 알고리즘과 Expert Advisor의 실제 거래 부분을 두 개의 사용자 지정 함수으로 나누는 것입니다.

Expert Advisor는 동시에 12개의 금융 자산에 대해 작업하기 때문에 OnTick() 블록 내에서 이러한 함수를 12번 호출해야 합니다. 

당연히 이러한 함수의 첫 번째 입력 매개 변수는 이러한 거래 자산이 나열되는 고유 번호여야 합니다. 두 번째 입력 매개 변수는 명백한 이유로 거래 금융 자산의 라인 이름입니다.

세 번째 매개 변수의 역할은 거래를 해결하기 위한 논리 변수를 설정합니다. 다음으로 거래 신호를 결정하는 알고리즘의 경우 입력 인디케이터 신호를 따르고 거래 함수의 경우 보류 주문까지의 거리, 포지션 볼륨 및 슬립 (오픈 포지션 가격의 허용 가능한 슬립)을 따릅니다.

한 함수에서 다른 함수로 거래 신호를 전송하려면 정적 배열을 함수의 매개 변수로 설정해야 합니다. 이 매개 변수는 참조를 통해 값을 유도합니다. 이것은 OnTick() 함수에 대해 제안된 코드의 최종 버전입니다.

void OnTick()
  {
//--- declare variables arrays for trade signals 
   static bool UpSignal[12], DnSignal[12], UpStop[12], DnStop[12];
  
//--- get trade signals
   TradeSignalCounter( 0, Symb0,  Trade0,  Per0,  ApPrice0,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 1, Symb1,  Trade1,  Per1,  ApPrice1,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 2, Symb2,  Trade2,  Per2,  ApPrice2,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 3, Symb3,  Trade3,  Per3,  ApPrice3,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 4, Symb4,  Trade4,  Per4,  ApPrice4,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 5, Symb5,  Trade5,  Per5,  ApPrice5,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 6, Symb6,  Trade6,  Per6,  ApPrice6,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 7, Symb7,  Trade7,  Per7,  ApPrice7,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 8, Symb8,  Trade8,  Per8,  ApPrice8,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 9, Symb9,  Trade9,  Per9,  ApPrice9,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter(10, Symb10, Trade10, Per10, ApPrice10, UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter(11, Symb11, Trade11, Per11, ApPrice11, UpSignal, DnSignal, UpStop, DnStop);
  
//--- perform trade operations
   TradePerformer( 0, Symb0,  Trade0,  StLoss0,  TkProfit0,  Lots0,  Slippage0,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 1, Symb1,  Trade1,  StLoss1,  TkProfit1,  Lots1,  Slippage1,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 2, Symb2,  Trade2,  StLoss2,  TkProfit2,  Lots2,  Slippage2,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 3, Symb3,  Trade3,  StLoss3,  TkProfit3,  Lots3,  Slippage3,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 4, Symb4,  Trade4,  StLoss4,  TkProfit4,  Lots4,  Slippage4,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 5, Symb5,  Trade5,  StLoss5,  TkProfit5,  Lots5,  Slippage5,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 6, Symb6,  Trade6,  StLoss6,  TkProfit6,  Lots6,  Slippage6,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 7, Symb7,  Trade7,  StLoss7,  TkProfit7,  Lots7,  Slippage7,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 8, Symb8,  Trade8,  StLoss8,  TkProfit8,  Lots8,  Slippage8,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 9, Symb9,  Trade9,  StLoss9,  TkProfit9,  Lots9,  Slippage9,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer(10, Symb10, Trade10, StLoss10, TkProfit10, Lots10, Slippage10, UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer(11, Symb11, Trade11, StLoss11, TkProfit11, Lots11, Slippage11, UpSignal, DnSignal, UpStop, DnStop); 
//---
  }

TradeSignalCounter() 함수 내에서는 각 칩이 시작될 때 한 번 기술 인디케이터 Triple Exponential Moving Average의 핸들을 얻은 다음 바가 변경 될 때마다 거래 신호를 계산하기만 하면 됩니다.

코드에서 구현된 이 비교적 간단한 체계는 사소한 세부 사항으로 넘쳐나기 시작했습니다.

bool TradeSignalCounter(int Number,
                        string Symbol_,
                        bool Trade,
                        int period,
                        ENUM_APPLIED_PRICE ApPrice,
                        bool &UpSignal[],
                        bool &DnSignal[],
                        bool &UpStop[],
                        bool &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);

//--- declare variable to store final size of variables arrays
   static int Size_=0;

//--- declare array to store handles of indicators as static variable
   static int Handle[];

   static int Recount[],MinBars[];
   double TEMA[4],dtema1,dtema2;

//--- initialization
   if(Number+1>Size_) // Entering the initialization block only on first start
     {
      Size_=Number+1; // For this number entering the block is prohibited

      //--- change size of variables arrays
      ArrayResize(Handle,Size_);
      ArrayResize(Recount,Size_);
      ArrayResize(MinBars,Size_);

      //--- determine minimum number of bars, sufficient for calculation 
      MinBars[Number]=3*period;

      //--- setting array elements to 0
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- use array as timeseries
      ArraySetAsSeries(TEMA,true);

      //--- get indicator's handle
      Handle[Number]=iTEMA(Symbol_,0,period,0,ApPrice);
     }

//--- check if number of bars is sufficient for calculation 
   if(Bars(Symbol_,0)<MinBars[Number])return(true);
//--- get trade signals 
   if(IsNewBar(Number,Symbol_,0) || Recount[Number]) // Entering the block on bar change or on failed copying of data
     {
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- using indicator's handles, copy values of indicator's
      //--- buffers into static array, specially prepared for this purpose
      if(CopyBuffer(Handle[Number],0,0,4,TEMA)<0)
        {
         Recount[Number]=true; // As data were not received, we should return 
                               // into this block (where trade signals are received) on next tick!
         return(false);        // Exiting the TradeSignalCounter() function without receiving trade signals
        }

      //--- all copy operations from indicator buffer are successfully completed
      Recount[Number]=false; // We may not return to this block until next change of bar

      int Digits_ = int(SymbolInfoInteger(Symbol_,SYMBOL_DIGITS)+4);
      dtema2 = NormalizeDouble(TEMA[2] - TEMA[3], Digits_);
      dtema1 = NormalizeDouble(TEMA[1] - TEMA[2], Digits_);

      //---- determining the input signals
      if(dtema2 > 0 && dtema1 < 0) DnSignal[Number] = true;
      if(dtema2 < 0 && dtema1 > 0) UpSignal[Number] = true;

      //---- determining the output signals
      if(dtema1 > 0) DnStop[Number] = true;
      if(dtema1 < 0) UpStop[Number] = true;
     }
//----+
   return(true);
  }

이 측면에서 TradePerformer() 함수의 코드는 꽤 간단합니다.

bool TradePerformer(int    Number,
                    string Symbol_,
                    bool   Trade,
                    int    StLoss,
                    int    TkProfit,
                    double Lots,
                    int    Slippage,
                    bool  &UpSignal[],
                    bool  &DnSignal[],
                    bool  &UpStop[],
                    bool  &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);

//--- close opened positions 
   if(UpStop[Number])BuyPositionClose(Symbol_,Slippage);
   if(DnStop[Number])SellPositionClose(Symbol_,Slippage);

//--- open new positions
   if(UpSignal[Number])
      if(BuyPositionOpen(Symbol_,Slippage,Lots,StLoss,TkProfit))
         UpSignal[Number]=false; //This trade signal will be no more on this bar!
//---
   if(DnSignal[Number])
      if(SellPositionOpen(Symbol_,Slippage,Lots,StLoss,TkProfit))
         DnSignal[Number]=false; //This trade signal will be no more on this bar!
//---
   return(true);
  }
그러나 이는 거래 작업 수행을 위한 실제 명령이 네 가지 추가 함수으로 압축되어있기 때문입니다.
BuyPositionClose();
SellPositionClose();
BuyPositionOpen();
SellPositionOpen();

네 가지 함수 모두 완전히 유사하게 작동하므로 그중 하나만 검사하도록 제한 할 수 있습니다.

bool BuyPositionClose(const string symbol,ulong deviation)
  {
//--- declare structures of trade request and result of trade request
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   ZeroMemory(result);

//--- check if there is BUY position
   if(PositionSelect(symbol))
     {
      if(PositionGetInteger(POSITION_TYPE)!=POSITION_TYPE_BUY) return(false);
     }
   else  return(false);

//--- initializing structure of the MqlTradeRequest to close BUY position
   request.type   = ORDER_TYPE_SELL;
   request.price  = SymbolInfoDouble(symbol, SYMBOL_BID);
   request.action = TRADE_ACTION_DEAL;
   request.symbol = symbol;
   request.volume = PositionGetDouble(POSITION_VOLUME);
   request.sl = 0.0;
   request.tp = 0.0;
   request.deviation=(deviation==ULONG_MAX) ? deviation : deviation;
   request.type_filling=ORDER_FILLING_FOK;
//---
   string word="";
   StringConcatenate(word,
                     "<<< ============ BuyPositionClose():   Close Buy position at ",
                     symbol," ============ >>>");
   Print(word);

//--- send order to close position to trade server
   if(!OrderSend(request,result))
     {
      Print(ResultRetcodeDescription(result.retcode));
      return(false);
     }
//----+
   return(true);
  }

기본적으로 그것은 거의 모든 다중 통화 Expert Advisor (Exp_TEMA.mq5)입니다!

고려되는 함수 외에도 두 가지 추가 사용자 함수가 포함되어 있습니다.

bool IsNewBar(int Number, string symbol, ENUM_TIMEFRAMES timeframe);
string ResultRetcodeDescription(int retcode);

이러한 함수 중 첫 번째 함수는 선택한 기호와 시간대를 기준으로 바의 변경 순간에 참 값을 반환하고 두 번째 함수는 거래 요청 구조 MqlTradeResult의 필드 리코드로부터 파생된 거래 트랜잭션의 결과 코드를 기준으로 선을 반환합니다. 

Expert Advisor가 준비되었습니다. 이제 테스트를 시작할 시간입니다! 복수 통화 Expert Advisor과 단일 통화 Expert Advisor의 테스트에서 눈에 띄는 큰 차이는 없습니다.

전략 테스터의 "매개 변수"탭에서 구성을 결정합니다.

그림 1. 전략 테스터의 "설정"탭

그림 1. "설정" 전략 테스터

필요한 경우 "입력 매개 변수"탭에서 입력 매개 변수의 값을 조정하십시오.

그림 2. 전략 테스터의 "매개 변수"탭

그림 2. 전략 테스터의 "매개 변수"탭

그런 다음 "설정"탭의 전략 테스터에서 "시작"버튼을 클릭합니다.

그림 3. Expert Advisor 테스트 실행

그림 3. Expert Advisor 테스트 실행

Expert Advisor의 첫 번째 테스트 통과 시간은 12개 심볼 모두에 대한 기록 로드로 인해 매우 중요한 것으로 판명 될 수 있습니다. 전략 테스터에서 테스트를 완료한 후 "결과"탭을 엽니다.

그림 4. 테스트 결과

그림 4. 테스트 결과

"차트"탭의 내용을 사용하여 데이터를 분석합니다.

그림 5. 균형 역학 및 형평성 차트

그림 5. 균형 역학 및 형평성 차트

및 "저널":

그림 6. 전략 테스터 저널

그림 6. 전략 테스터 저널

당연히 이 Expert Advisor의 알고리즘의 진입과 퇴출의 본질은 너무 간단하며 첫 번째 임의 매개 변수를 사용할 때 매우 중요한 결과를 기대하는 것은 순진합니다. 그러나 여기서 우리의 목표는 가능한 가장 간단한 방법으로 다중 통화 Expert Advisor을 구성하는 기본 아이디어를 보여주는 것입니다.

이 Expert Advisor의 최적화로 인해 너무 많은 입력 매개 변수로 인해 불편함이 발생할 수 있습니다. 최적화의 유전적 알고리즘은 이러한 매개 변수의 훨씬 적은 양을 필요로하므로 Expert Advisor는 각 칩에서 개별적으로 최적화되어야 하며 나머지 칩은 TradeN 입력 매개 변수를 비활성화 해야 합니다.

이제 접근 방식의 본질이 요약되면 다중 통화 로봇에 대한 더 흥미로운 의사 결정 알고리즘으로 작업을 시작할 수 있습니다.


2. 금융 시장에 대한 반향과 거래 시스템에서의 적용

일반적으로 서로 다른 금융 자산 간의 상관 관계를 고려하는 아이디어는 새로운 것이 아니며 이러한 추세 분석에 정확하게 기반을 둔 알고리즘을 구현하는 것이 흥미로울 것입니다. 이 글에서는 "Currency Speculator"(러시아어) 04, 05, 2001 저널에 게재 된 Vasily Yakimkin "Resonances-새로운 기술 인디케이터 클래스"글을 기반으로 다중 통화 자동화를 구현할 것입니다.

이 접근 방식의 핵심은 다음과 같습니다. 예를 들어 EUR / USD에 대한 조사를 위해 금융 자산에 대한 일부 인디케이터의 결과 뿐만 아니라 EUR/USD 자산과 관련된 동일한 인디케이터 (EUR/JPY 및 USD/JPY)의 결과도 사용합니다. 측정 및 계산의 단순성과 용이성을 위해 동일한 변경 범위에서 값이 정규화되는 인디케이터를 사용하는 것이 가장 좋습니다.

이러한 요구 사항을 고려할 때 이 고전에 적합한 것은 확률적 인디케이터입니다. 실제로 다른 인디케이터의 사용에는 차이가 없습니다. 추세 방향으로 우리는 확률 론적 Stoh 값과 신호선 Sign 사이의 차이 기호를 고려할 것입니다.

그림 7. 추세 방향 결정

그림 7. 추세 방향 결정

변수 기호 d Stoh 의 경우 현재 추세의 방향에 대한 가능한 조합 및 해석에 대한 전체 표가 있습니다.

그림 8. 변수 기호 dStoh와 추세 방향의 조합

그림 8. 변수 기호 dStoh와 추세 방향의 조합

EUR / JPY 및 USD / JPY 자산의 두 신호가 반대 값을 갖는 경우 그 합계를 결정해야 하며 이 합계가 0보다 크면 두 신호를 모두 양수로 간주하고 그렇지 않으면 음수로 간주합니다.

EUR / JPY 및 USD / JPY 자산의 두 신호가 반대 값을 갖는 경우 그 합계를 결정해야 하며 이 합계가 0보다 크면 두 신호를 모두 양수로 간주하고 그렇지 않으면 음수로 간주합니다. 또한 주 자산에 신호가 없고 나머지 자산에 대한 변수 dStoh의 합이 0보다 작으면 롱을 종료합니다. 숏의 경우 모든 것이 절대적으로 유사하며 상황만 반대가 됩니다.

가장 합리적인 해결책은 Expert Advisor의 전체 분석 부분을 다중 통화 인디케이터에 배치하고 Expert Advisor의 경우 인디케이터 버퍼에서 거래 통제를 위해 준비된 신호만 취하는 것입니다. 이 인디케이터 유형의 버전은 MultiStochastic.mq5 인디케이터로 표시되어 시장 상황에 대한 시각적 분석을 제공합니다.

그림 9. 다중 확률 인디케이터

그림 9. 다중 확률 인디케이터

초록색 바는 매수 포지션의 개장과 유지를, 빨간색 바는 매도 포지션을 각각 나타냅니다. 차트 상단 가장자리의 분홍색과 연한 녹색 점은 롱 포지션과 숏 포지션을 종료한다는 신호를 나타냅니다.

이 인디케이터는 Expert Advisor에서 신호를 수신하는 데 직접 사용할 수 있지만 여전히 작업을 용이하게 하고 불필요한 버퍼 및 시각화 요소를 모두 제거하여 거래 신호 공급에 직접 관련된 것만 남겨 두는 것이 좋습니다. 이것이 바로 MultiStochastic_Exp.mq5 인디케이터에서 수행된 작업입니다.

이 Expert Advisor에서 저는 3개의 칩으로만 거래했기 때문에 OnTick() 함수의 코드가 매우 간단해졌습니다.

void OnTick()
  {
//--- declare variables arrays for trade signals
  static bool UpSignal[], DnSignal[], UpStop[], DnStop[];
  
//--- get trade signals
  TradeSignalCounter(0, Trade0, Kperiod0, Dperiod0, slowing0, ma_method0, price_0, SymbolA0, SymbolB0, SymbolC0, UpSignal, DnSignal, UpStop, DnStop);
  TradeSignalCounter(1, Trade1, Kperiod1, Dperiod1, slowing1, ma_method1, price_1, SymbolA1, SymbolB1, SymbolC1, UpSignal, DnSignal, UpStop, DnStop);
  TradeSignalCounter(2, Trade2, Kperiod2, Dperiod2, slowing2, ma_method2, price_2, SymbolA2, SymbolB2, SymbolC2, UpSignal, DnSignal, UpStop, DnStop);
                             
//--- perform trade operations
   TradePerformer( 0, SymbolA0,  Trade0,  StopLoss0,  0,  Lots0,  Slippage0,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 1, SymbolA1,  Trade1,  StopLoss1,  0,  Lots1,  Slippage1,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 2, SymbolA2,  Trade2,  StopLoss2,  0,  Lots2,  Slippage2,  UpSignal, DnSignal, UpStop, DnStop);
//---
  }

그러나 TradeSignalCounter() 함수의 코드는 조금 더 복잡합니다. 사실 다중 통화 인디케이터가 서로 다른 금융 자산의 세 가지 시계열과 직접 작동하기 때문에 우리는 바의 적절성에 대해 더 미묘한 검증을 구현합니다. Rates_Total() 함수를 사용하여 세 시계열 중 하나의 최소 수입니다.

또한 SynchroCheck() 함수를 사용하여 시계열 동기화에 대한 추가 검증을 수행하여 모든 시계열에서 동시에 바의 변경이 발생하는 순간을 결정하는 정확성을 보장합니다.

bool TradeSignalCounter(int Number,
                        bool Trade,
                        int Kperiod,
                        int Dperiod,
                        int slowing,
                        ENUM_MA_METHOD ma_method,
                        ENUM_STO_PRICE price_,
                        string SymbolA,
                        string SymbolB,
                        string SymbolC,
                        bool &UpSignal[],
                        bool &DnSignal[],
                        bool &UpStop[],
                        bool &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);
//--- declare variable to store sizes of variables arrays
   static int Size_=0;
//--- declare arrays to store handles of indicators as static variables
   static int Handle[];
   static int Recount[],MinBars[];
//---
   double dUpSignal_[1],dDnSignal_[1],dUpStop_[1],dDnStop_[1];
//--- change size of variables arrays
   if(Number+1>Size_)
     {
      uint size=Number+1;
      //----
      if(ArrayResize(Handle,size)==-1
         || ArrayResize(Recount,size)==-1
         || ArrayResize(UpSignal, size) == -1
         || ArrayResize(DnSignal, size) == -1
         || ArrayResize(UpStop, size) == -1
         || ArrayResize(DnStop, size) == -1
         || ArrayResize(MinBars,size) == -1)
        {
         string word="";
         StringConcatenate(word,"TradeSignalCounter( ",Number,
                           " ): Error!!! Unable to change sizes of variables arrays!!!");
         int error=GetLastError();
         ResetLastError();
         //---
         if(error>4000)
           {
            StringConcatenate(word,"TradeSignalCounter( ",Number," ): Error code ",error);
            Print(word);
           }
         Size_=-2;
         return(false);
        }

      Size_=int(size);
      Recount[Number] = false;
      MinBars[Number] = Kperiod + Dperiod + slowing;

      //--- get indicator's handle
      Handle[Number]=iCustom(SymbolA,0,"MultiStochastic_Exp",
                             Kperiod,Dperiod,slowing,ma_method,price_,
                             SymbolA,SymbolB,SymbolC);
     }
//--- check if number of bars is sufficient for calculation 
   if(Rates_Total(SymbolA,SymbolB,SymbolC)<MinBars[Number])return(true);
//--- check timeseries synchronization
   if(!SynchroCheck(SymbolA,SymbolB,SymbolC))return(true);
//--- get trade signals 
   if(IsNewBar(Number,SymbolA,0) || Recount[Number])
     {
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- using indicators' handles, copy values of indicator's 
      //--- buffers into static arrays, specially prepared for this purpose
      if(CopyBuffer(Handle[Number], 1, 1, 1, dDnSignal_) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 2, 1, 1, dUpSignal_) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 3, 1, 1, dDnStop_  ) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 4, 1, 1, dUpStop_  ) < 0){Recount[Number] = true; return(false);}

      //--- convert obtained values into values of logic variables of trade commands
      if(dDnSignal_[0] == 300)DnSignal[Number] = true;
      if(dUpSignal_[0] == 300)UpSignal[Number] = true;
      if(dDnStop_  [0] == 300)DnStop  [Number] = true;
      if(dUpStop_  [0] == 300)UpStop  [Number] = true;

      //--- all copy operations from indicator's buffers completed successfully
      //--- unnecessary to return into this block until next bar change
      Recount[Number]=false;
     }
//----+
   return(true);
  }

이 Expert Advisor (Exp_ResonanceHunter.mq5)의 코드는 동일한 함수적 구성 요소를 기반으로 컴파일 되었기 때문에 다른 근본적인 이데올로기적 차이는 없습니다. 따라서 내부 구조에 더 이상 시간을 할애할 필요는 없다고 생각합니다.


결론

제 생각에는 MQL5의 다중 통화 Expert Advisor 코드는 일반 Expert Advisor의 코드와 절대적으로 유사합니다.


MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/105

MQL5에서 이동 평균 계산 성능 테스트 MQL5에서 이동 평균 계산 성능 테스트
첫 번째 이동 평균 인디케이터 생성 이후 여러 많은 인디케이터가 나타났습니다. 그들 중 다수는 유사한 평활 방법을 사용하지만 다른 이동 평균 알고리즘의 성능은 연구되지 않았습니다. 이 글에서는 MQL5에서 이동 평균을 사용하는 가능한 방법을 고려하고 성능을 비교합니다.
캔들스틱 패턴 분석 캔들스틱 패턴 분석
일본 캔들스틱 차트의 구성과 캔들스틱 패턴 분석은 놀라운 기술적 분석 영역을 구성합니다. 캔들스틱의 장점은 데이터 내부의 역학을 추적 할 수 있는 방식으로 데이터를 표현한다는 것입니다. 이 글에서는 캔들스틱 유형, 캔들스틱 패턴 분류를 분석하고 캔들스틱 패턴을 결정할 수 있는 인디케이터를 제시합니다.
예시를 통해 보는 MQL5 의 OOP: 프로세싱 경고와 에러 코드 예시를 통해 보는 MQL5 의 OOP: 프로세싱 경고와 에러 코드
이 문서에서는 매매 서버 리턴 코드 작업을 위한 클래스를 생성하는 예와 MQL 프로그램 실행 중에 발생하는 모든 오류에 대해 설명합니다. 이 문서를 다 읽고나면 당신은 MQL5로 클래스나 객체를 어떻게 다뤄야하는지 알게될 것입니다. 또한 이 도구는 오류를 처리하는 데 편리한 도구이며 특정 필요에 따라 이 도구를 추가로 변경할 수 있습니다.
Delphi로 MQL5용 DLL 짜는 법 Delphi로 MQL5용 DLL 짜는 법
이 문서는 Delphi 환경에서 인기좋은 언어 ObjectPascal을 이용해 DLL 모듈을 짜는 법에 대해서 알아볼 것입니다. 본 문서에서 제공하는 자료는 주로 외부 DLL 모듈을 연결하여 MQL5의 내장 프로그래밍 언어의 경계를 허문 초보자 프로그래머를 대상으로 합니다.