English Deutsch
preview
初心者からエキスパートへ:MQL5での共同デバッグ

初心者からエキスパートへ:MQL5での共同デバッグ

MetaTrader 5 | 3 12月 2024, 10:13
338 0
Clemence Benjamin
Clemence Benjamin

コアコンテンツ 


はじめに

通常、すべての著者は記事の最初から最後まで特定の問題に取り組むことを目指します。本日のタイトルは「デバッグ」ですが、このタイトルを軽視しないでください。ここではプロセスの基本にとどまらず、さらに深く掘り下げます。私は、長年にわたって複数の成功したプロジェクトで実際に採用してきたテクニックを紹介します。ソフトウェアプログラミングのあらゆる分野において、デバッグは欠かせないトピックです。しかし、多くの著者がコードを正しく動作させるために直面した苦労を共有することなく、洗練された最終製品の提示に重点を置いていることに気づきました。

ニューラルネットワークシステム、人工知能、その他関連するソフトウェア分野のいずれにおいても、デバッグは不可欠です。最も価値のあるスキルは、問題が発生した際にそれを解決する能力であり、このスキルは将来同様の課題に直面した際に不可欠な要素となると私は信じています。したがって、問題解決を通じて強力なスキルセットが構築され、徐々に専門家としての成長へとつながっていくのです。

共同デバッグ

共同デバッグ

この記事を書こうと決心したとき、私はあるプロジェクトに取り組んでいました。そのプロジェクトではコードをコンパイルしようとした際、いくつものエラーが発生していました。中にはデバッガーが50行にも及ぶエラーを表示し、それらすべてに対処しなければならないこともありました。試行錯誤を重ねる中で、バグに対処するためのルーチンを開発しました。このルーチンを使えば、わずか数分、場合によっては数秒で問題を解決し、プログラムをスムーズに実行させることが可能となったのです。

私の目標は、デバッグプロセスを加速させるテクニックについて知っていただくことにあります。私の経験から得た最も貴重な教訓の1つは、デバッグプロジェクトに積極的に取り組むことで、MQL5を迅速かつ効果的に習得できるということです。以前、バグのあるプログラムを保存しておいたので、それを一緒に確認しながら改良してみましょう。

根強い課題の1つとして、多くの人が無料で入手可能な長いMQL5の書籍を読み通すのに苦労するという現実があります。しかし、それによってこれらの書籍の価値が損なわれるわけではありません。これらの書籍には、MQL5プログラミングの基本から高度な概念に至るまで重要な知識が含まれています。最良の結果を得るには、進行中の作業に関連する特定のトピックについてこれらの書籍を参照しつつ、アクティブなプロジェクトに参加することが賢明です。このようなプロジェクトを完了することで、自然と豊富な知識を吸収できます。

通常、バグレポートは以下の表のように4列に編成されます。

列(名前) 説明
詳細 この列には、コード内で発生したエラーまたは警告の簡単な説明が表示されます。構文エラー、宣言されていない変数、型の不一致、その他のコーディングミスなど、問題の性質を説明できます。説明を理解することで、プログラマーは問題を迅速に特定できます。
ファイル ここでは、エラーが発生したファイル名が示されます(例:D1 PriceMarker.mq5)。プロジェクト内に複数のファイルがある場合、どのファイルに問題が含まれているかを知ることは、効果的なデバッグと修正をおこなう上で非常に重要です。
指定されたファイル内でエラーが見つかった正確な行番号を指定します。この特定により、プログラマーは注意が必要なコードの特定の部分にすばやく移動でき、問題を見つけるのに必要な時間を短縮できます。
エラーが検出された行の特定の列番号を示します。前の列ほど頻繁に参照されるわけではありませんが、複雑なステートメントで発生したエラーや、行に多数の要素(複数の関数呼び出しやパラメータなど)が含まれている場合にエラーを識別するのに特に役立ちます。

これらは通常、以下に示すように、左から右に配置されます。また、この説明でデバッグするプログラムの完全なエラーレポートも含まれています。このレポートには、20個のエラーと4個の警告が含まれています(スニペットの下部を参照)。これは、テーブルレイアウトのすぐ下にあります。レポートの特徴は簡単に識別できます。最後まで読んでいただければ、以下のコードスニペットに示されているエラーを解決する方法について説明します。

