English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
その他のアプリのためにMetaTrader5の取引価格を準備する方法

その他のアプリのためにMetaTrader5の取引価格を準備する方法

MetaTrader 5 | 27 10月 2015, 10:35
693 0
Anatoli Kazharski
Anatoli Kazharski

内容

はじめに
1. 取り扱われるトピック
2. データフォーマット
3. プログラムの外部パラメーター
4. ユーザーにより入力されたパラメーターのチェック
5. グローバル変数
6. インフォメーションパネル
7. アプリのメインブロック
8. フォルダーの作成とデータの格納
結論


はじめに

MQL5を勉強し始める前に、トレーディングシステムの作成のためにその他多数のアプリケーションを試しました。時間の浪費だったとは言えません。いくつかは、ユーザーの時間を節約し、たくさんの問題を扱い、神話を破壊し、プログラミング言語の知識なしに、開発するためのより多くの方向性を素早く選択できるようにするいくつかのツールを持っています。

これらのアプリは、履歴データを必要とします。ある特定の標準データフォーマットがないため、それらは必要なプログラムに適用されるフォーマットに一致するために使用される前に(例えば、エクセルなど)編集されなければいけません。たとえ全ての必要な詳細を理解できるとしても、たくさんのことを手動で行う必要があります。ユーザーは、MetaTrader4から必要なフォーマットに取引価格をコピーするよう設計されたスクリプトの様々なバージョンを見つけることができます。もしそのような需要があれば、MQL5のためのスクリプトを開発できます。


1. 取り扱いトピック

この記事は、以下のトピックを紹介しています。

  • Market Watchウィンドウのシンボルリストの操作と、サーバーの共通シンボルリスト
  • 使用可能なデータ深度のチェックと、様々な状況を扱う上で必要なら欠如した量のダウンロード
  • カスタムパネルチャートとジャーナルでの必要なデータについての情報提示
  • ユーザー定義のフォーマットに格納するためのデータの準備
  • ファイルディレクトリの作成
  • データ格納


2. データフォーマット

NeuroShell DayTrader Professional (NSDT)にて使用されるためのデータを準備する例を提示します。NSDTバージョン5や6を試し、データフォーマットに異なる必要な点があるということがわかりました。NSDTバージョン5日付・時刻データは、異なるコラムにある必要があります。そのファイルの最初の行は、以下のようである必要があります:

"Date" "Time" "Open" "High" "Low" "Close" "Volume"

NSDTバージョン6のヘッダーラインは、そのアプリがファイルを受け取れるようにするために異なる姿になります。日付・時刻は同じコラムにあるということです。

Date,Open,High,Low,Close,Volume

MetaTrader5*.csvファイルの取引価格を保存できるようにします。ファイルのデータは以下のようになります;

図1. MetaTrader5ターミナルによって保存されるデータ

図1. MetaTrader5ターミナルによって保存されるデータ


しかし、そのデータがその他のフォーマットを持つように、ヘッダーを編集できません。NSDT v.5:

dd.mm.yyyy,hh:mm,Open,High,Low,Close,Volume
NSDT v.6:
dd/mm/yyyy hh:mm,Open,High,Low,Close,Volume

ドロップダウンリストは、スクリプト外部パラメーター内にて使用されます。そこでは、ユーザーは、必要なフォーマットを選択できます。ヘッダーとデータフォーマット選択するのとは別に、ユーザーにシンボルの数を選択させ、ファイルに書き込みたいデータを選ぶことができます。このために、3つのバージョンを用意します。

  • その現在のシンボルに関するデータをスクリプトがすでに稼働されているチャートに記述します。
  • Write the data on the symbols located in Market Watch ウィンドウ(MARKETWATCH SYMBOLS)に一するシンボルに関するデータを作成します。
  • サーバー(ALL LIST SYMBOLS)で使用可能な全てのシンボルにおけるデータを記載する。

そのようなリストを作成するためにスクリプトコードに外部コード前に以下のコードを入力しましょう。

//_________________________________
// HEADER_FORMATS_ENUMERATION
enum FORMAT_HEADERS
  {
   NSDT_5 = 0, // "Date" "Time" "Open" "High" "Low" "Close" "Volume"
   NSDT_6 = 1  // Date,Open,High,Low,Close,Volume
  };
//---
//___________________________
// ENUMERATION_OF_DATA_FORMATS
enum FORMAT_DATETIME
  {
   SEP_POINT1 = 0, // dd.mm.yyyy hh:mm
   SEP_POINT2 = 1, // dd.mm.yyyy, hh:mm
   SEP_SLASH1 = 2, // dd/mm/yyyy hh:mm
   SEP_SLASH2 = 3  // dd/mm/yyyy, hh:mm
  };
//---
//____________________________
// ENUMERATION_OF_FILING_MODES
enum CURRENT_MARKETWATCH
  {
   CURRENT          = 0, // ONLY CURRENT SYMBOLS
   MARKETWATCH      = 1, // MARKETWATCH SYMBOLS
   ALL_LIST_SYMBOLS = 2  // ALL LIST SYMBOLS
  };

MQL5 Referenceにて列挙型について詳しく知ることができます。


3. プログラムの外部パラメーター

スクリプトの全ての外部パラメーターリストを作成します。

//____________________________________________________________________
//+------------------------------------------------------------------+
//| EXTERNAL_PARAMETERS                                              |
//+------------------------------------------------------------------+
input datetime            start_date     = D'01.01.2011'; // Start Date
input datetime            end_date       = D'18.09.2012'; // End Date
input FORMAT_HEADERS      format_headers = NSDT_5;     // Format Headers
input FORMAT_DATETIME     format_date    = SEP_POINT2; // Format Datetime
input CURRENT_MARKETWATCH curr_mwatch    = CURRENT;    // Mode Write Symbols
input bool                clear_mwatch   = true;        // Clear Market Watch
input bool                show_progress  = true;        // Show Progress (%)

