English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
名前つきパイプを使用したMetaTrader 5端末間コミュニケーションにDLLを使用しないソリューション

名前つきパイプを使用したMetaTrader 5端末間コミュニケーションにDLLを使用しないソリューション

MetaTrader 5 | 6 10月 2015, 13:27
2 546 0
investeo
investeo

はじめに

私はときどMetaTrader 5端末間コミュニケーションを可能にする方法について考えました。目標は、端末のひとつで異なるクオート提供者からのティックインディケータと表示ティックを使用することです。

当然の解決法はハードドライブ上の個別ファイルの使用です。一つの端末がファイルにデータを書き込み、他の端末がそれを読み取ります。単独のメッセージを送るのに適したこの手法はクオートの流れにはあまり効果的とは思えません。

わたしはWCFサービスを用いて.NETアプリケーションにクオートをエクスポートする方法について述べたAlexander著のすばらしい記事に出会いました。 そして私がそろそろそれを読み終えるころ、Sergeev著のもうひとつ別の記事が登場したのです。

どちらの記事も私が求めていたものに近いものでしたが、私はDLLを使わない方法を探していました。それはサーバーとクライアントと異なる端末で使われる可能性のあるものです。ウェブ検索をしているとき、名前付きパイプを通信に使うことができることを提案したメモを見つけ、そのパイプを使ったプロセス間通信のためのMSDN仕様 を全部読みました。

名前付きパイプが同一コンピュータ上のまたはイントラネット上の異なるコンピュータ間の通信を助けることを発見し、このアプローチを試すことにしました。

本稿は名前付きパイプの通信を紹介し、CNamedPipesクラスを設計する手順について述べています。また、MetaTrader 5端末間のティックインディケータストリームの検証とシステム間の全体的スループットを扱っています。


1. 名前付きパイプを使用したプロセス間通信

一般的なパイプについて考えるとき、メディアを運搬するのに使われる筒のようなものをイメージします。これもオペレーションシステム上のプロセス間通信手段の一つに関して使われる用語です。 ただ2つのプロセスをつなぐパイプをイメージしてください。この場合、データ交換をするMetaTrader 5端末です。

パイプは匿名でも名前を付けてもかまいません。両者間には大きな違いが2つあります。ひとつめは匿名パイプはネットワーク間では使用できないこと。ふたつめは、2つのプロセスが連携する必要があることです。2つというのは、プロセスのひとつが親プロセス、他方が子プロセスであるものです。名前付きパイプにはこの制約はありません。

パイプを使って通信するためには、サーバー処理は知られている名前でパイプの設定をしなければなりません。パイプ名はストリングで、\\servername\pipe\pipename形式の必要があります。パイプが同一コンピュータ上で使用される場合、サーバー名は省略可能で、その代りドットを使うことができます。:\\.\pipe\pipename.

パイプに接続しようとするクライアントはその名前を知っている必要があります。私は端末を区別するため\\.\pipe\mt[account_number] の命名法をよく使っていますが、命名法は自由に変更可能です。


2. CNamedPipesクラスの実装

名前付パイプの作成と接続のメカニズムは低いレベルの短い記述から始めようと思います。ウィンドウズオペレーティングシステムでは、パイプを操作するすべての関数はkernel32.dllライブラリを介して入手可能です。サーバー側で名前付きパイプのインスタンスを作成する関数はCreateNamedPipe()です。

パイプが作成できたら、サーバーはConnectNamedPipe()関数を呼び、クライアント端末が接続するのを待ちます。問題なく接続すると、ConnectNamedPipe()はゼロ以外の整数を返します。しかし、クライアント端末がCreateNamedPipe()を呼んだ後、 ConnectNamedPipe() を呼ぶ前にうまく接続する場合もあります。この場合は、ConnectNamedPipe()はゼロを返し、 GetLastError()はエラー535 (0X217) : ERROR_PIPE_CONNECTEDを返します。

パイプに書く、またパイプから読むのはファイルアクセスと同じ関数で行われます。