詳細 ファイル

'D1 PriceMarker.mq5'                    1
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      70      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      70      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      71      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      71      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      72      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      72      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      73      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      73      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      74      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      74      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      75      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      75      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      76      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      76      5
'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      77      5
   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      77      5
'ObjectCreate' - wrong parameters count D1 PriceMarker.mq5      15      9
   built-in: bool ObjectCreate(long,const string,ENUM_OBJECT,int,datetime,double,...)   D1 PriceMarker.mq5      15      9
'ObjectCreate' - wrong parameters count D1 PriceMarker.mq5      27      9
   built-in: bool ObjectCreate(long,const string,ENUM_OBJECT,int,datetime,double,...)   D1 PriceMarker.mq5      27      9
'ObjectSetText' - undeclared identifier D1 PriceMarker.mq5      37      5
',' - unexpected token  D1 PriceMarker.mq5      37      28
'labelName' - some operator expected    D1 PriceMarker.mq5      37      19
'+' - illegal operation use     D1 PriceMarker.mq5      37      36
',' - unexpected token  D1 PriceMarker.mq5      37      69
result of expression not used   D1 PriceMarker.mq5      37      43
',' - unexpected token  D1 PriceMarker.mq5      37      73
expression has no effect        D1 PriceMarker.mq5      37      71
',' - unexpected token  D1 PriceMarker.mq5      37      82
expression has no effect        D1 PriceMarker.mq5      37      76
')' - unexpected token  D1 PriceMarker.mq5      37      87
expression has no effect        D1 PriceMarker.mq5      37      84
'OBJPROP_Y' - undeclared identifier     D1 PriceMarker.mq5      41      36
'ObjectSetInteger' - no one of the overloads can be applied to the function call        D1 PriceMarker.mq5      41      5
could be one of 2 function(s)   D1 PriceMarker.mq5      41      5
   built-in: bool ObjectSetInteger(long,const string,ENUM_OBJECT_PROPERTY_INTEGER,long) D1 PriceMarker.mq5      41      5
   built-in: bool ObjectSetInteger(long,const string,ENUM_OBJECT_PROPERTY_INTEGER,int,long)     D1 PriceMarker.mq5      41      5
20 errors, 4 warnings           21      5

このトピックについて議論する際に理解すべき一般的な用語をいくつか紹介します。

  • 構文:MetaTrader 5プラットフォームがプログラム(取引アルゴリズム、指標、スクリプトなど)を正しく理解して実行できるようにするために、プログラムをどのように記述する必要があるかを規定する特定のルールセットを指します。
  • エラー:コードの間違いや問題により、コードが正しく実行されないことを指します。エラーは、構文エラー、ランタイムエラー、論理エラー、型エラー、コンパイルエラーなど、いくつかの種類に分類できます。


デバッグとは何か?

皆さんのほとんどはこの活気に満ちた用語をよくご存知だと思いますが、初心者にとってはその概念を詳細に把握することが不可欠です。ここで、デバッグのプロセスをよりよく理解できるように、バグを定義します。

  • バグ

コンピュータプログラムやシステムにおいて、予期せぬ動作や不正確な動作を引き起こすエラーや欠陥のことです。 

  • デバッグ

プログラムが意図したとおりに動作し、さまざまな条件下で正しい出力が得られるようにすることを目的として、コンピュータプログラムやシステムのエラーやバグを特定、分離、修正するプロセスです。

MQL5プログラミングの文脈におけるデバッグ

ここでは、MQL5に特有のデバッグの側面をいくつか紹介します。

 1. MQL5でよくあるバグの種類

  • 構文エラー:スクリプトのコンパイルを妨げるMQL5コード構造の間違い

この例では、Print()関数の閉じ括弧が欠落している単純な構文エラーを表示しています。その結果、スクリプトはコンパイルに失敗します。コード構造を慎重にチェックする必要があることがわかります。