外部パラメーターは、以下の目的のために使用されます:

  • ユーザーは、Start Date(start_date)とEnd Date(end_date)パラメータを用いて日付間のインターバルを特定できます。
  • Format Headers (format_headers) ドロップダウンリストは、ヘッダーフォーマットを選択できるようにします。
  • Format Datetime (format_date) ドロップダウンリストは、ユーザーが日付フォーマットを選択できるようにします。
  • Mode Write Symbols (curr_mwatch) ドロップダウンリストは、ユーザーが格納のためのシンボル数を選択できるようにします。
  • Clear Market Watch (clear_mwatch)パラメーターが真であれば、ユーザーは格納後Market Windowウィンドウから全てのシンボルを削除できるようになります。これは、現在アクティブではないチャートのシンボルのみに関連します。
  • Show Progress (%) (show_progress) パラメーターは、格納の進行をデータパネルに表示します。その格納は、このパラメーターが停止されれば早く実行されます。

以下は、外部パラメーターが稼働中どのようになるかを示しています。

図 2. アプリの外部パラメーター

図 2. アプリの外部パラメーター


4. ユーザーによるパラメーターのチェック

ベースコード前にユーザーによって入力されたパラメーターのチェックのための関数を作成しましょう!例えば、そのStart Dateパラメーターの開始日付は、End Dateのそれよりも早いはずです。ヘッダーのフォーマットは、日付・時刻フォーマットにマッチするはずです。もしユーザーがパラメーターの設定時にいくつかのエラーを作成すれば、以下の警告メッセージが表示され、そのプログラムは停止されます。

サンプル警告メッセージ

図3. 間違って特定された値の警告

図3. 間違って特定されたパラメーターにおけるサンプルエラーメッセージ


ValidationParameters() 関数;