BOOL WINAPI ReadFile(
  __in         HANDLE hFile,
  __out        LPVOID lpBuffer,
  __in         DWORD nNumberOfBytesToRead,
  __out_opt    LPDWORD lpNumberOfBytesRead,
  __inout_opt  LPOVERLAPPED lpOverlapped
);
BOOL WINAPI WriteFile(
  __in         HANDLE hFile,
  __in         LPCVOID lpBuffer,
  __in         DWORD nNumberOfBytesToWrite,
  __out_opt    LPDWORD lpNumberOfBytesWritten,
  __inout_opt  LPOVERLAPPED lpOverlapped
);

名前付きパイプについて学習して、指導力の低さを隠すためCNamedPipesクラスを設計しました。

今はCNamedPipes.mqhファイルを端末の適切(/include)フォルダに入れ、それをソースコードに含めCNamedPipeオブジェクトを宣言するだけで十分です。

私が設計したクラスは名前付きパイプを操作するいくつかの基本的はメソッドを提示します。

Create(), Connect(), Disconnect(), Open(), Close(), WriteUnicode(), ReadUnicode(), WriteANSI(), ReadANSI(), WriteTick(), ReadTick()

クラスは追加条件によりもっと拡張される可能性があります。

Create() メソッドは与えられた名前でパイプを作成しようとします。端末間の接続を簡素化するために、パイプを使うクライアントのアカウントナンバーとして入力パラメータを 'account'とします。

アカウント名が入力されていなければ、メソッドは現在の端末アカウントナンバーでパイプを開こうとしますパイプがうまく作成できたら、Create()関数はtrueを返します。

//+------------------------------------------------------------------+
/// Create() : try to create a new instance of Named Pipe
/// \param account - source terminal account number  
/// \return true - if created, false otherwise                                                                |
//+------------------------------------------------------------------+
bool CNamedPipe::Create(int account=0)
  {
   if(account==0)
      pipeNumber=IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN));
   else
      pipeNumber=IntegerToString(account);

   string fullPipeName=pipeNamePrefix+pipeNumber;

   hPipe=CreateNamedPipeW(fullPipeName,
                          (int)GENERIC_READ|GENERIC_WRITE|(ENUM_PIPE_ACCESS)PIPE_ACCESS_DUPLEX,
                          (ENUM_PIPE_MODE)PIPE_TYPE_RW_BYTE,PIPE_UNLIMITED_INSTANCES,
                          BufferSize*sizeof(ushort),BufferSize*sizeof(ushort),0,NULL);

   if(hPipe==INVALID_HANDLE_VALUE) return false;
   else
      return true;

  }

Connect() メソッドはクライアントがパイプに接続するのを待ちます。クライアントがうまくパイプに接続できたらtrueを返します。

//+------------------------------------------------------------------+
/// Connect() : wait for a client to connect to a pipe   
/// \return true - if connected, false otherwise.
//+------------------------------------------------------------------+
bool CNamedPipe::Connect(void)
  {
   if(ConnectNamedPipe(hPipe,NULL)==false)
      return(kernel32::GetLastError()==ERROR_PIPE_CONNECTED);
   else return true;
  }

Disconnect() メソッドはサーバーをパイプから接続解除します。

//+------------------------------------------------------------------+
/// Disconnect(): disconnect from a pipe
/// \return true - if disconnected, false otherwise    
//+------------------------------------------------------------------+
bool CNamedPipe::Disconnect(void)
  {
   return DisconnectNamedPipe(hPipe);
  }

Open() メソッドはクライアントによって使われ、以前に作成したパイプを開きます。うまく開けたらtrueを返します。なんらかの理由で5秒以内に作成したパイプに接続できない場合、またはパイプを開くのに失敗した場合は、falseを返します。

//+------------------------------------------------------------------+
/// Open() : try to open previously created pipe
/// \param account - source terminal account number
/// \return true - if successfull, false otherwise.
//+------------------------------------------------------------------+
bool CNamedPipe::Open(int account=0)
  {
   if(account==0)
      pipeName=IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN));
   else
      pipeName=IntegerToString(account);

   string fullPipeName=pipeNamePrefix+pipeName;

   if(hPipe==INVALID_HANDLE_VALUE)
     {
      if(WaitNamedPipeW(fullPipeName,5000)==0)
        {
         Print("Pipe "+fullPipeName+" not available...");
         return false;
        }

      hPipe=CreateFileW(fullPipeName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
      if(hPipe==INVALID_HANDLE_VALUE)
        {
         Print("Pipe open failed");
         return false;
        }

     }
   return true;
  }