void OnStart()
{
    Print("Hello, World!" // Missing closing parenthesis
}
  • 論理エラー:コードはコンパイルされて実行されるが、誤った取引シグナルが生成されたり、予期しない動作をしたりする問題

ここには、条件が誤って買い注文をトリガーする論理エラーがあります。プログラマーは、市場の状況に依存するより複雑なロジックを活用することを意図していましたが、現在の実装では不要な取引が発生します。

void OnTick()
{
    double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double targetPrice = currentPrice + 100; // Intended to use a different logic

    // Mistakenly placing a buy when conditions aren't right
    if (currentPrice < targetPrice) // Logic Error
    {
        OrderSend(_Symbol, OP_BUY, 0.1, currentPrice, 3, 0, 0, "Buy order", 0, 0, clrGreen);
    }
}
  • ランタイムエラー:範囲外の配列にアクセスしようとしたり、取引注文を適切に処理しなかったりするなど、実行中に発生するエラー
この例では、有効なインデックスが5つしかない配列の6番目の要素にアクセスしようとしています。これは実行時エラーとなり、配列を扱う際の境界チェックの重要性を示しています。
void OnStart()
{
    double prices[5];
    
    // Attempt to access out-of-range index (e.g., index 5)
    double value = prices[5]; // Runtime error: Array out of range
}

2.MQL5のデバッグツール

  • MetaEditor:MQL5の統合開発環境(IDE)で、構文の強調表示、コード補完、および構文エラーを迅速に特定するのに役立つエラー表示を提供します。
以下のコードでは、result変数の計算にブレークポイントを設定できます。MetaEditorでデバッグする場合、この時点で変数を検査し、期待通りに設定されていることを確認することで、プログラムの流れを分析するための行ごとの実行が容易になります。
void OnStart()
{
    double startValue = 10.0;

    // Set a breakpoint here to inspect value
    double result = startValue * 2;

    Print("Result: ", result); // Check the value of result
}
  • Print()文:Print()関数を使って、変数の値や実行フローのログをEAログに出力します。これは問題を追跡する簡単な方法です。
このコード例では、Print()関数を使って現在の買値と売値を記録しています。このアプローチは、実行中の変数値をトレースするのに有益であり、期待値と実際の値を比較することで論理エラーを診断するのに役立ちます。
void OnTick()
{
    double bidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    
    // Logging prices for debugging
    Print("Bid: ", bidPrice, ", Ask: ", askPrice);
}
  • コードのコメントアウト:問題のある領域を特定するために、コードの一部を一時的に無効にします。
この例では、代替ロジックに焦点を当てるため、コード1行をコメントアウトしています。このテクニックは、バグを切り分けたり、完全に除去せずにコードの異なる部分をテストしたりするのに便利です。
void OnTick()
{
    // double result = SomeFunction(); // Temporarily disabling this line
    
    // Run alternate logic while debugging
    Print("Running alternative logic.");
}
3. MetaEditorでデバッガを使う

MetaEditorには次の機能を備えた組み込みデバッガーが含まれています。
  • ブレークポイント:コードにブレークポイントを設定することで、特定の行で実行を一時停止し、変数の値を調べることができます。
  • ステップスルー:コードを1行ずつたどりながら、変数がどのように変化し、ロジックの流れがどのようになっているかを観察することができます。
  • ウォッチ:コードの実行中、特定の変数の値を監視します。
 4. テストと最適化
  • ストラテジーテスター:MQL5は、履歴データを使用して取引戦略のバックテストを実行できるストラテジーテスターを備えています。取引をシミュレートし、パフォーマンスを分析することで、隠れたバグを明らかにすることができます。
  • 最適化:取引アルゴリズムのパフォーマンスを向上させるためにパラメータを最適化することができ、ロジックや実行の潜在的なバグを浮き彫りにすることもできます。
 5. エラー処理
  • 取引操作に関連する関数の戻り値のチェックなど、MQL5固有のエラーコードを処理します。一般的な関数には、注文実行関数(OrderSendOrderCloseなど)があり、適切なエラー処理によって、クラッシュや望ましくない結果を防ぐことができます。

MQL5におけるデバッグのベストプラクティス

1. コードのモジュール性:関数に分割してモジュール化されたコードを記述します。これにより、個々のコンポーネントのテストとデバッグが容易になります。2. コードの文書化:コードにコメントを付けて各部分の動作を説明します。これは、時間が経過してからコードを再確認するときに非常に役立ちます。3. 定期的なテスト:全体の作業が完了するまで待たず、開発中に頻繁にコードをテストします。これにより、バグを早期に発見し、修正することができます。


MQL5におけるデバッグの実装

少し前に、友人と私は前日足(D1)ローソク足のラベル付き価格ラインを描画し、高値、安値、始値、終値などの重要な価格レベルをマークするスクリプトの下書きを作成しました。このバージョンは、この記事のために保存しておいたものです。 

通常、エキスパートアドバイザー(EA)を作成する際には、MetaEditorが正しい言語構文に基づいて詳細を入力していれば、テンプレートやパラメータの提案を提供してくれるため、開発者を支援しエラーの可能性を減らしてくれます。しかし、一方でフォーラムなどから得たコードにはエラーが点在している場合があります。以下に、バグのあるスクリプトプログラムのコードスニペットを示します。

//+------------------------------------------------------------------+
//|                                               D1 PriceMarker.mq5 |
//|                                Copyright 2024, Clemence Benjamin |
//|             https://www.mql5.com/ja/users/billionaire2024/seller |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Clemence Benjamin"
#property link      "https://www.mql5.com/ja/users/billionaire2024/seller"
#property version   "1.00"
#property strict

// Function to create a price line with a label
void CreatePriceLine(string name, double price, color clr, string label)
{
    // Create a horizontal line
    if(!ObjectCreate(name, OBJ_HLINE, 0, 0, price))
    {
        Print("Failed to create line: ", GetLastError());
        return;
    }
    
    // Set line properties
    ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
    ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);

    // Create a label for the price
    string labelName = name + "_label";
    if(!ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0))
    {
        Print("Failed to create label: ", GetLastError());
        return;
    }

    // Set label properties
    ObjectSetInteger(0, labelName, OBJPROP_XSIZE, 70);
    ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 10);
    ObjectSetInteger(0, labelName, OBJPROP_COLOR, clr);
    ObjectSetText(labelName, label + ": " + DoubleToString(price, 2), 10, "Arial", clr);

    // Position the label
    double yPos = price; // Positioning along the price axis
    ObjectSetInteger(0, labelName, OBJPROP_Y, yPos);
    ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 5);
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
{
    // Get the previous D1 candle's open, high, low, and close prices
    datetime prevCandleTime = iTime(NULL, PERIOD_D1, 1);
    double openPrice = iOpen(NULL, PERIOD_D1, 1);
    double highPrice = iHigh(NULL, PERIOD_D1, 1);
    double lowPrice = iLow(NULL, PERIOD_D1, 1);
    double closePrice = iClose(NULL, PERIOD_D1, 1);

    // Draw labeled price lines for open, high, low, and close prices
    CreatePriceLine("PrevCandle_Open", openPrice, clrBlue, "Open");
    CreatePriceLine("PrevCandle_High", highPrice, clrRed, "High");
    CreatePriceLine("PrevCandle_Low", lowPrice, clrGreen, "Low");
    CreatePriceLine("PrevCandle_Close", closePrice, clrOrange, "Close");
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Remove the drawn price lines and labels upon indicator deinitialization
    ObjectDelete("PrevCandle_Open");
    ObjectDelete("PrevCandle_High");
    ObjectDelete("PrevCandle_Low");
    ObjectDelete("PrevCandle_Close");
    ObjectDelete("PrevCandle_Open_label");
    ObjectDelete("PrevCandle_High_label");
    ObjectDelete("PrevCandle_Low_label");
    ObjectDelete("PrevCandle_Close_label");
}

