初級から中級まで:サンドボックスの操作
はじめに
前回の「初級から中級まで:ランダムアクセス(II)」では、ファイルに含まれるデータや情報にランダムアクセスできるようにしながら、ファイルを操作する方法を解説しました。 また、ファイルの内部に格納された内容だけに着目した場合、同じ概念に基づいていても、必ずしも同じ結果が得られるとは限らないことも説明し、実例を示しました。 しかし、ターミナルに表示される結果については、実装そのものが期待される結果に合うように調整・適応させるため、実装方法の違いによる差は生じません。
ファイルの扱い方は、全体としてそれほど大きく変わるものではありません。また、各ファイルの内部には構造化されたデータが格納されているものの、その内容を表示しただけでは、どのような種類のデータが含まれているのかを明示的に示す情報はない、という点も理解しているものとします。 これで、ファイルへのアクセスと操作を扱う第1部をひとまず締めくくることができます。 実際には、それぞれの言語で利用できる関数やプロシージャを最大限に活用するために、その言語固有のドキュメントを確認する必要があります。
読者の皆さん、どうか誤解しないでください。 MQL5の各関数やプロシージャがどのように使われるのか、興味をお持ちの方も多いでしょう。しかし、私の考えでは、それだけを取り上げてもあまり有益ではありません。 むしろ、そのようなアプローチでは記事の内容が画一的な枠組みに縛られ、退屈で単調なものになってしまうでしょう。 つまり、ファイルに関する最初の導入部分はひとまず完了したと考えられますが、このテーマについての解説が終わったわけではありません。 これまで扱ってきた内容は、MetaTrader 5がサポートするサンドボックス内に限られているからです。 基本的に、ここまではユーザーレベルのアクセスを扱ってきたにすぎません。
しかし、アクセスにはもう1つのレベルがあります。それがアプリケーションレベルのアクセスです。 これについては後ほど解説します。 このようにユーザーレベルのアクセスとアプリケーションレベルのアクセスを区別すると、サンドボックスの使用によって課される制約をはるかに超える、かなり複雑な問題が生じます。 ここから話が複雑になっていきます。 もっとも、それはMetaTrader 5のサンドボックスシステムの仕組みを理解していない場合の話です。 この点については、これまでの記事でもすでに触れてきました。
この問題に進む前に、いくつかのプロシージャと関数について説明しておく必要があります。 これらはファイルを扱ううえで非常に役立ち、通常なら実行できない操作も可能にしてくれるからです。 この問題を正しく理解するために、さっそく本記事の主題に入りましょう。
ファイルとディレクトリの探索
このような検索処理は不要だと考える人もいるでしょうし、実際、ほとんどのアプリケーションでは必要ありません。しかし、MetaTrader 5向けの開発に限らず、ほかのプログラミング環境でも、ディレクトリツリーやその中にあるファイルを検索する処理を実装しなければならない、特定の状況が存在します。 この方法を理解しておくことは、プログラミングで遭遇する作業の中でも、特に日常的で定型的なものに対処するうえで役立つでしょう。 多くの場合、この種の作業は非常に単調で、ある意味では退屈です。 それでも、こうした処理をどのように実装すればよいのかを知っておくことは重要です。
MetaTrader 5向けのプログラミングには特有の性質があるため、検索をおこなう方法は2つあります。 一方は対話モードで、もう一方は、いわば自動的に処理する方法です。 対話モードでは、小さなファイルブラウザーのようなダイアログボックスを使用します。 一方、自動化された方法では、MQL5が提供する関数を利用してOSのプロシージャにアクセスし、ファイルシステムを検索します。
まず、前回の記事で取り上げたスクリプトの1つを、ごく簡単な方法で修正してみましょう。 これにより、ファイルやディレクトリへの対話モードでのアクセスと検索が、どのように機能するのかを理解できます。 修正後のコード全文を以下に示します。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int handle; 07. const datetime dt = D'31.10.2024 15:30:10'; 08. const int i32 = 356248; 09. string filenames[]; 10. 11. if (FileSelectDialog("Save as...", NULL, "All files (*.*)|*.*", FSD_WRITE_FILE, filenames, "Hello Word.txt") <= 0) 12. return; 13. 14. if ((handle = FileOpen(filenames[0], FILE_WRITE| FILE_READ | FILE_ANSI)) == INVALID_HANDLE) 15. { 16. Print("Error..."); 17. return; 18. }; 19. 20. FileWrite(handle, i32, "Info", dt); 21. 22. FileFlush(handle); 23. 24. FileSeek(handle, 0, SEEK_SET); 25. while (!FileIsEnding(handle)) 26. Print(FileTell(handle), " >> ", FileReadString(handle)); 27. 28. FileClose(handle); 29. } 30. //+------------------------------------------------------------------+
コード01
「よくわかりません。 一体コードのどこが変更されたのでしょうか。 一見すると、前回の記事で取り上げたコード例とまったく同じに見えます。」変更点はごくわずかで、一見しただけではコードに大きな影響を与えるようには見えません。 多くの人は、新しいコードを開発するには大幅な改変が必要だと考えていますが、実際には必ずしもそうとは限りません。 今回の変更点は非常にわかりやすく、11行目にあります。 しかし、変更が11行目だけであっても、コードを実行すると、それまでとは異なる動作が起こります。 まず、FileSelectDialog関数によって、以下に示すようなウィンドウが開きます。