Close() メソッドはパイプハンドルを閉じます。

//+------------------------------------------------------------------+
/// Close() : close pipe handle
/// \return 0 if successfull, non-zero otherwise  
//+------------------------------------------------------------------+
int CNamedPipe::Close(void)
  {
   return CloseHandle(hPipe);
  }

次の6つのメソッドはパイプを通して読み書きするのに使用されます。最初の2つのペアのハンドルストリングはUnicodeおよびANSI形式で、とちらも端末間でコマンドやメッセージを送信するのに使用できます。

MQL5のこのストリング変数はUnicode形式のオブジェクトとして保存されます。よって通常はUnicodeメソッドを提供しますが、 MQL5が UnicodeToANSIメソッドを提供するので私は ANSIストリング通信も実装します。 最後の2つのメソッドは名前付きパイプを介してMqlTickオブジェクトの送受信を操作します。

WriteUnicode() メソッドはUnicode形式の文字で構成されるメッセージを書きます。それぞれの文字は2バイトで構成されるので、この関数はパイプに ushort配列を送信します。

//+------------------------------------------------------------------+
/// WriteUnicode() : write Unicode string to a pipe
/// \param message - string to send
/// \return number of bytes written to a pipe     
//+------------------------------------------------------------------+
int CNamedPipe::WriteUnicode(string message)
  {
   int ushortsToWrite, bytesWritten;
   ushort UNICODEarray[];
   ushortsToWrite = StringToShortArray(message, UNICODEarray);
   WriteFile(hPipe,ushortsToWrite,sizeof(int),bytesWritten,0);
   WriteFile(hPipe,UNICODEarray,ushortsToWrite*sizeof(ushort),bytesWritten,0);
   return bytesWritten;
  }

ReadUnicode() メソッドはushorts配列を受け取り、ストリングオブジェクトを返します。

//+------------------------------------------------------------------+
/// ReadUnicode(): read unicode string from a pipe
/// \return unicode string (MQL5 string)
//+------------------------------------------------------------------+
string CNamedPipe::ReadUnicode(void)
  {
   string ret;
   ushort UNICODEarray[STR_SIZE*sizeof(uint)];
   int bytesRead, ushortsToRead;
 
   ReadFile(hPipe,ushortsToRead,sizeof(int),bytesRead,0);
   ReadFile(hPipe,UNICODEarray,ushortsToRead*sizeof(ushort),bytesRead,0);
   if(bytesRead!=0)
      ret = ShortArrayToString(UNICODEarray);
   
   return ret;
  }

WriteANSI() メソッドはパイプにANSI uchar配列を書きます。

//+------------------------------------------------------------------+
/// WriteANSI() : write ANSI string to a pipe
/// \param message - string to send
/// \return number of bytes written to a pipe                                                                  |
//+------------------------------------------------------------------+
int CNamedPipe::WriteANSI(string message)
  {
   int bytesToWrite, bytesWritten;
   uchar ANSIarray[];
   bytesToWrite = StringToCharArray(message, ANSIarray);
   WriteFile(hPipe,bytesToWrite,sizeof(int),bytesWritten,0);
   WriteFile(hPipe,ANSIarray,bytesToWrite,bytesWritten,0);
   return bytesWritten;
  }

ReadANSI() メソッドはパイプかuchar配列を読み、ストリングオブジェクトを返します。

//+------------------------------------------------------------------+
/// ReadANSI(): read ANSI string from a pipe
/// \return unicode string (MQL5 string)
//+------------------------------------------------------------------+
string CNamedPipe::ReadANSI(void)
  {
   string ret;
   uchar ANSIarray[STR_SIZE];
   int bytesRead, bytesToRead;
 
   ReadFile(hPipe,bytesToRead,sizeof(int),bytesRead,0);
   ReadFile(hPipe,ANSIarray,bytesToRead,bytesRead,0);
   if(bytesRead!=0)
      ret = CharArrayToString(ANSIarray);
   
   return ret;
  }

WriteTick() メソッドはパイプにパイプ単独のMqlTickオブジェクトを書きます。