//+------------------------------------------------------------------+                                                                                                            

(i)バグの検出

バグのあるプログラムをコンパイルしようとする場合、MetaEditorの内蔵デバッガはかなり使い勝手がいいことがわかりました。ほとんどのバグは、MetaEditorの[コンパイル]または[リアルタイムプロファイリング]ボタンをクリックしたときに検出されます。ただし、プログラムのコンパイルを妨げないパフォーマンスエラーもあります。これらは、プログラムを実行しようとしたときにプラットフォームまたはテスターでのみ識別できます。

開発者は、プログラム全体をゼロから書いてからデバッグすることも、既存のプログラムを単にデバッグすることもできます。下の画像では、MetaEditorに内蔵されているコンパイラとデバッガを利用して、エラーのサマリーを取得しています(画像のツールボックスウィンドウの下部を参照)。エラー行をダブルクリックすると、カーソルが該当するエラー行に移動し、ハイライト表示されます。[コンパイル]ボタンを押すまで、コード内のエラーに気付くことはほとんどありませんでした。その時点で、デバッガーは発生した問題を報告します。

エラーの特定

MetaEditorでのエラーの特定

プログラムのコンパイルは成功するが、期待した結果が得られないこともあります。このような場合、MetaTrader 5プラットフォームのツールボックスウィンドウで利用可能なエキスパートログと操作ログ出力を確認して、潜在的なエラーを特定するのが賢明です。これらのログは、実行中に何が問題になっているかについての貴重な洞察を提供し、トラブルシューティングや問題の効率的な解決に役立ちます。

