English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
かずかずのインスツルメントで取引を行うExpert Advisorの作成

かずかずのインスツルメントで取引を行うExpert Advisorの作成

MetaTrader 5 | 6 10月 2015, 12:50
531 0
Nikolay Kositsin
Nikolay Kositsin

はじめに

同時に異なるファイナンシャルアセットの取引を行うことを可能にする、一つのチャートに実装された単独のExpert Advisorに整然とプログラムコードを実装する技術的側面、これはMQL4でさえ問題ではありませんでした。しかし、ただMetaTrader 5クライアント端末が出現したことで、トレーダーはついにストラテジーテスタを用いそういった自動化作業のフル分析を行う機会を得ました。

複数通貨自動化はかつてない人気を得るでしょう。そのようなトレーディングシステムの構築にわきあがる興味を抱くことになるのです。しかし、そのようなロボットの導入にあたり主な問題は、プログラムコードにおけるディメンションの広がりであり、せいぜい算術的進歩では、一般的なプログラマにとって受け入れやすいものではありません。

本稿では、シンプルな複数通貨対Expert Advisorを書いていきます。そこでは構造体フローは、存在しないものとして、あっても最小化されています。


1. シンプルなトレンド追跡システム

内蔵テクニカルインディケータの「トリプル指数移動平均」を基本としてトレンドを追うことで、実際最大限シンプル化されたトレーディングシステムを用いて始めることはできました。これはたいへん簡単なアルゴリズムです。特別なコメント記述を必要としませんし、プそれはログラムコードに組み込まれます。

しかしまず最初にそして最大限に、Expert Advisorについてごく一般的な結論に至りたいと思います。グローバルレベルで宣言されている、入ってくるExpert Advisorパラメータのブロックから始めるのは道理的であると思います。

そこでまず、作業を行うファイナンシャルアセットの選択を行う必要があります。これはアセットシンボルが保存されている入力変数を用いて行うことができます。各ファイナンシャルアセットに、アセットによってトレード処理を無効にできるトレードバンを設けることができればなお良いでしょう。

当然、各アセットは個別のストップロス、テイクプロフィット、オープンポジションのボリューム、スリッページというトレーディングパラメータと連携している必要があります。そして、わかりやすい理由として、各トレーディングチップに対する「トリプル指数移動平均」は独立している必要があります。

ここにはただ一つのチップに対する一つの入力変数があり、これら引数と連携して実行されます。その他のブロックは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のトレーディングパートを2つのカスタム関数へ分割することです。

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()関数内部では、各チップ開始時にテクニカルインディケータである「トリプル指数移動平均」のハンドル取得 が必要なだけで、その後トレーディングシグナルを計算するためのバーが変更するたびに取得が必要です。

このコード実装をする比較的シンプルなスキームは、重要でない詳細であふれ始めています。

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);
  }
しかし、これは実際のトレード処理コマンドはさらに4つの関数にパックされているからにすぎません。
BuyPositionClose();
SellPositionClose();
BuyPositionOpen();
SellPositionOpen();

4つの関数すべては完全に類似的に動作し、そのためそのうち1つだけを検証することにします。

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)は手に余るものです!

考察した関数以外にも2つのユーザー関数があります。

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

そのうち最初の関数は、選択されたシンボル、時間枠に基づきバー変更の際、true値を返します。 二番目の関数はトレード要求ストラクチャ MqlTradeResultのフィールドretcodeから派生したトレード処理の結果コードによって行を返します。

これでExpert Advisorは準備できました。検証を始める時間です。 複数通貨対応Expert Advisorの検証は、単通貨対応Expert Advisorの検証と大きく変わるところはありません。

「ストラテジーテスタ」の「パラメータ」タブ上のコンフィギュレーションを決定します。

図1 「ストラテジーテスタ」の『設定』タブ

図1 「ストラテジーテスタ」の『設定』タブ

必要であれば、「入力パラメータ」タブの入力パラメータ値を調整します。

図2 「ストラテジーテスタ」の『パラメータ』タブ

図2 「ストラテジーテスタ」の『パラメータ』タブ

そして『設定』タブ上「ストラテジーテスタ」の『開始』ボタンをクリックします。

図3 Expert Advisor検証の実行

図3 Expert Advisor検証の実行

12個すべてのシンボルについての履歴をロードする関係上、 Expert Advisorの最初の検証で経過する時間はたいへん長くなる可能性があります。ストラテジーテスタでの検証が完了すると『結果』タブを開きます。

図4 検証結果

図4 検証結果

そして『チャート』タブのコンテンツを利用してデータ分析を行います。

図5 バランスの動きとequityのチャート

図5 バランスの動きとequityのチャート

そして『ジャーナル』です。

図6 ストラテジーテスタジャーナル

図6 ストラテジーテスタジャーナル

ごく当然のことですが、このExpert Advisorのアルゴリズムのマーケットへの入りと出の基本の基本はシンプルすぎて、最初のランダムなパラメータを使うときは大きな結果は期待できないでしょう。しかしここでの目標はできるだけシンプルな方法で複数通貨対応Expert Advisorを構築する考え方の基礎を示すことです。

このExpert Advisorの最適化によって多くの入力パラメータによる不都合が生じる可能性があります。 最適化の遺伝的アルゴリズムはこれらパラメータがもっと小さいことを要求します。そのためExpert Advisorはチップごとに個別に最適化される必要があり、入力パラメータの TradeNの残りのパラメータチップを無効化します。.