//+------------------------------------------------------------------+
/// WriteTick() : write MqlTick to a pipe
/// \param MqlTick to send
/// \return true if tick was written correctly, false otherwise
//+------------------------------------------------------------------+
int CNamedPipe::WriteTick(MqlTick &outgoing)
  {
   int bytesWritten;

   WriteFile(hPipe,outgoing,MQLTICK_SIZE,bytesWritten,0);

   return bytesWritten;
  }

ReadTick() メソッドはパイプから単独のMqlTickオブジェクトを読みます。パイプが空の場合は、0を返し、そうでない場合はMqlTickオブジェクトのバイト数を返します。

//+------------------------------------------------------------------+
/// ReadTick() : read MqlTick from a pipe
/// \return true if tick was read correctly, false otherwise
//+------------------------------------------------------------------+
int CNamedPipe::ReadTick(MqlTick &incoming)
  {
   int bytesRead;

   ReadFile(hPipe,incoming,MQLTICK_SIZE,bytesRead,NULL);

   return bytesRead;
  }
//+------------------------------------------------------------------+

名前付きパイプを操作する基本メソッドはわかったので、2つのMQLプログラムから始めます。クオートを受け取るシンプルなスクリプトとクオート送信のインディケータです。


3. クオート受け取りのサーバースクリプト

例で使うサーバーは名前付きパイプを初期化しクライアントが接続するのを待ちます。クライアントが接続を切ったら、そのクライアントによって合計いくつのティックが受け取られたかを表示し、新しいクライアントが接続するのを待ちます。クライアントが接続を切り、サーバーがグローバル変数 'gvar0' を認めると、サーバーは停止します。'gvar0' 変数が存在しなければ、チャート上で右クリックをしてExpert List オプションを選択し、サーバーを手動で停止することも可能です。

//+------------------------------------------------------------------+
//|                                              NamedPipeServer.mq5 |
//|                                      Copyright 2010, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

#include <CNamedPipes.mqh>

CNamedPipe pipe;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   bool tickReceived;
   int i=0;

   if(pipe.Create()==true)
      while (GlobalVariableCheck("gvar0")==false)
        {
         Print("Waiting for client to connect.");
         if (pipe.Connect()==true)
            Print("Pipe connected");
         while(true)
           {
            do
              {
               tickReceived=pipe.ReadTick();

               if(tickReceived==false)
                 {
                  if(GetError()==ERROR_BROKEN_PIPE)
                    {
                     Print("Client disconnected from pipe "+pipe.Name());
                     pipe.Disconnect();
                     break;
                    }
                 } else i++;
                  Print(IntegerToString(i) + "ticks received.");
              } while(tickReceived==true);
            if (i>0) 
            {
               Print(IntegerToString(i) + "ticks received.");
               i=0;
            };
            if(GlobalVariableCheck("gvar0")==true || (GetError()==ERROR_BROKEN_PIPE)) break;
           }

        }

 pipe.Close(); 
  }


4. クオート送信のシンプルなインディケータ

クオート送信のインディケータはOnInit()メソッド内でパイプを開き、OnCalculate() メソッドが動作するたびに単独の MqlTickを送ります。

//+------------------------------------------------------------------+
//|                                        SendTickPipeIndicator.mq5 |
//|                                      Copyright 2010, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property indicator_chart_window

#include <CNamedPipes.mqh>

CNamedPipe pipe;
int ctx;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
 
   while (!pipe.Open(AccountInfoInteger(ACCOUNT_LOGIN)))
   {
      Print("Pipe not created, retrying in 5 seconds...");
      if (GlobalVariableCheck("gvar1")==true) break;
   }
   
   ctx = 0;
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
   ctx++;
   MqlTick outgoing;
   SymbolInfoTick(Symbol(), outgoing);
   pipe.WriteTick(outgoing);
   Print(IntegerToString(ctx)+" tick send to server by SendTickPipeClick.");
   return(rates_total);
  }
//+------------------------------------------------------------------+


5. ひとつのクライアント端末における複数プロバイダからのティックインディケータの実行

個別のティックインディケータの着信クオートを表示したいので事態は複雑化してきました。これができたのはEventChartCustom() メソッドを動作させることでティックインディケータに対し受信ティックをブロードキャストするパイプサーバーを実装したからです。