(ii)3つのデバッグ技術

エラーはしばしばタイプミスや用語の誤用から生じることがあり、デバッガーは通常、説明や解決に向けた部分的なヒントを提供します。これらのメッセージを理解することができれば、コードを再検討し、必要な修正を加えることはたいていの場合簡単です。しかし、診断が難しい複雑な状況で、参考書やコミュニティの専門家によるより深い知識が必要な場合もあります。

私の経験では、複雑な問題をデバッグするときには、いくつかの戦略を使うのが一般的です。これらの手順を3つの主要なアプローチに分類していますが、このリストは網羅的なものではなく、この議論の目的に特化したものです。それぞれの手順を詳しく説明します。

1. ドキュメンテーションの再検討

構文や関数の使用方法を明確にし、エラーメッセージを適切に解釈することで、MQL5プログラムのデバッグは大幅に効率化されます。詳細な説明や具体的な例を参照することで、誤った実装を特定し、組み込み関数への理解を深める助けとなります。さらに、ドキュメントには一般的なエラー、ベストプラクティス、代替ソリューションに関する情報が含まれている場合が多く、これにより開発者は問題を効果的にトラブルシューティングし、コードを最適化してパフォーマンスを向上させることができます。このプロジェクトでは、下の画像を見て、ドキュメントに簡単にアクセスする方法をご覧ください。

ドキュメンテーションの再検討

ドキュメントの再検討

エラー報告

'ObjectDelete' - wrong parameters count D1 PriceMarker.mq5      70      5

解決のヒント

   built-in: bool ObjectDelete(long,const string)       D1 PriceMarker.mq5      70      5

現在の状況

   ObjectDelete("PrevCandle_Open");

解決のヒントから、ObjectDelete関数は2つのパラメータを要求していることがわかります。この食い違いが問題の所在を示し、それに応じて対処することができます。ドキュメントによると、MQL5のObjectDelete関数は2つのパラメータを必要とします。

  1. name:削除するオブジェクトの名前を文字列で指定します。
  2. Chart_id:オブジェクトを削除すべきチャートのIDを整数で指定します。省略された場合、関数は現在のチャートをデフォルトとします。