//____________________________________________________________________
//+------------------------------------------------------------------+
//| CHECKING_CORRECTNESS_OF_PARAMETERS                               |
//+------------------------------------------------------------------+
bool ValidationParameters()
  {
   if(start_date>=end_date)
     {
      MessageBox("The start date should be earlier than the ending one!\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Parameter error!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   if(format_headers==NSDT_5 && 
      (format_date==SEP_POINT1 || format_date==SEP_SLASH1))
     {
      MessageBox("For the headers of the following format:\n\n"
                 "\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\"\n\n"
                 "Date/time format can be selected out of two versions:\n\n"
                 "dd.mm.yyyy, hh:mm\n"
                 "dd/mm/yyyy, hh:mm\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Header and date/time formats do not match!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   if(format_headers==NSDT_6 && 
      (format_date==SEP_POINT2 || format_date==SEP_SLASH2))
     {
      MessageBox("For the headers of the following format:\n\n"
                 "Date,Open,High,Low,Close,Volume\n\n"
                 "Date/time format can be selected out of two versions:\n\n"
                 "dd.mm.yyyy hh:mm\n"
                 "dd/mm/yyyy hh:mm\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Header and date/time formats do not match!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   return(false);
  }


5. グローバル変数

次に、全てのグローバル変数、スクリプトにて使用される配列を決定する必要があります;

//____________________________________________________________________
//+------------------------------------------------------------------+
//| GLOBAL_VARIABLES_AND_ARRAYS                                      |
//+------------------------------------------------------------------+
MqlRates rates[]; // Array for copying data
//---
string symbols[]; // Symbol array
//---
// Array of graphic object names
string arr_nmobj[22]=
  {
   "fon","hd01",
   "nm01","nm02","nm03","nm04","nm05","nm06","nm07","nm08","nm09","nm10",
   "nm11","nm12","nm13","nm14","nm15","nm16","nm17","nm18","nm19","nm20"
  };
//---
// Array of displayed text containing graphic objects
string arr_txtobj[21];
//---
string path="";         // File path
int cnt_symb=0;         // Number of symbols
int sz_arr_symb=0;      // Symbol array size
int bars=0;             // Number of bars according to the specified TF
int copied_bars=0;      // Number of bars copied for writing
double pgs_pcnt=0;      // Writing progress
int hFl=INVALID_HANDLE;  // File handle
//---
string   // Variables for data formatting
sdt="",  // Date line
dd="",   // Day
mm="",   // Month
yyyy="", // Year
tm="",   // Time
sep="";  // Separator
//---
int max_bars=0; // Maximum number of bars in the terminal settings
//---
datetime
first_date=0,        // First available data in a specified period
first_termnl_date=0, // First available data in the terminal's database
first_server_date=0, // First available data in the server's database
check_start_date=0;  // Checked correct date value


6. インフォーメーションパネル

インフォメーションパネルにて表示されるべき要素を扱います。グラフィックオブジェクトの3つの種類がバックグラウンドとして使用されます。

  • 最もシンプルで、明確なものとして – "Rectangle label" (OBJ_RECTANGLE_LABEL)があります。
  • インターフェースを特徴的なものにしたい人は、 "Bitmap" オブジェクト(OBJ_BITMAP)を使用できます。
  • "Edit" オブジェクト (OBJ_EDIT) は、バックグラウンドとして使用されます。 "読み取り専用"プロパティをテキストが書き込まれる可能性を除去するために設定してください。 "Edit" オブジェクトを使用することによる別の利点があります。もしExpert Advisorのインフォメーションパネルを作成し、ビジュアル化モードのテスト中に同じようなインターフェースにしたい場合、最後のタイプがそれを実現する上での唯一の手段です。OBJ_RECTANGLE_LABELやOBJ_BITMAP は、ビジュアル化モードのテスト中には表示されません。

Expert Advisorの代わりのスクリプトを通してのみ開発されるOBJ_EDITオブジェクトのバックグラウンドは例として作成されます。その結果は、以下の図にて示されます:

図4. インフォメーションパネル

図4. インフォメーションパネル


そのパネルにて示される全てのデータを記載します:

  • Symbol (current/total) – シンボル、現在ダウンロード/コピー/記述されるデータ角括弧の左の数字は、現在のシンボル数を示します。右の数字は、そのスクリプトが扱う共通のシンボル数を示します。
  • Path Symbol – 所属するシンボルパスやカテゴリMarket Watchウィンドウで右クリックすることで、コンテクストメニューを出し、「Symobols...」を選択すると、そのウィンドウは全てののシンボルリストとともに表示されます。ターミナルのユーザーガイドにて詳細をご覧になれます。
  • Timeframe – 期間(timeframe). スクリプトが稼働されるタイムフレームは使用される必要があります。
  • Input Start Date – スクリプトパラメーターにてユーザーにより特定されたデータ開始日付
  • First Date (H1) – 現在のタイムフレームの最初の使用可能データ日付
  • First Terminal Date (M1) – すでに存在するターミナルデータのM1タイムフレームの最初の使用可能日付
  • First Server Date (M1) – サーバーのM1タイムフレームの最初の使用可能な日付
  • Max. Bars In Options Terminal – ターミナルの設定にて明記されるチャートで表示されるバーの最大数
  • Copied Bars – 記述のためのコピーされたバーの数
  • Progress Value Current Symbol – 現在のシンボルの記述されるデータのパーセント値

以下は、そのようなインフォメーションパネルのコードです。

//____________________________________________________________________
//+------------------------------------------------------------------+
//| INFORMATION_PANEL                                                |
//|------------------------------------------------------------------+
void InfoTable(int s)
  {
   int fnt_sz=8;            // Font size
   string fnt="Calibri";     // Header font
   color clr=clrWhiteSmoke;  // Color
//---
   int xH=300;
   int height_pnl=0;
   int yV1=1,yV2=12,xV1=165,xV2=335,xV3=1;
//---
   string sf="",stf="",ssf="";
   bool flg_sf=false,flg_stf=false,flg_ssf=false;
//---
   if(show_progress) { height_pnl=138; } else { height_pnl=126; }
//---
   flg_sf=SeriesInfoInteger(symbols[s],_Period,SERIES_FIRSTDATE,first_date);
   flg_stf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_termnl_date);
   flg_ssf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_SERVER_FIRSTDATE,first_server_date);
//---
   if(flg_sf) { sf=TSdm(first_date); } else { sf="?"; }
   if(flg_stf) { stf=TSdm(first_termnl_date); } else { stf="?"; }
   if(flg_ssf) { ssf=TSdm(first_server_date); } else { ssf="?"; }
//---
   if(cnt_symb==0) { cnt_symb=1; }
//---
   int anchor1=ANCHOR_LEFT_UPPER,anchor2=ANCHOR_RIGHT_UPPER,corner=CORNER_LEFT_UPPER;
//---
   string path_symbol=SymbolInfoString(symbols[s],SYMBOL_PATH);
   path_symbol=StringSubstr(path_symbol,0,StringLen(path_symbol)-StringLen(symbols[s]));
//---
   arr_txtobj[0]="INFO TABLE";
   arr_txtobj[1]="Symbol (current / total) : ";
   arr_txtobj[2]=""+symbols[s]+" ("+IS(s+1)+"/"+IS(cnt_symb)+")";
   arr_txtobj[3]="Path Symbol : ";
   arr_txtobj[4]=path_symbol;
   arr_txtobj[5]="Timeframe : ";
   arr_txtobj[6]=gStrTF(_Period);
   arr_txtobj[7]="Input Start Date : ";
   arr_txtobj[8]=TSdm(start_date);
   arr_txtobj[9]="First Date (H1) : ";
   arr_txtobj[10]=sf;
   arr_txtobj[11]="First Terminal Date (M1) : ";
   arr_txtobj[12]=stf;
   arr_txtobj[13]="First Server Date (M1) : ";
   arr_txtobj[14]=ssf;
   arr_txtobj[15]="Max. Bars In Options Terminal : ";
   arr_txtobj[16]=IS(max_bars);
   arr_txtobj[17]="Copied Bars : ";
   arr_txtobj[18]=IS(copied_bars);
   arr_txtobj[19]="Progress Value Current Symbol : ";
   arr_txtobj[20]=DS(pgs_pcnt,2)+"%";
//---
   Create_Edit(0,0,arr_nmobj[0],"",corner,fnt,fnt_sz,clrDimGray,clrDimGray,345,height_pnl,xV3,yV1,2,C'15,15,15');
//---
   Create_Edit(0,0,arr_nmobj[1],arr_txtobj[0],corner,fnt,8,clrWhite,C'64,0,0',345,12,xV3,yV1,2,clrFireBrick);
//---
   Create_Label(0,arr_nmobj[2],arr_txtobj[1],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2,0);
   Create_Label(0,arr_nmobj[3],arr_txtobj[2],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2,0);
//---
   Create_Label(0,arr_nmobj[4],arr_txtobj[3],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*2,0);
   Create_Label(0,arr_nmobj[5],arr_txtobj[4],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*2,0);
//---
   Create_Label(0,arr_nmobj[6],arr_txtobj[5],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*3,0);
   Create_Label(0,arr_nmobj[7],arr_txtobj[6],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*3,0);
//---
   Create_Label(0,arr_nmobj[8],arr_txtobj[7],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*4,0);
   Create_Label(0,arr_nmobj[9],arr_txtobj[8],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*4,0);
//---
   Create_Label(0,arr_nmobj[10],arr_txtobj[9],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*5,0);
   Create_Label(0,arr_nmobj[11],arr_txtobj[10],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*5,0);
//---
   Create_Label(0,arr_nmobj[12],arr_txtobj[11],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*6,0);
   Create_Label(0,arr_nmobj[13],arr_txtobj[12],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*6,0);
//---
   Create_Label(0,arr_nmobj[14],arr_txtobj[13],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*7,0);
   Create_Label(0,arr_nmobj[15],arr_txtobj[14],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*7,0);
//---
   Create_Label(0,arr_nmobj[16],arr_txtobj[15],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*8,0);
   Create_Label(0,arr_nmobj[17],arr_txtobj[16],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*8,0);
//---
   Create_Label(0,arr_nmobj[18],arr_txtobj[17],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*9,0);
   Create_Label(0,arr_nmobj[19],arr_txtobj[18],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*9,0);
//---
   if(show_progress)
     {
      Create_Label(0,arr_nmobj[20],arr_txtobj[19],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*10,0);
      Create_Label(0,arr_nmobj[21],arr_txtobj[20],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*10,0);
     }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| CREATING_LABEL_OBJECT                                            |
//+------------------------------------------------------------------+
void Create_Label(long   chrt_id,   // chart id
                  string lable_nm,  // object name
                  string rename,    // displayed name
                  long   anchor,    // anchor point
                  long   corner,    // attachment corner
                  string font_bsc,  // font
                  int    font_size, // font size
                  color  font_clr,  // font color
                  int    x_dist,    // X scale coordinate
                  int    y_dist,    // Y scale coordinate
                  long   zorder)    // priority
  {
   if(ObjectCreate(chrt_id,lable_nm,OBJ_LABEL,0,0,0)) // creating object
     {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,rename);          // set name
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);        // set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);      // set font color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ANCHOR,anchor);       // set anchor point
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);       // set attachment corner
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);  // set font size
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);    // set X coordinates
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);    // set Y coordinates
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,false);     // unable to highlight the object, if FALSE
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);       // Higher/lower priority
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");         // no tooltip, if "\n"
     }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| CREATING_EDIT_OBJECT                                             |