手法の基本がだいたいわかったところで、複数通貨対応ロボットについて判断を行うもっと興味深いアルゴリズムについてみていきましょう。


2. ファイナンシャルマーケットにおける共振とトレーディングシステムでの適用

異なるファイナンシャルアセット間の連携を考慮する考え方は一般的に新しいものではありません。また正確にそういったトレンドの分析に基づくアルゴリズムを実装することは興味を引かれるものかもしれません。本稿では、複数通貨対応自動化を実装します。それは、2001年5月4日発行のジャーナル"Currency Speculator"(ロシア語)掲載、Vasily Yakimkin氏の記事"Resonances - a New Class of Technical Indicators"を基にしたものです。

この手法の基本の基本を端的に言うと以下のようなことです。たとえば、EUR / USDについて調査する場合、ファイナンシャルアセットのインディケータ結果だけを使うのではなく、EUR/USDアセットに関連する同様のインディケータ結果も使います。 EUR/JPYやUSD/JPYです。インディケータ、変更の同じ範囲内でシンプル化のため、また計測と計算を簡単にするため、普通化される値を使うのは最良の方法です。

これら要求を考慮すると、このありがちなものによくあてはまるのは確率論的インディケータです。しかし、実際は他のインディケータを使ってもなんら違いはありません。トレンド方向として、確率値 Stoh とそのシグナル行 Sign の間の異なるサインを考察します。

図7 トレンド方向の判断

図7 トレンド方向の判断

変数シンボル dStoh について、可能性ある組合せの表と、その現在トレンド方向への解釈があります。

図8 変数シンボルdStohとトレンド方向の組合せ

図8 変数シンボルdStohとトレンド方向の組合せ

アセットEUR / JPYとUSD / JPYの2つのシグナルが逆の値を示す場所で、それらの合計とこの合計がゼロより大きいことを判断する必要があります。どちらのシグナルも正で、それ以外では負と考えます。

オープニングのロングには、トレンドが成長の場合の状況を採用します。出には下降トレンド、または主要アセットのEUR / USDインディケータシグナルが負というトレンドを採用します。また、主要アセットにシグナルがない場合または、残りのアセットについての変数dStohの合計がゼロ以下の時 はロングを出ます。ショートに関しては、すべてが絶対的に類似しています。状況が逆なだけです。

最も根本的な解決法はExpert Advisorの分析的部分の全体を複数通貨インディケータに配置することです。そしてインディケータバッファからのExpert Advisorについてはトレードコントロールの準備シグナルを取得するだけです。このインディケータタイプのバージョンは、マーケット条件の視覚的分析をまじえてMultiStochastic.mq5で提供します。

図9 MultiStochasticインディケータ

図9 MultiStochasticインディケータ

グリーンのバーはロングの、赤はショートの開始と保持をそれぞれ示します。チャートの上端にあるピンクと薄いグリーンの点はロングとショートポジションの退出シグナルを表します。

このインディケータは直接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()のコードはすこし複雑です。というのも複数通貨対応インディケータは異なるファイナンシャルアセットの3つのタイムシリーズに直接動作します。そのため、Rates_Total()関数を使って、3つのタイムシリーズにおけるそれらの最小数値のadequacy のためにバーの検証をより精密に行います。

また、タイムシリーズの同期における追加の検証も行います。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 Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/105

添付されたファイル |
multistochastic.mq5 (17.47 KB)
exp_tema.mq5 (25.17 KB)
MQL5における移動平均計算パフォーマンス検証 MQL5における移動平均計算パフォーマンス検証
最初に「移動平均」インディケータが作成されて以来、多くのインディケータが登場してきました。それらの多くは類似の平滑化手法を使用していますが、異なる移動平均アルゴリズムの性能については研究されていません。本稿ではMQL5で「移動平均」を使用する可能な方法について考察し、それらのパフォーマンスを比較していきます。
ろうそく足パターンの分析 ろうそく足パターンの分析
日本式のろうそく足チャートの構築とろうそく足パターンの分析は技術分析のすばらしい領域となっています。ろうそく足の利点はデータ内部の動きを追跡できるデータ表現になっていることです。本稿では、ろうそく足タイプとパターン分類を分析し、 またろうそく足パターンを決定するインディケータについてお伝えしていきます。
インディケータの経済的計算原理 インディケータの経済的計算原理
自動化されたトレーディングシステムのプログラムコードではユーザーとテクニカルインディケータの呼び出しはほとんどスペースを取りません。たいてい数行のコード行ですむ簡単なものです。ただこの数行のコードがExpert Advisorの検証に必要な時間の多くを費やす、ということはよくあることです。インディケータ内でデータ計算に関連することはすべて、一見したよりもずっと綿密に配慮される必要があります。本稿ではこの件に関して詳しく述べていきます。
DelphiでDLLをMQL5向けに書くためのガイド DelphiでDLLをMQL5向けに書くためのガイド
本稿は、人気のプログラム言語ObjectPascalを使用しDelphiプログラム環境でDLLモジュールの作成メカニズムを検証します。本稿で使用している資料は、まずは問題を抱えたプログラム初心者用に考えられでおります。外部DLLに接続することでMQL5プログラム言語に埋め込まれた境界を破ります。