MQL5 プログラミングの基礎: ファイル
コンテンツ
- イントロダクション
- テキスト ファイルを読み込み
- テキスト ファイルを作成。
- テキスト ファイルの末尾への書き込み
- テキスト ファイルの指定した行を変更。
- 配列にテキスト ファイルを読み取る
- 区切りテキスト ファイルを作成。
- 区切りテキスト ファイルを読み取る
- 配列に区切りファイルの読み込み
- テキスト ファイルの区切りシンボルと配列を書き込む
- UNICODE ファイル
- 区切りシンボルを持つテキスト ファイルを操作するための追加関数
- バイナリ ファイル
- バイナリ ファイル、変数
- バイナリ ファイル、構造
- 変数による文章構造
- UNICODE ファイル、FileReadInteger 関数を定義。
- バイナリ ファイル、配列、構造体配列
- バイナリ ファイル、文字列、行の配列
- ファイル用の共有フォルダー
- テスター内のファイル
- ファイルへのアクセスを共有
- ターミナル間のデータ交換用ファイルの使用
- 余分な関数
- フォルダーの操作
- ファイルの一覧を取得
- コードページ
- 制限なしファイルの操作
- 便利なスクリプト
- トピックの詳細
- 結論
- 添付
イントロダクション
他の多くのプログラミング言語のように、MQL5 でファイルを扱うための関数を実行します。MQL5 でEAとインジケーターを開発するとき、遅かれ早かれ開発者は直面します。 ファイル作業を必要とする範囲は十分に広いです。EA やインジケーターは、(たとえば、ニュース カレンダー) 相場データの読み取りの複雑なパラメータを持つ特別なファイルの作成カスタムトレードレポートの生成が含まれます。この記事は、MQL5 内のファイルを操作するためのすべての関数を扱っています。スキルアップを目的とした実用的な作業を伴います。タスクから離れて、実際に適用することができ、便利な関数を考慮します。
MQL5 をドキュメントには、ここでファイルの関数の説明が含まれています。
テキスト ファイルを読み込み
最も簡単な最も頻繁に使用される関数は、テキスト ファイルの読み込みです。練習してみましょう。MetaEditor を開きます。ファイルを選択します-は、データ フォルダーを開きます。MQL5 をフォルダーを新しいウィンドウで開きます。その後、ファイル フォルダーを開きます。MQL5 をファイル関数で処理可能なファイルがあります。データのセキュリティを確保します。ユーザーは積極的に MQL5 をアプリケーションを共有します。制限なしの場合、侵入者が削除したり、重要なファイルを破損または個人データを盗むによって PC に害を引き起こすことはあまりにも簡単です。
新しく開いたMQL5 ファイル フォルダーにテキスト ファイルを作成します。フォルダー内の場所をクリックし、新規を選択。「テスト」を名前します。完全な名前は、"test.txt"にする必要があります。PC上のファイル拡張子の表示を有効にすることをお勧めします。
再ファイルの命名後に、開きます。メモ帳などエディターで開きます。2-3 テキスト行をファイルに書き込み、保存します。ANSI エンコーディングが「名前を付けて保存] ウィンドウ (図 1) の下部のドロップ ダウン リストで選択されていることを確認します。
図1Windows のメモ帳でテキスト ファイルを保存します。赤い矢印は、選択したファイルのエンコーディングを示しています
MQL5 を用いてファイルを読み込みます。MetaEditorでスクリプトを作成し、sTestFileRead という名前を付けます。
ファイルを読み込み、書き込みを行う前に、閉じる必要があります。2つの必須パラメータを持つFileOpen()関数でファイルを開きます。最初の1つは、ファイル名です。ここで"test.txt"を指定する必要があります。MQL5 ファイル フォルダーから、フル ・ パスを指定することに注意してください。2番目のパラメータは、ファイルの操作のモードを定義するフラグの組み合わせです。ファイルを読み取るため、FILE_READ フラグを指定する必要があります。"test.txt"は 2 つのより多くのフラグを使用する必要があります。ANSI エンコードを適用するテキスト ファイル: FILE_TXT と FILE_ANSI。フラグによって示される「or」論理演算「|」で組み合わせます。
FileOpen() 関数は、ファイル ハンドルを返します。ハンドルの関数については詳細に扱いません。ファイルの文字列名の代わりに使用される数値 (int) であるとしましょう。ファイルの文字列名は、そのファイルにアクションを実行するハンドルを使用中、ファイルを開くときに指定されます。
(STestFileRead スクリプトの OnStart() 関数にコードを記述) ファイルを開いてみましょう
int h=FileOpen("test.txt",FILE_READ|FILE_ANSI|FILE_TXT);
その後、実際に同じファイルを開いていることを確認します。受信のハンドルの値をチェックすることによって行われます。
if(h==INVALID_HANDLE){ Alert("Error opening file"); return; }
ファイルを開くエラーがよくあります。ファイルが既に開いている場合、 2 番目を開くことができません。サードパーティ製のアプリケーションでファイルを開けない可能性があります。たとえば、同時に Windows のメモ帳で MQL5 をファイル開くことがあります。Microsoft Excel で開いた場合は、開くことができます。
(FILE_TXT フラグを指定して開いた) テキスト ファイルからデータを読み取り、 FileReadString()関数によって行われます。読み込みが 1 行ずつ実行されます。1 つの関数呼び出しは、単一ファイルの行を読み取ります。1 行を読み取り、メッセージ ボックスに表示してみましょう。
string str=FileReadString(h); Alert(str);
ファイルを閉じます。
FileClose(h);
FileOpen() 関数でファイルを開くとき、受け取ったハンドル (h 変数) を指定することによって FileReadString() と FileClose() 関数の呼び出しが実行されることに注意してください。
sTestFileRead スクリプトを実行することができます。うまくいかない場合は、sTestFileRead ファイルを以下に添付したコードと比較します。"Test.txt"ファイルから最初の行のウィンドウは、スクリプト操作 (図 2) の結果として表示されます。
図 2。STestFileReadスクリプト操作の結果
"test.txt"ファイルから 1 行だけを読んでいます。残りの 2 つを読むために関数を呼び出し、 FileReadString() が2 回以上です。実際にはファイルの行の数は、通常事前にわかりません。この問題を解決するためには、 FileIsEnding()関数と、演算子間を適用すべきです。ファイルの末尾に達すると、FileIsEnding() 関数は 'true' 返します。すべてのファイルの行を読み、FileIsEnding() 関数を使用して、メッセージ ボックスに表示するためのカスタム関数を書いてみましょう。ファイルでの作業に関する実験をすることができます。次の関数を取得します。
void ReadFileToAlert(string FileName){ int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } Alert("=== Start ==="); while(!FileIsEnding(h)){ string str=FileReadString(h); Alert(str); } FileClose(h);
sTestFileReadToAlert スクリプトを作成し、関数をコピーし、スクリプトの OnStart() 関数から呼び出します。
void OnStart(){ ReadFileToAlert("test.txt"); }
メッセージ ボックス「= = = 開始 = = ="行と"test.txt"の 3 つの行が表示されます。ファイルを完全に読み取るようになりました (図 3)。
図3。FileIsEnding() 関数とファイル全体を読み取るための 'wile' ループを行いました
テキスト ファイルを作成。
ファイルを作成するために FileOpen() 関数を使用します。FILE_WRITE 1 つではなく FILE_READ フラグを使用して"test.txt"ファイルを開きます。
int h=FileOpen("test.txt",FILE_WRITE|FILE_ANSI|FILE_TXT);
ファイルを開いた後、ファイルを読んで同様ハンドルを確認します。関数を正常に実行すると、新しい"test.txt"ファイルが作成されます。ファイルが既に存在する場合は完全に消去されます。貴重なデータを失わないように、書き込み用のファイルを開くときに注意します。
テキスト ファイルへの書き込みは、 FileWrite()関数によって実行されます。最初のパラメータは、ファイル ハンドルを設定し、2 つ目はファイルに書き込む行を設定します。新しい行は、FileWrite() 関数の各呼び出しに書き込まれます。
ループ内でファイル10 行書いてみましょう。最終的なスクリプト コード (sTestFileCreate) は、次のようになります。
void OnStart(){ int h=FileOpen("test.txt",FILE_WRITE|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } for(int i=1;i<=10;i++){ FileWrite(h,"Line-"+IntegerToString(i)); } FileClose(h); Alert("File created"); }
コードを実行した後、"test.txt"ファイルは、10 行含める必要があります。ファイルの内容を確認するには、メモ帳で開きます。 または sTestFileReadToAlert スクリプトを実行します。
FileWrite() 関数に注意してください。2 つの引数があります。複数の文字列変数を関数に渡すこともでき、1つの行に結合されます。指定したコードで FileWrite() 関数の呼び出しを記述できます。
FileWrite(h,"Line-",IntegerToString(i));
関数は自動的に行を結合します。
テキスト ファイルの末尾への書き込み
場合によっては、コンテンツの残りの部分をそのまま既存のファイルに新しいテキスト行を追加する必要があります。このような操作を実行するには、同時に読み書きするファイルを開く必要があります。FileOpen() 関数を呼び出すとき両方のフラグ (FILE_READ と FILE_WRITE) を指定する必要があります。
int h=FileOpen("test.txt",FILE_READ|FILE_WRITE|FILE_ANSI|FILE_TXT);
指定した名前のファイルが存在しない場合は作成されます。既に存在する場合、その内容はそのまま保持しながら開きます。ただし、ファイルへの書き込みをすぐに開始する場合、ファイルの先頭から書き込みを行うので前の内容が削除されます。
「ポインター」のようなものがあるファイルを操作する場合、次のエントリまたはファイルから読み取りを実行するポジションを示す数値です。ファイルを開くと、ポインターが自動的にファイルの先頭に設定されます。読み取り、データの書き込み中に自動的に再配置のサイズによって読み取りまたは書き込まれたデータです。必要に応じて自分のポインターを移動できます。これを行うには、 FileSeek()関数を使用します。
以前の内容を保存し、ファイルの末尾に新しいものを追加するために、書き込み前にファイルの末尾にポインターを移動します。
FileSeek(h,0,SEEK_END);
3つのパラメータは、FileSeek() 関数に送信されます: 処理、移転のポインター値とポジションからシフトを計算します。この例の定数は、ファイルの末尾を意味します。したがって、ポインターは、(最後の最後へのシフトを意味する) ファイルの末尾から 0 バイトだけシフトされます。
ファイルの追加の最後のスクリプト コードは次のとおりです。
void OnStart(){ int h=FileOpen("test.txt",FILE_READ|FILE_WRITE|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } FileSeek(h,0,SEEK_END); FileWrite(h,"Additional line"); FileClose(h); Alert("Added to file"); }
また、このスクリプトを(sTestFileAddToFile) に添付します。スクリプトを起動し、test.txt ファイルの内容を確認します。STestFileAddToFile スクリプトの各呼び出しは、test.txt に 1 つの行を追加します。
テキスト ファイルの指定した行を変更。
テキスト ファイルの場合、ファイル中にポインターを自由に移動し、ファイルへの追加を目的のみに使用することができ、変更は適用されません。ファイルの行はシンプルに概念ファイルに連続的な一連データが含まれていますので、特定のファイルの行の変更を加えることが可能です。このようなシリーズは、特殊文字のテキスト エディターで非表示にできます。新しい行に次の情報を表示します。行の先頭にポインターを設定した場合、以前のデータ行は書き込まれたデータのサイズが既存のラインよりも小さい場合に残ります。それ以外の場合、次の行のデータの一部とともに新しいライン シンボルが削除されます
Test.txt の 2 行目を交換してみましょう。1行、2行目の先頭にポインターを移動し、"AB"(sTestFileChangeLine2-1 スクリプトの下に添付) の 2 つの文字から成る新しい行を読んで、リーディング、ライティングのためファイルを開きます。
void OnStart(){ int h=FileOpen("test.txt",FILE_READ|FILE_WRITE|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } string str=FileReadString(h); FileWrite(h,"AB"); FileClose(h); Alert("Done"); }
得られた test.txt ファイルは次のようになります。 (図 4)。
図41つの行を変更した後のテキストファイルの内容
1 つではなく 2 つの行:"AB"と「-2」。「-2」は、2 番目の行から残りの 4 つの文字が削除されています。FileWrite() 関数を使用して行を作成するときに、新しいシンボルを書かれたテキストの末尾に追加します。Windows オペレーティング システムでは、新しいライン シンボルは、2 つの文字で構成されています。"AB"の行の 2 つの文字を追加すると、4 つの文字が結果ファイルに削除された理由が分かります。
Test.txt を復元し、2 番目の行も交換してください。 sTestFileCreate スクリプトを実行します。「ライン-12345」(sTestFileChangeLine2-2 スクリプトの下に添付) を書いてみましょう。
void OnStart(){ int h=FileOpen("test.txt",FILE_READ|FILE_WRITE|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } string str=FileReadString(h); FileWrite(h,"Line-12345"); FileClose(h); Alert("Done"); }
(図 5) の結果のファイルを見てみましょう。
図5テキスト ファイルの1行を変更する2番目の結果
新しい行は、前のものより長く、3 行目と同様に影響されています。
テキストファイルを変更する唯一のメソッドを読み込んで、再度完全に書き込みます。配列にファイルを読み取り、必要な配列要素に変更を加えます。1 行を別のファイルに保存、古いファイルを削除、新しい 1 つの名前を変更します。配列は必要ありません: 1 つのファイルから行を読み取り中、別に書き込みができます。特定の時点で変更は行われ、必要な行に保存されます。その後、古いファイルが削除され、新しい名前を変更します。
(配列に変更)、後者のオプションを適用してみましょう。まず、一時ファイルを作成する必要があります。一時ファイルの一意の名前を受信するための関数を書いてみましょう。ファイル名と拡張子は、関数に渡されます。関数自体の内で (標準的なFileIsExists()関数) によって実行ファイルが存在するかどうかチェックします。ファイルが存在する場合、そのような名前のファイルが検出されるまで、追加されます。関数は、次のようになります。
string TmpFileName(string Name,string Ext){ string fn=Name+"."+Ext; //名前を形成 int n=0; while(FileIsExist(fn)){ //ファイルが存在するかどうか n++; fn=Name+IntegerToString(n)+"."+Ext; //名前に番号を追加 } return(fn); }
sTestFileChangeLine2 3 スクリプトを作成、関数をコピーし、OnStart() 関数に次のコードを配置します。
読み込み用に test.txt を開きます。
int h=FileOpen("test.txt",FILE_READ|FILE_ANSI|FILE_TXT);
一時ファイルの名前が表示されます。
string tmpName=TmpFileName("test","txt"); int tmph=FileOpen(tmpName,FILE_WRITE|FILE_ANSI|FILE_TXT);
ラインを数えるファイルを読みます。すべて読む線が一時ファイルに送信され、2番目の行が置き換えられます。
int cnt=0; while(!FileIsEnding(h)){ cnt++; string str=FileReadString(h); if(cnt==2){ //行を置き換えます。 FileWrite(tmph,"New line-2"); } else{ //変更せずに行を書き換えます FileWrite(tmph,str); } }
両方のファイルを閉じます。
FileClose(tmph); FileClose(h);
すべての元のファイルを削除し、一時的な名前を変更します。標準FileDelete()関数を使用して、削除します。
FileDelete("test.txt");
ファイルの名前を変更するには、移動またはファイル名を変更するように設計し、標準FileMove()関数を使用する必要があります。この関数は、4 つの必須パラメータを受け取ります: 移転ファイル (ソース ファイル) のファイル場所フラグは、新しいファイル名、上書きフラグです。ファイル名ですべてクリア、2番目と 4番目のパラメータに近い外観を持っています。2番目のパラメータは、ソース ファイルの場所を定義します。MQL5で処理可能なファイルは、ターミナルの MQL5 フォルダーにはすべてのターミナルの共通のフォルダーに配置できます。後でより詳細に検討します。今は、0だけ設定してみましょう。最後のパラメータは、変換先ファイルの場所を定義します。ターゲット ファイルが存在する場合、動作を定義する追加のフラグもあります。以来、ソース ファイル (リンク先ファイル) が削除、4 番目のパラメータは 0 に設定されます。
FileMove(tmpName,0,"test.txt",0);
STestFileChangeLine2-3 のスクリプトを実行する前に sTestFileCreate スクリプトを使用して test.txt を復元します。STestFileChangeLine2-3 スクリプト操作後 text.txt は以下の内容 (図 6) である必要があります。
図6行を交換した後ファイルの内容
FileMove() 関数に戻りましょう。4番目のパラメータとして (リンク先のファイルを書き換えていくことができる) FILE_REWRITE のフラグを設定します。
FileMove(tmpName,0,"test.txt",FILE_REWRITE);
スクリプトから元のファイルを削除する必要はありません。sTestFileChangeLine2-3 スクリプトでこのオプションを使用します。
FileMove() 関数ではなく別の標準関数FileCopy()を使用して、一時的なファイルを削除する必要があります。
FileCopy(tmpName,0,"test.txt",FILE_REWRITE); FileDelete(tmpName);
配列にテキスト ファイルを読み取る
便利な関数を (受信、空いているファイル名) この記事ですでに述べました。ファイルを扱うときに用いられるもう一つの関数 — 配列にファイルの読み取り。ファイル名と行の配列は、関数に渡されます。この配列は、リンク経由で渡され、ファイルの内容でいっぱいです。その操作の結果に応じてtrue または falseを返します。
boolReadFileToArray (文字列ファイル名、文字列・ Lines[]) { ResetLastError(); int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ int ErrNum=GetLastError(); printf("Error opening file %s # %i",FileName,ErrNum); return(false); } int cnt=0; //ファイルの行の数をカウントする変数を使用 while(!FileIsEnding(h)){ string str=FileReadString(h); //ファイルから次の行を読み込む //左と右を検出し、空の行を使用して避けるためにスペースを削除します。 StringTrimLeft(str); StringTrimRight(str); if(str!=""){ if(cnt>=ArraySize(Lines)){ //配列が完全に満たされる ArrayResize(Lines,ArraySize(Lines)+1024); //1024 要素によって配列のサイズを増加 } Lines[cnt]=str; //配列にリード線を送信 cnt++; //読み取り行数カウンターを増加 } } ArrayResize(Lines,cnt); FileClose(h); return(true); }
今のところここで提供されるデータから明らかな詳細については、この関数を考慮することはしません。既に詳しくコメントされています。ニュアンスを言及する必要があります。Str変数にファイルから行を読み取り後、行端のスペースはStringTrimLeft()とStringTrimRight()関数によって削除されます。その後、 str文字列が空でないかどうかを調べます。不要な空白行をスキップするために行われます。配列をエントリーすると、1 つではなく 1024 要素によってブロックに増加します。この関数は、このメソッドで動作するより高速です。最後に、この配列は読み取り行の実際の数に従って拡大縮小されます。
この関数は、sTestFileReadFileToArray スクリプトを以下に添付にあります。。
区切りテキスト ファイルを作成。
ここまでは、シンプルなテキスト ファイルのみを検討してきました。ただし、テキスト ファイルの別の種類がある-区切りシンボルを持つものです。通常、.csv 拡張子 (「カンマ区切り」の略) があります。実際には、テキスト エディターで開くと同様、読み取り、および裁量で編集できるテキスト ファイルです。特定の文字 (カンマではありません) は、行のフィールドの区切り文字として使用されます。したがって、シンプルなテキスト ファイルと比較すると、異なるアクションを実行できます。主な違いは、シンプルなテキストファイルの行全体が読み取られる区切りシンボルでファイルの中に FileRedaString() 関数が呼び出されたときは読み込みが区切りシンボルまたは行の末尾まで実行されます。FileWrite() 関数の異なる動作: この関数で列挙されるすべての変数はシンプルに 1 つの行に接続されません。代わりに、間の区切りシンボルが追加されます。
Csv ファイルを作成してみましょう。1つのFILE_TXT の代わりに FILE_CSV フラグを指定する記述するため、テキスト ファイルを開きます。3番目のパラメータは、区切りシンボルとして使用されるシンボルです。
int h=FileOpen("test.csv",FILE_WRITE|FILE_ANSI|FILE_CSV,";");
1行につき 3 つのフィールドを持つファイルの 10 行を書いてみましょう。
for(int i=1;i<=10;i++){ string str="Line-"+IntegerToString(i)+"-"; FileWrite(h,str+"1",str+"2",str+"3"); }
最後にファイルを閉じることを確認します。このコードは、下記の添付 sTestFileCreateCSV スクリプトで得られます。結果として、「test.csv」ファイルが作成されます。ファイルの内容を図 7 に示します。FileWrite() 関数のパラメータは単一行の間の区切りシンボルに形成します。
図7。区切りファイルの内容
区切りテキスト ファイルを読み取る
この記事の冒頭にテキスト ファイルと同じように csv ファイルを読み込むましょう。STestFileReadToAlertCSV をという名前の sTestFileReadToAlert スクリプトのコピーを作ってみましょう。ReadFileToAlert() 関数の最初の文字列を変更します。
int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV,";");
ReadFileToAlertCSV() に ReadFileToAlert() 関数を変更し、関数に渡されるファイルの名前を変更します。
void OnStart(){ ReadFileToAlertCSV("test.csv"); }
スクリプト操作の結果は、ファイルが 1 つのフィールドで読み取られたことを示します。1行のフィールドが読み取られ、新しい行を開始すると良いでしょう。FileIsLineEnding()関数が適用されます。
STestFileReadToAlertCSV2 をという名前の sTestFileReadToAlertCSV スクリプトのコピーを作成し、ReadFileToAlertCSV2 に ReadFileToAlertCSV 関数の名前を変更してみましょう。FileIsLineEnding() 関数の追加: 'true' を返す場合、分割線"---"。
void ReadFileToAlertCSV2(string FileName){ int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV,";"); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } Alert("=== Start ==="); while(!FileIsEnding(h)){ string str=FileReadString(h); Alert(str); if(FileIsLineEnding(h)){ Alert("---"); } } FileClose(h); }
スクリプトによってメッセージ ウィンドウに送信されるフィールドは、(図 8) のグループに分かれています。
図8"---"フィールド グループ単一ファイルの行の間の区切りシンボル
配列に区切りファイルの読み込み
csv ファイルでの作業に精通し、配列に csv ファイルを読むためのもう一つの便利な関数を記述しましょう。読み込みは、各要素が 1 つのファイルの行に対応する構造体の配列で実行されます。構造の線の配列が単一行フィールドに対応する要素に含まれます。
Structure:
struct SLine{ string line[]; };
関数:
bool ReadFileToArrayCSV(string FileName,SLine & Lines[]){ ResetLastError(); int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV,";"); if(h==INVALID_HANDLE){ int ErrNum=GetLastError(); printf("Error opening file %s # %i",FileName,ErrNum); return(false); } int lcnt=0; //ラインを計算するための変数 int fcnt=0; //行フィールドを計算する変数 while(!FileIsEnding(h)){ string str=FileReadString(h); //新しい行 (構造体配列の新しい要素) if(lcnt>=ArraySize(Lines)){ //完全な構造配列 ArrayResize(Lines,ArraySize(Lines)+1024); //1024 要素によって配列のサイズを増加 } ArrayResize(Lines[lcnt].field,64);//構造体の配列のサイズを変更する Lines[lcnt].field[0]=str; //最初のフィールドの値を割り当てる //行のほかのフィールドを読み取りを開始。 fcnt=1; //行の配列の 1 つの要素は占められるまで while(!FileIsLineEnding(h)){ //行のフィールドの残りの部分を読む str=FileReadString(h); if(fcnt>=ArraySize(Lines[lcnt].field)){ //フィールドの配列が満タン ArrayResize(Lines[lcnt].field,ArraySize(Lines[lcnt].field)+64); //要素の配列のサイズ } Lines[lcnt].field[fcnt]=str; //次のフィールドの値を割り当てる fcnt++; //ライン カウンターを増加 } ArrayResize(Lines[lcnt].field,fcnt); //フィールドの実際の数によるとフィールドの配列のサイズを変更する lcnt++; //ライン カウンターを増加 } ArrayResize(Lines,lcnt); //行の実際の数 (行) 構造体の配列を変更 FileClose(h); return(true); }
ほとんどの重要なポイントでこの関数は考慮されません。先頭に1つのフィールドを読み取り、しばらくの間 (!FileIsEnding(h)) ループします。ここでは構造体の配列に追加する要素について調べます。配列のサイズを確認し、必要に応じて 1024 要素によって増加します。一度にフィールドの配列のサイズを変更します。64 要素のサイズを設定し、ファイルから読み取る最初の行のフィールドの値は、0 のインデックスを持つ要素に割り当てられています。その後残りのフィールドを読み、しばらくの間 (!FileIsLineEnding(h)) ループします。別のフィールドを読んだ後に、配列のサイズを確認し必要に応じて増やし、配列にファイルから読み込まれた行を送信します。(終了最後に行を読んだ後、しばらくの間 (!FileIsLineEnding(h)) ループし)、実際の数にフィールドの配列のサイズを変更します。最後の最後で読み取りの行の数によるライン配列のサイズ変更します。
この関数は、sTestFileReadFileToArrayCSV スクリプトを以下に添付します。スクリプトは配列に test.csv ファイルを読み取り、メッセージ ウィンドウで配列を表示します。この結果は、図8に示すものと同じです。
テキスト ファイルの区切りシンボルと配列を書き込む
このタスクは、行のフィールドの数が事前にわかっている場合、かなり簡単です。似たようなタスクは、「区切りテキスト ファイルの作成」セクションで既に解決されています。フィールドの数が既知の場合、すべてのフィールドを収集できる単一行にループし、区切りシンボルで FILE_TXT フラグを指定して開いたファイルに行を書き込みます。
ファイルを開きます。
int h=FileOpen("test.csv",FILE_WRITE|FILE_ANSI|FILE_TXT);
区切りシンボルを使用して 1 行にすべてのフィールド (配列要素) を収集します。行の末尾に区分線はなく、冗長な空のフィールドの行になります。
string str=""; int size=ArraySize(a); if(size>0){ str=a[0]; for(int i=1;i<size;i++){ str=str+";"+a[i]; //差し込みPrintフィールドの区切りシンボルを使用 } }
ファイルに行を書き込み、閉じます。
FileWriteString(h,str); FileClose(h);
次の使用例は、下記の添付 sTestFileWriteArrayToFileCSV スクリプトにあります。
UNICODE ファイル
今までは、FILE_ANSI フラグが、エンコードを定義するファイルを開くとき常に指定されました。このエンコーディングは、1 文字が 1 バイトに対応し、そのため、全体のセットは 256 シンボルに限定されます。ただし、UNICODE エンコーディングは広く使用します。このエンコーディングの 1 つのシンボルはバイトで定義され、テキスト ファイルは別のアルファベット、文字や他のグラフィックシンボルから文字を含む文字の非常に大きな数を含めることができます。
実験しましょう。STestFileReadToAlert スクリプトをエディターで開き、sTestFileReadToAlertUTF の名前で保存し、FILE_UNICODE で FILE_ANSI フラグを置き換えます。
int h=FileOpen(FileName,FILE_READ|FILE_UNICODE|FILE_TXT);
以来、test.txt を ansi 形式で保存すると、新しいウィンドウには、テキストの文字化け (図 9) があります。
図9。テキスト ファイルの元のエンコードが一致しない場合、1 つのファイルを開くときに文字化けします。
ファイルの元のエンコード ファイルを開くときに指定されたものと一致しないために発生します。
STestFileCreate スクリプトをエディターで開き、sTestFileCreateUTF の名前で保存し、FILE_UNICODE で FILE_ANSI フラグを置き換えます。
int h=FileOpen("test.txt",FILE_WRITE|FILE_UNICODE|FILE_TXT);
新しい test.txt ファイルを作成する sTestFileCreateUTF スクリプトを起動します。sTestFileReadToAlertUTF の読み取り可能なテキスト (図 10)。
図10。STestFileCreateUTFスクリプトによって生成されたファイルを読み取るためのsTestFileReadToAlertUTF スクリプトを使用してください。
Test.txt をメモ帳で開き、メイン メニューの「別名で保存...」コマンドを実行します。Unicode は、「名前を付けて保存」ウィンドウの下部に [エンコード] ボックスで選択されていることに注意してください。メモ帳は、ファイルのエンコーディングを何とか定義しています。Unicode ファイルは、シンボルの標準的なセット、いわゆる BOM (バイト オーダー マーク) に始まります。その後、テキスト ファイルの種類 (ANSI または UNCODE) を定義する関数を記述します。
区切りシンボルを持つテキスト ファイルを操作するための追加関数
ファイル関数(シンプルなものと区切りシンボルを持つもの両方) のテキスト ファイルの内容を操作するため、 FileWrite()とFileReadString()が必要です。また、(詳細については、以下参照) バイナリ ファイルを操作するため、FileReadString() 関数を使用します。重要ではありませんが、FileWrite() 関数から離れて FileWriteString() 関数を使用できます。
より便利に、他の関数を使用ことができる区切りシンボルを持つテキスト ファイルを使用する場合: FileReadBool()、 FileReadNumber() 、 FileReadDatetime()。FileReadNumber() 関数は、番号を読み取るために使用されます。事前にファイルから読み取るフィールドに数値だけが含まれていることがわかり、この関数が適用されます。その効果は、FileReadString() 関数で行を読むと、 StringToDouble()関数で数値に変換するのと同じです。同様に、FileReadBool() 関数は、bool 型の値を読み取るために使用されます。文字列には、 true/falseまたは0/1があります。FileReadDatetime() 関数を使用して、行の形式でデータを読み取り、数値の datetime 型の値に変換します。その効果は、行の読み取りをし、 StringToTime()関数を使用して変換するのに似ています。
バイナリ ファイル
前述のファイル、プログラムにより読み取り、ファイル内の参照のテキストエディターで開くと一致します。エディターでファイルを調べることによって、プログラムの操作結果をシンプルに管理できます。必要に応じて、ファイルを裁量で変更することができます。(明らかに 1 つのファイルの行を置き換えるときに直面した難しさを考えると) 、テキスト ファイルの欠点から限られたオプションがあります。
テキストファイルが小さい場合、かなり快適です。そのサイズより多くの時間、作業にかかります。大量のデータを処理する場合に、バイナリ ファイルを使用します。
バイナリ モードでファイルを開くと、FILE_TXT や FILE_CSV の代わりに FILE_BIN フラグを指定します。バイナリのファイル番号ファイルなので、FILE_ANSI または FILE_UNCODE のエンコード ファイルを指定する点はありません。
もちろん、メモ帳などのテキスト エディターでは、バイナリ ファイルの内容を見ます。時々、読みやすいテキストを見ることができますが、ファイルの内容をメモ帳で行うことが増えました。
とにかく、ファイルをテキスト エディターでプロセスで破損したため、間違えて編集しないでください。原因についてその事実を受け入れます。もちろん、特別なバイナリ ファイル エディターがありますが、編集プロセスがまだないです。
バイナリ ファイル、変数
MQL5 を内のファイルを操作するためのほとんどの関数は、バイナリ モードで設計されています。異なる型の変数の読み書きの関数があります:
ここですべての変数の説明はしません。残りは、同じように使用されます。FileWriteDouble() と FileReadDouble() の関数を実験してみましょう。
まず、ファイルを作成し、3 つの変数を書き込み、ランダムなオーダーでを読みます。
ファイルを開きます。
int h=FileOpen("test.bin",FILE_WRITE|FILE_BIN);
値1.2、3.45、6.789 ファイルと 3 つのdouble変数を作成します。
FileWriteDouble(h,1.2); FileWriteDouble(h,3.45); FileWriteDouble(h,6.789);
ファイルを閉じることを忘れないでください。
sTestFileCreateBin スクリプトのコードを見つけることができます。結果として、test.bin ファイルは MQL5 を/ファイル] フォルダーに表示されます。メモ帳 (図 11) でその内容を見てください。メモ帳を開き、ファイルをドラッグします。
図11メモ帳でバイナリ ファイル
メモ帳でこのようなファイル表示はありません。
ファイルを読んでみましょう。FileReadDouble() 関数を使用して、読み取ってください。ファイルを開きます。
int h=FileOpen("test.bin",FILE_READ|FILE_BIN);
ファイルから値を読み取り、3つの変数を宣言し、メッセージ ボックスに表示します。
double v1,v2,v3; v1=FileReadDouble(h); v2=FileReadDouble(h); v3=FileReadDouble(h); Alert(DoubleToString(v1)," ",DoubleToString(v2)," ",DoubleToString(v3));
ファイルを閉じることを忘れないでください。sTestFileReadBin スクリプトのコードを見つけることができます。結果として、 次のメッセージが表示されます: 1.20000000 3.45000000 6.78900000.
バイナリ ファイルの構造を知って、いくつか限定的な変更をすることが可能です。ファイル全体を再記述せず、2 番目の変数を変更してみましょう。
ファイルを開きます。
int h=FileOpen("test.bin",FILE_READ|FILE_WRITE|FILE_BIN);
オープニングの後の指定したポジションにポインターを移動します。ポジションの計算には sizeof() 関数をお勧めします。指定したデータ型のサイズを返します。また、データの種類とそのサイズに精通するのが良いでしょう。2番目の変数の先頭にポインターを移動します。
FileSeek(h,sizeof(double)*1,0);
sizeof (ダブル) を実施 * 1 乗算は、をオフにして、最初の変数の末尾です。3番目の変数を変更する必要があり、 2を乗算する必要があります。
新しい値を書き込みます。
FileWriteDouble(h,12345.6789);
sTestFileChangeBin スクリプトのコードを見つけることができます。スクリプトを実行すると、sTestFileReadBin スクリプトを起動し、受信します: 1.20000000 12345.67890000 6.78900000.
同じメソッド (ファイル全体) ではなく、特定の変数を読むことができます。Test.bin から 3番目のdouble変数を読み取るコードを読んでみましょう。
ファイルを開きます。
int h=FileOpen("test.bin",FILE_READ|FILE_BIN);
ポインターを移動し、値を読み取り、メッセージ ボックスに表示します。
FileSeek(h,sizeof(double)*2,SEEK_SET); double v=FileReadDouble(h); Alert(DoubleToString(v));
次の使用例は、下記の添付 sTestFileReadBin2 スクリプトにあります。。結果として、 次のメッセージが表示されます: 6.78900000-3 番目の変数。2番目の変数を読み取るコードを変更します。
他の種類とその組み合わせの変数を同じように読むことができます。ポインターの設定ポジションを正しく計算するファイル構造を知ることが重要です。
バイナリ ファイル、構造
異なる型の複数の変数をファイルに書き込む場合は、構造を記述して読み取り/書き込み読み取り/書き込み変数 1 つずつではなく、全体の構造を使います。通常ファイル (ファイル形式) 内のデータのポジションを示す構造から始まるデータが続きます。ただし、制限があります: 構造ではない動的配列と行のサイズが知られています。
書き込みと読み取りファイルに実験してみましょう。さまざまな種類の複数の変数を持つ構造体について説明します。
struct STest{ long ValLong; double VarDouble; int ArrInt[3]; bool VarBool; };
sTestFileWriteStructBin スクリプトのコードを見つけることができます。2つの変数を宣言し、OnStart() 関数に異なる値でを埋めます。
STest s1; STest s2; s1.ArrInt[0]=1; s1.ArrInt[1]=2; s1.ArrInt[2]=3; s1.ValLong=12345; s1.VarDouble=12.34; s1.VarBool=true; s2.ArrInt[0]=11; s2.ArrInt[1]=22; s2.ArrInt[2]=33; s2.ValLong=6789; s2.VarDouble=56.78; s2.VarBool=false;
ファイルを開きます。
int h=FileOpen("test.bin",FILE_WRITE|FILE_BIN);
両方の構造体を書き込みます。
FileWriteStruct(h,s1); FileWriteStruct(h,s2);
ファイルを閉じることを忘れないでください。ファイルを作成するスクリプトを実行します。
ファイルを読んでみましょう。2番目の構造体を読み取る。
ファイルを開きます。
int h=FileOpen("test.bin",FILE_READ|FILE_BIN);
2つ目の構造体の先頭にポインターを移動します。
FileSeek(h,sizeof(STest)*1,SEEK_SET);
変数を宣言し、 (STest 構造の記述をファイルの先頭に追加) をファイルからデータを読み取ります。
STest s;
FileReadStruct(h,s);
ウィンドウの構造体のフィールドの値について説明します。
Alert(s.ArrInt[0]," ",s.ArrInt[1]," ",s.ArrInt[2]," ",s.ValLong," ",s.VarBool," ",s.VarDouble);
この結果はメッセージ ボックスに次の行が表示されます: 11 22 33 6789 false 56.78。この行は、2 番目の構造データに対応します。
この例のコードは、下記の添付 sTestFileReadStructBin スクリプトにあります。。
変数による文章構造
MQL5 を構造体フィールド シフト (ポジション合わせ) することなく、次々に特定の構造体のフィールドを読み取ることができます。
Test.bin ファイルで 2 番目の構造から2重の変数の値を読み取ります。ポインターを設定するポジションを計算することが重要です。
FileSeek(h,sizeof(STest)+sizeof(long),SEEK_SET);
残りの部分は既にやっているようなものです。: 読み取り、開くファイルを閉じる。この例のコードは、下記の添付 sTestFileReadStructBin2 スクリプトで見つけることができます。
UNICODE ファイル、FileReadInteger 関数を定義。
バイナリ ファイルを習熟して、UNICODE ファイルを定義するための便利な関数を作成できます。ファイルは、最初のバイトと等しい 255 の値によって区別できます。255 コード印字シンボルに対応する、普通の ANSI ファイルに存在することはできません。
つまり、ファイルから 1 バイトを読み込む必要があり、その値をチェックします。FileReadInteger()関数は、読み取り変数のサイズを指定するパラメータを受け取るので、long以外の様々 な整数型の変数を読むために使用されます。v変数にファイルから 1 バイトを読み込みます。
uchar v=FileReadInteger(h,CHAR_VALUE);
変数の値をチェックします。フル関数のコードは以下のとおりです。
bool CheckUnicode(string FileName,bool & Unicode){ ResetLastError(); int h=FileOpen(FileName,FILE_READ|FILE_BIN); if(h==INVALID_HANDLE){ int ErrNum=GetLastError(); printf("Error opening file %s # %i",FileName,ErrNum); return(false); } uchar v=FileReadInteger(h,CHAR_VALUE); Unicode=(v==255); FileClose(h); return(true); }
チェックが成功したかどうかによってtrue または falseを返します。関数が実行された後、(リンク経由で渡される) 2 つ目はtrueUNICODE ファイルのとfalseANSI ファイルの変数とファイル名は最初のパラメータとして関数に渡されます。
sTestFileCheckUnicode スクリプトでは、関数のコードおよびその呼び出し例があります。STestFileCreate スクリプトを起動し、sTestFileCheckUnicode スクリプトを使用してその型をチェックします。その後、sTestFileCreateUTF スクリプトを起動し、sTestFileCheckUnicode スクリプトをもう一度実行します。異なる結果が得られます。
バイナリ ファイル、配列、構造体配列
バイナリ ファイルの主な利点は、大量のデータを操作するときに顕著になります。データが (別々 の変数を使用して大量に受信しにくい) ので配列と文字列が通常です。配列は、標準の変数と上記の要件を満たす必要がある構造の両方で構成されます動的配列と文字列が含まれていない必要があります。
配列は、 FileWriteArray()関数を使用してファイルに書き込まれます。ファイル ハンドルは、配列名に続いて最初のパラメータとして関数に渡されます。次の 2 つのパラメータはオプションです。配列全体を保存する必要がない場合は、配列の最初の要素のインデックスと保存されている要素の数を指定します。
FileReadArray()関数を使用して配列を読むと、関数パラメータ FileWriteArray() 関数のパラメータと同じです。
ファイルに 3 つの要素で構成されるintの変数を記述します。
void OnStart(){ int h=FileOpen("test.bin",FILE_WRITE|FILE_BIN); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } int a[]={1,2,3}; FileWriteArray(h,a); FileClose(h); Alert("File written"); }
このコードは、下記の添付 sTestFileWriteArray ファイルにあります。
(sTestFileReadArray スクリプト) を読み、ウィンドウに表示します。
void OnStart(){ int h=FileOpen("test.bin",FILE_READ|FILE_BIN); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } int a[]; FileReadArray(h,a); FileClose(h); Alert(a[0]," ",a[1]," ",a[2]); }
その結果、 「1 2 3」を得る以前に指定された配列に対応する行です。配列のサイズが定義されていない、FileReadArray() 関数を呼び出すときに指定されていないことに注意してください。代わりに、ファイル全体が読み取られます。しかし、このファイルは、さまざまな種類の複数の配列が必要です。したがって、同様にファイルのサイズに保存するが妥当ででしょう。両方のサイズを含むint変数で始まるファイルにintやdoubleの配列を書いてみましょう。
void OnStart(){ int h=FileOpen("test.bin",FILE_WRITE|FILE_BIN); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } //2 つの配列 int a1[]={1,2,3}; double a2[]={1.2,3.4}; //配列のサイズを定義します。 int s1=ArraySize(a1); int s2=ArraySize(a2); //配列 1 を書き込む FileWriteInteger(h,s1,INT_VALUE); //配列のサイズを書く FileWriteArray(h,a1); //配列を書き込む //2 配列を書き込む FileWriteInteger(h,s2,INT_VALUE); //配列のサイズを書く FileWriteArray(h,a2); //配列を書き込む FileClose(h); Alert("File written"); }
コードは、下記の添付 sTestFileWriteArray2 スクリプトにあります。
ファイルの読み取り中、 配列のサイズを最初にし、その後配列に指定した要素数を読みます。
void OnStart(){ int h=FileOpen("test.bin",FILE_READ|FILE_BIN); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } int a1[]; double a2[]; int s1,s2; s1=FileReadInteger(h,INT_VALUE); //配列 1 のサイズを読む FileReadArray(h,a1,0,s1); //配列に s1 に設定されている要素の数を読む s2=FileReadInteger(h,INT_VALUE); //配列 2 のサイズを読む FileReadArray(h,a2,0,s2); //配列に s2 に設定されている要素の数を読む FileClose(h); Alert(ArraySize(a1),": ",a1[0]," ",a1[1]," ",a1[2]," :: ",ArraySize(a2),": ",a2[0]," ",a2[1]); }
コードは、下記の添付 sTestFileReadArray2 スクリプトにあります。
その結果、このスクリプトはメッセージを示しています: 3:1 2 3 - 2: 1.2 3.4 サイズと、ファイルに書き込まれる前の配列の内容に対応します。
FileReadArray() 関数を使用して配列を読み取り、配列は自動的に縮小されます。しかし、現在のサイズが読み込まれた要素の数よりも少ない場合にのみは、スケーリングが実行されます。配列のサイズが超えた場合は、変更されません。配列の一部だけは代わりになります。
構造体配列の操作は完全に構造体のサイズが正しく定義されるので標準型の配列を扱うのと同じです (動的配列と文字列)。ここで構造体の配列を含む例は扱いません。自分で試すことができます。
また、すべてのファイル ポインターを移動することができる要素の 1 つだけは配列の一部を読み取ることができることに注意してください。ポインターのポジションを正しく計算することが重要です。別の要素の読み取りの例はまた表示されません。ここで記事の長さを短くします。自身で試すことができます。
バイナリ ファイル、文字列、行の配列
FileWriteString()関数は、文字列をバイナリ ファイルに書き込むためです。2つの必須パラメータは、関数に渡されます: ファイル ハンドルとファイルに書き込む行。最初のパラメータは省略可能: ラインの一部を記述する必要がある場合のみ、書かれたシンボルの数を設定できます。
この行は、 FileReadString()関数によって読み取られます。読み取られた文字の数を設定するのには (省略可能) 2 つ目を使用しながら、この関数では、最初のパラメータはハンドルです。
一般に、書き込み/読み取りの行は配列での作業に非常に類似しています。: 行が 1 行文字中、全体の配列に類似した共通の 1 つの配列要素、一行書き込み/読み取りの例は表示されません。代わりにより複雑な例を考えてみます: 文字列配列の読み書き。まず、配列のサイズとintの変数をファイルに書き込み、先頭のサイズとintの変数を追加するループ内の個別の要素を書きます。
void OnStart(){ int h=FileOpen("test.bin",FILE_WRITE|FILE_BIN); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } string a[]={"Line-1","Line-2","Line-3"}; //配列を書き込み FileWriteInteger(h,ArraySize(a),INT_VALUE); //配列のサイズを書く for(int i=0;i<ArraySize(a);i++){ FileWriteInteger(h,StringLen(a[i]),INT_VALUE); //書き込みサイズ (単一の配列要素) FileWriteString(h,a[i]); } FileClose(h); Alert("File written"); }
sTestFileWriteStringArray スクリプトのコードにあります。
読むときは、配列のサイズを最初に読み、サイズを変更し、サイズを読んで別の要素を読み取ります。
void OnStart(){ int h=FileOpen("test.bin",FILE_READ|FILE_BIN); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } string a[]; //この配列にファイルを読む int s=FileReadInteger(h,INT_VALUE); //配列のサイズを読む ArrayResize(a,s); //配列のサイズを変更する for(int i=0;i<s;i++){ //すべての配列要素 int ss=FileReadInteger(h,INT_VALUE); //リード線サイズ a[i]=FileReadString(h,ss); //行を読む } FileClose(h); //読み込み用の配列を表示します。 Alert("=== Start ==="); for(int i=0;i<ArraySize(a);i++){ Alert(a[i]); } }
sTestFileReadStringArray スクリプトのコードがあります。
ファイル用の共有フォルダー
今までは、MQL5 を/ファイル ディレクトリ内のファイルを扱いました。ただし、ファイルが唯一の場所ではありません。MetaEditor のメイン メニューで [ファイル - 一般的なデータ フォルダーを開くを実行します。ファイルのディレクトリでフォルダーが開きます。MQL5で開発したアプリケーションから利用できるファイルもあります。(図 12) へのパスに注意してください。
図12共通のデータ フォルダーへのパス
共通のデータ フォルダーへのパスは、何もターミナルと記事の中で扱ったファイル ディレクトリ パスとしています。多くのターミナル (「/ポータブル」キーで実行されているものを含む) に関係なく、すべてに同じ共有フォルダーが開きます。
フォルダーへのパスをプログラムで定義できます。(全体の記事の中で働いて MQL5 をファイル/ディレクトリを含む) データ フォルダーへのパス:
TerminalInfoString(TERMINAL_DATA_PATH);
共有データ フォルダー (ファイル ディレクトリを含む) へのパス:
TerminalInfoString(TERMINAL_COMMONDATA_PATH);
同様に、ターミナル (ターミナルがインストールされているルート ディレクトリ) へのパスを定義できます。
TerminalInfoString(TERMINAL_PATH);
MQL5ファイルのディレクトリと同様に、共有フォルダーからファイルを操作する場合は、完全パスを指定する必要はありません。代わりに、FileOpen() 関数に渡されたフラグの組み合わせに FILE_COMMON フラグを追加する必要があります。ファイルの関数がある共有フォルダー フラグを指定するため、特定のパラメータを含ませます。FileDelete()、 FileMove()、 FileCopy()のとおりです。
Test.txt を MQL5 を/ファイル] フォルダーから共通のデータ フォルダーにコピーします。
if(FileCopy("test.txt",0,"test.txt",FILE_COMMON)){ Alert("File copied"); } else{ Alert("Error copying file"); }
sTestFileCopy スクリプトのコードがあります。スクリプトを実行すると、共有ファイル フォルダーに test.txt ファイルが表示されます。2回目に起動するスクリプトと、エラー メッセージが表示されます。ファイルを許可し、 FILE_REWRITE フラグを追加することによって上書きします。
FileCopy("test.txt",0,"test.txt",FILE_COMMON|FILE_REWRITE)
別の名前 (sTestFileCopy2 スクリプト) と同じフォルダーに共有フォルダーからファイルをコピーします。
FileCopy("test.txt",FILE_COMMON,"test_copy.txt",FILE_COMMON)
最後に、MQL5 (sTestFileCopy3 スクリプト) に共通のフォルダーからファイルをコピーします。
FileCopy("test.txt",FILE_COMMON,"test_copy.txt",0)
コピーは作成されませんが同じように、FileMove() 関数を呼びます。代わりに、ファイルを移動 (または名前変更)。
テスター内のファイル
この時点で、MQL5プログラム (スクリプト、EA、インジケーター) アカウントで実行されているファイルに関連していました。テスターで EA を起動したとき、すべてが違います。メタトレーダー5 のテスターは分散 (クラウド) 実行する能力を持っているので、リモート エージェントを使用してテストします。大雑把に言えば、最適化実行 1-10 (番号は条件付き) が 1 つの PC 上で実行、11-20 で実行されます。問題が発生し、ファイルでの作業に影響を与えます。関数とフォーム テスター内のファイルを操作するときに従う必要があります。
ファイルを操作する場合、FileOpen() 関数は、ターミナルデータ フォルダー内 MQL5 を/ファイル ディレクトリ内のファイルにアクセスします。関数テスト エージェント フォルダー内 MQL5 を/ファイル ディレクトリのファイルにアクセスします。単一の最適化実行 (または単一テスト)で必要なファイルの例を明確な位置または保留中の注文、データを格納する次ファイル実行 (EA の初期化中に) します。ファイルが裁量で生成される EA 操作パラメータを決定するために、ターミナルのデータ フォルダーの MQL5ファイル ディレクトリに配置します。つまり、テスターはを参照できません。EAアクセス ファイルを知らせるため、エージェントに渡される必要があります。"#property tester_file"プロパティ設定経由で EA で行われます。したがって、ファイルの任意の量を送信することが可能です。
#propertytester_file"file1.txt" #propertytester_file「file2.txt」 #propertytester_file"file3.txt"
ただし、"#property tester_file"を使用してファイルを指定すると、まだテスト エージェントのディレクトリにあるファイルのコピーを書き込みます。ターミナルデータのフォルダー内のファイルは変更されません。ファイルの読み込みは、エージェント フォルダーから実行されます。つまり、変更されたファイルを読み込みます。したがって、保存する場合、分析データの一部をテスト、最適化、保存データ ファイルは適用されません。代わりにフレームを使用する必要があります。
リモート エージェントを使用しない場合は、共有フォルダー (ファイルを開くときに、FILE_COMMON フラグ セット) からファイルを操作します。この場合、EA プロパティでファイル名を指定する必要はありません。EA はファイルに書き込むことができます。一言で言えば、共通のデータ フォルダーを使用する場合、テスターからのファイルの操作はリモート エージェントを使用しないでください。EA に実際の作業で使用されるファイルが破損していないです。テスターでの作業をプログラムで定義できます。
MQLInfoInteger(MQL5_TESTER)
テストするときは、他のファイル名を使用します。
ファイルへのアクセスを共有
すでに述べたように、ファイルが既に開かれている場合に2 回目を開くことができません 。別のプログラムはへのアクセス、ファイルが閉じられるまでです。ただし、MQL5 をファイルを共有する関数を使います。追加の共有 (共有読み取り)を設定し、ファイルを開くときまたはモード (共有の書き込み)フラグです。注意深く、フラグを使用します。現代のオペレーティング システム関数をマルチタスクにします。したがって、保証はありませんが書き込みをし、シーケンスを読んで正しく実行されます共有の書き込みと読み取りを許可する場合、1 つのプログラムがデータを書き込み、別のプログラムが同時に同じ (未完成) データを読み取るかもしれません。したがって、 別のプログラムからファイルへのアクセスを同期するための追加措置を取る必要があります。この記事の範囲を越えて拡張するかなり複雑な作業です。さらに、同期せずに、ファイル (表示されます以下、ターミナル間でデータを交換するファイルを使用するとき) を共有する可能性が最も高いです。
共有読み込み (共有) とこのような正当化ファイルを安全に開くことができ、インスタンスの構成ファイルのような EA やインジケーターの操作パラメータを定義するファイルを使用する場合だけです。マニュアルまたは追加のスクリプトによって作成され、初期化中に EA やインジケーターのインスタンスで読みます。初期化中に行うことを許可する必要があるので、 EAがほぼ同時に、ファイルを開くかみてください。同時に、読み取りと書き込みが行われていない保証があります。
ターミナル間のデータ交換用ファイルの使用
ファイルを共有フォルダーに保存するターミナル間のデータ交換を手配します。もちろん、ベスト ソリューションではない可能性がありますが、このような目的のファイル使用は便利です。解決策は非常に簡単です: ファイルへの共有アクセスを許可しません。代わりに、ファイルは、通常の方法で開きます。ファイルは、書き込みまで誰でも開くことができます。書き込みが完了したら、ファイルを閉じ、プログラムの他のインスタンスを読み取ることができません。以下は sTestFileTransmitter スクリプトの関数コードを記述データのコードです。
bool WriteData(string str){ for(int i=0;i<30 && !IsStopped();i++){ //試行 int h=FileOpen("data.txt",FILE_WRITE|FILE_ANSI|FILE_TXT); if(h!=INVALID_HANDLE){ //ファイルが正常に開かれた FileWriteString(h,str); //データを書き込む FileClose(h); //ファイルに書き込む Sleep(100); //他のプログラムのように一時ストップを増やす //データを読み取る return(true); //成功した場合に 'true' を返す } Sleep(1); //他のプログラムを聞かせて、一瞬ストップ //ファイルを読み終える //ファイルが利用可能なとき } return(false); //データの書き込みに失敗した場合 }
ファイルを開くための試みがされています。ファイルを開く、ライティング、終了、その他のプログラムがファイルを開き、比較的長い一時ストップ (Sleep(100) 関数) が続きます。短い一時停止をした場合、エラーを開くファイル、ファイルが利用可能なときの瞬間をキャッチする (sleep (1) の関数)。
同じ原理を受け入れ、(読み込み) 関数に従います。sTestFileReceiver スクリプトは、このような関数を備えています。得られたデータは、Comment() 関数で表示されます。1 つのグラフに送信機スクリプトと別の (または別のターミナル インスタンス) 受信スクリプトを起動します。
余分な関数
一部を除いてファイルでほとんどの作業に使用されるものため、 すでにほぼすべての関数を検討しています: FileSize()、 FileTell() 、 FileFlush()。FileSize() 関数は、開いたファイルのサイズをバイト単位で返します。
void OnStart(){ int h=FileOpen("test.txt",FILE_READ|FILE_ANSI|FILE_TXT); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } ulong size=FileSize(h); FileClose(h); Alert("File size "+IntegerToString(size)+" (bytes)"); }
sTestFileSize スクリプトのコードがあります。スクリプトを実行すると、ファイルのサイズとメッセージ ウィンドウが開きます。
FileTell() 関数は、開いているファイルのファイル ポインターのポジションを返します。この関数を使用し、難しい任意の適切な例です。シンプルに注意してください。
FileFlush() 関数より便利です。ドキュメントで述べたように、この関数は、ディスクにファイルエントリー/出力バッファーに残っているすべてのデータを送信します。関数呼び出しの効果は、(ただし、リソース効率がよくあり、ファイル ポインターは最初場所に残ります) ファイルを再オープン/クローズ処理に似ています。ご存知のように、ファイルはディスク上のエントリとして格納されます。ただし、ファイルを開くまで、ディスクではなくバッファーに書き込みが実行されます。ディスクへの書き込みはファイルが閉じられたときに実行されます。したがって、緊急プログラム停止の場合は、データは保存されません。ファイルへの各書き込みの後 FileFlush() を呼び出すと、ディスクにデータを保存し、プログラムがクラッシュする任意の問題が発生しません。
フォルダーの操作
ファイルでの作業に加えて MQL5 をフォルダーを操作するための関数です: FolderCreate()、 FolderDelete() FolderClean()。FolderCreate 関数は、フォルダーの作成に使用されます。すべての関数は、2 つのパラメータを持ちます。最初の 1 つは、フォルダー名に必須です。2つ目は、 FILE_COMMON フラグ (共通のデータ フォルダー内のフォルダーの操作)です。
FolderDelete() は、指定したフォルダーを削除します。空のフォルダーのみを削除できます。ただし、フォルダーの内容を消去する FolderClean() 関数が使用されるので問題ではないです。サブフォルダーとファイルを含むすべての内容が削除されます。
ファイルの一覧を取得
正確に必要なファイルの名前は覚えていないことがあります。始まり数値でなく、数字で終わるのは覚えているかもしれません。たとえば file1.txt、file2.txt などです。この場合、マスク、 FileFindFirst()、 FileFindNext()、 FileFindClose()関数を使用して、ファイル名を取得できます。この関数は、ファイルとフォルダーの両方を検索します。フォルダー名は、末尾にバック スラッシュがファイル名から区別できます。
ファイルとフォルダーの一覧を取得するための関数を書いてみましょう。別のフォルダー名の中の 1 つの配列内のファイル名を収集してみましょう。
void GetFiles(string folder, string & files[],string & folders[],int common_flag=0){ int files_cnt=0; //ファイル カウンター int folders_cnt=0; //フォルダー カウンター string name; //ファイルまたはフォルダーの名前を受け取る変数 long h=FileFindFirst(folder,name,common_flag); //検索ハンドルと名前を受け取る //最初のファイル/フォルダーの (存在する場合) if(h!=INVALID_HANDLE){ //少なくとも 1 つのファイルまたはフォルダーが存在 do{ if(StringSubstr(name,StringLen(name)-1,1)=="\\"){ //フォルダー if(folders_cnt>=ArraySize(folders)){ //配列のサイズを確認してください //必要に応じて増加します。 ArrayResize(folders,ArraySize(folders)+64); } folders[folders_cnt]=name; //フォルダー名を配列に送信する folders_cnt++; //フォルダーをカウント } else{ //ファイル if(files_cnt>=ArraySize(files)){ //配列のサイズを確認してください //必要に応じて増加します。 ArrayResize(files,ArraySize(files)+64); } files[files_cnt]=name; //配列にファイル名を送信 files_cnt++; //ファイルをカウント } } while(FileFindNext(h,name)); //次のファイルまたはフォルダーの名前を受け取る FileFindClose(h); //検索の終了 } ArrayResize(files,files_cnt); //配列サイズを変更 //実際のファイル数 ArrayResize(folders,folders_cnt); //配列サイズを変更 //フォルダーの実際の番号 }
この関数を試してください。次のメソッド、スクリプトから呼び出します。
void OnStart(){ string files[],folders[]; GetFiles("*",files,folders); Alert("=== Start ==="); for(int i=0;i<ArraySize(folders);i++){ Alert("Folder: "+folders[i]); } for(int i=0;i<ArraySize(files);i++){ Alert("File: "+files[i]); } }
STestFileGetFiles スクリプトは、以下に添付されます。メモ、"*"検索マスク。
GetFiles("*",files,folders);
マスクは、すべてのファイルや MQL5 を/ファイル ディレクトリ内のフォルダーを検索できます。
すべてのファイルとフォルダー"test"を見つけるために「テスト *」マスクを使用できます。Txt ファイルが必要な場合は、"*.txt"マスクなどする必要があります。ファイル数とフォルダー (たとえば、"folder1") を作成します。「Folder1\\ *」マスクを使用すると、含まれるファイルの一覧を表示できます。
コードページ
現在の記事では、FileOpen() 関数は、サンプル コードでしばしば適用されます。記述されていないパラメータのいずれかを見てみましょう-コードページ。コード ページは、テキスト シンボルとその数値の換算表です。もっとわかりやすく ANSI エンコーディングで見てみましょう。エンコーディングの文字テーブルには、各言語にオペレーティング システムの設定で定義されている別のコード ページを使用することを意味し、 256 文字が含まれます。CP_ACP 定数は、既定では、FileOpen() 関数の呼び出し元に対応しています。異なるコード ページを使用する必要があり、このテーマに関する詳細に意味がないとは非常に考えにくいです。一般的な知識は充分でしょう。
制限なしファイルの操作
場合によって、ターミナルのファイル (外 MQL5 を/ファイルまたは共有フォルダー)「サンド ボックス」の外のファイルを操作できます。MQL5 をアプリケーションのソース コード ファイルを処理に自動的にを変更、オンザフライでグラフィカルなインターフェイス イメージ ファイルを生成、コードなどを生成するための関数を大幅に拡大できる可能性があります。信頼できるプログラマを雇うことができます。「WinAPI 経由でファイル操作」で続きを読むことができます。また、もっと簡単なメソッドがあります。MQL5 をファイルでの作業のすべての必要な手段したがって、ファイルをターミナルの「サンド ボックス」に移動し、すべての必要な操作を実行して戻ります。単一の WinAPI 関数 (CopyFile) で十分です。
MQL5アプリケーションを使用できるので、WinAPI 関数のアプリケーションの許可が必要です。アクセス許可は、ターミナルの設定 (メイン メニューのツール - オプション - EA - DLL インポート) で有効です。この場合、アクセス許可はその後起動したすべてのプログラムで有効です。一般的な権限ではなく、起動しているプログラムに対してのみアクセス許可を有効にできます。WinAPI 関数やその他の Dll にアクセスするアプリケーションの場合は、そのウィンドウで「DLL インポートを許可する」オプションの依存関係タブが表示されます。
CopyFile関数の 2 つのバージョンがあります: CopyFileA() とCopyFileW()。いずれかを使用できます。ただし、CopyFileA() 関数を使用する場合は、文字列型の引数を最初に変換する必要があります。「MQL5 をプログラミングの基礎: 文字列」の「呼び出し API 関数」をご覧ください。最新の CopyFileW() 関数をお勧めします。この例では、引数が指定された文字列の変換は必要はありません。
CopyFileW() 関数を使用するためにまず読み込む必要があります。Kernel32.dll ライブラリでを見つけることができます。
#import"kernel32.dll" int CopyFileW(string,string,int); #import
sTestFileWinAPICopyFileW スクリプトのコードにあります。
このスクリプトは、MQL5 を/ファイルのソース コードを含むファイルをコピーします。
void OnStart(){ string src=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Scripts\\"+MQLInfoString(MQL_PROGRAM_NAME)+".mq5"; string dst=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\"+MQLInfoString(MQL_PROGRAM_NAME)+".mq5"; if(CopyFileW(src,dst,0)==1){ Alert("File copied"); } else{ Alert("Failed to copy the file"); } }
成功した場合、CopyFileW() は1、それ以外の場合 0 を返します。この関数の 3 番目のパラメータは、ターゲットファイルがある場合、ファイルを上書きできるかどうかを示します: 0-有効 1-無効です。スクリプトを起動します。正常に動作する場合、MQL5ファイルのフォルダーを確認します。
オペレーティング システムファイルのコピーの制限に注意してください。いわゆる「ユーザー アカウント制御パラメータ」です。有効な場合、ファイルをコピーできません。たとえば、システム ドライブのルートにファイルをコピーすることはできません。
便利なスクリプト
ファイルを扱うための便利な関数だけでなく、より多くの便利なスクリプトを作成してみましょう。引用符を csv ファイルにエクスポートし、トレード結果をエクスポートするためのスクリプトを開発します。
引用エクスポート ・ スクリプト、データの開始、終了日、日付が使用される場合、すべてのデータをエクスポートする必要があります。スクリプトのプロパティ ウィンドウを開くのに必要なプロパティを設定します。
#propertyscript_show_inputs
その後、外部のパラメータを宣言します。
input bool UseDateFrom = false; //開始日を設定 input datetime DateFrom=0; //開始日 input bool UseDateTo=false; //終了日を設定 input datetime DateTo=0; //終了日
OnStrat() スクリプト関数のコードを記述します。スクリプトのパラメータに従って日付を定義します。
datetime from,to; if(UseDateFrom){ from=DateFrom; } else{ int bars=Bars(Symbol(),Period()); if(bars>0){ datetime tm[]; if(CopyTime(Symbol(),Period(),bars-1,1,tm)==-1){ Alert("Error defining data start, please try again later"); return; } else{ from=tm[0]; } } else{ Alert("Timeframe is under construction, please try again later"); return; } } if(UseDateTo){ to=DateTo; } else{ to=TimeCurrent(); }
変数を定義する日付を使用する場合、その値が使用されます。終了日の TimeCurrent() を使用する以外の場合、開始日は、最初に定義されます。
日付があるので、引用符を MqlRates 型の配列にコピーします。
MqlRates rates[]; if(CopyRates(Symbol(),Period(),from,to,rates)==-1){ Alert("Error copying quotes, please try again later"); }
配列データをファイルに保存します。
string FileName=Symbol()+" "+IntegerToString(PeriodSeconds()/60)+".csv"; int h=FileOpen(FileName,FILE_WRITE|FILE_ANSI|FILE_CSV,";"); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; } //ファイルにデータを書き込む: 時間、始値、高値、安値、終値、ボリューム、ティック //最初の行の場所。 FileWrite(h,"Time","Open","High","Low","Close","Volume","Ticks"); for(int i=0;i<ArraySize(rates);i++){ FileWrite(h,rates[i].time,rates[i].open,rates[i].high,rates[i].low,rates[i].close,rates[i].real_volume,rates[i].tick_volume); } FileClose(h); Alert("Save complete, see the file "+FileName);
成功した場合、スクリプト ファイルが正常に保存されている適切なメッセージ通知が開きます。それ以外の場合、エラー メッセージが表示されます。既製の sQuotesExport スクリプトは、以下にあります。
トレード履歴スクリプトを開発してみましょう。初めはほぼ同じです: 外部変数の最初に、時間の定義は実装がはるかに簡単です。開始時間 0 は十分なヒストリーをリクエストするときです。
datetime from,to; if(UseDateFrom){ from=DateFrom; } else{ from=0; } if(UseDateTo){ to=DateTo; } else{ to=TimeCurrent(); }
ヒストリーを割り当てます。
if(!HistorySelect(from,to)){ Alert("Error allocating history"); return; }
ファイルを開きます。
string FileName="history.csv"; int h=FileOpen(FileName,FILE_WRITE|FILE_ANSI|FILE_CSV,";"); if(h==INVALID_HANDLE){ Alert("Error opening file"); return; }
フィールド名の最初の行を書きます。
FileWrite(h,"Time","Deal","Order","Symbol","Type","Direction","Volume","Price","Comission","Swap","Profit","Comment");
すべてのトレードを書き込みファイルに。
for(int i=0;i<HistoryDealsTotal();i++){ ulong ticket=HistoryDealGetTicket(i); if(ticket!=0){ long type=HistoryDealGetInteger(ticket,DEAL_TYPE); if(type==DEAL_TYPE_BUY || type==DEAL_TYPE_SELL){ long entry=HistoryDealGetInteger(ticket,DEAL_ENTRY); FileWrite(h,(datetime)HistoryDealGetInteger(ticket,DEAL_TIME), ticket, HistoryDealGetInteger(ticket,DEAL_ORDER), HistoryDealGetString(ticket,DEAL_SYMBOL), (type==DEAL_TYPE_BUY?"buy":"sell"), (entry==DEAL_ENTRY_IN?"in":(entry==DEAL_ENTRY_OUT?"out":"in/out")), DoubleToString(HistoryDealGetDouble(ticket,DEAL_VOLUME),2), HistoryDealGetDouble(ticket,DEAL_PRICE), DoubleToString(HistoryDealGetDouble(ticket,DEAL_COMMISSION),2), DoubleToString(HistoryDealGetDouble(ticket,DEAL_SWAP),2), DoubleToString(HistoryDealGetDouble(ticket,DEAL_PROFIT),2), HistoryDealGetString(ticket,DEAL_COMMENT) ); } } else{ Alert("Error allocating a trade, please try again"); FileClose(h); return; } }
注: (買い/売り) のトレードの種類、方向 (エントリー/出力) は、文字列に変換されます。ダブル型の値は、2 つの小数点を含む文字列に変換されます。
最後に、ファイルを閉じ、メッセージが表示されます。
FileClose(h); Alert("Save complete, see the file "+FileName);
SHistoryExport スクリプトは、以下に添付されます。
トピックの詳細
記事のセクションには、関連のファイルを操作するメソッドで注目すべき膨大な量があります。
- HTML と CSS を使った別のログ ファイル
- メタト レーダー4 と Matlab の CSV ファイルを介して相互作用
- HTML の図表
- グループ化されたファイルの操作
- EA、インジケーターやスクリプトのエントリーパラメータを格納するテキスト ファイルの使用
- 他のアプリケーションのメタト レーダー 5 引用を準備するメソッド
- MQL5でエラー処理とログ
- エラーの検出およびログ
- 純粋な MQL5 をアーカイブ ZIPで処理
- ファイルの作業。重要な相場のイベントの可視化の例
- MQL5クックブック: トレード履歴をファイルに書き込み、Excel の各シンボルのグラフのバランスをとる
- MQL5クックブック: 指定された条件に基づいてEAアドバイザーの最適化の結果の保存
- WinAPI 経由でのファイル操作
結論
この記事では、 MQL5のファイルを操作するためのすべての関数を検討しています。一見狭いトピックが非常に大きいことが判明しました。。ただし、十分な実用的な例は、トピックに関連する問題を検討されています。とにかく、最も一般的なタスクは、テスター内のファイル操作です。さらに、便利な関数を開発し、すべての例で、実用的かつ論理的に完全です。すべてのコードは、スクリプトとして添付します。
添付
- sTestFileRead-ANSI テキスト ファイルから 1 行を読み取り、メッセージ ボックスに表示します。
- sTestFileReadToAlert-ANSI テキスト ファイルからすべての行を読み取り、メッセージ ボックスに表示します。
- sTestFileCreate-ANSI テキスト ファイルを作成します。
- sTestFileAddToFile-ANSI テキスト ファイルに行を追加します。
- sTestFileChangeLine2 1-ANSI テキスト ファイルの 1 行を変更することはできません。
- sTestFileChangeLine2 2- まだ別の無効は、ANSI テキスト ファイルの 1 行を変更します。
- sTestFileChangeLine2 3-ANSI テキスト ファイルの 1 行に置き換えるファイル全体を書き換えします。
- sTestFileReadFileToArray — 配列に ANSI テキスト ファイルを読み取る関数です。
- sTestFileCreateCSV-ANSI CSV ファイルを作成します。
- sTestFileReadToAlertCSV-フィールドによってメッセージ ボックスに ANSI CSV ファイルを読みます。
- sTestFileReadToAlertCSV2 — 線分離とフィールドによってメッセージ ボックスに ANSI CSV ファイルの読み込み.
- sTestFileReadFileToArrayCSV — 構造配列に ANSI CSV ファイルを読みます。
- sTestFileWriteArrayToFileCSV-CSV ANSI ファイルに 1 行に配列を書き込みます。
- sTestFileReadToAlertUTF-UNICODE テキスト ファイルを読み取り、メッセージ ボックスに表示します。
- sTestFileCreateUTF-UNICODE テキスト ファイルを作成します。
- sTestFileCreateBin-バイナリ ファイルを作成し、3 つのdouble変数を書き込みます。
- sTestFileReadBin-バイナリ ファイルから 3 つのdouble変数の読み取り。
- sTestFileChangeBin-バイナリ ファイルで 2 番目のdouble変数の書き換え。
- sTestFileReadBin2-バイナリ ファイルから 3 番目のdouble変数の読み取り。
- sTestFileWriteStructBin-構造をバイナリ ファイルに書き込みます。
- sTestFileReadStructBin-構造をバイナリ ファイルから読み取る。
- sTestFileReadStructBin2-構造を持つバイナリ ファイルから 1 つの変数を読み取ります。
- sTestFileCheckUnicode-ファイルの種類 (ANSI または UNCODE) をチェックします。
- sTestFileWriteArray-配列をバイナリ ファイルに書き込みます。
- sTestFileReadArray-配列をバイナリ ファイルから読み取る。
- sTestFileWriteArray2-2つの配列をバイナリ ファイルに書き込みます。
- sTestFileReadArray2-2つの配列をバイナリ ファイルから読み取る。
- sTestFileWriteStringArray-文字列の配列をバイナリ ファイルに書き込みます。
- sTestFileReadStringArray-文字列配列をバイナリ ファイルから読み取る。
- sTestFileCopy-MQL5 を/ファイルから共有フォルダーにファイルをコピーします。
- sTestFileCopy2-ファイルを共有フォルダーにコピーします。
- sTestFileCopy3-MQL5 を/ファイルを共有フォルダーからファイルをコピーします。
- sTestFileTransmitter-共有ファイル経由でデータを送信するためのスクリプトフォルダー。
- sTestFileReceiver-共有データ フォルダーのファイルを使用してデータを受信するためのスクリプト。
- sTestFileSize-ファイルのサイズを定義します。
- sTestFileGetFiles-マスクによってファイルの一覧を受信します。
- sTestFileWinAPICopyFileW-WinAPI CopyFileW() 関数の使用例です。
- sQuotesExport-クオートをエクスポートするためのスクリプト。
- sHistoryExport-トレード履歴を保存するためのスクリプト。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2720
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索