この問題を解決するには、ObjectDeleteを呼び出すときに両方のパラメータを確実に渡す必要があります。そうすることで、関数の呼び出しを期待される構文に合わせ、エラーをなくすことができます。

    解決:

    ObjectDelete(0, "PrevCandle_Open");

    次に、メインコードを見てみると、ObjectDelete関数のインスタンスがいくつかあることに気づきます。調査から集めた情報を使えば、そのすべてに必要な調整を施すことができます。各インスタンスに必要な両方のパラメータを確実に提供することで、これらのエラーを効果的に解決することができます。

    以下の画像で、エラーの総数をいかにして10も減らすことに成功したかをご覧ください。これは、私たちのスクリプトのデバッグに大きな進展があったことを示しており、適切なドキュメントに基づく徹底的な調査と修正の重要性を示しています。

    ObjectDelete関数の解決

    ObjectDelete関数のエラー解決

    完成です。エラーが発生したら、解決策を試行するたびに[コンパイル]ボタンを押すのがよい習慣です。これにより、エラーがまだ続いているかどうかを確認し、残っている問題を特定することができます。

    さて、次のエラーに移りましょう。

    エラー報告

    'ObjectSetText' - undeclared identifier D1 PriceMarker.mq5      29      5
    'ObjectSetText' - undeclared identifier D1 PriceMarker.mq5      29      5
    ',' - unexpected token  D1 PriceMarker.mq5      29      28
    'labelName' - some operator expected    D1 PriceMarker.mq5      29      19
    '+' - illegal operation use     D1 PriceMarker.mq5      29      36
    ',' - unexpected token  D1 PriceMarker.mq5      29      69
    result of expression not used   D1 PriceMarker.mq5      29      43
    ',' - unexpected token  D1 PriceMarker.mq5      29      73
    expression has no effect        D1 PriceMarker.mq5      29      71
    ',' - unexpected token  D1 PriceMarker.mq5      29      82
    expression has no effect        D1 PriceMarker.mq5      29      76
    ')' - unexpected token  D1 PriceMarker.mq5      29      87
    expression has no effect        D1 PriceMarker.mq5      29      84

    今回、複数のレポートを集めたのは、確認すると同じ行でエラーが発生しているからです。これは多くの場合、コードの特定の部分で対処すべき共通の問題を示しています。根本的な問題を特定し、必要な修正を判断するために、問題のラインを詳しく見てみよう。

    解決のヒント

    このシナリオでは、宣言されていない識別子、期待される演算子、式が有効でない、予期しないトークンのようなエラーが発生します。

    現在の状況

    ObjectSetText(labelName, label + ": " + DoubleToString(price, 2), 10, "Arial", clr);
                
    

    ドキュメントを確認しましたが、ObjectSetTextへの言及は見つかりませんでした。しかし、ObjectSet...と入力し始めると、いくつかの候補が表示され、ObjectSetStringが最良の選択肢でした。この関数は正しいものであることが判明し、期待通りに機能しました。

    私たちの取り組みは下記に反映されています。

    ObjectSetTextがドキュメントにない

    ObjectSetTextがドキュメントにない


    ObjectSetString

    ObjectSetString

    ドキュメントに従うObjectSetString関数のパラメータは以下の通りです。

    bool  ObjectSetString(
       long                            chart_id,          // chart identifier
       string                          name,              // object name
       ENUM_OBJECT_PROPERTY_STRING     prop_id,           // property
       int                             prop_modifier,     // modifier
       string                          prop_value         // value
       );

    解決

    最初のエラーに対してと同じように、必要な調整をおこなうことで、ほぼすべての問題を解決することができました。あとは数行を修正するのみです。残されたエラーを完全に解消するために、最終調整に集中しましょう。

     ObjectSetString(0, labelName, OBJPROP_TEXT, label + ": " + DoubleToString(price, 2));

    バグがいくつか残っています。

    残り2つのエラー

    残り2つのエラー

    最後に、残りのエラーを修正します。

    ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, price); // Position label at the price level

    OBJPROP_Yではなく、OBJPROP_YDISTANCEのはずでした。

    エラーが解消され、プログラムがコンパイル可能になる

    ドキュメントを参考にデバッグを成功させる

    最終的にクリーンアップされたコードは次のとおりです。

    //+------------------------------------------------------------------+
    //|                                               D1 PriceMarker.mq5 |
    //|                                Copyright 2024, Clemence Benjamin |
    //|             https://www.mql5.com/ja/users/billionaire2024/seller |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, Clemence Benjamin"
    #property link      "https://www.mql5.com/ja/users/billionaire2024/seller"
    #property version   "1.00"
    #property strict
    
    
    // Function to create a price line with a label
    void CreatePriceLine(string name, double price, color clr, string label)
    {
        // Create a horizontal line
        if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
        {
            Print("Failed to create line: ", GetLastError());
            return;
        }
        
        // Set line properties
        ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
        ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
    
        // Create a label for the price
        string labelName = name + "_label";
        if(!ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0))
        {
            Print("Failed to create label: ", GetLastError());
            return;
        }
    
        // Set label properties
        ObjectSetInteger(0, labelName, OBJPROP_XSIZE, 70);
        ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 10);
        ObjectSetInteger(0, labelName, OBJPROP_COLOR, clr);
        ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, price); // Position label at the price level
        ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 5);
        
        // Set the text of the label
        ObjectSetString(0, labelName, OBJPROP_TEXT, label + ": " + DoubleToString(price, 2));
    }
    
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    void OnInit()
    {
        // Get the previous D1 candle's open, high, low, and close prices
        datetime prevCandleTime = iTime(NULL, PERIOD_D1, 1);
        double openPrice = iOpen(NULL, PERIOD_D1, 1);
        double highPrice = iHigh(NULL, PERIOD_D1, 1);
        double lowPrice = iLow(NULL, PERIOD_D1, 1);
        double closePrice = iClose(NULL, PERIOD_D1, 1);
    
        // Draw labeled price lines for open, high, low, and close prices
        CreatePriceLine("PrevCandle_Open", openPrice, clrBlue, "Open");
        CreatePriceLine("PrevCandle_High", highPrice, clrRed, "High");
        CreatePriceLine("PrevCandle_Low", lowPrice, clrGreen, "Low");
        CreatePriceLine("PrevCandle_Close", closePrice, clrOrange, "Close");
    }
    
    //+------------------------------------------------------------------+
    //| Custom indicator deinitialization function                       |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
        // Remove the drawn price lines and labels upon indicator deinitialization
        ObjectDelete(0, "PrevCandle_Open");
        ObjectDelete(0, "PrevCandle_High");
        ObjectDelete(0, "PrevCandle_Low");
        ObjectDelete(0, "PrevCandle_Close");
        ObjectDelete(0, "PrevCandle_Open_label");
        ObjectDelete(0, "PrevCandle_High_label");
        ObjectDelete(0, "PrevCandle_Low_label");
        ObjectDelete(0, "PrevCandle_Close_label");
    }
    
    //+------------------------------------------------------------------+

    D1 PriceMarkerは、前日足(D1)の高値、安値、始値、終値に対応する水平線を描画することで、取引チャートにおけるテクニカル分析を支援するよう設計されたMQL5スクリプトです。このスクリプトは初期化時にこれら4つの価格ポイントを取得し、ヘルパー関数を使用して、各価格に対応する水平線を描画します。それぞれの線は異なる色で示されます(始値は青、高値は赤、安値は緑、終値はオレンジ)。さらに、各価格線には、その価格を示すラベル付きのテキストが付属しています。スクリプトがチャートから削除される際には、描画された線とラベルがすべて自動的に削除され、トレーダーの作業スペースが整理されます。

    2.AIによるデバッグ

    誰もがAIモデルをどのように活用できるかに興味を持っていることは理解しています。このトピックについては簡単に触れたうえで、後ほど詳細に議論する予定です。幸いにも、これらのAIモデルの多くは、構文を人間よりも迅速かつ正確に理解する能力を持っています。ただし、予期しない結果が生じる場合もあるため、特に複雑なケースでは、人間による慎重な監視が必要となることを忘れてはなりません。AIは適切に利用すれば非常に優れたツールとなります。私自身、多くのコーディング課題をAIの提案を活用して解決してきました。

    基本的に、AIプロンプトを作成する際は、まずデバッグ対象のプログラムを提供することから始めます。その後、MetaEditorのレポートからエラー行をコピーし、それらをプロンプトに貼り付けることで、AIがデバッグプロセスを支援できるようにします。この方法は多くの場合成功につながりますが、場合によってはさらに複雑な問題を引き起こすこともあります。そのため、AIの提案に盲目的に従うのではなく、批判的に考え、必要に応じてさらに一歩踏み込むことが重要です。適切に使用すれば、AIは他のデバッグツールとともに効果的に活用でき、その結果はこれらのツールが生成するはずの結果と一致することが期待されます。

    エラーをコピー

    AIプロンプトにエラーをコピーする

    3. フォーラム訪問

    上記と同様に、フォーラムのメンバーもデバッグに関する貴重な洞察を提供するためには情報が必要です。コーディングの課題について議論に参加することは、他の専門家から学び、知見を深めるための素晴らしい方法です。プログラムを提出することで、他のメンバーから賢明な提案や具体的な解決策を得る機会が得られます。このような共同アプローチは、単に問題を解決するだけでなく、フォーラムに参加するすべての人々の知識とスキルを向上させるのに役立ちます。

    MetaTrader 5上のプログラム

    D1 PriceMarker

    D1 PriceMarkerスクリプト 


    結論

    MQL5プログラミングにおけるチームワークは、D1 PriceMarkerスクリプトの作成過程を通じて示されているように、堅牢な取引アルゴリズムの開発を強化する上で不可欠な実践であることが明らかになりました。デバッグプロセスはエラーレポートと包括的なMQL5リファレンスドキュメントに大きく依存しており、開発中に直面した問題を体系的に特定し、効果的に対処することを可能にしました。

    このアプローチにより、特定のエラーを迅速かつ正確に解決できるだけでなく、プログラミング環境全体に対する理解を深めることができました。また、将来的にデバッグを支援するために人工知能(AI)を活用する可能性についても触れました。AIが提供する洞察や推奨事項は、デバッグプロセスを効率化し、開発者にとって有益なサポートとなるでしょう。

    さらに、コミュニティの支援、特にMQL5フォーラムを通じたサポートの重要性も強調されます。他の経験豊富な開発者からのアドバイスを受けたり、知識を共有したりすることで、開発の質をさらに向上させることができます。このような共同作業とリソース主導のアプローチを採用することで、デバッグ作業の有効性を飛躍的に高め、最終的にはアルゴリズム取引の競争の激しい環境で信頼性が高く革新的な取引ソリューションの開発につながるのです。皆さん、取引をお楽しみください。

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

    添付されたファイル |
    D1_PriceMarker.mq5 (3.31 KB)
    ニューラルネットワークが簡単に(第93回):周波数領域と時間領域における適応予測(最終回) ニューラルネットワークが簡単に(第93回):周波数領域と時間領域における適応予測(最終回)
    本稿では、時系列予測において2つのブロック(周波数と時間)の結果を適応的に組み合わせるATFNetモデルのアプローチの実装を継続します。
    チャート上で取引を視覚化する(第2回):データのグラフ表示 チャート上で取引を視覚化する(第2回):データのグラフ表示
    ここでは、取引エントリを分析するために取引の印刷画面のアンロードを簡素化するスクリプトをゼロから開発します。単一の取引に関するすべての必要な情報は、異なる時間枠を描画する機能を備えた1つのチャートに便利に表示されます。
    Candlestick Trend Constraintモデルの構築(第9回):マルチ戦略エキスパートアドバイザー(I) Candlestick Trend Constraintモデルの構築(第9回):マルチ戦略エキスパートアドバイザー(I)
    今日は、MQL5を使って複数の戦略をエキスパートアドバイザー(EA)に組み込む可能性を探ります。EAは、指標やスクリプトよりも幅広い機能を提供し、変化する市場環境に適応できる、より洗練された取引アプローチを可能にします。詳しくは、この記事のディスカッションをご覧ください。
    リプレイシステムの開発(第53回):物事は複雑になる(V) リプレイシステムの開発(第53回):物事は複雑になる(V)
    今回は、あまり理解されていない重要なトピックを取り上げます。「カスタムイベント」です。これは危険です。これらの要素の長所と短所を解説します。このトピックは、MQL5やその他の言語でプロのプログラマーになりたい人にとって重要な鍵となります。ここではMQL5とMetaTrader 5に焦点を当てます。