図01
図01のウィンドウは、オペレーティングシステムによって提供・管理されており、いくつかの要素を簡単に確認できます。 まずは、ウィンドウのタイトルです。 ご覧のとおり、FileSelectDialog関数の第1引数に指定したタイトルとまったく同じです。 関数に渡す第2引数がNULLであるため、サンドボックスのルートディレクトリから開始します。 ここで注意してください。サンドボックス内にいるため、そのディレクトリの外へ出ることはできません。より正確に言えば、現在のルートディレクトリの外へ移動することはできないのです。 より正確に言えば、現在のルートディレクトリの外へ移動することはできないのです。 したがって、移動できる範囲は、現在のサンドボックスのディレクトリ構造内に限定されます。
関数の第3引数には、検索ウィンドウに表示される検索結果を絞り込むためのフィルタを指定します。 選択できるのは、11行目に記述されているフィルタだけです。 したがって、ここに記載されていないフィルタをオペレーティングシステムが受け付けてくれると期待してはいけません。そのようなことは起こらないからです。 関数の次の引数は、選択フラグです。 ここでは、ほかのフラグも実際に試し、それぞれがどのような結果をもたらし、何を目的としているのかを理解することが大切です。ファイル名などを指定するだけにとどまらず、さまざまな操作が可能だからです。 フラグに指定できる値については、ドキュメントを参照してください。
さて、次はFileSelectDialog関数の最後の2つの引数を見ていきましょう。 この部分は、採用している実装の種類によって多少異なる場合があります。 しかし、基本的に、第5引数には必ずstring型の動的配列を指定しなければなりません。 これは、関数が図01のダイアログボックスで行われたユーザーの操作に関するデータを、この配列に格納するためです。 一方、最後の引数は、必ずしもコード01のように記述する必要はありません。 ただし、特定のファイル名を使用する予定であれば、ここでその名前を指定する必要があります。 こうすることで、アプリケーションがデフォルトで想定するファイル名を指定できます。 ただし、ユーザーはこの名前を変更できることを忘れないでください。
さて、すべてが順調に進めば、この関数はゼロより大きい値を返します。 そうでなければ、エラーが発生したことを意味するため、スクリプトを停止する必要があります。 これは12行目でおこないます。 処理が成功した場合は、ファイルを保存するために14行目へ進みます。ここでは、コードは前回の記事と同じように動作します。 ただし、FileOpen関数を使用してファイルを作成または開く際には、第1引数として、配列に格納されている最初の値そのものが渡されることに注意してください。 この配列には、ユーザーが選択した複数のファイルを格納できます。 ファイルの選択は、11行目で関数を呼び出した際にユーザーがおこないます。 前述のとおり、MetaTrader 5のアプリケーションでFileSelectDialog関数をどのように使用するのかをより深く理解するには、実際に試してみることが必要です。
さて、この簡単な説明で、ファイルやディレクトリツリーを対話モードでナビゲートする方法について、理解し、練習するための手がかりは得られたと思います。 そこで、話題を明確に分けるため、次のセクションでは非対話型ナビゲーションについて見ていきましょう。
コードによるナビゲーション
状況によっては、ユーザーが検索処理に直接関与しないようにしたい場合があります。 しかしその一方で、何らかの理由から、ファイルだけでなくディレクトリ構造も含めて、ディレクトリツリーがどのように構成されているのかを把握したいこともあります。 そこで、コード01で見た方法はいったん脇に置き、別の方法を実装することにします。 これには、明確な目的があります。
ここでは、特定のアプリケーションを作成することではなく、できる限りわかりやすく説明することを目指しています。そのため、なぜディレクトリツリーをナビゲートする必要があるのかを説明するのは、なかなか難しいことです。 とはいえ、読者の皆さんには、ぜひ視野を広げ、ここでコードとして紹介する内容の先にある世界にも目を向けていただきたいと思います。 ファイル構造がどのように構成されているのかを把握する必要があるアプリケーションを想像してみてください。 そのうえで、この仕組みを実際の場面でどのように活用できるかを考えてみましょう。
いいですね。 この種のナビゲーションがどのように機能するのかを理解していただくために、まず、サンドボックス内のMQL5\Filesディレクトリが空であると仮定します。 つまり、現時点では、サンドボックス内にファイルもディレクトリも存在しないものとします。 すべてを筋道立てて理解するためには、この前提から始めることが重要です。 それでは、この前提を踏まえて、以下のコードを見ていきましょう。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. long handle; 07. string szFileName; 08. 09. if ((handle = FileFindFirst("*", szFileName)) == INVALID_HANDLE) 10. { 11. Print("Failed..."); 12. return; 13. } 14. do 15. { 16. Print(szFileName, " is a ", FileIsExist(szFileName) ? "file ..." : "directory..."); 17. }while (FileFindNext(handle, szFileName)); 18. FileFindClose(handle); 19. 20. Print("Search in directory completed successfully."); 21. } 22. //+------------------------------------------------------------------+
コード02
覚えておいてください。ここでおこなう操作はすべて、作業対象のサンドボックス内に限定されます。 原則として、サンドボックスの外にあるファイルやディレクトリを参照することはできません。 この点を忘れないでください。 では、コード02を実行すると、次のような結果になります。

