
MQL5で取引管理者パネルを作成する(第6回):取引管理パネル(II)
内容
はじめに
セキュリティテストに合格し、主要な機能にアクセスできる管理ホームパネル(Admin Home Panel)を操作できるようになったことを踏まえ、現在積極的に開発が進められているプロジェクトにおいて、多機能インターフェースのパフォーマンスを強化しつつ、MQL5 の実装を継続的に推進することが私たちの目標です。前回の記事では、パネルのさまざまな機能を紹介しましたが、取引管理パネル(Trade Management Panel)内の各ボタンの詳細な機能説明はおこないませんでした。今回は、取引管理パネルのすべてのボタンがクリック時に適切な応答を返すように改善を図ります。
さらに、「現在のパネルレイアウトに制限があるのか?」という疑問についても考察します。この課題を検討するにあたり、著名な取引アルゴリズム開発言語であるMQL5のダイアログクラスの機能を最大限に活用するための代替レイアウトのアイデアを探ります。以下の画像では、チャートの垂直スケールを調整する機能を示しています。この機能を活用することで、パネルの配置に利用できるスペースを最大化できます。また、チャートの視認性を保ちつつ、両方のパネルを同時に表示できるようにすることも有益だと考えています。この機能を実現するために、すべてのパネルを一度に表示できるボタンを管理ホームパネルに追加する予定です。
MetaTrader5チャートの垂直スケールによりスペースが作成され、ローソク足の範囲がより明確に表示される
先に進む前に、多機能インターフェイスのさまざまな要素をもう一度確認しましょう。これは、本連載を読み進める中で直面する暗黙の課題のいくつかに対処するのに役立ちます。- コンパイルエラーが発生している場合、原因は拡張されていないデフォルトのライブラリファイルを使用してコードを実行していることである可能性があります。この問題を解決するには、MQL5/Include/controlsディレクトリの内容を、前の記事で提供した拡張ヘッダーフォルダーのファイルで上書きしてください。
- もう1つの課題は、チャットIDとボットトークンを自分のものに正しく更新し、確認コードが自分のアカウントに送信されるようにすることです。
この2番目の課題を解決するために、Telegramアプリを利用して2つのボットを作成します。1つ目のボットは、アプリケーションの起動時に認証専用として使用します。2つ目のボットは、EAプログラムのコミュニケーションパネル内で、個別チャット、グループ、チャネルを介したコミュニケーション専用として使用します。
以下に、実際のチャットIDとボットトークンを入力してください。チャットIDがグループやチャネルのものではないことを確認してください。グループやチャネルのIDを使用すると、コードが複数のユーザーと共有されてしまうため、チャットIDは厳重に個人的なものにする必要があります。正しいチャットIDを持っていることを確認するには、ボットとの個別チャットを開始し、APIを使用してチャットIDを取得してください。これらの値はソースコードにハードコードされます。アプリケーションの起動時に入力するチャットIDやボットトークンとは異なることに注意してください。
これについては以前も説明しましたが、手順は簡単に実行できます。
手順1
まず、Telegramに登録されていることを確認してください。登録がまだの場合は、携帯電話またはデスクトップ用のTelegramアプリをダウンロードし、アプリの指示に従って新規登録を完了させてください。
手順2
BotFatherとのチャットを開始して、2つのボットを作成します。1つは2要素認証(2FA)用、もう1つはコミュニケーション用です。各ボットには固有のボットトークンが付与されます。 このトークンを使用すると、Telegram APIにアクセスし、チャットIDを取得できます。また、各ボットには自由に名前を付けることができるため、用途を区別しやすい名前にすると便利です。
手順3
次のリンクをクリックして、APIにアクセスします:https://api.telegram.org/botReplaceMeWithTheTokenFromTheBotFather/getUpdates。
Telegram API(Chromeブラウザを使用してアクセス)
手順4
2FAコードを受信するための専用ボットとのチャットを開始します。また、取引に関する分析や洞察を共有する予定のグループやチャンネルに、コミュニケーションボットを追加し、管理者権限を付与してください。これにより、ボットが適切に機能するようになります。セットアップが完了したら、グループ内でメッセージを送信し、チャットIDを取得します。その後、APIタブでブラウザを更新し、最新の情報が反映されていることを確認してください。
Telegramチャット:ボットとの会話を開始する(この場合、ボットにAdminPanelという名前を付けた)
Telegram API:ここで2FA用のチャットIDを取得できる
上の画像では、主に2FA配信用のチャットIDを取得するために個人チャットを開始しました。また、同じボットをグループやチャンネルに追加することも可能です。その後、そのグループやチャンネルで会話を開始すると、チャットIDがAPIに自動的に登録され、通常は最初の会話の下に表示されます(上記の画像のように)。たとえば、私はこのボットを教育チャンネルの1つに追加しました。その際に受信したAPIメッセージは、以下の画像に示されています。
要約すると、同じボットを複数のチャネルで使用でき、各チャネルには固有のチャットIDが付与されます。あるいは、必要に応じて、チャネルごとに異なるボットを使用することもできます。
Telegramチャンネルにボットを管理者として追加する
最後に、チャネルチャットIDを含むAPI JSONを以下に示します。
チャンネルチャット生成JASON
このコードスニペットには、2FAコード配信用のボット資格情報を入力する必要があります。// Constants for 2FA. Here put the chat ID dedicated for verification code delivery. It must be kept secure always. const string Hardcoded2FAChatId = "REPLACE WITH YOUR CHAT ID"; const string Hardcoded2FABotToken = "REPLACE WITH YOU BOT TOKEN"; //Obtain your bot token from a telegram bot father. //If you don't already have a bot you can start the chat with the bot father to create one.
以下は、アプリの初期化中に取引コミュニケーション用のTelegram資格情報を入力する場所を示す画像です。必要に応じてクイックメッセージをカスタマイズすることもできます。
初期化入力設定の説明
前述のとおり、上記のコードスニペットと画像には2つの異なるチャットIDが表示されていることに注意してください。1つは確認コードの配信に使用され、もう1つは個人チャットまたはTelegramグループを通じて管理コミュニケーションをブロードキャストするために使用されます。ボットに接続されている各ユーザー、グループ、チャネルには、一意のチャットIDがあります。
最後に、これまでの説明では同じPIN2024を使用してきましたが、ソースコード内で独自にカスタマイズして使用することもできます。2FAの場合、6桁のコード生成アルゴリズムによって自動的に処理されます。コードを安全に配信するには、一意のチャットIDを持っていることを確認するだけで済みます。
この簡単な要約で、今日の進捗に向けて準備が整うことを願っています。要約すると、取引管理ボタンのハンドラに焦点を当て、チャート上の位置と寸法に関するレイアウトを強化します。
取引管理パネルの強化
まず、コミュニケーションパネルのボタンと取引管理パネルの違いを理解していただきたいと思います。ほとんどの読者は、MetaTrader 5のデスクトップ版とモバイル版の両方で利用できる一括操作機能に精通していると思います。
パネル名が示すように、その機能は一目瞭然ですが、タイトルや説明が似ているため混乱する可能性があります。たとえば、コミュニケーションパネルのボタンはコミュニケーション専用ですが、取引管理パネルのボタンは取引の処理用に特別にプログラムされています。
コミュニケーションパネルで使用される同じボタンに取引ハンドラを実装して、クリックすると両方のタスクを同時に実行できるようにすることができます。ただし、コミュニケーションボタンを取引管理ボタンと区別しておく理由はいくつかあります。主な理由の1つは、管理者が必ずしもブロードキャストを目的としない取引を管理したい場合があることです。
最も重要な違いを強調した以下の画像をご覧ください。
コミュニケーションパネル:メッセージボタン
ナビゲーションボタンを除き、ここにあるほぼすべてのボタンはコミュニケーション用に設計されています。さらに、送信されるクイックメッセージは初期化時にカスタマイズできます。[Close All]クイックメッセージボタンは、指定されたTelegramクライアントにメッセージを送信するためだけに設計されており、他のアクションは実行しません。
取引管理パネル(これらのボタンはクリックすると取引操作を実行する必要がある)
上記の画像から、各機能の目的が明らかになりました。さて、取引管理パネルに目を向けると、やるべき作業がかなり残っています。現在、パネルのボタンは限られていますが、チャート表示のスペースを最大限に活用できるように拡張することを目指しています。新しいボタンは、[Close All Orders]などの重要な取引操作に不可欠です。
取引管理レイアウトの調整
新しいインターフェイスレイアウトは、この開発シリーズ内での通常の管理操作を可能にしながら、チャートの可視性を高めるためのスペースを増やすことを目的とした革新的なデザインです。このアプローチでは、MetaTrader 5チャートに対するパネルの位置座標を活用します。
現在、管理ホームパネルはコンテンツに対して大きすぎるため、これも調整する予定です。プロセスをよりわかりやすくするために、3つのセクションに分割します。
取引管理パネルの調整
初期化中に、次のコードを使用してパネルが作成されます。
if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 30, 30, 500, 500))
{
Print("Failed to create Communictions panel dialog");
return INIT_FAILED;
}
上記のコードでは、
x1 =30
x2 =500
したがって、幅=X2-X1=500-30=470となります。
X2値を増やすと、設計概念に従って新しい幅が拡大します。たとえば、私は元の幅を50%増やすので、以下のコードスニペットを参照してください。
// Let's increase our panel width by 50% of the former panel and is likely to be 250px but we will add an extra 30px to cover for the initial px on x1 co-ordinate.
// For the y co-ordinate we will reduce so much to 150px
if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 30, 30, 780, 150))
{
Print("Failed to create Communictions panel dialog");
return INIT_FAILED;
}
コンパイルとテスト後の結果は次のとおりです。
新しい取引パネルレイアウト
最近の変更により、一部のボタンが希望どおりの順序で配置されなくなり、パネルの境界内に留まらずにチャート上に浮かぶようになりました。この問題を解決するには、CreateTradeManagementControls()関数に移動し、以下のコードスニペットに示すようにボタンの座標を調整します。
// Create the Trade Management Panel controls
// Here we adjusted our button coordinates to fit well in the new Trade Management Panel
bool CreateTradeManagementControls()
{
long chart_id = ChartID();
// Buy Button
if (!buyButton.Create(chart_id, "BuyButton", 0, 130, 5, 210, 40))
{
Print("Failed to create Buy button");
return false;
}
buyButton.Text("Buy");
tradeManagementPanel.Add(buyButton);
// Sell Button
if (!sellButton.Create(chart_id, "SellButton", 0, 220, 5, 320, 40))
{
Print("Failed to create Sell button");
return false;
}
sellButton.Text("Sell");
tradeManagementPanel.Add(sellButton);
// Close Position Button
if (!closePosButton.Create(chart_id, "ClosePosButton", 0, 130, 50, 260, 70))
{
Print("Failed to create Close Position button");
return false;
}
closePosButton.Text("Close Position");
tradeManagementPanel.Add(closePosButton);
// Modify Position Button
if (!modifyPosButton.Create(chart_id, "ModifyPosButton", 0, 270, 50, 410, 70))
{
Print("Failed to create Modify Position button");
return false;
}
modifyPosButton.Text("Modify Position");
tradeManagementPanel.Add(modifyPosButton);
// Set Stop-Loss Button
if (!setSLButton.Create(chart_id, "SetSLButton", 0, 330, 5, 430, 40))
{
Print("Failed to create Set Stop-Loss button");
return false;
}
setSLButton.Text("Set SL");
tradeManagementPanel.Add(setSLButton);
// Set Take-Profit Button
if (!setTPButton.Create(chart_id, "SetTPButton", 0, 440, 5, 540, 40))
{
Print("Failed to create Set Take-Profit button");
return false;
}
setTPButton.Text("Set TP");
tradeManagementPanel.Add(setTPButton);
return true;
}
コードをコンパイルして実行すると、すべてのボタンが適切に配置された次の画像が生成されます。
取引管理パネル:適切なボタン配置
レイアウトの変更とボタンの配置が完了したので、既存のボタンの編集と新しいボタンの追加に移りましょう。
もう1つの重要な考慮事項は、内部ボタンとの競合を避けることです。たとえば、ネイティブボタンが管理パネルとどのように重なるかを示した以下の画像をご覧ください。
管理パネルに重なるクイックボタン
この問題に対処するには、x座標にシフトを適用し、右に移動してパネルの位置を変換します。以下のコードスニペットの更新された値を確認してください。
//1
//2
//2
if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 260, 30, 1040, 150))
{
Print("Failed to create Communictions panel dialog");
return INIT_FAILED;
}
コンパイルは成功し、問題は解決されました。以下のレイアウトをご覧ください。
クイックボタンは適切に配置されており、重なっていない
ヘルパー関数と新しいボタンの作成
C++の授業中、講師はrepeat関数の重要性を頻繁に強調していました。それは、プログラマーを目指す人にとっては基本的な概念であると考えられていたからです。その後、MQL5のヘルパー関数を調べているときに、最初はC++のrepeat関数に似たものに偶然出会ったと思いました。しかし、これらの関数には共通の利点があるものの、それぞれ異なる目的を果たすことにすぐに気付きました。
要約すると、MQL5ヘルパー関数は動作をパラメータ化する「関数オブジェクト」に似ていますが、C++繰り返しユーティリティは一貫した変換またはパターンを適用することに重点が置かれています。
両者の類似点は次のとおりです。
- どちらも繰り返しコードを減らすことを目的としている
- どちらもコードの明瞭性と保守性を向上させる
このディスカッションでは、作業をスマートかつ見栄えよくするために複数のボタンを実装する準備として、ヘルパー関数の概念を紹介しました。実装の詳細については、引き続きご注目ください。
複数の取引を管理するときに特に気に入っている機能の1つは、プロセスを合理化して、一度に多数の取引を効率的に処理できることです。
一括操作:MetaTrader5で多くの取引を管理するために使用
ワンクリックで実行できる取引操作を優先します。今後は、ストップレベルの調整や管理パネルからの直接設定など、取引変更機能に重点を移していきます。上の画像から、プロジェクトで使用するボタン名のヒントを得ることもできます。
以下にボタンの概要を示します。
- Close all Positions(すべてのポジションをクローズ)
- Close Profitable Positions(勝ちポジションをクローズ)
- Close Losing Positions(負けポジションをクローズ)
- Close Buy Positions(買いポジションをクローズ)
- Close Sell Positions(売りポジションをクローズ)
- Delete All Orders(すべての注文を削除)
- Delete Limit Orders(指値注文を削除)
- Delete Stop Orders(逆指値注文を削除)
- Delete Stop Limit Orders(ストップリミット注文を削除)
これまでのディスカッションで、ボタンについてはすでによくご存知だと思います。個々のボタンを作成する手順は、座標のみが異なり、ほぼ同じです。繰り返しのタスクを最小限に抑えるために、プロセスを効率化するためにカスタム構築されたヘルパー関数を活用します。このアプローチにより、コードのサイズが縮小され、すべての新しいボタンが効率的に組み込まれます。
まず、ボタンをグローバル変数として宣言します。
// Button Declarations CButton buyButton; // Button for Buy operations CButton sellButton; // Button for Sell operations CButton closeAllButton; // Button for closing all positions CButton closeProfitButton; // Button for closing profitable positions CButton closeLossButton; // Button for closing losing positions CButton closeBuyButton; // Button for closing Buy positions CButton closeSellButton; // Button for closing Sell positions CButton deleteAllOrdersButton; // Button for deleting all orders CButton deleteLimitOrdersButton; // Button for deleting limit orders CButton deleteStopOrdersButton; // Button for deleting stop orders CButton deleteStopLimitOrdersButton; // Button for deleting stop limit orders
宣言が完了したら、実装したボタンを作成するためのヘルパー関数を展開します。ヘルパー関数CreateButtonは、取引管理パネルでボタンを作成および構成する反復タスクを簡素化するように設計された合理化されたユーティリティです。
この関数は、エラー処理を含む基礎となる作成およびセットアップロジックを処理しながら、ボタンの参照、名前、ラベルテキスト、および座標のパラメータを受け取ります。このプロセスを一元化することで、冗長なコードが排除され、最小限の労力ですべてのボタンが一貫して作成されるようになります。
このモジュール性は、コードの可読性と保守性を向上させ、追加のボタンを使用してパネルを拡張したり、複数のインスタンスではなく1つの中央の場所で機能を調整したりすることが容易になるため、非常に重要です。基本的に、ヘルパー関数はパネル設計とボタン作成プロセスの間の橋渡しとして機能し、シームレスな統合を保証します。
ヘルパー関数のコードは次のとおりです。
//Helper Function For seamless Button creation bool CreateButton(CButton &button, const string name, const string text, int x1, int y1, int x2, int y2) { long chart_id = ChartID(); if (!button.Create(chart_id, name, 0, x1, y1, x2, y2)) { Print("Failed to create button: ", name); return false; } button.Text(text); tradeManagementPanel.Add(button); return true; }
上記のコードスニペットは、ボタン作成プロセス全体をカプセル化します。 CreateTradeManagementControls関数はマスターオーガナイザーとして機能し、CreateButtonを繰り返し呼び出して、取引管理パネル内で各ボタンを論理的に定義および配置します。この関数は、コントロールごとにボタン作成ロジックを複製するのではなく、座標、ラベル、ボタンタイプなどの固有の詳細を指定することにのみ重点を置いています。
CreateButtonによって実現されるモジュール設計により、この高レベルの機能は簡潔になり、パネルのレイアウトを構築するという主な目的に重点が置かれます。これら2つの関数は連携して動作し、CreateTradeManagementControlsが構造を処理し、反復的なタスクをCreateButtonに委任することで、取引管理パネルのクリーンかつ効率的で適応性の高い実装を実現します。すべてのボタンのコードはこちらです。
//+------------------------------------------------------------------+ //| Create Trade Management Controls | //+------------------------------------------------------------------+ bool CreateTradeManagementControls() { // Coordinates for buttons (adjust as needed) const int Y1_TOP = 5, Y2_TOP = 40; const int Y1_MID = 50, Y2_MID = 70; const int Y1_BOTTOM = 80, Y2_BOTTOM = 100; // Buy Button if (!CreateButton(buyButton, "BuyButton", "Buy", 130, Y1_TOP, 210, Y2_TOP)) return false; // Sell Button if (!CreateButton(sellButton, "SellButton", "Sell", 220, Y1_TOP, 320, Y2_TOP)) return false; // Close All Positions Button if (!CreateButton(closeAllButton, "CloseAllButton", "Close All", 130, Y1_MID, 230, Y2_MID)) return false; // Close Profitable Positions Button if (!CreateButton(closeProfitButton, "CloseProfitButton", "Close Profitable", 240, Y1_MID, 380, Y2_MID)) return false; // Close Losing Positions Button if (!CreateButton(closeLossButton, "CloseLossButton", "Close Losing", 390, Y1_MID, 510, Y2_MID)) return false; // Close Buy Positions Button if (!CreateButton(closeBuyButton, "CloseBuyButton", "Close Buys", 520, Y1_MID, 620, Y2_MID)) return false; // Close Sell Positions Button if (!CreateButton(closeSellButton, "CloseSellButton", "Close Sells", 630, Y1_MID, 730, Y2_MID)) return false; // Delete All Orders Button if (!CreateButton(deleteAllOrdersButton, "DeleteAllOrdersButton", "Delete All Orders", 130, Y1_BOTTOM , 270, Y2_BOTTOM )) return false; // Delete Limit Orders Button if (!CreateButton(deleteLimitOrdersButton, "DeleteLimitOrdersButton", "Delete Limits", 275, Y1_BOTTOM , 385, Y2_BOTTOM )) return false; // Delete Stop Orders Button if (!CreateButton(deleteStopOrdersButton, "DeleteStopOrdersButton", "Delete Stops", 390, Y1_BOTTOM , 515, Y2_BOTTOM )) return false; // Delete Stop Limit Orders Button if (!CreateButton(deleteStopLimitOrdersButton, "DeleteStopLimitOrdersButton", "Delete Stop Limits", 520, Y1_BOTTOM , 660, Y2_BOTTOM )) return false; return true; // All buttons created successfully }
新しいレイアウトの結果は次のとおりです。
新しいボタン統合後の新しいレイアウト
新しいボタンを追加するプロセス中に、統一性を保つために古いボタンの一部が削除されました。現時点では、追加データを入力する必要がなく、即時実行を必要とする操作、たとえば注文変更などのタスクに重点を置いています。
ボタンハンドラのコーディング
取引管理パネルの機能を強化するために、特定の取引操作を可能にするために各ボタンに専用のハンドラ関数を実装しました。各コードスニペットの説明は次のとおりです。
1. 買いボタンハンドラ(OnBuyButtonClick)
OnBuyButtonClick関数を使用すると、指定された資産を購入するための成行注文を作成できます。CTradeクラスを利用することで、ロットサイズ、スリッページ、ストップロス、テイクプロフィットなどの重要な取引パラメータを処理し、正確な実行を保証します。これは、プログラム制御された環境で買いポジションを迅速に開きたいトレーダーにとって重要です。
//+------------------------------------------------------------------+ //| Handle Buy button click | //+------------------------------------------------------------------+ void OnBuyButtonClick() { CTrade trade; double lotSize = 0.1; // Example lot size double slippage = 3; // Example slippage double stopLoss = 0; // Example stop loss (in points) double takeProfit = 0; // Example take profit (in points) // Open Buy order double askPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_ASK, askPrice) && askPrice > 0) { if (trade.Buy(lotSize, Symbol(), askPrice, slippage, stopLoss, takeProfit)) { Print("Buy order executed successfully."); } else { Print("Failed to execute Buy order. Error: ", GetLastError()); } } else { Print("Failed to retrieve Ask price. Error: ", GetLastError()); } // Execute Buy order logic here Print("Executing Buy operation"); }
2. 売りボタンハンドラ(OnSellButtonClick)
OnSellButtonClick関数は買いハンドラを反映し、ユーザーが市場注文を通じて資産を売れるようにします。売りロジックを構築することで、ロットサイズやスリッページなどの一貫したパラメータ処理が保証され、取引パネルがオンデマンドで売り注文を効率的に開始できるようになります。
//+------------------------------------------------------------------+ //| Handle Sell button click | //+------------------------------------------------------------------+ void OnSellButtonClick() { CTrade trade; double lotSize = 0.1; // Example lot size double slippage = 3; // Example slippage double stopLoss = 0; // Example stop loss (in points) double takeProfit = 0; // Example take profit (in points) double bidPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_BID, bidPrice) && bidPrice > 0) { // Open Sell order if (trade.Sell(lotSize, Symbol(), bidPrice, slippage, stopLoss, takeProfit)) { Print("Sell order opened successfully."); } else { Print("Error opening sell order: ", trade.ResultRetcode()); } } else { Print("Failed to retrieve Bid price. Error: ", GetLastError()); } }
3. 全ポジションクローズのハンドラ(OnCloseAllButtonClick)
この関数は、オープン取引を反復処理し、CTradeを使用して、すべてのアクティブポジションのクローズを自動化します。PositionCloseで実行します。これは、すべての取引を迅速に終了し、突然の市場変動から保護したり、戦略の終了要件を満たしたりすることを求めるトレーダーにとって特に便利です。
//+------------------------------------------------------------------+ //| Handle Close All button click | //+------------------------------------------------------------------+ void OnCloseAllButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i)) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("All positions closed."); }
4. 勝ちポジションクローズのハンドラ(OnCloseProfitButtonClick)
OnCloseProfitButtonClick関数を使用すると、トレーダーは利益のあるポジションのみをクローズすることで利益を確保できます。利益値に基づいて取引をフィルタリングし、選択的な決済を確実に実行します。これにより、利益を確定しながら損失を出す取引をさらに評価するために保持することに重点を置いた戦略が実現します。
//+------------------------------------------------------------------+ //| Handle Close Profitable button click | //+------------------------------------------------------------------+ void OnCloseProfitButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() > 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Profitable positions closed."); }
5. 負けポジションクローズのハンドラ(OnCloseLossButtonClick)
このハンドラは、損失が発生しているすべてのポジションをクローズすることでリスク管理ツールを提供します。マイナスの利益取引のみをターゲットにすることで、さらなるドローダウンを軽減するのに役立ちます。これは、口座のエクイティを維持し、事前に定義された損失限度を遵守するために不可欠です。
//+------------------------------------------------------------------+ //| Handle Close Losing button click | //+------------------------------------------------------------------+ void OnCloseLossButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() < 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Losing positions closed."); } void OnCloseBuyButtonClick() { // Close Buy positions logic Print("Closing Buy positions"); } void OnCloseSellButtonClick() { // Close Sell positions logic Print("Closing Sell positions"); }
6. 全注文削除のハンドラ(OnDeleteAllOrdersButtonClick)
この関数はすべての予約注文を削除し、残りの指値注文や逆指値注文が口座に影響しないようにします。COrderInfoクラスを利用して注文を取得およびキャンセルすることで、注文を整理し、意図しない実行を防ぐことができます。
//+------------------------------------------------------------------+ //| Handle Delete All Orders button click | //+------------------------------------------------------------------+ void OnDeleteAllOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i)) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All orders deleted."); }
7. 指値注文削除のハンドラ(OnDeleteLimitOrdersButtonClick)
OnDeleteLimitOrdersButtonClick関数は、指値注文のキャンセルにのみ焦点を当てています。これは、逆指値注文やその他の注文タイプを維持しながら戦略を調整する必要のあるトレーダーにとって不可欠であり、注文管理を正確に制御できます。
//+------------------------------------------------------------------+ //| Handle Delete Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All limit orders deleted."); }
8. 逆指値注文削除のハンドラ(OnDeleteStopOrdersButtonClick)
このハンドラは、すべての逆指値注文を削除することを目標とし、不安定な市場で望ましくない取引がトリガーされないようにします。逆指値注文を分離することで、トレーダーは予約注文の管理をきめ細かく制御できるようになります。
//+------------------------------------------------------------------+ //| Handle Delete Stop Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP && ORDER_TYPE_SELL_STOP) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop orders deleted."); }
9. ストップリミット注文削除のハンドラ(OnDeleteStopLimitOrdersButtonClick)
この関数は、ストップリミット注文の削除を管理します。ハイブリッド注文タイプを含む戦略に役立ちます。柔軟性が強化され、トレーダーの更新された市場見通しや戦略の変更に合わせて注文処理を調整します。
//+------------------------------------------------------------------+ //| Handle Delete Stop Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_LIMIT && ORDER_TYPE_SELL_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop limit orders deleted."); }
ボタンのクリックをこれらの関数に接続するには、それらの呼び出しをOnChartEvent関数内に統合します。ボタンのsparam値を対応するハンドラにリンクすることにより、プログラムはグラフィカルユーザーインターフェイスとバックエンドの取引ロジック間のシームレスな相互作用を保証し、パネルの応答性とユーザーフレンドリ性を高めます。
//+------------------------------------------------------------------+ //| Handle chart events | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { // Panel navigation buttons if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); } // Control buttons for panel resizing and closing else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "MaximizeButton") { OnMaximizeButtonClick(); } else if (sparam == "CloseButton") { ExpertRemove(); } { if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeButton") OnMinimizeButtonClick(); else if (sparam == "MaximizeButton") OnMaximizeButtonClick(); else if (sparam == "CloseButton") OnCloseButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } } // Trade management buttons if (sparam == "BuyButton") OnBuyButtonClick(); else if (sparam == "SellButton") OnSellButtonClick(); else if (sparam == "CloseAllButton") OnCloseAllButtonClick(); else if (sparam == "CloseProfitButton") OnCloseProfitButtonClick(); else if (sparam == "CloseLossButton") OnCloseLossButtonClick(); else if (sparam == "CloseBuyButton") OnCloseBuyButtonClick(); else if (sparam == "CloseSellButton") OnCloseSellButtonClick(); else if (sparam == "DeleteAllOrdersButton") OnDeleteAllOrdersButtonClick(); else if (sparam == "DeleteLimitOrdersButton") OnDeleteLimitOrdersButtonClick(); else if (sparam == "DeleteStopOrdersButton") OnDeleteStopOrdersButtonClick(); else if (sparam == "DeleteStopLimitOrdersButton") OnDeleteStopLimitOrdersButtonClick(); }
最終的なコードはこちらです。多くの行があります。
//+------------------------------------------------------------------+ //| Admin Panel.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 description "A secure and responsive Admin Panel. Send messages to your telegram clients without leaving MT5" #property version "1.22" #include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh> #include <Controls\Label.mqh> // Input parameters for quick messages input string QuickMessage1 = "Updates"; input string QuickMessage2 = "Close all"; input string QuickMessage3 = "In deep profits"; input string QuickMessage4 = "Hold position"; input string QuickMessage5 = "Swing Entry"; input string QuickMessage6 = "Scalp Entry"; input string QuickMessage7 = "Book profit"; input string QuickMessage8 = "Invalid Signal"; input string InputChatId = "YOUR_CHAT_ID"; input string InputBotToken = "YOUR_BOT_TOKEN"; // Constants for 2FA const string Hardcoded2FAChatId = "Replace chat ID with yours"; const string Hardcoded2FABotToken = "Replace with your bot token"; // Global variables CDialog adminHomePanel, tradeManagementPanel, communicationsPanel; CDialog authentication, twoFactorAuth; CButton homeButtonComm, homeButtonTrade; CButton sendButton, clearButton, changeFontButton, toggleThemeButton; CButton loginButton, closeAuthButton, twoFALoginButton, close2FAButton; CButton quickMessageButtons[8], minimizeButton, maximizeButton, closeButton; CButton tradeMgmtAccessButton, communicationsPanelAccessButton; CEdit inputBox, passwordInputBox, twoFACodeInput; CLabel charCounter, passwordPromptLabel, feedbackLabel, twoFAPromptLabel, twoFAFeedbackLabel; bool minimized = false; bool darkTheme = false; int MAX_MESSAGE_LENGTH = 4096; string availableFonts[] = { "Arial", "Courier New", "Verdana", "Times New Roman" }; int currentFontIndex = 0; string Password = "2024"; // Hardcoded password string twoFACode = ""; // Button Declarations for Trade Management CButton buyButton; // Button for Buy operations CButton sellButton; // Button for Sell operations CButton closeAllButton; // Button for closing all positions CButton closeProfitButton; // Button for closing profitable positions CButton closeLossButton; // Button for closing losing positions CButton closeBuyButton; // Button for closing Buy positions CButton closeSellButton; // Button for closing Sell positions CButton deleteAllOrdersButton; // Button for deleting all orders CButton deleteLimitOrdersButton; // Button for deleting limit orders CButton deleteStopOrdersButton; // Button for deleting stop orders CButton deleteStopLimitOrdersButton; // Button for deleting stop limit orders //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminHomePanel.Create(ChartID(), "Admin Home Panel", 0, 30, 30, 500, 500)) { Print("Failed to create Admin Home Panel"); return INIT_FAILED; } if (!CreateAdminHomeControls()) { Print("Home panel control creation failed"); return INIT_FAILED; } if (!communicationsPanel.Create(ChartID(), "Communications Panel", 0, 30, 30, 500, 500)) { Print("Failed to create Communications panel dialog"); return INIT_FAILED; } if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0,260, 30, 1040, 170)) { Print("Failed to create Trade Management panel dialog"); return INIT_FAILED; } if (!CreateControls()) { Print("Control creation failed"); return INIT_FAILED; } if (!CreateTradeManagementControls()) { Print("Trade management control creation failed"); return INIT_FAILED; } adminHomePanel.Hide(); // Hide home panel by default on initialization communicationsPanel.Hide(); // Hide the Communications Panel tradeManagementPanel.Hide(); // Hide the Trade Management Panel return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Handle chart events | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { // Panel navigation buttons if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); } // Control buttons for panel resizing and closing else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "MaximizeButton") { OnMaximizeButtonClick(); } else if (sparam == "CloseButton") { ExpertRemove(); } { if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeButton") OnMinimizeButtonClick(); else if (sparam == "MaximizeButton") OnMaximizeButtonClick(); else if (sparam == "CloseButton") OnCloseButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } } // Trade management buttons if (sparam == "BuyButton") OnBuyButtonClick(); else if (sparam == "SellButton") OnSellButtonClick(); else if (sparam == "CloseAllButton") OnCloseAllButtonClick(); else if (sparam == "CloseProfitButton") OnCloseProfitButtonClick(); else if (sparam == "CloseLossButton") OnCloseLossButtonClick(); else if (sparam == "CloseBuyButton") OnCloseBuyButtonClick(); else if (sparam == "CloseSellButton") OnCloseSellButtonClick(); else if (sparam == "DeleteAllOrdersButton") OnDeleteAllOrdersButtonClick(); else if (sparam == "DeleteLimitOrdersButton") OnDeleteLimitOrdersButtonClick(); else if (sparam == "DeleteStopOrdersButton") OnDeleteStopOrdersButtonClick(); else if (sparam == "DeleteStopLimitOrdersButton") OnDeleteStopLimitOrdersButtonClick(); } //+------------------------------------------------------------------+ //| Trade management button handlers | //+------------------------------------------------------------------+ void OnBuyButtonClick() { CTrade trade; double lotSize = 0.1; // lot size double slippage = 3; // slippage double stopLoss = 0; // stop loss (in points) double takeProfit = 0; // take profit (in points) // Open Buy order double askPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_ASK, askPrice) && askPrice > 0) { if (trade.Buy(lotSize, Symbol(), askPrice, slippage, stopLoss, takeProfit)) { Print("Buy order executed successfully."); } else { Print("Failed to execute Buy order. Error: ", GetLastError()); } } else { Print("Failed to retrieve Ask price. Error: ", GetLastError()); } // Execute Buy order logic here Print("Executing Buy operation"); } //+------------------------------------------------------------------+ //| Handle Sell button click | //+------------------------------------------------------------------+ void OnSellButtonClick() { CTrade trade; double lotSize = 0.1; // lot size double slippage = 3; // slippage double stopLoss = 0; // stop loss (in points) double takeProfit = 0; // take profit (in points) double bidPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_BID, bidPrice) && bidPrice > 0) { // Open Sell order if (trade.Sell(lotSize, Symbol(), bidPrice, slippage, stopLoss, takeProfit)) { Print("Sell order opened successfully."); } else { Print("Error opening sell order: ", trade.ResultRetcode()); } } else { Print("Failed to retrieve Bid price. Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Handle Close All button click | //+------------------------------------------------------------------+ void OnCloseAllButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i)) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("All positions closed."); } //+------------------------------------------------------------------+ //| Handle Close Profitable button click | //+------------------------------------------------------------------+ void OnCloseProfitButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() > 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Profitable positions closed."); } //+------------------------------------------------------------------+ //| Handle Close Losing button click | //+------------------------------------------------------------------+ void OnCloseLossButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() < 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Losing positions closed."); } void OnCloseBuyButtonClick() { // Close Buy positions logic Print("Closing Buy positions"); } void OnCloseSellButtonClick() { // Close Sell positions logic Print("Closing Sell positions"); } //+------------------------------------------------------------------+ //| Handle Delete All Orders button click | //+------------------------------------------------------------------+ void OnDeleteAllOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i)) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All orders deleted."); } //+------------------------------------------------------------------+ //| Handle Delete Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All limit orders deleted."); } //+------------------------------------------------------------------+ //| Handle Delete Stop Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP && ORDER_TYPE_SELL_STOP) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop orders deleted."); } //+------------------------------------------------------------------+ //| Handle Delete Stop Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_LIMIT && ORDER_TYPE_SELL_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop limit orders deleted."); } //+------------------------------------------------------------------+ //| Show authentication input dialog | //+------------------------------------------------------------------+ bool ShowAuthenticationPrompt() { if (!authentication.Create(ChartID(), "Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create authentication dialog"); return false; } if (!passwordInputBox.Create(ChartID(), "PasswordInputBox", 0, 20, 70, 260, 95)) { Print("Failed to create password input box"); return false; } authentication.Add(passwordInputBox); if (!passwordPromptLabel.Create(ChartID(), "PasswordPromptLabel", 0, 20, 20, 260, 40)) { Print("Failed to create password prompt label"); return false; } passwordPromptLabel.Text("Enter password: Access Admin Panel"); authentication.Add(passwordPromptLabel); if (!feedbackLabel.Create(ChartID(), "FeedbackLabel", 0, 20, 140, 380, 160)) { Print("Failed to create feedback label"); return false; } feedbackLabel.Text(""); feedbackLabel.Color(clrRed); // Red color for incorrect attempts authentication.Add(feedbackLabel); if (!loginButton.Create(ChartID(), "LoginButton", 0, 20, 120, 100, 140)) { Print("Failed to create login button"); return false; } loginButton.Text("Login"); authentication.Add(loginButton); if (!closeAuthButton.Create(ChartID(), "CloseAuthButton", 0, 120, 120, 200, 140)) { Print("Failed to create close button for authentication"); return false; } closeAuthButton.Text("Close"); authentication.Add(closeAuthButton); authentication.Show(); ChartRedraw(); return true; } //+------------------------------------------------------------------+ //| Show two-factor authentication input dialog | //+------------------------------------------------------------------+ void ShowTwoFactorAuthPrompt() { if (!twoFactorAuth.Create(ChartID(), "Two-Factor Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create 2FA dialog"); return; } if (!twoFACodeInput.Create(ChartID(), "TwoFACodeInput", 0, 20, 70, 260, 95)) { Print("Failed to create 2FA code input box"); return; } twoFactorAuth.Add(twoFACodeInput); if (!twoFAPromptLabel.Create(ChartID(), "TwoFAPromptLabel", 0, 20, 20, 380, 40)) { Print("Failed to create 2FA prompt label"); return; } twoFAPromptLabel.Text("Enter the 2FA code sent to your Telegram:"); twoFactorAuth.Add(twoFAPromptLabel); if (!twoFAFeedbackLabel.Create(ChartID(), "TwoFAFeedbackLabel", 0, 20, 140, 380, 160)) { Print("Failed to create 2FA feedback label"); return; } twoFAFeedbackLabel.Text(""); twoFAFeedbackLabel.Color(clrRed); // Red color for incorrect 2FA attempts twoFactorAuth.Add(twoFAFeedbackLabel); if (!twoFALoginButton.Create(ChartID(), "TwoFALoginButton", 0, 20, 120, 100, 140)) { Print("Failed to create 2FA login button"); return; } twoFALoginButton.Text("Verify"); twoFactorAuth.Add(twoFALoginButton); if (!close2FAButton.Create(ChartID(), "Close2FAButton", 0, 120, 120, 200, 140)) { Print("Failed to create close button for 2FA"); return; } close2FAButton.Text("Close"); twoFactorAuth.Add(close2FAButton); twoFactorAuth.Show(); ChartRedraw(); } //+------------------------------------------------------------------+ //| Admin Home Panel controls creation | //+------------------------------------------------------------------+ bool CreateAdminHomeControls() { long chart_id = ChartID(); if (!tradeMgmtAccessButton.Create(chart_id, "TradeMgmtAccessButton", 0, 50, 50, 250, 90)) { Print("Failed to create Trade Management Access button"); return false; } tradeMgmtAccessButton.Text("Trade Management Panel"); adminHomePanel.Add(tradeMgmtAccessButton); if (!communicationsPanelAccessButton.Create(chart_id, "CommunicationsPanelAccessButton", 0, 50, 100, 250, 140)) { Print("Failed to create Communications Panel Access button"); return false; } communicationsPanelAccessButton.Text("Communications Panel"); adminHomePanel.Add(communicationsPanelAccessButton); if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return false; } minimizeButton.Text("_"); adminHomePanel.Add(minimizeButton); if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return false; } maximizeButton.Text("[ ]"); adminHomePanel.Add(maximizeButton); if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return false; } closeButton.Text("X"); adminHomePanel.Add(closeButton); return true; } //Helper Function seamless Button creation bool CreateButton(CButton &button, const string name, const string text, int x1, int y1, int x2, int y2) { long chart_id = ChartID(); if (!button.Create(chart_id, name, 0, x1, y1, x2, y2)) { Print("Failed to create button: ", name); return false; } button.Text(text); tradeManagementPanel.Add(button); return true; } //+------------------------------------------------------------------+ //| Create Trade Management Controls (Buttons) | //+------------------------------------------------------------------+ bool CreateTradeManagementControls() { // Coordinates for buttons (adjust as needed) const int Y1_TOP = 5, Y2_TOP = 40; const int Y1_MID = 50, Y2_MID = 70; const int Y1_BOTTOM = 80, Y2_BOTTOM = 100; // Create Buttons if (!CreateButton(buyButton, "BuyButton", "Buy", 130, Y1_TOP, 210, Y2_TOP)) return false; if (!CreateButton(sellButton, "SellButton", "Sell", 220, Y1_TOP, 320, Y2_TOP)) return false; if (!CreateButton(closeAllButton, "CloseAllButton", "Close All", 130, Y1_MID, 230, Y2_MID)) return false; if (!CreateButton(closeProfitButton, "CloseProfitButton", "Close Profitable", 240, Y1_MID, 380, Y2_MID)) return false; if (!CreateButton(closeLossButton, "CloseLossButton", "Close Losing", 390, Y1_MID, 510, Y2_MID)) return false; if (!CreateButton(closeBuyButton, "CloseBuyButton", "Close Buys", 520, Y1_MID, 620, Y2_MID)) return false; if (!CreateButton(closeSellButton, "CloseSellButton", "Close Sells", 630, Y1_MID, 730, Y2_MID)) return false; if (!CreateButton(deleteAllOrdersButton, "DeleteAllOrdersButton", "Delete All Orders", 130, Y1_BOTTOM , 270, Y2_BOTTOM )) return false; if (!CreateButton(deleteLimitOrdersButton, "DeleteLimitOrdersButton", "Delete Limits", 275, Y1_BOTTOM , 385, Y2_BOTTOM )) return false; if (!CreateButton(deleteStopOrdersButton, "DeleteStopOrdersButton", "Delete Stops", 390, Y1_BOTTOM , 515, Y2_BOTTOM )) return false; if (!CreateButton(deleteStopLimitOrdersButton, "DeleteStopLimitOrdersButton", "Delete Stop Limits", 520, Y1_BOTTOM , 660, Y2_BOTTOM )) return false; return true; // All buttons created successfully } //+------------------------------------------------------------------+ //| Handle login button click | //+------------------------------------------------------------------+ void OnLoginButtonClick() { string enteredPassword = passwordInputBox.Text(); if (enteredPassword == Password) { twoFACode = GenerateRandom6DigitCode(); SendMessageToTelegram("A login attempt was made on the Admin Panel. Please use this code to verify your identity: " + twoFACode, Hardcoded2FAChatId, Hardcoded2FABotToken); authentication.Destroy(); ShowTwoFactorAuthPrompt(); Print("Password authentication successful. A 2FA code has been sent to your Telegram."); } else { feedbackLabel.Text("Wrong password. Try again."); passwordInputBox.Text(""); } ///Handlers for the trade management } //+------------------------------------------------------------------+ //| Handle 2FA login button click | //+------------------------------------------------------------------+ void OnTwoFALoginButtonClick() { // If 2FA is successful, show the trade management panel string enteredCode = twoFACodeInput.Text(); if (enteredCode == twoFACode) { twoFactorAuth.Destroy(); adminHomePanel.Show(); Print("2FA authentication successful. Access granted to Trade Management Panel."); } else { twoFAFeedbackLabel.Text("Wrong code. Try again."); twoFACodeInput.Text(""); } } //+------------------------------------------------------------------+ //| Handle close button for authentication | //+------------------------------------------------------------------+ void OnCloseAuthButtonClick() { authentication.Destroy(); ExpertRemove(); // Exit the expert Print("Authentication dialog closed."); } //+------------------------------------------------------------------+ //| Handle close button for 2FA | //+------------------------------------------------------------------+ void OnClose2FAButtonClick() { twoFactorAuth.Destroy(); ExpertRemove(); Print("2FA dialog closed."); } //+------------------------------------------------------------------+ //| Create necessary UI controls | //+------------------------------------------------------------------+ bool CreateControls() { long chart_id = ChartID(); if (!inputBox.Create(chart_id, "InputBox", 0, 5, 25, 460, 95)) { Print("Failed to create input box"); return false; } communicationsPanel.Add(inputBox); // Create Home Button for Communications Panel if (!homeButtonComm.Create(chart_id, "HomeButtonComm", 0, 20, 120, 120,150)) { Print("Failed to create Home button for Communications Panel"); return false; } homeButtonComm.Text("Home 🏠"); communicationsPanel.Add(homeButtonComm); // Create Home Button for Trade Management Panel if (!homeButtonTrade.Create(chart_id, "HomeButtonTrade", 0, 20, 10, 120, 30)) { Print("Failed to create Home button for Trade Management Panel"); return false; } homeButtonTrade.Text("Home 🏠"); tradeManagementPanel.Add(homeButtonTrade); if (!charCounter.Create(chart_id, "CharCounter", 0, 380, 5, 460, 25)) { Print("Failed to create character counter"); return false; } charCounter.Text("0/" + IntegerToString(MAX_MESSAGE_LENGTH)); communicationsPanel.Add(charCounter); if (!clearButton.Create(chart_id, "ClearButton", 0, 235, 95, 345, 125)) { Print("Failed to create clear button"); return false; } clearButton.Text("Clear"); communicationsPanel.Add(clearButton); if (!sendButton.Create(chart_id, "SendButton", 0, 350, 95, 460, 125)) { Print("Failed to create send button"); return false; } sendButton.Text("Send"); communicationsPanel.Add(sendButton); if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115)) { Print("Failed to create change font button"); return false; } changeFontButton.Text("Font<>"); communicationsPanel.Add(changeFontButton); if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115)) { Print("Failed to create toggle theme button"); return false; } toggleThemeButton.Text("Theme<>"); communicationsPanel.Add(toggleThemeButton); if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return false; } minimizeButton.Text("_"); communicationsPanel.Add(minimizeButton); if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return false; } maximizeButton.Text("[ ]"); communicationsPanel.Add(maximizeButton); if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return false; } closeButton.Text("X"); communicationsPanel.Add(closeButton); return CreateQuickMessageButtons(); } //+------------------------------------------------------------------+ //| Create quick message buttons | //+------------------------------------------------------------------+ bool CreateQuickMessageButtons() { string quickMessages[] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; int startX = 5, startY = 160, width = 222, height = 65, spacing = 5; for (int i = 0; i < ArraySize(quickMessages); i++) { bool created = quickMessageButtons[i].Create(ChartID(), "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height); if (!created) { Print("Failed to create quick message button ", i + 1); return false; } quickMessageButtons[i].Text(quickMessages[i]); communicationsPanel.Add(quickMessageButtons[i]); } return true; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { communicationsPanel.Destroy(); Print("Deinitialization complete"); } //+------------------------------------------------------------------+ //| Handle custom message send button click | //+------------------------------------------------------------------+ void OnSendButtonClick() { string message = inputBox.Text(); if (StringLen(message) > 0) { if (SendMessageToTelegram(message, InputChatId, InputBotToken)) Print("Custom message sent: ", message); else Print("Failed to send custom message."); } else { Print("No message entered."); } } //+------------------------------------------------------------------+ //| Handle clear button click | //+------------------------------------------------------------------+ void OnClearButtonClick() { inputBox.Text(""); OnInputChange(); Print("Input box cleared."); } //+------------------------------------------------------------------+ //| Handle quick message button click | //+------------------------------------------------------------------+ void OnQuickMessageButtonClick(long index) { string quickMessages[] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; string message = quickMessages[(int)index]; if (SendMessageToTelegram(message, InputChatId, InputBotToken)) Print("Quick message sent: ", message); else Print("Failed to send quick message."); } //+------------------------------------------------------------------+ //| Update character counter | //+------------------------------------------------------------------+ void OnInputChange() { int currentLength = StringLen(inputBox.Text()); charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH)); ChartRedraw(); } //+------------------------------------------------------------------+ //| Handle toggle theme button click | //+------------------------------------------------------------------+ void OnToggleThemeButtonClick() { darkTheme = !darkTheme; UpdateThemeColors(); Print("Theme toggled: ", darkTheme ? "Dark" : "Light"); } //+------------------------------------------------------------------+ //| Update theme colors for the panel | //+------------------------------------------------------------------+ void UpdateThemeColors() { color textColor = darkTheme ? clrWhite : clrBlack; color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro; color borderColor = darkTheme ? clrSlateGray : clrGray; color bgColor = darkTheme ? clrDarkBlue : clrWhite; UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(maximizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor); } ChartRedraw(); } //+------------------------------------------------------------------+ //| Apply theme settings to a button | //+------------------------------------------------------------------+ void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor) { button.SetTextColor(textColor); button.SetBackgroundColor(bgColor); button.SetBorderColor(borderColor); } //+------------------------------------------------------------------+ //| Handle change font button click | //+------------------------------------------------------------------+ void OnChangeFontButtonClick() { currentFontIndex = (currentFontIndex + 1) % ArraySize(availableFonts); SetFontForAll(availableFonts[currentFontIndex]); Print("Font changed to: ", availableFonts[currentFontIndex]); ChartRedraw(); } //+------------------------------------------------------------------+ //| Set font for all input boxes and buttons | //+------------------------------------------------------------------+ void SetFontForAll(string fontName) { inputBox.Font(fontName); clearButton.Font(fontName); sendButton.Font(fontName); toggleThemeButton.Font(fontName); changeFontButton.Font(fontName); minimizeButton.Font(fontName); maximizeButton.Font(fontName); closeButton.Font(fontName); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { quickMessageButtons[i].Font(fontName); } } //+------------------------------------------------------------------+ //| Generate a random 6-digit code for 2FA | //+------------------------------------------------------------------+ string GenerateRandom6DigitCode() { int code = MathRand() % 1000000; // Produces a 6-digit number return StringFormat("%06d", code); // Ensures leading zeros } //+------------------------------------------------------------------+ //| Handle minimize button click | //+------------------------------------------------------------------+ void OnMinimizeButtonClick() { minimized = true; communicationsPanel.Hide(); minimizeButton.Hide(); maximizeButton.Show(); closeButton.Show(); Print("Panel minimized."); } //+------------------------------------------------------------------+ //| Handle maximize button click | //+------------------------------------------------------------------+ void OnMaximizeButtonClick() { if (minimized) { communicationsPanel.Show(); minimizeButton.Show(); maximizeButton.Hide(); closeButton.Hide(); minimized = false; Print("Panel maximized."); } } //+------------------------------------------------------------------+ //| Handle close button click for admin panel | //+------------------------------------------------------------------+ void OnCloseButtonClick() { ExpertRemove(); Print("Admin panel closed."); } //+------------------------------------------------------------------+ //| Send the message to Telegram | //+------------------------------------------------------------------+ bool SendMessageToTelegram(string message, string chatId, string botToken) { string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; char postData[]; ArrayResize(postData, StringToCharArray(jsonMessage, postData) - 1); int timeout = 5000; char result[]; string responseHeaders; int responseCode = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, postData, result, responseHeaders); if (responseCode == 200) { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", responseCode, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } } //+------------------------------------------------------------------+
テスト
テストの結果、すべてのボタンが正しく機能し、プログラムどおりに応答していることが確認されました。取引管理パネルは取引管理者のツールキットの貴重なコンポーネントとなりました。新しいボタンの統合とイベントハンドラの実装は両方とも正常に完了しました。
取引管理パネルのボタンハンドラが動作している
注文の執行と決済が成功したことを示すEAコメント
結論
今回のディスカッションでは、Telegramの設定を再確認し、新しい取引管理ボタンを追加することで、取引管理パネルを強化しました。また、X方向への位置調整を含め、垂直スケールを縮小し、水平スケールを拡大することでレイアウトを改善しました。この調整により、パネルと組み込みのクイック取引ボタンの重複が解消され、取引ボタンへのアクセス性を維持しつつ、チャートの視認性が向上しました。
レイアウトの確定後は、ボタンのイベントハンドラを統合し、クリック時に適切に動作するように設定しました。
このディスカッションを通じて、MQL5におけるGUIプログラミングの幅広い可能性を実感し、さまざまなGUIコンポーネントを設計する際の創造的な可能性について理解を深めることができたのではないでしょうか。スキルと想像力を活かせば、この基盤をさらに発展させ、探求できることは無限に広がっています。
トレーダー仲間の皆さん、開発をお楽しみください。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16328




- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索