//+------------------------------------------------------------------+
void Create_Edit(long   chrt_id,       // chart id
                 int    nmb_win,       // window (subwindow) index
                 string lable_nm,      // object name
                 string text,          // displayed text
                 long   corner,        // attachment corner
                 string font_bsc,      // font
                 int    font_size,     // font size
                 color  font_clr,      // font color
                 color  font_clr_brd,  // font color
                 int    xsize,         // width
                 int    ysize,         // height
                 int    x_dist,        // X scale coordinate
                 int    y_dist,        // Y scale coordinate
                 long   zorder,        // priority
                 color  clr)           // background color
  {
   if(ObjectCreate(chrt_id,lable_nm,OBJ_EDIT,nmb_win,0,0)) // creating object
     {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,text);                     // set name
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);                // set attachment corner
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);                 // set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ALIGN,ALIGN_CENTER);         // center alignment
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);           // set font size
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);               // font color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_BORDER_COLOR,font_clr_brd);    // background color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_BGCOLOR,clr);                  // background color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XSIZE,xsize);                  // width
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YSIZE,ysize);                  // height
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);             // set X coordinate
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);             // set Y coordinate
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,false);              // unable to highlight the object, if FALSE
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);                // Higher/lower priority
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_READONLY,true);                // Read only
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");                  // no tooltip if "\n"
     }
  }

そのスクリプトの処理が終了するか、そのスクリプトがユーザーにより先に削除されたのちに、スクリプトにより作成された全てのグラフィックオブジェクトが削除される必要があります。以下の関数は、そのために使用されます:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| DELETE_ALL_GRAPHICAL_OBJECTS_CREATED_BY_THE_SCRIPT               |
//+------------------------------------------------------------------+
void DelAllScriptObjects()
  {
// Receive the size of graphical object names array
   int sz_arr1=ArraySize(arr_nmobj);
//---
// Delete all objects
   for(int i=0; i<sz_arr1; i++)
     { DelObjbyName(arr_nmobj[i]);  }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| DELETE_OBJECTS_BY_NAME                                           |
//+------------------------------------------------------------------+
int DelObjbyName(string Name)
  {
   int nm_obj=0;
   bool res=false;
//---
   nm_obj=ObjectFind(ChartID(),Name);
//---
   if(nm_obj>=0)
     {
      res=ObjectDelete(ChartID(),Name);
      //---
      if(!res) { Print("Object deletion error: - "+ErrorDesc(Error())+""); return(false); }
     }
//---
   return(res);
  }


7. アプリのメインブロック

そのスクリプトの主な関数はOnStart()です。これは、実行のためその他の関数を読み出すために使用される関数です。そのプログラムの処理の詳細は以下のコードにて示されます。

//____________________________________________________________________
//+------------------------------------------------------------------+
//| SCRIPT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
//+------------------------------------------------------------------+
void OnStart()
  {
// If user-defined parameters are incorrect,
// error message is shown and the program is closed
   if(ValidationParameters()) { return; }
//---
   max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); // Receive available number of bars in the window
//---
   GetSymbolsToArray();           // Filling symbol array with names
   sz_arr_symb=ArraySize(symbols); // Receive symbol array size
//---
   SetSeparateForFormatDate();    // Set a separator for date format
//---
// Revise all symbols and write their data to file
   for(int s=0; s<=sz_arr_symb-1; s++)
     {
      copied_bars=0; // Reset copied bars variable to zero for writing
      pgs_pcnt=0.0;  // Reset variable of the symbol data writing progress 
      //---
      InfoTable(s); ChartRedraw();
      //---
      // Receive current symbol data
      int res=GetDataCurrentSymbol(s);
      //---
      if(res==0) { BC } // If zero, break the loop or start the next iteration
      //---
      if(res==2)        // Program operation interrupted by user
        {
         DelAllScriptObjects(); // Deleted objects created by the script from the chart
         //---
         Print("------\nUser deleted the script!"); break;
        }
      //---
      // Receive the path for creating the file and create directories for them
      // If the string is empty, break the loop or start the next iteration
      if((path=CheckCreateGetPath(s))=="") { BC }
      //---
      WriteDataToFile(s); // Write data to file
     }
//---
// Delete symbols from Market Watch window if necessary
   DelSymbolsFromMarketWatch();
//---
// Delete objects created by the script from the chart
   Sleep(1000); DelAllScriptObjects();
  }