図02
「なんてことだ、ここで一体何が起きたんだ? どうしてコードが失敗したんだ? 一体何をしたから、こんな目に遭わなきゃいけないんだ? これは間違いなく神罰に違いない。」(笑)読者の皆さん、落ち着いてください。 慌てて結論を出してはいけません。コードにエラーはなく、すべて正常に動作しています。 「どういうことですか? エラーが発生したのがわからないのですか?」もう一度言いますが、慌てないでください。 処理を始める前に何と説明したか、覚えていますか。 では、今回サンドボックスとして使用している MQL5\Filesディレクトリは、原則として完全に空であるはずですよね?
FileFindFirst関数は、サンドボックス内で該当する項目を何も見つけられなかったため、無効なハンドル値を返します。 つまり、指定したフィルタに一致する項目が見つからず、検索が失敗したことを示す値が返されたのです。 まさにそれが、図02に示された結果の理由です。 実際、今ここでもう一度コード01を実行すると、次のような結果が得られます。

図03
「なるほど、わかってきました。 でも、 サンドボックス内に何かが入っている場合はどうなるのでしょうか?」それは、サンドボックス内の内容を処理するように、コードがどのように構成されているかによります。 今回は非常に単純でわかりやすい処理を扱っているため、現時点で得られる結果も同じように単純明快です。 ただし、具体的な状況によっては、もう少し高度な解決策が必要になる場合もあります。 いずれにしても、まずはサンドボックス内に何らかの内容が存在する場合、どのような結果になるのかを確認しましょう。 そのために、テスト目的でいくつかのファイルとフォルダを作成しました。 コード01をもう一度実行すれば、それを確認できます。 この場合、結果は次の図に示すとおりです。

