その他のアプリのためにMetaTrader5の取引価格を準備する方法
内容
はじめに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ターミナルによって保存されるデータ
しかし、そのデータがその他のフォーマットを持つように、ヘッダーを編集できません。NSDT v.5:
dd.mm.yyyy,hh:mm,Open,High,Low,Close,VolumeNSDT 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. アプリの外部パラメーター
4. ユーザーによるパラメーターのチェック
ベースコード前にユーザーによって入力されたパラメーターのチェックのための関数を作成しましょう!例えば、そのStart Dateパラメーターの開始日付は、End Dateのそれよりも早いはずです。ヘッダーのフォーマットは、日付・時刻フォーマットにマッチするはずです。もしユーザーがパラメーターの設定時にいくつかのエラーを作成すれば、以下の警告メッセージが表示され、そのプログラムは停止されます。
サンプル警告メッセージ
図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. インフォメーションパネル
そのパネルにて示される全てのデータを記載します:
- 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
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索