重要な点が発生している関数を詳しく見てみましょう。

そのシンボル配列は、(symbols[]) は、GetSymbolsToArray() 関数のシンボル名が格納されます。シンボル数と同様、配列サイズは、Mode Write Symbols(curr_mwatch)パラメーターのユーザーにより選択されたバリアントに依存します。

もしユーザーが1つのシンボルのみからデータを得るのであれば、配列のサイズは1に等しいです。

ArrayResize(symbols,1); // Set the array size to be equal to 1
symbols[0]=_Symbol;     // Specify the current symbol's name

もしユーザーがMarket Watchウィンドウからの全てのシンボルにおけるデータを取得したければ、その配列サイズは、以下の関数により定義されます。

int SymbolsTotal(
   bool selected   // true – only MarketWatch symbols
);

同一のコードにおける二つのバリアントでの二つのブロックの作成を避けるために、MWatchOrAllList()ポインター関数を作成します。これはtrueかfalseを返します。この値がシンボルリストがとこから取得されるかを定義します - Market Watchウィンドウか(true)、シンボルの共通リストからです。(false)

//____________________________________________________________________
//+------------------------------------------------------------------+
//| POINTER_TO_MARKET_WATCH_WINDOW_OR_TO_COMMON_LIST                 |
//+------------------------------------------------------------------+
bool MWatchOrAllList()
  {
   if(curr_mwatch==MARKETWATCH) { return(true); }
   if(curr_mwatch==ALL_LIST_SYMBOLS) { return(false); }
//---
   return(true);
  }

ループのシンボル数を取得したのち、全てのリストを通過し、シンボル名をその配列に配列サイズを1ずつ大きくする反復ごとに挿入します。シンボル名SymbolName()関数を用いてインデックス数によr取得されます。

int SymbolName(
   int pos,        // list index number
   bool selected   // true – only MarketWatch symbols
);

MWatchOrAllList()ポインター関数は、SymbolName()関数にてシンボルリストを選択するために使用されます。GetSymbolsToArray()関数コード:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| FILLING_SYMBOL_ARRAY_WITH_NAMES                                  |
//+------------------------------------------------------------------+
void GetSymbolsToArray()
  {
// If only the current symbol data is required
   if(curr_mwatch==CURRENT)
     { ArrayResize(symbols,1); symbols[0]=_Symbol; }
//---
// If data on all symbols  from Market Watch window or
// or the entire symbol list is required
   if(curr_mwatch==MARKETWATCH || curr_mwatch==ALL_LIST_SYMBOLS)
     {
      // Receive the number of symbols in Market Watch window
      cnt_symb=SymbolsTotal(MWatchOrAllList());
      //---
      for(int i=0; i<=cnt_symb-1; i++)
        {
         string nm_symb="";
         //---
         ArrayResize(symbols,i+1); // Increase the array size by one once again
         //---
         // Receive a name of a symbol from Market Watch window
         nm_symb=SymbolName(i,MWatchOrAllList());
         symbols[i]=nm_symb; // Put the symbol name into the array
        }
     }
  }

SetSeparateForFormatDate() 関数はとてもシンプルです。どの種類のセパレーターがFormat Dateパラメーターのドロップダウンリストのユーザーの選択に応じて使用されるかを定義するために使用されます。

//____________________________________________________________________
//+------------------------------------------------------------------+
//| DEFINING_SEPARATOR_FOR_DATE_FORMAT                               |
//+------------------------------------------------------------------+
void SetSeparateForFormatDate()
  {
   switch(format_date)
     {
      case SEP_POINT1 : case SEP_POINT2 : sep="."; break; // Full point as a separator
      case SEP_SLASH1 : case SEP_SLASH2 : sep="/"; break; // Slash as a separator
     }
  }

様々なチェックを持つループは次です。全てのチェックが成功すれば、そのデータはファイルに記載されます。さもなければ、そのループは終了し、全てのオブジェクトはチャートから削除され、そのスクリプトは除去されるか(1つのシンボルの場合)、次の反復が開始します。(一つ以上のシンボルの場合)symbols[]配列のそれぞれのシンボルは、ループにて呼ばれます。インデックス数は、ループのそれぞれの関数に送られます。したがって、全ての関数における正確なシーケンスが保存されます。

そのループの現在のシンボルに関するデータは、ループ分の最初で取得されます。GetDataCurrentSymbol() 関数がそのために使用されます。この関数内で何が起こるか見てみましょう。

シンボルデータをrate[]配列にコピーする前に、CheckLoadHistory()関数を用いてデータの使用可能性がチェックされます。この関数は、例として開発者により提供されています。MQL5 Referenceにて初期バージョンをご覧になれます。そのスクリプトを使用してわずかな訂正を行いました。そのリファレンスは、詳しい記載を持っているので(勉強してみるのも良いです)、私のものは紹介しません。さらに、詳細なコメント付きのコードをご覧になれます。