図04
これで、ようやくお見せできるものができました。 続いてコード02をもう一度実行すると、次のような結果が得られます。

図05
ここで注意していただきたいのは、コードには一切変更を加えておらず、サンドボックス内にファイルやフォルダを追加しただけだという点です。 しかし、ここから少し話が複雑になってきます。 もちろん、それは実際にどのような機能を実装したいかによって異なります。 前の図からもわかるように、コード02は正常に動作するものの、1つだけ注意すべき点があります。 それは、コード02が最初に指定した検索対象ディレクトリにしか適用されないことです。 ディレクトリツリー内のほかのディレクトリに入り込み、それぞれの内容を報告することはできません。 特定のディレクトリにアクセスするには、そのディレクトリを明示的に指定する必要があります。 これは、9行目から始まる検索処理を開始する前におこなわなければなりません。 そのため、状況によっては実現できることが多少制限されます。
ここで少し立ち止まって、その理由を考えてみましょう。 実は、ディレクトリツリーをたどるための解決策は、コード02そのものにあります。 ただし、すべてが期待どおりに動作するようにするには、コードにいくつかの小さな変更を加える必要があります。 つまり、サンドボックスのディレクトリツリー内にあるすべてのディレクトリについて、それぞれに存在するすべてのファイルを報告できるように、コードを変更しなければなりません。
さて、FileFindFirst関数にフィルタを指定する際、サンドボックス内のパスも含められることがわかりました。 では、コード02を再帰コードに変更したらどうなるでしょうか。 期待通りの動作が得られるでしょうか。 コード02の16行目では、各ファイルの名前とその場所を取得できます。 つまり、今、私たちが答えなければならないのはこの問題です。 ここでこれから紹介する処理を実現する方法は、いくつかあることも覚えておいてください。 どの方法が適しているかは、それぞれの状況によって異なります。
それでは、まずコードを以下に示すような形に変更しましょう。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. SearchIn(""); 07. 08. Print("== Research completed. =="); 09. } 10. //+------------------------------------------------------------------+ 11. void SearchIn(const string szDir) 12. { 13. long handle; 14. string szFileName; 15. 16. Print("[",szDir,"]"); 17. if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE) 18. return; 19. do 20. { 21. if (FileIsExist(szFileName)) Print(szFileName); 22. }while (FileFindNext(handle, szFileName)); 23. FileFindClose(handle); 24. } 25. //+------------------------------------------------------------------+
コード03
これが最初のステップです。 それでは、ここからはよく注意してください。 このコードを実行すると、上に示した結果とは異なる結果が得られます。 これは、ここではファイル名の表示だけに注目しているためです。 この点を明確に理解しておくことが非常に重要です。 おそらく、ファイルエクスプローラーのアドレスバーに表示されるように、ディレクトリのパスとファイル名の両方が表示されることを期待していたのではないでしょうか。 しかし、実際に目にしているのは、オペレーティングシステムやプログラムが内容を表示する方法にすぎません。 ディスク上に保存されているフォルダやファイルの構造の内部では、それらは異なる形で整理されています。
実際、ファイルシステムはリストや電話帳によく似ています。 おそらく、この問題や一連の混乱は、Windows 95の登場をきっかけに始まったのでしょう。 その頃、ディレクトリツリーをファイル名の一部として扱うという考え方が広まり始めました。 実際には、仕組みはそれほど単純ではありません。 ただし、この説明は本記事の範囲を超えるため、ここでは扱いません。 本題に戻りましょう。 コード03を実行した結果を、次の図に示します。