bid およびask クオートはセミコロンで区切られたひとつのストリングとして送られます。次のようなものです。'1.20223;120225'. 適切なインディケータがOnChartEvent()内のカスタムイベントを操作し、ティックチャートを表示します。

//+------------------------------------------------------------------+
//|                                   NamedPipeServerBroadcaster.mq5 |
//|                                      Copyright 2010, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property script_show_inputs
#include <CNamedPipes.mqh>

input int account = 0;

CNamedPipe pipe;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   bool tickReceived;
   int i=0;

   if(pipe.Create(account)==true)
      while(GlobalVariableCheck("gvar0")==false)
        {
         if(pipe.Connect()==true)
            Print("Pipe connected");
            i=0;
         while(true)
           {
            do
              {
               tickReceived=pipe.ReadTick();
               if(tickReceived==false)
                 {
                  if(kernel32::GetLastError()==ERROR_BROKEN_PIPE)
                    {
                     Print("Client disconnected from pipe "+pipe.GetPipeName());
                     pipe.Disconnect();
                     break;
                    }
                  } else  {
                   i++; Print(IntegerToString(i)+" ticks received BY server.");
                  string bidask=DoubleToString(pipe.incoming.bid)+";"+DoubleToString(pipe.incoming.ask);
                  long currChart=ChartFirst(); int chart=0;
                  while(chart<100) 
                    {
                     EventChartCustom(currChart,6666,0,(double)account,bidask);
                     currChart=ChartNext(currChart); 
                     if(currChart==0) break;         // Reached the end of the charts list
                     chart++;
                    }
                     if(GlobalVariableCheck("gvar0")==true || (kernel32::GetLastError()==ERROR_BROKEN_PIPE)) break;
              
                 }
              }
            while(tickReceived==true);
            if(i>0)
              {
               Print(IntegerToString(i)+"ticks received.");
               i=0;
              };
            if(GlobalVariableCheck("gvar0")==true || (kernel32::GetLastError()==ERROR_BROKEN_PIPE)) break;
            Sleep(100);
           }

        }


  pipe.Close(); 
  }

ティック表示のために、わたしはティックインディケータを MQLmagazineに配置しましたが OnCalculate() メソッドの代わりにOnChartEvent()内部での処理を実装し、条件命令を追加しました。dparamパラメータがパイプ番号に等しく、イベントがCHARTEVENT_CUSTOM+6666に等しいときだけクオートは処理に受け付けられます。

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
  if (dparam==(double)incomingPipe)
   if(id>CHARTEVENT_CUSTOM)
     {
      if(id==CHARTEVENT_CUSTOM+6666)
        {
        // Process incoming tick
        }
     } else
        {
         // Handle the user event 
        }
  }

下のスクリーンショットでは、3つのティックインディケータがあります。

そのうち2つはパイプを介して受け取られたティックを表示し、パイプを使わない三番目のインディケータは失われたティックがないかチェックするため実行されます。

異なる端末からのデータを伴なうティックインディケータ

図1 名前付きパイプを介して受け取られたクオート

添付のスクリーンキャストを見てください。そこには私がインディケータを実行した方法がコメントとしてあります。


図2 インディケータの設定を述べたスクリーンキャスト


6. システムスループット検証

パイプは共有メモリを使うので、通信が速いのです。二台の MetaTrader 5端末間で100 000 および1 000 000ティックを送信するテストをしました。送信スクリプトはWriteTick() 関数を使いGetTickCount()を使ってタイムスパンを測定します。

   Print("Sending...");
   uint start = GetTickCount();
   for (int i=0;i<100000;i++)
      pipe.WriteTick(outgoing);
   uint stop = GetTickCount();
   Print("Sending took" + IntegerToString(stop-start) + " [ms]");
   pipe.Close();

サーバーは受信クオートを読みます。タイムスパンは最初の受信クオートからクライアントが接続を切るまで測定されます。

//+------------------------------------------------------------------+
//|                                          SpeedTestPipeServer.mq5 |
//|                                      Copyright 2010, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

#property script_show_inputs
#include <CNamedPipes.mqh>

input int account=0;
bool tickReceived;
uint start,stop;