ここで言及できる唯一の点は、CheckLoadHistory()関数がエラーか成功した実行コードをかえし、それに応じて、switchオペレーターブロックから適切なメッセージがジャーナル内に保存されます。取得されたコードによると、GetDataCurrentSymbol() 関数は、処理に従うか、そのコードを返します。

全てがうまくいった場合、CopyRates()関数を用いて、履歴データがコピーされます。その配列サイズは、グローバル変数に保存されます。それから、関数からのエグジットは、コード1を返したのち、実行されます。もしうまくいかなければ、その関数は、switchオペレーターにて処理を停止し、0か2のコードを返します。

//____________________________________________________________________
//+------------------------------------------------------------------+
//| RECEIVE_SYMBOL_DATA                                              |
//+------------------------------------------------------------------+
int GetDataCurrentSymbol(int s)
  {
   Print("------\n№"+IS(s+1)+" >>>"); // Save a symbol number in the journal
//---
// Check and download the necessary amount of requested data
   int res=CheckLoadHistory(s,_Period);
//---
   InfoTable(s); ChartRedraw(); // Update the data in the data table
//---
   switch(res)
     {
      case -1 : Print("Unknown symbol "+symbols[s]+" (code: -1)!");                        return(0);
      case -2 :
         Print("Number of requested bars exceeds the maximum number that can be displayed on a chart (code: -2)!...\n"
               "...The available amount of data will be used for writing.");                break;
      //---
      case -3 : Print("Execution interrupted by user (code: -3)!");                         return(2);
      case -4 : Print("Download failed (code: -4)!");                                      return(0);
      case  0 : Print("All symbol data downloaded (code: 0).");                             break;
      case  1 : Print("Time series data is sufficient (code: 1).");                          break;
      case  2 : Print("Time series created based on existing terminal data (code: 2).");      break;
      //---
      default : Print("Execution result is not defined!");
     }
//---
// Copy data to the array
   if(CopyRates(symbols[s],_Period,check_start_date,end_date,rates)<=0)
     { Print("Error when copying symbol data "+symbols[s]+" - ",ErrorDesc(Error())+""); return(0); }
   else
     {
      copied_bars=ArraySize(rates); // Receive array size
      //---
      Print("Symbol: ",symbols[s],"; Timeframe: ",gStrTF(_Period),"; Copied bars: ",copied_bars);
     }
//---
   return(1); // Return 1, if all is well
  }

そのあと、そのプログラムはOnStart()関数のループ部分に配置されます。res ローカル変数によりそのコードは割り当てられ、チェックがその値に沿って実行されます。ゼロ値はエラーを意味します。ループの現在のシンボルデータが記述できないということを意味します。エラーの説明は、ジャーナルにて保存され、その決定はもしそのループが停止するか、次の反復が開始されるなら、実行されます。

if(res==0) { BC } // If zero, the loop is interrupted or the next iteration starts

上記コードは、この選択がBCキャラクターにより実行されることを示します。マクロの拡大があります。それについての情報はMQL5 Referenceでご覧になれます。言及されるべき唯一の点は、全ての表現は、上記の例で示されていたようなショートエントリに貼り付けられます。ある場合、このメソッドは、より便利で関数よりもコンパクトなものになります。現在の場合、これは以下のようになります:

// Macro expansion with further action selection
#define BC if(curr_mwatch==CURRENT) { break; } if(curr_mwatch==MARKETWATCH || curr_mwatch==ALL_LIST_SYMBOLS) { continue; }

以下は、このスクリプトで使用されるマクロ拡大のその他の例です。

#define nmf __FUNCTION__+": " // Macro expansion of the function name before sending the message to the journal
//---
#define TRM_DP TerminalInfoString(TERMINAL_DATA_PATH) // Folder for storing the terminal data

GetDataCurrentSymbol()が2を返すなら、そのプログラムは、ユーザーにより除去されます。MQL5は、IsStopped()関数をこのイベントを特定するために所持しています。この関数が、プログラムの処理を時間内に正しく停止する上で役に立ちます。もしその関数がtrueを返すと、プログラムが除去される前に3秒の全ての処理を実行する時間があります。全てのグラフィカルオブジェクトは除去され、そのメッセージはジャーナルに送られます:

if(res==2) // Program execution interrupted by user
   {
    DelAllScriptObjects(); // Delete all objects created by the script from the chart
    //---
    Print("------\nUser deleted the script!"); break;
   }


8. フォルダーの作成とデータの格納

CheckCreateGetPath() 関数は、ルートデータフォルダーの存在をチェックします。DATA_OHLCと呼び、 C:\Metatrader 5\MQL5\Filesに格納しましょう。シンボル名のあるフォルダーを持ちます。データの記述するためのファイルがそこに作成されます。

もしルートフォルダーか、現在のシンボルにおけるフォルダーは存在しないなら、その関数がそれを作成します。もし全てがうまくいけば、その関数は、ファイルの作成のためのパスを含むStringを返します。ユーザーにより実行されたチャートからのプログラムの削除の試みか、エラーの場合、その関数は空のStringを返します。

以下のコードは、理解を助ける詳細なコメント付きです。