図06
ここではファイル名だけが表示されていることに注意してください。 ディレクトリが表示されていないのは、現時点ではそれらに関心がないためです。 しかし、図05に示されているディレクトリに何らかの内容が含まれているとしたら、それをどのように表示すればよいのでしょうか。 これは最も簡単な部分です。 ただし、その説明に入る前に、ディレクトリを指定する際には、最後の文字がスラッシュになることに注意してください。 これは、次に説明する内容にとって非常に重要です。
つまり、文字列szFileNameがディレクトリを指している場合、その文字列にはスラッシュが含まれます。 したがって、それがディレクトリなのかファイルなのかを判別するために、FileIsExist関数を使用する必要はありません。 文字列にスラッシュが含まれているかどうかを確認するだけで十分です。 スラッシュがあればディレクトリ、 なければファイルです。 それだけです。
ただし、ここでコード03のもう1つの点に注目してください。 11行目のプロシージャは、引数として文字列を受け取ります。 これは、検索を実行する際の開始ディレクトリになります。 しかし、6行目では、11行目のプロシージャに引数を一切渡していません。 つまり、検索はサンドボックスのルートディレクトリから開始されます。 この点を理解することは非常に重要です。なぜなら、ここからコードの再帰処理が始まるからです。
文字列にスラッシュが含まれているかどうかを確認するときは、その文字列がディレクトリを指しているかどうかを調べていることを思い出してください。 この情報を利用するようにコードを変更したらどうなるでしょうか。 つまり、文字列にディレクトリ名が含まれているという情報を無視するのではなく、11行目のSearchInの呼び出しを変更し、この文字列の内容を利用するようにするのです。この場合、その文字列がディレクトリを指していることはわかっています。 では、何が起こるのでしょうか。 実際にどのように機能するのかを見てみましょう。 この考えに基づいて、コード03を以下のように変更できます。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. SearchIn(""); 07. 08. Print("== Research completed. =="); 09. } 10. //+------------------------------------------------------------------+ 11. void SearchIn(const string szDir) 12. { 13. long handle; 14. string szFileName; 15. 16. Print("[",szDir,"]"); 17. if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE) 18. return; 19. do 20. { 21. if (StringFind(szFileName, "\\") > 0) 22. SearchIn(szFileName); 23. else 24. Print(szFileName); 25. }while (FileFindNext(handle, szFileName)); 26. FileFindClose(handle); 27. } 28. //+------------------------------------------------------------------+
コード04
いいですね。 コード04では、先ほど説明した内容を実装するために加えた変更点を確認できます。 したがって、コード04を実行すると、図06で見たものとはまったく異なる結果が得られます。 ただし、その結果は図06に示されたものと非常によく似ています。 この結果をわかりやすいと感じる人もいれば、混乱する人もいるでしょう。 わかりやすくするために、以下の図07をご覧ください。

図07
では、何が問題なのでしょうか。 図07を見て、Backup.zipファイルがどのフォルダに属しているかわかりますか。 Sub 02フォルダだと言えるでしょう。 しかし、よく見ると、Sub 01フォルダやSub 11フォルダでも同様のことが起きていることがわかります。 「ちょっと待ってください。 これは想像していたよりもずっと複雑です。 図04を見ると、Sub 02フォルダはSub 01フォルダと同じように、ルートディレクトリにあります。 しかし、図07のように表示されると、Backup.zipファイルは実際にはSub 01\Sub 11\Sub 02というパスにあるように思えます。 これはおかしいです。 少し混乱してきました。」
この方法では、サンドボックス内のディレクトリツリーが実際にどのような構造になっているのかを理解するのが、やや難しくなります。 そこで、ここで実際の構造を示しましょう。 これにより、結果をどのように表現すべきかがわかるはずです。 以下のアニメーションで確認できます。