CNamedPipe pipe;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int i=0;
   if(pipe.Create(account)==true)
      if(pipe.Connect()==true)
         Print("Pipe connected");

   do
     {
      tickReceived=pipe.ReadTick();
      if(i==0) start=GetTickCount();
      if(tickReceived==false)
        {
         if(kernel32::GetLastError()==ERROR_BROKEN_PIPE)
           {
            Print("Client disconnected from pipe "+pipe.GetPipeName());
            pipe.Disconnect();
            break;
           }
        }
      else i++;
     }
   while(tickReceived==true);
   stop=GetTickCount();

   if(i>0)
     {
      Print(IntegerToString(i)+" ticks received.");
      i=0;
     };
   
   pipe.Close();
   Print("Server: receiving took "+IntegerToString(stop-start)+" [ms]");

  }
//+------------------------------------------------------------------+

10回サンプル実行をした結果は以下です。

実行 クオート 送信時間 [ms] 受信時間 [ms]
1 100000 624 624
2 100000 702 702
3 100000 687 687
4 100000 592 608
5 100000 624 624
6 1000000 5616 5616
7 1000000 5788 5788
8 1000000 5928 5913
9 1000000 5772 5756
10 1000000 5710 5710

表1 Throughput スピード計測

1 000 000クオートの平均送信時間は170 000 ティック/秒でした。使用したのは、Windows Vista with 2.0GHz T4200 CPUと 3GB RAMです。


おわりに

名前付きパイプを使用したMetaTrader 5端末間コミュニケーション手法を提示しました。端末間でリアルタイムのクオート送信にはこの手法は十分であることが判りました。

CNamedPipesクラスがこれ以上の条件についてより範囲を拡げた内容に使用可能です。たとえば、2つの独立したアカウントにヘッジを作成する場合です。添付のCNamedPipeクラスソースコードをご覧ください。ドキュメンテーションもchmフォーマットで、また本稿執筆のために実装したその他のソースコードも一緒に添付しています。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/115

MQL5オブジェクト指向のプログラミングアプローチを使ったExpert Advisorのプログラミング MQL5オブジェクト指向のプログラミングアプローチを使ったExpert Advisorのプログラミング
本稿では初心者のためのAdvisor in MQL5でプログラミングをする段階的ガイドで行ったこと、すなわちExpert Advisor作成に対してオブジェクト指向のアプローチに注目します。ほとんどの方はこれは難しいと思われるでしょう。しかし本稿を読み終わるまでにみなさんはブジェクト指向でExpert Advisorを書けるようになっている、という点をはっきり述べておきたいと思います。
Google Chart APIからチャートを構築するためのライブラリ Google Chart APIからチャートを構築するためのライブラリ
さまざまなタイプのダイアグラムの構築がマーケット状況を分析しトレーディングシステムを検証する主要部分です。往々にしてみばえのよいダイアグラムを構築するにはデータのアウトプットをファイルに整理することが必要です。その後 MS Excelなどアプリケーションで使用していくのです。これはあまり便利な方法ではなく、動的にデータを更新する機能を奪います。Google Charts APIは、サーバーに特別な依頼を送るとオンラインでチャートを作成する手段を提供してくれます。本稿では、そのような依頼を作成し、チャートをGoogleサーバーから取得するプロセスを自動化していきます。
指定されたマジックナンバーによるトータルポジションボリューム計算のための最適化された手法 指定されたマジックナンバーによるトータルポジションボリューム計算のための最適化された手法
本稿では指定されたシンボルのトータルポジションボリューム計算とマジックナンバーに関する問題について考察します。提案する手法では取引履歴の最小限を要求し、トータルポジションがゼロに最も近い時刻を見つけ、最近の取引についての計算を行います。クライアント端末のグローバル変数による作業も考察します。
単一インスツルメント上で異なるExpert Advisorsを使ったトレーディングのためのORDER_MAGICの使用 単一インスツルメント上で異なるExpert Advisorsを使ったトレーディングのためのORDER_MAGICの使用
本稿は、異なるExpert Advisorsの自動トレーディングの分割、組立て、同期同様magic-identificationを使用したインフォメーションコーディングの疑問について考察します。本稿は、より経験を積んだトレーダー同様初心者にも興味深い内容となっています。その理由は、Expert Advisorsおよび様々な戦略の複雑なシステムの同期を実装するのに有用な垂直ポジションの疑問に取り組んでいるからです。