//____________________________________________________________________
//+------------------------------------------------------------------+
//| CHECK_DIRECTORY_AND_CREATE_NECESSARY_DATA_FOLDERS                |
//+------------------------------------------------------------------+
string CheckCreateGetPath(int s)
  {
   int i=1;
   long search=-1;
   string ffname="",lpath="";
   string file="*.csv",folder="*";
   string
   root="DATA_OHLC\\",         // Root data folder
   fSmb=symbols[s]+"\\",     // Symbol name
   fTF=gStrTF(_Period)+"\\"; // Symbol time frame
//---
   bool flgROOT=false,flgSYMBOL=false;
//---
//+------------------------------------------------------------------+
//| SEARCHING_FOR_DATA_OHLC_ROOT_FOLDER                              |
//+------------------------------------------------------------------+
   lpath=folder;
   search=FileFindFirst(lpath,ffname); // Set search handle in Metatrader 5\MQL5\Files
//---
   Print("Directory: ",TRM_DP+"\\MQL5\\Files\\");
//---
// Set the flag if the first folder is a root one
   if(ffname==root)
     { flgROOT=true; Print("Root folder "+root+" present"); }
//---
   if(search!=INVALID_HANDLE) // If search handle received
     {
      if(!flgROOT) // If the first folder is not a root one
        {
         // Sort out all files searching for the root folder
         while(FileFindNext(search,ffname))
           {
            if(IsStopped()) // Execution interrupted by user
              {
               // Delete objects created by the script from the chart
               DelAllScriptObjects();
               //---
               Print("------\nUser deleted the script!"); return("");
              }
            //---
            if(ffname==root) // Set the flag if found
              { flgROOT=true; Print("Root folder "+root+" present"); break; }
           }
        }
      //---
      FileFindClose(search); search=-1; // Close root folder search handle
     }
   else { Print("Error when receiving the search handle or directory "+TRM_DP+" is empty: ",ErrorDesc(Error())); }
//---
//+------------------------------------------------------------------+
//| SEARCHING_SYMBOL_FOLDER                                          |
//+------------------------------------------------------------------+
   lpath=root+folder;
//---
// Set search handle in the root folder ..\Files\DATA OHLC\
   search=FileFindFirst(lpath,ffname);
//---
// Set the flag if the first folder of the current symbol
   if(ffname==fSmb) { flgSYMBOL=true; Print("Symbol folder "+fSmb+" present"); }
//---
   if(search!=INVALID_HANDLE) // If search handle is received
     {
      if(!flgSYMBOL) // If the first folder is not of the current symbol
        {
         // Sort out all the files in the root folder searching the symbol folder
         while(FileFindNext(search,ffname))
           {
            if(IsStopped()) // Execution interrupted by user
              {
               // Delete objects created by the script from the chart
               DelAllScriptObjects();
               //---
               Print("------\nUser deleted the script!"); return("");
              }
            //---
            if(ffname==fSmb) // Set the flag if found
              { flgSYMBOL=true; Print("Symbol folder"+fSmb+" present"); break; }
           }
        }
      //---
      FileFindClose(search); search=-1; // Close symbol folder search handle
     }
   else { Print("Error when receiving search handle or the directory "+path+" is empty"); }
//---
//+------------------------------------------------------------------+
//| CREATE_NECESSARY_DIRECTORIES_ACCORDING_TO_CHECK_RESULTS          |
//+------------------------------------------------------------------+
   if(!flgROOT) // If there is no DATA_OHLC... root folder
     {
      if(FolderCreate("DATA_OHLC")) // ...we should create it
        { Print("..\DATA_OHLC\\ root folder created"); }
      else
        { Print("Error when creating DATA_OHLC: root folder",ErrorDesc(Error())); return(""); }
     }
//---
   if(!flgSYMBOL) // If there is no folder of the symbol, the values of which should be received...
     {
      if(FolderCreate(root+symbols[s])) // ...we should create it
        {
         Print("..\DATA_OHLC\\" symbol folder created+fSmb+"");
         //---
         return(root+symbols[s]+"\\"); // Return the path for creating the file for writing
        }
      else
        { Print("Error when creating ..\DATA_OHLC\\ symbol folder"+fSmb+"\: ",ErrorDesc(Error())); return(""); }
     }
//---
   if(flgROOT && flgSYMBOL)
     {
      return(root+symbols[s]+"\\"); // Return the path for creating the file for writing
     }
//---
   return("");
  }

CheckCreateGetPath()関数が空の行を返した場合、そのループは停止されるか、次の反復がすでに馴染みのあるマクロ拡大(BC)を用いて開始します。

// Receive the path for creating a file and create directories for them
// If the line is empty, the loop is interrupted or the next iteration starts
if((path=CheckCreateGetPath(s))=="") { BC }

もしこのステージに達すれば、そのデータはうまくコピーされ、パスString変数は、ループの現在のシンボルのデータの記述のためにファイルを作成するパスを含みます。

そのファイルにデータを記述するためのWriteDataToFile()関数を作成します。[Path]+[file name] がその関数の最初に生成されます。ファイル名は、シンボル名や現在のタイムフレームからなります。例えば、 EURUSD_H1.csv. もしそのような名前を持つファイルがすでに存在していれば、記述のために展開されます。以前記述されたデータが削除されます。新しいデータが変わりに記述されます。もしそのファイルがうまく作成/開かれれば、FileOpen()関数は、ファイルへのアクセスに使用されるハンドラを返します。

ハンドルのチェックもしそれが存在すれば、そのヘッダー行が記述されます。適切な行がユーザーによって選択されたヘッダーに応じて記述されます。履歴データの記述のループはその後始まります。

次の行を記述する前に、ユーザーによって明記されたフォーマットに転換される必要があります。そのために、バーオープン時刻を取得し、日、月、年、時刻で個別に StringSubstr() 関数を用いて分類する必要があります。それから、その日付や時間が、シングルか個別のコラムに位置するかをユーザーによって明記されたフォーマットに応じて設定します。StringConcatenate()関数を用いて全てが一つの行に組み合わされます。全ての行が記述された後、FileClose()関数によってそのファイルが閉じられます。