アニメーション01
アニメーション01では、非常にシンプルなフォルダ構造と、図07には表示されていないファイルを確認できます。 一見すると、これは少し奇妙に思えます。 図07では、Backup.zipファイルがディレクトリ内にあるにもかかわらず、表示されているからです。 では、何が間違っているのでしょうか。 問題は、コード04の22行目でディレクトリ構造を無視していることにあります。 実際には、ツリー構造を考慮せず、ディレクトリそのものにしかアクセスしていません。 このような問題の解決方法は非常に簡単です。考えてみれば、ある意味では当たり前のことでもあります。
ただし、コードにもう1つ変更を加えます。 ファイル名を出力する際に、そのファイルが見つかったパスを追加します。 こうすることで、全体として、より理解しやすい構造になります。 その結果、次のようなコードになります。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. SearchIn(""); 07. 08. Print("== Research completed. =="); 09. } 10. //+------------------------------------------------------------------+ 11. void SearchIn(const string szDir) 12. { 13. long handle; 14. string szFileName; 15. 16. Print("[",szDir,"]"); 17. if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE) 18. return; 19. do 20. { 21. if (StringFind(szFileName, "\\") > 0) 22. SearchIn(szDir + szFileName); 23. else 24. Print(szDir, szFileName); 25. }while (FileFindNext(handle, szFileName)); 26. FileFindClose(handle); 27. } 28. //+------------------------------------------------------------------+
コード05
それでは、上記に示した新しいコードを実行してみましょう。 結果は以下の通りです。

図08
さて、これで非常に興味深い結果が得られました。 コード04に簡単な変更を加えてコード05に示す結果を得ただけで、まったく異なる、しかもはるかに興味深い結果になったことに注目してください。 実際、必要であれば、コードの16行目を削除しても、ディレクトリ構造がどのように構成されているかを理解し、各ファイルがどこにあるかを視覚的に確認できます。 これは興味深いことです。 しかし、コード05には、いわば、小さいながらもかなり厄介な問題があります。 ご覧のとおり、コード自体は正常に動作します。 ただし、ディレクトリとファイルが混在して表示される、特定の状況があります。 これはコードのエラーでも、ソフトウェアの不具合でもありません。 別の種類の問題です。
これは具体的には、FileFindFirst関数とFileFindNext関数がどのように連携するかに関係しています。 重要なのは、FileFindFirst関数が呼び出されると、システムがオペレーティングシステムに対して、指定されたフィルタに一致する結果を要求するという点です。 返される結果は、ファイルの場合もディレクトリの場合もあります。 理論上、どちらが先に返されるかを制御することはできません。 これはオペレーティングシステムによって決まります。 しかし、次の要素を再度問い合わせるときに問題が生じます。 これはFileFindNext関数を使用しておこないます。 では、何が問題なのでしょうか。 たとえば、ディレクトリに移る前にすべてのファイルを処理したい場合、あるいはその逆の場合を考えてみましょう。 どうすればよいのでしょうか。 オペレーティングシステムがどの種類の項目を返すかは制御できないことを覚えておいてください。 受け取れるのは返された項目だけで、それをどう扱うかは自分で決めることになります。
このような問題を解決するには、別のアプローチを取る必要があります。 この問題については、次の記事で取り上げていきます。
まとめ
今回の記事では、MetaTrader 5を使ってサンドボックスの内容を確認するための、シンプルで簡単、かつ実用的な方法を見てきました。 少なくとも現段階では、一見すると、ここで目にするものには特に意味や明確な目的がないように思えるかもしれません。 しかし、コードを使ってフォルダ内の内容やルートディレクトリ全体を表示する方法を知り、さらに重要なこととして、その使い方を理解しておけば、無数のファイルやフォルダの中に埋もれている特定のデータを素早く見つけるのに役立ちます。
ここで目にするものを扱う方法を学ぶ主な目的は、次の記事で取り上げる別のトピックを理解することです。 そのため、次の記事の内容を理解できるよう、この記事で読んだことを注意深く、落ち着いて振り返ってみてください。 次は、プログラミングを学び始めたばかりの方には難しそうに感じられるかもしれませんが、非常に興味深いトピックに進みます。 次の記事でお会いしましょう。
| ファイル | 説明 |
|---|---|
| コード01 | フォルダ間を移動する方法を示します。 |
| コード02 | フォルダ間を移動する方法を示します。 |
| コード03 | フォルダ間を移動する方法を示します。 |
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/16322
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
取引におけるニューラルネットワーク:インテリジェントな予測パイプライン(スパース混合エキスパート)
初級から中級まで:ランダムアクセス(II)
取引におけるニューラルネットワーク:適応的周期セグメンテーション(LightGTS)
MQL5をマスターする — 初心者からプロまで(第7回):MQLアプリケーションのデバッグの原則
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索