WriteDataToFile()関数コードが以下に示されています:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| WRITE_DATA_TO_FILE                                               |
//+------------------------------------------------------------------+
void WriteDataToFile(int s)
  {
// Number of decimal places in the symbol price
   int dgt=(int)SymbolInfoInteger(symbols[s],SYMBOL_DIGITS);
//---
   string nm_fl=path+symbols[s]+"_"+gStrTF(_Period)+".csv"; // File name
//---
// Receive file handle for writing
   hFl=FileOpen(nm_fl,FILE_WRITE|FILE_CSV|FILE_ANSI,',');
//---
   if(hFl>0) // If the handle is received
     {
      // Write the headers
      if(format_headers==NSDT_5)
        { FileWrite(hFl,"\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\""); }
      //---
      if(format_headers==NSDT_6)
        { FileWrite(hFl,"Date","Open","High","Low","Close","Volume"); }
      //---
      // Write the data
      for(int i=0; i<=copied_bars-1; i++)
        {
         if(IsStopped()) // If program execution interrupted by a user
           {
            DelAllScriptObjects(); // Delete objects created by the script from the chart
            //---
            Print("------\nUser deleted the script!"); break;
           }
         //---
         sdt=TSdm(rates[i].time); // Bar open time
         //---
         // Divide the date by year, month and time
         yyyy=StringSubstr(sdt,0,4);
         mm=StringSubstr(sdt,5,2);
         dd=StringSubstr(sdt,8,2);
         tm=StringSubstr(sdt,11);
         //---
         string sep_dt_tm=""; // Separator of Date and Time columns
         //---
         // Join the data with the separator in the necessary order
         if(format_date==SEP_POINT1 || format_date==SEP_SLASH1) { sep_dt_tm=" "; }
         if(format_date==SEP_POINT2 || format_date==SEP_SLASH2) { sep_dt_tm=","; }
         //---
         // Join everything in one line
         StringConcatenate(sdt,dd,sep,mm,sep,yyyy,sep_dt_tm,tm);
         //---
         FileWrite(hFl,
                   sdt,// Date-time
                   DS_dgt(rates[i].open,dgt),      // Open price
                   DS_dgt(rates[i].high,dgt),      // High price
                   DS_dgt(rates[i].low,dgt),       // Low price
                   DS_dgt(rates[i].close,dgt),     // Close price
                   IS((int)rates[i].tick_volume)); // Tick volume price
         //---
         // Update writing progress value for the current symbol
         pgs_pcnt=((double)(i+1)/copied_bars)*100;
         //---
         // Update data in the table
         InfoTable(s); if(show_progress) { ChartRedraw(); }
        }
      //---
      FileClose(hFl); // Close the file
     }
   else { Print("Error when creating/opening file!"); }
  }

これは、OnStart()関数の基礎ループにおける最後の関数です。もしそれが最後のシンボルでなければ、全てが次のために繰り返されます。さもなければ、そのループが終了されます。もしMarket Watchウィンドウにてシンボルリストを除去するよう明記すれば、現在の非活性チャートのシンボルは、DelSymbolsFromMarketWatch()関数によって削除されます。その後、そのスクリプトによって作成された全てのグラフィカルオブジェクトは削除され、そのプログラムは停止します。そのデータは使用準備ができています。

NeuroShell DayTrader Professionalにデータをダウンロードする方法については、私のブログにてご覧ください。以下は、スクリプトの処理を示すビデオです。


結論

トレーディング戦略を開発するために使用するプログラムが何であれ、常にアイディアの実現を妨げる制限にぶつかりました。最終的に、プログラミングは重要であると気付きました。MQL5は、本当に成功したい人のための最高のソリューションです。しかし、データ分析とトレーディング戦略の作成におけるその他のプログラムは、新しい案を探索する際に便利です。もしツールを一つのみ使用していれば、それらを見つけるのにもっと多くの時間がかかったことでしょう。

がんばってください!

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/502

添付されたファイル |
writedatatofile.mq5 (68.96 KB)
MetaTraderのマーケットからトレードロボットを購入し、インストールする方法 MetaTraderのマーケットからトレードロボットを購入し、インストールする方法
メタトレーダーのプロダクトは、mql5.com のウェブサイト上またはMetaTrader4,MetaTrader5から直接買うことができます。 希望のお支払い方法を選択して、トレーディングスタイルに合ったプロダクトをお選びいただき、アクティベートしてください。
DLLを使用せず、名前のつけられたパイプを使っての MetaTrader 5との通信 DLLを使用せず、名前のつけられたパイプを使っての MetaTrader 5との通信
多くの開発者が同じ課題に出会います。安全性の低い DLL を使わずトレーディングターミナルのサンドボックスを手に入れる方法です。もっとも簡単で安全な方法の一つは、通常のファイル処理で動作する標準的な「名前付きパイプ」を使用することです。名前付きパイプにより、プロセッサ内でプログラム間のクライアントサーバー通信を行うことができます。サーバー、クライアント、それらの間のデータ交換、パフォーマンスのベンチマークを含んだ C++ 言語および MQL5 での実用例を見ていきます。
ニューラルネットワーク:理論~実践 ニューラルネットワーク:理論~実践
今日、トレーダーはだれしもニューラルネットワークについて聞いたことがあり、それを使うのがかっこいいということがわかっています。多数の人がニューラルネットワークを利用してディールを行える人はスーパーヒューマンだと思っています。本稿ではニューラルネットワークのアーキテクチャを説明し、アプリケーションについて記述し、実用例を示していこうと思います。
トレーディングシグナルを定期購入する方法 トレーディングシグナルを定期購入する方法
「シグナル」サービスは MetaTrader 4 および MetaTrader 5でのソーシャルトレーディングを紹介します。その「サービス」はトレーディングプラットフォームに統合され、だれでも簡単にプロのトレーダーのトレードをコピーすることができます。シグナル提供者の何千というシグナルをどれでも選び、数回クリックするだけで定期購買をすると、提供者のトレードがみなさんのアカウントにコピーされます。