Consolidate Python ignore rules into root gitignore

This commit is contained in:
Hiroaki86
2026-05-27 23:01:28 +09:00
commit fa3394415d
399 changed files with 509103 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
# MQL5 Expert Advisor 開発指示書
あなたはMQL5のシニアエンジニアであり、同時に定量的リスク管理の専門家です。常に**『バックテストの再現性』と『ライブ実行時のエラー耐性』**を最優先に考えた回答をしてください。
## 1. 基本設計方針
- **言語:** MQL5 (C++ベース)
- **標準ライブラリの優先:** `Trade\Trade.mqh``CTrade` クラスを積極的に使用し、注文処理(OrderSend)を簡略化・安全化すること。
- **イベント駆動:** `OnInit`, `OnDeinit`, `OnTick` などのイベントハンドラを適切に使用すること。
## 2. コーディングスタイル
- **命名規則:**
- 外部パラメータ(input)は `input_` または `inp` を接頭辞につける。
- グローバル変数は `g_`、メンバ変数は `m_` をつける。
- **エラーハンドリング:** - 注文実行時やインジケータハンドル作成時は、必ず戻り値をチェックし、失敗した場合は `GetLastError()` を用いてログ出力(Print)すること。
- **最適化:** - 重い処理は `OnTick` ではなく `OnInit` や特定の足が確定したタイミングで行うように工夫すること。
## 3. 重要事項
- **マジックナンバー:** EAごとに固有の `input int MagicNumber` を定義し、注文時に必ず使用すること。
- **シンボル/期間:** `_Symbol` および `_Period` を使用し、汎用性を持たせること。
- **コメント:** コードの重要セクションには、ロジックを説明する英語のコメントを付与すること。
## 4. 禁止事項
- MQL4の古い関数(OrderSendの旧形式など)は絶対に使用しないこと。
- バックテストのパフォーマンスを著しく低下させる無駄なループ処理を避けること。
## 5. ドキュメント管理規則 (Documentation & Specifications)
- **フォルダ構成:** プロジェクトルートに `docs` フォルダを維持し、各EA/インジケータに対応する仕様書(Markdown形式)を格納すること。
- **ファイル命名:** 仕様書は英語版と日本語版を両方作成し、以下の形式で区別すること:
- 日本語版:`{プログラム名}_spec_ja.md`
- 英語版:`{プログラム名}_spec_en.md`
- **新規作成時のルール:** - 新しいEAまたはインジケータを作成する際は、コードを書く前、あるいは同時に `docs/` 内に日本語版と英語版の両方の仕様書を生成すること。
- **修正時の同期ルール:** - プログラムのロジック、外部パラメータ(input)、または重要な関数を変更した際は、必ず対応する `docs/{プログラム名}_spec_ja.md` および `docs/{プログラム名}_spec_en.md` を読み込み、修正内容を反映させること。
- 修正の際は「変更履歴(Changelog)」セクションを仕様書末尾に設け、日付と修正概要を記録すること。
## 6. 仕様書の標準構成案
仕様書を作成する際は、以下の項目を含めること:
1. **概要**: プログラムの目的と動作概要。
2. **使用インジケータ**: 依存している標準・カスタムインジケータ。
3. **パラメータ設定**: `input` 変数の説明、デフォルト値、設定の意味。
4. **エントリー/エグジット条件**: ロジックの詳細(文章および箇条書き)。
5. **リスク管理**: マジックナンバー、ロット計算、ストップロス等の仕様。
6. **変更履歴**: 日付、修正箇所、修正理由。
## 7. フォルダ構成と再利用性のルール
### 7.1 プロジェクト単位のフォルダ管理
- **プロジェクトフォルダ:** 各EA/インジケータは `Experts/MyProject/``Indicators/MyProject/` のようにプロジェクト名でフォルダを作成し、その中に関連ファイルを配置すること。
- **仕様書の配置:** 対応する仕様書は `docs/MyProject/` 内に格納すること。
### 7.2 標準フォルダ構成
```
MQL5/
├── Experts/
│ └── MyProject/ # プロジェクトごとのフォルダ
│ ├── MyEA.mq5 # メインソース
│ └── MyEA.mqh # (オプション) EA固有のヘッダー
├── Indicators/
│ └── MyProject/ # 関連するカスタムインジケータ
│ └── MySignal.mq5
├── Include/
│ └── MyLib/ # 【重要】自作ライブラリの本拠地
│ ├── Common/ # 汎用ツール(時間操作、ログ、配列操作など)
│ │ └── TimeUtils.mqh
│ ├── Trading/ # トレードロジック(資金管理、注文処理)
│ │ └── RiskManager.mqh
│ ├── Signals/ # 売買サイン判定ロジック
│ │ └── CrossLogic.mqh
│ └── Wrapper/ # 標準ライブラリの拡張
│ └── MyTrade.mqh
├── Scripts/
│ └── Utilities/ # 一括決済などの便利ツール
├── docs/ # 仕様書フォルダ
│ └── MyProject/
│ ├── MyEA_spec_ja.md # 日本語仕様書
│ └── MyEA_spec_en.md # 英語仕様書
└── .github/ # Copilot指示書など
└── copilot-instructions.md
```
### 7.3 再利用性のルール
- **共通ロジックの配置:** 複数のプロジェクトで利用可能なロジックは、必ず `Include/MyLib/` 内の適切なサブフォルダにクラスまたは関数として定義すること。
- `Common/`: 汎用ユーティリティ(時間、ログ、配列操作など)
- `Trading/`: トレード関連(資金管理、注文処理、ポジション管理など)
- `Signals/`: 売買サイン判定ロジック
- `Wrapper/`: 標準ライブラリの拡張クラス
- **EAの構成:** `Experts/` 内の `.mq5` ファイルはエントリーポイントとしての役割に専念させ、具体的なロジックは `Include/MyLib/` 側のヘッダーファイルをインクルードして呼び出す形式をとること。
- **依存関係の解決:** 新しいファイルを作成する際は、既存の `Include/MyLib/` 内にある自作ライブラリを優先的に再利用するよう提案すること。
## 8. 自動コンパイルとバグ修正フロー
- **対象:** 新規作成または修正した `.mq5` / `.mqh` ファイル。
- **実行手段:** まず VSCode の MQL Tools のコンパイル機能を優先して使用し、環境要件や自動化の都合で難しい場合は `metaeditor64.exe /compile` を使用すること。
- **必須ループ:** 「実装 → コンパイル → ログ確認 → 修正」を繰り返し、`0 errors, 0 warnings` を満たすまで作業を継続すること。
- **ログ管理:** コンパイルログは `MQL5/Logs/compile_{ProgramName}.log` に保存し、修正時は直近ログを根拠に対応すること。
- **修正優先度:** コンパイルエラーを最優先で解消し、その後に警告を解消すること。
- **完了条件:** ①コンパイル成功、②主要ロジックの整合性確認、③仕様書(`_spec_ja.md` / `_spec_en.md`)への反映。
+176
View File
@@ -0,0 +1,176 @@
# ==============================================================================
# MQL5 Project .gitignore
# ==============================================================================
# ------------------------------------------------------------------------------
# Compiled Files (コンパイル済みファイル)
# ------------------------------------------------------------------------------
*.ex4
*.ex5
# ------------------------------------------------------------------------------
# Logs and Temporary Files (ログと一時ファイル)
# ------------------------------------------------------------------------------
*.log
Logs/
*/Logs/
# ------------------------------------------------------------------------------
# Tester and Profiles (テスターとプロファイル)
# ------------------------------------------------------------------------------
Tester/
*/Tester/
Profiles/
# ------------------------------------------------------------------------------
# Runtime Generated Files (実行時生成ファイル)
# ------------------------------------------------------------------------------
Files/
Images/
# ------------------------------------------------------------------------------
# Standard MT5 Folders (標準MT5フォルダ - 除外)
# ------------------------------------------------------------------------------
# Market downloads
Market/
*/Market/
# Standard examples
Examples/
Experts/Examples/
Indicators/Examples/
Scripts/Examples/
# Standard advisors
Experts/Advisors/
# Free robots and indicators
Experts/Free Robots/
Indicators/Free Indicators/
# Standard libraries (Include配下の標準ライブラリは含めるが、サブフォルダのMarket等は除外)
Include/*/Market/
Include/*/Examples/
# Services
Services/
# Shared Projects
Shared Projects/
# ------------------------------------------------------------------------------
# Third-party Packages (サードパーティパッケージ)
# ------------------------------------------------------------------------------
# OANDA packages
Indicators/oanda_basic_package/
Indicators/oanda_lab/
Indicators/oanda_lab_new/
# Market indicators/experts (root level ex5 files)
Indicators/*.ex5
Experts/*.ex5
# ------------------------------------------------------------------------------
# Editor and IDE (エディタとIDE設定)
# ------------------------------------------------------------------------------
.history/
.vscode/ipch/
.vscode/msvc.json
# ------------------------------------------------------------------------------
# OS Specific (OS固有ファイル)
# ------------------------------------------------------------------------------
# macOS
.DS_Store
# Windows
Thumbs.db
desktop.ini
experts.dat
*.lnk
# ------------------------------------------------------------------------------
# Python Project (python_for_ea)
# ------------------------------------------------------------------------------
# Python bytecode and C extensions
python_for_ea/**/__pycache__/
python_for_ea/**/*.py[cod]
python_for_ea/**/*$py.class
python_for_ea/**/*.so
# Virtual environments
python_for_ea/**/.venv/
python_for_ea/**/venv/
python_for_ea/**/env/
python_for_ea/**/ENV/
# Environment variables
python_for_ea/**/.env
python_for_ea/**/.env.*
!python_for_ea/**/.env.example
# Python package and build outputs
python_for_ea/**/build/
python_for_ea/**/dist/
python_for_ea/**/*.egg-info/
python_for_ea/**/.eggs/
python_for_ea/**/*.egg
# Test, coverage, type-checker, and linter caches
python_for_ea/**/.pytest_cache/
python_for_ea/**/.coverage
python_for_ea/**/.coverage.*
python_for_ea/**/htmlcov/
python_for_ea/**/.tox/
python_for_ea/**/.nox/
python_for_ea/**/.mypy_cache/
python_for_ea/**/.pyright/
python_for_ea/**/.ruff_cache/
python_for_ea/**/.ty/
# Jupyter, editor, local output, and database files
python_for_ea/**/.ipynb_checkpoints/
python_for_ea/**/.vscode/
python_for_ea/**/.idea/
python_for_ea/**/*.code-workspace
python_for_ea/**/logs/
python_for_ea/**/data/
python_for_ea/**/output/
python_for_ea/**/outputs/
python_for_ea/**/tmp/
python_for_ea/**/temp/
python_for_ea/**/.cache/
python_for_ea/**/*.db
python_for_ea/**/*.sqlite
python_for_ea/**/*.sqlite3
python_for_ea/**/.streamlit/secrets.toml
# Excel / Office temporary files
python_for_ea/**/~$*.xlsx
python_for_ea/**/~$*.xls
python_for_ea/**/~$*.csv
# uv.lock is intentionally not ignored so reproducible environments can be tracked.
# ------------------------------------------------------------------------------
# VS Code AI Rules (VSCode AI設定)
# ------------------------------------------------------------------------------
.github/instructions/codacy.instructions.md
# ------------------------------------------------------------------------------
# MQL Clangd Settings
# ------------------------------------------------------------------------------
.clangd
.clang-format
.cache/
# ==============================================================================
# Keep Custom Projects (自作プロジェクトは含める)
# ==============================================================================
# !Experts/YourProjectName/
# !Indicators/YourProjectName/
# !Include/MyLib/
# !Scripts/Utilities/
# !docs/
# !README.md
# !.github/copilot-instructions.md
+27
View File
@@ -0,0 +1,27 @@
{
"C_Cpp.default.includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/Include"
],
"C_Cpp.default.compilerPath": "",
"C_Cpp.default.intelliSenseMode": "gcc-x64",
"C_Cpp.errorSquiggles": "disabled",
"C_Cpp.autocompleteAddParentheses": true,
"files.exclude": {
"**/*.ex4": true,
"**/*.ex5": true,
"**/*_@!!@.mq4": true,
"**/*_@!!@.mq5": true,
"**/*_@!!@.mqh": true,
"**/*_@!!@.log": true
},
"files.associations": {
"*.mqh": "cpp",
"*.mq4": "cpp",
"*.mq5": "cpp"
},
"editor.tabSize": 3,
"C_Cpp.default.forcedInclude": [
"c:\\Users\\new\\.vscode\\extensions\\l-i-v.mql-tools-2.2.0\\data\\mql5_en.mqh"
]
}
+94
View File
@@ -0,0 +1,94 @@
# MQL5 Expert Advisor 開発指示書
あなたはMQL5のシニアエンジニアであり、同時に定量的リスク管理の専門家です。常に**『バックテストの再現性』と『ライブ実行時のエラー耐性』**を最優先に考えた回答をしてください。
## 1. 基本設計方針
- **言語:** MQL5 (C++ベース)
- **標準ライブラリの優先:** `Trade\Trade.mqh``CTrade` クラスを積極的に使用し、注文処理(OrderSend)を簡略化・安全化すること。
- **イベント駆動:** `OnInit`, `OnDeinit`, `OnTick` などのイベントハンドラを適切に使用すること。
## 2. コーディングスタイル
- **命名規則:**
- 外部パラメータ(input)は `input_` または `inp` を接頭辞につける。
- グローバル変数は `g_`、メンバ変数は `m_` をつける。
- **エラーハンドリング:** - 注文実行時やインジケータハンドル作成時は、必ず戻り値をチェックし、失敗した場合は `GetLastError()` を用いてログ出力(Print)すること。
- **最適化:** - 重い処理は `OnTick` ではなく `OnInit` や特定の足が確定したタイミングで行うように工夫すること。
## 3. 重要事項
- **マジックナンバー:** EAごとに固有の `input int MagicNumber` を定義し、注文時に必ず使用すること。
- **シンボル/期間:** `_Symbol` および `_Period` を使用し、汎用性を持たせること。
- **コメント:** コードの重要セクションには、ロジックを説明する英語のコメントを付与すること。
## 4. 禁止事項
- MQL4の古い関数(OrderSendの旧形式など)は絶対に使用しないこと。
- バックテストのパフォーマンスを著しく低下させる無駄なループ処理を避けること。
## 5. ドキュメント管理規則 (Documentation & Specifications)
- **フォルダ構成:** プロジェクトルートに `docs` フォルダを維持し、各EA/インジケータに対応する仕様書(Markdown形式)を格納すること。
- **ファイル命名:** 仕様書は英語版と日本語版を両方作成し、以下の形式で区別すること:
- 日本語版:`{プログラム名}_spec_ja.md`
- 英語版:`{プログラム名}_spec_en.md`
- **新規作成時のルール:** - 新しいEAまたはインジケータを作成する際は、コードを書く前、あるいは同時に `docs/` 内に日本語版と英語版の両方の仕様書を生成すること。
- **修正時の同期ルール:** - プログラムのロジック、外部パラメータ(input)、または重要な関数を変更した際は、必ず対応する `docs/{プログラム名}_spec_ja.md` および `docs/{プログラム名}_spec_en.md` を読み込み、修正内容を反映させること。
- 修正の際は「変更履歴(Changelog)」セクションを仕様書末尾に設け、日付と修正概要を記録すること。
## 6. 仕様書の標準構成案
仕様書を作成する際は、以下の項目を含めること:
1. **概要**: プログラムの目的と動作概要。
2. **使用インジケータ**: 依存している標準・カスタムインジケータ。
3. **パラメータ設定**: `input` 変数の説明、デフォルト値、設定の意味。
4. **エントリー/エグジット条件**: ロジックの詳細(文章および箇条書き)。
5. **リスク管理**: マジックナンバー、ロット計算、ストップロス等の仕様。
6. **変更履歴**: 日付、修正箇所、修正理由。
## 7. フォルダ構成と再利用性のルール
### 7.1 プロジェクト単位のフォルダ管理
- **プロジェクトフォルダ:** 各EA/インジケータは `Experts/MyProject/``Indicators/MyProject/` のようにプロジェクト名でフォルダを作成し、その中に関連ファイルを配置すること。
- **仕様書の配置:** 対応する仕様書は `docs/MyProject/` 内に格納すること。
### 7.2 標準フォルダ構成
```
MQL5/
├── Experts/
│ └── MyProject/ # プロジェクトごとのフォルダ
│ ├── MyEA.mq5 # メインソース
│ └── MyEA.mqh # (オプション) EA固有のヘッダー
├── Indicators/
│ └── MyProject/ # 関連するカスタムインジケータ
│ └── MySignal.mq5
├── Include/
│ └── MyLib/ # 【重要】自作ライブラリの本拠地
│ ├── Common/ # 汎用ツール(時間操作、ログ、配列操作など)
│ │ └── TimeUtils.mqh
│ ├── Trading/ # トレードロジック(資金管理、注文処理)
│ │ └── RiskManager.mqh
│ ├── Signals/ # 売買サイン判定ロジック
│ │ └── CrossLogic.mqh
│ └── Wrapper/ # 標準ライブラリの拡張
│ └── MyTrade.mqh
├── Scripts/
│ └── Utilities/ # 一括決済などの便利ツール
├── docs/ # 仕様書フォルダ
│ └── MyProject/
│ ├── MyEA_spec_ja.md # 日本語仕様書
│ └── MyEA_spec_en.md # 英語仕様書
└── .github/ # Copilot指示書など
└── copilot-instructions.md
```
### 7.3 再利用性のルール
- **共通ロジックの配置:** 複数のプロジェクトで利用可能なロジックは、必ず `Include/MyLib/` 内の適切なサブフォルダにクラスまたは関数として定義すること。
- `Common/`: 汎用ユーティリティ(時間、ログ、配列操作など)
- `Trading/`: トレード関連(資金管理、注文処理、ポジション管理など)
- `Signals/`: 売買サイン判定ロジック
- `Wrapper/`: 標準ライブラリの拡張クラス
- **EAの構成:** `Experts/` 内の `.mq5` ファイルはエントリーポイントとしての役割に専念させ、具体的なロジックは `Include/MyLib/` 側のヘッダーファイルをインクルードして呼び出す形式をとること。
- **依存関係の解決:** 新しいファイルを作成する際は、既存の `Include/MyLib/` 内にある自作ライブラリを優先的に再利用するよう提案すること。
## 8. 自動コンパイルとバグ修正フロー
- **対象:** 新規作成または修正した `.mq5` / `.mqh` ファイル。
- **実行手段:** まず VSCode の MQL Tools のコンパイル機能を優先して使用し、環境要件や自動化の都合で難しい場合は `metaeditor64.exe /compile` を使用すること。
- **必須ループ:** 「実装 → コンパイル → ログ確認 → 修正」を繰り返し、`0 errors, 0 warnings` を満たすまで作業を継続すること。
- **ログ管理:** コンパイルログは `MQL5/Logs/compile_{ProgramName}.log` に保存し、修正時は直近ログを根拠に対応すること。
- **修正優先度:** コンパイルエラーを最優先で解消し、その後に警告を解消すること。
- **完了条件:** ①コンパイル成功、②主要ロジックの整合性確認、③仕様書(`_spec_ja.md` / `_spec_en.md`)への反映。
Binary file not shown.
File diff suppressed because it is too large Load Diff
+935
View File
@@ -0,0 +1,935 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.00"
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
#import "Shell32.dll"
int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 20; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define DEFAULT_TARGET_PRICE 0.0
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // ★追加:トレンドを格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 必要な関数プロトタイプ宣言
//| プロセス完了ファイル("process_done.txt")関連
//+------------------------------------------------------------------+
// "process_done.txt"を作成する関数
void CreateDoneFile(const string name);
// "process_done.txt"を削除する関数
void DeleteDoneFile(const string name);
// "process_done.txt"の存在を確認し、存在する場合はtrueを返す関数
bool CheckDoneFile(const string name);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 必要な関数プロトタイプ宣言
//| OHLCデータの取得からターゲット価格の取得まで
//+------------------------------------------------------------------+
//| 最新のOHLCデータを取得する関数
bool GetLatestOHLC(datetime &times[], double &open_prices[], double &high_prices[], double &low_prices[], double &close_prices[], ENUM_TIMEFRAMES tf, int bars_count);
//| "ohlc.csv"を出力する関数
void RecordOHLC(const string filename, const datetime &times[], const double &open_prices[], const double &high_prices[], const double &low_prices[], const double &close_prices[]);
//| バッチファイル(Pythonスクリプト)を実行する関数
void ExecuteBatchTrend();
void ExecuteBatchEntry();
// | "ohlc.csv"を出力後、バッチファイルの実行する関数
bool RecordOHLCAndExecuteBatch_Trend(EAState &state);
bool RecordOHLCAndExecuteBatch_Entry(EAState &state);
//| ターゲット価格を取得する関数
bool GetTargetPrices(EAState &state);
//| "target_prices.txt"を読み込む関数
void LoadTargetPrices(double &target_prices[]);
//| "xxx"を読み込む関数
bool GetTrendState(EAState &state);
void LoadTrendState(int &trend_state);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 必要な関数プロトタイプ宣言
//| エントリー注文関連
//+------------------------------------------------------------------+
//| エントリー注文を送信する関数 (1:buy-stop, 2:buy-limit, 3:sell-stop, 4:sell-limit)
bool SendOrder(int orderType, double price, double tp, double sl);
//| 注文の執行ポリシーを取得する関数
ENUM_ORDER_TYPE_FILLING GetOrderFillingPolicy(string symbol);
//| 注文コメント(ローカル時刻)を生成する関数(先頭に orderType を付与)
string RequestComment(int orderType);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 必要な関数プロトタイプ宣言
//| 時間制限処理関連
//+------------------------------------------------------------------+
//| 時間が経過したエントリー注文をキャンセルする関数
bool CancelExpiredOrders();
//| 時間が経過したポジションをクローズする関数
bool CloseExpiredPositions();
//| 指定された時間に最も近いバーのインデックスを返す関数
// int GetBarIndexByTime(datetime time, int default_index = 0);
int GetBarShiftByTime(datetime time, ENUM_TIMEFRAMES tf, int default_shift = -1);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
void OnInit()
// プロセス完了ファイル("process_done.txt)"を作成
{
CreateDoneFile(done_trend_file);
CreateDoneFile(done_entry_file);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
void OnTick()
{
static int init_order_flg = initial_order;
// ─────────────────────────────────────────────
// (1) H4更新検知:トレンド用
// ─────────────────────────────────────────────
int current_bars_H4 = iBars(NULL, PERIOD_H4);
static int pre_bars_H4 = current_bars_H4;
int bars_H4_change = current_bars_H4 - pre_bars_H4;
if(bars_H4_change > 0 || init_order_flg == 1)
{
RecordOHLCAndExecuteBatch_Trend(g_ea);
}
pre_bars_H4 = current_bars_H4;
// trend done待ち(なければ以降をスキップ)
if(!CheckDoneFile(done_trend_file))
return;
// トレンド取得
GetTrendState(g_ea);
// ─────────────────────────────────────────────
// (2) H1更新検知:エントリー用
// ─────────────────────────────────────────────
static bool bars_H1_check = false;
int current_bars_H1 = iBars(NULL, PERIOD_H1);
static int pre_bars_H1 = current_bars_H1;
int bars_H1_change = current_bars_H1 - pre_bars_H1;
if(bars_H1_change > 0 || init_order_flg == 1)
{
init_order_flg = 0;
bars_H1_check = true;
g_ea.chk_cnt = 0;
g_ea.last_chk = 0;
RecordOHLCAndExecuteBatch_Entry(g_ea);
}
pre_bars_H1 = current_bars_H1;
// ── ティック情報・コメント表示 ──
MqlTick last_tick;
if(!SymbolInfoTick(_Symbol, last_tick))
{
return;
}
double Ask = last_tick.ask;
double Bid = last_tick.bid;
double Spread = MathRound((Ask - Bid) / Point()) * Point();
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
string message = StringFormat(
" \nAsk: %." + IntegerToString(digits) + "f"
"\nBid: %." + IntegerToString(digits) + "f"
"\nSpread: %." + IntegerToString(digits) + "f"
"\n\nLast Trend Update:\n %s"
"\n\nTrend State: %.0f" // ★追加
"\n\nLast Target Update:\n %s"
"\n\n[T1 Buy Stop ] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f"
"\n[T2 Buy Limit] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f"
"\n[T3 Sell Stop] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f"
"\n[T4 SellLimit] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f\n",
Ask, Bid, Spread,
TimeToString(g_ea.last_trend_update, TIME_DATE | TIME_MINUTES),
g_ea.trend_state, // ★追加
TimeToString(g_ea.last_target_update, TIME_DATE | TIME_MINUTES),
g_ea.en_price[1], g_ea.tp_price[1], g_ea.sl_price[1],
g_ea.en_price[2], g_ea.tp_price[2], g_ea.sl_price[2],
g_ea.en_price[3], g_ea.tp_price[3], g_ea.sl_price[3],
g_ea.en_price[4], g_ea.tp_price[4], g_ea.sl_price[4]
);
Comment(message);
// スプレッド制限
if(Spread > spread_limit * Point())
return;
// entry done待ち
if(!CheckDoneFile(done_entry_file))
return;
// ターゲット取得
GetTargetPrices(g_ea);
// 期限切れ注文キャンセル・ポジクローズ
if(OrdersTotal() > 0)
CancelExpiredOrders();
if(PositionsTotal() > 0)
CloseExpiredPositions();
// ─────────────────────────────────────────────
// エントリー条件判定&注文送信(H1更新タイミングで1回)
// ─────────────────────────────────────────────
// if(bars_H4_check && TimeCurrent() - g_ea.last_chk >= 60)
// {
// bars_H4_check = false;
// g_ea.last_chk = TimeCurrent();
if(bars_H1_check && TimeCurrent() - g_ea.last_chk >= 60)
{
bars_H1_check = false;
g_ea.last_chk = TimeCurrent();
if(g_ea.res_chk == 0)
{
Print("[Entry Skip] res_chk=0 (range). No entry orders are sent.");
g_ea.chk_cnt = 0;
}
else
{
int used = OrdersTotal() + PositionsTotal();
if(used >= POSITION_LIMIT)
{
Print("Position limit exceeded: used=", used, " limit=", POSITION_LIMIT);
}
else
{
int sent_success = 0; // ★ 送信成功数(= SendOrder true の回数)
// ★ 1..4 を順に判定して、条件OKなら送る
for(int t=1; t<=4; t++)
{
// ポジション上限チェック(途中で到達したら打ち切り)
used = OrdersTotal() + PositionsTotal();
if(used >= POSITION_LIMIT)
{
Print("Position limit reached while sending. used=", used, " limit=", POSITION_LIMIT);
break;
}
string entry_type;
double cur_price; // ログ用(Ask/Bid
if(t==1)
{
entry_type="Buy Stop";
cur_price=Ask;
}
else
if(t==2)
{
entry_type="Buy Limit";
cur_price=Ask;
}
else
if(t==3)
{
entry_type="Sell Stop";
cur_price=Bid;
}
else
{
entry_type="Sell Limit"; // t==4
cur_price=Bid;
}
double en = g_ea.en_price[t];
double tp = g_ea.tp_price[t];
double sl = g_ea.sl_price[t];
bool ok=false;
if(t==1)
ok = (Ask < en && tp > en && sl < en); // buy-stop
else
if(t==2)
ok = (Ask > en && tp > en && sl < en); // buy-limit
else
if(t==3)
ok = (Bid > en && tp < en && sl > en); // sell-stop
else
ok = (Bid < en && tp < en && sl > en); // sell-limit
if(ok)
{
Print("[", entry_type, " Order Try at ", cur_price, "] en=", en, " tp=", tp, " sl=", sl);
if(SendOrder(t, en, tp, sl))
{
sent_success++;
Print("[", entry_type, " Order Sent] ticket ok. en=", en, " tp=", tp, " sl=", sl);
}
else
{
Print("[", entry_type, " Order Failed] en=", en, " tp=", tp, " sl=", sl);
}
}
else
{
Print("[No ", entry_type, "] cur=", cur_price, " en=", en, " tp=", tp, " sl=", sl);
}
}
if(sent_success > 0)
{
g_ea.chk_cnt = 0; // 1件でも通ったら終了
}
else
{
g_ea.chk_cnt += 1;
Print("[Retry] no order sent. chk_cnt=", g_ea.chk_cnt, "/10");
if(g_ea.chk_cnt < 10)
{
// bars_H4_check = true; // 60秒後に再度このブロックに入る
bars_H1_check = true; // ★ GPT-EAの bars_H4_check → bars_H1_check に変更
}
else
{
Print("[Retry End] reached max tries. reset chk_cnt.");
g_ea.chk_cnt = 0;
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| "process_done.txt"を作成する関数
//+------------------------------------------------------------------+
void CreateDoneFile(const string name)
{
if(!FileIsExist(name))
{
int h = FileOpen(name, FILE_WRITE|FILE_TXT);
if(h != INVALID_HANDLE)
FileClose(h);
else
Print("Failed to create file: ", name, " err=", GetLastError());
}
}
//+------------------------------------------------------------------+
//| "process_done.txt"を削除する関数
//+------------------------------------------------------------------+
void DeleteDoneFile(const string name)
{
if(FileIsExist(name))
FileDelete(name);
}
//+------------------------------------------------------------------+
//| "process_done.txt"の存在を確認し、存在する場合はtrueを返す関数
//+------------------------------------------------------------------+
bool CheckDoneFile(const string name)
{
return FileIsExist(name);
}
//+------------------------------------------------------------------+
//| 最新のOHLCデータを取得する関数
//+------------------------------------------------------------------+
bool GetLatestOHLC(datetime &times[], double &open_prices[], double &high_prices[], double &low_prices[], double &close_prices[], ENUM_TIMEFRAMES tf, int bars_count)
{
ArrayResize(times, 0);
ArrayResize(open_prices, 0);
ArrayResize(high_prices, 0);
ArrayResize(low_prices, 0);
ArrayResize(close_prices, 0);
if(bars_count < 2)
return false;
// 時間データを取得
if(CopyTime(_Symbol, tf, 0, bars_count, times) <= 0)
{
Print(__FUNCTION__, ": Failed to copy time data (bars=", bars_count, ") err=", GetLastError());
return false;
}
// OHLCデータを取得
MqlRates rates[];
if(CopyRates(_Symbol, tf, 0, bars_count, rates) <= 0)
{
Print(__FUNCTION__, ": Failed to copy rates data (bars=", bars_count, ") err=", GetLastError());
return false;
}
// 必要なデータを配列に格納
for(int i = 0; i < ArraySize(rates); i++)
{
ArrayResize(open_prices, i + 1);
ArrayResize(high_prices, i + 1);
ArrayResize(low_prices, i + 1);
ArrayResize(close_prices, i + 1);
open_prices[i] = rates[i].open;
high_prices[i] = rates[i].high;
low_prices[i] = rates[i].low;
close_prices[i] = rates[i].close;
}
return true;
}
//+------------------------------------------------------------------+
//| "ohlc.csv"を出力する関数
//+------------------------------------------------------------------+
void RecordOHLC(const string filename, const datetime &times[], const double &open_prices[], const double &high_prices[], const double &low_prices[], const double &close_prices[])
{
// 出力先ファイル名
// string filename = "ohlc.csv";
// ファイルを "書き込みモード" でオープン (テキスト/ANSI)
int fileHandle = FileOpen(filename, FILE_WRITE | FILE_TXT | FILE_ANSI);
// ファイルが開けたかチェック
if(fileHandle == INVALID_HANDLE)
{
Print(__FUNCTION__, " : Failed to open file: ", GetLastError());
return;
}
// 配列サイズを取得 (times, open, high, low, close の要素数は同じ前提)
int size = ArraySize(times);
// ヘッダー行を追加
FileWrite(fileHandle, "Time,Open,High,Low,Close");
// 小数点の桁数を取得
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
// フォーマット文字列を動的に生成
string formatString = StringFormat("%%s,%%.%df,%%.%df,%%.%df,%%.%df", digits, digits, digits, digits);
// 1行ずつ "時刻, Open, High, Low, Close" の形式で書き込み
for(int i = 0; i < size; i++)
{
// 時間をフォーマット
string timeStr = TimeToString(times[i], TIME_DATE | TIME_MINUTES);
// 1行分の文字列を生成 (小数点以下の桁数を `digits` に調整)
string line = StringFormat(formatString,
timeStr, open_prices[i], high_prices[i], low_prices[i], close_prices[i]);
// ファイルに書き込み (改行付き)
FileWrite(fileHandle, line);
}
// 書き込み終了後、ファイルを閉じる
FileClose(fileHandle);
}
//+------------------------------------------------------------------+
//| バッチファイル(Pythonスクリプト)を実行する関数
//+------------------------------------------------------------------+
void ExecuteBatchTrend()
{
if(CheckDoneFile(done_trend_file))
{
DeleteDoneFile(done_trend_file);
ShellExecuteW(0, "open", get_trend_reply_bat, "", "", 1);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ExecuteBatchEntry()
{
if(CheckDoneFile(done_entry_file))
{
DeleteDoneFile(done_entry_file);
ShellExecuteW(0, "open", get_entry_reply_bat, "", "", 1);
}
}
//+------------------------------------------------------------------+
//| "ohlc.csv"を出力後、バッチファイルの実行する関数
//+------------------------------------------------------------------+
bool RecordOHLCAndExecuteBatch_Trend(EAState &state)
{
datetime times[];
double open_prices[], high_prices[], low_prices[], close_prices[];
if(!GetLatestOHLC(times, open_prices, high_prices, low_prices, close_prices,
PERIOD_H4, HISTORY_BARS))
{ Print("GetLatestOHLC(H4) failed."); return false; }
RecordOHLC("ohlc_H4.csv", times, open_prices, high_prices, low_prices, close_prices);
ExecuteBatchTrend();
state.load_trend_flg = true;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool RecordOHLCAndExecuteBatch_Entry(EAState &state)
{
datetime times[];
double open_prices[], high_prices[], low_prices[], close_prices[];
if(!GetLatestOHLC(times, open_prices, high_prices, low_prices, close_prices,
PERIOD_H1, HISTORY_BARS))
{ Print("GetLatestOHLC(H1) failed."); return false; }
RecordOHLC("ohlc_H1.csv", times, open_prices, high_prices, low_prices, close_prices);
ExecuteBatchEntry();
state.load_target_flg = true;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool GetTrendState(EAState &state)
{
bool ProcessDone = CheckDoneFile(done_trend_file);
if(ProcessDone && g_ea.load_trend_flg)
{
int trend_state;
LoadTrendState(trend_state);
state.trend_state = trend_state;
Print("trend_state: ", state.trend_state);
g_ea.load_trend_flg = false;
g_ea.last_trend_update = TimeLocal();
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LoadTrendState(int &trend_state)
{
string filename = "trend_state.txt";
if(FileIsExist(filename))
{
int filehandle = FileOpen(filename, FILE_READ | FILE_TXT);
if(filehandle != INVALID_HANDLE)
{
string line = FileReadString(filehandle);
trend_state = (int)StringToInteger(line);
FileClose(filehandle);
}
else
{ Print("Failed to open trend_state.txt"); trend_state = 0; }
}
else
{ Print("trend_state.txt not found"); trend_state = 0; }
}
//+------------------------------------------------------------------+
//| ターゲット価格を取得する関数
//+------------------------------------------------------------------+
bool GetTargetPrices(EAState &state)
{
bool ProcessDone = CheckDoneFile(done_entry_file); // ←変更
if(ProcessDone && g_ea.load_target_flg) // ←変更
{
double target_prices[];
LoadTargetPrices(target_prices);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
// 先頭は res_chk
state.res_chk = (int)target_prices[0];
// ★ 1..4 の (en,tp,sl) を読む:合計12個
for(int t=1; t<=4; t++)
{
int base = 1 + (t-1)*3; // 1,4,7,10
state.en_price[t] = NormalizeDouble(target_prices[base + 0], digits);
state.tp_price[t] = NormalizeDouble(target_prices[base + 1], digits);
state.sl_price[t] = NormalizeDouble(target_prices[base + 2], digits);
}
// ログ(任意)
Print("target_prices: res=", state.res_chk,
" | T1 en=", state.en_price[1], " tp=", state.tp_price[1], " sl=", state.sl_price[1],
" | T2 en=", state.en_price[2], " tp=", state.tp_price[2], " sl=", state.sl_price[2],
" | T3 en=", state.en_price[3], " tp=", state.tp_price[3], " sl=", state.sl_price[3],
" | T4 en=", state.en_price[4], " tp=", state.tp_price[4], " sl=", state.sl_price[4]);
g_ea.load_target_flg = false; // ←変更
g_ea.last_target_update = TimeLocal(); // ←変更
}
return true;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| "target_prices.txt"を読み込む関数
//+------------------------------------------------------------------+
void LoadTargetPrices(double &target_prices[])
{
ArrayResize(target_prices, TARGET_SIZE);
string filename = "target_prices.txt";
if(FileIsExist(filename))
{
int filehandle = FileOpen(filename, FILE_READ | FILE_TXT);
if(filehandle != INVALID_HANDLE)
{
int i = 0;
while(!FileIsEnding(filehandle) && i < TARGET_SIZE)
{
string line = FileReadString(filehandle);
target_prices[i] = StringToDouble(line);
i++;
}
FileClose(filehandle);
}
else
{
Print("Failed to open file. Error code: ", GetLastError());
for(int i = 0; i < TARGET_SIZE; i++)
{
target_prices[i] = DEFAULT_TARGET_PRICE;
}
}
}
else
{
Print("File does not exist: ", filename);
for(int i = 0; i < TARGET_SIZE; i++)
{
target_prices[i] = DEFAULT_TARGET_PRICE;
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| エントリー注文を送信する関数 (1:buy-stop, 2:buy-limit, 3:sell-stop, 4:sell-limit)
//+------------------------------------------------------------------+
bool SendOrder(int orderType, double price, double tp, double sl)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.magic = magic_number;
request.symbol = _Symbol;
request.volume = lot_size;
request.deviation = slippage;
request.type_filling = GetOrderFillingPolicy(_Symbol);
request.price = NormalizeDouble(price, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
request.tp = NormalizeDouble(tp, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
request.sl = NormalizeDouble(sl, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
request.comment = RequestComment(orderType);
string orderTypeStr = "";
// 指値または逆指値注文
request.action = TRADE_ACTION_PENDING;
switch(orderType)
{
case 1: // 順張り買い (buy-stop)
request.type = ORDER_TYPE_BUY_STOP;
orderTypeStr = "buy-stop";
break;
case 2: // 逆張り買い (buy-limit)
request.type = ORDER_TYPE_BUY_LIMIT;
orderTypeStr = "buy-limit";
break;
case 3: // 順張り売り (sell-stop)
request.type = ORDER_TYPE_SELL_STOP;
orderTypeStr = "sell-stop";
break;
case 4: // 逆張り売り (sell-limit)
request.type = ORDER_TYPE_SELL_LIMIT;
orderTypeStr = "sell-limit";
break;
default: // 不正なorderType
Print(__FUNCTION__, ": invalid orderType=", orderType);
return false;
}
// 注文送信
if(!OrderSend(request, result))
{
Print(__FUNCTION__, ": OrderSend failed. err=", GetLastError());
return false;
}
// 注文成功確認
if(result.retcode == TRADE_RETCODE_PLACED ||
result.retcode == TRADE_RETCODE_DONE ||
result.retcode == TRADE_RETCODE_DONE_PARTIAL)
{
Print(request.comment + " - " + orderTypeStr + " order success (ticket=", result.order, ")");
return true;
}
else
{
Print(__FUNCTION__, ": OrderSend retcode=", result.retcode);
return false;
}
}
//+------------------------------------------------------------------+
//| 注文の執行ポリシーを取得する関数
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetOrderFillingPolicy(string symbol)
{
long fill_mode = SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
if((fill_mode & SYMBOL_FILLING_IOC) != 0)
return ORDER_FILLING_IOC;
if((fill_mode & SYMBOL_FILLING_FOK) != 0)
return ORDER_FILLING_FOK;
return ORDER_FILLING_RETURN;
}
//+------------------------------------------------------------------+
//| 注文コメント(ローカル時刻)を生成する関数(先頭に orderType を付与)
//+------------------------------------------------------------------+
string RequestComment(int orderType)
{
datetime localTime = TimeLocal();
string timeStr = TimeToString(localTime, TIME_DATE|TIME_MINUTES);
// 先頭に 1,2,3,4 を付ける(例: "1 | PC Time: 2026.02.14 19:05"
return IntegerToString(orderType) + " | PC Time: " + timeStr;
}
//+------------------------------------------------------------------+
//| 時間が経過したエントリー注文をキャンセルする関数
//+------------------------------------------------------------------+
bool CancelExpiredOrders()
{
bool result = false;
// 未決済注文の数を取得
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket)) // 注文を選択
{
if(OrderGetString(ORDER_SYMBOL) != _Symbol)
continue;
if(OrderGetInteger(ORDER_MAGIC) != magic_number)
continue;
datetime open_time = (datetime)OrderGetInteger(ORDER_TIME_SETUP);
int open_shift = GetBarShiftByTime(open_time, PERIOD_H1, -1); // H1
if(open_shift < 0)
continue; // 時刻解決できないなら触らない
if(open_shift >= ENTRY_H1_LIMIT) // H1本数(=1本 ≒ 1時間)
{
MqlTradeRequest request = {};
MqlTradeResult trade_result = {};
request.action=TRADE_ACTION_REMOVE; // 取引操作タイプ
request.order = ticket; // 注文チケット
if(!OrderSend(request, trade_result)) // 削除リクエスト送信
{
Print("Failed to delete order. Ticket: ", ticket, " Error: ", GetLastError());
}
else
{
if(trade_result.retcode == TRADE_RETCODE_DONE)
{
Print("Order canceled successfully due to a time limit. Ticket: ", ticket);
result = true; // 削除成功フラグ
}
else
{
Print("Order cancellation failed. Ticket: ", ticket, " Retcode: ", trade_result.retcode);
}
}
}
}
}
return result;
}
//+------------------------------------------------------------------+
//| 時間が経過したポジションをクローズする関数
//+------------------------------------------------------------------+
bool CloseExpiredPositions()
{
bool result = false;
// ポジションを逆順でループ
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
string position_symbol = PositionGetSymbol(i);
if(position_symbol!="")
{
// Magic Number とシンボルでフィルタリング
if(position_symbol != _Symbol)
continue;
if(PositionGetInteger(POSITION_MAGIC) == magic_number)
{
// ポジションのエントリー時刻を取得
datetime entry_time = (datetime)PositionGetInteger(POSITION_TIME);
int entry_shift = GetBarShiftByTime(entry_time, PERIOD_H1, -1);
if(entry_shift < 0)
continue;
if(entry_shift >= CLOSE_H1_LIMIT) // H1本数(=12本 ≒ 12時間)
{
MqlTradeRequest request = {};
MqlTradeResult trade_result = {};
// ポジションタイプに応じてリクエストを設定
int position_type = (int)PositionGetInteger(POSITION_TYPE);
request.action = TRADE_ACTION_DEAL;
request.position = PositionGetInteger(POSITION_TICKET); // ポジションのチケット番号
request.symbol = position_symbol; // シンボル
request.volume = PositionGetDouble(POSITION_VOLUME); // ポジションサイズ
request.price = (position_type == POSITION_TYPE_BUY)
? SymbolInfoDouble(position_symbol, SYMBOL_BID) // BUYの場合はBIDでクローズ
: SymbolInfoDouble(position_symbol, SYMBOL_ASK); // SELLの場合はASKでクローズ
request.deviation = slippage;
request.type = (position_type == POSITION_TYPE_BUY)
? ORDER_TYPE_SELL // BUYポジションをSELLでクローズ
: ORDER_TYPE_BUY; // SELLポジションをBUYでクローズ
request.type_filling = GetOrderFillingPolicy(position_symbol); // 注文執行ポリシー
request.magic = magic_number;
// 注文送信
if(!OrderSend(request, trade_result))
{
Print("Failed to close position. Ticket: ", request.position, " Error: ", GetLastError());
continue;
}
// 結果の確認
if(trade_result.retcode == TRADE_RETCODE_DONE || trade_result.retcode == TRADE_RETCODE_DONE_PARTIAL)
{
Print("Position closed successfully due to a time limit. Ticket: ", request.position);
result = true; // 少なくとも1つ成功した場合
}
else
{
Print("Failed to close position. Ticket: ", request.position, " Retcode: ", trade_result.retcode);
}
}
}
}
else
{
Print("Failed to select position at index ", i, ". Error: ", GetLastError());
}
}
return result;
}
//+------------------------------------------------------------------+
//| 指定された時間に最も近いバーのインデックスを返す関数
//+------------------------------------------------------------------+
int GetBarShiftByTime(datetime time, ENUM_TIMEFRAMES tf, int default_shift = -1)
{
if(time <= 0)
return default_shift;
int shift = iBarShift(_Symbol, tf, time, false); // 近傍バーで解決する
if(shift < 0)
return default_shift;
return shift;
}
//+------------------------------------------------------------------+
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+441
View File
@@ -0,0 +1,441 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.01"
#include <MyLib/Trading/SLTPManager.mqh>
#include <MyLib/Panel/SLTPManagerPanel.mqh>
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
// Windowsプロセス起動・終了確認用
#define CREATE_NO_WINDOW 0x08000000
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
#define SYNCHRONIZE 0x00100000
#define WAIT_OBJECT_0 0
#define WAIT_TIMEOUT 258
#define STILL_ACTIVE 259
struct STARTUPINFO_W
{
uint cb;
string lpReserved;
string lpDesktop;
string lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttribute;
uint dwFlags;
ushort wShowWindow;
ushort cbReserved2;
long lpReserved2;
long hStdInput;
long hStdOutput;
long hStdError;
};
struct PROCESS_INFORMATION
{
long hProcess;
long hThread;
uint dwProcessId;
uint dwThreadId;
};
#import "kernel32.dll"
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
int CloseHandle(long hObject);
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
// Python出力ファイル
string trend_state_file = "trend_state.txt";
string target_prices_file = "target_prices.txt";
// Python実行中を判定するための管理ファイル
string running_trend_file = "process_running_trend.txt";
string running_entry_file = "process_running_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 60; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
#define M15_CONFIRM_BARS 30
#define M15_MIN_ENTRY_ZONE_POINTS 10
#define M15_MIN_BODY_RATIO 0.25
#define M15_REJECTION_WICK_RATIO 0.35
#define ENTRY_RETRY_SECONDS 60
#define ENTRY_RETRY_LIMIT 10
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define DEFAULT_TARGET_PRICE 0.0
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
#define MARKET_LOW_VOL_RANGE 0
#define MARKET_HIGH_VOL_RANGE 1
#define MARKET_LOW_VOL_UP 2
#define MARKET_HIGH_VOL_UP 3
#define MARKET_LOW_VOL_DOWN 4
#define MARKET_HIGH_VOL_DOWN 5
#define MARKET_TECHNICAL_ERROR_STOP 6
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // H4 market_state0..5、6は技術エラー停止)を格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
// initial_order 用の初回処理フラグ
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
bool g_init_trend_pending = false;
bool g_init_entry_pending = false;
// H4/H1のバー更新状態
int g_pre_bars_H4 = 0;
int g_pre_bars_H1 = 0;
int g_pre_bars_M15 = 0;
bool g_bars_H1_check = false;
bool g_bars_M15_check = false;
// ティックごとの価格情報
struct TickContext
{
double ask;
double bid;
double spread;
double spread_points;
int digits;
};
// 外部Pythonプロセスの状態
struct ExternalProcessState
{
long handle;
uint process_id;
bool active;
bool exit_code_ready;
uint exit_code;
datetime started_at;
};
ExternalProcessState g_trend_process;
ExternalProcessState g_entry_process;
CSLTPManager g_sltp_manager;
CSLTPManagerPanel g_sltp_panel;
SLTPManagerPanelSettings g_sltp_settings;
bool g_sltp_settings_valid = false;
bool g_sltp_panel_created = false;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
/**
* @brief EA起動時の初期化処理を行います。
*
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
*/
int OnInit()
// プロセス完了ファイルと実行中ファイルの状態を初期化
{
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
g_init_trend_pending = (initial_order == 1);
g_init_entry_pending = (initial_order == 1);
if(!InitializeSLTPManager())
return INIT_FAILED;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 終了時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetExternalProcessState(g_trend_process);
ResetExternalProcessState(g_entry_process);
if(g_sltp_panel_created)
g_sltp_panel.Destroy(reason);
// Clear chart status text left by Comment() when the EA is removed.
Comment("");
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
/**
* @brief ティック受信ごとにEA全体の処理を制御します。
*
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
*/
void OnTick()
{
TickContext ctx;
if(!GetTickContext(ctx))
return;
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
ManageExpiredTrades();
// Existing-position protection stays active even while Python results are pending.
ManageSLTPPositions();
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
RecoverTimedOutPythonProcesses();
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
ProcessTrendUpdate(g_ea);
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
if(!IsTrendResultReady())
return;
RefreshTrendState(g_ea);
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
ProcessEntryUpdate(g_ea);
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
ProcessM15EntryTimingUpdate();
UpdateStatusComment(ctx);
// ここから下は新規注文に関する処理。
if(!IsSpreadAllowed(ctx))
return;
if(!IsEntryResultReady())
return;
RefreshTargetPrices(g_ea);
ProcessEntryDecisionIfNeeded(g_ea, ctx);
}
//+------------------------------------------------------------------+
//| SLTP manager panel and settings bridge
//+------------------------------------------------------------------+
string SLTPBoolText(const bool value)
{
return value ? "ON" : "OFF";
}
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
{
settings.manager_enabled = input_sltp_manager_enabled;
settings.use_breakeven = input_sltp_use_breakeven;
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
settings.use_active_trailing = input_sltp_use_active_trailing;
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
settings.active_step_move_pips = input_sltp_active_step_move_pips;
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
}
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
const bool print_summary)
{
g_sltp_settings_valid = false;
g_sltp_manager.SetMagicNumber((ulong)magic_number);
g_sltp_manager.SetSymbol(_Symbol);
g_sltp_manager.SetDeviationInPoints(slippage);
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
settings.breakeven_trigger_pips,
settings.breakeven_buffer_pips);
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
settings.elapsed_breakeven_hours,
settings.elapsed_breakeven_buffer_pips);
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
settings.active_breakeven_pips,
settings.active_stop_loss_offset_pips,
settings.active_step_trigger_pips,
settings.active_step_move_pips);
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
settings.tp_progress_trigger_percent,
settings.tp_progress_sl_lock_percent);
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
if(!g_sltp_manager.ValidateSettings())
{
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
return false;
}
g_sltp_settings = settings;
g_sltp_settings_valid = true;
if(print_summary)
{
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
" BE=", SLTPBoolText(settings.use_breakeven),
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
}
return true;
}
bool InitializeSLTPManager()
{
SLTPManagerPanelSettings initial_settings;
LoadSLTPInputSettings(initial_settings);
if(!ApplySLTPSettings(initial_settings, true))
return false;
g_sltp_panel.Init(g_sltp_settings);
if(input_sltp_show_panel)
{
if(!g_sltp_panel.CreatePanel())
{
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
return true;
}
g_sltp_panel.SetInitialValues();
g_sltp_panel_created = true;
}
return true;
}
void ManageSLTPPositions()
{
if(!g_sltp_settings_valid)
return;
if(!g_sltp_settings.manager_enabled)
return;
g_sltp_manager.ManagePositions();
g_sltp_manager.HighVolatilityLimit();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(!g_sltp_panel_created)
return;
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
{
if(!ApplySLTPSettings(candidate_settings, true))
Print("HIT SLTP panel apply failed. Please review panel values.");
}
}
// Function implementations are kept in project headers so the EA entry points stay compact.
#include <MyLib/Common/HITRuntimeController.mqh>
#include <MyLib/Signals/HITEntrySignal.mqh>
#include <MyLib/Common/HITExternalProcess.mqh>
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
#include <MyLib/Trading/HITTradeManager.mqh>
@@ -0,0 +1,440 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.01"
#include <MyLib/Trading/SLTPManager.mqh>
#include <MyLib/Panel/SLTPManagerPanel.mqh>
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
// Windowsプロセス起動・終了確認用
#define CREATE_NO_WINDOW 0x08000000
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
#define SYNCHRONIZE 0x00100000
#define WAIT_OBJECT_0 0
#define WAIT_TIMEOUT 258
#define STILL_ACTIVE 259
struct STARTUPINFO_W
{
uint cb;
string lpReserved;
string lpDesktop;
string lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttribute;
uint dwFlags;
ushort wShowWindow;
ushort cbReserved2;
long lpReserved2;
long hStdInput;
long hStdOutput;
long hStdError;
};
struct PROCESS_INFORMATION
{
long hProcess;
long hThread;
uint dwProcessId;
uint dwThreadId;
};
#import "kernel32.dll"
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
int CloseHandle(long hObject);
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
// Python出力ファイル
string trend_state_file = "trend_state.txt";
string target_prices_file = "target_prices.txt";
// Python実行中を判定するための管理ファイル
string running_trend_file = "process_running_trend.txt";
string running_entry_file = "process_running_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 60; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
#define M15_CONFIRM_BARS 30
#define M15_MIN_ENTRY_ZONE_POINTS 10
#define M15_MIN_BODY_RATIO 0.25
#define M15_REJECTION_WICK_RATIO 0.35
#define ENTRY_RETRY_SECONDS 60
#define ENTRY_RETRY_LIMIT 10
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define DEFAULT_TARGET_PRICE 0.0
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
#define MARKET_LOW_VOL_RANGE 0
#define MARKET_HIGH_VOL_RANGE 1
#define MARKET_LOW_VOL_UP 2
#define MARKET_HIGH_VOL_UP 3
#define MARKET_LOW_VOL_DOWN 4
#define MARKET_HIGH_VOL_DOWN 5
#define MARKET_TECHNICAL_ERROR_STOP 6
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // H4 market_state0..5、6は技術エラー停止)を格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
// initial_order 用の初回処理フラグ
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
bool g_init_trend_pending = false;
bool g_init_entry_pending = false;
// H4/H1のバー更新状態
int g_pre_bars_H4 = 0;
int g_pre_bars_H1 = 0;
int g_pre_bars_M15 = 0;
bool g_bars_H1_check = false;
bool g_bars_M15_check = false;
// ティックごとの価格情報
struct TickContext
{
double ask;
double bid;
double spread;
double spread_points;
int digits;
};
// 外部Pythonプロセスの状態
struct ExternalProcessState
{
long handle;
uint process_id;
bool active;
bool exit_code_ready;
uint exit_code;
datetime started_at;
};
ExternalProcessState g_trend_process;
ExternalProcessState g_entry_process;
CSLTPManager g_sltp_manager;
CSLTPManagerPanel g_sltp_panel;
SLTPManagerPanelSettings g_sltp_settings;
bool g_sltp_settings_valid = false;
bool g_sltp_panel_created = false;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
/**
* @brief EA起動時の初期化処理を行います。
*
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
*/
int OnInit()
// プロセス完了ファイルと実行中ファイルの状態を初期化
{
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
g_init_trend_pending = (initial_order == 1);
g_init_entry_pending = (initial_order == 1);
if(!InitializeSLTPManager())
return INIT_FAILED;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 終了時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetExternalProcessState(g_trend_process);
ResetExternalProcessState(g_entry_process);
if(g_sltp_panel_created)
g_sltp_panel.Destroy(reason);
// Clear chart status text left by Comment() when the EA is removed.
Comment("");
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
/**
* @brief ティック受信ごとにEA全体の処理を制御します。
*
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
*/
void OnTick()
{
TickContext ctx;
if(!GetTickContext(ctx))
return;
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
ManageExpiredTrades();
// Existing-position protection stays active even while Python results are pending.
ManageSLTPPositions();
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
RecoverTimedOutPythonProcesses();
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
ProcessTrendUpdate(g_ea);
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
if(!IsTrendResultReady())
return;
RefreshTrendState(g_ea);
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
ProcessEntryUpdate(g_ea);
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
ProcessM15EntryTimingUpdate();
UpdateStatusComment(ctx);
// ここから下は新規注文に関する処理。
if(!IsSpreadAllowed(ctx))
return;
if(!IsEntryResultReady())
return;
RefreshTargetPrices(g_ea);
ProcessEntryDecisionIfNeeded(g_ea, ctx);
}
//+------------------------------------------------------------------+
//| SLTP manager panel and settings bridge
//+------------------------------------------------------------------+
string SLTPBoolText(const bool value)
{
return value ? "ON" : "OFF";
}
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
{
settings.manager_enabled = input_sltp_manager_enabled;
settings.use_breakeven = input_sltp_use_breakeven;
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
settings.use_active_trailing = input_sltp_use_active_trailing;
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
settings.active_step_move_pips = input_sltp_active_step_move_pips;
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
}
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
const bool print_summary)
{
g_sltp_settings_valid = false;
g_sltp_manager.SetMagicNumber((ulong)magic_number);
g_sltp_manager.SetSymbol(_Symbol);
g_sltp_manager.SetDeviationInPoints(slippage);
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
settings.breakeven_trigger_pips,
settings.breakeven_buffer_pips);
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
settings.elapsed_breakeven_hours,
settings.elapsed_breakeven_buffer_pips);
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
settings.active_breakeven_pips,
settings.active_stop_loss_offset_pips,
settings.active_step_trigger_pips,
settings.active_step_move_pips);
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
settings.tp_progress_trigger_percent,
settings.tp_progress_sl_lock_percent);
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
if(!g_sltp_manager.ValidateSettings())
{
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
return false;
}
g_sltp_settings = settings;
g_sltp_settings_valid = true;
if(print_summary)
{
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
" BE=", SLTPBoolText(settings.use_breakeven),
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
}
return true;
}
bool InitializeSLTPManager()
{
SLTPManagerPanelSettings initial_settings;
LoadSLTPInputSettings(initial_settings);
if(!ApplySLTPSettings(initial_settings, true))
return false;
g_sltp_panel.Init(g_sltp_settings);
if(input_sltp_show_panel)
{
if(!g_sltp_panel.CreatePanel())
{
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
return true;
}
g_sltp_panel.SetInitialValues();
g_sltp_panel_created = true;
}
return true;
}
void ManageSLTPPositions()
{
if(!g_sltp_settings_valid)
return;
if(!g_sltp_settings.manager_enabled)
return;
g_sltp_manager.ManagePositions();
g_sltp_manager.HighVolatilityLimit();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(!g_sltp_panel_created)
return;
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
{
if(!ApplySLTPSettings(candidate_settings, true))
Print("HIT SLTP panel apply failed. Please review panel values.");
}
}
// Function implementations are kept in project headers so the EA entry points stay compact.
#include <MyLib/Common/HITRuntimeController.mqh>
#include <MyLib/Signals/HITEntrySignal.mqh>
#include <MyLib/Common/HITExternalProcess.mqh>
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
#include <MyLib/Trading/HITTradeManager.mqh>
+462
View File
@@ -0,0 +1,462 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.01"
#include <MyLib/Trading/SLTPManager.mqh>
#include <MyLib/Panel/SLTPManagerPanel.mqh>
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
// Windowsプロセス起動・終了確認用
#define CREATE_NO_WINDOW 0x08000000
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
#define SYNCHRONIZE 0x00100000
#define WAIT_OBJECT_0 0
#define WAIT_TIMEOUT 258
#define STILL_ACTIVE 259
struct STARTUPINFO_W
{
uint cb;
string lpReserved;
string lpDesktop;
string lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttribute;
uint dwFlags;
ushort wShowWindow;
ushort cbReserved2;
long lpReserved2;
long hStdInput;
long hStdOutput;
long hStdError;
};
struct PROCESS_INFORMATION
{
long hProcess;
long hThread;
uint dwProcessId;
uint dwThreadId;
};
#import "kernel32.dll"
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
int CloseHandle(long hObject);
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
// Python出力ファイル
string trend_state_file = "trend_state.txt";
string target_prices_file = "target_prices.txt";
string target_zones_file = "target_zones.txt";
// Python実行中を判定するための管理ファイル
string running_trend_file = "process_running_trend.txt";
string running_entry_file = "process_running_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
enum SplitLotMode
{
SPLIT_LOT_TOTAL = 0, // 総ロットをN分割
SPLIT_LOT_FIXED = 1 // 1注文あたり固定ロット
};
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 60; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
input int input_position_limit = 10; // 自EAの未約定注文+ポジション上限
input bool use_split_entry_zone = false; // H1予測ゾーンで分割エントリーする
input int split_entry_count = 3; // 分割エントリー本数(1..10)
input SplitLotMode split_lot_mode = SPLIT_LOT_TOTAL; // 分割ロット配分モード
input double split_total_lot_size = 0.09; // 総量分割モードの合計ロット
input double split_fixed_lot_size = 0.01; // 固定ロットモードの1注文ロット
input bool cancel_old_split_pending_on_new_zone = true; // 新ゾーン読込時に旧分割pendingを取消
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
input int input_entry_max_candidate_age_minutes = 120; // H1候補価格を新規発注に使う最大経過分数
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 2 // H1本数(=2時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
#define M15_CONFIRM_BARS 30
#define M15_MIN_ENTRY_ZONE_POINTS 10
#define M15_MIN_BODY_RATIO 0.25
#define M15_REJECTION_WICK_RATIO 0.35
#define ENTRY_RETRY_SECONDS 60
#define ENTRY_RETRY_LIMIT 10
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define TARGET_ZONE_SCHEMA_VERSION 2
#define DEFAULT_TARGET_PRICE 0.0
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
#define MARKET_LOW_VOL_RANGE 0
#define MARKET_HIGH_VOL_RANGE 1
#define MARKET_LOW_VOL_UP 2
#define MARKET_HIGH_VOL_UP 3
#define MARKET_LOW_VOL_DOWN 4
#define MARKET_HIGH_VOL_DOWN 5
#define MARKET_TECHNICAL_ERROR_STOP 6
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // H4 market_state0..5、6は技術エラー停止)を格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
int zone_res_chk; // 予測ゾーンが正しく取得できたか
string zone_candidate_id; // H1確定足由来の候補ID
double zone_low[5]; // 分割エントリー用ゾーン下限
double zone_high[5]; // 分割エントリー用ゾーン上限
double zone_tp[5]; // 分割エントリー用TP
double zone_sl[5]; // 分割エントリー用SL
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
// initial_order 用の初回処理フラグ
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
bool g_init_trend_pending = false;
bool g_init_entry_pending = false;
// H4/H1のバー更新状態
int g_pre_bars_H4 = 0;
int g_pre_bars_H1 = 0;
int g_pre_bars_M15 = 0;
bool g_bars_H1_check = false;
bool g_bars_M15_check = false;
// ティックごとの価格情報
struct TickContext
{
double ask;
double bid;
double spread;
double spread_points;
int digits;
};
// 外部Pythonプロセスの状態
struct ExternalProcessState
{
long handle;
uint process_id;
bool active;
bool exit_code_ready;
uint exit_code;
datetime started_at;
};
ExternalProcessState g_trend_process;
ExternalProcessState g_entry_process;
CSLTPManager g_sltp_manager;
CSLTPManagerPanel g_sltp_panel;
SLTPManagerPanelSettings g_sltp_settings;
bool g_sltp_settings_valid = false;
bool g_sltp_panel_created = false;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
/**
* @brief EA起動時の初期化処理を行います。
*
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
*/
int OnInit()
// プロセス完了ファイルと実行中ファイルの状態を初期化
{
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
g_init_trend_pending = (initial_order == 1);
g_init_entry_pending = (initial_order == 1);
if(!InitializeSLTPManager())
return INIT_FAILED;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 終了時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetExternalProcessState(g_trend_process);
ResetExternalProcessState(g_entry_process);
if(g_sltp_panel_created)
g_sltp_panel.Destroy(reason);
// Clear chart status text left by Comment() when the EA is removed.
Comment("");
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
/**
* @brief ティック受信ごとにEA全体の処理を制御します。
*
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
*/
void OnTick()
{
TickContext ctx;
if(!GetTickContext(ctx))
return;
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
ManageExpiredTrades();
// Existing-position protection stays active even while Python results are pending.
ManageSLTPPositions();
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
RecoverTimedOutPythonProcesses();
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
ProcessTrendUpdate(g_ea);
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
if(!IsTrendResultReady())
return;
RefreshTrendState(g_ea);
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
ProcessEntryUpdate(g_ea);
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
ProcessM15EntryTimingUpdate();
UpdateStatusComment(ctx);
// ここから下は新規注文に関する処理。
if(!IsSpreadAllowed(ctx))
return;
if(!IsEntryResultReady())
return;
RefreshTargetPrices(g_ea);
ProcessEntryDecisionIfNeeded(g_ea, ctx);
}
//+------------------------------------------------------------------+
//| SLTP manager panel and settings bridge
//+------------------------------------------------------------------+
string SLTPBoolText(const bool value)
{
return value ? "ON" : "OFF";
}
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
{
settings.manager_enabled = input_sltp_manager_enabled;
settings.use_breakeven = input_sltp_use_breakeven;
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
settings.use_active_trailing = input_sltp_use_active_trailing;
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
settings.active_step_move_pips = input_sltp_active_step_move_pips;
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
}
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
const bool print_summary)
{
g_sltp_settings_valid = false;
g_sltp_manager.SetMagicNumber((ulong)magic_number);
g_sltp_manager.SetSymbol(_Symbol);
g_sltp_manager.SetDeviationInPoints(slippage);
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
settings.breakeven_trigger_pips,
settings.breakeven_buffer_pips);
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
settings.elapsed_breakeven_hours,
settings.elapsed_breakeven_buffer_pips);
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
settings.active_breakeven_pips,
settings.active_stop_loss_offset_pips,
settings.active_step_trigger_pips,
settings.active_step_move_pips);
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
settings.tp_progress_trigger_percent,
settings.tp_progress_sl_lock_percent);
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
if(!g_sltp_manager.ValidateSettings())
{
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
return false;
}
g_sltp_settings = settings;
g_sltp_settings_valid = true;
if(print_summary)
{
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
" BE=", SLTPBoolText(settings.use_breakeven),
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
}
return true;
}
bool InitializeSLTPManager()
{
SLTPManagerPanelSettings initial_settings;
LoadSLTPInputSettings(initial_settings);
if(!ApplySLTPSettings(initial_settings, true))
return false;
g_sltp_panel.Init(g_sltp_settings);
if(input_sltp_show_panel)
{
if(!g_sltp_panel.CreatePanel())
{
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
return true;
}
g_sltp_panel.SetInitialValues();
g_sltp_panel_created = true;
}
return true;
}
void ManageSLTPPositions()
{
if(!g_sltp_settings_valid)
return;
if(!g_sltp_settings.manager_enabled)
return;
g_sltp_manager.ManagePositions();
g_sltp_manager.HighVolatilityLimit();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(!g_sltp_panel_created)
return;
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
{
if(!ApplySLTPSettings(candidate_settings, true))
Print("HIT SLTP panel apply failed. Please review panel values.");
}
}
// Function implementations are kept in project headers so the EA entry points stay compact.
#include <MyLib/Common/HITRuntimeController.mqh>
#include <MyLib/Signals/HITEntrySignal.mqh>
#include <MyLib/Common/HITExternalProcess.mqh>
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
#include <MyLib/Trading/HITTradeManager.mqh>
@@ -0,0 +1,441 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.01"
#include <MyLib/Trading/SLTPManager.mqh>
#include <MyLib/Panel/SLTPManagerPanel.mqh>
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
// Windowsプロセス起動・終了確認用
#define CREATE_NO_WINDOW 0x08000000
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
#define SYNCHRONIZE 0x00100000
#define WAIT_OBJECT_0 0
#define WAIT_TIMEOUT 258
#define STILL_ACTIVE 259
struct STARTUPINFO_W
{
uint cb;
string lpReserved;
string lpDesktop;
string lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttribute;
uint dwFlags;
ushort wShowWindow;
ushort cbReserved2;
long lpReserved2;
long hStdInput;
long hStdOutput;
long hStdError;
};
struct PROCESS_INFORMATION
{
long hProcess;
long hThread;
uint dwProcessId;
uint dwThreadId;
};
#import "kernel32.dll"
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
int CloseHandle(long hObject);
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
// Python出力ファイル
string trend_state_file = "trend_state.txt";
string target_prices_file = "target_prices.txt";
// Python実行中を判定するための管理ファイル
string running_trend_file = "process_running_trend.txt";
string running_entry_file = "process_running_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 60; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
#define M15_CONFIRM_BARS 30
#define M15_MIN_ENTRY_ZONE_POINTS 10
#define M15_MIN_BODY_RATIO 0.25
#define M15_REJECTION_WICK_RATIO 0.35
#define ENTRY_RETRY_SECONDS 60
#define ENTRY_RETRY_LIMIT 10
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define DEFAULT_TARGET_PRICE 0.0
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
#define MARKET_LOW_VOL_RANGE 0
#define MARKET_HIGH_VOL_RANGE 1
#define MARKET_LOW_VOL_UP 2
#define MARKET_HIGH_VOL_UP 3
#define MARKET_LOW_VOL_DOWN 4
#define MARKET_HIGH_VOL_DOWN 5
#define MARKET_TECHNICAL_ERROR_STOP 6
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // H4 market_state0..5、6は技術エラー停止)を格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
// initial_order 用の初回処理フラグ
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
bool g_init_trend_pending = false;
bool g_init_entry_pending = false;
// H4/H1のバー更新状態
int g_pre_bars_H4 = 0;
int g_pre_bars_H1 = 0;
int g_pre_bars_M15 = 0;
bool g_bars_H1_check = false;
bool g_bars_M15_check = false;
// ティックごとの価格情報
struct TickContext
{
double ask;
double bid;
double spread;
double spread_points;
int digits;
};
// 外部Pythonプロセスの状態
struct ExternalProcessState
{
long handle;
uint process_id;
bool active;
bool exit_code_ready;
uint exit_code;
datetime started_at;
};
ExternalProcessState g_trend_process;
ExternalProcessState g_entry_process;
CSLTPManager g_sltp_manager;
CSLTPManagerPanel g_sltp_panel;
SLTPManagerPanelSettings g_sltp_settings;
bool g_sltp_settings_valid = false;
bool g_sltp_panel_created = false;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
/**
* @brief EA起動時の初期化処理を行います。
*
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
*/
int OnInit()
// プロセス完了ファイルと実行中ファイルの状態を初期化
{
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
g_init_trend_pending = (initial_order == 1);
g_init_entry_pending = (initial_order == 1);
if(!InitializeSLTPManager())
return INIT_FAILED;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 終了時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetExternalProcessState(g_trend_process);
ResetExternalProcessState(g_entry_process);
if(g_sltp_panel_created)
g_sltp_panel.Destroy(reason);
// Clear chart status text left by Comment() when the EA is removed.
Comment("");
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
/**
* @brief ティック受信ごとにEA全体の処理を制御します。
*
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
*/
void OnTick()
{
TickContext ctx;
if(!GetTickContext(ctx))
return;
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
ManageExpiredTrades();
// Existing-position protection stays active even while Python results are pending.
ManageSLTPPositions();
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
RecoverTimedOutPythonProcesses();
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
ProcessTrendUpdate(g_ea);
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
if(!IsTrendResultReady())
return;
RefreshTrendState(g_ea);
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
ProcessEntryUpdate(g_ea);
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
ProcessM15EntryTimingUpdate();
UpdateStatusComment(ctx);
// ここから下は新規注文に関する処理。
if(!IsSpreadAllowed(ctx))
return;
if(!IsEntryResultReady())
return;
RefreshTargetPrices(g_ea);
ProcessEntryDecisionIfNeeded(g_ea, ctx);
}
//+------------------------------------------------------------------+
//| SLTP manager panel and settings bridge
//+------------------------------------------------------------------+
string SLTPBoolText(const bool value)
{
return value ? "ON" : "OFF";
}
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
{
settings.manager_enabled = input_sltp_manager_enabled;
settings.use_breakeven = input_sltp_use_breakeven;
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
settings.use_active_trailing = input_sltp_use_active_trailing;
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
settings.active_step_move_pips = input_sltp_active_step_move_pips;
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
}
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
const bool print_summary)
{
g_sltp_settings_valid = false;
g_sltp_manager.SetMagicNumber((ulong)magic_number);
g_sltp_manager.SetSymbol(_Symbol);
g_sltp_manager.SetDeviationInPoints(slippage);
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
settings.breakeven_trigger_pips,
settings.breakeven_buffer_pips);
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
settings.elapsed_breakeven_hours,
settings.elapsed_breakeven_buffer_pips);
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
settings.active_breakeven_pips,
settings.active_stop_loss_offset_pips,
settings.active_step_trigger_pips,
settings.active_step_move_pips);
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
settings.tp_progress_trigger_percent,
settings.tp_progress_sl_lock_percent);
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
if(!g_sltp_manager.ValidateSettings())
{
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
return false;
}
g_sltp_settings = settings;
g_sltp_settings_valid = true;
if(print_summary)
{
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
" BE=", SLTPBoolText(settings.use_breakeven),
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
}
return true;
}
bool InitializeSLTPManager()
{
SLTPManagerPanelSettings initial_settings;
LoadSLTPInputSettings(initial_settings);
if(!ApplySLTPSettings(initial_settings, true))
return false;
g_sltp_panel.Init(g_sltp_settings);
if(input_sltp_show_panel)
{
if(!g_sltp_panel.CreatePanel())
{
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
return true;
}
g_sltp_panel.SetInitialValues();
g_sltp_panel_created = true;
}
return true;
}
void ManageSLTPPositions()
{
if(!g_sltp_settings_valid)
return;
if(!g_sltp_settings.manager_enabled)
return;
g_sltp_manager.ManagePositions();
g_sltp_manager.HighVolatilityLimit();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(!g_sltp_panel_created)
return;
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
{
if(!ApplySLTPSettings(candidate_settings, true))
Print("HIT SLTP panel apply failed. Please review panel values.");
}
}
// Function implementations are kept in project headers so the EA entry points stay compact.
#include <MyLib/Common/HITRuntimeController.mqh>
#include <MyLib/Signals/HITEntrySignal.mqh>
#include <MyLib/Common/HITExternalProcess.mqh>
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
#include <MyLib/Trading/HITTradeManager.mqh>
@@ -0,0 +1,441 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.01"
#include <MyLib/Trading/SLTPManager.mqh>
#include <MyLib/Panel/SLTPManagerPanel.mqh>
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
// Windowsプロセス起動・終了確認用
#define CREATE_NO_WINDOW 0x08000000
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
#define SYNCHRONIZE 0x00100000
#define WAIT_OBJECT_0 0
#define WAIT_TIMEOUT 258
#define STILL_ACTIVE 259
struct STARTUPINFO_W
{
uint cb;
string lpReserved;
string lpDesktop;
string lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttribute;
uint dwFlags;
ushort wShowWindow;
ushort cbReserved2;
long lpReserved2;
long hStdInput;
long hStdOutput;
long hStdError;
};
struct PROCESS_INFORMATION
{
long hProcess;
long hThread;
uint dwProcessId;
uint dwThreadId;
};
#import "kernel32.dll"
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
int CloseHandle(long hObject);
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
// Python出力ファイル
string trend_state_file = "trend_state.txt";
string target_prices_file = "target_prices.txt";
// Python実行中を判定するための管理ファイル
string running_trend_file = "process_running_trend.txt";
string running_entry_file = "process_running_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 60; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
#define M15_CONFIRM_BARS 30
#define M15_MIN_ENTRY_ZONE_POINTS 10
#define M15_MIN_BODY_RATIO 0.25
#define M15_REJECTION_WICK_RATIO 0.35
#define ENTRY_RETRY_SECONDS 60
#define ENTRY_RETRY_LIMIT 10
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define DEFAULT_TARGET_PRICE 0.0
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
#define MARKET_LOW_VOL_RANGE 0
#define MARKET_HIGH_VOL_RANGE 1
#define MARKET_LOW_VOL_UP 2
#define MARKET_HIGH_VOL_UP 3
#define MARKET_LOW_VOL_DOWN 4
#define MARKET_HIGH_VOL_DOWN 5
#define MARKET_TECHNICAL_ERROR_STOP 6
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // H4 market_state0..5、6は技術エラー停止)を格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
// initial_order 用の初回処理フラグ
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
bool g_init_trend_pending = false;
bool g_init_entry_pending = false;
// H4/H1のバー更新状態
int g_pre_bars_H4 = 0;
int g_pre_bars_H1 = 0;
int g_pre_bars_M15 = 0;
bool g_bars_H1_check = false;
bool g_bars_M15_check = false;
// ティックごとの価格情報
struct TickContext
{
double ask;
double bid;
double spread;
double spread_points;
int digits;
};
// 外部Pythonプロセスの状態
struct ExternalProcessState
{
long handle;
uint process_id;
bool active;
bool exit_code_ready;
uint exit_code;
datetime started_at;
};
ExternalProcessState g_trend_process;
ExternalProcessState g_entry_process;
CSLTPManager g_sltp_manager;
CSLTPManagerPanel g_sltp_panel;
SLTPManagerPanelSettings g_sltp_settings;
bool g_sltp_settings_valid = false;
bool g_sltp_panel_created = false;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
/**
* @brief EA起動時の初期化処理を行います。
*
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
*/
int OnInit()
// プロセス完了ファイルと実行中ファイルの状態を初期化
{
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
g_init_trend_pending = (initial_order == 1);
g_init_entry_pending = (initial_order == 1);
if(!InitializeSLTPManager())
return INIT_FAILED;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 終了時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetExternalProcessState(g_trend_process);
ResetExternalProcessState(g_entry_process);
if(g_sltp_panel_created)
g_sltp_panel.Destroy(reason);
// Clear chart status text left by Comment() when the EA is removed.
Comment("");
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
/**
* @brief ティック受信ごとにEA全体の処理を制御します。
*
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
*/
void OnTick()
{
TickContext ctx;
if(!GetTickContext(ctx))
return;
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
ManageExpiredTrades();
// Existing-position protection stays active even while Python results are pending.
ManageSLTPPositions();
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
RecoverTimedOutPythonProcesses();
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
ProcessTrendUpdate(g_ea);
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
if(!IsTrendResultReady())
return;
RefreshTrendState(g_ea);
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
ProcessEntryUpdate(g_ea);
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
ProcessM15EntryTimingUpdate();
UpdateStatusComment(ctx);
// ここから下は新規注文に関する処理。
if(!IsSpreadAllowed(ctx))
return;
if(!IsEntryResultReady())
return;
RefreshTargetPrices(g_ea);
ProcessEntryDecisionIfNeeded(g_ea, ctx);
}
//+------------------------------------------------------------------+
//| SLTP manager panel and settings bridge
//+------------------------------------------------------------------+
string SLTPBoolText(const bool value)
{
return value ? "ON" : "OFF";
}
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
{
settings.manager_enabled = input_sltp_manager_enabled;
settings.use_breakeven = input_sltp_use_breakeven;
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
settings.use_active_trailing = input_sltp_use_active_trailing;
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
settings.active_step_move_pips = input_sltp_active_step_move_pips;
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
}
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
const bool print_summary)
{
g_sltp_settings_valid = false;
g_sltp_manager.SetMagicNumber((ulong)magic_number);
g_sltp_manager.SetSymbol(_Symbol);
g_sltp_manager.SetDeviationInPoints(slippage);
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
settings.breakeven_trigger_pips,
settings.breakeven_buffer_pips);
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
settings.elapsed_breakeven_hours,
settings.elapsed_breakeven_buffer_pips);
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
settings.active_breakeven_pips,
settings.active_stop_loss_offset_pips,
settings.active_step_trigger_pips,
settings.active_step_move_pips);
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
settings.tp_progress_trigger_percent,
settings.tp_progress_sl_lock_percent);
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
if(!g_sltp_manager.ValidateSettings())
{
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
return false;
}
g_sltp_settings = settings;
g_sltp_settings_valid = true;
if(print_summary)
{
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
" BE=", SLTPBoolText(settings.use_breakeven),
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
}
return true;
}
bool InitializeSLTPManager()
{
SLTPManagerPanelSettings initial_settings;
LoadSLTPInputSettings(initial_settings);
if(!ApplySLTPSettings(initial_settings, true))
return false;
g_sltp_panel.Init(g_sltp_settings);
if(input_sltp_show_panel)
{
if(!g_sltp_panel.CreatePanel())
{
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
return true;
}
g_sltp_panel.SetInitialValues();
g_sltp_panel_created = true;
}
return true;
}
void ManageSLTPPositions()
{
if(!g_sltp_settings_valid)
return;
if(!g_sltp_settings.manager_enabled)
return;
g_sltp_manager.ManagePositions();
g_sltp_manager.HighVolatilityLimit();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(!g_sltp_panel_created)
return;
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
{
if(!ApplySLTPSettings(candidate_settings, true))
Print("HIT SLTP panel apply failed. Please review panel values.");
}
}
// Function implementations are kept in project headers so the EA entry points stay compact.
#include <MyLib/Common/HITRuntimeController.mqh>
#include <MyLib/Signals/HITEntrySignal.mqh>
#include <MyLib/Common/HITExternalProcess.mqh>
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
#include <MyLib/Trading/HITTradeManager.mqh>
@@ -0,0 +1,462 @@
//+------------------------------------------------------------------+
//| HIT_EA.mq5 |
//| Copyright 2026, nanpin-martin.com |
//| https://www.nanpin-martin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.01"
#include <MyLib/Trading/SLTPManager.mqh>
#include <MyLib/Panel/SLTPManagerPanel.mqh>
//+------------------------------------------------------------------+
//| バッチファイル実行用の設定
//+------------------------------------------------------------------+
// Windowsプロセス起動・終了確認用
#define CREATE_NO_WINDOW 0x08000000
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
#define SYNCHRONIZE 0x00100000
#define WAIT_OBJECT_0 0
#define WAIT_TIMEOUT 258
#define STILL_ACTIVE 259
struct STARTUPINFO_W
{
uint cb;
string lpReserved;
string lpDesktop;
string lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttribute;
uint dwFlags;
ushort wShowWindow;
ushort cbReserved2;
long lpReserved2;
long hStdInput;
long hStdOutput;
long hStdError;
};
struct PROCESS_INFORMATION
{
long hProcess;
long hThread;
uint dwProcessId;
uint dwThreadId;
};
#import "kernel32.dll"
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
int CloseHandle(long hObject);
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
#import
// バッチファイルのパス
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
// プロセス完了ファイルの設定
string done_trend_file = "process_done_trend.txt";
string done_entry_file = "process_done_entry.txt";
// Python出力ファイル
string trend_state_file = "trend_state.txt";
string target_prices_file = "target_prices.txt";
string target_zones_file = "target_zones.txt";
// Python実行中を判定するための管理ファイル
string running_trend_file = "process_running_trend.txt";
string running_entry_file = "process_running_entry.txt";
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| インプットの設定
//+------------------------------------------------------------------+
enum SplitLotMode
{
SPLIT_LOT_TOTAL = 0, // 総ロットをN分割
SPLIT_LOT_FIXED = 1 // 1注文あたり固定ロット
};
//--- 入力パラメータ
input double lot_size = 0.01; // ロット数
input double spread_limit = 60; // 許容スプレッド(point)
input int magic_number = 10001; // マジックナンバー
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
input int input_position_limit = 10; // 自EAの未約定注文+ポジション上限
input bool use_split_entry_zone = false; // H1予測ゾーンで分割エントリーする
input int split_entry_count = 3; // 分割エントリー本数(1..10)
input SplitLotMode split_lot_mode = SPLIT_LOT_TOTAL; // 分割ロット配分モード
input double split_total_lot_size = 0.09; // 総量分割モードの合計ロット
input double split_fixed_lot_size = 0.01; // 固定ロットモードの1注文ロット
input bool cancel_old_split_pending_on_new_zone = true; // 新ゾーン読込時に旧分割pendingを取消
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
ulong slippage = 10; // スリッページ
//--- 主要な定数・設定
#define POSITION_LIMIT 48
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
#define HISTORY_BARS 72
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
#define M15_CONFIRM_BARS 30
#define M15_MIN_ENTRY_ZONE_POINTS 10
#define M15_MIN_BODY_RATIO 0.25
#define M15_REJECTION_WICK_RATIO 0.35
#define ENTRY_RETRY_SECONDS 60
#define ENTRY_RETRY_LIMIT 10
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
#define TARGET_SIZE 13
#define TARGET_ZONE_SCHEMA_VERSION 2
#define DEFAULT_TARGET_PRICE 0.0
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
#define MARKET_LOW_VOL_RANGE 0
#define MARKET_HIGH_VOL_RANGE 1
#define MARKET_LOW_VOL_UP 2
#define MARKET_HIGH_VOL_UP 3
#define MARKET_LOW_VOL_DOWN 4
#define MARKET_HIGH_VOL_DOWN 5
#define MARKET_TECHNICAL_ERROR_STOP 6
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| EAの状態をまとめる構造体
//+------------------------------------------------------------------+
struct EAState
{
int trend_state; // H4 market_state0..5、6は技術エラー停止)を格納する変数
int res_chk; // GPTの回答が正しく取得できたか
double en_price[5]; // エントリー基準価格
double tp_price[5]; // 利益確定価格
double sl_price[5]; // ロスカット基準価格
int zone_res_chk; // 予測ゾーンが正しく取得できたか
string zone_candidate_id; // H1確定足由来の候補ID
double zone_low[5]; // 分割エントリー用ゾーン下限
double zone_high[5]; // 分割エントリー用ゾーン上限
double zone_tp[5]; // 分割エントリー用TP
double zone_sl[5]; // 分割エントリー用SL
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
int chk_cnt; // エントリー判定の試行回数
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
datetime last_chk;
};
EAState g_ea; // EA全体の状態をここで管理
// initial_order 用の初回処理フラグ
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
bool g_init_trend_pending = false;
bool g_init_entry_pending = false;
// H4/H1のバー更新状態
int g_pre_bars_H4 = 0;
int g_pre_bars_H1 = 0;
int g_pre_bars_M15 = 0;
bool g_bars_H1_check = false;
bool g_bars_M15_check = false;
// ティックごとの価格情報
struct TickContext
{
double ask;
double bid;
double spread;
double spread_points;
int digits;
};
// 外部Pythonプロセスの状態
struct ExternalProcessState
{
long handle;
uint process_id;
bool active;
bool exit_code_ready;
uint exit_code;
datetime started_at;
};
ExternalProcessState g_trend_process;
ExternalProcessState g_entry_process;
CSLTPManager g_sltp_manager;
CSLTPManagerPanel g_sltp_panel;
SLTPManagerPanelSettings g_sltp_settings;
bool g_sltp_settings_valid = false;
bool g_sltp_panel_created = false;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
/**
* @brief EA起動時の初期化処理を行います。
*
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
*/
int OnInit()
// プロセス完了ファイルと実行中ファイルの状態を初期化
{
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
g_init_trend_pending = (initial_order == 1);
g_init_entry_pending = (initial_order == 1);
if(!InitializeSLTPManager())
return INIT_FAILED;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 終了時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetExternalProcessState(g_trend_process);
ResetExternalProcessState(g_entry_process);
if(g_sltp_panel_created)
g_sltp_panel.Destroy(reason);
// Clear chart status text left by Comment() when the EA is removed.
Comment("");
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
/**
* @brief ティック受信ごとにEA全体の処理を制御します。
*
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
*/
void OnTick()
{
TickContext ctx;
if(!GetTickContext(ctx))
return;
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
ManageExpiredTrades();
// Existing-position protection stays active even while Python results are pending.
ManageSLTPPositions();
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
RecoverTimedOutPythonProcesses();
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
ProcessTrendUpdate(g_ea);
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
if(!IsTrendResultReady())
return;
RefreshTrendState(g_ea);
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
ProcessEntryUpdate(g_ea);
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
ProcessM15EntryTimingUpdate();
UpdateStatusComment(ctx);
// ここから下は新規注文に関する処理。
if(!IsSpreadAllowed(ctx))
return;
if(!IsEntryResultReady())
return;
RefreshTargetPrices(g_ea);
ProcessEntryDecisionIfNeeded(g_ea, ctx);
}
//+------------------------------------------------------------------+
//| SLTP manager panel and settings bridge
//+------------------------------------------------------------------+
string SLTPBoolText(const bool value)
{
return value ? "ON" : "OFF";
}
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
{
settings.manager_enabled = input_sltp_manager_enabled;
settings.use_breakeven = input_sltp_use_breakeven;
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
settings.use_active_trailing = input_sltp_use_active_trailing;
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
settings.active_step_move_pips = input_sltp_active_step_move_pips;
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
}
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
const bool print_summary)
{
g_sltp_settings_valid = false;
g_sltp_manager.SetMagicNumber((ulong)magic_number);
g_sltp_manager.SetSymbol(_Symbol);
g_sltp_manager.SetDeviationInPoints(slippage);
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
settings.breakeven_trigger_pips,
settings.breakeven_buffer_pips);
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
settings.elapsed_breakeven_hours,
settings.elapsed_breakeven_buffer_pips);
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
settings.active_breakeven_pips,
settings.active_stop_loss_offset_pips,
settings.active_step_trigger_pips,
settings.active_step_move_pips);
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
settings.tp_progress_trigger_percent,
settings.tp_progress_sl_lock_percent);
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
if(!g_sltp_manager.ValidateSettings())
{
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
return false;
}
g_sltp_settings = settings;
g_sltp_settings_valid = true;
if(print_summary)
{
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
" BE=", SLTPBoolText(settings.use_breakeven),
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
}
return true;
}
bool InitializeSLTPManager()
{
SLTPManagerPanelSettings initial_settings;
LoadSLTPInputSettings(initial_settings);
if(!ApplySLTPSettings(initial_settings, true))
return false;
g_sltp_panel.Init(g_sltp_settings);
if(input_sltp_show_panel)
{
if(!g_sltp_panel.CreatePanel())
{
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
return true;
}
g_sltp_panel.SetInitialValues();
g_sltp_panel_created = true;
}
return true;
}
void ManageSLTPPositions()
{
if(!g_sltp_settings_valid)
return;
if(!g_sltp_settings.manager_enabled)
return;
g_sltp_manager.ManagePositions();
g_sltp_manager.HighVolatilityLimit();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(!g_sltp_panel_created)
return;
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
{
if(!ApplySLTPSettings(candidate_settings, true))
Print("HIT SLTP panel apply failed. Please review panel values.");
}
}
// Function implementations are kept in project headers so the EA entry points stay compact.
#include <MyLib/Common/HITRuntimeController.mqh>
#include <MyLib/Signals/HITEntrySignal.mqh>
#include <MyLib/Common/HITExternalProcess.mqh>
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
#include <MyLib/Trading/HITTradeManager.mqh>
+395
View File
@@ -0,0 +1,395 @@
//+------------------------------------------------------------------+
//| TradingPanel EA entry point
//+------------------------------------------------------------------+
#include <MyLib/Trading/TradingPanelTradingManagers.mqh>
#include <MyLib/Panel/TradingPanelPanel.mqh>
#define POSITION_TYPE_ALL ((ENUM_POSITION_TYPE) - 1) // フィルタ無し
// トータルブレークイーブン
#define BE_BUY "BreakEvenBuy"
#define BE_SELL "BreakEvenSell"
//--- カテゴリ1:取引設定
input group "■ 取引設定";
input int exit_time_interval = 4; // 時間制限クローズまでの保有時間(時間)
//--- カテゴリ2:基本設定
input group "■ 基本設定";
input ulong slippage = 10; // スリッページ
input int magic_number = 10001; // マジックナンバー
input group "■ SLTP設定: Common";
input double take_profit_pips = 150.0; // TP設定値
input double default_sl = 100.0; // SL初期値
input double stop_offset_pips = 10.0; // ストップロスオフセット(pips)
input group "■ SLTP設定: TRAIL";
input bool enable_breakeven = true; // ブレークイーブンを有効化
input double breakeven_pips = 30.0; // ブレークイーブン判定利幅
input double stop_loss_offset_pips = 5.0; // 建値からのマージン
input double step_trigger_pips = 10.0; // トレール更新トリガーpips
input double step_move_pips = 8.0; // トレール更新pips
input double tp_edit_pips = 10.0; // TP更新初期pips
//--- カテゴリ4:フィルター設定
input group "■ レンジフィルター設定";
input double range_pips = 80.0; // レンジ幅pips1
//--- カテゴリ5:時間設定
input group "■ 取引時間設定";
input bool isTradingTimeEnabled = true; // 取引時間を制限
input int TradeStartHour = 4; // 開始時間GMT(時間)
input int TradeStartMin = 0; // 開始時間GMT(分)
input int TradeEndHour = 23; // 終了時間GMT(時間)
input int TradeEndMin = 0; // 終了時間GMT(分)
int TimerPeriod_sec = 1; // n 秒ごとに OnTimer
bool wasInTradingTime = false;
bool beforeTradingInitDone = false;
bool afterTradingInitDone = false;
bool timelimit_exit = true; // 時間制限クローズ 初期状態
bool input_lock = true; // 時間制限クローズ 初期状態
// --------------------------------------------------------------
// EAとの共有用グローバル変数
// --------------------------------------------------------------
int gl_exitTimeIntervalInSeconds = exit_time_interval * 3600;
double gl_breakeven_pips = breakeven_pips;
double gl_stop_loss_offset_pips = stop_loss_offset_pips;
double gl_step_trigger_pips = step_trigger_pips;
double gl_step_move_pips = step_move_pips;
double gl_default_sl_pips = default_sl;
double gl_take_profit_pips = take_profit_pips;
double gl_stop_offset_pips = stop_offset_pips;
int buy_position = 0; // CountPositions() で随時更新
int sell_position = 0;
datetime last_buy_time = 0;
datetime last_sell_time = 0;
bool buy_total_be_flg = false;
bool sell_total_be_flg = false;
//+------------------------------------------------------------------+
//| トータルのブレークイーブン用変数
//+------------------------------------------------------------------+
bool InpShowBuyLine = true; // 買いのブレークイーブンライン
bool InpShowSellLine = true; // 売りのブレークイーブンライン
double BufferPips = 2.0; // BE バッファ
int LabelShiftBars = 60; // 何本前のバーにラベルを置くか
double LabelOffsetPips = 4.0; // ライン ⇔ ラベルの距離
CTradingPanelStopManager g_stop_manager;
CTradingPanelPositionManager g_position_manager;
CTradingPanelBreakEvenLineManager g_break_even_manager;
CTradingPanelPanel g_panel;
//+------------------------------------------------------------------+
//| 起動時の処理
//+------------------------------------------------------------------+
int OnInit()
{
g_stop_manager.Init(_Symbol, (ulong)magic_number, slippage);
g_position_manager.Init(_Symbol, (ulong)magic_number, slippage);
g_break_even_manager.Init(_Symbol, (ulong)magic_number);
g_panel.Init(exit_time_interval,
range_pips,
breakeven_pips,
stop_loss_offset_pips,
step_trigger_pips,
step_move_pips,
default_sl,
take_profit_pips,
tp_edit_pips,
stop_offset_pips);
// EA設定変更用のパネルを表示
if (!g_panel.CreatePanel(input_lock))
return INIT_FAILED;
g_panel.SetInitialValues();
// Backfill missing initial stops for existing matching positions.
g_position_manager.ApplyInitialStops(gl_default_sl_pips, gl_take_profit_pips);
// タイマーをセット
EventSetTimer(TimerPeriod_sec);
return (INIT_SUCCEEDED); // 成功コードを明示しておく
}
//+------------------------------------------------------------------+
//| 削除時の処理
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
// EA適用後のプロパティで変更すると、EAを再読み込みする。
g_panel.Destroy(reason);
// トータルブレークイーブンラインを削除
if (InpShowBuyLine)
g_break_even_manager.DeleteLine(BE_BUY);
if (InpShowSellLine)
g_break_even_manager.DeleteLine(BE_SELL);
// EAが削除された際にコメントを消す
Comment("");
}
//+------------------------------------------------------------------+
//| タイマー処理
//+------------------------------------------------------------------+
void OnTimer()
{
// 時間状態の変化を検知
HandleTradingTimeTransition();
// ティックが少ない時間帯でも時間制限クローズを監視する。
g_position_manager.CloseTimedPositions(POSITION_TYPE_BUY, ORDER_TYPE_SELL,
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
g_position_manager.CloseTimedPositions(POSITION_TYPE_SELL, ORDER_TYPE_BUY,
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
// 取引時間が指定時間内か確認
if (!IsTradingTime())
return;
}
//+------------------------------------------------------------------+
//| ティック毎の処理
//+------------------------------------------------------------------+
void OnTick()
{
// 時間状態の変化を検知
HandleTradingTimeTransition();
// EAの設定を画面上に表示
DisplayEAValues();
// 時間制限クローズは取引時間フィルターとは独立して実行する。
g_position_manager.CloseTimedPositions(POSITION_TYPE_BUY, ORDER_TYPE_SELL,
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
g_position_manager.CloseTimedPositions(POSITION_TYPE_SELL, ORDER_TYPE_BUY,
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
// 取引時間が指定時間内か確認
if (!IsTradingTime())
return;
// レート急伸SL
g_stop_manager.HighVolatilityLimit();
//------------------------------------
// ブレークイーブン / トレールストップ監視
//------------------------------------
g_stop_manager.ManageStops(enable_breakeven,
gl_breakeven_pips,
gl_stop_loss_offset_pips,
gl_step_trigger_pips,
gl_step_move_pips);
g_break_even_manager.ManageBuy(buy_total_be_flg && InpShowBuyLine,
buy_total_be_flg,
BufferPips,
LabelShiftBars,
LabelOffsetPips,
gl_default_sl_pips,
g_stop_manager);
g_break_even_manager.ManageSell(sell_total_be_flg && InpShowSellLine,
sell_total_be_flg,
BufferPips,
LabelShiftBars,
LabelOffsetPips,
gl_default_sl_pips,
g_stop_manager);
// 保有ポジションの確認
buy_position = g_position_manager.CountPositions(POSITION_TYPE_BUY, magic_number);
sell_position = g_position_manager.CountPositions(POSITION_TYPE_SELL, magic_number);
}
//+------------------------------------------------------------------+
//| 取引時間を指定する関数
//+------------------------------------------------------------------+
bool IsTradingTime()
{
// 取引時間が有効化されていない場合、常にtrueを返す
if (!isTradingTimeEnabled)
{
return true;
}
MqlDateTime structTime;
TimeCurrent(structTime);
structTime.sec = 0;
structTime.hour = TradeStartHour;
structTime.min = TradeStartMin;
datetime timeStart = StructToTime(structTime);
structTime.hour = TradeEndHour;
structTime.min = TradeEndMin;
datetime timeEnd = StructToTime(structTime);
// エラーチェック
if (TradeStartHour >= TradeEndHour && TradeStartMin >= TradeEndMin)
{
Print("Error: Invalid Time input");
return false;
}
// 現在の時間を取得
datetime now = TimeCurrent();
// 時間内かどうかをチェック
return (now >= timeStart && now < timeEnd);
}
//+------------------------------------------------------------------+
//| 取引時間内外に状態が変化した時の初期化処理
//+------------------------------------------------------------------+
void HandleTradingTimeTransition()
{
bool nowInTradingTime = IsTradingTime();
// --- 時間内に入った瞬間 ---
if (nowInTradingTime && !wasInTradingTime)
{
if (!beforeTradingInitDone)
{
Print("取引時間内 初期化処理");
beforeTradingInitDone = true;
}
afterTradingInitDone = false;
}
// --- 時間外に出た瞬間 ---
if (!nowInTradingTime && wasInTradingTime)
{
if (!afterTradingInitDone)
{
Print("取引時間外 初期化処理");
afterTradingInitDone = true;
}
beforeTradingInitDone = false;
}
wasInTradingTime = nowInTradingTime;
}
//+------------------------------------------------------------------+
//| pipsを価格に換算する関数
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// 出力処理を関数にまとめる
//+------------------------------------------------------------------+
void DisplayEAValues()
{
Comment("\n",
"ブレークイーブン: ", (int)gl_breakeven_pips, "pips\n",
"時間制限クローズ: ", timelimit_exit ? "ON" : "OFF",
" | 保有時間: ", gl_exitTimeIntervalInSeconds / 3600, "時間\n",
"------------------------------------------------------------------------------------\n");
}
// +------------------------------------------------------------------+
// | チャートイベントのハンドラ
// +------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
ENUM_POSITION_TYPE tp_side = POSITION_TYPE_ALL;
double tp_adjust_pips = 0.0;
if (g_panel.HandleChartEvent(id,
lparam,
dparam,
sparam,
exit_time_interval,
range_pips,
breakeven_pips,
stop_loss_offset_pips,
step_trigger_pips,
step_move_pips,
default_sl,
take_profit_pips,
tp_edit_pips,
stop_offset_pips,
timelimit_exit,
input_lock,
buy_total_be_flg,
sell_total_be_flg,
gl_exitTimeIntervalInSeconds,
gl_breakeven_pips,
gl_stop_loss_offset_pips,
gl_step_trigger_pips,
gl_step_move_pips,
gl_default_sl_pips,
gl_take_profit_pips,
gl_stop_offset_pips,
tp_side,
tp_adjust_pips))
{
g_position_manager.AdjustTakeProfit(tp_adjust_pips, tp_side);
}
}
//------------------------------------------------------------------
// 取引イベントコールバック(再エントリーを防止)
//------------------------------------------------------------------
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
bool recalc_needed = false; // ポジション再集計フラグ
// 1) Deal が追加された(約定)
if (trans.type == TRADE_TRANSACTION_DEAL_ADD)
{
recalc_needed = true;
//---- Deal 詳細を取得 --------------------------------------
if (HistoryDealSelect(trans.deal)) // Deal を選択
{
ENUM_DEAL_REASON deal_reason = (ENUM_DEAL_REASON)
HistoryDealGetInteger(trans.deal, DEAL_REASON);
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)
HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
//==== ★ クローズ条件(手動 or SL/TP ===================
bool is_close =
(deal_entry == DEAL_ENTRY_OUT) &&
(deal_reason == DEAL_REASON_CLIENT || // 手動決済
deal_reason == DEAL_REASON_MOBILE || // スマホアプリ決済
deal_reason == DEAL_REASON_WEB || // WEB版決済
deal_reason == DEAL_REASON_EXPERT || // EAのタイマー決済
deal_reason == DEAL_REASON_SL || // SL ヒット(部分/全量とも)
deal_reason == DEAL_REASON_TP); // TP ヒット(部分/全量とも)
if (is_close)
{
Print("Position closed (", EnumToString(deal_reason), ") — EA waits for next prediction.");
}
}
}
// 2) サーバ側でポジション内容が変更 (数量減少・SL変更等)
else if (trans.type == TRADE_TRANSACTION_POSITION)
{
recalc_needed = true;
}
// 3) 必要に応じてポジション再集計
if (recalc_needed)
{
g_position_manager.CheckPositions(buy_position, sell_position, last_buy_time, last_sell_time);
g_position_manager.ApplyInitialStops(gl_default_sl_pips, gl_take_profit_pips);
}
}
+182
View File
@@ -0,0 +1,182 @@
//+------------------------------------------------------------------+
//| Array.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CArray |
//| Purpose: Base class of dynamic arrays. |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CArray : public CObject
{
protected:
int m_step_resize; // increment size of the array
int m_data_total; // number of elements
int m_data_max; // maximmum size of the array without memory reallocation
int m_sort_mode; // mode of array sorting
public:
CArray(void);
~CArray(void);
//--- methods of access to protected data
int Step(void) const { return(m_step_resize); }
bool Step(const int step);
int Total(void) const { return(m_data_total); }
int Available(void) const { return(m_data_max-m_data_total); }
int Max(void) const { return(m_data_max); }
bool IsSorted(const int mode=0) const { return(m_sort_mode==mode); }
int SortMode(void) const { return(m_sort_mode); }
//--- cleaning method
void Clear(void) { m_data_total=0; }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- sorting method
void Sort(const int mode=0);
protected:
virtual void QuickSort(int beg,int end,const int mode=0) { m_sort_mode=-1; }
//--- templates for methods of searching for minimum and maximum
template<typename T>
int Minimum(const T &data[],const int start,const int count) const;
template<typename T>
int Maximum(const T &data[],const int start,const int count) const;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArray::CArray(void) : m_step_resize(16),
m_data_total(0),
m_data_max(0),
m_sort_mode(-1)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArray::~CArray(void)
{
}
//+------------------------------------------------------------------+
//| Method Set for variable m_step_resize |
//+------------------------------------------------------------------+
bool CArray::Step(const int step)
{
//--- check
if(step>0)
{
m_step_resize=step;
return(true);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Sorting an array in ascending order |
//+------------------------------------------------------------------+
void CArray::Sort(const int mode)
{
//--- check
if(IsSorted(mode))
return;
m_sort_mode=mode;
if(m_data_total<=1)
return;
//--- sort
QuickSort(0,m_data_total-1,mode);
}
//+------------------------------------------------------------------+
//| Writing header of array to file |
//+------------------------------------------------------------------+
bool CArray::Save(const int file_handle)
{
//--- check handle
if(file_handle!=INVALID_HANDLE)
{
//--- write start marker - 0xFFFFFFFFFFFFFFFF
if(FileWriteLong(file_handle,-1)==sizeof(long))
{
//--- write array type
if(FileWriteInteger(file_handle,Type(),INT_VALUE)==INT_VALUE)
return(true);
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Reading header of array from file |
//+------------------------------------------------------------------+
bool CArray::Load(const int file_handle)
{
//--- check handle
if(file_handle!=INVALID_HANDLE)
{
//--- read and check start marker - 0xFFFFFFFFFFFFFFFF
if(FileReadLong(file_handle)==-1)
{
//--- read and check array type
if(FileReadInteger(file_handle,INT_VALUE)==Type())
return(true);
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Find minimum of array |
//+------------------------------------------------------------------+
template<typename T>
int CArray::Minimum(const T &data[],const int start,const int count) const
{
int real_count;
//--- check for empty array
if(m_data_total<1)
{
SetUserError(ERR_USER_ARRAY_IS_EMPTY);
return(-1);
}
//--- check for start is out of range
if(start<0 || start>=m_data_total)
{
SetUserError(ERR_USER_ITEM_NOT_FOUND);
return(-1);
}
//--- compute count of elements
real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count;
#ifdef __MQL5__
return(ArrayMinimum(data,start,real_count));
#else
return(ArrayMinimum(data,real_count,start));
#endif
}
//+------------------------------------------------------------------+
//| Find maximum of array |
//+------------------------------------------------------------------+
template<typename T>
int CArray::Maximum(const T &data[],const int start,const int count) const
{
int real_count;
//--- check for empty array
if(m_data_total<1)
{
SetUserError(ERR_USER_ARRAY_IS_EMPTY);
return(-1);
}
//--- check for start is out of range
if(start<0 || start>=m_data_total)
{
SetUserError(ERR_USER_ITEM_NOT_FOUND);
return(-1);
}
//--- compute count of elements
real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count;
#ifdef __MQL5__
return(ArrayMaximum(data,start,real_count));
#else
return(ArrayMaximum(data,real_count,start));
#endif
}
//+------------------------------------------------------------------+
+770
View File
@@ -0,0 +1,770 @@
//+------------------------------------------------------------------+
//| ArrayChar.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayChar. |
//| Purpose: Class of dynamic array of char type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayChar : public CArray
{
protected:
char m_data[]; // data array
public:
CArrayChar(void);
~CArrayChar(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_CHAR); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const char element);
bool AddArray(const char &src[]);
bool AddArray(const CArrayChar *src);
bool Insert(const char element,const int pos);
bool InsertArray(const char &src[],const int pos);
bool InsertArray(const CArrayChar *src,const int pos);
bool AssignArray(const char &src[]);
bool AssignArray(const CArrayChar *src);
//--- method of access to the array
char At(const int index) const;
char operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const char element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const char &array[]) const;
bool CompareArray(const CArrayChar *array) const;
//--- methods for working with the sorted array
bool InsertSort(const char element);
int Search(const char element) const;
int SearchGreat(const char element) const;
int SearchLess(const char element) const;
int SearchGreatOrEqual(const char element) const;
int SearchLessOrEqual(const char element) const;
int SearchFirst(const char element) const;
int SearchLast(const char element) const;
int SearchLinear(const char element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const char element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayChar::CArrayChar(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayChar::~CArrayChar(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayChar::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayChar::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayChar::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayChar::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayChar::Add(const char element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayChar::AddArray(const char &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayChar::AddArray(const CArrayChar *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayChar::Insert(const char element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayChar::InsertArray(const char &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayChar::InsertArray(const CArrayChar *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayChar::AssignArray(const char &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayChar::AssignArray(const CArrayChar *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
char CArrayChar::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(CHAR_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayChar::Update(const int index,const char element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayChar::Shift(const int index,const int shift)
{
char tmp_char;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_char=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_char;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayChar::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayChar::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayChar::CompareArray(const char &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayChar::CompareArray(const CArrayChar *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayChar::QuickSort(int beg,int end,const int mode)
{
int i,j;
char p_char;
char t_char;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_char=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_char)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_char)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_char=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_char;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayChar::InsertSort(const char element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayChar::SearchLinear(const char element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::QuickSearch(const char element) const
{
int i,j,m=-1;
char t_char;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_char=m_data[m];
if(t_char==element)
break;
if(t_char>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::Search(const char element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::SearchGreat(const char element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayChar::SearchLess(const char element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::SearchGreatOrEqual(const char element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::SearchLessOrEqual(const char element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::SearchFirst(const char element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayChar::SearchLast(const char element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayChar::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],CHAR_VALUE)!=CHAR_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayChar::Load(const int file_handle)
{
int i,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=(char)FileReadInteger(file_handle,CHAR_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+770
View File
@@ -0,0 +1,770 @@
//+------------------------------------------------------------------+
//| ArrayColor.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayColor. |
//| Purpose: Class of dynamic array of color type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayColor : public CArray
{
protected:
color m_data[]; // data array
public:
CArrayColor(void);
~CArrayColor(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_COLOR); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const color element);
bool AddArray(const color &src[]);
bool AddArray(const CArrayColor *src);
bool Insert(const color element,const int pos);
bool InsertArray(const color &src[],const int pos);
bool InsertArray(const CArrayColor *src,const int pos);
bool AssignArray(const color &src[]);
bool AssignArray(const CArrayColor *src);
//--- method of access to the array
color At(const int index) const;
color operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods change
bool Update(const int index,const color element);
bool Shift(const int index,const int shift);
//--- methods for deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for compare arrays
bool CompareArray(const color &array[]) const;
bool CompareArray(const CArrayColor *array) const;
//--- methods for working with the sorted array
bool InsertSort(const color element);
int Search(const color element) const;
int SearchGreat(const color element) const;
int SearchLess(const color element) const;
int SearchGreatOrEqual(const color element) const;
int SearchLessOrEqual(const color element) const;
int SearchFirst(const color element) const;
int SearchLast(const color element) const;
int SearchLinear(const color element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const color element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayColor::CArrayColor(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayColor::~CArrayColor(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayColor::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayColor::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayColor::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayColor::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayColor::Add(const color element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayColor::AddArray(const color &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayColor::AddArray(const CArrayColor *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayColor::Insert(const color element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayColor::InsertArray(const color &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayColor::InsertArray(const CArrayColor *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayColor::AssignArray(const color &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayColor::AssignArray(const CArrayColor *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
color CArrayColor::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(clrNONE);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayColor::Update(const int index,const color element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayColor::Shift(const int index,const int shift)
{
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
color tmp_long=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_long;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayColor::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayColor::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayColor::CompareArray(const color &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayColor::CompareArray(const CArrayColor *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayColor::QuickSort(int beg,int end,const int mode)
{
//--- check
if(beg<0 || end<0)
return;
//--- sort
int i=beg;
int j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
color p_long=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_long)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_long)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
color tmp=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=tmp;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayColor::InsertSort(const color element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayColor::SearchLinear(const color element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::QuickSearch(const color element) const
{
int i,j,m=-1;
long t_long;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_long=m_data[m];
if(t_long==element)
break;
if(t_long>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::Search(const color element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::SearchGreat(const color element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayColor::SearchLess(const color element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::SearchGreatOrEqual(const color element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::SearchLessOrEqual(const color element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::SearchFirst(const color element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayColor::SearchLast(const color element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayColor::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayColor::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=(color)FileReadLong(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+770
View File
@@ -0,0 +1,770 @@
//+------------------------------------------------------------------+
//| ArrayDatetime.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayDatetime. |
//| Purpose: Class of dynamic array of datetime type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayDatetime : public CArray
{
protected:
datetime m_data[]; // data array
public:
CArrayDatetime(void);
~CArrayDatetime(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_DATETIME); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const datetime element);
bool AddArray(const datetime &src[]);
bool AddArray(const CArrayDatetime *src);
bool Insert(const datetime element,const int pos);
bool InsertArray(const datetime &src[],const int pos);
bool InsertArray(const CArrayDatetime *src,const int pos);
bool AssignArray(const datetime &src[]);
bool AssignArray(const CArrayDatetime *src);
//--- method of access to the array
datetime At(const int index) const;
datetime operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods change
bool Update(const int index,const datetime element);
bool Shift(const int index,const int shift);
//--- methods for deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for compare arrays
bool CompareArray(const datetime &array[]) const;
bool CompareArray(const CArrayDatetime *array) const;
//--- methods for working with the sorted array
bool InsertSort(const datetime element);
int Search(const datetime element) const;
int SearchGreat(const datetime element) const;
int SearchLess(const datetime element) const;
int SearchGreatOrEqual(const datetime element) const;
int SearchLessOrEqual(const datetime element) const;
int SearchFirst(const datetime element) const;
int SearchLast(const datetime element) const;
int SearchLinear(const datetime element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const datetime element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayDatetime::CArrayDatetime(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayDatetime::~CArrayDatetime(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayDatetime::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayDatetime::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayDatetime::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayDatetime::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayDatetime::Add(const datetime element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayDatetime::AddArray(const datetime &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayDatetime::AddArray(const CArrayDatetime *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayDatetime::Insert(const datetime element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayDatetime::InsertArray(const datetime &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayDatetime::InsertArray(const CArrayDatetime *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayDatetime::AssignArray(const datetime &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayDatetime::AssignArray(const CArrayDatetime *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
datetime CArrayDatetime::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(LONG_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayDatetime::Update(const int index,const datetime element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayDatetime::Shift(const int index,const int shift)
{
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
datetime tmp_long=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_long;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayDatetime::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayDatetime::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayDatetime::CompareArray(const datetime &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayDatetime::CompareArray(const CArrayDatetime *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayDatetime::QuickSort(int beg,int end,const int mode)
{
//--- check
if(beg<0 || end<0)
return;
//--- sort
int i=beg;
int j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
datetime p_long=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_long)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_long)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
datetime tmp=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=tmp;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayDatetime::InsertSort(const datetime element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchLinear(const datetime element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::QuickSearch(const datetime element) const
{
int i,j,m=-1;
long t_long;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_long=m_data[m];
if(t_long==element)
break;
if(t_long>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::Search(const datetime element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchGreat(const datetime element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchLess(const datetime element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchGreatOrEqual(const datetime element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchLessOrEqual(const datetime element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchFirst(const datetime element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDatetime::SearchLast(const datetime element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayDatetime::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayDatetime::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=(datetime)FileReadLong(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+777
View File
@@ -0,0 +1,777 @@
//+------------------------------------------------------------------+
//| ArrayDouble.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayDouble. |
//| Puprpose: Class of dynamic array of double type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayDouble : public CArray
{
protected:
double m_data[]; // data array
double m_delta; // search tolerance
public:
CArrayDouble(void);
~CArrayDouble(void);
//--- methods of access to protected data
void Delta(const double delta) { m_delta=MathAbs(delta); }
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_DOUBLE); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const double element);
bool AddArray(const double &src[]);
bool AddArray(const CArrayDouble *src);
bool Insert(const double element,const int pos);
bool InsertArray(const double &src[],const int pos);
bool InsertArray(const CArrayDouble *src,const int pos);
bool AssignArray(const double &src[]);
bool AssignArray(const CArrayDouble *src);
//--- method of access to the array
double At(const int index) const;
double operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const double element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const double &array[]) const;
bool CompareArray(const CArrayDouble *array) const;
//--- methods for working with a sorted array
bool InsertSort(const double element);
int Search(const double element) const;
int SearchGreat(const double element) const;
int SearchLess(const double element) const;
int SearchGreatOrEqual(const double element) const;
int SearchLessOrEqual(const double element) const;
int SearchFirst(const double element) const;
int SearchLast(const double element) const;
int SearchLinear(const double element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const double element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayDouble::CArrayDouble(void) : m_delta(0.0)
{
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayDouble::~CArrayDouble(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayDouble::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayDouble::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayDouble::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayDouble::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayDouble::Add(const double element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayDouble::AddArray(const double &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayDouble::AddArray(const CArrayDouble *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayDouble::Insert(const double element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayDouble::InsertArray(const double &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayDouble::InsertArray(const CArrayDouble *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayDouble::AssignArray(const double &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayDouble::AssignArray(const CArrayDouble *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
double CArrayDouble::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(DBL_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayDouble::Update(const int index,const double element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayDouble::Shift(const int index,const int shift)
{
double tmp_double;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_double=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_double;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayDouble::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayDouble::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayDouble::CompareArray(const double &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayDouble::CompareArray(const CArrayDouble *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayDouble::QuickSort(int beg,int end,const int mode)
{
int i,j;
double p_double,t_double;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_double=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_double)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_double)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_double=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_double;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayDouble::InsertSort(const double element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchLinear(const double element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(MathAbs(m_data[i]-element)<=m_delta)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::QuickSearch(const double element) const
{
int i,j,m=-1;
double t_double;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_double=m_data[m];
//--- compare with delta
if(MathAbs(t_double-element)<=m_delta)
break;
if(t_double>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::Search(const double element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
//--- compare with delta
if(MathAbs(m_data[pos]-element)<=m_delta)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchGreat(const double element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
//--- compare with delta
while(m_data[pos]<=element+m_delta)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchLess(const double element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
//--- compare with delta
while(m_data[pos]>=element-m_delta)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchGreatOrEqual(const double element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchLessOrEqual(const double element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchFirst(const double element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
//--- compare with delta
while(MathAbs(m_data[pos]-element)<=m_delta)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayDouble::SearchLast(const double element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
//--- compare with delta
while(MathAbs(m_data[pos]-element)<=m_delta)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayDouble::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteDouble(file_handle,m_data[i])!=sizeof(double))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayDouble::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadDouble(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+777
View File
@@ -0,0 +1,777 @@
//+------------------------------------------------------------------+
//| ArrayFloat.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayFloat. |
//| Purpose: Class of dynamic array of float type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayFloat : public CArray
{
protected:
float m_data[]; // data array
float m_delta; // search tolerance
public:
CArrayFloat(void);
~CArrayFloat(void);
//--- methods of access to protected data
void Delta(const float delta) { m_delta=(float)MathAbs(delta); }
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_FLOAT); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const float element);
bool AddArray(const float &src[]);
bool AddArray(const CArrayFloat *src);
bool Insert(const float element,const int pos);
bool InsertArray(const float &src[],const int pos);
bool InsertArray(const CArrayFloat *src,const int pos);
bool AssignArray(const float &src[]);
bool AssignArray(const CArrayFloat *src);
//--- method of access to the array
float At(const int index) const;
float operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const float element);
bool Shift(const int index,const int shift);
//--- methods deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const float &array[]) const;
bool CompareArray(const CArrayFloat *array) const;
//--- methods for working with the sorted array
bool InsertSort(const float element);
int Search(const float element) const;
int SearchGreat(const float element) const;
int SearchLess(const float element) const;
int SearchGreatOrEqual(const float element) const;
int SearchLessOrEqual(const float element) const;
int SearchFirst(const float element) const;
int SearchLast(const float element) const;
int SearchLinear(const float element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const float element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayFloat::CArrayFloat(void) : m_delta(0.0)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayFloat::~CArrayFloat(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayFloat::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayFloat::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayFloat::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayFloat::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayFloat::Add(const float element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayFloat::AddArray(const float &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayFloat::AddArray(const CArrayFloat *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayFloat::Insert(const float element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayFloat::InsertArray(const float &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayFloat::InsertArray(const CArrayFloat *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayFloat::AssignArray(const float &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayFloat::AssignArray(const CArrayFloat *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
float CArrayFloat::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(FLT_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayFloat::Update(const int index,const float element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayFloat::Shift(const int index,const int shift)
{
float tmp_float;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_float=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_float;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayFloat::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayFloat::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayFloat::CompareArray(const float &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayFloat::CompareArray(const CArrayFloat *array) const
{
//--- check
if(!CheckPointer(array)) return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayFloat::QuickSort(int beg,int end,const int mode)
{
int i,j;
float p_float,t_float;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_float=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_float)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_float)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_float=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_float;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayFloat::InsertSort(const float element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchLinear(const float element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(MathAbs(m_data[i]-element)<=m_delta)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::QuickSearch(const float element) const
{
int i,j,m=-1;
float t_float;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_float=m_data[m];
//--- compare with delta
if(MathAbs(t_float-element)<=m_delta)
break;
if(t_float>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::Search(const float element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
//--- compare with delta
if(MathAbs(m_data[pos]-element)<=m_delta)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchGreat(const float element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
//--- compare with delta
while(m_data[pos]<=element+m_delta)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchLess(const float element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
//--- compare with delta
while(m_data[pos]>=element-m_delta)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchGreatOrEqual(const float element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchLessOrEqual(const float element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchFirst(const float element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
//--- compare with delta
while(MathAbs(m_data[pos]-element)<=m_delta)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayFloat::SearchLast(const float element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
//--- compare with delta
while(MathAbs(m_data[pos]-element)<=m_delta)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayFloat::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteFloat(file_handle,m_data[i])!=sizeof(float))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayFloat::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadFloat(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+769
View File
@@ -0,0 +1,769 @@
//+------------------------------------------------------------------+
//| ArrayInt.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayInt. |
//| Puprose: Class of dynamic array of int type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayInt : public CArray
{
protected:
int m_data[]; // data array
public:
CArrayInt(void);
~CArrayInt(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_INT); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const int element);
bool AddArray(const int &src[]);
bool AddArray(const CArrayInt *src);
bool Insert(const int element,const int pos);
bool InsertArray(const int &src[],const int pos);
bool InsertArray(const CArrayInt *src,const int pos);
bool AssignArray(const int &src[]);
bool AssignArray(const CArrayInt *src);
//--- method of access to the array
int At(const int index) const;
int operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const int element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const int &array[]) const;
bool CompareArray(const CArrayInt *array) const;
//--- methods for working with the sorted array
bool InsertSort(const int element);
int Search(const int element) const;
int SearchGreat(const int element) const;
int SearchLess(const int element) const;
int SearchGreatOrEqual(const int element) const;
int SearchLessOrEqual(const int element) const;
int SearchFirst(const int element) const;
int SearchLast(const int element) const;
int SearchLinear(const int element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const int element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayInt::CArrayInt(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayInt::~CArrayInt(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayInt::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayInt::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayInt::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayInt::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayInt::Add(const int element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayInt::AddArray(const int &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayInt::AddArray(const CArrayInt *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::Insert(const int element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::InsertArray(const int &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::InsertArray(const CArrayInt *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayInt::AssignArray(const int &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayInt::AssignArray(const CArrayInt *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
int CArrayInt::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(INT_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::Update(const int index,const int element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayInt::Shift(const int index,const int shift)
{
int tmp_int;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_int=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_int;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayInt::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayInt::CompareArray(const int &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayInt::CompareArray(const CArrayInt *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayInt::QuickSort(int beg,int end,const int mode)
{
int i,j;
int p_int,t_int;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_int=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_int)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_int)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_int=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_int;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayInt::InsertSort(const int element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLinear(const int element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::QuickSearch(const int element) const
{
int i,j,m=-1;
int t_int;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_int=m_data[m];
if(t_int==element)
break;
if(t_int>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::Search(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchGreat(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLess(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchGreatOrEqual(const int element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLessOrEqual(const int element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchFirst(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLast(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayInt::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],INT_VALUE)!=INT_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayInt::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadInteger(file_handle,INT_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+769
View File
@@ -0,0 +1,769 @@
//+------------------------------------------------------------------+
//| ArrayLong.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayLong. |
//| Purpose: Class of dynamic array of long type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayLong : public CArray
{
protected:
long m_data[]; // data array
public:
CArrayLong(void);
~CArrayLong(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_LONG); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const long element);
bool AddArray(const long &src[]);
bool AddArray(const CArrayLong *src);
bool Insert(const long element,const int pos);
bool InsertArray(const long &src[],const int pos);
bool InsertArray(const CArrayLong *src,const int pos);
bool AssignArray(const long &src[]);
bool AssignArray(const CArrayLong *src);
//--- method of access to the array
long At(const int index) const;
long operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods change
bool Update(const int index,const long element);
bool Shift(const int index,const int shift);
//--- methods for deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for compare arrays
bool CompareArray(const long &array[]) const;
bool CompareArray(const CArrayLong *array) const;
//--- methods for working with the sorted array
bool InsertSort(const long element);
int Search(const long element) const;
int SearchGreat(const long element) const;
int SearchLess(const long element) const;
int SearchGreatOrEqual(const long element) const;
int SearchLessOrEqual(const long element) const;
int SearchFirst(const long element) const;
int SearchLast(const long element) const;
int SearchLinear(const long element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const long element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayLong::CArrayLong(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayLong::~CArrayLong(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayLong::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayLong::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayLong::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayLong::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayLong::Add(const long element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayLong::AddArray(const long &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayLong::AddArray(const CArrayLong *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::Insert(const long element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::InsertArray(const long &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::InsertArray(const CArrayLong *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayLong::AssignArray(const long &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayLong::AssignArray(const CArrayLong *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
long CArrayLong::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(LONG_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::Update(const int index,const long element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayLong::Shift(const int index,const int shift)
{
long tmp_long;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_long=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_long;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayLong::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayLong::CompareArray(const long &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayLong::CompareArray(const CArrayLong *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayLong::QuickSort(int beg,int end,const int mode)
{
int i,j;
long p_long,t_long;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_long=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_long)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_long)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_long=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_long;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayLong::InsertSort(const long element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLinear(const long element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::QuickSearch(const long element) const
{
int i,j,m=-1;
long t_long;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_long=m_data[m];
if(t_long==element)
break;
if(t_long>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::Search(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchGreat(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLess(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchGreatOrEqual(const long element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLessOrEqual(const long element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchFirst(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLast(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayLong::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayLong::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadLong(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+759
View File
@@ -0,0 +1,759 @@
//+------------------------------------------------------------------+
//| ArrayObj.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayObj. |
//| Puprose: Class of dynamic array of pointers to instances |
//| of the CObject class and its derivatives. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayObj : public CArray
{
protected:
CObject *m_data[]; // data array
bool m_free_mode; // flag of necessity of "physical" deletion of object
public:
CArrayObj(void);
~CArrayObj(void);
//--- methods of access to protected data
bool FreeMode(void) const { return(m_free_mode); }
void FreeMode(const bool mode) { m_free_mode=mode; }
//--- method of identifying the object
virtual int Type(void) const { return(0x7778); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- method of creating an element of array
virtual bool CreateElement(const int index) { return(false); }
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(CObject *element);
bool AddArray(const CArrayObj *src);
bool Insert(CObject *element,const int pos);
bool InsertArray(const CArrayObj *src,const int pos);
bool AssignArray(const CArrayObj *src);
//--- method of access to thre array
CObject *At(const int index) const;
//--- methods of changing
bool Update(const int index,CObject *element);
bool Shift(const int index,const int shift);
//--- methods of deleting
CObject *Detach(const int index);
bool Delete(const int index);
bool DeleteRange(int from,int to);
void Clear(void);
//--- method for comparing arrays
bool CompareArray(const CArrayObj *array) const;
//--- methods for working with the sorted array
bool InsertSort(CObject *element);
int Search(const CObject *element) const;
int SearchGreat(const CObject *element) const;
int SearchLess(const CObject *element) const;
int SearchGreatOrEqual(const CObject *element) const;
int SearchLessOrEqual(const CObject *element) const;
int SearchFirst(const CObject *element) const;
int SearchLast(const CObject *element) const;
protected:
void QuickSort(int beg,int end,const int mode);
int QuickSearch(const CObject *element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayObj::CArrayObj(void) : m_free_mode(true)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayObj::~CArrayObj(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayObj::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC)
delete m_data[dest+i];
//---
m_data[dest+i]=m_data[src+i];
m_data[src+i]=NULL;
}
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC)
delete m_data[dest+i];
//---
m_data[dest+i]=m_data[src+i];
m_data[src+i]=NULL;
}
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayObj::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
//--- explicitly zeroize all the loose items in the array
for(int i=m_data_total;i<m_data_max;i++)
m_data[i]=NULL;
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayObj::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_total>size)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode)
for(int i=size;i<m_data_total;i++)
if(CheckPointer(m_data[i])==POINTER_DYNAMIC)
delete m_data[i];
m_data_total=size;
}
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayObj::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
Clear();
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayObj::Add(CObject *element)
{
//--- check
if(!CheckPointer(element))
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayObj::AddArray(const CArrayObj *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::Insert(CObject *element,const int pos)
{
//--- check
if(pos<0 || !CheckPointer(element))
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::InsertArray(const CArrayObj *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num)) return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayObj::AssignArray(const CArrayObj *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
CObject *CArrayObj::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(NULL);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::Update(const int index,CObject *element)
{
//--- check
if(index<0 || !CheckPointer(element) || index>=m_data_total)
return(false);
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC)
delete m_data[index];
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayObj::Shift(const int index,const int shift)
{
CObject *tmp_node;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_node=m_data[index];
m_data[index]=NULL;
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_node;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::Delete(const int index)
{
//--- check
if(index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1)
{
if(index>=0 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
}
else
if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC)
delete m_data[index];
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Detach element from the specified position |
//+------------------------------------------------------------------+
CObject *CArrayObj::Detach(const int index)
{
CObject *result;
//--- check
if(index>=m_data_total)
return(NULL);
//--- detach
result=m_data[index];
//--- reset the array element, so as not remove the method MemMove
m_data[index]=NULL;
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(NULL);
m_data_total--;
//--- successful
return(result);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayObj::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
for(int i=to-from+1;i>0;i--,m_data_total--)
if(m_free_mode && CheckPointer(m_data[m_data_total-1])==POINTER_DYNAMIC)
delete m_data[m_data_total-1];
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Clearing of array without the release of memory |
//+------------------------------------------------------------------+
void CArrayObj::Clear(void)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode)
{
for(int i=0;i<m_data_total;i++)
{
if(CheckPointer(m_data[i])==POINTER_DYNAMIC)
delete m_data[i];
m_data[i]=NULL;
}
}
m_data_total=0;
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayObj::CompareArray(const CArrayObj *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i].Compare(array.m_data[i],0)!=0)
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayObj::QuickSort(int beg,int end,const int mode)
{
int i,j;
CObject *p_node;
CObject *t_node;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_node=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i].Compare(p_node,mode)<0)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j].Compare(p_node,mode)>0)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_node=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_node;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j,mode);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayObj::InsertSort(CObject *element)
{
int pos;
//--- check
if(!CheckPointer(element) || m_sort_mode==-1)
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
int mode=m_sort_mode;
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)>0)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=mode;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::QuickSearch(const CObject *element) const
{
int i,j,m=-1;
CObject *t_node;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m==m_data_total-1)
break;
t_node=m_data[m];
if(t_node.Compare(element,m_sort_mode)==0)
break;
if(t_node.Compare(element,m_sort_mode)>0)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::Search(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchGreat(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos].Compare(element,m_sort_mode)<=0)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchLess(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos].Compare(element,m_sort_mode)>=0)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchGreatOrEqual(const CObject *element) const
{
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos].Compare(element,m_sort_mode)>=0)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchLessOrEqual(const CObject *element) const
{
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos].Compare(element,m_sort_mode)<=0)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchFirst(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
{
while(m_data[pos].Compare(element,m_sort_mode)==0)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchLast(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
{
while(m_data[pos].Compare(element,m_sort_mode)==0)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayObj::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(m_data[i].Save(file_handle)!=true)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayObj::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
//--- create new element
if(!CreateElement(i))
break;
if(m_data[i].Load(file_handle)!=true)
break;
m_data_total++;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+769
View File
@@ -0,0 +1,769 @@
//+------------------------------------------------------------------+
//| ArrayShort.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayShort. |
//| Pupose: Class of dynamic array of short type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayShort : public CArray
{
protected:
short m_data[]; // data array
public:
CArrayShort(void);
~CArrayShort(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_SHORT); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const short element);
bool AddArray(const short &src[]);
bool AddArray(const CArrayShort *src);
bool Insert(const short element,const int pos);
bool InsertArray(const short &src[],const int pos);
bool InsertArray(const CArrayShort *src,const int pos);
bool AssignArray(const short &src[]);
bool AssignArray(const CArrayShort *src);
//--- method of access to the array
short At(const int index) const;
short operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const short element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const short &array[]) const;
bool CompareArray(const CArrayShort *array) const;
//--- methods for working with the sorted array
bool InsertSort(const short element);
int Search(const short element) const;
int SearchGreat(const short element) const;
int SearchLess(const short element) const;
int SearchGreatOrEqual(const short element) const;
int SearchLessOrEqual(const short element) const;
int SearchFirst(const short element) const;
int SearchLast(const short element) const;
int SearchLinear(const short element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const short element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayShort::CArrayShort(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayShort::~CArrayShort(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayShort::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayShort::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayShort::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayShort::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayShort::Add(const short element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayShort::AddArray(const short &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayShort::AddArray(const CArrayShort *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayShort::Insert(const short element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayShort::InsertArray(const short &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayShort::InsertArray(const CArrayShort *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayShort::AssignArray(const short &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayShort::AssignArray(const CArrayShort *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
short CArrayShort::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(SHORT_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayShort::Update(const int index,const short element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayShort::Shift(const int index,const int shift)
{
short tmp_short;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_short=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_short;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayShort::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayShort::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayShort::CompareArray(const short &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayShort::CompareArray(const CArrayShort *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayShort::QuickSort(int beg,int end,const int mode)
{
int i,j;
short p_short,t_short;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_short=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_short)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_short)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_short=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_short;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayShort::InsertSort(const short element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayShort::SearchLinear(const short element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::QuickSearch(const short element) const
{
int i,j,m=-1;
short t_short;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_short=m_data[m];
if(t_short==element)
break;
if(t_short>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::Search(const short element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::SearchGreat(const short element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayShort::SearchLess(const short element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::SearchGreatOrEqual(const short element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::SearchLessOrEqual(const short element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::SearchFirst(const short element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayShort::SearchLast(const short element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayShort::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],SHORT_VALUE)!=SHORT_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayShort::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=(short)FileReadInteger(file_handle,SHORT_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+780
View File
@@ -0,0 +1,780 @@
//+------------------------------------------------------------------+
//| ArrayString.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayString. |
//| Purpose: Class of dynamic array of string type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayString : public CArray
{
protected:
string m_data[]; // data array
public:
CArrayString(void);
~CArrayString(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_STRING); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const string element);
bool AddArray(const string &src[]);
bool AddArray(const CArrayString *src);
bool Insert(const string element,const int pos);
bool InsertArray(const string &src[],const int pos);
bool InsertArray(const CArrayString *src,const int pos);
bool AssignArray(const string &src[]);
bool AssignArray(const CArrayString *src);
//--- method of access to the array
string At(const int index) const;
string operator[](const int index) const { return(At(index)); }
//--- methods of changing
bool Update(const int index,const string element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const string &array[]) const;
bool CompareArray(const CArrayString *array) const;
//--- methods for working with the sorted array
bool InsertSort(const string element);
int Search(const string element) const;
int SearchGreat(const string element) const;
int SearchLess(const string element) const;
int SearchGreatOrEqual(const string element) const;
int SearchLessOrEqual(const string element) const;
int SearchFirst(const string element) const;
int SearchLast(const string element) const;
int SearchLinear(const string element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const string element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayString::CArrayString(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayString::~CArrayString(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayString::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayString::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayString::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayString::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayString::Add(const string element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayString::AddArray(const string &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayString::AddArray(const CArrayString *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::Insert(const string element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::InsertArray(const string &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::InsertArray(const CArrayString *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayString::AssignArray(const string &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayString::AssignArray(const CArrayString *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
string CArrayString::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return("");
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::Update(const int index,const string element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayString::Shift(const int index,const int shift)
{
string tmp_string;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_string=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_string;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayString::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayString::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayString::CompareArray(const string &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayString::CompareArray(const CArrayString *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayString::QuickSort(int beg,int end,const int mode)
{
int i,j;
string p_string;
string t_string;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_string=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_string)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_string)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_string=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_string;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayString::InsertSort(const string element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayString::SearchLinear(const string element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::QuickSearch(const string element) const
{
int i,j,m=-1;
string t_string;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_string=m_data[m];
if(t_string==element)
break;
if(t_string>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::Search(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchGreat(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchLess(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchGreatOrEqual(const string element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchLessOrEqual(const string element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchFirst(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchLast(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayString::Save(const int file_handle)
{
int i=0,len;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
{
len=StringLen(m_data[i]);
//--- write string length
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
//--- write string
if(len!=0) if(FileWriteString(file_handle,m_data[i],len)!=len)
break;
}
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayString::Load(const int file_handle)
{
int i=0,num,len;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
//--- read string length
len=FileReadInteger(file_handle,INT_VALUE);
//--- read string
if(len!=0)
m_data[i]=FileReadString(file_handle,len);
else
m_data[i]="";
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+770
View File
@@ -0,0 +1,770 @@
//+------------------------------------------------------------------+
//| ArrayUChar.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayUChar. |
//| Purpose: Class of dynamic array of uchar type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayUChar : public CArray
{
protected:
uchar m_data[]; // data array
public:
CArrayUChar(void);
~CArrayUChar(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_UCHAR); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const uchar element);
bool AddArray(const uchar &src[]);
bool AddArray(const CArrayUChar *src);
bool Insert(const uchar element,const int pos);
bool InsertArray(const uchar &src[],const int pos);
bool InsertArray(const CArrayUChar *src,const int pos);
bool AssignArray(const uchar &src[]);
bool AssignArray(const CArrayUChar *src);
//--- method of access to the array
uchar At(const int index) const;
uchar operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const uchar element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const uchar &array[]) const;
bool CompareArray(const CArrayUChar *array) const;
//--- methods for working with the sorted array
bool InsertSort(const uchar element);
int Search(const uchar element) const;
int SearchGreat(const uchar element) const;
int SearchLess(const uchar element) const;
int SearchGreatOrEqual(const uchar element) const;
int SearchLessOrEqual(const uchar element) const;
int SearchFirst(const uchar element) const;
int SearchLast(const uchar element) const;
int SearchLinear(const uchar element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const uchar element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayUChar::CArrayUChar(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayUChar::~CArrayUChar(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayUChar::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayUChar::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayUChar::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayUChar::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayUChar::Add(const uchar element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayUChar::AddArray(const uchar &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayUChar::AddArray(const CArrayUChar *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayUChar::Insert(const uchar element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayUChar::InsertArray(const uchar &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayUChar::InsertArray(const CArrayUChar *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayUChar::AssignArray(const uchar &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayUChar::AssignArray(const CArrayUChar *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
uchar CArrayUChar::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(CHAR_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayUChar::Update(const int index,const uchar element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayUChar::Shift(const int index,const int shift)
{
uchar tmp_char;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_char=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_char;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayUChar::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayUChar::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayUChar::CompareArray(const uchar &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayUChar::CompareArray(const CArrayUChar *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayUChar::QuickSort(int beg,int end,const int mode)
{
int i,j;
uchar p_char;
uchar t_char;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_char=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_char)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_char)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_char=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_char;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayUChar::InsertSort(const uchar element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchLinear(const uchar element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::QuickSearch(const uchar element) const
{
int i,j,m=-1;
uchar t_char;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_char=m_data[m];
if(t_char==element)
break;
if(t_char>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::Search(const uchar element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchGreat(const uchar element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchLess(const uchar element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchGreatOrEqual(const uchar element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchLessOrEqual(const uchar element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchFirst(const uchar element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUChar::SearchLast(const uchar element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayUChar::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],CHAR_VALUE)!=CHAR_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayUChar::Load(const int file_handle)
{
int i,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=(uchar)FileReadInteger(file_handle,CHAR_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+774
View File
@@ -0,0 +1,774 @@
//+------------------------------------------------------------------+
//| ArrayUInt.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayUInt. |
//| Puprose: Class of dynamic array of uint type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayUInt : public CArray
{
protected:
uint m_data[]; // data array
public:
CArrayUInt(void);
~CArrayUInt(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_UINT); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const uint element);
bool AddArray(const uint &src[]);
bool AddArray(const CArrayUInt *src);
bool Insert(const uint element,const int pos);
bool InsertArray(const uint &src[],const int pos);
bool InsertArray(const CArrayUInt *src,const int pos);
bool AssignArray(const uint &src[]);
bool AssignArray(const CArrayUInt *src);
//--- method of access to the array
uint At(const int index) const;
uint operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const uint element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const uint &array[]) const;
bool CompareArray(const CArrayUInt *array) const;
//--- methods for working with the sorted array
bool InsertSort(const uint element);
int Search(const uint element) const;
int SearchGreat(const uint element) const;
int SearchLess(const uint element) const;
int SearchGreatOrEqual(const uint element) const;
int SearchLessOrEqual(const uint element) const;
int SearchFirst(const uint element) const;
int SearchLast(const uint element) const;
int SearchLinear(const uint element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const uint element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayUInt::CArrayUInt(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayUInt::~CArrayUInt(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayUInt::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayUInt::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayUInt::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayUInt::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayUInt::Add(const uint element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayUInt::AddArray(const uint &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayUInt::AddArray(const CArrayUInt *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayUInt::Insert(const uint element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayUInt::InsertArray(const uint &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayUInt::InsertArray(const CArrayUInt *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayUInt::AssignArray(const uint &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayUInt::AssignArray(const CArrayUInt *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
uint CArrayUInt::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(INT_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayUInt::Update(const int index,const uint element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayUInt::Shift(const int index,const int shift)
{
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
uint tmp_int=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_int;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayUInt::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayUInt::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayUInt::CompareArray(const uint &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayUInt::CompareArray(const CArrayUInt *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayUInt::QuickSort(int beg,int end,const int mode)
{
//--- check
if(beg<0 || end<0)
return;
//--- sort
int i=beg;
int j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
uint p_int=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_int)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_int)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
uint t_uint=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_uint;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayUInt::InsertSort(const uint element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchLinear(const uint element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::QuickSearch(const uint element) const
{
//--- search
int m=-1;
int i=0;
int j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
uint t_int=m_data[m];
if(t_int==element)
break;
if(t_int>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::Search(const uint element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchGreat(const uint element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchLess(const uint element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchGreatOrEqual(const uint element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchLessOrEqual(const uint element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchFirst(const uint element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUInt::SearchLast(const uint element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayUInt::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],INT_VALUE)!=INT_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayUInt::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadInteger(file_handle,INT_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+769
View File
@@ -0,0 +1,769 @@
//+------------------------------------------------------------------+
//| ArrayULong.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayULong. |
//| Purpose: Class of dynamic array of ulong type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayULong : public CArray
{
protected:
ulong m_data[]; // data array
public:
CArrayULong(void);
~CArrayULong(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_ULONG); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const ulong element);
bool AddArray(const ulong &src[]);
bool AddArray(const CArrayULong *src);
bool Insert(const ulong element,const int pos);
bool InsertArray(const ulong &src[],const int pos);
bool InsertArray(const CArrayULong *src,const int pos);
bool AssignArray(const ulong &src[]);
bool AssignArray(const CArrayULong *src);
//--- method of access to the array
ulong At(const int index) const;
ulong operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods change
bool Update(const int index,const ulong element);
bool Shift(const int index,const int shift);
//--- methods for deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for compare arrays
bool CompareArray(const ulong &array[]) const;
bool CompareArray(const CArrayULong *array) const;
//--- methods for working with the sorted array
bool InsertSort(const ulong element);
int Search(const ulong element) const;
int SearchGreat(const ulong element) const;
int SearchLess(const ulong element) const;
int SearchGreatOrEqual(const ulong element) const;
int SearchLessOrEqual(const ulong element) const;
int SearchFirst(const ulong element) const;
int SearchLast(const ulong element) const;
int SearchLinear(const ulong element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const ulong element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayULong::CArrayULong(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayULong::~CArrayULong(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayULong::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayULong::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayULong::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayULong::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayULong::Add(const ulong element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayULong::AddArray(const ulong &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayULong::AddArray(const CArrayULong *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayULong::Insert(const ulong element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayULong::InsertArray(const ulong &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayULong::InsertArray(const CArrayULong *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayULong::AssignArray(const ulong &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayULong::AssignArray(const CArrayULong *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
ulong CArrayULong::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(LONG_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayULong::Update(const int index,const ulong element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayULong::Shift(const int index,const int shift)
{
ulong tmp_long;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_long=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_long;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayULong::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayULong::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayULong::CompareArray(const ulong &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayULong::CompareArray(const CArrayULong *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayULong::QuickSort(int beg,int end,const int mode)
{
int i,j;
ulong p_long,t_long;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_long=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_long)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_long)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_long=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_long;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayULong::InsertSort(const ulong element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayULong::SearchLinear(const ulong element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::QuickSearch(const ulong element) const
{
int i,j,m=-1;
ulong t_long;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_long=m_data[m];
if(t_long==element)
break;
if(t_long>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::Search(const ulong element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::SearchGreat(const ulong element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayULong::SearchLess(const ulong element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::SearchGreatOrEqual(const ulong element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::SearchLessOrEqual(const ulong element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::SearchFirst(const ulong element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayULong::SearchLast(const ulong element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayULong::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteLong(file_handle,m_data[i])!=sizeof(ulong))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayULong::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadLong(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+769
View File
@@ -0,0 +1,769 @@
//+------------------------------------------------------------------+
//| ArrayUShort.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayUShort. |
//| Pupose: Class of dynamic array of ushort type values. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayUShort : public CArray
{
protected:
ushort m_data[]; // data array
public:
CArrayUShort(void);
~CArrayUShort(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_USHORT); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const ushort element);
bool AddArray(const ushort &src[]);
bool AddArray(const CArrayUShort *src);
bool Insert(const ushort element,const int pos);
bool InsertArray(const ushort &src[],const int pos);
bool InsertArray(const CArrayUShort *src,const int pos);
bool AssignArray(const ushort &src[]);
bool AssignArray(const CArrayUShort *src);
//--- method of access to the array
ushort At(const int index) const;
ushort operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const ushort element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const ushort &array[]) const;
bool CompareArray(const CArrayUShort *array) const;
//--- methods for working with the sorted array
bool InsertSort(const ushort element);
int Search(const ushort element) const;
int SearchGreat(const ushort element) const;
int SearchLess(const ushort element) const;
int SearchGreatOrEqual(const ushort element) const;
int SearchLessOrEqual(const ushort element) const;
int SearchFirst(const ushort element) const;
int SearchLast(const ushort element) const;
int SearchLinear(const ushort element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const ushort element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayUShort::CArrayUShort(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayUShort::~CArrayUShort(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayUShort::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayUShort::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayUShort::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayUShort::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayUShort::Add(const ushort element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayUShort::AddArray(const ushort &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayUShort::AddArray(const CArrayUShort *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayUShort::Insert(const ushort element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayUShort::InsertArray(const ushort &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayUShort::InsertArray(const CArrayUShort *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayUShort::AssignArray(const ushort &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayUShort::AssignArray(const CArrayUShort *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
ushort CArrayUShort::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(SHORT_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayUShort::Update(const int index,const ushort element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayUShort::Shift(const int index,const int shift)
{
ushort tmp_short;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_short=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_short;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayUShort::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayUShort::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayUShort::CompareArray(const ushort &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayUShort::CompareArray(const CArrayUShort *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayUShort::QuickSort(int beg,int end,const int mode)
{
int i,j;
ushort p_short,t_short;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_short=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_short)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_short)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_short=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_short;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayUShort::InsertSort(const ushort element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchLinear(const ushort element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::QuickSearch(const ushort element) const
{
int i,j,m=-1;
ushort t_short;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_short=m_data[m];
if(t_short==element)
break;
if(t_short>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::Search(const ushort element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchGreat(const ushort element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchLess(const ushort element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchGreatOrEqual(const ushort element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchLessOrEqual(const ushort element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchFirst(const ushort element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayUShort::SearchLast(const ushort element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayUShort::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],SHORT_VALUE)!=SHORT_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayUShort::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=(ushort)FileReadInteger(file_handle,SHORT_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
+657
View File
@@ -0,0 +1,657 @@
//+------------------------------------------------------------------+
//| List.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CList. |
//| Purpose: Provides the possibility of working with the list of |
//| CObject instances and its dervivatives |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CList : public CObject
{
protected:
CObject *m_first_node; // pointer to the first element of the list
CObject *m_last_node; // pointer to the last element of the list
CObject *m_curr_node; // pointer to the current element of the list
int m_curr_idx; // index of the current list item
int m_data_total; // number of elements
bool m_free_mode; // flag of the necessity of "physical" deletion of object
bool m_data_sort; // flag if the list is sorted or not
int m_sort_mode; // mode of sorting of array
public:
CList(void);
~CList(void);
//--- methods of access to protected data
bool FreeMode(void) const { return(m_free_mode); }
void FreeMode(bool mode) { m_free_mode=mode; }
int Total(void) const { return(m_data_total); }
bool IsSorted(void) const { return(m_data_sort); }
int SortMode(void) const { return(m_sort_mode); }
//--- method of identifying the object
virtual int Type(void) const { return(0x7779); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- method of creating an element of the list
virtual CObject *CreateElement(void) { return(NULL); }
//--- methods of filling the list
int Add(CObject *new_node);
int Insert(CObject *new_node,int index);
//--- methods for navigating
int IndexOf(CObject *node);
CObject *GetNodeAtIndex(int index);
CObject *GetFirstNode(void);
CObject *GetPrevNode(void);
CObject *GetCurrentNode(void);
CObject *GetNextNode(void);
CObject *GetLastNode(void);
//--- methods for deleting
CObject *DetachCurrent(void);
bool DeleteCurrent(void);
bool Delete(int index);
void Clear(void);
//--- method for comparing lists
bool CompareList(CList *List);
//--- methods for changing
void Sort(int mode);
bool MoveToIndex(int index);
bool Exchange(CObject *node1,CObject *node2);
//--- method for searching
CObject *Search(CObject *element);
protected:
void QuickSort(int beg,int end,int mode);
CObject *QuickSearch(CObject *element);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CList::CList(void) : m_first_node(NULL),
m_last_node(NULL),
m_curr_node(NULL),
m_curr_idx(-1),
m_data_total(0),
m_free_mode(true),
m_data_sort(false),
m_sort_mode(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CList::~CList(void)
{
Clear();
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CList::QuickSort(int beg,int end,int mode)
{
int i,j,k;
CObject *i_ptr,*j_ptr,*k_ptr;
//---
i_ptr=GetNodeAtIndex(i=beg);
j_ptr=GetNodeAtIndex(j=end);
while(i<end)
{
//--- ">>1" is quick division by 2
k_ptr=GetNodeAtIndex(k=(beg+end)>>1);
while(i<j)
{
while(i_ptr.Compare(k_ptr,mode)<0)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
i_ptr=i_ptr.Next();
}
while(j_ptr.Compare(k_ptr,mode)>0)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
j_ptr=j_ptr.Prev();
}
if(i<=j)
{
Exchange(i_ptr,j_ptr);
i++;
i_ptr=GetNodeAtIndex(i);
//--- control the output of the array bounds
if(j==0)
break;
else
{
j--;
j_ptr=GetNodeAtIndex(j);
}
}
}
if(beg<j)
QuickSort(beg,j,mode);
beg=i;
i_ptr=GetNodeAtIndex(i=beg);
j_ptr=GetNodeAtIndex(j=end);
}
}
//+------------------------------------------------------------------+
//| Index of element specified via the pointer to the list item |
//+------------------------------------------------------------------+
int CList::IndexOf(CObject *node)
{
//--- check
if(!CheckPointer(node) || !CheckPointer(m_curr_node))
return(-1);
//--- searching index
if(node==m_curr_node)
return(m_curr_idx);
if(GetFirstNode()==node)
return(0);
for(int i=1;i<m_data_total;i++)
if(GetNextNode()==node)
return(i);
//---
return(-1);
}
//+------------------------------------------------------------------+
//| Adding a new element to the end of the list |
//+------------------------------------------------------------------+
int CList::Add(CObject *new_node)
{
//--- check
if(!CheckPointer(new_node))
return(-1);
//--- add
if(m_first_node==NULL)
m_first_node=new_node;
else
{
m_last_node.Next(new_node);
new_node.Prev(m_last_node);
}
m_curr_node=new_node;
m_curr_idx=m_data_total;
m_last_node=new_node;
m_data_sort=false;
//--- result
return(m_data_total++);
}
//+------------------------------------------------------------------+
//| Inserting a new element to the specified position in the list. |
//| Inserting element to the current position of the list if index=-1|
//+------------------------------------------------------------------+
int CList::Insert(CObject *new_node,int index)
{
CObject *tmp_node;
//--- check
if(!CheckPointer(new_node))
return(-1);
if(index>m_data_total || index<0)
return(-1);
//--- adjust
if(index==-1)
{
if(m_curr_node==NULL)
return(Add(new_node));
}
else
{
if(GetNodeAtIndex(index)==NULL)
return(Add(new_node));
}
//--- no need to check m_curr_node
tmp_node=m_curr_node.Prev();
new_node.Prev(tmp_node);
if(tmp_node!=NULL)
tmp_node.Next(new_node);
else
m_first_node=new_node;
new_node.Next(m_curr_node);
m_curr_node.Prev(new_node);
m_data_total++;
m_data_sort=false;
m_curr_node=new_node;
//--- result
return(index);
}
//+------------------------------------------------------------------+
//| Get a pointer to the position of element in the list |
//+------------------------------------------------------------------+
CObject *CList::GetNodeAtIndex(int index)
{
int i;
bool revers;
CObject *result;
//--- check
if(index>=m_data_total)
return(NULL);
if(index==m_curr_idx)
return(m_curr_node);
//--- optimize bust list
if(index<m_curr_idx)
{
//--- index to the left of the current
if(m_curr_idx-index<index)
{
//--- closer to the current index
i=m_curr_idx;
revers=true;
result=m_curr_node;
}
else
{
//--- closer to the top of the list
i=0;
revers=false;
result=m_first_node;
}
}
else
{
//--- index to the right of the current
if(index-m_curr_idx<m_data_total-index-1)
{
//--- closer to the current index
i=m_curr_idx;
revers=false;
result=m_curr_node;
}
else
{
//--- closer to the end of the list
i=m_data_total-1;
revers=true;
result=m_last_node;
}
}
if(!CheckPointer(result))
return(NULL);
//---
if(revers)
{
//--- search from right to left
for(;i>index;i--)
{
result=result.Prev();
if(result==NULL)
return(NULL);
}
}
else
{
//--- search from left to right
for(;i<index;i++)
{
result=result.Next();
if(result==NULL)
return(NULL);
}
}
m_curr_idx=index;
//--- result
return(m_curr_node=result);
}
//+------------------------------------------------------------------+
//| Get a pointer to the first itme of the list |
//+------------------------------------------------------------------+
CObject *CList::GetFirstNode(void)
{
//--- check
if(!CheckPointer(m_first_node))
return(NULL);
//--- save
m_curr_idx=0;
//--- result
return(m_curr_node=m_first_node);
}
//+------------------------------------------------------------------+
//| Get a pointer to the previous itme of the list |
//+------------------------------------------------------------------+
CObject *CList::GetPrevNode(void)
{
//--- check
if(!CheckPointer(m_curr_node) || m_curr_node.Prev()==NULL)
return(NULL);
//--- decrement
m_curr_idx--;
//--- result
return(m_curr_node=m_curr_node.Prev());
}
//+------------------------------------------------------------------+
//| Get a pointer to the current item of the list |
//+------------------------------------------------------------------+
CObject *CList::GetCurrentNode(void)
{
return(m_curr_node);
}
//+------------------------------------------------------------------+
//| Get a pointer to the next item of the list |
//+------------------------------------------------------------------+
CObject *CList::GetNextNode(void)
{
//--- check
if(!CheckPointer(m_curr_node) || m_curr_node.Next()==NULL)
return(NULL);
//--- increment
m_curr_idx++;
//--- result
return(m_curr_node=m_curr_node.Next());
}
//+------------------------------------------------------------------+
//| Get a pointer to the last itme of the list |
//+------------------------------------------------------------------+
CObject *CList::GetLastNode(void)
{
//--- check
if(!CheckPointer(m_last_node))
return(NULL);
//---
m_curr_idx=m_data_total-1;
//--- result
return(m_curr_node=m_last_node);
}
//+------------------------------------------------------------------+
//| Detach current item in the list |
//+------------------------------------------------------------------+
CObject *CList::DetachCurrent(void)
{
CObject *tmp_node,*result=NULL;
//--- check
if(!CheckPointer(m_curr_node))
return(result);
//--- "explode" list
result=m_curr_node;
m_curr_node=NULL;
//--- if the deleted item was not the last one, pull up the "tail" of the list
if((tmp_node=result.Next())!=NULL)
{
tmp_node.Prev(result.Prev());
m_curr_node=tmp_node;
}
//--- if the deleted item was not the first one, pull up "head" list
if((tmp_node=result.Prev())!=NULL)
{
tmp_node.Next(result.Next());
//--- if "last_node" is removed, move the current pointer to the end of the list
if(m_curr_node==NULL)
{
m_curr_node=tmp_node;
m_curr_idx=m_data_total-2;
}
}
m_data_total--;
//--- if necessary, adjust the settings of the first and last elements
if(m_first_node==result)
m_first_node=result.Next();
if(m_last_node==result)
m_last_node=result.Prev();
//--- complete the processing of element removed from the list
//--- remove references to the list
result.Prev(NULL);
result.Next(NULL);
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Delete current item of list item |
//+------------------------------------------------------------------+
bool CList::DeleteCurrent(void)
{
CObject *result=DetachCurrent();
//--- check
if(result==NULL)
return(false);
//--- complete the processing of element removed from the list
if(m_free_mode)
{
//--- delete it "physically"
if(CheckPointer(result)==POINTER_DYNAMIC)
delete result;
}
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Delete an item from a given position in the list |
//+------------------------------------------------------------------+
bool CList::Delete(int index)
{
if(GetNodeAtIndex(index)==NULL)
return(false);
//--- result
return(DeleteCurrent());
}
//+------------------------------------------------------------------+
//| Remove all items from the list |
//+------------------------------------------------------------------+
void CList::Clear(void)
{
GetFirstNode();
while(m_data_total!=0)
if(!DeleteCurrent())
break;
}
//+------------------------------------------------------------------+
//| Equality comparing of two lists |
//+------------------------------------------------------------------+
bool CList::CompareList(CList *List)
{
CObject *node,*lnode;
//--- check
if(!CheckPointer(List))
return(false);
if((node=GetFirstNode())==NULL)
return(false);
if((lnode=List.GetFirstNode())==NULL)
return(false);
//--- compare
if(node.Compare(lnode)!=0)
return(false);
while((node=GetNextNode())!=NULL)
{
if((lnode=List.GetNextNode())==NULL)
return(false);
if(node.Compare(lnode)!=0)
return(false);
}
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Sorting an array in ascending order |
//+------------------------------------------------------------------+
void CList::Sort(int mode)
{
//--- check
if(m_data_total==0)
return;
if(m_data_sort && m_sort_mode==mode)
return;
//--- sort
QuickSort(0,m_data_total-1,mode);
m_sort_mode=mode;
m_data_sort=true;
}
//+------------------------------------------------------------------+
//| Move the current item of list to the specified position |
//+------------------------------------------------------------------+
bool CList::MoveToIndex(int index)
{
//--- check
if(index>=m_data_total || !CheckPointer(m_curr_node))
return(false);
//--- tune
if(m_curr_idx==index)
return(true);
if(m_curr_idx<index)
index--;
//--- move
Insert(DetachCurrent(),index);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Move an item of the list from the specified position to the |
//| current one |
//+------------------------------------------------------------------+
bool CList::Exchange(CObject *node1,CObject *node2)
{
CObject *tmp_node,*node;
//--- check
if(!CheckPointer(node1) || !CheckPointer(node2))
return(false);
//---
tmp_node=node1.Prev();
node1.Prev(node2.Prev());
if(node1.Prev()!=NULL)
{
node=node1.Prev();
node.Next(node1);
}
else
m_first_node=node1;
node2.Prev(tmp_node);
if(node2.Prev()!=NULL)
{
node=node2.Prev();
node.Next(node2);
}
else
m_first_node=node2;
tmp_node=node1.Next();
node1.Next(node2.Next());
if(node1.Next()!=NULL)
{
node=node1.Next();
node.Prev(node1);
}
else
m_last_node=node1;
node2.Next(tmp_node);
if(node2.Next()!=NULL)
{
node=node2.Next();
node.Prev(node2);
}
else
m_last_node=node2;
//---
m_curr_idx=0;
m_curr_node=m_first_node;
m_data_sort=false;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search position of an element in a sorted list |
//+------------------------------------------------------------------+
CObject *CList::QuickSearch(CObject *element)
{
int i,j,m;
CObject *t_node=NULL;
//--- check
if(m_data_total==0)
return(NULL);
//--- check the pointer is not needed
i=0;
j=m_data_total;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_node=GetNodeAtIndex(m);
if(t_node.Compare(element,m_sort_mode)==0)
break;
if(t_node.Compare(element,m_sort_mode)>0)
j=m-1;
else
i=m+1;
t_node=NULL;
}
//--- result
return(t_node);
}
//+------------------------------------------------------------------+
//| Search position of an element in a sorted list |
//+------------------------------------------------------------------+
CObject *CList::Search(CObject *element)
{
CObject *result;
//--- check
if(!CheckPointer(element) || !m_data_sort)
return(NULL);
//--- search
result=QuickSearch(element);
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Writing list to file |
//+------------------------------------------------------------------+
bool CList::Save(const int file_handle)
{
CObject *node;
bool result=true;
//--- check
if(!CheckPointer(m_curr_node) || file_handle==INVALID_HANDLE)
return(false);
//--- write start marker - 0xFFFFFFFFFFFFFFFF
if(FileWriteLong(file_handle,-1)!=sizeof(long))
return(false);
//--- write type
if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE)
return(false);
//--- write list size
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- sequential scannning of elements in the list using the call of method Save()
node=m_first_node;
while(node!=NULL)
{
result&=node.Save(file_handle);
node=node.Next();
}
//--- successful
return(result);
}
//+------------------------------------------------------------------+
//| Reading list from file |
//+------------------------------------------------------------------+
bool CList::Load(const int file_handle)
{
uint i,num;
CObject *node;
bool result=true;
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- read and checking begin marker - 0xFFFFFFFFFFFFFFFF
if(FileReadLong(file_handle)!=-1)
return(false);
//--- read and checking type
if(FileReadInteger(file_handle,INT_VALUE)!=Type())
return(false);
//--- read list size
num=FileReadInteger(file_handle,INT_VALUE);
//--- sequential creation of list items using the call of method Load()
Clear();
for(i=0;i<num;i++)
{
node=CreateElement();
if(node==NULL)
return(false);
Add(node);
result&=node.Load(file_handle);
}
//--- successful
return(result);
}
//+------------------------------------------------------------------+
+415
View File
@@ -0,0 +1,415 @@
//+------------------------------------------------------------------+
//| Tree.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "TreeNode.mqh"
//+------------------------------------------------------------------+
//| Class CTree. |
//| Purpose: Building a binary tree of instances of CTreeNode class |
//| and its derviatives. |
//| Derives from class CTreeNode. |
//+------------------------------------------------------------------+
class CTree : public CTreeNode
{
protected:
CTreeNode *m_root_node; // root node of the tree
public:
CTree(void);
~CTree(void);
//--- methods of access to protected data
CTreeNode *Root(void) const { return(m_root_node); }
//--- method of identifying the object
virtual int Type() const { return(0x9999); }
//--- method of filling the tree
CTreeNode *Insert(CTreeNode *new_node);
//--- methods of removing tree nodes
bool Detach(CTreeNode *node);
bool Delete(CTreeNode *node);
void Clear(void);
//--- method of searching data in the tree
CTreeNode *Find(const CTreeNode *node);
//--- method to create elements in the tree
virtual CTreeNode *CreateElement() { return(NULL); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
void Balance(CTreeNode *node);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CTree::CTree(void) : m_root_node(NULL)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CTree::~CTree(void)
{
Clear();
}
//+------------------------------------------------------------------+
//| Method of adding a node to the tree |
//+------------------------------------------------------------------+
CTreeNode *CTree::Insert(CTreeNode *new_node)
{
CTreeNode *p_node;
CTreeNode *result=m_root_node;
//--- check
if(!CheckPointer(new_node))
return(NULL);
//--- add
if(result!=NULL)
{
p_node=NULL;
result=m_root_node;
while(result!=NULL && result.Compare(new_node)!=0)
{
p_node=result;
result=result.GetNext(new_node);
}
if(result!=NULL)
return(result);
if(p_node.Compare(new_node)>0)
p_node.Left(new_node);
else
p_node.Right(new_node);
new_node.Parent(p_node);
Balance(p_node);
}
else
m_root_node=new_node;
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Method of removing a node from the tree |
//+------------------------------------------------------------------+
bool CTree::Delete(CTreeNode *node)
{
//--- check
if(!CheckPointer(node))
return(false);
//--- delete
if(Detach(node) && CheckPointer(node)==POINTER_DYNAMIC)
delete node;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Method of detaching node from the tree |
//+------------------------------------------------------------------+
bool CTree::Detach(CTreeNode *node)
{
CTreeNode *curr_node,*tmp_node;
CTreeNode *nodeA,*nodeB;
//--- check
curr_node=node;
if(!CheckPointer(curr_node))
return(false);
//--- detach
if(curr_node.BalanceL()>curr_node.BalanceR())
{
nodeA=curr_node.Left();
while(nodeA.Right()!=NULL)
nodeA=nodeA.Right();
nodeB=nodeA.Parent();
if(nodeB!=curr_node)
{
nodeB.Right(nodeA.Left());
tmp_node=nodeB.Right();
if(tmp_node!=NULL)
tmp_node.Parent(nodeB);
tmp_node=curr_node.Left();
nodeA.Left(tmp_node);
tmp_node.Parent(nodeA);
}
//--- left link of curr_node is already installed as it should be
curr_node.Left(NULL);
//--- transferring the right link of curr_node to nodeA
nodeA.Right(curr_node.Right());
tmp_node=curr_node.Right();
if(tmp_node!=NULL)
tmp_node.Parent(nodeA);
curr_node.Right(NULL);
//--- transferring the root link of curr_node to nodeA
tmp_node=curr_node.Parent();
nodeA.Parent(tmp_node);
if(tmp_node!=NULL)
{
if(tmp_node.Left()==curr_node)
tmp_node.Left(nodeA);
else
tmp_node.Right(nodeA);
}
else
{
curr_node.Parent(NULL);
m_root_node=nodeA;
tmp_node=nodeA;
}
Balance(tmp_node);
}
else
{
if(curr_node.BalanceR()>0)
{
nodeA=curr_node.Right();
while(nodeA.Left()!=NULL)
nodeA=nodeA.Left();
nodeB=nodeA.Parent();
if(nodeB!=curr_node)
{
nodeB.Left(nodeA.Right());
tmp_node=nodeB.Left();
if(tmp_node!=NULL)
tmp_node.Parent(nodeB);
tmp_node=curr_node.Right();
nodeA.Right(tmp_node);
tmp_node.Parent(nodeA);
}
//--- right link of curr_node is already installed as it should be
curr_node.Right(NULL);
//--- transferring the left link of curr_node to nodeA
nodeA.Left(curr_node.Left());
tmp_node=curr_node.Left();
if(tmp_node!=NULL)
tmp_node.Parent(nodeA);
curr_node.Left(NULL);
//--- transferring the root link of curr_node to nodeA
tmp_node=curr_node.Parent();
nodeA.Parent(tmp_node);
if(tmp_node!=NULL)
{
if(tmp_node.Left()==curr_node)
tmp_node.Left(nodeA);
else
tmp_node.Right(nodeA);
}
else
{
curr_node.Parent(NULL);
m_root_node=nodeA;
tmp_node=nodeA;
}
Balance(tmp_node);
}
else
{
//--- node list
if(curr_node.Parent()==NULL)
m_root_node=NULL;
else
{
tmp_node=curr_node.Parent();
if(tmp_node.Left()==curr_node)
tmp_node.Left(NULL);
else
tmp_node.Right(NULL);
curr_node.Parent(NULL);
}
Balance(curr_node.Parent());
}
}
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Method of cleaning the tree |
//+------------------------------------------------------------------+
void CTree::Clear(void)
{
if(CheckPointer(m_root_node)==POINTER_DYNAMIC)
delete m_root_node;
m_root_node=NULL;
}
//+------------------------------------------------------------------+
//| Method of searching for a node in the tree |
//+------------------------------------------------------------------+
CTreeNode *CTree::Find(const CTreeNode *node)
{
CTreeNode *result=m_root_node;
//--- find
while(result!=NULL && result.Compare(node)!=0)
result=result.GetNext(node);
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Method of balancing the tree |
//+------------------------------------------------------------------+
void CTree::Balance(CTreeNode *node)
{
CTreeNode *nodeA,*nodeB,*nodeC,*curr_node,*tmp_node;
//---
curr_node=node;
while(curr_node!=NULL)
{
curr_node.RefreshBalance();
if(MathAbs(curr_node.BalanceL()-curr_node.BalanceR())<=1)
curr_node=curr_node.Parent();
else
{
if(curr_node.BalanceR()>curr_node.BalanceL())
{
//--- rotation to the right
tmp_node=curr_node.Right();
if(tmp_node.BalanceL()>tmp_node.BalanceR())
{
//--- great rotation to the right
nodeA=curr_node;
nodeB=nodeA.Right();
nodeC=nodeB.Left();
nodeC.Parent(nodeA.Parent());
tmp_node=nodeC.Parent();
if(tmp_node!=NULL)
{
if(tmp_node.Right()==nodeA)
tmp_node.Right(nodeC);
else
tmp_node.Left(nodeC);
}
else
m_root_node=nodeC;
nodeA.Parent(nodeC);
nodeB.Parent(nodeC);
nodeA.Right(nodeC.Left());
tmp_node=nodeA.Right();
if(tmp_node!=NULL)
tmp_node.Parent(nodeA);
nodeC.Left(nodeA);
nodeB.Left(nodeC.Right());
tmp_node=nodeB.Left();
if(tmp_node!=NULL)
tmp_node.Parent(nodeB);
nodeC.Right(nodeB);
if(m_root_node==nodeA)
m_root_node=nodeC;
curr_node=nodeC.Parent();
}
else
{
//--- slight rotation to the right
nodeA=curr_node;
nodeB=nodeA.Right();
nodeB.Parent(nodeA.Parent());
tmp_node=nodeB.Parent();
if(tmp_node!=NULL)
{
if(tmp_node.Right()==nodeA)
tmp_node.Right(nodeB);
else
tmp_node.Left(nodeB);
}
else
m_root_node=nodeB;
nodeA.Parent(nodeB);
nodeA.Right(nodeB.Left());
tmp_node=nodeA.Right();
if(tmp_node!=NULL)
tmp_node.Parent(nodeA);
nodeB.Left(nodeA);
if(m_root_node==nodeA)
m_root_node=nodeB;
curr_node=nodeB.Parent();
}
}
else
{
//--- rotation to the left
tmp_node=curr_node.Left();
if(tmp_node.BalanceR()>tmp_node.BalanceL())
{
//--- great rotation to the left
nodeA=curr_node;
nodeB=nodeA.Left();
nodeC=nodeB.Right();
nodeC.Parent(nodeA.Parent());
tmp_node=nodeC.Parent();
if(tmp_node!=NULL)
{
if(tmp_node.Right()==nodeA)
tmp_node.Right(nodeC);
else
tmp_node.Left(nodeC);
}
else
m_root_node=nodeC;
nodeA.Parent(nodeC);
nodeB.Parent(nodeC);
nodeA.Left(nodeC.Right());
tmp_node=nodeA.Left();
if(tmp_node!=NULL)
tmp_node.Parent(nodeA);
nodeC.Right(nodeA);
nodeB.Right(nodeC.Left());
tmp_node=nodeB.Right();
if(tmp_node!=NULL)
tmp_node.Parent(nodeB);
nodeC.Left(nodeB);
if(m_root_node==nodeA)
m_root_node=nodeC;
curr_node=nodeC.Parent();
}
else
{
//--- small rotation to the left
nodeA=curr_node;
nodeB=nodeA.Left();
nodeB.Parent(nodeA.Parent());
tmp_node=nodeB.Parent();
if(tmp_node!=NULL)
{
if(tmp_node.Right()==nodeA)
tmp_node.Right(nodeB);
else
tmp_node.Left(nodeB);
}
else
m_root_node=nodeB;
nodeA.Parent(nodeB);
nodeA.Left(nodeB.Right());
tmp_node=nodeA.Left();
if(tmp_node!=NULL)
tmp_node.Parent(nodeA);
nodeB.Right(nodeA);
if(m_root_node==nodeA)
m_root_node=nodeB;
curr_node=nodeB.Parent();
}
}
}
}
}
//+------------------------------------------------------------------+
//| Writing tree to file |
//+------------------------------------------------------------------+
bool CTree::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
if(m_root_node==NULL)
return(true);
//--- result
return(m_root_node.SaveNode(file_handle));
}
//+------------------------------------------------------------------+
//| Reading tree from file |
//+------------------------------------------------------------------+
bool CTree::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- create root node only
Clear();
Insert(CreateElement());
//--- result
return(m_root_node.LoadNode(file_handle,m_root_node));
}
//+------------------------------------------------------------------+
+174
View File
@@ -0,0 +1,174 @@
//+------------------------------------------------------------------+
//| TreeNode.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CTreeNode. |
//| Purpose: Base class of node of binary tree CTree. |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CTreeNode : public CObject
{
private:
CTreeNode *m_p_node; // link to node up
CTreeNode *m_l_node; // link to node left
CTreeNode *m_r_node; // link to node right
//--- variables
int m_balance; // balance of node
int m_l_balance; // balance of the left branch
int m_r_balance; // balance of the right branch
public:
CTreeNode(void);
~CTreeNode(void);
//--- methods of access to protected data
CTreeNode* Parent(void) const { return(m_p_node); }
void Parent(CTreeNode *node) { m_p_node=node; }
CTreeNode* Left(void) const { return(m_l_node); }
void Left(CTreeNode *node) { m_l_node=node; }
CTreeNode* Right(void) const { return(m_r_node); }
void Right(CTreeNode *node) { m_r_node=node; }
int Balance(void) const { return(m_balance); }
int BalanceL(void) const { return(m_l_balance); }
int BalanceR(void) const { return(m_r_balance); }
//--- method of identifying the object
virtual int Type(void) const { return(0x8888); }
//--- methods for controlling
int RefreshBalance(void);
CTreeNode *GetNext(const CTreeNode *node);
//--- methods for working with files
bool SaveNode(const int file_handle);
bool LoadNode(const int file_handle,CTreeNode *main);
protected:
//--- method for creating an instance of class
virtual CTreeNode *CreateSample(void) { return(NULL); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CTreeNode::CTreeNode(void) : m_p_node(NULL),
m_l_node(NULL),
m_r_node(NULL),
m_balance(0),
m_l_balance(0),
m_r_balance(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CTreeNode::~CTreeNode(void)
{
//--- delete nodes of the next level
if(m_l_node!=NULL)
delete m_l_node;
if(m_r_node!=NULL)
delete m_r_node;
}
//+------------------------------------------------------------------+
//| Calculating the balance of the node |
//+------------------------------------------------------------------+
int CTreeNode::RefreshBalance(void)
{
//--- calculate the balance of the left branch
if(m_l_node==NULL)
m_l_balance=0;
else
m_l_balance=m_l_node.RefreshBalance();
//--- calculate the balance of the right branch
if(m_r_node==NULL)
m_r_balance=0;
else
m_r_balance=m_r_node.RefreshBalance();
//--- calculate the balance of the node
if(m_r_balance>m_l_balance)
m_balance=m_r_balance+1;
else
m_balance=m_l_balance+1;
//--- result
return(m_balance);
}
//+------------------------------------------------------------------+
//| Selecting next node |
//+------------------------------------------------------------------+
CTreeNode *CTreeNode::GetNext(const CTreeNode *node)
{
if(Compare(node)>0)
return(m_l_node);
//--- result
return(m_r_node);
}
//+------------------------------------------------------------------+
//| Writing node data to file |
//+------------------------------------------------------------------+
bool CTreeNode::SaveNode(const int file_handle)
{
bool result=true;
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- write left node (if it is available)
if(m_l_node!=NULL)
{
FileWriteInteger(file_handle,'L',SHORT_VALUE);
result&=m_l_node.SaveNode(file_handle);
}
else
FileWriteInteger(file_handle,'X',SHORT_VALUE);
//--- write data of current node
result&=Save(file_handle);
//--- write right node (if it is available)
if(m_r_node!=NULL)
{
FileWriteInteger(file_handle,'R',SHORT_VALUE);
result&=m_r_node.SaveNode(file_handle);
}
else
FileWriteInteger(file_handle,'X',SHORT_VALUE);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading node data from file |
//+------------------------------------------------------------------+
bool CTreeNode::LoadNode(const int file_handle,CTreeNode *main)
{
bool result=true;
short s_val;
CTreeNode *node;
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- read directions
s_val=(short)FileReadInteger(file_handle,SHORT_VALUE);
if(s_val=='L')
{
//--- read left node (if there is data)
node=CreateSample();
if(node==NULL)
return(false);
m_l_node=node;
node.Parent(main);
result&=node.LoadNode(file_handle,node);
}
//--- read data of current node
result&=Load(file_handle);
//--- read directions
s_val=(short)FileReadInteger(file_handle,SHORT_VALUE);
if(s_val=='R')
{
//--- read right node (if there is data)
node=CreateSample();
if(node==NULL)
return(false);
m_r_node=node;
node.Parent(main);
result&=node.LoadNode(file_handle,node);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
+347
View File
@@ -0,0 +1,347 @@
//+------------------------------------------------------------------+
//| HistogramChart.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "ChartCanvas.mqh"
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Class CHistogramChart |
//| Usage: generates histogram chart |
//+------------------------------------------------------------------+
class CHistogramChart : public CChartCanvas
{
private:
//--- colors
uint m_fill_brush[];
//--- adjusted parameters
bool m_gradient;
uint m_bar_gap;
uint m_bar_min_size;
uint m_bar_border;
//--- data
CArrayObj *m_values;
public:
CHistogramChart(void);
~CHistogramChart(void);
//--- create
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE);
//--- adjusted parameters
void Gradient(const bool flag=true) { m_gradient=flag; }
void BarGap(const uint value) { m_bar_gap=value; }
void BarMinSize(const uint value) { m_bar_min_size=value; }
void BarBorder(const uint value) { m_bar_border=value; }
//--- data
bool SeriesAdd(const double &value[],const string descr="",const uint clr=0);
bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0);
bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0);
bool SeriesDelete(const uint pos);
bool ValueUpdate(const uint series,const uint pos,double value);
protected:
virtual void DrawData(const uint idx);
void DrawBar(const int x,const int y,const int w,const int h,const uint clr);
void GradientBrush(const int size,const uint fill_clr);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CHistogramChart::CHistogramChart(void) : m_gradient(true),
m_bar_gap(3),
m_bar_min_size(5),
m_bar_border(0)
{
ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CHistogramChart::~CHistogramChart(void)
{
if(ArraySize(m_fill_brush)!=0)
ArrayFree(m_fill_brush);
}
//+------------------------------------------------------------------+
//| Create dynamic resource |
//+------------------------------------------------------------------+
bool CHistogramChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
//--- create object to store data
if((m_values=new CArrayObj)==NULL)
return(false);
//--- pass responsibility for its destruction to the parent class
m_data=m_values;
//--- call method of parent class
if(!CChartCanvas::Create(name,width,height,clrfmt))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Adds data series |
//+------------------------------------------------------------------+
bool CHistogramChart::SeriesAdd(const double &value[],const string descr,const uint clr)
{
//--- check
if(m_data_total==m_max_data)
return(false);
//--- add
CArrayDouble *arr=new CArrayDouble;
if(!m_values.Add(arr))
return(false);
if(!arr.AssignArray(value))
return(false);
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
return(false);
if(!m_descriptors.Add(descr))
return(false);
m_data_total++;
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Inserts data series |
//+------------------------------------------------------------------+
bool CHistogramChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr)
{
//--- check
if(m_data_total==m_max_data)
return(false);
if(pos>=m_data_total)
return(false);
//--- insert
CArrayDouble *arr=new CArrayDouble;
if(!m_values.Insert(arr,pos))
return(false);
if(!arr.AssignArray(value))
return(false);
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
return(false);
if(!m_descriptors.Insert(descr,pos))
return(false);
m_data_total++;
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Updates data series |
//+------------------------------------------------------------------+
bool CHistogramChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr)
{
//--- check
if(pos>=m_data_total)
return(false);
CArrayDouble *data=m_values.At(pos);
if(data==NULL)
return(false);
//--- update
if(!data.AssignArray(value))
return(false);
if(clr!=0 && !m_colors.Update(pos,clr))
return(false);
if(descr!=NULL && !m_descriptors.Update(pos,descr))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Deletes data series |
//+------------------------------------------------------------------+
bool CHistogramChart::SeriesDelete(const uint pos)
{
//--- check
if(pos>=m_data_total && m_data_total!=0)
return(false);
//--- delete
if(!m_values.Delete(pos))
return(false);
m_data_total--;
if(!m_colors.Delete(pos))
return(false);
if(!m_descriptors.Delete(pos))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Updates element in data series |
//+------------------------------------------------------------------+
bool CHistogramChart::ValueUpdate(const uint series,const uint pos,double value)
{
CArrayDouble *data=m_values.At(series);
//--- check
if(data==NULL)
return(false);
//--- update
if(!data.Update(pos,value))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Draws histogram |
//+------------------------------------------------------------------+
void CHistogramChart::DrawData(const uint idx)
{
double value=0.0;
//--- check
CArrayDouble *data=m_values.At(idx);
if(data==NULL)
return;
int total=data.Total();
if(total==0 || (int)idx>=total)
return;
//--- calculate
int x1=m_data_area.left;
int x2=m_data_area.right;
int dx=(x2-x1)/total;
uint clr=m_colors[idx];
uint w=dx/m_data_total;
if(w<m_bar_min_size)
w=m_bar_min_size;
int x=x1+(int)(m_bar_gap+w*idx);
//--- set font
string fontname;
int fontsize=0;
uint fontflags=0;
uint fontangle=0;
if(IS_SHOW_VALUE)
{
FontGet(fontname,fontsize,fontflags,fontangle);
FontSet(fontname,-10*(w-3),fontflags,900);
}
//--- prepare gradient fill
GradientBrush(w,clr);
//--- draw
for(int i=0;i<total;i++,x+=dx)
{
int y,h = 0;
double val=data[i];
if(val==EMPTY_VALUE)
continue;
if(m_accumulative)
value+=val;
else
value=val;
// int val=(int)(value*m_scale_y);
if(value>0)
{
y=(m_y_0+(int)(value*m_scale_y));
h=m_y_0-y;
}
else
{
y=m_y_0;
h=(int)(value*m_scale_y);
}
DrawBar(x,y,w,h,clr);
//--- draw text of value
if(IS_SHOW_VALUE)
{
string text =DoubleToString(value,2);
int width=(int)(TextWidth(text)+w);
if(value>0)
{
if(width>y-m_y_max)
TextOut(x+w/2,y+w,text,m_color_text,TA_RIGHT|TA_VCENTER);
else
TextOut(x+w/2,y-w,text,m_color_text,TA_LEFT|TA_VCENTER);
}
else
{
if(width>m_y_min-y-h)
TextOut(x+w/2,y+h-w,text,m_color_text,TA_LEFT|TA_VCENTER);
else
TextOut(x+w/2,y+h+w,text,m_color_text,TA_RIGHT|TA_VCENTER);
}
}
}
if(IS_SHOW_VALUE)
FontSet(fontname,fontsize,fontflags,fontangle);
}
//+------------------------------------------------------------------+
//| Draws bar |
//+------------------------------------------------------------------+
void CHistogramChart::DrawBar(const int x,const int y,const int w,const int h,const uint clr)
{
//--- draw bar
if(!m_gradient || ArraySize(m_fill_brush)<w)
FillRectangle(x+1,y+1,w-x-2,h-y-2,clr);
else
{
for(int i=1;i<h;i++)
ArrayCopy(m_pixels,m_fill_brush,(y+i)*m_width+x+1,0,w);
}
//--- draw bar border
if(m_bar_border!=0)
Rectangle(x,y,x+w-1,y+h-1,m_color_border);
}
//+------------------------------------------------------------------+
//| Creates brush for gradient fill |
//+------------------------------------------------------------------+
void CHistogramChart::GradientBrush(const int size,const uint fill_clr)
{
//--- to prepare gradient fill, we will use Bresenham's circle algorithm
//--- X coordinate - size of the fill,
//--- Y coordinate - color brightness
if(m_gradient)
{
//--- adjust gradient radius if necessary
int r=size;
//--- check
if(r<1)
return;
if(r!=ArrayResize(m_fill_brush,r))
return;
//--- initialize brush
ArrayInitialize(m_fill_brush,m_color_background);
//--- variables
int f =1-r;
int dd_x=1;
int dd_y=-2*r;
int dx =0;
int dy =r;
int i1,i2;
uint clr,dclr;
//---
i1=i2=r>>1;
if((r&1)==0)
i1--;
//--- calculate
while(dy>=dx)
{
clr=fill_clr;
dclr=GETRGB(XRGB((r-dy)*GETRGBR(clr)/r,(r-dy)*GETRGBG(clr)/r,(r-dy)*GETRGBB(clr)/r));
clr-=dclr;
m_fill_brush[i1]=clr;
m_fill_brush[i2]=clr;
//---
if(f>=0)
{
dy--;
dd_y+=2;
f+=dd_y;
}
dx++;
if(--i1<0)
break;
i2++;
dd_x+=2;
f+=dd_x;
}
}
else
ArrayFree(m_fill_brush);
}
//+------------------------------------------------------------------+
+383
View File
@@ -0,0 +1,383 @@
//+------------------------------------------------------------------+
//| LineChart.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "ChartCanvas.mqh"
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Class CLineChart |
//| Usage: generates line chart |
//+------------------------------------------------------------------+
class CLineChart : public CChartCanvas
{
private:
//--- data
CArrayObj* m_values;
//--- adjusted parameters
bool m_filled;
public:
CLineChart(void);
~CLineChart(void);
//--- create
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE);
//--- adjusted parameters
void Filled(const bool flag=true) { m_filled=flag; }
//--- set up
bool SeriesAdd(const double &value[],const string descr="",const uint clr=0);
bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0);
bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0);
bool SeriesDelete(const uint pos);
bool ValueUpdate(const uint series,const uint pos,double value);
protected:
virtual void DrawChart(void);
virtual void DrawData(const uint index=0);
private:
double CalcArea(const uint index);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CLineChart::CLineChart(void) : m_filled(false)
{
ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CLineChart::~CLineChart(void)
{
}
//+------------------------------------------------------------------+
//| Create dynamic resource |
//+------------------------------------------------------------------+
bool CLineChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
//--- create object to store data
if((m_values=new CArrayObj)==NULL)
return(false);
//--- pass responsibility for its destruction to the parent class
m_data=m_values;
//--- call method of parent class
if(!CChartCanvas::Create(name,width,height,clrfmt))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Adds data series |
//+------------------------------------------------------------------+
bool CLineChart::SeriesAdd(const double &value[],const string descr,const uint clr)
{
//--- check
if(m_data_total==m_max_data)
return(false);
//--- add
CArrayDouble *arr=new CArrayDouble;
if(!m_values.Add(arr))
return(false);
if(!arr.AssignArray(value))
return(false);
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
return(false);
if(!m_descriptors.Add(descr))
return(false);
m_data_total++;
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Inserts data series |
//+------------------------------------------------------------------+
bool CLineChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr)
{
//--- check
if(m_data_total==m_max_data)
return(false);
if(pos>=m_data_total)
return(false);
//--- insert
CArrayDouble *arr=new CArrayDouble;
if(!m_values.Insert(arr,pos))
return(false);
if(!arr.AssignArray(value))
return(false);
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
return(false);
if(!m_descriptors.Insert(descr,pos))
return(false);
m_data_total++;
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Updates data series |
//+------------------------------------------------------------------+
bool CLineChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr)
{
//--- check
if(pos>=m_data_total)
return(false);
CArrayDouble *data=m_values.At(pos);
if(data==NULL)
return(false);
//--- update
if(!data.AssignArray(value))
return(false);
if(clr!=0 && !m_colors.Update(pos,clr))
return(false);
if(descr!=NULL && !m_descriptors.Update(pos,descr))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Deletes data series |
//+------------------------------------------------------------------+
bool CLineChart::SeriesDelete(const uint pos)
{
//--- check
if(pos>=m_data_total && m_data_total!=0)
return(false);
//--- delete
if(!m_values.Delete(pos))
return(false);
m_data_total--;
if(!m_colors.Delete(pos))
return(false);
if(!m_descriptors.Delete(pos))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Updates element in data series |
//+------------------------------------------------------------------+
bool CLineChart::ValueUpdate(const uint series,const uint pos,double value)
{
CArrayDouble *data=m_values.At(series);
//--- check
if(data==NULL)
return(false);
//--- update
if(!data.Update(pos,value))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Redraws data |
//+------------------------------------------------------------------+
void CLineChart::DrawChart(void)
{
if(m_filled)
{
//--- calculate areas of filling
double s[];
ArrayResize(s,m_data_total);
ArrayInitialize(s,0);
for(uint i=0;i<m_data_total;i++)
{
CArrayDouble *data=m_values.At(i);
if(data==NULL)
continue;
int total=data.Total();
if(total<=1)
continue;
s[i]=CalcArea(i);
}
int index=ArrayMaximum(s);
while(index!=-1 && s[index]!=0.0)
{
//--- draw in area descending order
DrawData(index);
s[index]=0.0;
index=ArrayMaximum(s);
}
}
else
for(uint i=0;i<m_data_total;i++)
DrawData(i);
}
//+------------------------------------------------------------------+
//| Draws lines |
//+------------------------------------------------------------------+
void CLineChart::DrawData(const uint index)
{
double value=0.0;
//--- check
CArrayDouble *data=m_values.At(index);
if(data==NULL)
return;
int total=data.Total();
if(total<=1)
return;
//--- calculate
int dx=m_data_area.Width()/(total-1);
int x=m_data_area.left+1;
int y1=0;
int y2=(int)(m_y_min+(data[0]-m_v_scale_min)*m_scale_y);
//--- draw
for(int i=1;i<total;i++,x+=dx)
{
y1=y2;
double val=data[i];
if(val==EMPTY_VALUE)
continue;
if(m_accumulative)
value+=val;
else
value=val;
y2=(int)(m_y_min+(value-m_v_scale_min)*m_scale_y);
if(m_filled)
{
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_y_0))
{
//--- draw two triangles
int x3;
if(y1>y2)
{
x3=x+dx*(y1-m_y_0)/(y1-y2);
FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]);
FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]);
}
else
{
x3=x+dx*(m_y_0-y1)/(y2-y1);
FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]);
FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]);
}
continue;
}
if(y1<m_y_0 || y2<m_y_0)
{
if(y1>y2)
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
if(y1<y2)
{
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
y1=y2;
}
}
if(y1>m_y_0 || y2>m_y_0)
{
if(y1<y2)
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
if(y1>y2)
{
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
y1=y2;
}
}
FillRectangle(x,m_y_0,x+dx,y1,(uint)m_colors[index]);
}
else
LineAA(x,y1,x+dx,y2,(uint)m_colors[index],STYLE_SOLID);
}
}
//+------------------------------------------------------------------+
//| Area of filling |
//+------------------------------------------------------------------+
double CLineChart::CalcArea(const uint index)
{
double area =0;
double value=0;
int dx =100;
//---
CArrayDouble *data=m_values.At(index);
if(data==NULL)
return(0);
int total=data.Total();
if(total<=1)
return(0);
int y1=0;
int y2=(int)(m_y_0-data[0]*m_scale_y);
for(int i=0;i<total;i++)
{
y1=y2;
double val=data[i];
if(val==EMPTY_VALUE)
continue;
if(m_accumulative)
value+=val;
else
value=val;
y2=(int)(m_y_0-value*m_scale_y);
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_y_0))
{
//--- line of values crosses the Y axis
int x;
if(y1>y2)
{
//--- from the bottom up
x=dx*(y1-m_y_0)/(y1-y2);
//--- add area of lower triangle
area+=x*(y1-m_y_0)/2;
//--- add area of upper triangle
area+=(dx-x)*(m_y_0-y2)/2;
}
else
{
//--- from top down
x=dx*(m_y_0-y1)/(y2-y1);
//--- add area of upper triangle
area+=x*(m_y_0-y1)/2;
//--- add area of lower triangle
area+=(dx-x)*(y2-m_y_0)/2;
}
continue;
}
if(y1<m_y_0 || y2<m_y_0)
{
//--- both values are greater than zero
if(y1>y2)
{
//--- add area of triangle
area+=dx*(y1-y2)/2;
//--- add area of rectangle
area+=dx*(m_y_0-y2);
}
if(y1<y2)
{
//--- add area of triangle
area+=dx*(y2-y1)/2;
//--- add area of rectangle
area+=dx*(m_y_0-y1);
}
}
if(y1>m_y_0 || y2>m_y_0)
{
//--- both values are less than zero
if(y1<y2)
{
//--- add area of triangle
area+=dx*(y2-y1)/2;
//--- add area of rectangle
area+=dx*(y1-m_y_0);
}
if(y1>y2)
{
//--- add area of triangle
area+=dx*(y1-y2)/2;
//--- add area of rectangle
area+=dx*(y2-m_y_0);
}
}
}
//---
return(area);
}
//+------------------------------------------------------------------+
+414
View File
@@ -0,0 +1,414 @@
//+------------------------------------------------------------------+
//| PieChart.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "ChartCanvas.mqh"
//+------------------------------------------------------------------+
//| Class CPieChart |
//| Usage: generates pie chart |
//+------------------------------------------------------------------+
class CPieChart : public CChartCanvas
{
private:
//--- data
CArrayDouble *m_values;
//--- for draw
int m_x0;
int m_y0;
int m_r;
public:
CPieChart(void);
~CPieChart(void);
//--- create
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
//--- data
bool SeriesSet(const double &value[],const string &text[],const uint &clr[]);
bool ValueAdd(const double value,const string descr="",const uint clr=0);
bool ValueInsert(const uint pos,const double value,const string descr="",const uint clr=0);
bool ValueUpdate(const uint pos,const double value,const string descr=NULL,const uint clr=0);
bool ValueDelete(const uint pos);
protected:
virtual void DrawChart(void);
void DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr);
string LabelMake(const string text,const double value,const bool to_left);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CPieChart::CPieChart(void)
{
uint flags=FLAG_SHOW_LEGEND|FLAG_SHOW_DESCRIPTORS|FLAG_SHOW_VALUE|FLAG_SHOW_PERCENT;
AllowedShowFlags(flags);
ShowFlags(flags);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CPieChart::~CPieChart(void)
{
}
//+------------------------------------------------------------------+
//| Create dynamic resource |
//+------------------------------------------------------------------+
bool CPieChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
//--- create object to store data
if((m_values=new CArrayDouble)==NULL)
return(false);
//--- pass responsibility for its destruction to the parent class
m_data=m_values;
//--- call method of parent class
if(!CChartCanvas::Create(name,width,height,clrfmt))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Sets displayed parameters |
//+------------------------------------------------------------------+
bool CPieChart::SeriesSet(const double &value[],const string &text[],const uint &clr[])
{
//--- !!! user is responsible for correct filling of arrays !!!
//--- check
if(m_values==NULL)
return(false);
//--- set
if(!m_values.AssignArray(value))
return(false);
if(!m_descriptors.AssignArray(text))
return(false);
if(!m_colors.AssignArray(clr))
return(false);
m_data_total=m_values.Total();
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Adds displayed parameter (to the end) |
//+------------------------------------------------------------------+
bool CPieChart::ValueAdd(const double value,const string descr,const uint clr)
{
//--- check
if((value<=0))
return(false);
//--- add
if(!m_values.Add(value))
return(false);
if(!m_descriptors.Add(descr))
return(false);
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
return(false);
m_data_total++;
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Inserts displayed parameter (to specified position) |
//+------------------------------------------------------------------+
bool CPieChart::ValueInsert(const uint pos,const double value,const string descr,const uint clr)
{
//--- check
if((value<=0))
return(false);
//--- insert
if(!m_values.Insert(value,pos))
return(false);
if(!m_descriptors.Insert(descr,pos))
return(false);
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
return(false);
m_data_total++;
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Updates displayed parameter (in specified position) |
//+------------------------------------------------------------------+
bool CPieChart::ValueUpdate(const uint pos,const double value,const string descr,const uint clr)
{
//--- check
if((value<=0))
return(false);
//--- update
if(!m_values.Update(pos,value))
return(false);
if(descr!=NULL && !m_descriptors.Update(pos,descr))
return(false);
if(clr!=0 && !m_colors.Update(pos,clr))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Deletes displayed parameter (from specified position) |
//+------------------------------------------------------------------+
bool CPieChart::ValueDelete(const uint pos)
{
//--- delete
if(!m_values.Delete(pos))
return(false);
m_data_total--;
if(!m_descriptors.Delete(pos))
return(false);
if(!m_colors.Delete(pos))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Draws |
//+------------------------------------------------------------------+
void CPieChart::DrawChart(void)
{
//--- check
if(m_data_total==0)
return;
//--- variables
string text="";
double angle=M_PI*(m_data_offset%360)/180;
int width,height;
int dw=0;
int dh=0;
int index;
CPoint p0[];
CPoint p1[];
//--- calculate geometry
width =(m_data_area.Width()<<3)/10;
height=(m_data_area.Height()<<3)/10;
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
{
if(IS_SHOW_VALUE)
dw=(int)m_max_value_width;
else
{
if(IS_SHOW_PERCENT)
dw=TextWidth("100.00%");
}
}
else
{
if(IS_SHOW_DESCRIPTORS)
{
if(IS_SHOW_VALUE)
dw=(int)m_max_value_width+TextWidth(" ()");
else
{
if(IS_SHOW_PERCENT)
dw=TextWidth(" (100.00%)");
}
dw+=(int)m_max_descr_width;
}
}
//--- pie chart will always be round
width -=2*dw+10;
height-=20;
m_x0=m_data_area.left+(m_data_area.Width()>>1);
m_y0=m_data_area.top+(m_data_area.Height()>>1);
m_r =(((width>height) ? height : width)>>1);
//--- draw pie chart
if(ArrayResize(p0,m_data_total+1)==-1)
return;
if(m_data_total==1)
{
FillCircle(m_x0,m_y0,m_r,m_colors[0]);
Circle(m_x0,m_y0,m_r,m_color_border);
}
else
{
Circle(m_x0,m_y0,m_r,m_color_border);
for(uint i=0;i<m_index_size;i++)
{
index=m_index[i];
double val=m_values[index];
double d_a=2*M_PI*val/m_sum;
DrawPie(angle,angle+d_a,i,p0,m_colors[index]);
angle+=d_a;
angle=MathMod(angle,2*M_PI);
}
if(m_data_total!=m_index_size)
DrawPie(angle,angle+2*M_PI*m_others/m_sum,m_index_size,p0,COLOR2RGB(clrBlack));
for(uint i=0;i<=m_index_size;i++)
Line(m_x0,m_y0,p0[i].x,p0[i].y,m_color_border);
Circle(m_x0,m_y0,m_r,m_color_border);
}
//--- draw descriptors
angle=M_PI*(m_data_offset%360)/180;
int r1=(int)round(1.1*m_r);
if(ArrayResize(p1,m_data_total)==-1)
return;
//--- calculations
for(uint i=0;i<m_index_size;i++)
{
index=m_index[i];
angle+=M_PI*m_values[index]/m_sum;
//--- lines
p0[i].x=m_x0+(int)round(m_r*cos(angle));
p0[i].y=m_y0-(int)round(m_r*sin(angle));
p1[i].x=m_x0+(int)round(r1*cos(angle));
p1[i].y=m_y0-(int)round(r1*sin(angle));
angle+=M_PI*m_values[index]/m_sum;
}
if(m_data_total!=m_index_size)
{
index=(int)m_data_total-1;
angle+=M_PI*m_others/m_sum;
p0[index].x=m_x0+(int)round(m_r*cos(angle));
p0[index].y=m_y0-(int)round(m_r*sin(angle));
p1[index].x=m_x0+(int)round(r1*cos(angle));
p1[index].y=m_y0-(int)round(r1*sin(angle));
}
int x,y;
//--- draw descriptors to the left
for(uint i=0;i<m_index_size;i++)
if(p0[i].x<m_x0)
{
x=p1[i].x-10;
y=p1[i].y;
index=m_index[i];
text=LabelMake(m_descriptors[index],m_values[index],true);
if(text!="")
{
Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border);
Line(p1[i].x,p1[i].y,x,y,m_color_border);
TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER);
}
}
//--- draw descriptors to the right
for(uint i=0;i<m_index_size;i++)
if(p0[i].x>=m_x0)
{
x=p1[i].x+10;
y=p1[i].y;
index=m_index[i];
text=LabelMake(m_descriptors[index],m_values[index],false);
if(text!="")
{
Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border);
Line(p1[i].x,p1[i].y,x,y,m_color_border);
TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER);
}
}
if(m_data_total!=m_index_size)
{
index=(int)m_data_total-1;
if(p0[index].x>=m_x0)
{
x=p1[index].x+10;
y=p1[index].y;
text=LabelMake("Others",m_others,true);
TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER);
}
else
{
x=p1[index].x-10;
y=p1[index].y;
text=LabelMake("Others",m_others,false);
TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER);
}
if(text!="")
{
Line(p0[index].x,p0[index].y,p1[index].x,p1[index].y,m_color_border);
Line(p1[index].x,p1[index].y,x,y,m_color_border);
}
}
ArrayFree(p1);
ArrayFree(p0);
}
//+------------------------------------------------------------------+
//| Draw pie |
//+------------------------------------------------------------------+
void CPieChart::DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr)
{
//--- draw arc
Arc(m_x0,m_y0,m_r,m_r,fi3,fi4,p[idx].x,p[idx].y,p[idx+1].x,p[idx+1].y,clr);
//--- variables
int x3=p[idx].x;
int y3=p[idx].y;
int x4=p[idx+1].x;
int y4=p[idx+1].y;
//--- draw radii
if(idx==0)
Line(m_x0,m_y0,x3,y3,clr);
if(idx!=m_data_total-1)
Line(m_x0,m_y0,x4,y4,clr);
//--- fill
double fi=(fi3+fi4)/2;
int xf=m_x0+(int)(0.99*m_r*cos(fi));
int yf=m_y0-(int)(0.99*m_r*sin(fi));
Fill(xf,yf,clr);
//--- for small pie
if(fi4-fi3<=M_PI_4)
Line(m_x0,m_y0,xf,yf,clr);
}
//+------------------------------------------------------------------+
//| Make label for pie |
//+------------------------------------------------------------------+
string CPieChart::LabelMake(const string text,const double value,const bool to_left)
{
string label="";
//---
if(to_left)
{
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
{
if(IS_SHOW_VALUE)
label=DoubleToString(value,2);
else
{
if(IS_SHOW_PERCENT)
label=DoubleToString(100*value/m_sum,2)+"%";
}
}
else
{
label=text;
if(IS_SHOW_VALUE)
label+=" ("+DoubleToString(value,2)+")";
else
{
if(IS_SHOW_PERCENT)
label+=" ("+DoubleToString(100*value/m_sum,2)+"%)";
}
}
}
else
{
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
{
if(IS_SHOW_VALUE)
label=DoubleToString(value,2);
else
{
if(IS_SHOW_PERCENT)
label=DoubleToString(100*value/m_sum,2)+"%";
}
}
else
{
if(IS_SHOW_VALUE)
label="("+DoubleToString(value,2)+") ";
else
{
if(IS_SHOW_PERCENT)
label="("+DoubleToString(100*value/m_sum,2)+"%) ";
}
label+=text;
}
}
//---
return(label);
}
//+------------------------------------------------------------------+
+75
View File
@@ -0,0 +1,75 @@
//+------------------------------------------------------------------+
//| DXBox.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//---
#include "DXMesh.mqh"
#include "DXMath.mqh"
#include "DXUtils.mqh"
//+------------------------------------------------------------------+
//| 3D Box object |
//+------------------------------------------------------------------+
class CDXBox : public CDXMesh
{
public:
CDXBox();
~CDXBox();
//--- create bon in specified context
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVector3 &from,const DXVector3 &to);
//--- update box
bool Update(const DXVector3 &from,const DXVector3 &to);
private:
//---
void PrepareVertices(const DXVector3 &from,const DXVector3 &to);
};
//+------------------------------------------------------------------+
//| Class constructor |
//+------------------------------------------------------------------+
void CDXBox::CDXBox() : CDXMesh()
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
void CDXBox::~CDXBox(void)
{
}
//+------------------------------------------------------------------+
//| Create box in specified context |
//+------------------------------------------------------------------+
bool CDXBox::Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVector3 &from,const DXVector3 &to)
{
//--- release previous buffers
Shutdown();
//---
DXVertex vertices[];
uint indices[];
//--- prepare box vertices and indices
if(!DXComputeBox(from,to,vertices,indices))
return(false);
for(int i=0; i<ArraySize(vertices); i++)
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
//--- create mesh
return(CDXMesh::Create(dispatcher,buffer_scene,vertices,indices));
}
//+------------------------------------------------------------------+
//| Update box bounds |
//+------------------------------------------------------------------+
bool CDXBox::Update(const DXVector3 &from,const DXVector3 &to)
{
//---
DXVertex vertices[];
uint indices[];
//--- prepare box vertices and indices
if(!DXComputeBox(from,to,vertices,indices))
return(false);
for(int i=0; i<ArraySize(vertices); i++)
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
//--- update mesh vertices, indices are the same
return(CDXMesh::VerticesSet(vertices));
}
//+------------------------------------------------------------------+
+92
View File
@@ -0,0 +1,92 @@
//+------------------------------------------------------------------+
//| DXVertexBuffer.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#include "DXHandle.mqh"
//+------------------------------------------------------------------+
//| DX vertex buffer |
//+------------------------------------------------------------------+
class CDXVertexBuffer : public CDXHandleShared
{
public:
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
virtual ~CDXVertexBuffer(void)
{
Shutdown();
}
//+------------------------------------------------------------------+
//| Create vertex buffer in specified context |
//+------------------------------------------------------------------+
template<typename TVertex>
bool Create(int context_handle,const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY)
{
Shutdown();
m_context=context_handle;
m_handle=DXBufferCreate(m_context,DX_BUFFER_VERTEX,vertices,start,count);
return(m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//| Render |
//+------------------------------------------------------------------+
bool Render(uint start=0,uint count=WHOLE_ARRAY)
{
return(DXBufferSet(m_context,m_handle,start,count));
}
//+------------------------------------------------------------------+
//| Shutdown |
//+------------------------------------------------------------------+
void Shutdown(void)
{
//--- relase handle
if(m_handle!=INVALID_HANDLE)
DXRelease(m_handle);
m_handle=INVALID_HANDLE;
}
};
//+------------------------------------------------------------------+
//| DX index buffer |
//+------------------------------------------------------------------+
class CDXIndexBuffer : public CDXHandleShared
{
public:
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
virtual ~CDXIndexBuffer(void)
{
Shutdown();
}
//+------------------------------------------------------------------+
//| Create index buffer in specified context |
//+------------------------------------------------------------------+
bool Create(int context_handle,const uint &indices[],uint start=0,uint count=WHOLE_ARRAY)
{
Shutdown();
m_context=context_handle;
m_handle=DXBufferCreate(m_context,DX_BUFFER_INDEX,indices,start,count);
return(m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//| Render |
//+------------------------------------------------------------------+
bool Render(uint start=0,uint count=WHOLE_ARRAY)
{
return(DXBufferSet(m_context,m_handle,start,count));
}
//+------------------------------------------------------------------+
//| Shutdown |
//+------------------------------------------------------------------+
void Shutdown(void)
{
//--- relase handle
if(m_handle!=INVALID_HANDLE)
DXRelease(m_handle);
m_handle=INVALID_HANDLE;
}
};
//+------------------------------------------------------------------+
Binary file not shown.
+373
View File
@@ -0,0 +1,373 @@
//+------------------------------------------------------------------+
//| DXDispatcher.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//---
#include "DXObjectBase.mqh"
#include "DXData.mqh"
#include "DXBuffers.mqh"
#include "DXInput.mqh"
#include "DXTexture.mqh"
#include "DXShader.mqh"
//--- default shaders
#resource "Shaders/DefaultShaderVertex.hlsl" as string ExtDefaultShaderVertex;
#resource "Shaders/DefaultShaderPixel.hlsl" as string ExtDefaultShaderPixel;
//+------------------------------------------------------------------+
//| DX dispatcher which holds all resources |
//+------------------------------------------------------------------+
class CDXDispatcher : public CDXObjectBase
{
protected:
CDXObjectBase m_dx_resources; // DX resources list (Textures, Shaders, etc.)
//--- default shaders
CDXShader* m_default_vs;
CDXShader* m_default_ps;
public:
CDXDispatcher(void);
~CDXDispatcher(void);
//--- create/destroy
bool Create(int context);
void Destroy(void);
//--- check resources
void Check(void);
//--- get DX Context Handle
int DXContext(void) const { return(m_context); }
//--- create shaders
CDXShader* ShaderCreateDefault(ENUM_DX_SHADER_TYPE shader_type);
CDXShader* ShaderCreateFromFile(ENUM_DX_SHADER_TYPE shader_type,string path,string entry_point);
CDXShader* ShaderCreateFromSource(ENUM_DX_SHADER_TYPE shader_type,string source,string entry_point);
//--- create buffers
template<typename TVertex>
CDXVertexBuffer* VertexBufferCreate(const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY);
CDXIndexBuffer* IndexBufferCreate(const uint &indicies[],uint start=0,uint count=WHOLE_ARRAY);
//--- create shader inputs
template<typename TInput>
CDXInput* InputCreate(void);
CDXTexture* TextureCreateFromFile(string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0);
CDXTexture* TextureCreateFromData(ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0);
private:
//--- add resource to list
bool ResourceAdd(CDXObjectBase *resource);
//--- check resources
void ResourcesCheck(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDXDispatcher::CDXDispatcher(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDXDispatcher::~CDXDispatcher(void)
{
Destroy();
}
//+------------------------------------------------------------------+
//| Create |
//+------------------------------------------------------------------+
bool CDXDispatcher::Create(int context)
{
//--- check if context already exist
if(m_context!=INVALID_HANDLE)
return(false);
//--- save context
m_context=context;
//---
return(true);
}
//+------------------------------------------------------------------+
//| Destroy |
//+------------------------------------------------------------------+
void CDXDispatcher::Destroy(void)
{
//--- release default shaders
if(m_default_ps)
{
m_default_ps.Release();
m_default_ps=NULL;
}
if(m_default_vs)
{
m_default_vs.Release();
m_default_vs=NULL;
}
//--- release and delete all DX resources
while(m_dx_resources.Next())
{
CDXHandleShared* resource=(CDXHandleShared*)m_dx_resources.Next();
resource.Release();
}
//--- forget context
m_context=INVALID_HANDLE;
}
//+------------------------------------------------------------------+
//| Check resources |
//+------------------------------------------------------------------+
void CDXDispatcher::Check(void)
{
//---
CDXHandleShared* resource=(CDXHandleShared*)m_dx_resources.Next();
//--- release and delete all DX resources
while(CheckPointer(resource)!=POINTER_INVALID)
{
CDXHandleShared* next=(CDXHandleShared*)resource.Next();
//--- if references count 1 or less, then only we hold the resource
if(resource.References()<=1)
resource.Release();
//---
resource=next;
}
}
//+------------------------------------------------------------------+
//| Create default shader of specified type |
//+------------------------------------------------------------------+
CDXShader* CDXDispatcher::ShaderCreateDefault(ENUM_DX_SHADER_TYPE shader_type)
{
switch(shader_type)
{
//--- default pixel shader
case DX_SHADER_PIXEL:
{
if(m_default_ps==NULL)
m_default_ps=ShaderCreateFromSource(DX_SHADER_PIXEL,ExtDefaultShaderPixel,"PSMain");
return(m_default_ps);
}
//--- default vertex shader
case DX_SHADER_VERTEX:
{
if(m_default_vs==NULL)
{
m_default_vs=ShaderCreateFromSource(DX_SHADER_VERTEX,ExtDefaultShaderVertex,"VSMain");
if(m_default_vs && !m_default_vs.LayoutSet<DXVertex>())
{
m_default_vs.Release();
m_default_vs=NULL;
}
}
return(m_default_vs);
}
}
//--- return result
return(NULL);
}
//+------------------------------------------------------------------+
//| Create new shader of specified type from file |
//+------------------------------------------------------------------+
CDXShader* CDXDispatcher::ShaderCreateFromFile(ENUM_DX_SHADER_TYPE shader_type,string path,string entry_point)
{
//--- open source file
int file=FileOpen(path,FILE_READ);
if(file==INVALID_HANDLE)
return(NULL);
//--- check file size
uint size=(uint)FileSize(file);
FileClose(file);
if(size>16*1024*1024)
return(NULL);
//--- prepare buffer
char buffer[];
ArrayResize(buffer,size);
//--- read file into buffer
int read=(int)FileLoad(path,buffer);
if(read<=0)
return(NULL);
//--- convert vuffer to string
string source=CharArrayToString(buffer,0,WHOLE_ARRAY,CP_UTF8);
//--- add shader by source
return(ShaderCreateFromSource(shader_type,source,entry_point));
}
//+------------------------------------------------------------------+
//| Create new shader of specified type from source code |
//+------------------------------------------------------------------+
CDXShader* CDXDispatcher::ShaderCreateFromSource(ENUM_DX_SHADER_TYPE shader_type,string source,string entry_point)
{
//--- check context
if(m_context==INVALID_HANDLE)
return(NULL);
//--- allocate new shader
CDXShader* shader=new CDXShader();
if(shader==NULL)
return(NULL);
//--- create shader
if(!shader.Create(m_context,shader_type,source,entry_point))
{
shader.Release();
return(NULL);
}
//--- add shader to resources list
if(!ResourceAdd(shader))
{
shader.Release();
return(NULL);
}
//--- return shader
return(shader);
}
//+------------------------------------------------------------------+
//| Create vertex buffer |
//+------------------------------------------------------------------+
template<typename TVertex>
CDXVertexBuffer* CDXDispatcher::VertexBufferCreate(const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY)
{
//--- check context
if(m_context==INVALID_HANDLE)
return(NULL);
//--- allocate new buffer
CDXVertexBuffer* buffer=new CDXVertexBuffer();
if(buffer==NULL)
return(NULL);
//--- create buffer
if(!buffer.Create(m_context,vertices,start,count))
{
buffer.Release();
return(NULL);
}
//--- add buffer to resources list
if(!ResourceAdd(buffer))
{
buffer.Release();
return(NULL);
}
//--- return buffer
return(buffer);
}
//+------------------------------------------------------------------+
//| Create vertex buffer |
//+------------------------------------------------------------------+
CDXIndexBuffer* CDXDispatcher::IndexBufferCreate(const uint &indicies[],uint start=0,uint count=WHOLE_ARRAY)
{
//--- check context
if(m_context==INVALID_HANDLE)
return(NULL);
//--- allocate new buffer
CDXIndexBuffer* buffer=new CDXIndexBuffer();
if(buffer==NULL)
return(NULL);
//--- create buffer
if(!buffer.Create(m_context,indicies,start,count))
{
buffer.Release();
return(NULL);
}
//--- add buffer to resources list
if(!ResourceAdd(buffer))
{
buffer.Release();
return(NULL);
}
//--- return input buffer
return(buffer);
}
//+------------------------------------------------------------------+
//| Create shader input buffer |
//+------------------------------------------------------------------+
template<typename TInput>
CDXInput* CDXDispatcher::InputCreate(void)
{
//--- check context
if(m_context==INVALID_HANDLE)
return(NULL);
//--- allocate new input buffer
CDXInput* input_buffer=new CDXInput();
if(input_buffer==NULL)
return(NULL);
//--- create buffer
if(!input_buffer.Create<TInput>(m_context))
{
input_buffer.Release();
return(NULL);
}
//--- add buffer to resources list
if(!ResourceAdd(input_buffer))
{
input_buffer.Release();
return(NULL);
}
//--- return shader
return(input_buffer);
}
//+------------------------------------------------------------------+
//| Create texture from bitmap file |
//+------------------------------------------------------------------+
CDXTexture* CDXDispatcher::TextureCreateFromFile(string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
{
//--- check context
if(m_context==INVALID_HANDLE)
return(NULL);
//--- allocate new texture
CDXTexture* texture=new CDXTexture();
if(texture==NULL)
return(NULL);
//--- create texture
if(!texture.Create(m_context,path,data_x,data_y,data_width,data_height))
{
texture.Release();
return(NULL);
}
//--- add texture to resources list
if(!ResourceAdd(texture))
{
texture.Release();
return(NULL);
}
//--- return shader
return(texture);
}
//+------------------------------------------------------------------+
//| Create texture from raw data, only 32-bit pixel formats supported|
//+------------------------------------------------------------------+
CDXTexture* CDXDispatcher::TextureCreateFromData(ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
{
//--- check context
if(m_context==INVALID_HANDLE)
return(NULL);
//--- allocate new texture
CDXTexture* texture=new CDXTexture();
if(texture==NULL)
return(NULL);
//--- create texture
if(!texture.Create(m_context,format,width,height,data,data_x,data_y,data_width,data_height))
{
texture.Release();
return(NULL);
}
//--- add texture to resources list
if(!ResourceAdd(texture))
{
texture.Release();
return(NULL);
}
//--- return shader
return(texture);
}
//+------------------------------------------------------------------+
//| Add DX resource |
//+------------------------------------------------------------------+
bool CDXDispatcher::ResourceAdd(CDXObjectBase *resource)
{
//--- add resource
if(!CheckPointer(resource))
return(false);
//---
CDXObjectBase *last=&m_dx_resources;
while(CheckPointer(last.Next())!=POINTER_INVALID)
{
if(last==resource)
return(false);
//---
last=last.Next();
}
//---
resource.Next(NULL);
resource.Prev(last);
last.Next(resource);
return(true);
}
//+------------------------------------------------------------------+
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+374
View File
@@ -0,0 +1,374 @@
//+------------------------------------------------------------------+
//| DXMesh.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#include "DXObject.mqh"
#include "DXDispatcher.mqh"
#include "DXData.mqh"
#include "DXUtils.mqh"
//+------------------------------------------------------------------+
//| DX simple mesh object with default shader |
//+------------------------------------------------------------------+
class CDXMesh : public CDXObject
{
protected:
//--- DX resources
CDXVertexBuffer* m_buffer_vertex;
CDXIndexBuffer* m_buffer_index;
CDXInput* m_buffer_object;
CDXInput* m_buffer_scene;
CDXShader* m_shader_vertex;
CDXShader* m_shader_pixel;
CDXTexture* m_texture;
//--- object data
DXMatrix m_transform_matrix;
DXColor m_diffuse_color;
DXColor m_emission_color;
DXColor m_specular_color;
float m_specular_power;
ENUM_DX_PRIMITIVE_TOPOLOGY m_topology;
public:
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDXMesh(void):m_buffer_vertex(NULL),m_buffer_index(NULL),m_buffer_object(NULL),m_buffer_scene(NULL),m_shader_vertex(NULL),m_shader_pixel(NULL),m_topology(WRONG_VALUE)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
~CDXMesh(void)
{
Shutdown();
}
//+------------------------------------------------------------------+
//| Create mesh object from vertices and indices list |
//+------------------------------------------------------------------+
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVertex &vertices[],const uint &indices[],ENUM_DX_PRIMITIVE_TOPOLOGY topology=DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
{
Shutdown();
//--- check data
if(buffer_scene==NULL || buffer_scene.Handle()==INVALID_HANDLE ||
ArraySize(vertices)<1 || ArraySize(indices)<1)
return(false);
//--- update context
m_context=dispatcher.DXContext();
//--- initialize default parameters
DXMatrixIdentity(m_transform_matrix);
m_diffuse_color =DXColor(1.0,1.0,1.0,1.0);
m_emission_color=DXColor(0.0,0.0,0.0,0.0);
m_specular_color=DXColor(0.0,0.0,0.0,0.0);
m_specular_power=16.0f;
//--- create object input
m_buffer_object=dispatcher.InputCreate<DXInputObject>();
if(m_buffer_object!=NULL)
{
m_buffer_object.AddRef();
//--- use default vertex shader
m_shader_vertex=dispatcher.ShaderCreateDefault(DX_SHADER_VERTEX);
if(m_shader_vertex!=NULL)
{
m_shader_vertex.AddRef();
//--- use default pixel shader
m_shader_pixel=dispatcher.ShaderCreateDefault(DX_SHADER_PIXEL);
if(m_shader_pixel!=NULL)
{
m_shader_pixel.AddRef();
//--- create vertex buffer
m_buffer_vertex=dispatcher.VertexBufferCreate(vertices);
if(m_buffer_vertex!=NULL)
{
m_buffer_vertex.AddRef();
//--- create index buffer
m_buffer_index=dispatcher.IndexBufferCreate(indices);
if(m_buffer_index!=NULL)
m_buffer_index.AddRef();
}
}
}
}
//--- set object buffer to shaders
if(m_buffer_object==NULL || m_shader_vertex==NULL || m_shader_pixel==NULL || m_buffer_vertex==NULL || m_buffer_index==NULL)
{
Shutdown();
return(false);
}
//--- save scene buffer
m_buffer_scene=buffer_scene;
m_buffer_scene.AddRef();
//--- save topology
m_topology=topology;
//---
return(true);
}
//+------------------------------------------------------------------+
//| Create mesh object from OBJ mesh file |
//+------------------------------------------------------------------+
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,string obj_path,float scale=1.0f,bool inverse_winding=false)
{
DXVertex vertices[];
uint indices[];
//--- load model
if(!DXLoadObjModel(obj_path,vertices,indices,scale))
return(false);
//--- set white vertices color
int count=ArraySize(vertices);
for(int i=0; i<count; i++)
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
//--- inverse winding
if(inverse_winding)
DXInverseWinding(vertices,indices);
//--- create mesh
return(Create(dispatcher,buffer_scene,vertices,indices));
}
//+------------------------------------------------------------------+
//| Update vertices |
//+------------------------------------------------------------------+
bool VerticesSet(const DXVertex &vertices[])
{
//--- check size
if(ArraySize(vertices)<1)
return(false);
//--- create new vertex buffer
if(!m_buffer_vertex.Create(m_context,vertices))
{
Shutdown();
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Update indices |
//+------------------------------------------------------------------+
bool IndicesSet(const uint &indices[])
{
//--- check size
if(ArraySize(indices)<1)
return(false);
//--- create new index buffer
if(!m_buffer_index.Create(m_context,indices))
{
Shutdown();
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Update indices |
//+------------------------------------------------------------------+
bool TopologySet(ENUM_DX_PRIMITIVE_TOPOLOGY topology)
{
m_topology=topology;
//---
return(true);
}
//+------------------------------------------------------------------+
//| Get transform matrix |
//+------------------------------------------------------------------+
void TransformMatrixGet(DXMatrix &mat) const
{
mat=m_transform_matrix;
}
//+------------------------------------------------------------------+
//| Set transform matrix |
//+------------------------------------------------------------------+
void TransformMatrixSet(const DXMatrix &mat)
{
m_transform_matrix=mat;
}
//+------------------------------------------------------------------+
//| Get diffuse color |
//+------------------------------------------------------------------+
void DiffuseColorGet(DXColor &clr) const
{
clr=m_diffuse_color;
}
//+------------------------------------------------------------------+
//| Set diffuse color |
//+------------------------------------------------------------------+
void DiffuseColorSet(const DXColor &clr)
{
m_diffuse_color=clr;
}
//+------------------------------------------------------------------+
//| Get specular color |
//+------------------------------------------------------------------+
void SpecularColorGet(DXColor &clr) const
{
clr=m_specular_color;
}
//+------------------------------------------------------------------+
//| Set specular color |
//+------------------------------------------------------------------+
void SpecularColorSet(const DXColor &clr)
{
m_specular_color=clr;
}
//+------------------------------------------------------------------+
//| Get specular power |
//+------------------------------------------------------------------+
void SpecularPowerGet(float &power) const
{
power=m_specular_power;
}
//+------------------------------------------------------------------+
//| Set specular power |
//+------------------------------------------------------------------+
void SpecularPowerSet(float power)
{
m_specular_power=power;
}
//+------------------------------------------------------------------+
//| Get emission color |
//+------------------------------------------------------------------+
void EmissionColorGet(DXColor &clr) const
{
clr=m_emission_color;
}
//+------------------------------------------------------------------+
//| Set emission color |
//+------------------------------------------------------------------+
void EmissionColorSet(const DXColor &clr)
{
m_emission_color=clr;
}
//+------------------------------------------------------------------+
//| Render mesh |
//+------------------------------------------------------------------+
virtual bool Render(void) override
{
//--- update object buffer
DXInputObject input_data;
DXMatrixTranspose(input_data.transform,m_transform_matrix);
input_data.diffuse_color =m_diffuse_color;
input_data.emission_color=m_emission_color;
input_data.specular_color=m_specular_color;
input_data.specular_power=m_specular_power;
//--- clear shader textures
m_shader_pixel.TexturesClear();
//--- set buffers, shaders, topology and render
if(m_buffer_object.InputSet(input_data))
if(m_buffer_vertex.Render())
if(m_buffer_index.Render())
if(m_shader_vertex.InputSet(0,m_buffer_scene) && m_shader_vertex.InputSet(1,m_buffer_object))
if(m_shader_pixel.InputSet(0,m_buffer_scene) && m_shader_pixel.InputSet(1,m_buffer_object))
if(CheckPointer(m_texture)==POINTER_INVALID || m_shader_pixel.TextureSet(0,m_texture))
if(m_shader_vertex.Render())
if(m_shader_pixel.Render())
if(DXPrimiveTopologySet(m_context,m_topology))
return(DXDrawIndexed(m_context));
//---
return(false);
}
//+------------------------------------------------------------------+
//| Set texture from image file |
//+------------------------------------------------------------------+
bool TextureSet(CDXDispatcher &dispatcher,string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
{
//--- check if texture already exist
if(CheckPointer(m_texture)==POINTER_INVALID)
{
m_texture=dispatcher.TextureCreateFromFile(path,data_x,data_y,data_width,data_height);
if(m_texture==NULL)
return(false);
m_texture.AddRef();
return(true);
}
//--- update texture data
if(!m_texture.Create(m_context,path,data_x,data_y,data_width,data_height))
{
m_texture.Release();
m_texture=NULL;
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Set texture from image data |
//+------------------------------------------------------------------+
bool TextureSet(CDXDispatcher &dispatcher,ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
{
//--- check if texture already exist
if(CheckPointer(m_texture)==POINTER_INVALID)
{
m_texture=dispatcher.TextureCreateFromData(format,width,height,data,data_x,data_y,data_width,data_height);
if(m_texture==NULL)
return(false);
m_texture.AddRef();
return(true);
}
//--- update texture data
if(!m_texture.Create(m_context,format,width,height,data,data_x,data_y,data_width,data_height))
{
m_texture.Release();
m_texture=NULL;
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Delete used texture |
//+------------------------------------------------------------------+
void TextureDelete()
{
//--- release texture
if(CheckPointer(m_texture)!=POINTER_INVALID)
{
m_texture.Release();
m_texture=NULL;
}
}
//+------------------------------------------------------------------+
//| Shutdown |
//+------------------------------------------------------------------+
virtual void Shutdown(void)
{
//--- release all dx resources
if(CheckPointer(m_buffer_vertex)!=POINTER_INVALID)
{
m_buffer_vertex.Release();
m_buffer_vertex=NULL;
}
if(CheckPointer(m_buffer_index)!=POINTER_INVALID)
{
m_buffer_index.Release();
m_buffer_index=NULL;
}
if(CheckPointer(m_buffer_object)!=POINTER_INVALID)
{
m_buffer_object.Release();
m_buffer_object=NULL;
}
if(CheckPointer(m_texture)!=POINTER_INVALID)
{
m_texture.Release();
m_texture=NULL;
}
if(CheckPointer(m_buffer_scene)!=POINTER_INVALID)
{
m_buffer_scene.Release();
m_buffer_scene=NULL;
}
if(CheckPointer(m_shader_pixel)!=POINTER_INVALID)
{
m_shader_pixel.Release();
m_shader_pixel=NULL;
}
if(CheckPointer(m_shader_vertex)!=POINTER_INVALID)
{
m_shader_vertex.Release();
m_shader_vertex=NULL;
}
m_topology =WRONG_VALUE;
}
};
//+------------------------------------------------------------------+
Binary file not shown.
Binary file not shown.
Binary file not shown.
+159
View File
@@ -0,0 +1,159 @@
//+------------------------------------------------------------------+
//| DXSurface.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//---
#include "DXMesh.mqh"
#include "DXMath.mqh"
#include "DXUtils.mqh"
//+------------------------------------------------------------------+
//| 3D Box object |
//+------------------------------------------------------------------+
class CDXSurface : public CDXMesh
{
public:
//--- surface creation flags
enum EN_SURFACE_FLAGS
{
SF_NONE =0x0,
SF_TWO_SIDED =0x1,
SF_USE_NORMALS =0x2,
};
//--- surface color scheme
enum EN_COLOR_SCHEME
{
CS_NONE =0,
CS_JET =1,
CS_COLD_TO_HOT =2,
CS_RED_TO_GREEN=3
};
protected:
uint m_data_width;
uint m_data_height;
uint m_flags;
EN_COLOR_SCHEME m_color_scheme;
public:
CDXSurface();
~CDXSurface();
//--- create bon in specified context
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,double &data[],uint m_data_widht,uint m_data_height,float data_range,const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,uint flags=SF_NONE,EN_COLOR_SCHEME color_scheme=CS_NONE);
//--- update box
bool Update(double &data[],uint m_data_widht,uint m_data_height,float data_range,const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,uint flags=0,EN_COLOR_SCHEME color_scheme=CS_NONE);
private:
//---
void PrepareColors(DXVertex &vertices[],const DXVector3 &from,const DXVector3 &to);
};
//+------------------------------------------------------------------+
//| Class constructor |
//+------------------------------------------------------------------+
void CDXSurface::CDXSurface() : CDXMesh()
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
void CDXSurface::~CDXSurface(void)
{
}
//+------------------------------------------------------------------+
//| Create box in specified context |
//+------------------------------------------------------------------+
bool CDXSurface::Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,
double &data[],uint data_width,uint data_height,float data_range,
const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,
uint flags=SF_NONE,EN_COLOR_SCHEME color_scheme=CS_NONE)
{
//--- release previous buffers
Shutdown();
//--- save parameters
m_data_width =data_width;
m_data_height =data_height;
m_flags =flags;
m_color_scheme=color_scheme;
//---
DXVertex vertices[];
uint indices[];
//--- prepare surface vertices and indices
if(!DXComputeSurface(data,data_width,data_height,data_range,from,to,texture_size,flags&SF_TWO_SIDED,flags&SF_USE_NORMALS,vertices,indices))
return(false);
//--- calculate colors
PrepareColors(vertices,from,to);
//--- create mesh
return(CDXMesh::Create(dispatcher,buffer_scene,vertices,indices));
}
//+------------------------------------------------------------------+
//| Update box bounds |
//+------------------------------------------------------------------+
bool CDXSurface::Update(double &data[],uint data_width,uint data_height,float data_range,
const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,
uint flags=0,EN_COLOR_SCHEME color_scheme=CS_NONE)
{
//---
DXVertex vertices[];
uint indices[];
//--- prepare surface vertices and indices
if(!DXComputeSurface(data,data_width,data_height,data_range,from,to,texture_size,flags&SF_TWO_SIDED,flags&SF_USE_NORMALS,vertices,indices))
return(false);
//--- calculate colors
m_color_scheme=color_scheme;
PrepareColors(vertices,from,to);
//--- update vertices
bool res=CDXMesh::VerticesSet(vertices);
//--- do not update indices if vertices relations are the same
if(m_data_width!=data_width || m_data_height!=data_height || (m_flags&SF_TWO_SIDED)!=(flags&SF_TWO_SIDED))
res=res && CDXMesh::IndicesSet(indices);
//--- check result
if(!res)
{
Shutdown();
return(false);
}
//--- save parameters
m_data_width =data_width;
m_data_height =data_height;
m_flags =flags;
//--- success
return(true);
}
//+------------------------------------------------------------------+
//| Update box bounds |
//+------------------------------------------------------------------+
void CDXSurface::PrepareColors(DXVertex &vertices[],const DXVector3 &from,const DXVector3 &to)
{
uint count=ArraySize(vertices);
float scale=1.0f/(fmax(FLT_EPSILON,to.y-from.y));
switch(m_color_scheme)
{
case CS_JET:
{
for(uint i=0; i<count; i++)
DXComputeColorJet((vertices[i].position.y-from.y)*scale,vertices[i].vcolor);
break;
}
case CS_COLD_TO_HOT:
{
for(uint i=0; i<count; i++)
DXComputeColorColdToHot((vertices[i].position.y-from.y)*scale,vertices[i].vcolor);
break;
}
case CS_RED_TO_GREEN:
{
for(uint i=0; i<count; i++)
DXComputeColorRedToGreen((vertices[i].position.y-from.y)*scale,vertices[i].vcolor);
break;
}
default:
{
for(uint i=0; i<count; i++)
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
break;
}
}
}
//+------------------------------------------------------------------+
Binary file not shown.
+942
View File
@@ -0,0 +1,942 @@
//+------------------------------------------------------------------+
//| DXUtils.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//---
#include "DXMath.mqh"
#include "DXData.mqh"
//--- data types in Wavefront OBJ file format
#define OBJ_DATA_UNKNOWN 0
#define OBJ_DATA_V 1
#define OBJ_DATA_VT 2
#define OBJ_DATA_VN 3
#define OBJ_DATA_F 4
//+------------------------------------------------------------------+
//| OBJFaceType |
//+------------------------------------------------------------------+
struct OBJFaceType
{
int total;
int v[4];
int t[4];
int n[4];
};
//+------------------------------------------------------------------+
//| Transforms right to left hand system, or backward |
//| TVertex must have |
//| DXVector4 normal and DXVector2 tcoord members |
//+------------------------------------------------------------------+
template <typename TVertex>
void DXInverseWinding(TVertex &vertices[],uint &indices[])
{
//--- proccess vertices
uint count=ArraySize(vertices);
for(uint i=0; i<count; i++)
{
//--- invert normals
vertices[i].normal.x=-vertices[i].normal.x;
vertices[i].normal.y=-vertices[i].normal.y;
vertices[i].normal.z=-vertices[i].normal.z;
//--- flip texture coordinates
vertices[i].tcoord.x=1.0f-vertices[i].tcoord.x;
}
//--- change indices order
count=ArraySize(indices);
for(uint i=2; i<count; i+=3)
{
uint tmp =indices[i];
indices[i] =indices[i-2];
indices[i-2]=tmp;
}
}
//+------------------------------------------------------------------+
//| Load static 3D models from Maya 2011 |
//| https://en.wikibooks.org/wiki/DirectX/10.0/Direct3D/Loading_Maya |
//+------------------------------------------------------------------+
bool DXLoadObjData(const string filename,DXVector4 &v_positions[],DXVector2 &v_tcoords[],DXVector4 &v_normals[],OBJFaceType &faces[],bool show_debug=false)
{
int total_positions=0;
int total_tcoords=0;
int total_normals=0;
int total_faces=0;
//---
ResetLastError();
int file_handle=FileOpen(filename,FILE_READ|FILE_TXT|FILE_ANSI);
if(file_handle==INVALID_HANDLE)
{
printf("FileOpen %s failed, error code=%d",filename,GetLastError());
return(false);
}
int str_length=0;
string str="";
int total_lines=0;
string str_parsed[];
string str_parsed_faces[];
//---
while(!FileIsEnding(file_handle))
{
str=FileReadString(file_handle,str_length);
total_lines++;
//--- replace two spaces to one
StringReplace(str,"\t"," ");
while(StringFind(str," ",0)!=-1)
StringReplace(str," "," ");
//--- split string to tokens
int total_items=StringSplit(str,' ',str_parsed);
if(total_items<1)
continue;
//--- when examining the file you can ignore every line unless it starts with a "V", "VT", "VN", or "F".
//--- the extra information in the file will not be needed for converting .obj to our file format.
StringToUpper(str_parsed[0]);
//--- parse data type
int data_type=OBJ_DATA_UNKNOWN;
if(str_parsed[0]=="V")
data_type=OBJ_DATA_V;
else
if(str_parsed[0]=="VT")
data_type=OBJ_DATA_VT;
else
if(str_parsed[0]=="VN")
data_type=OBJ_DATA_VN;
else
if(str_parsed[0]=="F")
data_type=OBJ_DATA_F;
//--- proceed data type
switch(data_type)
{
//--- 1. "V" lines are for the vertices, each is listed in X, Y, Z float format.
case OBJ_DATA_V:
{
total_positions++;
if(total_items<4)
{
PrintFormat("obj data error at line=%d: %s",total_lines,str);
FileClose(file_handle);
return(false);
}
ArrayResize(v_positions,total_positions,total_positions+1000);
int idx=total_positions-1;
v_positions[idx].x=(float)StringToDouble(str_parsed[1]);
v_positions[idx].y=(float)StringToDouble(str_parsed[2]);
v_positions[idx].z=(float)StringToDouble(str_parsed[3]);
v_positions[idx].w=1.0f;
//--- debug message
if(show_debug)
printf("posiiton %d: %f %f %f",idx,v_positions[idx].x,v_positions[idx].y,v_positions[idx].z);
//---
break;
}
//--- 2. "VT" lines are for the texture coordinates, they are listed in TU, TV float format.
case OBJ_DATA_VT:
{
total_tcoords++;
if(total_items<3)
{
PrintFormat("obj data error at line=%d: %s",total_lines,str);
FileClose(file_handle);
return(false);
}
ArrayResize(v_tcoords,total_tcoords,total_tcoords+1000);
int idx=total_tcoords-1;
v_tcoords[idx].x=(float)StringToDouble(str_parsed[1]);
v_tcoords[idx].y=(float)StringToDouble(str_parsed[2]);
//--- debug message
if(show_debug)
printf("tcoord %d: %f %f",idx,v_tcoords[idx].x,v_tcoords[idx].y);
//---
break;
}
//--- 3. "VN" lines are for the normal vectors, most of them are duplicated again
//--- since it records them for every vertex in every triangle in the model, they are listed in NX, NY, NZ float format.
case OBJ_DATA_VN:
{
total_normals++;
if(total_items<4)
{
PrintFormat("obj data error at line=%d: %s",total_lines,str);
FileClose(file_handle);
return(false);
}
//---
ArrayResize(v_normals,total_normals,total_normals+1000);
int idx=total_normals-1;
v_normals[idx].x=(float)StringToDouble(str_parsed[1]);
v_normals[idx].y=(float)StringToDouble(str_parsed[2]);
v_normals[idx].z=(float)StringToDouble(str_parsed[3]);
v_normals[idx].w=0.0f;
//--- debug message
if(show_debug)
printf("normal %d: %f %f %f",idx,v_normals[idx].x,v_normals[idx].y,v_normals[idx].z);
//---
break;
}
//--- 4. "F" lines are for each face in the model.
//--- the values listed are indexes into the vertices, texture coordinates, and normal vectors. The format of each face is:
//--- f Vertex1/Texture1/Normal1 Vertex2/Texture2/Normal2 Vertex3/Texture3/Normal3
//--- so a line that says "f 3/13/5 4/14/6 5/15/7" then translates to "Vertex3/Texture13/Normal5 Vertex4/Texture14/Normal6 Vertex5/Texture15/Normal7".
case OBJ_DATA_F:
{
total_faces++;
//--- check size
if(total_items<4)
{
PrintFormat("obj data error at line=%d: %s",total_lines,str);
FileClose(file_handle);
return(false);
}
//---
ArrayResize(faces,total_faces,total_faces+1000);
int idx=total_faces-1;
//--- clear all face indices
for(uint i=0; i<4; i++)
{
faces[idx].v[0]=0;
faces[idx].t[0]=0;
faces[idx].n[0]=0;
}
//--- read indices
faces[idx].total=MathMin(total_items-1,4);
for(int i=0; i<faces[idx].total; i++)
{
int elements=StringSplit(str_parsed[i+1],'/',str_parsed_faces);
if(elements>0)
faces[idx].v[i]=(int)StringToInteger(str_parsed_faces[0]);
if(elements>1)
faces[idx].t[i]=(int)StringToInteger(str_parsed_faces[1]);
if(elements>2)
faces[idx].n[i]=(int)StringToInteger(str_parsed_faces[2]);
}
//--- debug message
if(show_debug)
printf("%face d: %d vertex(%d,%d,%d,%d) texture(%d,%d,%d,%d) normal(%d,%d,%d,%d)",idx+1,
faces[idx].v[0],faces[idx].v[1],faces[idx].v[2],faces[idx].v[3],
faces[idx].t[0],faces[idx].t[1],faces[idx].t[2],faces[idx].t[3],
faces[idx].n[0],faces[idx].n[1],faces[idx].n[2],faces[idx].n[3]);
//---
break;
}
default:
{
break;
}
}
}
//--- close the file
FileClose(file_handle);
//---
if(show_debug)
{
printf("File %s loaded successfully. Total lines: %d",filename,total_lines);
printf("total v_positions=%d",total_positions);
printf("total v_normals=%d",total_normals);
printf("total v_tcoords=%d",total_tcoords);
printf("total faces=%d",total_faces);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Load static 3D models from Maya 2011 |
//| https://en.wikibooks.org/wiki/DirectX/10.0/Direct3D/Loading_Maya |
//| TVertex must have |
//| DXVector4 position, normal and DXVector2 tcoord members |
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXLoadObjModel(const string filename,TVertex &vertices[],uint &indices[],float scale=1.0f)
{
//--- intermediate data arrays
DXVector4 v_positions[];
DXVector2 v_tcoords[];
DXVector4 v_normals[];
OBJFaceType faces[];
//--- load data
if(!DXLoadObjData(filename,v_positions,v_tcoords,v_normals,faces,false))
{
printf("Error loading model data from %s",filename);
return(false);
}
//---
int total_v_positions=ArraySize(v_positions);
int total_v_tcoords =ArraySize(v_tcoords);
int total_v_normals =ArraySize(v_normals);
int total_faces =ArraySize(faces);
//--- check faces
if(total_faces==0)
{
printf("No model data.");
return(false);
}
//--- check consistency of the indices
int vertices_count=0;
int indices_count =0;
bool split_vertices=false;
for(int i=0; i<total_faces; i++)
{
//--- each face have to be 3 or 4 sided
if(faces[i].total<3 || faces[i].total>4)
{
printf("Error in %d face, face vertices count is %d",i,faces[i].total);
return(false);
}
//---
for(int j=0; j<faces[i].total; j++)
{
if(faces[i].v[j]<=0 || faces[i].v[j]>total_v_positions)
{
printf("Error in %d face, %d vertext index is %d. Total posiitons=%d",i,j,faces[i].v[j],total_v_positions);
return(false);
}
if(total_v_tcoords>0)
{
if(faces[i].t[j]<=0 || faces[i].t[j]>total_v_tcoords)
{
printf("Error in %d face, %d tcoord index is %d. Total tcoords=%d",i,j,faces[i].v[j],total_v_positions);
return(false);
}
if(faces[i].t[j]!=faces[i].v[j])
split_vertices=true;
}
if(total_v_normals>0)
{
if(faces[i].n[j]<=0 || faces[i].n[j]>total_v_normals)
{
printf("Error in %d face, %d normal index is %d. Total normals=%d",i,j,faces[i].v[j],total_v_positions);
return(false);
}
if(faces[i].n[j]!=faces[i].v[j])
split_vertices=true;
}
}
//--- calc counts
vertices_count+=faces[i].total;
if(faces[i].total<4)
indices_count+=3;
else
indices_count+=6;
}
printf("Data consistency checked.");
//--- prepare arrays
if(!split_vertices)
vertices_count=total_v_positions;
ArrayResize(vertices,vertices_count);
ArrayResize(indices, indices_count);
int v_idx=0,i_idx=0;
for(int i=0; i<total_faces; i++)
{
for(int j=0; j<faces[i].total; j++)
{
if(!split_vertices)
v_idx=faces[i].v[j]-1;
//--- posiitons
vertices[v_idx].position.x=v_positions[faces[i].v[j]-1].x*scale;
vertices[v_idx].position.y=v_positions[faces[i].v[j]-1].y*scale;
vertices[v_idx].position.z=v_positions[faces[i].v[j]-1].z*scale;
vertices[v_idx].position.w=1.0f;
//--- normal
if(faces[i].n[j])
DXVec4Normalize(vertices[v_idx].normal,v_normals[faces[i].n[j]-1]);
//--- tcoord
if(faces[i].t[j])
vertices[v_idx].tcoord=v_tcoords[faces[i].t[j]-1];
//--- indices
indices[i_idx++]=v_idx;
//--- increment indx
if(split_vertices)
v_idx++;
}
//--- the end of second triangle in 4-sided face
if(faces[i].total==4)
{
indices[i_idx]=indices[i_idx-4];
i_idx++;
indices[i_idx]=indices[i_idx-3];
i_idx++;
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Box |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeBox(const DXVector3 &from,const DXVector3 &to,TVertex &vertices[],uint &indices[])
{
//--- prepare arrays
const int faces=6;
if(ArrayResize(vertices,4*faces)!=4*faces)
return(false);
//--- set indices
uint ind[]= {0,1,2, 2,3,0, 4,5,6, 6,7,4, 8,9,10, 10,11,8, 12,13,14, 14,15,12, 16,17,18, 18,19,16, 20,21,22, 22,23,20};
ArrayResize(indices,0);
if(ArrayCopy(indices,ind)!=ArraySize(ind))
return(false);
//--- prepare boundaries
float left=from.x,right=to.x,bottom=from.y,top=to.y,near=from.z,far=to.z;
if(from.x>to.x)
{
right=from.x;
left= to.x;
}
if(from.y>to.y)
{
top= from.y;
bottom=to.y;
}
if(from.z>to.z)
{
far=from.z;
near=to.z;
}
//--- left face
vertices[0].position=DXVector4(left,top, far, 1.0);
vertices[1].position=DXVector4(left,top, near,1.0);
vertices[2].position=DXVector4(left,bottom,near,1.0);
vertices[3].position=DXVector4(left,bottom,far, 1.0);
for(int i=0; i<4; i++)
vertices[i].normal=DXVector4(-1.0,0.0,0.0,0.0);
//--- right face
vertices[4].position=DXVector4(right,top, near,1.0);
vertices[5].position=DXVector4(right,top, far, 1.0);
vertices[6].position=DXVector4(right,bottom,far, 1.0);
vertices[7].position=DXVector4(right,bottom,near,1.0);
for(int i=4; i<8; i++)
vertices[i].normal=DXVector4(1.0,0.0,0.0,0.0);
//--- front face
vertices[8].position =DXVector4(left, top, near,1.0);
vertices[9].position =DXVector4(right,top, near,1.0);
vertices[10].position=DXVector4(right,bottom,near,1.0);
vertices[11].position=DXVector4(left, bottom,near,1.0);
for(int i=8; i<12; i++)
vertices[i].normal=DXVector4(0.0,0.0,-1.0,0.0);
//--- back face
vertices[12].position=DXVector4(right,top, far,1.0);
vertices[13].position=DXVector4(left, top, far,1.0);
vertices[14].position=DXVector4(left, bottom,far,1.0);
vertices[15].position=DXVector4(right,bottom,far,1.0);
for(int i=12; i<16; i++)
vertices[i].normal=DXVector4(0.0,0.0,1.0,0.0);
//--- top face
vertices[16].position=DXVector4(left, top,far, 1.0);
vertices[17].position=DXVector4(right,top,far, 1.0);
vertices[18].position=DXVector4(right,top,near,1.0);
vertices[19].position=DXVector4(left, top,near,1.0);
for(int i=16; i<20; i++)
vertices[i].normal=DXVector4(0.0,1.0,0.0,0.0);
//--- bottom face
vertices[20].position=DXVector4(left, bottom,near,1.0);
vertices[21].position=DXVector4(right,bottom,near,1.0);
vertices[22].position=DXVector4(right,bottom,far, 1.0);
vertices[23].position=DXVector4(left, bottom,far, 1.0);
for(int i=20; i<24; i++)
vertices[i].normal=DXVector4(0.0,-1.0,0.0,0.0);
//--- texture coordinates
for(int i=0; i<faces; i++)
{
vertices[i*4+0].tcoord=DXVector2(0.0f,0.0f);
vertices[i*4+1].tcoord=DXVector2(1.0f,0.0f);
vertices[i*4+2].tcoord=DXVector2(1.0f,1.0f);
vertices[i*4+3].tcoord=DXVector2(0.0f,1.0f);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Sphere |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeSphere(float radius,uint tessellation,TVertex &vertices[],uint &indices[])
{
if(tessellation<3)
tessellation=3;
uint segments_y =tessellation;
uint segments_xz=tessellation*2;
//--- prepare arrays
uint count=(segments_y+1)*(segments_xz+1);
if(ArrayResize(vertices,count)!=count)
return(false);
count=6*segments_y*(segments_xz);
if(ArrayResize(indices,count)!=count)
return(false);
//--- create rings of vertices at progressively higher latitudes.
for(uint i=0,idx=0; i<=segments_y; i++)
{
DXVector2 tcoord=DXVector2(0.0f,1.0f-(float)i/segments_y);
float latitude=(i*DX_PI/segments_y)-DX_PI_DIV2;
float dy =(float)sin(latitude);
float dxz=(float)cos(latitude);
//--- create a single ring of vertices at this latitude.
for(uint j=0; j<=segments_xz; j++,idx++)
{
float longitude=(j%segments_xz)*DX_PI_MUL2/segments_xz;
//--- normal
DXVector3 normal=DXVector3((float)sin(longitude)*dxz,dy,(float)cos(longitude)*dxz);
vertices[idx].normal =DXVector4(normal.x,normal.y,normal.z,0.0);
//--- position
DXVec3Scale(normal,normal,radius);
vertices[idx].position=DXVector4(normal.x,normal.y,normal.z,1.0);
//--- texture coords
tcoord.x = float(j)/segments_xz;
vertices[idx].tcoord =tcoord;
}
}
//--- fill the index buffer with triangles joining each pair of latitude rings.
uint stride=segments_xz+1;
uint idx=0;
for(uint i=0; i<segments_y; i++)
{
for(uint j=0; j<segments_xz; j++)
{
uint next_i=i+1;
uint next_j=(j+1)%stride;
indices[idx++]=next_i*stride + next_j;
indices[idx++]=next_i*stride + j;
indices[idx++]= i*stride + j;
indices[idx++]= i*stride + j;
indices[idx++]= i*stride + next_j;
indices[idx++]=next_i*stride + next_j;
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Torus |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeTorus(float outer_radius,float inner_radius,uint tessellation,TVertex &vertices[],uint &indices[])
{
if(tessellation<3)
tessellation=3;
//--- prepare arrays
uint count=(tessellation+1)*(tessellation+1);
if(ArrayResize(vertices,count)!=count)
return(false);
count=6*tessellation*tessellation;
if(ArrayResize(indices,count)!=count)
return(false);
//---
uint v=0,idx=0;
uint stride=tessellation+1;
//--- first we loop around the main ring of the torus.
for(uint i=0; i<=tessellation; i++)
{
DXVector2 tcoord=DXVector2(float(i)/tessellation,0.0f);
//--- create a transform matrix that will align geometry to slice perpendicularly though the current ring position.
DXMatrix rotation,transform;
DXMatrixRotationY(rotation,-1.0f*(i%tessellation)*DX_PI_MUL2/tessellation-DX_PI_DIV2);
DXMatrixTranslation(transform,outer_radius,0.0f,0.0f);
DXMatrixMultiply(transform,transform,rotation);
//--- now we loop along the other axis, around the side of the tube.
for(uint j=0; j<=tessellation; j++)
{
//--- calc normal and position
float angle=(j%tessellation)*DX_PI_MUL2/tessellation+DX_PI;
vertices[v].normal=DXVector4((float)cos(angle),(float)sin(angle),0.0f,0.0f);
vertices[v].position=DXVector4(vertices[v].normal.x*inner_radius,vertices[v].normal.y*inner_radius,0.0f,1.0f);
DXVec4Transform(vertices[v].normal, vertices[v].normal, transform);
DXVec4Transform(vertices[v].position,vertices[v].position,transform);
//--- calc texture coord
tcoord.y=1-float(j)/tessellation;
vertices[v].tcoord=tcoord;
v++;
//--- create indices for two triangles.
if(i<tessellation && j<tessellation)
{
uint next_i=i+1;
uint next_j=j+1;
indices[idx++]=next_i*stride + next_j;
indices[idx++]=next_i*stride + j;
indices[idx++]= i*stride + j;
indices[idx++]= i*stride + j;
indices[idx++]= i*stride + next_j;
indices[idx++]=next_i*stride + next_j;
}
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Cylinder |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeCylinder(float radius,float height,uint tessellation,TVertex &vertices[],uint &indices[])
{
return(DXComputeTruncatedCone(radius,radius,height,tessellation,vertices,indices));
}
//+------------------------------------------------------------------+
//| Truncated Cone |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeTruncatedCone(float radius_top,float radius_bottom,float height,uint tessellation,TVertex &vertices[],uint &indices[])
{
if(tessellation<3)
tessellation=3;
//--- prepare arrays
uint count=2*(tessellation+1)+2*tessellation;
if(ArrayResize(vertices,count)!=count)
return(false);
count=6*tessellation+6*(tessellation-1);
if(ArrayResize(indices,count)!=count)
return(false);
//--- prepare normal
DXVector2 normal=DXVector2(height,radius_bottom-radius_top);
DXVec2Normalize(normal,normal);
float dy=height/2.0f;
uint v=0,idx=0;
uint stride=2;
//--- create top and bottom rings of vertices
for(uint i=0; i<=tessellation; i++)
{
float u=1.0f-(float)i/tessellation;
float angle=(i*DX_PI_MUL2/tessellation);
float dx=(float)sin(angle);
float dz=(float)cos(angle);
//---
vertices[v].normal =DXVector4(dx*normal.x,normal.y,dz*normal.x,0.0f);
vertices[v].position=DXVector4(dx*radius_bottom,-dy,dz*radius_bottom,1.0f);
vertices[v].tcoord =DXVector2(u,1.0f);
v++;
vertices[v].normal =vertices[v-1].normal;
vertices[v].position=DXVector4(dx*radius_top,dy,dz*radius_top,1.0f);
vertices[v].tcoord =DXVector2(u,0.0f);
v++;
//--- creater side surface
if(i<tessellation)
{
uint next_i=i+1;
indices[idx++]=next_i*stride + 1;
indices[idx++]= i*stride + 0;
indices[idx++]=next_i*stride + 0;
indices[idx++]= i*stride + 0;
indices[idx++]=next_i*stride + 1;
indices[idx++]= i*stride + 1;
}
}
//--- first cap vertex
uint cap_first=v;
//--- create caps
for(uint i=0; i<tessellation; i++)
{
float angle=(i*DX_PI_MUL2/tessellation);
float dx=(float)sin(angle);
float dz=(float)cos(angle);
vertices[v].normal =DXVector4(0.0f,-1.0f,0.0f,0.0f);
vertices[v].position=DXVector4(dx*radius_bottom,-dy,dz*radius_bottom,1.0f);
vertices[v].tcoord =DXVector2(0.5f+0.5f*dx,0.5f+0.5f*dz);
v++;
vertices[v].normal =DXVector4(0.0f,1.0f,0.0f,0.0f);
vertices[v].position=DXVector4(dx*radius_top,dy,dz*radius_top,1.0f);
vertices[v].tcoord =DXVector2(0.5f+0.5f*dx,0.5f-0.5f*dz);
v++;
//--- creater caps surface
if(i>0 && i<tessellation-1)
{
uint next_i=i+1;
indices[idx++]=cap_first;
indices[idx++]=cap_first+next_i*stride;
indices[idx++]=cap_first+ i*stride;
indices[idx++]=cap_first+1;
indices[idx++]=cap_first+ i*stride+1;
indices[idx++]=cap_first+next_i*stride+1;
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Cone |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeCone(float radius,float height,uint tessellation,TVertex &vertices[],uint &indices[])
{
if(tessellation<3)
tessellation=3;
//--- prepare arrays
uint count=2*(tessellation+1)+tessellation;
if(ArrayResize(vertices,count)!=count)
return(false);
count=3*tessellation+3*(tessellation-1);
if(ArrayResize(indices,count)!=count)
return(false);
//--- prepare normal
DXVector2 normal=DXVector2(height,radius);
DXVec2Normalize(normal,normal);
float dy=height/2.0f;
uint v=0,idx=0;
uint stride=2;
//--- create top and bottom rings of vertices
for(uint i=0; i<=tessellation; i++)
{
float u=1.0f-(float)i/tessellation;
float angle=(i*DX_PI_MUL2/tessellation);
float dx=(float)sin(angle);
float dz=(float)cos(angle);
//---
vertices[v].normal =DXVector4(dx*normal.x,normal.y,dz*normal.x,0.0f);
vertices[v].position=DXVector4(dx*radius,-dy,dz*radius,1.0f);
vertices[v].tcoord =DXVector2(u,1.0f);
v++;
vertices[v].normal =vertices[v-1].normal;
vertices[v].position=DXVector4(0.0f,dy,0.0f,1.0f);
vertices[v].tcoord =DXVector2(u,0.0f);
v++;
//--- creater side surface
if(i<tessellation)
{
uint next_i=i+1;
indices[idx++]=next_i*stride + 1;
indices[idx++]= i*stride + 0;
indices[idx++]=next_i*stride + 0;
}
}
//--- first cap vertex
uint cap_first=v;
//--- create caps
for(uint i=0; i<tessellation; i++)
{
float angle=(i*DX_PI_MUL2/tessellation);
float dx=(float)sin(angle);
float dz=(float)cos(angle);
vertices[v].normal =DXVector4(0.0f,-1.0f,0.0f,0.0f);
vertices[v].position=DXVector4(dx*radius,-dy,dz*radius,1.0f);
vertices[v].tcoord =DXVector2(0.5f+0.5f*dx,0.5f+0.5f*dz);
v++;
//--- creater caps surface
if(i>0 && i<tessellation-1)
{
indices[idx++]=cap_first;
indices[idx++]=cap_first+i+1;
indices[idx++]=cap_first+i;
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Surface |
//| TVertex must have |
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
//+------------------------------------------------------------------+
template <typename TVertex>
bool DXComputeSurface(double &data[],uint data_width,uint data_height,double data_range,
const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,
bool two_sided,bool use_normals,
TVertex &vertices[],uint &indices[])
{
//---
if(data_width<2 || data_height<2)
return(false);
//--- prepare arrays for vertices and triangles
uint count=data_width*data_height*(two_sided?2:1);
if(!ArrayResize(vertices,count))
return(false);
count=6*(data_width-1)*(data_height-1)*(two_sided?2:1);
if(!ArrayResize(indices,count))
return(false);
//--- find min and max value
float min_value=+FLT_MAX;
float max_value=-FLT_MAX;
for(uint j=0; j<data_height; j++)
for(uint i=0; i<data_width; i++)
{
float value=(float)data[j*data_width+i];
if(min_value>value)
min_value=value;
if(max_value<value)
max_value=value;
}
//--- check and fix data range
float avg_value=0.5f*(max_value+min_value);
float range=(float)data_range;
if(range<=0.0f)
range=max_value-min_value;
if(range<FLT_EPSILON)
range=FLT_EPSILON;
//---
min_value=avg_value-0.5f*range;
max_value=avg_value+0.5f*range;
//---
DXVector3 range_3d;
DXVec3Subtract(range_3d,to,from);
float step_x=range_3d.x/(data_width-1);
float step_y=range_3d.y/range;
float step_z=range_3d.z/(data_height-1);
//--- calculate vertices positions and colors
for(uint j=0; j<data_height; j++)
{
for(uint i=0; i<data_width; i++)
{
uint idx=j*data_width+i;
//--- calc value
float value=(float)data[idx]-min_value;
//--- calc position
vertices[idx].position.x = from.x+i *step_x;
vertices[idx].position.y = from.y+value*step_y;
vertices[idx].position.z = from.z+j *step_z;
vertices[idx].position.w = 1.0f;
//--- set texture coordinates
vertices[idx].tcoord=DXVector2(i*step_x/texture_size.x,j*step_z/texture_size.y);
}
}
//--- calculate normals
if(use_normals)
{
for(uint j=0; j<data_height; j++)
{
for(uint i=0; i<data_width; i++)
{
DXVector4 v1,v2,normal;
//--- v1
if(i<=0)
DXVec4Subtract(v1,vertices[j*data_width+i].position,vertices[j*data_width+i+1].position);
else
if(i>=data_width-1)
DXVec4Subtract(v1,vertices[j*data_width+i-1].position,vertices[j*data_width+i].position);
else
DXVec4Subtract(v1,vertices[j*data_width+i-1].position,vertices[j*data_width+i+1].position);
//--- v2
if(j<=0)
DXVec4Subtract(v2,vertices[j*data_width+i].position,vertices[(j+1)*data_width+i].position);
else
if(j>=data_height-1)
DXVec4Subtract(v2,vertices[(j-1)*data_width+i].position,vertices[j*data_width+i].position);
else
DXVec4Subtract(v2,vertices[(j-1)*data_width+i].position,vertices[(j+1)*data_width+i].position);
//--- normal
DXVec4Cross(normal,v2,v1,DXVector4(0.0f,0.0f,0.0f,1.0f));
float inv_len=(float)(1.0/sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z));
vertices[j*data_width+i].normal.x=normal.x*inv_len;
vertices[j*data_width+i].normal.y=normal.y*inv_len;
vertices[j*data_width+i].normal.z=normal.z*inv_len;
vertices[j*data_width+i].normal.w=0.0f;
}
}
}
else
{
DXVector4 n=DXVector4(0.0f,0.0f,0.0f,0.0f);
for(int i=0; i<ArraySize(vertices); i++)
vertices[i].normal=n;
}
//--- calculate triangles for every rectangle
int n=0;
for(uint i=0; i<data_width-1; i++)
{
for(uint j=0; j<data_height-1; j++)
{
//--- left triangle
indices[n++]=j*data_width+(i+1);
indices[n++]=j*data_width+i;
indices[n++]=(j+1)*data_width+i;
//--- right triangle
indices[n++]=(j+1)*data_width+(i+1);
indices[n++]=j*data_width+(i+1);
indices[n++]=(j+1)*data_width+(i);
}
}
//--- generate back side
if(two_sided)
{
uint offset=data_height*data_width;
for(uint j=0; j<data_height; j++)
{
for(uint i=0; i<data_width; i++)
{
uint idx=offset+j*data_width+i;
//--- copy vertices in backward direction
vertices[idx]=vertices[j*data_width+data_width-i-1];
//--- inverse normals
DXVec4Scale(vertices[idx].normal,vertices[idx].normal,-1.0f);
}
}
//--- calculate triangles for opposit side
for(uint i=0; i<data_width-1; i++)
{
for(uint j=0; j<data_height-1; j++)
{
//--- left triangle
indices[n++]=offset+j*data_width+(i+1);
indices[n++]=offset+j*data_width+i;
indices[n++]=offset+(j+1)*data_width+i;
//--- right triangle
indices[n++]=offset+(j+1)*data_width+(i+1);
indices[n++]=offset+j*data_width+(i+1);
indices[n++]=offset+(j+1)*data_width+(i);
}
}
}
//---
return(true);
}
//+---------------------------------------------------------------------+
//| Computes Matlab jet color scheme colors on [0;1] range |
//| dark blue > blue > light blue > green > yellow > red > dark red |
//+---------------------------------------------------------------------+
void DXComputeColorJet(const float value,DXColor &cout)
{
float v=value*1.1f-0.05f;
cout.r = fmin(fmax(v<0.75f ? 4*v-1.5f : 4.5f-4*v,0.0f),1.0f);
cout.g = fmin(fmax(v<0.5f ? 4*v-0.5f : 3.5f-4*v,0.0f),1.0f);
cout.b = fmin(fmax(v<0.25f ? 4*v+0.5f : 2.5f-4*v,0.0f),1.0f);
cout.a = 1.0;
}
//+---------------------------------------------------------------------+
//| Computes hot to cold color scheme colors on [0;1] range |
//| blue > light blue > green > yellow > red |
//+---------------------------------------------------------------------+
void DXComputeColorColdToHot(const float value,DXColor &cout)
{
float v=2*value-1.0f;
cout.r = fmin(fmax(2*v,0.0f),1.0f);
cout.g = fmin(fmax(2.0f-2*fabs(v),0.0f),1.0f);
cout.b = fmin(fmax(-2*v,0.0f),1.0f);
cout.a = 1.0;
}
//+---------------------------------------------------------------------+
//| Computes red to green color scheme colors on [0;1] range |
//| red > yellow > dark green |
//+---------------------------------------------------------------------+
void DXComputeColorRedToGreen(const float value,DXColor &cout)
{
if(value<=0.5)
{
cout.r=1.0f;
cout.g=DXScalarLerp(0.01f,0.95f,fmin(fmax(2*value,0.0f),1.0f));
}
else
{
cout.r=DXScalarLerp(0.1f,1.0f, fmin(fmax(2.0f-2*value,0.0f),1.0f));
cout.g=DXScalarLerp(0.6f,0.95f,fmin(fmax(2.0f-2*value,0.0f),1.0f));
}
cout.b=0.0f;
cout.a=1.0f;
}
//+------------------------------------------------------------------+
@@ -0,0 +1,71 @@
//+------------------------------------------------------------------+
//| Default Pixel Shader |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Inputs for whole scene |
//+------------------------------------------------------------------+
cbuffer InputScene : register(b0)
{
matrix view;
matrix projection;
float4 light_direction;
float4 light_color;
float4 ambient_color;
};
//+------------------------------------------------------------------+
//| Inputs for single object |
//+------------------------------------------------------------------+
cbuffer InputObject : register(b1)
{
matrix transform;
float4 diffuse_color;
float4 emission_color;
float4 specular_color;
float specular_power;
float dummy[3];
};
//+------------------------------------------------------------------+
//| Input texture |
//+------------------------------------------------------------------+
Texture2D<float4> diffuse_tex : register(t0);
//+------------------------------------------------------------------+
//| Texture sampler |
//+------------------------------------------------------------------+
SamplerState diffuse_samp
{
Filter =MIN_MAG_MIP_LINEAR;
AddressU=Wrap;
AddressV=Wrap;
};
//+------------------------------------------------------------------+
//| Pixel shader input type |
//+------------------------------------------------------------------+
struct PSInput
{
float4 position : SV_POSITION;
float4 camera : CAMERA;
float4 normal : NORMAL;
float2 tcoord : TEXCOORD;
float4 color : COLOR;
};
//+------------------------------------------------------------------+
//| Pixel shader entry point |
//+------------------------------------------------------------------+
float4 PSMain(PSInput input) : SV_TARGET
{
float3 diffuse =saturate(-dot(light_direction.xyz,input.normal.xyz))*light_color.rgb*light_color.a;
float3 ambient =ambient_color.rgb *ambient_color.a;
float3 light =(diffuse+ambient)*diffuse_color.rgb*diffuse_color.a+emission_color.rgb*emission_color.a;
float4 specular=float4(light_color.rgb*specular_color.rgb,pow(saturate(dot(reflect(normalize(light_direction.xyz),input.normal.xyz),normalize(input.camera.xyz))),specular_power)*light_color.a*specular_color.a);
float4 clr=input.color;
//--- use texture if it exist
uint width,height;
diffuse_tex.GetDimensions(width,height);
if(width*height>0)
clr*=diffuse_tex.Sample(diffuse_samp,frac(input.tcoord));
//--- combine light with colors
return(lerp(float4(light*clr.rgb,clr.a),float4(specular.rgb,1.0),specular.a));
}
//+------------------------------------------------------------------+
@@ -0,0 +1,72 @@
//+------------------------------------------------------------------+
//| Default Vertex Shader |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Inputs for whole scene |
//+------------------------------------------------------------------+
cbuffer InputScene : register(b0)
{
matrix view;
matrix projection;
float4 light_direction;
float4 light_color;
float4 ambient_color;
};
//+------------------------------------------------------------------+
//| Inputs for single object |
//+------------------------------------------------------------------+
cbuffer InputObject : register(b1)
{
matrix transform;
float4 diffuse_color;
float4 emission_color;
float4 specular_color;
float specular_power;
float dummy[3];
};
//+------------------------------------------------------------------+
//| Vertex shader input type |
//+------------------------------------------------------------------+
struct VSInput
{
float4 position : POSITION;
float4 normal : NORMAL;
float2 tcoord : TEXCOORD;
float4 color : COLOR;
};
//+------------------------------------------------------------------+
//| Pixel shader input type |
//+------------------------------------------------------------------+
struct PSInput
{
float4 position : SV_POSITION;
float4 camera : CAMERA;
float4 normal : NORMAL;
float2 tcoord : TEXCOORD;
float4 color : COLOR;
};
//+------------------------------------------------------------------+
//| Vertex shader entry point |
//+------------------------------------------------------------------+
PSInput VSMain(VSInput input)
{
PSInput output;
//--- posiiton and camera direction
output.position=mul(input .position,transform);
output.position=mul(output.position,view);
output.camera =-output.position;
output.position=mul(output.position,projection);
//--- transform normals
output.normal = mul(input.normal, transform);
output.normal = mul(output.normal, view);
output.normal = normalize(output.normal);
//--- color and texture coordinates
output.tcoord =input.tcoord;
output.color =input.color;
//---
return(output);
}
//+------------------------------------------------------------------+
+751
View File
@@ -0,0 +1,751 @@
//+------------------------------------------------------------------+
//| FlameCanvas.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Canvas.mqh"
#include <Controls\Defines.mqh>
//+------------------------------------------------------------------+
//| Gradient descriptors |
//+------------------------------------------------------------------+
struct GRADIENT_COLOR
{
uint clr; // color in ARGB format
uint pos; // position of color in percentage of gradient range
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct GRADIENT_SIZE
{
uint size; // width of gradient fill in percentage of base fill
uint pos; // position of color in percentage of gradient length
};
//+------------------------------------------------------------------+
//| Class CFlameCanvas |
//| Usage: generates flame |
//+------------------------------------------------------------------+
class CFlameCanvas : public CCanvas
{
private:
//--- parameters
uint m_bar_gap;
uint m_bar_width;
uint m_chart_scale;
double m_chart_price_min;
double m_chart_price_max;
ENUM_TIMEFRAMES m_timeframe;
string m_symbol;
int m_future_bars;
int m_back_bars;
int m_rates_total;
uint m_palette[256]; // flame palette
uchar m_flame[]; // buffer for calculation of flame
uint m_time_redraw;
uint m_delay;
// bool m_resize_flag;
// int m_tick_cnt;
//--- flame parameters
datetime m_tb1;
double m_pb1;
datetime m_te1;
double m_pe1;
datetime m_tb2;
double m_pb2;
datetime m_te2;
double m_pe2;
//--- equation parameters for flame
int m_cloud_axis[100];
double m_a1;
double m_b1;
double m_a2;
double m_b2;
int m_xb1;
int m_yb1;
int m_xe1;
int m_ye1;
int m_xb2;
int m_yb2;
int m_xe2;
int m_ye2;
public:
CFlameCanvas(void);
~CFlameCanvas(void);
//--- create
bool FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars=0);
void RatesTotal(const int value);
//--- setting
void PaletteSet(uint clr=0xFF0000);
//--- draw
void FlameDraw(const double &prices[],const int width,const int lenght);
void FlameSet(datetime xb1,double yb1,datetime xe1,double ye1,datetime xb2,double yb2,datetime xe2,double ye2);
//--- event handler
void ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam);
protected:
bool Resize(void);
void ChartScale(void);
void FlameSet(void);
void CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level=255,const bool custom_gradient=true);
void FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[]);
void GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[]);
void GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[]);
void GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2);
void FlameCreate(void);
void FlameCalculate(void);
void Delay(const uint value);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CFlameCanvas::CFlameCanvas(void) : m_bar_gap(16),
m_bar_width(8),
m_chart_scale(1),
m_chart_price_min(0.0),
m_chart_price_max(0.0),
m_timeframe(PERIOD_CURRENT),
m_symbol(NULL),
m_future_bars(0),
m_back_bars(0),
m_rates_total(0),
m_time_redraw(0),
m_delay(50),
m_tb1(0),
m_pb1(0),
m_te1(0),
m_pe1(0),
m_tb2(0),
m_pb2(0),
m_te2(0),
m_pe2(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CFlameCanvas::~CFlameCanvas(void)
{
Destroy();
}
//+------------------------------------------------------------------+
//| Creates dynamic resource with object |
//+------------------------------------------------------------------+
bool CFlameCanvas::FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars)
{
//--- get chart parameters
ChartScale();
//--- create
int width =(int)m_bar_gap*(future_bars+back_bars);
int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS);
if(!CreateBitmap(0,0,name,time-back_bars*PeriodSeconds(),m_chart_price_max,width,height,COLOR_FORMAT_ARGB_NORMALIZE))
return(false);
ArrayResize(m_flame,width*height);
//--- save parameters
m_future_bars=future_bars;
m_back_bars =back_bars;
//--- settings
PaletteSet();
m_timeframe =Period();
m_symbol =Symbol();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Resize |
//+------------------------------------------------------------------+
bool CFlameCanvas::Resize(void)
{
int x,y;
//--- get limits
double min=ChartGetDouble(0,CHART_PRICE_MIN);
double max=ChartGetDouble(0,CHART_PRICE_MAX);
if(m_chart_price_max!=max)
{
//--- move object
ObjectSetDouble(0,m_objname,OBJPROP_PRICE,0,max);
}
//--- check
if(m_chart_price_min==min && m_chart_price_max==max)
return(false);
m_chart_price_min=min;
m_chart_price_max=max;
//--- grt size
ChartTimePriceToXY(0,0,m_tb1,min,x,y);
int width =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS)-x;
int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS);
//--- resize
if(width<m_width)
width=m_width;
if(width<=0)
return(false);
CCanvas::Resize(width,height);
//--- resize flame buffer
ArrayResize(m_flame,width*height);
ArrayInitialize(m_flame,0);
ArrayInitialize(m_pixels,0);
//--- restore parameters
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CFlameCanvas::RatesTotal(const int value)
{
if(value==0)
return;
if(m_rates_total==0)
m_rates_total=value;
else
{
if(m_rates_total!=value)
{
//--- move object
ObjectSetInteger(0,m_objname,OBJPROP_TIME,0,
ObjectGetInteger(0,m_objname,OBJPROP_TIME)+(value-m_rates_total)*PeriodSeconds());
m_rates_total=value;
}
}
}
//+------------------------------------------------------------------+
//| Adjusts to the chart scale |
//+------------------------------------------------------------------+
void CFlameCanvas::ChartScale(void)
{
m_chart_scale=(uint)ChartGetInteger(0,CHART_SCALE);
//--- set params
switch(m_chart_scale)
{
case 0:
m_bar_gap =1;
m_bar_width=1;
break;
case 1:
m_bar_gap =2;
m_bar_width=1;
break;
case 2:
m_bar_gap =4;
m_bar_width=2;
break;
case 3:
m_bar_gap =8;
m_bar_width=4;
break;
case 4:
m_bar_gap =16;
m_bar_width=10;
break;
case 5:
m_bar_gap =32;
m_bar_width=22;
break;
default:
return;
}
}
//+------------------------------------------------------------------+
//| Sets palette |
//+------------------------------------------------------------------+
void CFlameCanvas::PaletteSet(uint clr)
{
//--- create palette
double g=0,b=0,dg=1.45,db=0.63;
//---
for(uint a,i=0;i<256;i++)
{
//--- the first 32 values ??of flame are completely transparent
a=uchar(i<32?0:i-32);
//--- generate color for the i value of flame
m_palette[i]=(a<<24)|(uint(255)<<16)|(uint(g+0.5)<<8)|uint(b+0.5);
//--- increment the color components
//--- the red color gets gradient due to transparency
if(i>80) g+=dg;
if(i>160) b+=db;
}
}
//+------------------------------------------------------------------+
//| Draws the flame |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameDraw(const double &prices[],const int width,const int lenght)
{
static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}};
static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}};
//--- draw
CloudDraw(prices,width,lenght,sword,flame);
//--- copy flame buffer
FlameCalculate();
//--- start timer
EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[])
{
//--- check
int total=ArraySize(m_cloud_axis);
if(total<2)
return;
if(total>lenght)
total=lenght;
//--- draw
int xb,xe; // coordinates of the segment
int ybm,yem; // coordinates of the center line
int yb1,ye1; // coordinates of the first line
int yb2,ye2; // coordinates of the second line
//--- for implementation of variable width
int w_total=ArraySize(size);
if(w_total<2)
return;
int w_i =0;
int w_is=(int)size[w_i].pos*total/100;
int w_ie=(int)size[w_i+1].pos*total/100;
double w =size[w_i].size*width/100;
double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is);
//--- draw from left to right
xb=0;
ybm=m_cloud_axis[0];
yb1=ybm-(int)(w/2);
yb2=ybm+(int)(w/2);
//--- draw
for(int i=1;i<total;i++)
{
xe=(int)(i*m_bar_gap);
if(m_cloud_axis[i]==DBL_MAX)
continue;
yem=m_cloud_axis[i];
w+=dw;
ye1=yem-(int)(w/2);
ye2=yem+(int)(w/2);
//--- draw the segment of 'cloud'
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
xb=xe;
if(xb>=m_width)
break;
yb1=ye1;
yb2=ye2;
while(i>=w_ie-1 && i!=total-1)
{
w_i++;
w_is=(int)size[w_i].pos*total/100;
w_ie=(int)size[w_i+1].pos*total/100;
w =size[w_i].size*width/100;
if(w_ie==w_is)
{
//--- for "instant" resize
dw=size[w_i+1].size*width/100-w;
w+=dw;
ye1=yem-(int)(w/2);
ye2=yem+(int)(w/2);
//--- draw the segment of 'cloud'
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
yb1=ye1;
yb2=ye2;
}
else
{
dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is);
break;
}
}
}
//--- copy flame buffer
FlameCalculate();
}
//+------------------------------------------------------------------+
//| Sets parameters of the flame and starts to draw |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameSet(void)
{
m_a1=m_bar_gap*((m_ye1-m_yb1)/((double)m_xe1-m_xb1));
m_a2=m_bar_gap*((m_ye2-m_yb2)/((double)m_xe2-m_xb2));
}
//+------------------------------------------------------------------+
//| Sets parameters of the flame and starts to draw |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameSet(datetime tb1,double pb1,
datetime te1,double pe1,
datetime tb2,double pb2,
datetime te2,double pe2)
{
datetime obj_time =(datetime)ObjectGetInteger(0,m_objname,OBJPROP_TIME);
double obj_price=ObjectGetDouble(0,m_objname,OBJPROP_PRICE);
int dx,dy;
//--- save parameters
m_tb1=tb1;
m_pb1=pb1;
m_te1=te1;
m_pe1=pe1;
m_tb2=tb2;
m_pb2=pb2;
m_te2=te2;
m_pe2=pe2;
//--- resize
Resize();
//--- convert
if(ChartTimePriceToXY(0,0,obj_time,obj_price,dx,dy))
{
dy=m_yb1;
if(ChartTimePriceToXY(0,0,tb1,pb1,m_xb1,m_yb1))
if(ChartTimePriceToXY(0,0,te1,pe1,m_xe1,m_ye1))
if(ChartTimePriceToXY(0,0,tb2,pb2,m_xb2,m_yb2))
if(ChartTimePriceToXY(0,0,te2,pe2,m_xe2,m_ye2))
{
//--- convert to canvas coordinates
m_xb1-=dx;
m_xe1-=dx;
m_xb2-=dx;
m_xe2-=dx;
//---
FlameSet();
}
}
//--- start timer
EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL);
}
//+------------------------------------------------------------------+
//| Generate array that describes the body of flame |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameCreate(void)
{
static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}};
static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}};
//---
double a=rand(); // parameter of line a*x+b
double b=rand(); // parameter of line a*x+b
double c=rand(); // parameter of sine c*Sin(d*x)
double d=rand(); // parameter of sine c*Sin(d*x)
int w=rand(); // width at the base
int l=rand(); // length
//--- normalize
a=fmod(a,(m_a2-m_a1))+m_a1;
b=(m_yb1+m_yb2)/2;
c=fmod(c,20);
d=fmod(d,3*M_PI)+M_PI;
//--- shape
w%=150;
if(w<10)
w=10; // but no less than 10
sword[1].size=w;
w=rand();
l%=50;
sword[1].pos=l+30;
l=rand();
//--- sizes
w=(m_yb2-m_yb1!=0) ? w%(m_yb2-m_yb1) : 10; // proportional to the starting width
if(w<10)
w=10; // but no less than 10
l=l%((m_xe1-m_xb1)/(int)m_bar_gap-20)+20; // proportional to length
//--- create
int total=ArraySize(m_cloud_axis);
for(int i=0;i<total;i++)
m_cloud_axis[i]=int(a*i+b+c*sin(i/d));
//--- draw
FlameDraw(w,l,sword,flame);
}
//+------------------------------------------------------------------+
//| Calculates and renders frame |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameCalculate(void)
{
//--- calculate new frame
int c;
int idx;
//--- draw body of flame to the right
for(int x=0,x_tot=m_width-1;x<x_tot;x++)
{
//--- separately for y==0
c=m_flame[x]+m_flame[x+m_width];
c+=+m_flame[x]+m_flame[x+m_width];
m_flame[x]=uchar(c/4);
//---
for(int y=1,y_tot=m_height-1;y<y_tot;y++)
{
idx=y*m_width+x;
c=m_flame[idx-m_width]+m_flame[idx]+m_flame[idx+m_width];
idx++;
c+=m_flame[idx-m_width]+m_flame[idx]+m_flame[idx+m_width];
m_flame[idx]=uchar(c/6);
}
//--- separately for y==m_height-1
idx=(m_height-1)*m_width+x;
c=m_flame[idx-m_width]+m_flame[idx];
idx++;
c+=m_flame[idx-m_width]+m_flame[idx];
m_flame[idx]=uchar(c/4);
}
//--- move flame to the resource buffer
for(int y=0;y<m_height;y++)
{
for(int x=0;x<m_width;x++)
{
idx=y*m_width+x;
m_pixels[idx]=m_palette[m_flame[idx]];
}
}
//---
}
//+------------------------------------------------------------------+
//| Draws "cloud" |
//+------------------------------------------------------------------+
void CFlameCanvas::CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level,const bool custom_gradient)
{
//--- check
int total=ArraySize(prices);
if(total<2)
return;
if(total>lenght)
total=lenght;
//--- draw
int xb,xe; // coordinates of the segment
int ybm,yem; // coordinates of the center line
int yb1,ye1; // coordinates of the first line
int yb2,ye2; // coordinates of the second line
int xx;
//--- for implementation of variable width
int w_total=ArraySize(size);
if(w_total<2)
return;
int w_i =0;
int w_is=(int)size[w_i].pos*total/100;
int w_ie=(int)size[w_i+1].pos*total/100;
double w =size[w_i].size*width/100;
double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is);
//--- draw from left to right
xb=0;
ChartTimePriceToXY(0,0,0,prices[0],xx,ybm);
yb1=ybm-(int)(w/2);
yb2=ybm+(int)(w/2);
//--- draw
for(int i=1;i<total;i++)
{
xe=(int)(i*m_bar_gap);
if(prices[i]==DBL_MAX)
continue;
ChartTimePriceToXY(0,0,0,prices[i],xx,yem);
w+=dw;
ye1=yem-(int)(w/2);
ye2=yem+(int)(w/2);
//--- draw the segment of 'cloud'
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
xb=xe;
if(xb>=m_width)
break;
yb1=ye1;
yb2=ye2;
while(i>=w_ie-1 && i!=total-1)
{
w_i++;
w_is=(int)size[w_i].pos*total/100;
w_ie=(int)size[w_i+1].pos*total/100;
w =size[w_i].size*width/100;
if(w_ie==w_is)
{
//--- for "instant" resize
dw=size[w_i+1].size*width/100-w;
w+=dw;
ye1=yem-(int)(w/2);
ye2=yem+(int)(w/2);
//--- draw the segment of 'cloud'
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
yb1=ye1;
yb2=ye2;
}
else
{
dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is);
break;
}
}
}
}
//+------------------------------------------------------------------+
//| Draws area with vertical fill using specified gradient |
//+------------------------------------------------------------------+
void CFlameCanvas::GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[])
{
//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order
//--- get length by X and Y
int x1 =xb;
int y1 =yb1;
int x2 =xb;
int y2 =yb2;
int dx =(xe>xb)? xe-xb : xb-xe;
int dy1=(ye1>yb1)? ye1-yb1 : yb1-ye1;
int dy2=(ye2>yb2)? ye2-yb2 : yb2-ye2;
//--- get direction by X and Y
int sx =(xb<xe)? 1 : -1;
int sy1=(yb1<ye1)? 1 : -1;
int sy2=(yb2<ye2)? 1 : -1;
int er1=dx-dy1;
int er2=dx-dy2;
//--- extreme colors
uint clr_first=gradient[0].clr;
uint clr_last =gradient[ArraySize(gradient)-1].clr;
//--- draw the first line
while(x1!=xe || y1!=ye1)
{
//--- calculate coordinates of next pixel of the first line
if((er1<<1)>-dy1)
{
//--- try to change X coordinate of the first line
//--- draw the second line
while(x2!=xe || y2!=ye2)
{
//--- calculate coordinates of next pixel of the second line
if((er2<<1)>-dy2)
{
//--- try to change X coordinate of the second line
//--- gradient fill
GradientVerticalLine(x1,y1,y2,gradient);
er2-=dy2;
if(x2!=xe)
x2+=sx;
}
if((er2<<1)<dx)
{
er2+=dx;
if(y2!=ye2)
y2+=sy2;
}
//--- draw the first line
if(x1!=x2)
break;
}
er1-=dy1;
if(x1!=xe)
x1+=sx;
}
if((er1<<1)<dx)
{
er1+=dx;
if(y1!=ye1)
y1+=sy1;
}
}
//--- gradient fill
GradientVerticalLine(x1,ye1,ye2,gradient);
}
//+------------------------------------------------------------------+
//| Draws gradient vertical line |
//+------------------------------------------------------------------+
void CFlameCanvas::GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2)
{
//---
double dc;
int dd,dy=y2-y1;
//--- check
if(dy==0)
return;
//--- extract components from the first color
uchar clr=(uchar)clr1;
//--- parameters of pixels iteration
if(dy>0)
{
dd=dy;
dy=1;
}
else
{
dd=-dy;
dy=-1;
}
//--- increments for the color components
dc=(double)((uchar)clr2-clr)/dd;
//--- draw
for(int i=0;y1!=y2;i++,y1+=dy)
{
int idx=y1*m_width+x;
//--- check range
if(idx<0 || idx>=ArraySize(m_flame))
continue;
if(x>=0 && x<m_width && y1>=0 && y1<m_height)
if(m_flame[idx]<(uchar)(clr+dc*i))
m_flame[idx]=(uchar)(clr+dc*i);
}
}
//+------------------------------------------------------------------+
//| Draws vertical line with specified gradient |
//+------------------------------------------------------------------+
void CFlameCanvas::GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[])
{
//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order
int total=ArraySize(gradient);
int dy=y2-y1;
//--- draw segments
for(int i=0;i<total-1;i++)
GradientVerticalLineMonochrome(x,y1+dy*gradient[i].pos/100,y1+dy*gradient[i+1].pos/100,gradient[i].clr,gradient[i+1].clr);
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CFlameCanvas::ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- events filter
switch(id)
{
case CHARTEVENT_CHART_CHANGE:
//--- handle only chart modification events
if(m_chart_scale!=(uint)ChartGetInteger(0,CHART_SCALE))
{
Delay(20);
//--- changed horizontal scale
ChartScale();
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
return;
}
if(m_height!=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS))
{
//--- changed vertical size
Delay(20);
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
return;
}
if(m_chart_price_min!=ChartGetDouble(0,CHART_PRICE_MIN) ||
m_chart_price_max!=ChartGetDouble(0,CHART_PRICE_MAX))
{
//--- changed vertical scale
Delay(20);
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
return;
}
break;
//--- organize custom timer
case CHARTEVENT_CUSTOM+1302:
//--- time to draw the new frame?
if(GetTickCount()>m_time_redraw)
{
//--- add the body of flame
FlameCreate();
//--- draw frame
FlameCalculate();
Update();
//--- calculate time for the next frame
m_time_redraw=GetTickCount()+m_delay;
}
//--- generate next event for custom timer
EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL);
break;
}
}
//+------------------------------------------------------------------+
//| Delay |
//+------------------------------------------------------------------+
void CFlameCanvas::Delay(const uint value)
{
//--- too small
if(value<10)
return;
//--- start delay
uint cnt=GetTickCount()+value;
//--- delay
while(cnt>=GetTickCount());
}
//+------------------------------------------------------------------+
File diff suppressed because it is too large Load Diff
+211
View File
@@ -0,0 +1,211 @@
//+------------------------------------------------------------------+
//| ChartObjectPanel.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include <ChartObjects\ChartObjectsTxtControls.mqh>
#include <Arrays\ArrayObj.mqh>
#include <Arrays\ArrayInt.mqh>
//+------------------------------------------------------------------+
//| Class CChartObjectPanel. |
//| Purpose: Class for grouping objects for managing a chart |
//+------------------------------------------------------------------+
class CChartObjectPanel : public CChartObjectButton
{
protected:
CArrayObj m_attachment; // array of attached objects
CArrayInt m_dX; // array of dX attached objects
CArrayInt m_dY; // array of dY attached objects
bool m_expanded; // collapsed/expanded flag
public:
CChartObjectPanel();
~CChartObjectPanel();
//--- method for attaching objects
bool Attach(CChartObjectLabel *chart_object);
bool X_Distance(const int X);
int X_Distance(void) const { return(CChartObjectButton::X_Distance()); }
bool Y_Distance(const int Y);
int Y_Distance(void) const { return(CChartObjectButton::Y_Distance()); }
int X_Size() const;
int X_Size(const int Y) const { return(CChartObjectButton::X_Size()); }
int Y_Size() const;
int Y_Size(const int Y) const { return(CChartObjectButton::Y_Size()); }
int Timeframes(void) const { return(CChartObjectButton::Timeframes()); }
virtual bool Timeframes(const int timeframes);
bool State(const bool state);
bool State(void) const { return(CChartObjectButton::State()); }
bool CheckState();
protected:
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
void CChartObjectPanel::CChartObjectPanel(void) : m_expanded(true)
{
}
//+------------------------------------------------------------------+
//| Destructor. |
//+------------------------------------------------------------------+
void CChartObjectPanel::~CChartObjectPanel(void)
{
//--- All objects added by the method Add(), deleted automatically
}
//+------------------------------------------------------------------+
//| Method Attach |
//+------------------------------------------------------------------+
bool CChartObjectPanel::Attach(CChartObjectLabel *chart_object)
{
if(m_attachment.Add(chart_object))
{
int x,y;
x=chart_object.X_Distance();
m_dX.Add(chart_object.X_Distance());
x+=X_Distance();
chart_object.X_Distance(X_Distance()+chart_object.X_Distance());
y=CChartObjectButton::Y_Size();
y+=chart_object.Y_Distance();
m_dY.Add(chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2);
chart_object.Y_Distance(Y_Distance()+chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2);
return(true);
}
//---
return(false);
}
//+------------------------------------------------------------------+
//| Method X_Distance |
//+------------------------------------------------------------------+
bool CChartObjectPanel::X_Distance(const int X)
{
CChartObjectLabel *chart_object;
//---
for(int i=0;i<m_attachment.Total();i++)
{
chart_object=m_attachment.At(i);
chart_object.X_Distance(X+m_dX.At(i));
}
//---
return(CChartObjectButton::X_Distance(X));
}
//+------------------------------------------------------------------+
//| Method Y_Distance |
//+------------------------------------------------------------------+
bool CChartObjectPanel::Y_Distance(const int Y)
{
CChartObjectLabel *chart_object;
//---
for(int i=0;i<m_attachment.Total();i++)
{
chart_object=m_attachment.At(i);
chart_object.Y_Distance(Y+m_dY.At(i));
}
//---
return(CChartObjectButton::Y_Distance(Y));
}
//+------------------------------------------------------------------+
//| Method X_Size |
//+------------------------------------------------------------------+
int CChartObjectPanel::X_Size() const
{
int max_x=CChartObjectButton::X_Size()+X_Distance();
CChartObjectLabel *chart_object;
//---
if(m_expanded)
{
for(int i=0;i<m_attachment.Total();i++)
if((chart_object=m_attachment.At(i))!=NULL)
if(max_x<chart_object.X_Distance()+chart_object.X_Size())
max_x=chart_object.X_Distance()+chart_object.X_Size();
return(max_x-X_Distance()+2);
}
//---
return(CChartObjectButton::X_Size()+2);
}
//+------------------------------------------------------------------+
//| Method Y_Size |
//+------------------------------------------------------------------+
int CChartObjectPanel::Y_Size() const
{
int max_y=CChartObjectButton::Y_Size()+Y_Distance();
CChartObjectLabel *chart_object;
//---
if(m_expanded)
{
for(int i=0;i<m_attachment.Total();i++)
if((chart_object=m_attachment.At(i))!=NULL)
if(max_y<chart_object.Y_Distance()+chart_object.Y_Size())
max_y=chart_object.Y_Distance()+chart_object.Y_Size();
return(max_y-Y_Distance()+2);
}
//---
return(CChartObjectButton::Y_Size()+2);
}
//+------------------------------------------------------------------+
//| Method Timeframes |
//+------------------------------------------------------------------+
bool CChartObjectPanel::Timeframes(const int timeframes)
{
int i;
bool res=CChartObject::Timeframes(timeframes);
CChartObjectLabel *chart_object;
//---
if(m_expanded)
for(i=0;i<m_attachment.Total();i++)
{
chart_object=m_attachment.At(i);
res&=chart_object.Timeframes(timeframes);
}
//---
return(res);
}
//+------------------------------------------------------------------+
//| Method State |
//+------------------------------------------------------------------+
bool CChartObjectPanel::State(const bool state)
{
if(CChartObjectButton::State(state))
{
m_expanded=state;
return(true);
}
//---
return(false);
}
//+------------------------------------------------------------------+
//| Method CheckState |
//+------------------------------------------------------------------+
bool CChartObjectPanel::CheckState(void)
{
//--- state changed
if(m_expanded!=State())
{
//--- apply new state
m_expanded=State();
if(m_expanded)
{
//--- make all objects visible
for(int i=0;i<m_attachment.Total();i++)
{
CChartObjectLabel *chart_object=m_attachment.At(i);
chart_object.Timeframes(-1);
}
}
else
{
//--- make all objects invisible
for(int i=0;i<m_attachment.Total();i++)
{
CChartObjectLabel *chart_object=m_attachment.At(i);
chart_object.Timeframes(0x100000);
}
}
return(true);
}
//---
return(false);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,398 @@
//+------------------------------------------------------------------+
//| ChartObjectSubChart.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectSubChart. |
//| Purpose: Class of the "SubChart" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectSubChart : public CChartObject
{
public:
CChartObjectSubChart(void);
~CChartObjectSubChart(void);
//--- method of creating object
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_CHART); }
//--- methods of access to properties of the object
int X_Distance(void) const;
bool X_Distance(const int X) const;
int Y_Distance(void) const;
bool Y_Distance(const int Y) const;
ENUM_BASE_CORNER Corner(void) const;
bool Corner(const ENUM_BASE_CORNER corner) const;
int X_Size(void) const;
bool X_Size(const int size) const;
int Y_Size(void) const;
bool Y_Size(const int size) const;
string Symbol(void) const;
bool Symbol(const string symbol) const;
int Period(void) const;
bool Period(const int period) const;
int Scale(void) const;
bool Scale(const int scale) const;
bool DateScale(void) const;
bool DateScale(const bool scale) const;
bool PriceScale(void) const;
bool PriceScale(const bool scale) const;
//--- change of time/price coordinates is blocked
datetime Time(const int point) const { return(CChartObject::Time(point)); }
bool Time(const int point,const datetime time) const { return(false); }
double Price(const int point) const { return(CChartObject::Price(point)); }
bool Price(const int point,const double price) const { return(false); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectSubChart::CChartObjectSubChart(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectSubChart::~CChartObjectSubChart(void)
{
}
//+------------------------------------------------------------------+
//| Create object "SubChart" |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Create(long chart_id,const string name,const int window,
const int X,const int Y,const int sizeX,const int sizeY)
{
if(!ObjectCreate(chart_id,name,OBJ_CHART,window,0,0,0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
if(!X_Size(sizeX) || !Y_Size(sizeY))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the X-distance |
//+------------------------------------------------------------------+
int CChartObjectSubChart::X_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the X-distance |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::X_Distance(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
}
//+------------------------------------------------------------------+
//| Get the Y-distance |
//+------------------------------------------------------------------+
int CChartObjectSubChart::Y_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the Y-distance |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Y_Distance(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
}
//+------------------------------------------------------------------+
//| Get base corner |
//+------------------------------------------------------------------+
ENUM_BASE_CORNER CChartObjectSubChart::Corner(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
}
//+------------------------------------------------------------------+
//| Set base corner |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Corner(const ENUM_BASE_CORNER corner) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
}
//+------------------------------------------------------------------+
//| Get the X-size |
//+------------------------------------------------------------------+
int CChartObjectSubChart::X_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
}
//+------------------------------------------------------------------+
//| Set X-size |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::X_Size(const int size) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,size));
}
//+------------------------------------------------------------------+
//| Get the Y-size |
//+------------------------------------------------------------------+
int CChartObjectSubChart::Y_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
}
//+------------------------------------------------------------------+
//| Set the Y-size |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Y_Size(const int size) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,size));
}
//+------------------------------------------------------------------+
//| Get chart symbol |
//+------------------------------------------------------------------+
string CChartObjectSubChart::Symbol(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_SYMBOL));
}
//+------------------------------------------------------------------+
//| Set chart symbol |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Symbol(const string symbol) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_SYMBOL,symbol));
}
//+------------------------------------------------------------------+
//| Get chart period |
//+------------------------------------------------------------------+
int CChartObjectSubChart::Period(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PERIOD));
}
//+------------------------------------------------------------------+
//| Set chart period |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Period(const int period) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_PERIOD,period));
}
//+------------------------------------------------------------------+
//| Get chart scale |
//+------------------------------------------------------------------+
int CChartObjectSubChart::Scale(void) const
{
//--- check
if(m_chart_id==-1)
return(-1);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CHART_SCALE));
}
//+------------------------------------------------------------------+
//| Set chart scale |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Scale(const int scale) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CHART_SCALE,scale));
}
//+------------------------------------------------------------------+
//| Get the "time scale" flag |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::DateScale(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE));
}
//+------------------------------------------------------------------+
//| Set the "time scale" flag |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::DateScale(const bool scale) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE,scale));
}
//+------------------------------------------------------------------+
//| Get the "price scale" flag |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::PriceScale(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE));
}
//+------------------------------------------------------------------+
//| Set the "price scale" flag |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::PriceScale(const bool scale) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE,scale));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "X-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "corner" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "X-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "symbol" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_SYMBOL);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write value of the "period" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PERIOD),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "scale" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
return(false);
//--- write value of the "time scale" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "price scale" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectSubChart::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "X-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "corner" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "X-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "symbol" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_SYMBOL,str))
return(false);
//--- read value of the "period" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_PERIOD,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "scale" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDatetime(file_handle)))
return(false);
//--- read value of the "time scale" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "price scale" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
+479
View File
@@ -0,0 +1,479 @@
//+------------------------------------------------------------------+
//| ChartObjectsArrows.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All arrows. |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectArrow. |
//| Purpose: Class of the "Arrow" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectArrow : public CChartObject
{
public:
CChartObjectArrow(void);
~CChartObjectArrow(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price,const char code);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_ARROW); }
//--- methods of access to properties of the object
char ArrowCode(void) const;
virtual bool ArrowCode(const char code) const;
ENUM_ARROW_ANCHOR Anchor(void) const;
virtual bool Anchor(const ENUM_ARROW_ANCHOR anchor) const;
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrow::CChartObjectArrow(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrow::~CChartObjectArrow(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Arrow" |
//+------------------------------------------------------------------+
bool CChartObjectArrow::Create(long chart_id,const string name,const int window,const datetime time,const double price,const char code)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!ArrowCode(code))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get code of "arrow" symbol |
//+------------------------------------------------------------------+
char CChartObjectArrow::ArrowCode(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((char)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE));
}
//+------------------------------------------------------------------+
//| Set code of "arrow" symbol |
//+------------------------------------------------------------------+
bool CChartObjectArrow::ArrowCode(const char code) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE,code));
}
//+------------------------------------------------------------------+
//| Get anchor type |
//+------------------------------------------------------------------+
ENUM_ARROW_ANCHOR CChartObjectArrow::Anchor(void) const
{
//--- result
return((ENUM_ARROW_ANCHOR)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR));
}
//+------------------------------------------------------------------+
//| Set anchor type |
//+------------------------------------------------------------------+
bool CChartObjectArrow::Anchor(const ENUM_ARROW_ANCHOR anchor) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,anchor));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectArrow::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- writing
if(!CObject::Save(file_handle))
return(false);
//--- write code of "arrow" symbol
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write anchor type
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectArrow::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- reading
if(!CObject::Load(file_handle))
return(false);
//--- read code of "arrow" symbol
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read anchor type
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowThumbUp. |
//| Purpose: Class of the "Thumbs Up" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowThumbUp : public CChartObjectArrow
{
public:
CChartObjectArrowThumbUp(void);
~CChartObjectArrowThumbUp(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_THUMB_UP); }
//--- change of arrow code is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowThumbUp::CChartObjectArrowThumbUp(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowThumbUp::~CChartObjectArrowThumbUp(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Thumbs Up" |
//+------------------------------------------------------------------+
bool CChartObjectArrowThumbUp::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_UP,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowThumbDown. |
//| Purpose: Class of the "Thumbs Down" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowThumbDown : public CChartObjectArrow
{
public:
CChartObjectArrowThumbDown(void);
~CChartObjectArrowThumbDown(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_THUMB_DOWN); }
//--- change of arrow code is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowThumbDown::CChartObjectArrowThumbDown(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowThumbDown::~CChartObjectArrowThumbDown(void)
{
}
//+------------------------------------------------------------------+
//| Create object "ThumbsDown" |
//+------------------------------------------------------------------+
bool CChartObjectArrowThumbDown::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_DOWN,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowUp. |
//| Purpose: Class of the "Arrow Up" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowUp : public CChartObjectArrow
{
public:
CChartObjectArrowUp(void);
~CChartObjectArrowUp(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_UP); }
//--- change of arrow code is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowUp::CChartObjectArrowUp(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowUp::~CChartObjectArrowUp(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Arrow Up" |
//+------------------------------------------------------------------+
bool CChartObjectArrowUp::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_UP,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowDown. |
//| Purpose: Class of the "Arrow Down" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowDown : public CChartObjectArrow
{
public:
CChartObjectArrowDown(void);
~CChartObjectArrowDown(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_DOWN); }
//--- change of arrow code is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowDown::CChartObjectArrowDown(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowDown::~CChartObjectArrowDown(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Arrow Down" |
//+------------------------------------------------------------------+
bool CChartObjectArrowDown::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_DOWN,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowStop. |
//| Purpose: Class of the "Stop Sign" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowStop : public CChartObjectArrow
{
public:
CChartObjectArrowStop(void);
~CChartObjectArrowStop(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_STOP); }
//--- change of arrow code is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowStop::CChartObjectArrowStop(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowStop::~CChartObjectArrowStop(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Stop Sign" |
//+------------------------------------------------------------------+
bool CChartObjectArrowStop::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_STOP,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowCheck. |
//| Purpose: Class of the "Check Sign" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowCheck : public CChartObjectArrow
{
public:
CChartObjectArrowCheck(void);
~CChartObjectArrowCheck(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_CHECK); }
//--- change of arrow code is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowCheck::CChartObjectArrowCheck(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowCheck::~CChartObjectArrowCheck(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Check Sign" |
//+------------------------------------------------------------------+
bool CChartObjectArrowCheck::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_CHECK,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowLeftPrice. |
//| Purpose: Class of the "Left Price Label" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowLeftPrice : public CChartObjectArrow
{
public:
CChartObjectArrowLeftPrice(void);
~CChartObjectArrowLeftPrice(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_LEFT_PRICE); }
//--- change of arrow code and anchor point is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
virtual bool Anchor(const ENUM_ARROW_ANCHOR anchor) const override { return(false); }
ENUM_ARROW_ANCHOR Anchor(void) const { return(CChartObjectArrow::Anchor()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowLeftPrice::CChartObjectArrowLeftPrice(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowLeftPrice::~CChartObjectArrowLeftPrice(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Left Price Label" |
//+------------------------------------------------------------------+
bool CChartObjectArrowLeftPrice::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_LEFT_PRICE,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectArrowRightPrice. |
//| Purpose: Class of the "Right Price Label" object of chart. |
//| Derives from class CChartObjectArrow. |
//+------------------------------------------------------------------+
class CChartObjectArrowRightPrice : public CChartObjectArrow
{
public:
CChartObjectArrowRightPrice(void);
~CChartObjectArrowRightPrice(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_ARROW_RIGHT_PRICE); }
//--- change of arrow code and anchor point is blocked
virtual bool ArrowCode(const char code) const override { return(false); }
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
virtual bool Anchor(const ENUM_ARROW_ANCHOR anchor) const override { return(false); }
ENUM_ARROW_ANCHOR Anchor(void) const { return(CChartObjectArrow::Anchor()); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectArrowRightPrice::CChartObjectArrowRightPrice(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectArrowRightPrice::~CChartObjectArrowRightPrice(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Right Price Label" |
//+------------------------------------------------------------------+
bool CChartObjectArrowRightPrice::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_ARROW_RIGHT_PRICE,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,512 @@
//+------------------------------------------------------------------+
//| ChartObjectsBmpControls.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All objects with "bmp" pictures. |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectBitmap. |
//| Purpose: Class of the "Bitmap" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectBitmap : public CChartObject
{
public:
CChartObjectBitmap(void);
~CChartObjectBitmap(void);
//--- methods of access to properties of the object
string BmpFile(void) const;
bool BmpFile(const string name) const;
int X_Offset(void) const;
bool X_Offset(const int X) const;
int Y_Offset(void) const;
bool Y_Offset(const int Y) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_BITMAP); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectBitmap::CChartObjectBitmap(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectBitmap::~CChartObjectBitmap(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Bitmapp" |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_BITMAP,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get name of bmp-file |
//+------------------------------------------------------------------+
string CChartObjectBitmap::BmpFile(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE));
}
//+------------------------------------------------------------------+
//| Set name of bmp-file |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::BmpFile(const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,name));
}
//+------------------------------------------------------------------+
//| Get the XOffset property |
//+------------------------------------------------------------------+
int CChartObjectBitmap::X_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XOFFSET));
}
//+------------------------------------------------------------------+
//| Set the XOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::X_Offset(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XOFFSET,X));
}
//+------------------------------------------------------------------+
//| Get the YOffset property |
//+------------------------------------------------------------------+
int CChartObjectBitmap::Y_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YOFFSET));
}
//+------------------------------------------------------------------+
//| Set the YOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Y_Offset(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YOFFSET,Y));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "name of bmp-file" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "name of bmp-file" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,str))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectBmpLabel. |
//| Purpose: Class of the "Bitmap label" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectBmpLabel : public CChartObject
{
public:
CChartObjectBmpLabel(void);
~CChartObjectBmpLabel(void);
//--- methods of access to properties of the object
int X_Distance(void) const;
bool X_Distance(const int X) const;
int Y_Distance(void) const;
bool Y_Distance(const int Y) const;
int X_Size(void) const;
int Y_Size(void) const;
ENUM_BASE_CORNER Corner(void) const;
bool Corner(const ENUM_BASE_CORNER corner) const;
string BmpFileOn(void) const;
bool BmpFileOn(const string name) const;
string BmpFileOff(void) const;
bool BmpFileOff(const string name) const;
bool State(void) const;
bool State(const bool state) const;
int X_Offset(void) const;
bool X_Offset(const int X) const;
int Y_Offset(void) const;
bool Y_Offset(const int Y) const;
//--- change of time/price coordinates is blocked
bool Time(const datetime time) const { return(false); }
bool Price(const double price) const { return(false); }
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_BITMAP_LABEL); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectBmpLabel::CChartObjectBmpLabel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectBmpLabel::~CChartObjectBmpLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Bitmap label" |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Create(long chart_id,const string name,const int window,const int X,const int Y)
{
if(!ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,window,0,0.0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the X-distance property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::X_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the X-distance property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::X_Distance(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
}
//+------------------------------------------------------------------+
//| Get the Y-distance property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::Y_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the Y-distance property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Y_Distance(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
}
//+------------------------------------------------------------------+
//| Get the X-size |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::X_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
}
//+------------------------------------------------------------------+
//| Get the Y-size |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::Y_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
}
//+------------------------------------------------------------------+
//| Get the Corner property |
//+------------------------------------------------------------------+
ENUM_BASE_CORNER CChartObjectBmpLabel::Corner(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
}
//+------------------------------------------------------------------+
//| Set the Corner property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Corner(const ENUM_BASE_CORNER corner) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
}
//+------------------------------------------------------------------+
//| Get filename of the "bmp-ON" property |
//+------------------------------------------------------------------+
string CChartObjectBmpLabel::BmpFileOn(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,0));
}
//+------------------------------------------------------------------+
//| Set filename for the "bmp-ON" property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::BmpFileOn(const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,0,name));
}
//+------------------------------------------------------------------+
//| Get filename of the "bmp-OFF" property |
//+------------------------------------------------------------------+
string CChartObjectBmpLabel::BmpFileOff(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,1));
}
//+------------------------------------------------------------------+
//| Set filename for the "bmp-OFF" property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::BmpFileOff(const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,1,name));
}
//+------------------------------------------------------------------+
//| Get the State property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::State(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE));
}
//+------------------------------------------------------------------+
//| Set the State property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::State(const bool state) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,state));
}
//+------------------------------------------------------------------+
//| Get the XOffset property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::X_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XOFFSET));
}
//+------------------------------------------------------------------+
//| Set the XOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::X_Offset(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XOFFSET,X));
}
//+------------------------------------------------------------------+
//| Get the YOffset property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::Y_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YOFFSET));
}
//+------------------------------------------------------------------+
//| Set the YOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Y_Offset(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YOFFSET,Y));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "X-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Corner" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "filename bmp-ON" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,0);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write value of the "filename bmp-OFF" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,1);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write state
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE))!=sizeof(long))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading object parameters from file |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "X-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of "Corner" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "filename bmp-ON" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,0,str))
return(false);
//--- read value of the "filename bmp-OFF" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,1,str))
return(false);
//--- read state
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,FileReadLong(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,246 @@
//+------------------------------------------------------------------+
//| ChartObjectsChannels.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All channels. |
//+------------------------------------------------------------------+
#include "ChartObjectsLines.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectChannel. |
//| Purpose: Class of the "Equidistant channel" object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectChannel : public CChartObjectTrend
{
public:
CChartObjectChannel(void);
~CChartObjectChannel(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_CHANNEL); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectChannel::CChartObjectChannel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectChannel::~CChartObjectChannel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Equidistant channel" |
//+------------------------------------------------------------------+
bool CChartObjectChannel::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_CHANNEL,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectStdDevChannel. |
//| Purpose: Class of the "Standrad deviation channel" |
//| object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectStdDevChannel : public CChartObjectTrend
{
public:
CChartObjectStdDevChannel(void);
~CChartObjectStdDevChannel(void);
//--- methods of access to properties of the object
double Deviations(void) const;
bool Deviations(const double deviation) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const datetime time2,const double deviation);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_STDDEVCHANNEL); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectStdDevChannel::CChartObjectStdDevChannel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectStdDevChannel::~CChartObjectStdDevChannel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Standard deviation channel" |
//+------------------------------------------------------------------+
bool CChartObjectStdDevChannel::Create(long chart_id,const string name,const int window,
const datetime time1,const datetime time2,const double deviation)
{
if(!ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,window,time1,0.0,time2,0.0))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
if(!Deviations(deviation))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "Deviations" property |
//+------------------------------------------------------------------+
double CChartObjectStdDevChannel::Deviations(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_DEVIATION));
}
//+------------------------------------------------------------------+
//| Set value for the "Deviations" property |
//+------------------------------------------------------------------+
bool CChartObjectStdDevChannel::Deviations(const double deviation) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_DEVIATION,deviation));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectStdDevChannel::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectTrend::Save(file_handle))
return(false);
//--- write value of the "Deviations" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_DEVIATION))!=sizeof(double))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectStdDevChannel::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectTrend::Load(file_handle))
return(false);
//--- read value of the "Deviations" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_DEVIATION,FileReadDouble(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectRegression. |
//| Purpose: Class of the "Regression channel" object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectRegression : public CChartObjectTrend
{
public:
CChartObjectRegression(void);
~CChartObjectRegression(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const datetime time2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_REGRESSION); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectRegression::CChartObjectRegression(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectRegression::~CChartObjectRegression(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Regression channel" |
//+------------------------------------------------------------------+
bool CChartObjectRegression::Create(long chart_id,const string name,const int window,
const datetime time1,const datetime time2)
{
if(!ObjectCreate(chart_id,name,OBJ_REGRESSION,window,time1,0.0,time2,0.0))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectPitchfork. |
//| Purpose: Class of the "Andrews pitchfork" object of chart |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectPitchfork : public CChartObjectTrend
{
public:
CChartObjectPitchfork(void);
~CChartObjectPitchfork(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_CHANNEL); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectPitchfork::CChartObjectPitchfork(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectPitchfork::~CChartObjectPitchfork(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Andrews pitchfork" |
//+------------------------------------------------------------------+
bool CChartObjectPitchfork::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_PITCHFORK,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,201 @@
//+------------------------------------------------------------------+
//| ChartObjectsElliott.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All Elliott tools. |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectElliottWave3. |
//| Purpose: Class of the "ElliottCorrectiveWave" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectElliottWave3 : public CChartObject
{
public:
CChartObjectElliottWave3(void);
~CChartObjectElliottWave3(void);
//--- methods of access to properties of the object
ENUM_ELLIOT_WAVE_DEGREE Degree(void) const;
bool Degree(const ENUM_ELLIOT_WAVE_DEGREE degree) const;
bool Lines(void) const;
bool Lines(const bool lines) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_ELLIOTWAVE3); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectElliottWave3::CChartObjectElliottWave3(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectElliottWave3::~CChartObjectElliottWave3(void)
{
}
//+------------------------------------------------------------------+
//| Create object "ElliottCorrectiveWave" |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave3::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE3,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "Degree" property |
//+------------------------------------------------------------------+
ENUM_ELLIOT_WAVE_DEGREE CChartObjectElliottWave3::Degree(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_ELLIOT_WAVE_DEGREE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DEGREE));
}
//+------------------------------------------------------------------+
//| Set value for the "Degree" property |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave3::Degree(const ENUM_ELLIOT_WAVE_DEGREE degree) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DEGREE,degree));
}
//+------------------------------------------------------------------+
//| Get value of the "Lines" property |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave3::Lines(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES));
}
//+------------------------------------------------------------------+
//| Set value for the "Lines" property |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave3::Lines(const bool lines) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES,lines));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave3::Save(const int file_handle)
{
bool result;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
result=CChartObject::Save(file_handle);
if(result)
{
//--- write value of the "Degree" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DEGREE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Lines" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES),INT_VALUE)!=sizeof(int))
return(false);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave3::Load(const int file_handle)
{
bool result;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
result=CChartObject::Load(file_handle);
if(result)
{
//--- read value of the "Degree" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DEGREE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Lines" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES,FileReadInteger(file_handle,INT_VALUE)))
return(false);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Class CChartObjectElliottWave5. |
//| Purpose: Class of the "ElliottMotiveWave" object of chart. |
//| Derives from class CChartObjectElliottWave3. |
//+------------------------------------------------------------------+
class CChartObjectElliottWave5 : public CChartObjectElliottWave3
{
public:
CChartObjectElliottWave5(void);
~CChartObjectElliottWave5(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3,
const datetime time4,const double price4,
const datetime time5,const double price5);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_ELLIOTWAVE5); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectElliottWave5::CChartObjectElliottWave5(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectElliottWave5::~CChartObjectElliottWave5(void)
{
}
//+------------------------------------------------------------------+
//| Create object "ElliottMotiveWave" |
//+------------------------------------------------------------------+
bool CChartObjectElliottWave5::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3,
const datetime time4,const double price4,
const datetime time5,const double price5)
{
if(!ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE5,window,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5))
return(false);
if(!Attach(chart_id,name,window,5))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
+365
View File
@@ -0,0 +1,365 @@
//+------------------------------------------------------------------+
//| ChartObjectsFibo.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All Fibonacci tools. |
//+------------------------------------------------------------------+
#include "ChartObjectsLines.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectFibo. |
//| Purpose: Class of the "Fibonacci Lines" object. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectFibo : public CChartObjectTrend
{
public:
CChartObjectFibo(void);
~CChartObjectFibo(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_FIBO); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectFibo::CChartObjectFibo(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectFibo::~CChartObjectFibo(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Fibonacci Lines" |
//+------------------------------------------------------------------+
bool CChartObjectFibo::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_FIBO,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectFiboTimes. |
//| Purpose: Class of the "Fibonacci Time Zones" object of chart |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectFiboTimes : public CChartObject
{
public:
CChartObjectFiboTimes(void);
~CChartObjectFiboTimes(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_FIBOTIMES); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectFiboTimes::CChartObjectFiboTimes(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectFiboTimes::~CChartObjectFiboTimes(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Fibonacci Time Zones" |
//+------------------------------------------------------------------+
bool CChartObjectFiboTimes::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_FIBOTIMES,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectFiboFan. |
//| Purpose: Class of the "Fibonacci Fan" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectFiboFan : public CChartObject
{
public:
CChartObjectFiboFan(void);
~CChartObjectFiboFan(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_FIBOFAN); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectFiboFan::CChartObjectFiboFan(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectFiboFan::~CChartObjectFiboFan(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Fibonacci Fan" |
//+------------------------------------------------------------------+
bool CChartObjectFiboFan::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_FIBOFAN,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectFiboArc. |
//| Purpose: Class of the "Fibonacci Arcs" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectFiboArc : public CChartObject
{
public:
CChartObjectFiboArc(void);
~CChartObjectFiboArc(void);
//--- methods of access to properties of the object
double Scale(void) const;
bool Scale(const double scale) const;
bool Ellipse(void) const;
bool Ellipse(const bool ellipse) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,const double scale);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_FIBOARC); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectFiboArc::CChartObjectFiboArc(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectFiboArc::~CChartObjectFiboArc(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Fibonacci Arcs" |
//+------------------------------------------------------------------+
bool CChartObjectFiboArc::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,const double scale)
{
if(!ObjectCreate(chart_id,name,OBJ_FIBOARC,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
if(!Scale(scale))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "Scale" property |
//+------------------------------------------------------------------+
double CChartObjectFiboArc::Scale(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
}
//+------------------------------------------------------------------+
//| Set value for the "Scale" property |
//+------------------------------------------------------------------+
bool CChartObjectFiboArc::Scale(const double scale) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,scale));
}
//+------------------------------------------------------------------+
//| Get value of the "Ellipse" property |
//+------------------------------------------------------------------+
bool CChartObjectFiboArc::Ellipse(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE));
}
//+------------------------------------------------------------------+
//| Set value for the "Ellipse" property |
//+------------------------------------------------------------------+
bool CChartObjectFiboArc::Ellipse(const bool ellipse) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE,ellipse));
}
//+------------------------------------------------------------------+
//| Writing parameter of object to file |
//+------------------------------------------------------------------+
bool CChartObjectFiboArc::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "Scale" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
return(false);
//--- write value of the "Ellipse" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectFiboArc::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "Scale" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
return(false);
//--- read value of the "Ellipse" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectFiboChannel. |
//| Purpose: Class of the "Fibonacci Channel" object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectFiboChannel : public CChartObjectTrend
{
public:
CChartObjectFiboChannel(void);
~CChartObjectFiboChannel(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_FIBOCHANNEL); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectFiboChannel::CChartObjectFiboChannel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectFiboChannel::~CChartObjectFiboChannel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Fibonacci Channel" |
//+------------------------------------------------------------------+
bool CChartObjectFiboChannel::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_FIBOCHANNEL,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectFiboExpansion. |
//| Purpose: Class of the "Fibonacci Expansion" object. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectFiboExpansion : public CChartObjectTrend
{
public:
CChartObjectFiboExpansion(void);
~CChartObjectFiboExpansion(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_EXPANSION); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectFiboExpansion::CChartObjectFiboExpansion(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectFiboExpansion::~CChartObjectFiboExpansion(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Fibonacci Expansion" |
//+------------------------------------------------------------------+
bool CChartObjectFiboExpansion::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_EXPANSION,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
+390
View File
@@ -0,0 +1,390 @@
//+------------------------------------------------------------------+
//| ChartObjectsGann.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All Gann tools. |
//+------------------------------------------------------------------+
#include "ChartObjectsLines.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectGannLine. |
//| Purpose: Class of the "Gann Line" object of chart. |
//| Derives from class CChartObjectTrendByAngle. |
//+------------------------------------------------------------------+
class CChartObjectGannLine : public CChartObjectTrendByAngle
{
public:
CChartObjectGannLine(void);
~CChartObjectGannLine(void);
//--- methods of access to properties of the object
double PipsPerBar(void) const;
bool PipsPerBar(const double ppb) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double ppb);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_GANNLINE); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectGannLine::CChartObjectGannLine(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectGannLine::~CChartObjectGannLine(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Gann Line" |
//+------------------------------------------------------------------+
bool CChartObjectGannLine::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double ppb)
{
if(!ObjectCreate(chart_id,name,OBJ_GANNLINE,window,time1,price1,time2,0.0))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
if(!PipsPerBar(ppb))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "PipsPerBar" property |
//+------------------------------------------------------------------+
double CChartObjectGannLine::PipsPerBar(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
}
//+------------------------------------------------------------------+
//| Set value for the "PipsPerBar" property |
//+------------------------------------------------------------------+
bool CChartObjectGannLine::PipsPerBar(const double ppb) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,ppb));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectGannLine::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectTrend::Save(file_handle))
return(false);
//--- write value of the "PipsPerBar"
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectGannLine::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectTrend::Load(file_handle))
return(false);
//--- read value of the "PipsPerBar" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectGannFan. |
//| Purpose: Class of the "Gann Fan" object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectGannFan : public CChartObjectTrend
{
public:
CChartObjectGannFan(void);
~CChartObjectGannFan(void);
//--- methods of access to properties of the object
double PipsPerBar(void) const;
bool PipsPerBar(const double ppb) const;
bool Downtrend(void) const;
bool Downtrend(const bool downtrend) const;
//--- method of create the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double ppb);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_GANNFAN); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectGannFan::CChartObjectGannFan(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectGannFan::~CChartObjectGannFan(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Gann Fan" |
//+------------------------------------------------------------------+
bool CChartObjectGannFan::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double ppb)
{
if(!ObjectCreate(chart_id,name,OBJ_GANNFAN,window,time1,price1,time2,0.0))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
if(!PipsPerBar(ppb))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "PipsPerBar" property |
//+------------------------------------------------------------------+
double CChartObjectGannFan::PipsPerBar(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
}
//+------------------------------------------------------------------+
//| Set value for the "PipsPerBar" property |
//+------------------------------------------------------------------+
bool CChartObjectGannFan::PipsPerBar(const double ppb) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,ppb));
}
//+------------------------------------------------------------------+
//| Get value of the "Downtrend" property |
//+------------------------------------------------------------------+
bool CChartObjectGannFan::Downtrend(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION));
}
//+------------------------------------------------------------------+
//| Set value for the "Downtrend" property |
//+------------------------------------------------------------------+
bool CChartObjectGannFan::Downtrend(const bool downtrend) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,downtrend));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectGannFan::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectTrend::Save(file_handle))
return(false);
//--- write value of the "PipsPerBar" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
return(false);
//--- write value of the "Downtrend" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION),CHAR_VALUE)!=sizeof(char))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading object parameters from file |
//+------------------------------------------------------------------+
bool CChartObjectGannFan::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectTrend::Load(file_handle))
return(false);
//--- read value of the "PipsPerBar" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
return(false);
//--- read value of the "Downtrend" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectGannGrid. |
//| Purpose: Class of the "Gann Grid" object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectGannGrid : public CChartObjectTrend
{
public:
CChartObjectGannGrid(void);
~CChartObjectGannGrid(void);
//--- methods of access to properties of the object
double PipsPerBar(void) const;
bool PipsPerBar(const double ppb) const;
bool Downtrend(void) const;
bool Downtrend(const bool downtrend) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double ppb);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_GANNGRID); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectGannGrid::CChartObjectGannGrid(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectGannGrid::~CChartObjectGannGrid(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Gann Grid" |
//+------------------------------------------------------------------+
bool CChartObjectGannGrid::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double ppb)
{
if(!ObjectCreate(chart_id,name,OBJ_GANNGRID,window,time1,price1,time2,0.0))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
if(!PipsPerBar(ppb))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the"PipsPerBar" property |
//+------------------------------------------------------------------+
double CChartObjectGannGrid::PipsPerBar(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
}
//+------------------------------------------------------------------+
//| Set value for the "PipsPerBar" property |
//+------------------------------------------------------------------+
bool CChartObjectGannGrid::PipsPerBar(const double ppb) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,ppb));
}
//+------------------------------------------------------------------+
//| Get the property value "Downtrend" |
//+------------------------------------------------------------------+
bool CChartObjectGannGrid::Downtrend(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION));
}
//+------------------------------------------------------------------+
//| Set the property value "Downtrend" |
//+------------------------------------------------------------------+
bool CChartObjectGannGrid::Downtrend(const bool downtrend) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,downtrend));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectGannGrid::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectTrend::Save(file_handle))
return(false);
//--- write value of the "PipsPerBar" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
return(false);
//--- write value of the "Downtrend" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION),CHAR_VALUE)!=sizeof(char))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading paprameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectGannGrid::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectTrend::Load(file_handle))
return(false);
//--- read value of the "PipsPerBar" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
return(false);
//--- read value of the "Downtrend" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
+335
View File
@@ -0,0 +1,335 @@
//+------------------------------------------------------------------+
//| ChartObjectsLines.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All lines. |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectVLine. |
//| Purpose: Class of the "Vertical line" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectVLine : public CChartObject
{
public:
CChartObjectVLine(void);
~CChartObjectVLine(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_VLINE); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectVLine::CChartObjectVLine(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectVLine::~CChartObjectVLine(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Vertical line" |
//+------------------------------------------------------------------+
bool CChartObjectVLine::Create(long chart_id,const string name,const int window,const datetime time)
{
if(!ObjectCreate(chart_id,name,OBJ_VLINE,window,time,0.0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectHLine. |
//| Purpose: Class of the "Horizontal line" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectHLine : public CChartObject
{
public:
CChartObjectHLine(void);
~CChartObjectHLine(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const double price);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_HLINE); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectHLine::CChartObjectHLine(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectHLine::~CChartObjectHLine(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Horizontal line" |
//+------------------------------------------------------------------+
bool CChartObjectHLine::Create(long chart_id,const string name,const int window,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_HLINE,window,0,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectTrend. |
//| Purpose: Class of the "Trendline" object of chart. |
//| Derives from class CChartObject. |
//| It is the parent class for all objects that have properties |
//| RAY_LEFT and RAY_RIGHT. |
//+------------------------------------------------------------------+
class CChartObjectTrend : public CChartObject
{
public:
CChartObjectTrend(void);
~CChartObjectTrend(void);
//--- methods of access to properties of the object
bool RayLeft(void) const;
bool RayLeft(const bool new_sel) const;
bool RayRight(void) const;
bool RayRight(const bool new_sel) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_TREND); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectTrend::CChartObjectTrend(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectTrend::~CChartObjectTrend(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Trendline" |
//+------------------------------------------------------------------+
bool CChartObjectTrend::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the "Ray left" flag |
//+------------------------------------------------------------------+
bool CChartObjectTrend::RayLeft(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT));
}
//+------------------------------------------------------------------+
//| Set the "Ray left" flag |
//+------------------------------------------------------------------+
bool CChartObjectTrend::RayLeft(const bool new_ray) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,new_ray));
}
//+------------------------------------------------------------------+
//| Get the "Ray right" flag |
//+------------------------------------------------------------------+
bool CChartObjectTrend::RayRight(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT));
}
//+------------------------------------------------------------------+
//| Set the "Ray right" flag |
//+------------------------------------------------------------------+
bool CChartObjectTrend::RayRight(const bool new_ray) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT,new_ray));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectTrend::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "Ray left" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "Ray right" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT),CHAR_VALUE)!=sizeof(char))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectTrend::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "Ray left" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "Ray right" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectTrendByAngle. |
//| Puprose: Class of the "Trendline by angle" object of chart. |
//| Derives from class CChartObjectTrend. |
//+------------------------------------------------------------------+
class CChartObjectTrendByAngle : public CChartObjectTrend
{
public:
CChartObjectTrendByAngle(void);
~CChartObjectTrendByAngle(void);
//--- methods of access to properties of the object
double Angle(void) const;
bool Angle(const double angle) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_TRENDBYANGLE); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectTrendByAngle::CChartObjectTrendByAngle(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectTrendByAngle::~CChartObjectTrendByAngle(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Trendline by angle" |
//+------------------------------------------------------------------+
bool CChartObjectTrendByAngle::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_TRENDBYANGLE,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the "Angle" property |
//+------------------------------------------------------------------+
double CChartObjectTrendByAngle::Angle(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//---
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE));
}
//+------------------------------------------------------------------+
//| Set the "Angle" property |
//+------------------------------------------------------------------+
bool CChartObjectTrendByAngle::Angle(const double angle) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,angle));
}
//+------------------------------------------------------------------+
//| Class CChartObjectCycles. |
//| Purpose: Class of the "Cycle lines" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectCycles : public CChartObject
{
public:
CChartObjectCycles(void);
~CChartObjectCycles(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_CYCLES); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectCycles::CChartObjectCycles(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectCycles::~CChartObjectCycles(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Cycle lines" |
//+------------------------------------------------------------------+
bool CChartObjectCycles::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_CYCLES,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
+142
View File
@@ -0,0 +1,142 @@
//+------------------------------------------------------------------+
//| ChartObjectsShapes.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All shapes. |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectRectangle. |
//| Purpose: Class of the "Rectangle" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectRectangle : public CChartObject
{
public:
CChartObjectRectangle(void);
~CChartObjectRectangle(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_RECTANGLE); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectRectangle::CChartObjectRectangle(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectRectangle::~CChartObjectRectangle(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Rectangle" |
//+------------------------------------------------------------------+
bool CChartObjectRectangle::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2)
{
if(!ObjectCreate(chart_id,name,OBJ_RECTANGLE,window,time1,price1,time2,price2))
return(false);
if(!Attach(chart_id,name,window,2))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectTriangle. |
//| Purpose: Class of the "Triangle" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectTriangle : public CChartObject
{
public:
CChartObjectTriangle(void);
~CChartObjectTriangle(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_TRIANGLE); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectTriangle::CChartObjectTriangle(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectTriangle::~CChartObjectTriangle(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Triangle" |
//+------------------------------------------------------------------+
bool CChartObjectTriangle::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_TRIANGLE,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectEllipse. |
//| Purpose: Class of the "Ellipse" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectEllipse : public CChartObject
{
public:
CChartObjectEllipse(void);
~CChartObjectEllipse(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_ELLIPSE); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectEllipse::CChartObjectEllipse(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectEllipse::~CChartObjectEllipse(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Ellipse" |
//+------------------------------------------------------------------+
bool CChartObjectEllipse::Create(long chart_id,const string name,const int window,
const datetime time1,const double price1,
const datetime time2,const double price2,
const datetime time3,const double price3)
{
if(!ObjectCreate(chart_id,name,OBJ_ELLIPSE,window,time1,price1,time2,price2,time3,price3))
return(false);
if(!Attach(chart_id,name,window,3))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,895 @@
//+------------------------------------------------------------------+
//| ChartObjectsTxtControls.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//| All text objects. |
//+------------------------------------------------------------------+
#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectText. |
//| Purpose: Class of the "Text" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectText : public CChartObject
{
public:
CChartObjectText(void);
~CChartObjectText(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_TEXT); }
//--- methods of access to properties of the object
double Angle(void) const;
bool Angle(const double angle) const;
string Font(void) const;
bool Font(const string font) const;
int FontSize(void) const;
bool FontSize(const int size) const;
ENUM_ANCHOR_POINT Anchor(void) const;
bool Anchor(const ENUM_ANCHOR_POINT anchor) const;
//--- methods for working with files
virtual bool Save(const int file_handle) override;
virtual bool Load(const int file_handle) override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectText::CChartObjectText(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectText::~CChartObjectText(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Text" |
//+------------------------------------------------------------------+
bool CChartObjectText::Create(long chart_id,const string name,const int window,
const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_TEXT,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "Angle" property |
//+------------------------------------------------------------------+
double CChartObjectText::Angle(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE));
}
//+------------------------------------------------------------------+
//| Set value of the "Angle" property |
//+------------------------------------------------------------------+
bool CChartObjectText::Angle(const double angle) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,angle));
}
//+------------------------------------------------------------------+
//| Get font name |
//+------------------------------------------------------------------+
string CChartObjectText::Font(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_FONT));
}
//+------------------------------------------------------------------+
//| Set font name |
//+------------------------------------------------------------------+
bool CChartObjectText::Font(const string font) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_FONT,font));
}
//+------------------------------------------------------------------+
//| Get font size |
//+------------------------------------------------------------------+
int CChartObjectText::FontSize(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE));
}
//+------------------------------------------------------------------+
//| Set font size |
//+------------------------------------------------------------------+
bool CChartObjectText::FontSize(const int size) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE,size));
}
//+------------------------------------------------------------------+
//| Get anchor point |
//+------------------------------------------------------------------+
ENUM_ANCHOR_POINT CChartObjectText::Anchor(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_ANCHOR_POINT)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR));
}
//+------------------------------------------------------------------+
//| Set anchor point |
//+------------------------------------------------------------------+
bool CChartObjectText::Anchor(const ENUM_ANCHOR_POINT anchor) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,anchor));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectText::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "Angle" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE))!=sizeof(double))
return(false);
//--- write value of the "Font Name" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_FONT);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write value of the "Font Size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Anchor Point" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectText::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- reading value of the "Angle" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,0,FileReadDouble(file_handle)))
return(false);
//--- read value of the "Font Name" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_FONT,str))
return(false);
//--- read value of the "Font Size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Anchor Point" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectLabel. |
//| Purpose: Class of the "Label" object of chart. |
//| Derives from class CChartObjectText. |
//+------------------------------------------------------------------+
class CChartObjectLabel : public CChartObjectText
{
public:
CChartObjectLabel(void);
~CChartObjectLabel(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_LABEL); }
//--- methods of access to properties of the object
int X_Distance(void) const;
bool X_Distance(const int X) const;
int Y_Distance(void) const;
bool Y_Distance(const int Y) const;
int X_Size(void) const;
int Y_Size(void) const;
ENUM_BASE_CORNER Corner(void) const;
bool Corner(const ENUM_BASE_CORNER corner) const;
//--- change of time/price coordinates is blocked
datetime Time(const int point) const { return(CChartObjectText::Time(point)); }
bool Time(const int point,const datetime time) const { return(false); }
double Price(const int point) const { return(CChartObjectText::Price(point)); }
bool Price(const int point,const double price) const { return(false); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectLabel::CChartObjectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectLabel::~CChartObjectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Label" |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Create(long chart_id,const string name,const int window,const int X,const int Y)
{
if(!ObjectCreate(chart_id,name,OBJ_LABEL,window,0,0.0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!Description(name))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the X-distance |
//+------------------------------------------------------------------+
int CChartObjectLabel::X_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the X-distance |
//+------------------------------------------------------------------+
bool CChartObjectLabel::X_Distance(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
}
//+------------------------------------------------------------------+
//| Get the Y-distance |
//+------------------------------------------------------------------+
int CChartObjectLabel::Y_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the Y-distance |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Y_Distance(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
}
//+------------------------------------------------------------------+
//| Get the X-size |
//+------------------------------------------------------------------+
int CChartObjectLabel::X_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
}
//+------------------------------------------------------------------+
//| Get the Y-size |
//+------------------------------------------------------------------+
int CChartObjectLabel::Y_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
}
//+------------------------------------------------------------------+
//| Get base corner |
//+------------------------------------------------------------------+
ENUM_BASE_CORNER CChartObjectLabel::Corner(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
}
//+------------------------------------------------------------------+
//| Set base corner |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Corner(const ENUM_BASE_CORNER corner) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectText::Save(file_handle))
return(false);
//--- write value of the "X-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Corner" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectText::Load(file_handle))
return(false);
//--- reading value of the "X-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Corner" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectEdit. |
//| Purpose: Class of the "Edit" object of chart. |
//| Derives from class CChartObjectLabel. |
//+------------------------------------------------------------------+
class CChartObjectEdit : public CChartObjectLabel
{
public:
CChartObjectEdit(void);
~CChartObjectEdit(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_EDIT); }
//--- methods of access to properties of the object
bool X_Size(const int X) const;
int X_Size(void) const { return(CChartObjectLabel::X_Size()); }
bool Y_Size(const int Y) const;
int Y_Size(void) const { return(CChartObjectLabel::Y_Size()); }
color BackColor(void) const;
bool BackColor(const color new_color) const;
color BorderColor(void) const;
bool BorderColor(const color new_color) const;
bool ReadOnly(void) const;
bool ReadOnly(const bool flag) const;
ENUM_ALIGN_MODE TextAlign(void) const;
bool TextAlign(const ENUM_ALIGN_MODE align) const;
//--- change of angle is blocked
bool Angle(const double angle) const { return(false); }
double Angle(void) const { return(CChartObjectLabel::Angle()); }
//--- methods for working with files
virtual bool Save(const int file_handle) override;
virtual bool Load(const int file_handle) override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectEdit::CChartObjectEdit(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectEdit::~CChartObjectEdit(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Edit" |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY)
{
if(!ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
if(!X_Size(sizeX) || !Y_Size(sizeY))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Set X-size |
//+------------------------------------------------------------------+
bool CChartObjectEdit::X_Size(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,X));
}
//+------------------------------------------------------------------+
//| Set Y-size |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Y_Size(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,Y));
}
//+------------------------------------------------------------------+
//| Get background color |
//+------------------------------------------------------------------+
color CChartObjectEdit::BackColor(void) const
{
//--- check
if(m_chart_id==-1)
return(clrNONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR));
}
//+------------------------------------------------------------------+
//| Set background color |
//+------------------------------------------------------------------+
bool CChartObjectEdit::BackColor(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get border color |
//+------------------------------------------------------------------+
color CChartObjectEdit::BorderColor(void) const
{
//--- check
if(m_chart_id==-1)
return(clrNONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_COLOR));
}
//+------------------------------------------------------------------+
//| Set border color |
//+------------------------------------------------------------------+
bool CChartObjectEdit::BorderColor(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_COLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get the "Read only" property |
//+------------------------------------------------------------------+
bool CChartObjectEdit::ReadOnly(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_READONLY));
}
//+------------------------------------------------------------------+
//| Set the "Read only" property |
//+------------------------------------------------------------------+
bool CChartObjectEdit::ReadOnly(const bool flag) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_READONLY,flag));
}
//+------------------------------------------------------------------+
//| Get the "Align" property |
//+------------------------------------------------------------------+
ENUM_ALIGN_MODE CChartObjectEdit::TextAlign(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((ENUM_ALIGN_MODE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ALIGN));
}
//+------------------------------------------------------------------+
//| Set the "Align" property |
//+------------------------------------------------------------------+
bool CChartObjectEdit::TextAlign(const ENUM_ALIGN_MODE align) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ALIGN,align));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectLabel::Save(file_handle))
return(false);
//--- write value of the "X-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write background color
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR))!=sizeof(long))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectLabel::Load(file_handle))
return(false);
//--- read value of the "X-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read background color
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,FileReadLong(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectButton. |
//| Purpose: Class of the "Button" object of chart. |
//| Derives from class CChartObjectEdit. |
//+------------------------------------------------------------------+
class CChartObjectButton : public CChartObjectEdit
{
public:
CChartObjectButton(void);
~CChartObjectButton(void);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_BUTTON); }
//--- methods of access to properties of the object
bool State(void) const;
bool State(const bool state) const;
//--- methods for working with files
virtual bool Save(const int file_handle) override;
virtual bool Load(const int file_handle) override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectButton::CChartObjectButton(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectButton::~CChartObjectButton(void)
{
}
//+------------------------------------------------------------------+
//| Get state |
//+------------------------------------------------------------------+
bool CChartObjectButton::State(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE));
}
//+------------------------------------------------------------------+
//| Set state |
//+------------------------------------------------------------------+
bool CChartObjectButton::State(const bool state) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,state));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectButton::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectEdit::Save(file_handle))
return(false);
//--- write state
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE))!=sizeof(long))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectButton::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectEdit::Load(file_handle))
return(false);
//--- read state
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,FileReadLong(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectRectLabel. |
//| Purpose: Class of the "Rectangle Label" object of chart. |
//| Derives from class CChartObjectLabel. |
//+------------------------------------------------------------------+
class CChartObjectRectLabel : public CChartObjectLabel
{
public:
CChartObjectRectLabel(void);
~CChartObjectRectLabel(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_RECTANGLE_LABEL); }
//--- methods of access to properties of the object
bool X_Size(const int X) const;
int X_Size(void)const { return(CChartObjectLabel::X_Size()); }
bool Y_Size(const int Y) const;
int Y_Size(void)const { return(CChartObjectLabel::Y_Size()); }
color BackColor(void) const;
bool BackColor(const color new_color) const;
ENUM_BORDER_TYPE BorderType(void) const;
bool BorderType(const ENUM_BORDER_TYPE flag) const;
//--- change of angle is blocked
bool Angle(const double angle) const { return(false); }
double Angle(void) const { return(CChartObjectLabel::Angle()); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectRectLabel::CChartObjectRectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectRectLabel::~CChartObjectRectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Ractangle Label" |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY)
{
if(!ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
if(!X_Size(sizeX) || !Y_Size(sizeY))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Set X-size |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::X_Size(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,X));
}
//+------------------------------------------------------------------+
//| Set Y-size |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Y_Size(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,Y));
}
//+------------------------------------------------------------------+
//| Get background color |
//+------------------------------------------------------------------+
color CChartObjectRectLabel::BackColor(void) const
{
//--- check
if(m_chart_id==-1)
return(clrNONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR));
}
//+------------------------------------------------------------------+
//| Set background color |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::BackColor(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get the "Border type" property |
//+------------------------------------------------------------------+
ENUM_BORDER_TYPE CChartObjectRectLabel::BorderType(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((ENUM_BORDER_TYPE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE));
}
//+------------------------------------------------------------------+
//| Set the "Border type" property |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::BorderType(const ENUM_BORDER_TYPE type) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE,type));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectLabel::Save(file_handle))
return(false);
//--- write value of the "X-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write background color
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR))!=sizeof(long))
return(false);
//--- write value of the "Border type" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectLabel::Load(file_handle))
return(false);
//--- read value of the "X-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read background color
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,FileReadLong(file_handle)))
return(false);
//--- read value of the "Border type" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
File diff suppressed because it is too large Load Diff
+268
View File
@@ -0,0 +1,268 @@
//+------------------------------------------------------------------+
//| BmpButton.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsBmpControls.mqh>
//+------------------------------------------------------------------+
//| Class CBmpButton |
//| Usage: control that is displayed by |
//| the CChartObjectBmpLabel object |
//+------------------------------------------------------------------+
class CBmpButton : public CWndObj
{
private:
CChartObjectBmpLabel m_button; // chart object
//--- parameters of the chart object
int m_border; // border width
string m_bmp_off_name; // name of BMP file for the "OFF" state (default state)
string m_bmp_on_name; // name of BMP file for the "ON" state
string m_bmp_passive_name;
string m_bmp_active_name;
public:
CBmpButton(void);
~CBmpButton(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- parameters of the chart object
int Border(void) const { return(m_border); }
bool Border(const int value);
bool BmpNames(const string off="",const string on="");
string BmpOffName(void) const { return(m_bmp_off_name); }
bool BmpOffName(const string name);
string BmpOnName(void) const { return(m_bmp_on_name); }
bool BmpOnName(const string name);
string BmpPassiveName(void) const { return(m_bmp_passive_name); }
bool BmpPassiveName(const string name);
string BmpActiveName(void) const { return(m_bmp_active_name); }
bool BmpActiveName(const string name);
//--- state
bool Pressed(void) const { return(m_button.State()); }
bool Pressed(const bool pressed) { return(m_button.State(pressed)); }
//--- properties
bool Locking(void) const { return(IS_CAN_LOCK); }
void Locking(const bool locking);
protected:
//--- handlers of object settings
virtual bool OnSetZOrder(void) { return(m_button.Z_Order(m_zorder)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnChange(void);
//--- íîâûå îáðàáîò÷èêè
virtual bool OnActivate(void);
virtual bool OnDeactivate(void);
virtual bool OnMouseDown(void);
virtual bool OnMouseUp(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CBmpButton::CBmpButton(void) : m_border(0),
m_bmp_off_name(NULL),
m_bmp_on_name(NULL),
m_bmp_passive_name(NULL),
m_bmp_active_name(NULL)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CBmpButton::~CBmpButton(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CBmpButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_button.Create(chart,name,subwin,x1,y1))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set border width |
//+------------------------------------------------------------------+
bool CBmpButton::Border(const int value)
{
//--- save new value of parameter
m_border=value;
//--- set up the chart object
return(m_button.Width(value));
}
//+------------------------------------------------------------------+
//| Set two images at once |
//+------------------------------------------------------------------+
bool CBmpButton::BmpNames(const string off,const string on)
{
//--- save new values of parameters
m_bmp_off_name=off;
m_bmp_on_name =on;
//--- set up the chart object
if(!m_button.BmpFileOff(off))
return(false);
if(!m_button.BmpFileOn(on))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "OFF" state |
//+------------------------------------------------------------------+
bool CBmpButton::BmpOffName(const string name)
{
//--- save new value of parameter
m_bmp_off_name=name;
//--- set up the chart object
if(!m_button.BmpFileOff(name))
return(false);
//--- set size by image dimensions
Width(m_button.X_Size());
Height(m_button.Y_Size());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "ON" state |
//+------------------------------------------------------------------+
bool CBmpButton::BmpOnName(const string name)
{
//--- save new value of parameter
m_bmp_on_name=name;
//--- set up the chart object
if(!m_button.BmpFileOn(name))
return(false);
//--- set size by image dimensions
Width(m_button.X_Size());
Height(m_button.Y_Size());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "OFF" state (passive) |
//+------------------------------------------------------------------+
bool CBmpButton::BmpPassiveName(const string name)
{
//--- save new value of parameter
m_bmp_passive_name=name;
//--- set up the chart object
if(!IS_ACTIVE)
return(BmpOffName(name));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "OFF" state (active) |
//+------------------------------------------------------------------+
bool CBmpButton::BmpActiveName(const string name)
{
//--- save new value of parameter
m_bmp_active_name=name;
//--- set up the chart object
if(IS_ACTIVE)
return(BmpOffName(name));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Locking flag |
//+------------------------------------------------------------------+
void CBmpButton::Locking(const bool flag)
{
if(flag)
PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
else
PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CBmpButton::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CBmpButton::OnShow(void)
{
return(m_button.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CBmpButton::OnHide(void)
{
return(m_button.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CBmpButton::OnMove(void)
{
//--- position the chart object
return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CBmpButton::OnChange(void)
{
//--- set up the chart object
return(m_button.Width(m_border) && m_button.BmpFileOff(m_bmp_off_name) && m_button.BmpFileOn(m_bmp_on_name));
}
//+------------------------------------------------------------------+
//| Handler of activating the group of controls |
//+------------------------------------------------------------------+
bool CBmpButton::OnActivate(void)
{
if(m_bmp_active_name!=NULL)
BmpOffName(m_bmp_active_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of deactivating the group of controls |
//+------------------------------------------------------------------+
bool CBmpButton::OnDeactivate(void)
{
if(m_bmp_passive_name!=NULL)
BmpOffName(m_bmp_passive_name);
if(!IS_CAN_LOCK)
Pressed(false);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CBmpButton::OnMouseDown(void)
{
if(!IS_CAN_LOCK)
Pressed(!Pressed());
//--- call of the method of the parent class
return(CWnd::OnMouseDown());
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CBmpButton::OnMouseUp(void)
{
//--- depress the button if it is not fixed
if(m_button.State() && !IS_CAN_LOCK)
m_button.State(false);
//--- call of the method of the parent class
return(CWnd::OnMouseUp());
}
//+------------------------------------------------------------------+
+146
View File
@@ -0,0 +1,146 @@
//+------------------------------------------------------------------+
//| Button.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CButton |
//| Usage: control that is displayed by |
//| the CChartObjectButton object |
//+------------------------------------------------------------------+
class CButton : public CWndObj
{
private:
CChartObjectButton m_button; // chart object
public:
CButton(void);
~CButton(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- state
bool Pressed(void) const { return(m_button.State()); }
bool Pressed(const bool pressed) { return(m_button.State(pressed)); }
//--- properties
bool Locking(void) const { return(IS_CAN_LOCK); }
void Locking(const bool flag);
protected:
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_button.Description(m_text)); }
virtual bool OnSetColor(void) { return(m_button.Color(m_color)); }
virtual bool OnSetColorBackground(void) { return(m_button.BackColor(m_color_background)); }
virtual bool OnSetColorBorder(void) { return(m_button.BorderColor(m_color_border)); }
virtual bool OnSetFont(void) { return(m_button.Font(m_font)); }
virtual bool OnSetFontSize(void) { return(m_button.FontSize(m_font_size)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnResize(void);
//--- íîâûå îáðàáîò÷èêè
virtual bool OnMouseDown(void);
virtual bool OnMouseUp(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CButton::CButton(void)
{
m_color =CONTROLS_BUTTON_COLOR;
m_color_background=CONTROLS_BUTTON_COLOR_BG;
m_color_border =CONTROLS_BUTTON_COLOR_BORDER;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CButton::~CButton(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height()))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Locking flag |
//+------------------------------------------------------------------+
void CButton::Locking(const bool flag)
{
if(flag)
PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
else
PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CButton::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CButton::OnShow(void)
{
return(m_button.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CButton::OnHide(void)
{
return(m_button.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CButton::OnMove(void)
{
//--- position the chart object
return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CButton::OnResize(void)
{
//--- resize the chart object
return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CButton::OnMouseDown(void)
{
if(!IS_CAN_LOCK)
Pressed(!Pressed());
//--- call of the method of the parent class
return(CWnd::OnMouseDown());
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CButton::OnMouseUp(void)
{
//--- depress the button if it is not fixed
if(m_button.State() && !IS_CAN_LOCK)
m_button.State(false);
//--- call of the method of the parent class
return(CWnd::OnMouseUp());
}
//+------------------------------------------------------------------+
+183
View File
@@ -0,0 +1,183 @@
//+------------------------------------------------------------------+
//| CheckBox.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "BmpButton.mqh"
#include "Edit.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "res\\CheckBoxOn.bmp"
#resource "res\\CheckBoxOff.bmp"
//+------------------------------------------------------------------+
//| Class CCheckBox |
//| Usage: class that implements the "CheckBox" control |
//+------------------------------------------------------------------+
class CCheckBox : public CWndContainer
{
private:
//--- dependent controls
CBmpButton m_button; // button object
CEdit m_label; // label object
//--- data
int m_value; // value
public:
CCheckBox(void);
~CCheckBox(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- settings
string Text(void) const { return(m_label.Text()); }
bool Text(const string value) { return(m_label.Text(value)); }
color Color(void) const { return(m_label.Color()); }
bool Color(const color value) { return(m_label.Color(value)); }
//--- state
bool Checked(void) const { return(m_button.Pressed()); }
bool Checked(const bool flag) { return(m_button.Pressed(flag)); }
//--- data
int Value(void) const { return(m_value); }
void Value(const int value) { m_value=value; }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateButton(void);
virtual bool CreateLabel(void);
//--- handlers of the dependent controls events
virtual bool OnClickButton(void);
virtual bool OnClickLabel(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CCheckBox)
ON_EVENT(ON_CLICK,m_button,OnClickButton)
ON_EVENT(ON_CLICK,m_label,OnClickLabel)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CCheckBox::CCheckBox(void) : m_value(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CCheckBox::~CCheckBox(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CCheckBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateButton())
return(false);
if(!CreateLabel())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CCheckBox::CreateButton(void)
{
//--- calculate coordinates
int x1=CONTROLS_CHECK_BUTTON_X_OFF;
int y1=CONTROLS_CHECK_BUTTON_Y_OFF;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH;
//--- create
if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button.BmpNames("::res\\CheckBoxOff.bmp","::res\\CheckBoxOn.bmp"))
return(false);
if(!Add(m_button))
return(false);
m_button.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create label |
//+------------------------------------------------------------------+
bool CCheckBox::CreateLabel(void)
{
//--- calculate coordinates
int x1=CONTROLS_CHECK_LABEL_X_OFF;
int y1=CONTROLS_CHECK_LABEL_Y_OFF;
int x2=Width();
int y2=Height();
//--- create
if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_label.Text(m_name))
return(false);
if(!Add(m_label))
return(false);
m_label.ReadOnly(true);
m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG);
m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckBox::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteInteger(file_handle,Checked());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckBox::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Checked(FileReadInteger(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CCheckBox::OnClickButton(void)
{
//--- send the "changed state" event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on label |
//+------------------------------------------------------------------+
bool CCheckBox::OnClickLabel(void)
{
//--- change button state
m_button.Pressed(!m_button.Pressed());
//--- return the result of the button click handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
+377
View File
@@ -0,0 +1,377 @@
//+------------------------------------------------------------------+
//| CheckGroup.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndClient.mqh"
#include "CheckBox.mqh"
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayLong.mqh>
#include <Arrays\ArrayInt.mqh>
//+------------------------------------------------------------------+
//| Class CCheckGroup |
//| Usage: view and edit group of flags |
//+------------------------------------------------------------------+
class CCheckGroup : public CWndClient
{
private:
//--- dependent controls
CCheckBox m_rows[]; // array of the row objects
//--- set up
int m_offset; // index of first visible row in array of rows
int m_total_view; // number of visible rows
int m_item_height; // height of visible row
//--- data
CArrayString m_strings; // array of rows
CArrayLong m_values; // array of values
CArrayInt m_states; // array of states
long m_value; // current value
int m_current; // index of current row in array of rows
public:
CCheckGroup(void);
~CCheckGroup(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- fill
virtual bool AddItem(const string item,const long value=0);
//--- data
long Value(void) const;
bool Value(const long value);
int Check(const int idx) const;
bool Check(const int idx,const int value);
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
bool CreateButton(int index);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void);
virtual bool OnVScrollHide(void);
virtual bool OnScrollLineDown(void);
virtual bool OnScrollLineUp(void);
virtual bool OnChangeItem(const int row_index);
//--- redraw
bool Redraw(void);
bool RowState(const int index,const bool select);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CCheckGroup)
ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CCheckGroup::CCheckGroup(void) : m_offset(0),
m_total_view(0),
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
m_current(CONTROLS_INVALID_INDEX),
m_value(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CCheckGroup::~CCheckGroup(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CCheckGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- determine the number of visible rows
m_total_view=(y2-y1)/m_item_height;
//--- check the number of visible rows
if(m_total_view<1)
return(false);
//--- call method of the parent class
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- set up
if(!m_background.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG))
return(false);
if(!m_background.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BORDER))
return(false);
//--- create dependent controls
ArrayResize(m_rows,m_total_view);
for(int i=0;i<m_total_view;i++)
if(!CreateButton(i))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CCheckGroup::Destroy(const int reason)
{
//--- call of the method of the parent class
CWndClient::Destroy(reason);
//--- clear items
m_strings.Clear();
m_values.Clear();
m_states.Clear();
}
//+------------------------------------------------------------------+
//| Create "row" |
//+------------------------------------------------------------------+
bool CCheckGroup::CreateButton(int index)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=y1+m_item_height;
//--- create
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
return(false);
if(!m_rows[index].Text(""))
return(false);
if(!Add(m_rows[index]))
return(false);
m_rows[index].Hide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CCheckGroup::AddItem(const string item,const long value)
{
//--- add
if(!m_strings.Add(item))
return(false);
if(!m_values.Add(value))
return(false);
if(!m_states.Add(0))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(IS_VISIBLE && total!=0)
m_rows[total-1].Show();
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(!IS_VISIBLE)
m_scroll_v.Visible(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
long CCheckGroup::Value(void) const
{
return(m_value);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Value(const long value)
{
m_value=value;
//---
return(Redraw());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CCheckGroup::Check(const int idx) const
{
//--- check
if(idx>=m_values.Total())
return(0);
//---
return(m_states[idx]);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Check(const int idx,const int value)
{
//--- check
if(idx>=m_values.Total())
return(false);
//---
bool res=(m_states.Update(idx,value) && Redraw());
//--- change value
if(res && idx<64)
{
if(m_rows[idx].Checked())
Value(m_value|m_values.At(idx));
else
Value(m_value&(~m_values.At(idx)));
}
//---
return(res);
}
//+------------------------------------------------------------------+
//| Makes the group visible |
//+------------------------------------------------------------------+
bool CCheckGroup::Show(void)
{
//--- call of the method of the parent class
if(!CWndClient::Show())
return(false);
//--- loop by rows
int total=m_values.Total();
for(int i=total;i<m_total_view;i++)
m_rows[i].Hide();
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Value(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Redraw |
//+------------------------------------------------------------------+
bool CCheckGroup::Redraw(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- copy text
if(!m_rows[i].Text(m_strings[i+m_offset]))
return(false);
//--- select
if(!RowState(i,m_states[i+m_offset]!=0))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Change state |
//+------------------------------------------------------------------+
bool CCheckGroup::RowState(const int index,const bool select)
{
//--- check index
if(index<0 || index>=ArraySize(m_rows))
return(true);
//--- change state
return(m_rows[index].Checked(select));
}
//+------------------------------------------------------------------+
//| Handler of the "Show vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnVScrollShow(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to shown vertical scrollbar
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
}
//--- check visibility
if(!IS_VISIBLE)
{
m_scroll_v.Visible(false);
return(true);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnVScrollHide(void)
{
//--- check visibility
if(!IS_VISIBLE)
return(true);
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to hidden vertical scroll bar
m_rows[i].Width(Width()-CONTROLS_BORDER_WIDTH);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll up for one row" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnScrollLineUp(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll down for one row" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnScrollLineDown(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of changing a "row" state |
//+------------------------------------------------------------------+
bool CCheckGroup::OnChangeItem(const int row_index)
{
//--- change value
m_states.Update(row_index+m_offset,m_rows[row_index].Checked());
if(row_index+m_offset<64)
{
if(m_rows[row_index].Checked())
Value(m_value|m_values.At(row_index+m_offset));
else
Value(m_value&(~m_values.At(row_index+m_offset)));
}
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
+324
View File
@@ -0,0 +1,324 @@
//+------------------------------------------------------------------+
//| ComboBox.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "Edit.mqh"
#include "BmpButton.mqh"
#include "ListView.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
//--- Can not place the same file into resource twice
#resource "res\\DropOn.bmp" // image file
#resource "res\\DropOff.bmp" // image file
//+------------------------------------------------------------------+
//| Class CComboBox |
//| Usage: drop-down list |
//+------------------------------------------------------------------+
class CComboBox : public CWndContainer
{
private:
//--- dependent controls
CEdit m_edit; // the entry field object
CBmpButton m_drop; // the button object
CListView m_list; // the drop-down list object
//--- set up
int m_item_height; // height of visible row
int m_view_items; // number of visible rows in the drop-down list
public:
CComboBox(void);
~CComboBox(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- fill
bool AddItem(const string item,const long value=0);
//--- set up
void ListViewItems(const int value) { m_view_items=value; }
//--- data
virtual bool ItemAdd(const string item,const long value=0) { return(m_list.ItemAdd(item,value)); }
virtual bool ItemInsert(const int index,const string item,const long value=0) { return(m_list.ItemInsert(index,item,value)); }
virtual bool ItemUpdate(const int index,const string item,const long value=0) { return(m_list.ItemUpdate(index,item,value)); }
virtual bool ItemDelete(const int index) { return(m_list.ItemDelete(index)); }
virtual bool ItemsClear(void) { return(m_list.ItemsClear()); }
//--- data
string Select(void) { return(m_edit.Text()); }
bool Select(const int index);
bool SelectByText(const string text);
bool SelectByValue(const long value);
//--- data (read only)
long Value(void) { return(m_list.Value()); }
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateEdit(void);
virtual bool CreateButton(void);
virtual bool CreateList(void);
//--- handlers of the dependent controls events
virtual bool OnClickEdit(void);
virtual bool OnClickButton(void);
virtual bool OnChangeList(void);
//--- show drop-down list
bool ListShow(void);
bool ListHide(void);
void CheckListHide(const int id,int x,int y);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CComboBox)
ON_EVENT(ON_CLICK,m_edit,OnClickEdit)
ON_EVENT(ON_CLICK,m_drop,OnClickButton)
ON_EVENT(ON_CHANGE,m_list,OnChangeList)
CheckListHide(id,(int)lparam,(int)dparam);
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void) : m_item_height(CONTROLS_COMBO_ITEM_HEIGHT),
m_view_items(CONTROLS_COMBO_ITEMS_VIEW)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CComboBox::~CComboBox(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CComboBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- check height
if(y2-y1<CONTROLS_COMBO_MIN_HEIGHT)
return(false);
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateButton())
return(false);
if(!CreateList())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create main entry field |
//+------------------------------------------------------------------+
bool CComboBox::CreateEdit(void)
{
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_edit.Text(""))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CComboBox::CreateButton(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_COMBO_BUTTON_X_OFF);
int y1=(Height()-CONTROLS_BUTTON_SIZE)/2;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_drop.Create(m_chart_id,m_name+"Drop",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_drop.BmpNames("::res\\DropOff.bmp","::res\\DropOn.bmp"))
return(false);
if(!Add(m_drop))
return(false);
m_drop.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::CreateList(void)
{
//--- create
if(m_list.TotalView(m_view_items))
{
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,Height(),Width(),0))
return(false);
if(!Add(m_list))
return(false);
m_list.Hide();
}
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CComboBox::AddItem(const string item,const long value)
{
//--- add item to list
return(m_list.AddItem(item,value));
}
//+------------------------------------------------------------------+
//| Select item |
//+------------------------------------------------------------------+
bool CComboBox::Select(const int index)
{
if(!m_list.Select(index))
return(false);
//--- call the handler
return(OnChangeList());
}
//+------------------------------------------------------------------+
//| Select item (by text) |
//+------------------------------------------------------------------+
bool CComboBox::SelectByText(const string text)
{
if(!m_list.SelectByText(text))
return(false);
//--- call the handler
return(OnChangeList());
}
//+------------------------------------------------------------------+
//| Select item (by value) |
//+------------------------------------------------------------------+
bool CComboBox::SelectByValue(const long value)
{
if(!m_list.SelectByValue(value))
return(false);
//--- call the handler
return(OnChangeList());
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CComboBox::Show(void)
{
m_edit.Show();
m_drop.Show();
m_list.Hide();
//--- call of the method of the parent class
return(CWnd::Show());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CComboBox::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CComboBox::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
SelectByValue(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on main entry field |
//+------------------------------------------------------------------+
bool CComboBox::OnClickEdit(void)
{
//--- change button state
if(!m_drop.Pressed(!m_drop.Pressed()))
return(false);
//--- call the click on button handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CComboBox::OnClickButton(void)
{
//--- show or hide the drop-down list depending on the button state
return((m_drop.Pressed()) ? ListShow() : ListHide());
}
//+------------------------------------------------------------------+
//| Handler of click on drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::OnChangeList(void)
{
string text=m_list.Select();
//--- hide the list, depress the button
ListHide();
m_drop.Pressed(false);
//--- set text in the main entry field
m_edit.Text(text);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Show the drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::ListShow(void)
{
BringToTop();
//--- show the list
return(m_list.Show());
}
//+------------------------------------------------------------------+
//| Hide drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::ListHide(void)
{
//--- hide the list
return(m_list.Hide());
}
//+------------------------------------------------------------------+
//| Hide the drop-down element if necessary |
//+------------------------------------------------------------------+
void CComboBox::CheckListHide(const int id,int x,int y)
{
//--- check event ID
if(id!=CHARTEVENT_CLICK)
return;
//--- check visibility of the drop-down element
if(!m_list.IsVisible())
return;
//--- check mouse cursor's position
y-=(int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,m_subwin);
if(!m_edit.Contains(x,y) && !m_list.Contains(x,y))
{
m_drop.Pressed(false);
m_list.Hide();
}
}
//+------------------------------------------------------------------+
+413
View File
@@ -0,0 +1,413 @@
//+------------------------------------------------------------------+
//| DateDropList.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "BmpButton.mqh"
#include "Picture.mqh"
#include <Canvas\Canvas.mqh>
#include <Tools\DateTime.mqh>
//+------------------------------------------------------------------+
//| Enumerations |
//+------------------------------------------------------------------+
//--- date modes
enum ENUM_DATE_MODES
{
DATE_MODE_MON, // month mode
DATE_MODE_YEAR // year mode
};
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
//--- Can not place the same file into resource twice
#resource "res\\LeftTransp.bmp"
#resource "res\\RightTransp.bmp"
//+------------------------------------------------------------------+
//| Class CDateDropList |
//| Usage: drop-down list |
//+------------------------------------------------------------------+
class CDateDropList : public CWndContainer
{
private:
//--- dependent controls
CBmpButton m_dec; // the button object
CBmpButton m_inc; // the button object
CPicture m_list; // the drop-down list object
CCanvas m_canvas; // and its canvas
//--- data
CDateTime m_value; // current value
//--- variable
ENUM_DATE_MODES m_mode; // operation mode
CRect m_click_rect[32]; // array of click sensibility areas on canvas
public:
CDateDropList(void);
~CDateDropList(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- data
datetime Value(void) { return(StructToTime(m_value)); }
void Value(datetime value) { m_value.Date(value); }
void Value(MqlDateTime& value) { (MqlDateTime&)m_value=value; }
//--- state
virtual bool Show(void);
protected:
//--- internal event handlers
virtual bool OnClick(void);
//--- create dependent controls
virtual bool CreateButtons(void);
virtual bool CreateList(void);
//--- draw
void DrawCanvas(void);
void DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment=0);
//--- handlers of the dependent controls events
virtual bool OnClickDec(void);
virtual bool OnClickInc(void);
virtual bool OnClickList(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CDateDropList)
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
ON_EVENT(ON_CLICK,m_list,OnClickList)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDateDropList::CDateDropList(void) : m_mode(DATE_MODE_MON)
{
ZeroMemory(m_value);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDateDropList::~CDateDropList(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CDateDropList::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- need to find dimensions depending on font size
//--- width 7 columns + 2 offsets
int w=7*(2*CONTROLS_FONT_SIZE)+2*CONTROLS_FONT_SIZE;
//--- header height + 7 rows
int h=(CONTROLS_BUTTON_SIZE+4*CONTROLS_BORDER_WIDTH)+7*(2*CONTROLS_FONT_SIZE);
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x1+w,y1+h))
return(false);
//--- create dependent controls
if(!CreateList())
return(false);
if(!CreateButtons())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create drop-down list |
//+------------------------------------------------------------------+
bool CDateDropList::CreateList(void)
{
//--- create object
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,0,Width(),Height()))
return(false);
if(!Add(m_list))
return(false);
//--- create canvas
if(!m_canvas.Create(m_name,Width(),Height()))
return(false);
m_canvas.FontSet(CONTROLS_FONT_NAME,CONTROLS_FONT_SIZE*(-10));
m_list.BmpName(m_canvas.ResourceName());
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create buttons |
//+------------------------------------------------------------------+
bool CDateDropList::CreateButtons(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=2*CONTROLS_BORDER_WIDTH;
int y1=2*CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create "Dec" button
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::res\\LeftTransp.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//---
x2=Width()-2*CONTROLS_BORDER_WIDTH;
x1=x2-CONTROLS_BUTTON_SIZE;
//--- create "Inc" button
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::res\\RightTransp.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CDateDropList::Show(void)
{
//--- draw canvas
DrawCanvas();
//--- call method of the parent class
return(CWndContainer::Show());
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CDateDropList::OnClickDec(void)
{
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
m_value.MonDec();
break;
//--- within the year
case DATE_MODE_YEAR:
m_value.YearDec();
break;
}
DrawCanvas();
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CDateDropList::OnClickInc(void)
{
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
m_value.MonInc();
break;
//--- within the year
case DATE_MODE_YEAR:
m_value.YearInc();
break;
}
DrawCanvas();
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on picture |
//+------------------------------------------------------------------+
bool CDateDropList::OnClickList(void)
{
m_mouse_x=m_list.MouseX();
m_mouse_y=m_list.MouseY();
//---
OnClick();
//---
m_mouse_x=0;
m_mouse_y=0;
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "click" event |
//+------------------------------------------------------------------+
bool CDateDropList::OnClick(void)
{
for(int i=0;i<32;i++)
{
if(m_click_rect[i].Contains(m_mouse_x,m_mouse_y))
{
if(i==0)
{
//--- clicked on the header
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
//--- switch to the "within the year" mode
m_mode=DATE_MODE_YEAR;
DrawCanvas();
break;
//--- within the year
case DATE_MODE_YEAR:
//--- do nothing for now
break;
}
}
else
{
//--- selected
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
m_value.Day(i);
Hide();
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
break;
//--- within the year
case DATE_MODE_YEAR:
m_value.Mon(i);
m_mode=DATE_MODE_MON;
DrawCanvas();
break;
default:
break;
}
}
break;
}
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Draw canvas |
//+------------------------------------------------------------------+
void CDateDropList::DrawCanvas(void)
{
int x,y;
int dx,dy;
string text;
uint text_al=TA_CENTER|TA_VCENTER;
CDateTime tmp_date;
int rows,cols;
int idx;
//--- zero out array of areas
for(int i=0;i<32;i++)
ZeroMemory(m_click_rect[i]);
//---
m_canvas.Erase(COLOR2RGB(CONTROLS_EDIT_COLOR_BG));
m_canvas.Rectangle(0,0,Width()-1,Height()-1,COLOR2RGB(CONTROLS_EDIT_COLOR_BORDER));
x=Width()/2;
y=CONTROLS_BUTTON_SIZE/2+2*CONTROLS_BORDER_WIDTH;
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
text=m_value.MonthName()+" "+IntegerToString(m_value.year);
DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
rows=6;
cols=7;
x=dx=Width()/(cols+1);
y+=y;
dy=(Height()-y-2*CONTROLS_BORDER_WIDTH)/(rows+1);
y+=dy/2;
for(int i=0;i<cols;i++,x+=dx)
m_canvas.TextOut(x,y,m_value.ShortDayName(i),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
//--- backup data
tmp_date=m_value;
//--- find the beginning of the first displayed week
tmp_date.DayDec(tmp_date.day_of_week);
while(tmp_date.mon==m_value.mon && tmp_date.day!=1)
tmp_date.DayDec(cols);
//--- draw
idx=1;
y+=dy;
for(int i=0;i<rows;i++,y+=dy)
{
x=dx;
for(int j=0;j<cols;j++,x+=dx)
{
text=IntegerToString(tmp_date.day);
if(tmp_date.mon==m_value.mon)
{
if(tmp_date.day==m_value.day)
m_canvas.FillRectangle(x-dx/2,y-dy/2,x+dx/2,y+dy/2,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
DrawClickRect(idx++,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
}
else
m_canvas.TextOut(x,y,text,COLOR2RGB(CONTROLS_BUTTON_COLOR_BORDER),text_al);
tmp_date.DayInc();
}
}
break;
//--- within the year
case DATE_MODE_YEAR:
text=IntegerToString(m_value.year);
DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
rows=3;
cols=4;
x=dx=Width()/(cols+1);
y+=y;
dy=(Height()-y)/rows;
y+=dy/2;
for(int i=0;i<rows*cols;i++)
{
if(i+1==m_value.mon)
m_canvas.FillRectangle(x-dx/2,y-dy/4,x+dx/2,y+dy/4,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
DrawClickRect(i+1,x,y,m_value.ShortMonthName(i+1),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
if(i%cols==cols-1)
{
x=dx;
y+=dy;
}
else
x+=dx;
}
break;
default:
break;
}
m_canvas.Update();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CDateDropList::DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment)
{
int text_w,text_h;
//--- display the text
m_canvas.TextOut(x,y,text,clr,alignment);
//--- determine area occupied by text
m_canvas.TextSize(text,text_w,text_h);
//--- convert relative coordinated to absolute ones
x+=Left();
y+=Top();
//--- check flags of horizontal alignment
switch(alignment&(TA_LEFT|TA_CENTER|TA_RIGHT))
{
case TA_LEFT:
m_click_rect[idx].left=x;
break;
case TA_CENTER:
m_click_rect[idx].left=x-text_w/2;
break;
case TA_RIGHT:
m_click_rect[idx].left=x-text_w;
break;
}
m_click_rect[idx].Width(text_w);
//--- check flags of vertical alignment
switch(alignment&(TA_TOP|TA_VCENTER|TA_BOTTOM))
{
case TA_TOP:
m_click_rect[idx].top=y;
break;
case TA_VCENTER:
m_click_rect[idx].top=y-text_h/2;
break;
case TA_BOTTOM:
m_click_rect[idx].top=y-text_h;
break;
}
m_click_rect[idx].Height(text_h);
}
//+------------------------------------------------------------------+
+264
View File
@@ -0,0 +1,264 @@
//+------------------------------------------------------------------+
//| DatePicker.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "Edit.mqh"
#include "BmpButton.mqh"
#include "DateDropList.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
//--- Can not place the same file into resource twice
#resource "res\\DateDropOn.bmp" // image file
#resource "res\\DateDropOff.bmp" // image file
//+------------------------------------------------------------------+
//| Class CDatePicker |
//| Usage: date picker |
//+------------------------------------------------------------------+
class CDatePicker : public CWndContainer
{
private:
//--- dependent controls
CEdit m_edit; // the entry field object
CBmpButton m_drop; // the button object
CDateDropList m_list; // the drop-down list object
//--- data
datetime m_value; // current value
public:
CDatePicker(void);
~CDatePicker(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- data
datetime Value(void) const { return(m_value); }
void Value(datetime value) { m_edit.Text(TimeToString(m_value=value,TIME_DATE)); }
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateEdit(void);
virtual bool CreateButton(void);
virtual bool CreateList(void);
//--- handlers of the dependent controls events
virtual bool OnClickEdit(void);
virtual bool OnClickButton(void);
virtual bool OnChangeList(void);
//--- show drop-down list
bool ListShow(void);
bool ListHide(void);
void CheckListHide(const int id,int x,int y);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CDatePicker)
ON_EVENT(ON_CLICK,m_edit,OnClickEdit)
ON_EVENT(ON_CLICK,m_drop,OnClickButton)
ON_EVENT(ON_CHANGE,m_list,OnChangeList)
CheckListHide(id,(int)lparam,(int)dparam);
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDatePicker::CDatePicker(void) : m_value(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDatePicker::~CDatePicker(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CDatePicker::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateButton())
return(false);
if(!CreateList())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create main entry field |
//+------------------------------------------------------------------+
bool CDatePicker::CreateEdit(void)
{
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_edit.Text(""))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CDatePicker::CreateButton(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(2*CONTROLS_BUTTON_SIZE+CONTROLS_COMBO_BUTTON_X_OFF);
int y1=(Height()-CONTROLS_BUTTON_SIZE)/2;
int x2=x1+2*CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_drop.Create(m_chart_id,m_name+"Drop",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_drop.BmpNames("::res\\DateDropOff.bmp","::res\\DateDropOn.bmp"))
return(false);
if(!Add(m_drop))
return(false);
m_drop.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::CreateList(void)
{
//--- create
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,Height()-1,Width(),0))
return(false);
if(!Add(m_list))
return(false);
m_list.Hide();
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CDatePicker::Show(void)
{
m_edit.Show();
m_drop.Show();
m_list.Hide();
//--- call method of the parent class
return(CWnd::Show());
}
//+------------------------------------------------------------------+
//| save |
//+------------------------------------------------------------------+
bool CDatePicker::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- write
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| load |
//+------------------------------------------------------------------+
bool CDatePicker::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- load
if(!FileIsEnding(file_handle))
Value(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on main entry field |
//+------------------------------------------------------------------+
bool CDatePicker::OnClickEdit(void)
{
//--- change button state
if(!m_drop.Pressed(!m_drop.Pressed()))
return(false);
//--- call the click on button handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CDatePicker::OnClickButton(void)
{
//--- show or hide the drop-down list depending on the button state
return((m_drop.Pressed()) ? ListShow():ListHide());
}
//+------------------------------------------------------------------+
//| Handler of change on drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::OnChangeList(void)
{
string text=TimeToString(m_value=m_list.Value(),TIME_DATE);
//--- hide the list, depress the button
ListHide();
m_drop.Pressed(false);
//--- set text in the main entry field
m_edit.Text(text);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Show the drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::ListShow(void)
{
//--- set value
m_list.Value(m_value);
//--- show the list
return(m_list.Show());
}
//+------------------------------------------------------------------+
//| Hide drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::ListHide(void)
{
//--- hide the list
return(m_list.Hide());
}
//+------------------------------------------------------------------+
//| Hide the drop-down element if necessary |
//+------------------------------------------------------------------+
void CDatePicker::CheckListHide(const int id,int x,int y)
{
//--- check event ID
if(id!=CHARTEVENT_CLICK)
return;
//--- check visibility of the drop-down element
if(!m_list.IsVisible())
return;
//--- check mouse cursor's position
y-=(int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,m_subwin);
if(!m_edit.Contains(x,y) && !m_list.Contains(x,y))
{
m_drop.Pressed(false);
m_list.Hide();
}
}
//+------------------------------------------------------------------+
+190
View File
@@ -0,0 +1,190 @@
//+------------------------------------------------------------------+
//| Defines.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Enumerations |
//+------------------------------------------------------------------+
//--- properties flags
enum ENUM_WND_PROP_FLAGS
{
WND_PROP_FLAG_CAN_DBL_CLICK = 1, // can be double clicked by mouse
WND_PROP_FLAG_CAN_DRAG = 2, // can be dragged by mouse
WND_PROP_FLAG_CLICKS_BY_PRESS= 4, // generates the "click" event series on pressing left mouse button
WND_PROP_FLAG_CAN_LOCK = 8, // control with fixed state (usually it is a button)
WND_PROP_FLAG_READ_ONLY =16 // read only (usually it is a edit)
};
//--- state flags
enum ENUM_WND_STATE_FLAGS
{
WND_STATE_FLAG_ENABLE = 1, // "object is enabled" flag
WND_STATE_FLAG_VISIBLE = 2, // "object is visible" flag
WND_STATE_FLAG_ACTIVE = 4, // "object is active" flag
};
//--- mouse flags
enum ENUM_MOUSE_FLAGS
{
MOUSE_INVALID_FLAGS =-1, // no buttons state
MOUSE_EMPTY = 0, // buttons are not pressed
MOUSE_LEFT = 1, // left button pressed
MOUSE_RIGHT = 2 // right button pressed
};
//--- alignment flags
enum ENUM_WND_ALIGN_FLAGS
{
WND_ALIGN_NONE = 0, // no alignment
WND_ALIGN_LEFT = 1, // align by left border
WND_ALIGN_TOP = 2, // align by top border
WND_ALIGN_RIGHT = 4, // align by right border
WND_ALIGN_BOTTOM = 8, // align by bottom border
WND_ALIGN_WIDTH = WND_ALIGN_LEFT|WND_ALIGN_RIGHT, // justify
WND_ALIGN_HEIGHT = WND_ALIGN_TOP|WND_ALIGN_BOTTOM, // align by top and bottom border
WND_ALIGN_CLIENT = WND_ALIGN_WIDTH|WND_ALIGN_HEIGHT // align by all sides
};
//+------------------------------------------------------------------+
//| Drawing styles and colors |
//+------------------------------------------------------------------+
//--- common
#define CONTROLS_FONT_NAME "Trebuchet MS"
#define CONTROLS_FONT_SIZE (10)
//--- Text
#define CONTROLS_COLOR_TEXT C'0x3B,0x29,0x28'
#define CONTROLS_COLOR_TEXT_SEL clrWhite
#define CONTROLS_COLOR_BG clrWhite
#define CONTROLS_COLOR_BG_SEL C'0x33,0x99,0xFF'
//--- Button
#define CONTROLS_BUTTON_COLOR C'0x3B,0x29,0x28'
#define CONTROLS_BUTTON_COLOR_BG C'0xDD,0xE2,0xEB'
#define CONTROLS_BUTTON_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- Label
#define CONTROLS_LABEL_COLOR C'0x3B,0x29,0x28'
//--- Edit
#define CONTROLS_EDIT_COLOR C'0x3B,0x29,0x28'
#define CONTROLS_EDIT_COLOR_BG clrWhite
#define CONTROLS_EDIT_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- Scrolls
#define CONTROLS_SCROLL_COLOR_BG C'0xEC,0xEC,0xEC'
#define CONTROLS_SCROLL_COLOR_BORDER C'0xD3,0xD3,0xD3'
//--- Client
#define CONTROLS_CLIENT_COLOR_BG C'0xDE,0xDE,0xDE'
#define CONTROLS_CLIENT_COLOR_BORDER C'0x2C,0x2C,0x2C'
//--- ListView
#define CONTROLS_LISTITEM_COLOR_TEXT C'0x3B,0x29,0x28'
#define CONTROLS_LISTITEM_COLOR_TEXT_SEL clrWhite
#define CONTROLS_LISTITEM_COLOR_BG clrWhite
#define CONTROLS_LISTITEM_COLOR_BG_SEL C'0x33,0x99,0xFF'
#define CONTROLS_LIST_COLOR_BG clrWhite
#define CONTROLS_LIST_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- CheckGroup
#define CONTROLS_CHECKGROUP_COLOR_BG C'0xF7,0xF7,0xF7'
#define CONTROLS_CHECKGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- RadioGroup
#define CONTROLS_RADIOGROUP_COLOR_BG C'0xF7,0xF7,0xF7'
#define CONTROLS_RADIOGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- Dialog
#define CONTROLS_DIALOG_COLOR_BORDER_LIGHT clrWhite
#define CONTROLS_DIALOG_COLOR_BORDER_DARK C'0xB6,0xB6,0xB6'
#define CONTROLS_DIALOG_COLOR_BG C'0xF0,0xF0,0xF0'
#define CONTROLS_DIALOG_COLOR_CAPTION_TEXT C'0x28,0x29,0x3B'
#define CONTROLS_DIALOG_COLOR_CLIENT_BG C'0xF7,0xF7,0xF7'
#define CONTROLS_DIALOG_COLOR_CLIENT_BORDER C'0xC8,0xC8,0xC8'
//+------------------------------------------------------------------+
//| Constants for the controls |
//+------------------------------------------------------------------+
//--- common
#define CONTROLS_INVALID_ID (-1) // invalid ID
#define CONTROLS_INVALID_INDEX (-1) // invalid index of array
#define CONTROLS_SELF_MESSAGE (-1) // message to oneself
#define CONTROLS_MAXIMUM_ID (10000) // maximum number of IDs in application
#define CONTROLS_BORDER_WIDTH (1) // border width
#define CONTROLS_SUBWINDOW_GAP (3) // gap between sub-windows along the Y axis
#define CONTROLS_DRAG_SPACING (50) // sensitivity threshold for dragging
#define CONTROLS_DBL_CLICK_TIME (100) // double click interval
//--- BmpButton
#define CONTROLS_BUTTON_SIZE (16) // default size of button (16 x 16)
//--- Scrolls
#define CONTROLS_SCROLL_SIZE (18) // default lateral size of scrollbar
#define CONTROLS_SCROLL_THUMB_SIZE (22) // default length of scroll box
//--- RadioButton
#define CONTROLS_RADIO_BUTTON_X_OFF (3) // X offset of radio button (for RadioButton)
#define CONTROLS_RADIO_BUTTON_Y_OFF (3) // Y offset of radio button (for RadioButton)
#define CONTROLS_RADIO_LABEL_X_OFF (20) // X offset of label (for RadioButton)
#define CONTROLS_RADIO_LABEL_Y_OFF (0) // Y offset of label (for RadioButton)
//--- CheckBox
#define CONTROLS_CHECK_BUTTON_X_OFF (3) // X offset of check button (for CheckBox)
#define CONTROLS_CHECK_BUTTON_Y_OFF (3) // Y offset of check button (for CheckBox)
#define CONTROLS_CHECK_LABEL_X_OFF (20) // X offset of label (for CheckBox)
#define CONTROLS_CHECK_LABEL_Y_OFF (0) // Y offset of label (for CheckBox)
//--- Spin
#define CONTROLS_SPIN_BUTTON_X_OFF (2) // X offset of button from right (for SpinEdit)
#define CONTROLS_SPIN_MIN_HEIGHT (18) // minimal height (for SpinEdit)
#define CONTROLS_SPIN_BUTTON_SIZE (8) // default size of button (16 x 8) (for SpinEdit)
//--- Combo
#define CONTROLS_COMBO_BUTTON_X_OFF (2) // X offset of button from right (for ComboBox)
#define CONTROLS_COMBO_MIN_HEIGHT (18) // minimal height (for ComboBox)
#define CONTROLS_COMBO_ITEM_HEIGHT (18) // height of combo box item (for ComboBox)
#define CONTROLS_COMBO_ITEMS_VIEW (8) // number of items in combo box (for ComboBox)
//--- ListView
#define CONTROLS_LIST_ITEM_HEIGHT (18) // height of list item (for ListView)
//--- Dialog
#define CONTROLS_DIALOG_CAPTION_HEIGHT (22) // height of dialog header
#define CONTROLS_DIALOG_BUTTON_OFF (3) // offset of dialog buttons
#define CONTROLS_DIALOG_CLIENT_OFF (2) // offset of dialog client area
#define CONTROLS_DIALOG_MINIMIZE_LEFT (10) // left coordinate of dialog in minimized state
#define CONTROLS_DIALOG_MINIMIZE_TOP (10) // top coordinate of dialog in minimized state
#define CONTROLS_DIALOG_MINIMIZE_WIDTH (100) // width of dialog in minimized state
#define CONTROLS_DIALOG_MINIMIZE_HEIGHT (4*CONTROLS_BORDER_WIDTH+CONTROLS_DIALOG_CAPTION_HEIGHT) // height of dialog in minimized state
//+------------------------------------------------------------------+
//| Macro |
//+------------------------------------------------------------------+
//--- check properties
#define IS_CAN_DBL_CLICK ((m_prop_flags&WND_PROP_FLAG_CAN_DBL_CLICK)!=0)
#define IS_CAN_DRAG ((m_prop_flags&WND_PROP_FLAG_CAN_DRAG)!=0)
#define IS_CLICKS_BY_PRESS ((m_prop_flags&WND_PROP_FLAG_CLICKS_BY_PRESS)!=0)
#define IS_CAN_LOCK ((m_prop_flags&WND_PROP_FLAG_CAN_LOCK)!=0)
#define IS_READ_ONLY ((m_prop_flags&WND_PROP_FLAG_READ_ONLY)!=0)
//--- check state
#define IS_ENABLED ((m_state_flags&WND_STATE_FLAG_ENABLE)!=0)
#define IS_VISIBLE ((m_state_flags&WND_STATE_FLAG_VISIBLE)!=0)
#define IS_ACTIVE ((m_state_flags&WND_STATE_FLAG_ACTIVE)!=0)
//+------------------------------------------------------------------+
//| Macro of event handling map |
//+------------------------------------------------------------------+
#define INTERNAL_EVENT (-1)
//--- beginning of map
#define EVENT_MAP_BEGIN(class_name) bool class_name::OnEvent(const int id,const long& lparam,const double& dparam,const string& sparam) {
//--- end of map
#define EVENT_MAP_END(parent_class_name) return(parent_class_name::OnEvent(id,lparam,dparam,sparam)); }
//--- event handling by numeric ID
#define ON_EVENT(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(); return(true); }
//--- event handling by numeric ID by pointer of control
#define ON_EVENT_PTR(event,control,handler) if(control!=NULL && id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(); return(true); }
//--- event handling without ID analysis
#define ON_NO_ID_EVENT(event,handler) if(id==(event+CHARTEVENT_CUSTOM)) { return(handler()); }
//--- event handling by row ID
#define ON_NAMED_EVENT(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && sparam==control.Name()) { handler(); return(true); }
//--- handling of indexed event
#define ON_INDEXED_EVENT(event,controls,handler) { int total=ArraySize(controls); for(int i=0;i<total;i++) if(id==(event+CHARTEVENT_CUSTOM) && lparam==controls[i].Id()) return(handler(i)); }
//--- handling of external event
#define ON_EXTERNAL_EVENT(event,handler) if(id==(event+CHARTEVENT_CUSTOM)) { handler(lparam,dparam,sparam); return(true); }
//+------------------------------------------------------------------+
//| Events |
//+------------------------------------------------------------------+
#define ON_CLICK (0) // clicking on control event
#define ON_DBL_CLICK (1) // double clicking on control event
#define ON_SHOW (2) // showing control event
#define ON_HIDE (3) // hiding control event
#define ON_CHANGE (4) // changing control event
#define ON_START_EDIT (5) // start of editing event
#define ON_END_EDIT (6) // end of editing event
#define ON_SCROLL_INC (7) // increment of scrollbar event
#define ON_SCROLL_DEC (8) // decrement of scrollbar event
#define ON_MOUSE_FOCUS_SET (9) // the "mouse cursor entered the control" event
#define ON_MOUSE_FOCUS_KILL (10) // the "mouse cursor exited the control" event
#define ON_DRAG_START (11) // the "control dragging start" event
#define ON_DRAG_PROCESS (12) // the "control is being dragged" event
#define ON_DRAG_END (13) // the "control dragging end" event
#define ON_BRING_TO_TOP (14) // the "mouse events priority increase" event
#define ON_APP_CLOSE (100) // "closing the application" event
//+------------------------------------------------------------------+
+971
View File
@@ -0,0 +1,971 @@
//+------------------------------------------------------------------+
//| Dialog.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "WndClient.mqh"
#include "Panel.mqh"
#include "Edit.mqh"
#include "BmpButton.mqh"
#include <Charts\Chart.mqh>
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "res\\Close.bmp"
#resource "res\\Restore.bmp"
#resource "res\\Turn.bmp"
//+------------------------------------------------------------------+
//| Class CDialog |
//| Usage: base class to create dialog boxes |
//| and indicator panels |
//+------------------------------------------------------------------+
class CDialog : public CWndContainer
{
private:
//--- dependent controls
CPanel m_white_border; // the "white border" object
CPanel m_background; // the background object
CEdit m_caption; // the window title object
CBmpButton m_button_close; // the "Close" button object
CWndClient m_client_area; // the client area object
protected:
//--- flags
bool m_panel_flag; // the "panel in a separate window" flag
//--- flags
bool m_minimized; // "create in minimized state" flag
//--- additional areas
CRect m_min_rect; // minimal area coordinates
CRect m_norm_rect; // normal area coordinates
public:
CDialog(void);
~CDialog(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
string Caption(void) const { return(m_caption.Text()); }
bool Caption(const string text) { return(m_caption.Text(text)); }
//--- fill
bool Add(CWnd *control);
bool Add(CWnd &control);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateWhiteBorder(void);
virtual bool CreateBackground(void);
virtual bool CreateCaption(void);
virtual bool CreateButtonClose(void);
virtual bool CreateClientArea(void);
//--- handlers of the dependent controls events
virtual void OnClickCaption(void);
virtual void OnClickButtonClose(void);
//--- access properties of caption
void CaptionAlignment(const int flags,const int left,const int top,const int right,const int bottom)
{ m_caption.Alignment(flags,left,top,right,bottom); }
//--- access properties of client area
bool ClientAreaVisible(const bool visible) { return(m_client_area.Visible(visible)); }
int ClientAreaLeft(void) const { return(m_client_area.Left()); }
int ClientAreaTop(void) const { return(m_client_area.Top()); }
int ClientAreaRight(void) const { return(m_client_area.Right()); }
int ClientAreaBottom(void) const { return(m_client_area.Bottom()); }
int ClientAreaWidth(void) const { return(m_client_area.Width()); }
int ClientAreaHeight(void) const { return(m_client_area.Height()); }
//--- handlers of drag
virtual bool OnDialogDragStart(void);
virtual bool OnDialogDragProcess(void);
virtual bool OnDialogDragEnd(void);
};
//+------------------------------------------------------------------+
//| Common handler of events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CDialog)
ON_EVENT(ON_CLICK,m_button_close,OnClickButtonClose)
ON_EVENT(ON_CLICK,m_caption,OnClickCaption)
ON_EVENT(ON_DRAG_START,m_caption,OnDialogDragStart)
ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnDialogDragProcess)
ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnDialogDragEnd)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDialog::CDialog(void) : m_panel_flag(false),
m_minimized(false)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDialog::~CDialog(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!m_panel_flag && !CreateWhiteBorder())
return(false);
if(!CreateBackground())
return(false);
if(!CreateCaption())
return(false);
if(!CreateButtonClose())
return(false);
if(!CreateClientArea())
return(false);
//--- set up additional areas
m_norm_rect.SetBound(m_rect);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add control to the client area (by pointer) |
//+------------------------------------------------------------------+
bool CDialog::Add(CWnd *control)
{
return(m_client_area.Add(control));
}
//+------------------------------------------------------------------+
//| Add control to the client area (by reference) |
//+------------------------------------------------------------------+
bool CDialog::Add(CWnd &control)
{
return(m_client_area.Add(control));
}
//+------------------------------------------------------------------+
//| Save |
//+------------------------------------------------------------------+
bool CDialog::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- save
FileWriteStruct(file_handle,m_norm_rect);
FileWriteInteger(file_handle,m_min_rect.left);
FileWriteInteger(file_handle,m_min_rect.top);
FileWriteInteger(file_handle,m_minimized);
//--- result
return(CWndContainer::Save(file_handle));
}
//+------------------------------------------------------------------+
//| Load |
//+------------------------------------------------------------------+
bool CDialog::Load(const int file_handle)
{
if(file_handle==INVALID_HANDLE)
return(false);
//--- load
if(!FileIsEnding(file_handle))
{
FileReadStruct(file_handle,m_norm_rect);
int left=FileReadInteger(file_handle);
int top=FileReadInteger(file_handle);
m_min_rect.Move(left,top);
m_minimized=FileReadInteger(file_handle);
}
//--- result
return(CWndContainer::Load(file_handle));
}
//+------------------------------------------------------------------+
//| Create "white border" |
//+------------------------------------------------------------------+
bool CDialog::CreateWhiteBorder(void)
{
//--- coordinates
int x1=0;
int y1=0;
int x2=Width();
int y2=Height();
//--- create
if(!m_white_border.Create(m_chart_id,m_name+"Border",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_white_border.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
return(false);
if(!m_white_border.ColorBorder(CONTROLS_DIALOG_COLOR_BORDER_LIGHT))
return(false);
if(!CWndContainer::Add(m_white_border))
return(false);
m_white_border.Alignment(WND_ALIGN_CLIENT,0,0,0,0);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create background |
//+------------------------------------------------------------------+
bool CDialog::CreateBackground(void)
{
int off=(m_panel_flag) ? 0:CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=off;
int y1=off;
int x2=Width()-off;
int y2=Height()-off;
//--- create
if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_background.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
return(false);
color border=(m_panel_flag) ? CONTROLS_DIALOG_COLOR_BG : CONTROLS_DIALOG_COLOR_BORDER_DARK;
if(!m_background.ColorBorder(border))
return(false);
if(!CWndContainer::Add(m_background))
return(false);
m_background.Alignment(WND_ALIGN_CLIENT,off,off,off,off);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create window title |
//+------------------------------------------------------------------+
bool CDialog::CreateCaption(void)
{
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=off;
int y1=off;
int x2=Width()-off;
int y2=y1+CONTROLS_DIALOG_CAPTION_HEIGHT;
//--- create
if(!m_caption.Create(m_chart_id,m_name+"Caption",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_caption.Color(CONTROLS_DIALOG_COLOR_CAPTION_TEXT))
return(false);
if(!m_caption.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
return(false);
if(!m_caption.ColorBorder(CONTROLS_DIALOG_COLOR_BG))
return(false);
if(!m_caption.ReadOnly(true))
return(false);
if(!m_caption.Text(m_name))
return(false);
if(!CWndContainer::Add(m_caption))
return(false);
m_caption.Alignment(WND_ALIGN_WIDTH,off,0,off,0);
if(!m_panel_flag)
m_caption.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Close" button |
//+------------------------------------------------------------------+
bool CDialog::CreateButtonClose(void)
{
int off=(m_panel_flag) ? 0 : 2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=Width()-off-(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF);
int y1=off+CONTROLS_DIALOG_BUTTON_OFF;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_button_close.Create(m_chart_id,m_name+"Close",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button_close.BmpNames("::res\\Close.bmp"))
return(false);
if(!CWndContainer::Add(m_button_close))
return(false);
m_button_close.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_DIALOG_BUTTON_OFF,0);
//--- change caption
CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create client area |
//+------------------------------------------------------------------+
bool CDialog::CreateClientArea(void)
{
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=off+CONTROLS_DIALOG_CLIENT_OFF;
int y1=off+CONTROLS_DIALOG_CAPTION_HEIGHT;
int x2=Width()-(off+CONTROLS_DIALOG_CLIENT_OFF);
int y2=Height()-(off+CONTROLS_DIALOG_CLIENT_OFF);
//--- create
if(!m_client_area.Create(m_chart_id,m_name+"Client",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_client_area.ColorBackground(CONTROLS_DIALOG_COLOR_CLIENT_BG))
return(false);
if(!m_client_area.ColorBorder(CONTROLS_DIALOG_COLOR_CLIENT_BORDER))
return(false);
CWndContainer::Add(m_client_area);
m_client_area.Alignment(WND_ALIGN_CLIENT,x1,y1,x1,x1);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the window title |
//+------------------------------------------------------------------+
void CDialog::OnClickCaption(void)
{
}
//+------------------------------------------------------------------+
//| Handler of click on the "Close" button |
//+------------------------------------------------------------------+
void CDialog::OnClickButtonClose(void)
{
Visible(false);
}
//+------------------------------------------------------------------+
//| Start dragging the dialog box |
//+------------------------------------------------------------------+
bool CDialog::OnDialogDragStart(void)
{
if(m_drag_object==NULL)
{
m_drag_object=new CDragWnd;
if(m_drag_object==NULL)
return(false);
}
//--- calculate coordinates
int x1=Left()-CONTROLS_DRAG_SPACING;
int y1=Top()-CONTROLS_DRAG_SPACING;
int x2=Right()+CONTROLS_DRAG_SPACING;
int y2=Bottom()+CONTROLS_DRAG_SPACING;
//--- create
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- constraints
CChart chart;
chart.Attach(m_chart_id);
m_drag_object.Limits(-CONTROLS_DRAG_SPACING,-CONTROLS_DRAG_SPACING,
chart.WidthInPixels()+CONTROLS_DRAG_SPACING,
chart.HeightInPixels(m_subwin)+CONTROLS_DRAG_SPACING);
chart.Detach();
//--- set mouse params
m_drag_object.MouseX(m_caption.MouseX());
m_drag_object.MouseY(m_caption.MouseY());
m_drag_object.MouseFlags(m_caption.MouseFlags());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Continue dragging the dialog box |
//+------------------------------------------------------------------+
bool CDialog::OnDialogDragProcess(void)
{
//--- checking
if(m_drag_object==NULL)
return(false);
//--- calculate coordinates
int x=m_drag_object.Left()+50;
int y=m_drag_object.Top()+50;
//--- move dialog
Move(x,y);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| End dragging the dialog box |
//+------------------------------------------------------------------+
bool CDialog::OnDialogDragEnd(void)
{
if(m_drag_object!=NULL)
{
m_caption.MouseFlags(m_drag_object.MouseFlags());
delete m_drag_object;
m_drag_object=NULL;
}
//--- set up additional areas
if(m_minimized)
m_min_rect.SetBound(m_rect);
else
m_norm_rect.SetBound(m_rect);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Class CAppDialog |
//| Usage: main dialog box of MQL5 application |
//+------------------------------------------------------------------+
class CAppDialog : public CDialog
{
private:
//--- dependent controls
CBmpButton m_button_minmax; // the "Minimize/Maximize" button object
//--- variables
string m_program_name; // name of program
string m_instance_id; // unique string ID
ENUM_PROGRAM_TYPE m_program_type; // type of program
string m_indicator_name;
int m_deinit_reason;
//--- for mouse
int m_subwin_Yoff; // subwindow Y offset
CWnd* m_focused_wnd; // pointer to object that has mouse focus
CWnd* m_top_wnd; // pointer to object that has priority over mouse events handling
protected:
CChart m_chart; // object to access chart
public:
CAppDialog(void);
~CAppDialog(void);
//--- main application dialog creation and destroy
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
virtual void Destroy(const int reason=REASON_PROGRAM);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- dialog run
bool Run(void);
//--- chart events processing
void ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
void Minimized(const bool flag) { m_minimized=flag; }
//--- to save/restore state
void IniFileSave(void);
void IniFileLoad(void);
virtual string IniFileName(void) const;
virtual string IniFileExt(void) const { return(".dat"); }
virtual bool Load(const int file_handle);
virtual bool Save(const int file_handle);
private:
bool CreateCommon(const long chart,const string name,const int subwin);
bool CreateExpert(const int x1,const int y1,const int x2,const int y2);
bool CreateIndicator(const int x1,const int y1,const int x2,const int y2);
protected:
//--- create dependent controls
virtual bool CreateButtonMinMax(void);
//--- handlers of the dependent controls events
virtual void OnClickButtonClose(void);
virtual void OnClickButtonMinMax(void);
//--- external event handlers
virtual void OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam);
//--- methods
virtual bool Rebound(const CRect &rect);
virtual void Minimize(void);
virtual void Maximize(void);
string CreateInstanceId(void);
string ProgramName(void) const { return(m_program_name); }
void SubwinOff(void);
};
//+------------------------------------------------------------------+
//| Common handler of events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CAppDialog)
ON_EVENT(ON_CLICK,m_button_minmax,OnClickButtonMinMax)
ON_EXTERNAL_EVENT(ON_APP_CLOSE,OnAnotherApplicationClose)
EVENT_MAP_END(CDialog)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CAppDialog::CAppDialog(void) : m_program_type(WRONG_VALUE),
m_deinit_reason(WRONG_VALUE),
m_subwin_Yoff(0),
m_focused_wnd(NULL),
m_top_wnd(NULL)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CAppDialog::~CAppDialog(void)
{
}
//+------------------------------------------------------------------+
//| Application dialog initialization function |
//+------------------------------------------------------------------+
bool CAppDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
if(!CreateCommon(chart,name,subwin))
return(false);
//---
switch(m_program_type)
{
case PROGRAM_EXPERT:
if(!CreateExpert(x1,y1,x2,y2))
return(false);
break;
case PROGRAM_INDICATOR:
if(!CreateIndicator(x1,y1,x2,y2))
return(false);
break;
default:
Print("CAppDialog: invalid program type");
return(false);
}
//--- Title of dialog window
if(!Caption(m_program_name))
return(false);
//--- create dependent controls
if(!CreateButtonMinMax())
return(false);
//--- get subwindow offset
SubwinOff();
//--- if flag is set, minimize the dialog
if(m_minimized)
Minimize();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialize common area |
//+------------------------------------------------------------------+
bool CAppDialog::CreateCommon(const long chart,const string name,const int subwin)
{
//--- save parameters
m_chart_id =chart;
m_name =name;
m_subwin =subwin;
m_program_name =name;
m_deinit_reason=WRONG_VALUE;
//--- get unique ID
m_instance_id=CreateInstanceId();
//--- initialize chart object
m_chart.Attach(chart);
//--- determine type of program
m_program_type=(ENUM_PROGRAM_TYPE)MQLInfoInteger(MQL_PROGRAM_TYPE);
//--- specify object and mouse events
if(!m_chart.EventObjectCreate() || !m_chart.EventObjectDelete() || !m_chart.EventMouseMove())
{
Print("CAppDialog: object events specify error");
m_chart.Detach();
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialize in Expert Advisor |
//+------------------------------------------------------------------+
bool CAppDialog::CreateExpert(const int x1,const int y1,const int x2,const int y2)
{
//--- EA works only in main window
m_subwin=0;
//--- geometry for the minimized state
m_min_rect.SetBound(CONTROLS_DIALOG_MINIMIZE_LEFT,
CONTROLS_DIALOG_MINIMIZE_TOP,
CONTROLS_DIALOG_MINIMIZE_LEFT+CONTROLS_DIALOG_MINIMIZE_WIDTH,
CONTROLS_DIALOG_MINIMIZE_TOP+CONTROLS_DIALOG_MINIMIZE_HEIGHT);
//--- call method of the parent class
if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,x1,y1,x2,y2))
{
Print("CAppDialog: expert dialog create error");
m_chart.Detach();
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialize in Indicator |
//+------------------------------------------------------------------+
bool CAppDialog::CreateIndicator(const int x1,const int y1,const int x2,const int y2)
{
int width=m_chart.WidthInPixels();
//--- geometry for the minimized state
m_min_rect.LeftTop(0,0);
m_min_rect.Width(width);
m_min_rect.Height(CONTROLS_DIALOG_MINIMIZE_HEIGHT-2*CONTROLS_BORDER_WIDTH);
//--- determine subwindow
m_subwin=ChartWindowFind();
if(m_subwin==-1)
{
Print("CAppDialog: find subwindow error");
m_chart.Detach();
return(false);
}
//---
int total=ChartIndicatorsTotal(m_chart.ChartId(),m_subwin);
m_indicator_name=ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1);
//--- if subwindow number is 0 (main window), then our program is
//--- not an indicator panel, but is an indicator with built-in settings dialog
//--- dialog of such an indicator should behave as an Expert Advisor dialog
if(m_subwin==0)
return(CreateExpert(x1,y1,x2,y2));
//--- if subwindow number is not 0, then our program is an indicator panel
//--- check if subwindow is not occupied by other indicators
if(total!=1)
{
Print("CAppDialog: subwindow busy");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- resize subwindow by dialog height
if(!IndicatorSetInteger(INDICATOR_HEIGHT,(y2-y1)+1))
{
Print("CAppDialog: subwindow resize error");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- indicator short name
m_indicator_name=m_program_name+IntegerToString(m_subwin);
if(!IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name))
{
Print("CAppDialog: shortname error");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- set flag
m_panel_flag=true;
//--- call method of the parent class
if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,0,0,width,y2-y1))
{
Print("CAppDialog: indicator dialog create error");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Application dialog deinitialization function |
//+------------------------------------------------------------------+
void CAppDialog::Destroy(const int reason)
{
//--- destroyed already?
if(m_deinit_reason!=WRONG_VALUE)
return;
//---
m_deinit_reason=reason;
IniFileSave();
//--- detach chart object from chart
m_chart.Detach();
//--- call parent destroy
CDialog::Destroy();
//---
if(reason==REASON_PROGRAM)
{
if(m_program_type==PROGRAM_EXPERT)
ExpertRemove();
if(m_program_type==PROGRAM_INDICATOR)
ChartIndicatorDelete(m_chart_id,m_subwin,m_indicator_name);
}
//--- send message
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_APP_CLOSE,m_subwin,0.0,m_program_name);
}
//+------------------------------------------------------------------+
//| Calculate subwindow offset |
//+------------------------------------------------------------------+
void CAppDialog::SubwinOff(void)
{
m_subwin_Yoff=m_chart.SubwindowY(m_subwin);
}
//+------------------------------------------------------------------+
//| Create the "Minimize/Maximize" button |
//+------------------------------------------------------------------+
bool CAppDialog::CreateButtonMinMax(void)
{
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=Width()-off-2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF);
int y1=off+CONTROLS_DIALOG_BUTTON_OFF;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_button_minmax.Create(m_chart_id,m_name+"MinMax",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button_minmax.BmpNames("::res\\Turn.bmp","::res\\Restore.bmp"))
return(false);
if(!CWndContainer::Add(m_button_minmax))
return(false);
m_button_minmax.Locking(true);
m_button_minmax.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_BUTTON_SIZE+2*CONTROLS_DIALOG_BUTTON_OFF,0);
//--- change caption
CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Charts event processing |
//+------------------------------------------------------------------+
void CAppDialog::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
int mouse_x=(int)lparam;
int mouse_y=(int)dparam-m_subwin_Yoff;
//--- separate mouse events from others
switch(id)
{
case CHARTEVENT_CHART_CHANGE:
//--- assumed that the CHARTEVENT_CHART_CHANGE event can handle only the application dialog
break;
case CHARTEVENT_OBJECT_CLICK:
//--- we won't handle the CHARTEVENT_OBJECT_CLICK event, as we are working with the CHARTEVENT_MOUSE_MOVE events
return;
case CHARTEVENT_CUSTOM+ON_MOUSE_FOCUS_SET:
//--- the CHARTEVENT_CUSTOM + ON_MOUSE_FOCUS_SET event
if(CheckPointer(m_focused_wnd)!=POINTER_INVALID)
{
//--- if there is an element with focus, try to take its focus away
if(!m_focused_wnd.MouseFocusKill(lparam))
return;
}
m_focused_wnd=ControlFind(lparam);
return;
case CHARTEVENT_CUSTOM+ON_BRING_TO_TOP:
m_top_wnd=ControlFind(lparam);
return;
case CHARTEVENT_MOUSE_MOVE:
//--- the CHARTEVENT_MOUSE_MOVE event
if(CheckPointer(m_top_wnd)!=POINTER_INVALID)
{
//--- if a priority element already exists, pass control to it
if(m_top_wnd.OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam)))
{
//--- event handled
m_chart.Redraw();
return;
}
}
if(OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam)))
m_chart.Redraw();
return;
default:
//--- call event processing and redraw chart if event handled
if(OnEvent(id,lparam,dparam,sparam))
m_chart.Redraw();
return;
}
//--- if event was not handled, try to handle the CHARTEVENT_CHART_CHANGE event
if(id==CHARTEVENT_CHART_CHANGE)
{
//--- if subwindow number is not 0, and dialog subwindow has changed its number, then restart
if(m_subwin!=0 && m_subwin!=ChartWindowFind())
{
long fiction=1;
OnAnotherApplicationClose(fiction,dparam,sparam);
}
//--- if subwindow height is less that dialog height, minimize application window (always)
if(m_chart.HeightInPixels(m_subwin)<Height()+CONTROLS_BORDER_WIDTH)
{
m_button_minmax.Pressed(true);
Minimize();
m_chart.Redraw();
}
//--- if chart width is less that dialog width, and subwindow number is not 0, try to modify dialog width
if(m_chart.WidthInPixels()!=Width() && m_subwin!=0)
{
Width(m_chart.WidthInPixels());
m_chart.Redraw();
}
//--- get subwindow offset
SubwinOff();
return;
}
}
//+------------------------------------------------------------------+
//| Run application |
//+------------------------------------------------------------------+
bool CAppDialog::Run(void)
{
//--- redraw chart for dialog invalidate
m_chart.Redraw();
//--- here we begin to assign IDs to controls
if(Id(m_subwin*CONTROLS_MAXIMUM_ID)>CONTROLS_MAXIMUM_ID)
{
Print("CAppDialog: too many objects");
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Stop application |
//+------------------------------------------------------------------+
void CAppDialog::OnClickButtonClose(void)
{
//--- destroy application
Destroy();
}
//+------------------------------------------------------------------+
//| Handler of click on the "Minimize/Maximize" button |
//+------------------------------------------------------------------+
void CAppDialog::OnClickButtonMinMax(void)
{
if(m_button_minmax.Pressed())
Minimize();
else
Maximize();
//--- get subwindow offset
SubwinOff();
}
//+------------------------------------------------------------------+
//| Resize |
//+------------------------------------------------------------------+
bool CAppDialog::Rebound(const CRect &rect)
{
if(!Move(rect.LeftTop()))
return(false);
if(!Size(rect.Size()))
return(false);
//--- resize subwindow
if(m_program_type==PROGRAM_INDICATOR && !IndicatorSetInteger(INDICATOR_HEIGHT,rect.Height()+1))
{
Print("CAppDialog: subwindow resize error");
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Minimize dialog window |
//+------------------------------------------------------------------+
void CAppDialog::Minimize(void)
{
//--- set flag
m_minimized=true;
//--- resize
Rebound(m_min_rect);
//--- hide client area
ClientAreaVisible(false);
}
//+------------------------------------------------------------------+
//| Restore dialog window |
//+------------------------------------------------------------------+
void CAppDialog::Maximize(void)
{
//--- reset flag
m_minimized=false;
//--- resize
Rebound(m_norm_rect);
//--- show client area
ClientAreaVisible(true);
}
//+------------------------------------------------------------------+
//| Create unique prefix for object names |
//+------------------------------------------------------------------+
string CAppDialog::CreateInstanceId(void)
{
return(IntegerToString(rand(),5,'0'));
}
//+------------------------------------------------------------------+
//| Handler of the ON_APP_CLOSE external event |
//+------------------------------------------------------------------+
void CAppDialog::OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam)
{
//--- exit if we are in the main window
if(m_subwin==0)
return;
//--- exit if external program was closed in main window
if(lparam==0)
return;
//--- get subwindow offset
SubwinOff();
//--- exit if external program was closed in subwindow with greater number
if(lparam>=m_subwin)
return;
//--- after all the checks we must change the subwindow
//--- get the new number of subwindow
m_subwin=ChartWindowFind();
//--- change short name
m_indicator_name=m_program_name+IntegerToString(m_subwin);
IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name);
//--- change dialog title
Caption(m_program_name);
//--- reassign IDs
Run();
}
//+------------------------------------------------------------------+
//| Save the current state of the program |
//+------------------------------------------------------------------+
void CAppDialog::IniFileSave(void)
{
string filename=IniFileName()+IniFileExt();
int handle=FileOpen(filename,FILE_WRITE|FILE_BIN|FILE_ANSI);
//---
if(handle!=INVALID_HANDLE)
{
Save(handle);
FileClose(handle);
}
}
//+------------------------------------------------------------------+
//| Read the previous state of the program |
//+------------------------------------------------------------------+
void CAppDialog::IniFileLoad(void)
{
string filename=IniFileName()+IniFileExt();
int handle=FileOpen(filename,FILE_READ|FILE_BIN|FILE_ANSI);
//---
if(handle!=INVALID_HANDLE)
{
Load(handle);
FileClose(handle);
}
}
//+------------------------------------------------------------------+
//| Generate the filename |
//+------------------------------------------------------------------+
string CAppDialog::IniFileName(void) const
{
string name;
//---
name=(m_indicator_name!=NULL) ? m_indicator_name : m_program_name;
//---
name+="_"+Symbol();
name+="_Ini";
//---
return(name);
}
//+------------------------------------------------------------------+
//| Load data |
//+------------------------------------------------------------------+
bool CAppDialog::Load(const int file_handle)
{
if(CDialog::Load(file_handle))
{
if(m_minimized)
{
m_button_minmax.Pressed(true);
Minimize();
}
else
{
m_button_minmax.Pressed(false);
Maximize();
}
int prev_deinit_reason=FileReadInteger(file_handle);
if(prev_deinit_reason==REASON_CHARTCLOSE || prev_deinit_reason==REASON_CLOSE)
{
//--- if the previous time program ended after closing the chart window,
//--- delete object left since the last start of the program
string prev_instance_id=IntegerToString(FileReadInteger(file_handle),5,'0');
if(prev_instance_id!=m_instance_id)
{
long chart_id=m_chart.ChartId();
int total=ObjectsTotal(chart_id,m_subwin);
for(int i=total-1;i>=0;i--)
{
string obj_name=ObjectName(chart_id,i,m_subwin);
if(StringFind(obj_name,prev_instance_id)==0)
ObjectDelete(chart_id,obj_name);
}
}
}
return(true);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Save data |
//+------------------------------------------------------------------+
bool CAppDialog::Save(const int file_handle)
{
if(CDialog::Save(file_handle))
{
FileWriteInteger(file_handle,m_deinit_reason);
FileWriteInteger(file_handle,(int)StringToInteger(m_instance_id));
return(true);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
+188
View File
@@ -0,0 +1,188 @@
//+------------------------------------------------------------------+
//| Edit.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CEdit |
//| Usage: control that is displayed by |
//| the CChartObjectEdit object |
//+------------------------------------------------------------------+
class CEdit : public CWndObj
{
private:
CChartObjectEdit m_edit; // chart object
//--- parameters of the chart object
bool m_read_only; // "read-only" mode flag
ENUM_ALIGN_MODE m_align_mode; // align mode
public:
CEdit(void);
~CEdit(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- parameters of the chart object
bool ReadOnly(void) const { return(m_read_only); }
bool ReadOnly(const bool flag);
ENUM_ALIGN_MODE TextAlign(void) const { return(m_align_mode); }
bool TextAlign(const ENUM_ALIGN_MODE align);
//--- data access
string Text(void) const { return(m_edit.Description()); }
bool Text(const string value) { return(CWndObj::Text(value)); }
protected:
//--- handlers of object events
virtual bool OnObjectEndEdit(void);
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_edit.Description(m_text)); }
virtual bool OnSetColor(void) { return(m_edit.Color(m_color)); }
virtual bool OnSetColorBackground(void) { return(m_edit.BackColor(m_color_background)); }
virtual bool OnSetColorBorder(void) { return(m_edit.BorderColor(m_color_border)); }
virtual bool OnSetFont(void) { return(m_edit.Font(m_font)); }
virtual bool OnSetFontSize(void) { return(m_edit.FontSize(m_font_size)); }
virtual bool OnSetZOrder(void) { return(m_edit.Z_Order(m_zorder)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnResize(void);
virtual bool OnChange(void);
virtual bool OnClick(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
if(m_name==sparam && id==CHARTEVENT_OBJECT_ENDEDIT)
return(OnObjectEndEdit());
//--- event was not handled
return(CWndObj::OnEvent(id,lparam,dparam,sparam));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CEdit::CEdit(void) : m_read_only(false),
m_align_mode(ALIGN_LEFT)
{
m_color =CONTROLS_EDIT_COLOR;
m_color_background=CONTROLS_EDIT_COLOR_BG;
m_color_border =CONTROLS_EDIT_COLOR_BORDER;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CEdit::~CEdit(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height()))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set parameter |
//+------------------------------------------------------------------+
bool CEdit::ReadOnly(const bool flag)
{
//--- save new value of parameter
m_read_only=flag;
//--- set up the chart object
return(m_edit.ReadOnly(flag));
}
//+------------------------------------------------------------------+
//| Set parameter |
//+------------------------------------------------------------------+
bool CEdit::TextAlign(const ENUM_ALIGN_MODE align)
{
//--- save new value of parameter
m_align_mode=align;
//--- set up the chart object
return(m_edit.TextAlign(align));
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CEdit::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CEdit::OnShow(void)
{
return(m_edit.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CEdit::OnHide(void)
{
return(m_edit.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CEdit::OnMove(void)
{
//--- position the chart object
return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CEdit::OnResize(void)
{
//--- resize the chart object
return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CEdit::OnChange(void)
{
//--- set up the chart object
return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode));
}
//+------------------------------------------------------------------+
//| Handler of the "End of editing" event |
//+------------------------------------------------------------------+
bool CEdit::OnObjectEndEdit(void)
{
//--- send the ON_END_EDIT notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "click" event |
//+------------------------------------------------------------------+
bool CEdit::OnClick(void)
{
//--- if editing is enabled, send the ON_START_EDIT notification
if(!m_read_only)
{
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name);
//--- handled
return(true);
}
//--- else send the ON_CLICK notification
return(CWnd::OnClick());
}
//+------------------------------------------------------------------+
+93
View File
@@ -0,0 +1,93 @@
//+------------------------------------------------------------------+
//| Label.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CLabel |
//| Usage: control that is displayed by |
//| the CChartObjectLabel object |
//+------------------------------------------------------------------+
class CLabel : public CWndObj
{
private:
CChartObjectLabel m_label; // chart object
public:
CLabel(void);
~CLabel(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
protected:
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_label.Description(m_text)); }
virtual bool OnSetColor(void) { return(m_label.Color(m_color)); }
virtual bool OnSetFont(void) { return(m_label.Font(m_font)); }
virtual bool OnSetFontSize(void) { return(m_label.FontSize(m_font_size)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CLabel::CLabel(void)
{
m_color=CONTROLS_LABEL_COLOR;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CLabel::~CLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CLabel::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_label.Create(chart,name,subwin,x1,y1))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CLabel::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_label.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CLabel::OnShow(void)
{
return(m_label.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CLabel::OnHide(void)
{
return(m_label.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CLabel::OnMove(void)
{
//--- position the chart object
return(m_label.X_Distance(m_rect.left) && m_label.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
+544
View File
@@ -0,0 +1,544 @@
//+------------------------------------------------------------------+
//| ListView.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndClient.mqh"
#include "Edit.mqh"
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayLong.mqh>
//+------------------------------------------------------------------+
//| Class CListView |
//| Usage: display lists |
//+------------------------------------------------------------------+
class CListView : public CWndClient
{
private:
//--- dependent controls
CEdit m_rows[]; // array of the row objects
//--- set up
int m_offset; // index of first visible row in array of rows
int m_total_view; // number of visible rows
int m_item_height; // height of visible row
bool m_height_variable; // ïðèçíàê ïåðåìåííîé âûñîòû ñïèñêà
//--- data
CArrayString m_strings; // array of rows
CArrayLong m_values; // array of values
int m_current; // index of current row in array of rows
public:
CListView(void);
~CListView(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
bool TotalView(const int value);
//--- fill
virtual bool AddItem(const string item,const long value=0);
//--- data
virtual bool ItemAdd(const string item,const long value=0);
virtual bool ItemInsert(const int index,const string item,const long value=0);
virtual bool ItemUpdate(const int index,const string item,const long value=0);
virtual bool ItemDelete(const int index);
virtual bool ItemsClear(void);
//--- data
int Current(void) { return(m_current); }
string Select(void) { return(m_strings.At(m_current)); }
bool Select(const int index);
bool SelectByText(const string text);
bool SelectByValue(const long value);
//--- data (read only)
long Value(void) { return(m_values.At(m_current)); }
//--- state
virtual bool Show(void);
protected:
//--- create dependent controls
bool CreateRow(const int index);
//--- event handlers
virtual bool OnResize(void);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void);
virtual bool OnVScrollHide(void);
virtual bool OnScrollLineDown(void);
virtual bool OnScrollLineUp(void);
virtual bool OnItemClick(const int index);
//--- redraw
bool Redraw(void);
bool RowState(const int index,const bool select);
bool CheckView(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CListView)
ON_INDEXED_EVENT(ON_CLICK,m_rows,OnItemClick)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CListView::CListView(void) : m_offset(0),
m_total_view(0),
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
m_current(CONTROLS_INVALID_INDEX),
m_height_variable(false)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CListView::~CListView(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CListView::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
int y=y2;
//--- if the number of visible rows is previously determined, adjust the vertical size
if(!TotalView((y2-y1)/m_item_height))
y=m_item_height+y1+2*CONTROLS_BORDER_WIDTH;
//--- check the number of visible rows
if(m_total_view<1)
return(false);
//--- call method of the parent class
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y))
return(false);
//--- set up
if(!m_background.ColorBackground(CONTROLS_LIST_COLOR_BG))
return(false);
if(!m_background.ColorBorder(CONTROLS_LIST_COLOR_BORDER))
return(false);
//--- create dependent controls
ArrayResize(m_rows,m_total_view);
for(int i=0;i<m_total_view;i++)
{
if(!CreateRow(i))
return(false);
if(m_height_variable && i>0)
m_rows[i].Hide();
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CListView::Destroy(const int reason)
{
//--- call of the method of the parent class
CWndClient::Destroy(reason);
//--- clear items
m_strings.Clear();
m_values.Clear();
//---
m_offset =0;
m_total_view=0;
}
//+------------------------------------------------------------------+
//| Set parameter |
//+------------------------------------------------------------------+
bool CListView::TotalView(const int value)
{
//--- if parameter is not equal to 0, modifications are not possible
if(m_total_view!=0)
{
m_height_variable=true;
return(false);
}
//--- save value
m_total_view=value;
//--- parameter has been changed
return(true);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CListView::Show(void)
{
//--- call of the method of the parent class
CWndClient::Show();
//--- number of items
int total=m_strings.Total();
//---
if(total==0)
total=1;
//---
if(m_height_variable && total<m_total_view)
for(int i=total;i<m_total_view;i++)
m_rows[i].Hide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create "row" |
//+------------------------------------------------------------------+
bool CListView::CreateRow(const int index)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
int x2=Width()-2*CONTROLS_BORDER_WIDTH;
int y2=y1+m_item_height;
//--- create
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
return(false);
if(!m_rows[index].Text(""))
return(false);
if(!m_rows[index].ReadOnly(true))
return(false);
if(!RowState(index,false))
return(false);
if(!Add(m_rows[index]))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CListView::AddItem(const string item,const long value)
{
//--- method left for compatibility with previous version
return(ItemAdd(item,value));
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemAdd(const string item,const long value)
{
//--- add
if(!m_strings.Add(item))
return(false);
if(!m_values.Add((value)?value:m_values.Total()))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(m_height_variable && total!=1)
{
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
if(IS_VISIBLE)
m_rows[total-1].Show();
}
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(IS_VISIBLE && !OnVScrollShow())
return(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Insert item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemInsert(const int index,const string item,const long value)
{
//--- insert
if(!m_strings.Insert(item,index))
return(false);
if(!m_values.Insert(value,index))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(m_height_variable && total!=1)
{
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
if(IS_VISIBLE)
m_rows[total-1].Show();
}
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(IS_VISIBLE && !OnVScrollShow())
return(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Update item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemUpdate(const int index,const string item,const long value)
{
//--- update
if(!m_strings.Update(index,item))
return(false);
if(!m_values.Update(index,value))
return(false);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Delete item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemDelete(const int index)
{
//--- delete
if(!m_strings.Delete(index))
return(false);
if(!m_values.Delete(index))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view)
{
if(m_height_variable && total!=0)
{
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
m_rows[total].Hide();
}
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view)
{
//--- disable vertical scrollbar
if(!VScrolled(false))
return(false);
//--- and immediately make it unvisible
if(!OnVScrollHide())
return(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Delete all items |
//+------------------------------------------------------------------+
bool CListView::ItemsClear(void)
{
m_offset=0;
//--- clear
if(!m_strings.Shutdown())
return(false);
if(!m_values.Shutdown())
return(false);
//---
if(m_height_variable)
{
Height(m_item_height+2*CONTROLS_BORDER_WIDTH);
for(int i=1;i<m_total_view;i++)
m_rows[i].Hide();
}
//--- disable vertical scrollbar
if(!VScrolled(false))
return(false);
//--- and immediately make it unvisible (if needed)
if(!OnVScrollHide())
return(false);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Sett current item |
//+------------------------------------------------------------------+
bool CListView::Select(const int index)
{
//--- check index
if(index>=m_strings.Total())
return(false);
if(index<0 && index!=CONTROLS_INVALID_INDEX)
return(false);
//--- unselect
if(m_current!=CONTROLS_INVALID_INDEX)
RowState(m_current-m_offset,false);
//--- select
if(index!=CONTROLS_INVALID_INDEX)
RowState(index-m_offset,true);
//--- save value
m_current=index;
//--- succeed
return(CheckView());
}
//+------------------------------------------------------------------+
//| Set current item (by text) |
//+------------------------------------------------------------------+
bool CListView::SelectByText(const string text)
{
//--- find text
int index=m_strings.SearchLinear(text);
//--- if text is not found, exit without changing the selection
if(index==CONTROLS_INVALID_INDEX)
return(false);
//--- change selection
return(Select(index));
}
//+------------------------------------------------------------------+
//| Set current item (by value) |
//+------------------------------------------------------------------+
bool CListView::SelectByValue(const long value)
{
//--- find value
int index=m_values.SearchLinear(value);
//--- if value is not found, exit without changing the selection
if(index==CONTROLS_INVALID_INDEX)
return(false);
//--- change selection
return(Select(index));
}
//+------------------------------------------------------------------+
//| Redraw |
//+------------------------------------------------------------------+
bool CListView::Redraw(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- copy text
if(!m_rows[i].Text(m_strings.At(i+m_offset)))
return(false);
//--- select
if(!RowState(i,(m_current==i+m_offset)))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Change state |
//+------------------------------------------------------------------+
bool CListView::RowState(const int index,const bool select)
{
//--- check index
if(index<0 || index>=ArraySize(m_rows))
return(true);
//--- determine colors
color text_color=(select) ? CONTROLS_LISTITEM_COLOR_TEXT_SEL : CONTROLS_LISTITEM_COLOR_TEXT;
color back_color=(select) ? CONTROLS_LISTITEM_COLOR_BG_SEL : CONTROLS_LISTITEM_COLOR_BG;
//--- get pointer
CEdit *item=GetPointer(m_rows[index]);
//--- recolor the "row"
return(item.Color(text_color) && item.ColorBackground(back_color) && item.ColorBorder(back_color));
}
//+------------------------------------------------------------------+
//| Check visibility of selected row |
//+------------------------------------------------------------------+
bool CListView::CheckView(void)
{
//--- check visibility
if(m_current>=m_offset && m_current<m_offset+m_total_view)
return(true);
//--- selected row is not visible
int total=m_strings.Total();
m_offset=(total-m_current>m_total_view) ? m_current : total-m_total_view;
//--- adjust the scrollbar
m_scroll_v.CurrPos(m_offset);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CListView::OnResize(void)
{
//--- call of the method of the parent class
if(!CWndClient::OnResize())
return(false);
//--- set up the size of "row"
if(VScrolled())
OnVScrollShow();
else
OnVScrollHide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Show vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CListView::OnVScrollShow(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to shown vertical scrollbar
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
}
//--- check visibility
if(!IS_VISIBLE)
{
m_scroll_v.Visible(false);
return(true);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CListView::OnVScrollHide(void)
{
//--- check visibility
if(!IS_VISIBLE)
return(true);
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to hidden vertical scroll bar
m_rows[i].Width(Width()-2*CONTROLS_BORDER_WIDTH);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll up for one row" event |
//+------------------------------------------------------------------+
bool CListView::OnScrollLineUp(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll down for one row" event |
//+------------------------------------------------------------------+
bool CListView::OnScrollLineDown(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of click on row |
//+------------------------------------------------------------------+
bool CListView::OnItemClick(const int index)
{
//--- select "row"
Select(index+m_offset);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
+124
View File
@@ -0,0 +1,124 @@
//+------------------------------------------------------------------+
//| Panel.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CPanel |
//| Usage: control that is displayed by |
//| the CChartObjectRectLabel object |
//+------------------------------------------------------------------+
class CPanel : public CWndObj
{
private:
CChartObjectRectLabel m_rectangle; // chart object
//--- parameters of the chart object
ENUM_BORDER_TYPE m_border; // border type
public:
CPanel(void);
~CPanel(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- parameters of the chart object
ENUM_BORDER_TYPE BorderType(void) const { return(m_border); }
bool BorderType(const ENUM_BORDER_TYPE type);
protected:
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_rectangle.Description(m_text)); }
virtual bool OnSetColorBackground(void) { return(m_rectangle.BackColor(m_color_background)); }
virtual bool OnSetColorBorder(void) { return(m_rectangle.Color(m_color_border)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnResize(void);
virtual bool OnChange(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CPanel::CPanel(void) : m_border(BORDER_FLAT)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CPanel::~CPanel(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CPanel::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_rectangle.Create(chart,name,subwin,x1,y1,Width(),Height()))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set border type |
//+------------------------------------------------------------------+
bool CPanel::BorderType(const ENUM_BORDER_TYPE type)
{
//--- save new value of parameter
m_border=type;
//--- set up the chart object
return(m_rectangle.BorderType(type));
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CPanel::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_rectangle.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CPanel::OnShow(void)
{
return(m_rectangle.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CPanel::OnHide(void)
{
return(m_rectangle.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CPanel::OnMove(void)
{
//--- position the chart object
return(m_rectangle.X_Distance(m_rect.left) && m_rectangle.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CPanel::OnResize(void)
{
//--- resize the chart object
return(m_rectangle.X_Size(m_rect.Width()) && m_rectangle.Y_Size(m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CPanel::OnChange(void)
{
//--- set up the chart object
return(CWndObj::OnChange() && m_rectangle.BorderType(m_border));
}
//+------------------------------------------------------------------+
+125
View File
@@ -0,0 +1,125 @@
//+------------------------------------------------------------------+
//| Picture.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsBmpControls.mqh>
//+------------------------------------------------------------------+
//| Class CPicture |
//| Note: image displayed by |
//| the CChartObjectBmpLabel object |
//+------------------------------------------------------------------+
class CPicture : public CWndObj
{
private:
CChartObjectBmpLabel m_picture; // chart object
//--- parameters of the chart object
int m_border; // border width
string m_bmp_name; // filename
public:
CPicture(void);
~CPicture(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- parameters of the chart object
int Border(void) const { return(m_border); }
bool Border(const int value);
string BmpName(void) const { return(m_bmp_name); }
bool BmpName(const string name);
protected:
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnChange(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CPicture::CPicture(void) : m_border(0),
m_bmp_name(NULL)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CPicture::~CPicture(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CPicture::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_picture.Create(chart,name,subwin,x1,y1))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set border width |
//+------------------------------------------------------------------+
bool CPicture::Border(const int value)
{
//--- save new value of parameter
m_border=value;
//--- set up the chart object
return(m_picture.Width(value));
}
//+------------------------------------------------------------------+
//| Set image |
//+------------------------------------------------------------------+
bool CPicture::BmpName(const string name)
{
//--- save new value of parameter
m_bmp_name=name;
//--- set up the chart object
return(m_picture.BmpFileOn(name));
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CPicture::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_picture.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CPicture::OnShow(void)
{
return(m_picture.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CPicture::OnHide(void)
{
return(m_picture.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CPicture::OnMove(void)
{
//--- position the chart object
return(m_picture.X_Distance(m_rect.left) && m_picture.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CPicture::OnChange(void)
{
//--- set up the chart object
return(m_picture.Width(m_border) && m_picture.BmpFileOn(m_bmp_name));
}
//+------------------------------------------------------------------+
+160
View File
@@ -0,0 +1,160 @@
//+------------------------------------------------------------------+
//| RadioButton.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "BmpButton.mqh"
#include "Edit.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "res\\RadioButtonOn.bmp"
#resource "res\\RadioButtonOff.bmp"
//+------------------------------------------------------------------+
//| Class CRadioButton |
//| Usage: class that implements the "RadioButton" control |
//+------------------------------------------------------------------+
class CRadioButton : public CWndContainer
{
private:
//--- dependent controls
CBmpButton m_button; // button object
CEdit m_label; // label object
public:
CRadioButton(void);
~CRadioButton(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- settings
string Text(void) const { return(m_label.Text()); }
bool Text(const string value) { return(m_label.Text(value)); }
color Color(void) const { return(m_label.Color()); }
bool Color(const color value) { return(m_label.Color(value)); }
//--- state
bool State(void) const { return(m_button.Pressed()); }
bool State(const bool flag) { return(m_button.Pressed(flag)); }
protected:
//--- create dependent controls
virtual bool CreateButton(void);
virtual bool CreateLabel(void);
//--- handlers of the dependent controls events
virtual bool OnClickButton(void);
virtual bool OnClickLabel(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CRadioButton)
ON_EVENT(ON_CLICK,m_button,OnClickButton)
ON_EVENT(ON_CLICK,m_label,OnClickLabel)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CRadioButton::CRadioButton(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CRadioButton::~CRadioButton(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CRadioButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateButton())
return(false);
if(!CreateLabel())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CRadioButton::CreateButton(void)
{
//--- calculate coordinates
int x1=CONTROLS_RADIO_BUTTON_X_OFF;
int y1=CONTROLS_RADIO_BUTTON_Y_OFF;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH;
//--- create
if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button.BmpNames("::res\\RadioButtonOff.bmp","::res\\RadioButtonOn.bmp"))
return(false);
if(!Add(m_button))
return(false);
m_button.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create label |
//+------------------------------------------------------------------+
bool CRadioButton::CreateLabel(void)
{
//--- calculate coordinates
int x1=CONTROLS_RADIO_LABEL_X_OFF;
int y1=CONTROLS_RADIO_LABEL_Y_OFF;
int x2=Width();
int y2=Height();
//--- create
if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_label.Text(m_name))
return(false);
if(!Add(m_label))
return(false);
m_label.ReadOnly(true);
m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG);
m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CRadioButton::OnClickButton(void)
{
//--- if button is in the "turned off" state, turn it on again and complete the handling
//--- this is due to that radio button can not be turned off by clicking on it (it can be only turned on)
if(!m_button.Pressed())
{
//--- turn on the radio button
if(!m_button.Pressed(true))
return(false);
}
//--- send the "changed state" event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on label |
//+------------------------------------------------------------------+
bool CRadioButton::OnClickLabel(void)
{
//--- if button is in the "turned on" state, simply complete the handling
//--- this is due to that radio button can not be turned off by clicking on it (it can be only turned on)
if(m_button.Pressed())
return(true);
//--- turn on the radio button
m_button.Pressed(true);
//--- return the result of the button click handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
+361
View File
@@ -0,0 +1,361 @@
//+------------------------------------------------------------------+
//| RadioGroup.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndClient.mqh"
#include "RadioButton.mqh"
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayLong.mqh>
//+------------------------------------------------------------------+
//| Class CRadioGroup |
//| Usage: view and edit radio buttons |
//+------------------------------------------------------------------+
class CRadioGroup : public CWndClient
{
private:
//--- dependent controls
CRadioButton m_rows[]; // array of the row objects
//--- set up
int m_offset; // index of first visible row in array of rows
int m_total_view; // number of visible rows
int m_item_height; // height of visible row
//--- data
CArrayString m_strings; // array of rows
CArrayLong m_values; // array of values
int m_current; // index of current row in array of rows
public:
CRadioGroup(void);
~CRadioGroup(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- fill
virtual bool AddItem(const string item,const long value=0);
//--- data
long Value(void) const { return(m_values.At(m_current)); }
bool Value(const long value);
bool ValueCheck(long value) const;
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
bool CreateButton(const int index);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void);
virtual bool OnVScrollHide(void);
virtual bool OnScrollLineDown(void);
virtual bool OnScrollLineUp(void);
virtual bool OnChangeItem(const int row_index);
//--- redraw
bool Redraw(void);
bool RowState(const int index,const bool select);
void Select(const int index);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CRadioGroup)
ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CRadioGroup::CRadioGroup(void) : m_offset(0),
m_total_view(0),
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
m_current(CONTROLS_INVALID_INDEX)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CRadioGroup::~CRadioGroup(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CRadioGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- determine the number of visible rows
m_total_view=(y2-y1)/m_item_height;
//--- check the number of visible rows
if(m_total_view<1)
return(false);
//--- call method of the parent class
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- set up
if(!m_background.ColorBackground(CONTROLS_RADIOGROUP_COLOR_BG))
return(false);
if(!m_background.ColorBorder(CONTROLS_RADIOGROUP_COLOR_BORDER))
return(false);
//--- create dependent controls
ArrayResize(m_rows,m_total_view);
for(int i=0;i<m_total_view;i++)
if(!CreateButton(i))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CRadioGroup::Destroy(const int reason)
{
//--- call of the method of the parent class
CWndClient::Destroy(reason);
//--- clear items
m_strings.Clear();
m_values.Clear();
}
//+------------------------------------------------------------------+
//| Create "row" |
//+------------------------------------------------------------------+
bool CRadioGroup::CreateButton(const int index)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=y1+m_item_height;
//--- create
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
return(false);
if(!m_rows[index].Text(""))
return(false);
if(!Add(m_rows[index]))
return(false);
m_rows[index].Hide();
//---
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CRadioGroup::AddItem(const string item,const long value)
{
//--- check value
if(value!=0 && !ValueCheck(value))
return(false);
//--- add
if(!m_strings.Add(item))
return(false);
if(!m_values.Add(value))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(IS_VISIBLE && total!=0)
m_rows[total-1].Show();
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(!IS_VISIBLE)
m_scroll_v.Visible(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::Value(const long value)
{
//--- çíà÷åíèå äîëæíî ïðèñóòñòâîâàòü â íàáîðå
int total=m_values.Total();
//---
for(int i=0;i<total;i++)
if(m_values.At(i)==value)
Select(i+m_offset);
//---
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::ValueCheck(long value) const
{
//--- ïðîâåðÿåìîå çíà÷åíèå íå äîëæíî äóáëèðîâàòü óæå ñóùåñòâóþùåå
int total=m_values.Total();
//---
for(int i=0;i<total;i++)
if(m_values.At(i)==value)
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Makes the group visible |
//+------------------------------------------------------------------+
bool CRadioGroup::Show(void)
{
//--- call of the method of the parent class
if(!CWndClient::Show())
return(false);
//--- loop by rows
int total=m_values.Total();
for(int i=total;i<m_total_view;i++)
m_rows[i].Hide();
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Value(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Sett current item |
//+------------------------------------------------------------------+
void CRadioGroup::Select(const int index)
{
//--- disable the "ON" state
if(m_current!=-1)
RowState(m_current-m_offset,false);
//--- enable the "ON" state
if(index!=-1)
RowState(index-m_offset,true);
//--- save value
m_current=index;
}
//+------------------------------------------------------------------+
//| Redraw |
//+------------------------------------------------------------------+
bool CRadioGroup::Redraw(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- copy text
if(!m_rows[i].Text(m_strings.At(i+m_offset)))
return(false);
//--- select
if(!RowState(i,(m_current==i+m_offset)))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Change state |
//+------------------------------------------------------------------+
bool CRadioGroup::RowState(const int index,const bool select)
{
//--- check index
if(index<0 || index>=ArraySize(m_rows))
return(true);
//--- change state
return(m_rows[index].State(select));
}
//+------------------------------------------------------------------+
//| Handler of the "Show vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnVScrollShow(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to shown vertical scrollbar
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
}
//--- check visibility
if(!IS_VISIBLE)
{
m_scroll_v.Visible(false);
return(true);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnVScrollHide(void)
{
//--- check visibility
if(!IS_VISIBLE)
return(true);
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to hidden vertical scroll bar
m_rows[i].Width(Width()-CONTROLS_BORDER_WIDTH);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll up for one row" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnScrollLineUp(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll down for one row" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnScrollLineDown(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of changing a "row" state |
//+------------------------------------------------------------------+
bool CRadioGroup::OnChangeItem(const int row_index)
{
//--- select "row"
Select(row_index+m_offset);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
+279
View File
@@ -0,0 +1,279 @@
//+------------------------------------------------------------------+
//| Rect.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Structure CPoint |
//| Usage: point of chart in Cartesian coordinates |
//+------------------------------------------------------------------+
struct CPoint
{
int x; // horizontal coordinate
int y; // vertical coordinate
};
//+------------------------------------------------------------------+
//| Structure CSize |
//| Usage: size of area of chart in Cartesian coordinates |
//+------------------------------------------------------------------+
struct CSize
{
int cx; // horizontal size
int cy; // vertical size
};
//+------------------------------------------------------------------+
//| Structure CRect |
//| Usage: area of chart in Cartesian coordinates |
//+------------------------------------------------------------------+
struct CRect
{
int left; // left coordinate
int top; // top coordinate
int right; // right coordinate
int bottom; // bottom coordinate
//--- methods
CPoint LeftTop(void) const;
void LeftTop(const int x,const int y);
void LeftTop(const CPoint& point);
CPoint RightBottom(void) const;
void RightBottom(const int x,const int y);
void RightBottom(const CPoint& point);
CPoint CenterPoint(void) const;
int Width(void) const { return(right-left); }
void Width(const int w) { right=left+w; }
int Height(void) const { return(bottom-top); }
void Height(const int h) { bottom=top+h; }
CSize Size(void) const;
void Size(const int cx,const int cy);
void Size(const CSize& size);
void SetBound(const int l,const int t,const int r,const int b);
void SetBound(const CRect& rect);
void SetBound(const CPoint& point,const CSize& size);
void SetBound(const CPoint& left_top,const CPoint& right_bottom);
void Move(const int x,const int y);
void Move(const CPoint& point);
void Shift(const int dx,const int dy);
void Shift(const CPoint& point);
void Shift(const CSize& size);
bool Contains(const int x,const int y) const;
bool Contains(const CPoint& point) const;
void Normalize(void);
};
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CPoint CRect::LeftTop(void) const
{
CPoint point;
//--- action
point.x=left;
point.y=top;
//--- result
return(point);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::LeftTop(const int x,const int y)
{
left=x;
top =y;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::LeftTop(const CPoint& point)
{
left=point.x;
top =point.y;
}
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CPoint CRect::RightBottom(void) const
{
CPoint point;
//--- action
point.x=right;
point.y=bottom;
//--- result
return(point);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::RightBottom(const int x,const int y)
{
right =x;
bottom=y;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::RightBottom(const CPoint& point)
{
right =point.x;
bottom=point.y;
}
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CPoint CRect::CenterPoint(void) const
{
CPoint point;
//--- action
point.x=left+Width()/2;
point.y=top+Height()/2;
//--- result
return(point);
}
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CSize CRect::Size(void) const
{
CSize size;
//--- action
size.cx=right-left;
size.cy=bottom-top;
//--- result
return(size);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::Size(const int cx,const int cy)
{
right =left+cx;
bottom=top+cy;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::Size(const CSize& size)
{
right =left+size.cx;
bottom=top+size.cy;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const int l,const int t,const int r,const int b)
{
left =l;
top =t;
right =r;
bottom=b;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const CRect& rect)
{
left =rect.left;
top =rect.top;
right =rect.right;
bottom=rect.bottom;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const CPoint& point,const CSize& size)
{
LeftTop(point);
Size(size);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const CPoint& left_top,const CPoint& right_bottom)
{
LeftTop(left_top);
RightBottom(right_bottom);
}
//+------------------------------------------------------------------+
//| Absolute movement of area |
//+------------------------------------------------------------------+
void CRect::Move(const int x,const int y)
{
right +=x-left;
bottom+=y-top;
left =x;
top =y;
}
//+------------------------------------------------------------------+
//| Absolute movement of area |
//+------------------------------------------------------------------+
void CRect::Move(const CPoint& point)
{
right +=point.x-left;
bottom+=point.y-top;
left =point.x;
top =point.y;
}
//+------------------------------------------------------------------+
//| Relative movement of area |
//+------------------------------------------------------------------+
void CRect::Shift(const int dx,const int dy)
{
left +=dx;
top +=dy;
right +=dx;
bottom+=dy;
}
//+------------------------------------------------------------------+
//| Relative movement of area |
//+------------------------------------------------------------------+
void CRect::Shift(const CPoint& point)
{
left +=point.x;
top +=point.y;
right +=point.x;
bottom+=point.y;
}
//+------------------------------------------------------------------+
//| Relative movement of area |
//+------------------------------------------------------------------+
void CRect::Shift(const CSize& size)
{
left +=size.cx;
top +=size.cy;
right +=size.cx;
bottom+=size.cy;
}
//+------------------------------------------------------------------+
//| Check if a point is within the area |
//+------------------------------------------------------------------+
bool CRect::Contains(const int x,const int y) const
{
//--- check and return the result
return(x>=left && x<=right && y>=top && y<=bottom);
}
//+------------------------------------------------------------------+
//| Check if a point is within the area |
//+------------------------------------------------------------------+
bool CRect::Contains(const CPoint& point) const
{
//--- check and return the result
return(point.x>=left && point.x<=right && point.y>=top && point.y<=bottom);
}
//+------------------------------------------------------------------+
//| Standardizes the height and width |
//+------------------------------------------------------------------+
void CRect::Normalize(void)
{
if(left>right)
{
int tmp1=left;
left=right;
right=tmp1;
}
if(top>bottom)
{
int tmp2=top;
top=bottom;
bottom=tmp2;
}
}
//+------------------------------------------------------------------+
+675
View File
@@ -0,0 +1,675 @@
//+------------------------------------------------------------------+
//| Scrolls.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "Panel.mqh"
#include "BmpButton.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "res\\Up.bmp"
#resource "res\\ThumbVert.bmp"
#resource "res\\Down.bmp"
#resource "res\\Left.bmp"
#resource "res\\ThumbHor.bmp"
#resource "res\\Right.bmp"
//+------------------------------------------------------------------+
//| Class CScroll |
//| Usage: base class for scrollbars |
//+------------------------------------------------------------------+
class CScroll : public CWndContainer
{
protected:
//--- dependent controls
CPanel m_back; // the "scrollbar background" object
CBmpButton m_inc; // the "increment button" object ("down" for vertical scrollbar, "right" for horizontal scrollbar)
CBmpButton m_dec; // the "decrement button" object ("up" for vertical scrollbar, "left" for horizontal scrollbar)
CBmpButton m_thumb; // the "scroll box" object
//--- set up
int m_min_pos; // minimum value
int m_max_pos; // maximum value
//--- state
int m_curr_pos; // current value
public:
CScroll(void);
~CScroll(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
int MinPos(void) const { return(m_min_pos); }
void MinPos(const int value);
int MaxPos(void) const { return(m_max_pos); }
void MaxPos(const int value);
//--- state
int CurrPos(void) const { return(m_curr_pos); }
bool CurrPos(int value);
protected:
//--- create dependent controls
virtual bool CreateBack(void);
virtual bool CreateInc(void) { return(true); }
virtual bool CreateDec(void) { return(true); }
virtual bool CreateThumb(void) { return(true); }
//--- handlers of the dependent controls events
virtual bool OnClickInc(void);
virtual bool OnClickDec(void);
//--- internal event handlers
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnChangePos(void) { return(true); }
//--- handlers of dragging
virtual bool OnThumbDragStart(void) { return(true); }
virtual bool OnThumbDragProcess(void) { return(true); }
virtual bool OnThumbDragEnd(void) { return(true); }
//--- calculate position by coordinate
virtual int CalcPos(const int coord) { return(0); }
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CScroll)
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
ON_EVENT(ON_DRAG_START,m_thumb,OnThumbDragStart)
ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnThumbDragProcess)
ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnThumbDragEnd)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CScroll::CScroll(void) : m_curr_pos(0),
m_min_pos(0),
m_max_pos(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CScroll::~CScroll(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CScroll::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateBack())
return(false);
if(!CreateInc())
return(false);
if(!CreateDec())
return(false);
if(!CreateThumb())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scrollbar background |
//+------------------------------------------------------------------+
bool CScroll::CreateBack(void)
{
//--- create
if(!m_back.Create(m_chart_id,m_name+"Back",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_back.ColorBackground(CONTROLS_SCROLL_COLOR_BG))
return(false);
if(!m_back.ColorBorder(CONTROLS_SCROLL_COLOR_BORDER))
return(false);
if(!Add(m_back))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set current value |
//+------------------------------------------------------------------+
bool CScroll::CurrPos(int value)
{
//--- check value
if(value<m_min_pos)
value=m_min_pos;
if(value>m_max_pos)
value=m_max_pos;
//--- if value was changed
if(m_curr_pos!=value)
{
m_curr_pos=value;
//--- call virtual handler
return(OnChangePos());
}
//--- value has not been changed
return(false);
}
//+------------------------------------------------------------------+
//| Set minimum value |
//+------------------------------------------------------------------+
void CScroll::MinPos(const int value)
{
//--- if value was changed
if(m_min_pos!=value)
{
m_min_pos=value;
//--- adjust the scroll box position
CurrPos(m_curr_pos);
}
}
//+------------------------------------------------------------------+
//| Set maximum value |
//+------------------------------------------------------------------+
void CScroll::MaxPos(const int value)
{
//--- if value was changed
if(m_max_pos!=value)
{
m_max_pos=value;
//--- adjust the scroll box position
CurrPos(m_curr_pos);
}
}
//+------------------------------------------------------------------+
//| Handler of the "Show scrollbar" event |
//+------------------------------------------------------------------+
bool CScroll::OnShow(void)
{
if(m_id==CONTROLS_INVALID_ID)
return(true);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SHOW,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide scrollbar" event |
//+------------------------------------------------------------------+
bool CScroll::OnHide(void)
{
if(m_id==CONTROLS_INVALID_ID)
return(true);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_HIDE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the "increment" button |
//+------------------------------------------------------------------+
bool CScroll::OnClickInc(void)
{
//--- try to increment current value
if(!CurrPos(m_curr_pos+1))
return(true);
//--- if value was changed, send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SCROLL_INC,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the "decrement" button |
//+------------------------------------------------------------------+
bool CScroll::OnClickDec(void)
{
//--- try to decrement current value
if(!CurrPos(m_curr_pos-1))
return(true);
//--- if value was changed, send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SCROLL_DEC,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Class CScrollV |
//| Usage: class of vertical scrollbar |
//+------------------------------------------------------------------+
class CScrollV : public CScroll
{
public:
CScrollV(void);
~CScrollV(void);
protected:
//--- create dependent controls
virtual bool CreateInc(void);
virtual bool CreateDec(void);
virtual bool CreateThumb(void);
//--- internal event handlers
virtual bool OnResize(void);
virtual bool OnChangePos(void);
//--- handlers of dragging
virtual bool OnThumbDragStart(void);
virtual bool OnThumbDragProcess(void);
virtual bool OnThumbDragEnd(void);
//--- calculate position by coordinate
virtual int CalcPos(const int coord);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CScrollV::CScrollV(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CScrollV::~CScrollV(void)
{
}
//+------------------------------------------------------------------+
//| Create the "Increment" button |
//+------------------------------------------------------------------+
bool CScrollV::CreateInc(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=Height()-CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::res\\Down.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- property
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Decrement" button |
//+------------------------------------------------------------------+
bool CScrollV::CreateDec(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::res\\Up.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//--- property
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scroll box |
//+------------------------------------------------------------------+
bool CScrollV::CreateThumb(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_SCROLL_THUMB_SIZE;
//--- create
if(!m_thumb.Create(m_chart_id,m_name+"Thumb",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_thumb.BmpNames("::res\\ThumbVert.bmp"))
return(false);
if(!Add(m_thumb))
return(false);
m_thumb.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of changing current state |
//+------------------------------------------------------------------+
bool CScrollV::OnChangePos(void)
{
//--- check if scrolling is possible
if(m_max_pos-m_min_pos<=0)
return(Visible(false));
else
if(!Visible(true))
return(false);
//--- calculate new coordinated of the scrollbar
int steps =m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Bottom(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Top()-m_thumb.Height(); // maximum possible coordinate (corresponds to the m_max_pos value)
int new_coord=min_coord+(max_coord-min_coord)*m_curr_pos/steps; // new coordinate
//--- adjust the scroll box position
return(m_thumb.Move(m_thumb.Left(),new_coord));
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CScrollV::OnResize(void)
{
//--- can not change the lateral size
if(Width()!=CONTROLS_SCROLL_SIZE)
m_rect.Width(CONTROLS_SCROLL_SIZE);
//--- resize the scrollbar background
if(!m_back.Size(Size()))
return(false);
//--- move the "Increment" button
if(!m_inc.Move(m_inc.Left(),Bottom()-CONTROLS_SCROLL_SIZE))
return(false);
//--- adjust the scroll box position
return(OnChangePos());
}
//+------------------------------------------------------------------+
//| Start dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollV::OnThumbDragStart(void)
{
if(m_drag_object==NULL)
{
m_drag_object=new CDragWnd;
if(m_drag_object==NULL)
return(false);
}
//--- calculate coordinates
int x1=m_thumb.Left()-CONTROLS_DRAG_SPACING;
int y1=m_thumb.Top()-CONTROLS_DRAG_SPACING;
int x2=m_thumb.Right()+CONTROLS_DRAG_SPACING;
int y2=m_thumb.Bottom()+CONTROLS_DRAG_SPACING;
//--- create
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- îãðàíè÷åíèÿ
m_drag_object.Limits(x1,m_dec.Bottom()-CONTROLS_DRAG_SPACING,x2,m_inc.Top()+CONTROLS_DRAG_SPACING);
//--- set mouse params
m_drag_object.MouseX(m_thumb.MouseX());
m_drag_object.MouseY(m_thumb.MouseY());
m_drag_object.MouseFlags(m_thumb.MouseFlags());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Continue dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollV::OnThumbDragProcess(void)
{
//--- checking
if(m_drag_object==NULL)
return(false);
//--- calculate coordinates
int x=m_drag_object.Left()+CONTROLS_DRAG_SPACING;
int y=m_drag_object.Top()+CONTROLS_DRAG_SPACING;
//--- calculate new position
int new_pos=CalcPos(y);
if(new_pos!=m_curr_pos)
{
ushort event_id=(m_curr_pos<new_pos) ? ON_SCROLL_INC : ON_SCROLL_DEC;
m_curr_pos=new_pos;
EventChartCustom(CONTROLS_SELF_MESSAGE,event_id,m_id,0.0,m_name);
}
//--- move thumb
m_thumb.Move(x,y);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| End dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollV::OnThumbDragEnd(void)
{
if(m_drag_object!=NULL)
{
m_thumb.MouseFlags(m_drag_object.MouseFlags());
delete m_drag_object;
m_drag_object=NULL;
}
//--- succeed
return(m_thumb.Pressed(false));
}
//+------------------------------------------------------------------+
//| Calculate position by coordinate |
//+------------------------------------------------------------------+
int CScrollV::CalcPos(const int coord)
{
//--- calculate new position of the scrollbar
int steps =m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Bottom(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Top()-m_thumb.Height(); // maximum possible coordinate (corresponds to the m_max_pos value)
//--- checkeng
if(max_coord==min_coord)
return(0);
if(coord<min_coord || coord>max_coord)
return(m_curr_pos);
//---
int new_pos=(int)MathRound((((double)(coord-min_coord))/(max_coord-min_coord))*steps); // new position
//---
return(new_pos);
}
//+------------------------------------------------------------------+
//| Class CScrollH |
//| Usage: class of horizontal scrollbar |
//+------------------------------------------------------------------+
class CScrollH : public CScroll
{
public:
CScrollH(void);
~CScrollH(void);
protected:
//--- create dependent controls
virtual bool CreateInc(void);
virtual bool CreateDec(void);
virtual bool CreateThumb(void);
//--- internal event handlers
virtual bool OnResize(void);
virtual bool OnChangePos(void);
//--- handlers of dragging
virtual bool OnThumbDragStart(void);
virtual bool OnThumbDragProcess(void);
virtual bool OnThumbDragEnd(void);
//--- calculate position by coordinate
virtual int CalcPos(const int coord);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CScrollH::CScrollH(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CScrollH::~CScrollH(void)
{
}
//+------------------------------------------------------------------+
//| Create the "Increment" button |
//+------------------------------------------------------------------+
bool CScrollH::CreateInc(void)
{
//--- calculate coordinates
int x1=Width()-CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::res\\Right.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- property
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Decrement" button |
//+------------------------------------------------------------------+
bool CScrollH::CreateDec(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::res\\Left.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//--- property
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scroll box |
//+------------------------------------------------------------------+
bool CScrollH::CreateThumb(void)
{
//--- calculate coordinates
int x1=CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_SCROLL_THUMB_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_thumb.Create(m_chart_id,m_name+"Thumb",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_thumb.BmpNames("::res\\ThumbHor.bmp"))
return(false);
if(!Add(m_thumb))
return(false);
m_thumb.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of changing current state |
//+------------------------------------------------------------------+
bool CScrollH::OnChangePos(void)
{
//--- check if scrolling is possible
if(m_max_pos-m_min_pos<=0)
return(Visible(false));
else
if(!Visible(true))
return(false);
//--- calculate new coordinated of the scrollbar
int steps=m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Right(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Left()-m_thumb.Width(); // maximum possible coordinate (corresponds to the m_max_pos value)
int new_coord=min_coord+(max_coord-min_coord)*m_curr_pos/steps; // new coordinate
//--- adjust the scroll box position
return(m_thumb.Move(new_coord,m_thumb.Top()));
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CScrollH::OnResize(void)
{
//--- can not change the lateral size
if(Height()!=CONTROLS_SCROLL_SIZE)
m_rect.Height(CONTROLS_SCROLL_SIZE);
//--- resize the scrollbar background
if(!m_back.Size(Size()))
return(false);
//--- move the "Increment" button
if(!m_inc.Move(Right()-CONTROLS_SCROLL_SIZE,m_inc.Top()))
return(false);
//--- adjust the scroll box position
return(OnChangePos());
}
//+------------------------------------------------------------------+
//| Start dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollH::OnThumbDragStart(void)
{
if(m_drag_object==NULL)
{
m_drag_object=new CDragWnd;
if(m_drag_object==NULL)
return(false);
}
//--- calculate coordinates
int x1=m_thumb.Left()-CONTROLS_DRAG_SPACING;
int y1=m_thumb.Top()-CONTROLS_DRAG_SPACING;
int x2=m_thumb.Right()+CONTROLS_DRAG_SPACING;
int y2=m_thumb.Bottom()+CONTROLS_DRAG_SPACING;
//--- create
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- îãðàíè÷åíèÿ
m_drag_object.Limits(m_dec.Right()-CONTROLS_DRAG_SPACING,y1,m_inc.Left()+CONTROLS_DRAG_SPACING,y2);
//--- set mouse params
m_drag_object.MouseX(m_thumb.MouseX());
m_drag_object.MouseY(m_thumb.MouseY());
m_drag_object.MouseFlags(m_thumb.MouseFlags());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Continue dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollH::OnThumbDragProcess(void)
{
//--- checking
if(m_drag_object==NULL)
return(false);
//--- calculate coordinates
int x=m_drag_object.Left()+CONTROLS_DRAG_SPACING;
int y=m_drag_object.Top()+CONTROLS_DRAG_SPACING;
//--- calculate new position
int new_pos=CalcPos(x);
if(new_pos!=m_curr_pos)
{
ushort event_id=(m_curr_pos<new_pos)?ON_SCROLL_INC:ON_SCROLL_DEC;
m_curr_pos=new_pos;
EventChartCustom(CONTROLS_SELF_MESSAGE,event_id,m_id,0.0,m_name);
}
//--- move thumb
m_thumb.Move(x,y);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| End dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollH::OnThumbDragEnd(void)
{
if(m_drag_object!=NULL)
{
m_thumb.MouseFlags(m_drag_object.MouseFlags());
delete m_drag_object;
m_drag_object=NULL;
}
//--- succeed
return(m_thumb.Pressed(false));
}
//+------------------------------------------------------------------+
//| Calculate position by coordinate |
//+------------------------------------------------------------------+
int CScrollH::CalcPos(const int coord)
{
//--- calculate new position of the scrollbar
int steps =m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Right(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Left()-m_thumb.Width(); // maximum possible coordinate (corresponds to the m_max_pos value)
//--- checkeng
if(max_coord==min_coord)
return(0);
if(coord<min_coord || coord>max_coord)
return(m_curr_pos);
//---
int new_pos=(int)MathRound((((double)(coord-min_coord))/(max_coord-min_coord))*steps); // new position
//---
return(new_pos);
}
//+------------------------------------------------------------------+
+265
View File
@@ -0,0 +1,265 @@
//+------------------------------------------------------------------+
//| SpinEdit.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "Edit.mqh"
#include "BmpButton.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "res\\SpinInc.bmp"
#resource "res\\SpinDec.bmp"
//+------------------------------------------------------------------+
//| Class CSpinEdit |
//| Usage: class that implements the "Up-Down" control |
//+------------------------------------------------------------------+
class CSpinEdit : public CWndContainer
{
private:
//--- dependent controls
CEdit m_edit; // the entry field object
CBmpButton m_inc; // the "Increment button" object
CBmpButton m_dec; // the "Decrement button" object
//--- adjusted parameters
int m_min_value; // minimum value
int m_max_value; // maximum value
//--- state
int m_value; // current value
public:
CSpinEdit(void);
~CSpinEdit(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
int MinValue(void) const { return(m_min_value); }
void MinValue(const int value);
int MaxValue(void) const { return(m_max_value); }
void MaxValue(const int value);
//--- state
int Value(void) const { return(m_value); }
bool Value(int value);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateEdit(void);
virtual bool CreateInc(void);
virtual bool CreateDec(void);
//--- handlers of the dependent controls events
virtual bool OnClickInc(void);
virtual bool OnClickDec(void);
//--- internal event handlers
virtual bool OnChangeValue(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CSpinEdit)
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSpinEdit::CSpinEdit(void) : m_min_value(0),
m_max_value(0),
m_value(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CSpinEdit::~CSpinEdit(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CSpinEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- check height
if(y2-y1<CONTROLS_SPIN_MIN_HEIGHT)
return(false);
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateInc())
return(false);
if(!CreateDec())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set current value |
//+------------------------------------------------------------------+
bool CSpinEdit::Value(int value)
{
//--- check value
if(value<m_min_value)
value=m_min_value;
if(value>m_max_value)
value=m_max_value;
//--- if value was changed
if(m_value!=value)
{
m_value=value;
//--- call virtual handler
return(OnChangeValue());
}
//--- value has not been changed
return(false);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSpinEdit::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteInteger(file_handle,m_value);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSpinEdit::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Value(FileReadInteger(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set minimum value |
//+------------------------------------------------------------------+
void CSpinEdit::MinValue(const int value)
{
//--- if value was changed
if(m_min_value!=value)
{
m_min_value=value;
//--- adjust the edit value
Value(m_value);
}
}
//+------------------------------------------------------------------+
//| Set maximum value |
//+------------------------------------------------------------------+
void CSpinEdit::MaxValue(const int value)
{
//--- if value was changed
if(m_max_value!=value)
{
m_max_value=value;
//--- adjust the edit value
Value(m_value);
}
}
//+------------------------------------------------------------------+
//| Create the edit field |
//+------------------------------------------------------------------+
bool CSpinEdit::CreateEdit(void)
{
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_edit.Text(""))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Increment" button |
//+------------------------------------------------------------------+
bool CSpinEdit::CreateInc(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_SPIN_BUTTON_X_OFF);
int y1=(Height()-2*CONTROLS_SPIN_BUTTON_SIZE)/2;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_SPIN_BUTTON_SIZE;
//--- create
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::res\\SpinInc.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- property
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Decrement" button |
//+------------------------------------------------------------------+
bool CSpinEdit::CreateDec(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_SPIN_BUTTON_X_OFF);
int y1=(Height()-2*CONTROLS_SPIN_BUTTON_SIZE)/2+CONTROLS_SPIN_BUTTON_SIZE;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_SPIN_BUTTON_SIZE;
//--- create
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::res\\SpinDec.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//--- property
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the "increment" button |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickInc(void)
{
//--- try to increment current value
return(Value(m_value+1));
}
//+------------------------------------------------------------------+
//| Handler of click on the "decrement" button |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickDec(void)
{
//--- try to decrement current value
return(Value(m_value-1));
}
//+------------------------------------------------------------------+
//| Handler of changing current state |
//+------------------------------------------------------------------+
bool CSpinEdit::OnChangeValue(void)
{
//--- copy text to the edit field edit
m_edit.Text(IntegerToString(m_value));
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
+755
View File
@@ -0,0 +1,755 @@
//+------------------------------------------------------------------+
//| Wnd.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Rect.mqh"
#include "Defines.mqh"
#include <Object.mqh>
class CDragWnd;
//+------------------------------------------------------------------+
//| Class CWnd |
//| Usage: base class of the control object that creates |
//| control panels and indicator panels |
//+------------------------------------------------------------------+
class CWnd : public CObject
{
protected:
//--- parameters of creation
long m_chart_id; // chart ID
int m_subwin; // chart subwindow
string m_name; // object name
//--- geometry
CRect m_rect; // chart area
//--- ID
long m_id; // object ID
//--- state flags
int m_state_flags;
//--- properties flags
int m_prop_flags;
//--- alignment
int m_align_flags; // alignment flags
int m_align_left; // fixed offset from left border
int m_align_top; // fixed offset from top border
int m_align_right; // fixed offset from right border
int m_align_bottom; // fixed offset from bottom border
//--- the last saved state of mouse
int m_mouse_x; // X coordinate
int m_mouse_y; // Y coordinate
int m_mouse_flags; // state of buttons
uint m_last_click; // last click time
//--- drag object
CDragWnd *m_drag_object; // pointer to the dragged object
public:
CWnd(void);
~CWnd(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- release memory
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
virtual bool OnMouseEvent(const int x,const int y,const int flags);
//--- naming (read only)
string Name(void) const { return(m_name); }
//--- access the contents of container
int ControlsTotal(void) const { return(0); }
CWnd* Control(const int ind) const { return(NULL); }
virtual CWnd* ControlFind(const long id);
//--- geometry
const CRect Rect(void) const { return(m_rect); }
int Left(void) const { return(m_rect.left); }
virtual void Left(const int x) { m_rect.left=x; }
int Top(void) const { return(m_rect.top); }
virtual void Top(const int y) { m_rect.top=y; }
int Right(void) const { return(m_rect.right); }
virtual void Right(const int x) { m_rect.right=x; }
int Bottom(void) const { return(m_rect.bottom); }
virtual void Bottom(const int y) { m_rect.bottom=y; }
int Width(void) const { return(m_rect.Width()); }
virtual bool Width(const int w);
int Height(void) const { return(m_rect.Height()); }
virtual bool Height(const int h);
CSize Size(void) const { return(m_rect.Size()); }
virtual bool Size(const int w,const int h);
virtual bool Size(const CSize &size);
virtual bool Move(const int x,const int y);
virtual bool Move(const CPoint &point);
virtual bool Shift(const int dx,const int dy);
bool Contains(const int x,const int y) const { return(m_rect.Contains(x,y)); }
bool Contains(CWnd *control) const;
//--- alignment
void Alignment(const int flags,const int left,const int top,const int right,const int bottom);
virtual bool Align(const CRect &rect);
//--- ID
virtual long Id(const long id);
long Id(void) const { return(m_id); }
//--- state
bool IsEnabled(void) const { return(IS_ENABLED); }
virtual bool Enable(void);
virtual bool Disable(void);
bool IsVisible(void) const { return(IS_VISIBLE); }
virtual bool Visible(const bool flag);
virtual bool Show(void);
virtual bool Hide(void);
bool IsActive(void) const { return(IS_ACTIVE); }
virtual bool Activate(void);
virtual bool Deactivate(void);
//--- state flags
int StateFlags(void) const { return(m_state_flags); }
void StateFlags(const int flags) { m_state_flags=flags; }
void StateFlagsSet(const int flags) { m_state_flags|=flags; }
void StateFlagsReset(const int flags) { m_state_flags&=~flags; }
//--- properties flags
int PropFlags(void) const { return(m_prop_flags); }
void PropFlags(const int flags) { m_prop_flags=flags; }
void PropFlagsSet(const int flags) { m_prop_flags|=flags; }
void PropFlagsReset(const int flags) { m_prop_flags&=~flags; }
//--- for mouse operations
int MouseX(void) const { return(m_mouse_x); }
void MouseX(const int value) { m_mouse_x=value; }
int MouseY(void) const { return(m_mouse_y); }
void MouseY(const int value) { m_mouse_y=value; }
int MouseFlags(void) const { return(m_mouse_flags); }
virtual void MouseFlags(const int value) { m_mouse_flags=value; }
bool MouseFocusKill(const long id=CONTROLS_INVALID_ID);
bool BringToTop(void);
protected:
//--- internal event handlers
virtual bool OnCreate(void) { return(true); }
virtual bool OnDestroy(void) { return(true); }
virtual bool OnMove(void) { return(true); }
virtual bool OnResize(void) { return(true); }
virtual bool OnEnable(void) { return(true); }
virtual bool OnDisable(void) { return(true); }
virtual bool OnShow(void) { return(true); }
virtual bool OnHide(void) { return(true); }
virtual bool OnActivate(void) { return(true); }
virtual bool OnDeactivate(void) { return(true); }
virtual bool OnClick(void);
virtual bool OnDblClick(void);
virtual bool OnChange(void) { return(true); }
//--- mouse event handlers
virtual bool OnMouseDown(void);
virtual bool OnMouseUp(void);
//--- handlers of dragging
virtual bool OnDragStart(void);
virtual bool OnDragProcess(const int x,const int y);
virtual bool OnDragEnd(void);
//--- methods for drag-object
virtual bool DragObjectCreate(void) { return(false); }
virtual bool DragObjectDestroy(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CWnd::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
if((id!=CHARTEVENT_MOUSE_MOVE))
return(false);
if(!IS_VISIBLE)
return(false);
int x=(int)lparam;
int y=(int)dparam;
int flags=(int)StringToInteger(sparam);
//---
if(m_drag_object!=NULL)
return(m_drag_object.OnMouseEvent(x,y,flags));
//---
return(OnMouseEvent(x,y,flags));
}
//+------------------------------------------------------------------+
//| Common handler of mouse events |
//+------------------------------------------------------------------+
bool CWnd::OnMouseEvent(const int x,const int y,const int flags)
{
if(!Contains(x,y))
{
//--- if cursor is not inside the element and this element is active - deactivate
if(IS_ACTIVE)
{
//--- reset state and coordinates
m_mouse_x =0;
m_mouse_y =0;
m_mouse_flags=MOUSE_INVALID_FLAGS;
//--- deactivate
Deactivate();
}
return(false);
}
//--- check the state of the left mouse button
if((flags&MOUSE_LEFT)!=0)
{
//--- left mouse button is pressed
if(m_mouse_flags==MOUSE_INVALID_FLAGS)
{
//--- but not in this control (i.e., cursor entered the element with mouse button pressed)
//--- activate the control, but there will be no click
if(!IS_ACTIVE)
{
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_MOUSE_FOCUS_SET,m_id,0.0,m_name);
//--- activate
return(Activate());
}
return(true);
}
if((m_mouse_flags&MOUSE_LEFT)!=0)
{
//--- mouse button has already been pressed
if(IS_CAN_DRAG)
return(OnDragProcess(x,y));
if(IS_CLICKS_BY_PRESS)
{
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CLICK,m_id,0.0,m_name);
//--- handled
return(true);
}
}
else
{
//--- mouse button has been released (pressing)
//--- save the state and coordinates
m_mouse_flags=flags;
m_mouse_x =x;
m_mouse_y =y;
//--- call the handler
return(OnMouseDown());
}
}
else
{
//--- left mouse button is released
if(m_mouse_flags==MOUSE_INVALID_FLAGS)
{
//--- cursor entered the control with mouse button released
//--- activate control and save state to the member
m_mouse_flags=flags;
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_MOUSE_FOCUS_SET,m_id,0.0,m_name);
//--- activate
return(Activate());
}
if((m_mouse_flags&MOUSE_LEFT)!=0)
{
//--- mouse button has been pressed (clicking)
//--- save the state and coordinates
m_mouse_flags=flags;
m_mouse_x =x;
m_mouse_y =y;
//--- call the handler
return(OnMouseUp());
}
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWnd::CWnd(void) : m_chart_id(CONTROLS_INVALID_ID),
m_subwin(CONTROLS_INVALID_ID),
m_name(NULL),
m_id(CONTROLS_INVALID_ID),
m_state_flags(WND_STATE_FLAG_ENABLE+WND_STATE_FLAG_VISIBLE),
m_prop_flags(0),
m_align_flags(WND_ALIGN_NONE),
m_align_left(0),
m_align_top(0),
m_align_right(0),
m_align_bottom(0),
m_mouse_x(0),
m_mouse_y(0),
m_mouse_flags(MOUSE_INVALID_FLAGS),
m_last_click(0),
m_drag_object(NULL)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWnd::~CWnd(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CWnd::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- attach to chart
m_chart_id=chart;
m_name =name;
m_subwin =subwin;
//--- set coordinates of area
Left(x1);
Top(y1);
Right(x2);
Bottom(y2);
//--- always successful
return(true);
}
//+------------------------------------------------------------------+
//| Destruction of the control |
//+------------------------------------------------------------------+
void CWnd::Destroy(const int reason)
{
//--- call virtual event handler
if(OnDestroy())
m_name="";
}
//+------------------------------------------------------------------+
//| Find control by specified ID |
//+------------------------------------------------------------------+
CWnd* CWnd::ControlFind(const long id)
{
CWnd *result=NULL;
//--- check
if(id==m_id)
result=GetPointer(this);
//--- return the result
return(result);
}
//+------------------------------------------------------------------+
//| Change width of control |
//+------------------------------------------------------------------+
bool CWnd::Width(const int w)
{
//--- change width
m_rect.Width(w);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Change height of control |
//+------------------------------------------------------------------+
bool CWnd::Height(const int h)
{
//--- change height
m_rect.Height(h);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Resize control |
//+------------------------------------------------------------------+
bool CWnd::Size(const int w,const int h)
{
//--- change size
m_rect.Size(w,h);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Resize control |
//+------------------------------------------------------------------+
bool CWnd::Size(const CSize &size)
{
//--- change size
m_rect.Size(size);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Absolute movement of the control |
//+------------------------------------------------------------------+
bool CWnd::Move(const int x,const int y)
{
//--- moving
m_rect.Move(x,y);
//--- call virtual event handler
return(OnMove());
}
//+------------------------------------------------------------------+
//| Absolute movement of the control |
//+------------------------------------------------------------------+
bool CWnd::Move(const CPoint &point)
{
//--- moving
m_rect.Move(point);
//--- call virtual event handler
return(OnMove());
}
//+------------------------------------------------------------------+
//| Relative movement of the control |
//+------------------------------------------------------------------+
bool CWnd::Shift(const int dx,const int dy)
{
//--- moving
m_rect.Shift(dx,dy);
//--- call virtual event handler
return(OnMove());
}
//+------------------------------------------------------------------+
//| Check contains |
//+------------------------------------------------------------------+
bool CWnd::Contains(CWnd *control) const
{
//--- check
if(control==NULL)
return(false);
//--- result
return(Contains(control.Left(),control.Top()) && Contains(control.Right(),control.Bottom()));
}
//+------------------------------------------------------------------+
//| Enables event handling by the control |
//+------------------------------------------------------------------+
bool CWnd::Enable(void)
{
//--- if there are now changes, then succeed
if(IS_ENABLED)
return(true);
//--- change flag
StateFlagsSet(WND_STATE_FLAG_ENABLE);
//--- call virtual event handler
return(OnEnable());
}
//+------------------------------------------------------------------+
//| Disables event handling by the control |
//+------------------------------------------------------------------+
bool CWnd::Disable(void)
{
//--- if there are now changes, then succeed
if(!IS_ENABLED)
return(true);
//--- change flag
StateFlagsReset(WND_STATE_FLAG_ENABLE);
//--- call virtual event handler
return(OnDisable());
}
//+------------------------------------------------------------------+
//| Set the "object is visible" flag for the control |
//+------------------------------------------------------------------+
bool CWnd::Visible(const bool flag)
{
//--- if there are now changes, then succeed
if(IS_VISIBLE==flag)
return(true);
//--- call virtual event handler
return(flag ? Show() : Hide());
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CWnd::Show(void)
{
//--- change flag
StateFlagsSet(WND_STATE_FLAG_VISIBLE);
//--- call virtual event handler
return(OnShow());
}
//+------------------------------------------------------------------+
//| Makes the control hidden |
//+------------------------------------------------------------------+
bool CWnd::Hide(void)
{
//--- change flag
StateFlagsReset(WND_STATE_FLAG_VISIBLE);
//--- call virtual event handler
return(OnHide());
}
//+------------------------------------------------------------------+
//| Makes the control active |
//+------------------------------------------------------------------+
bool CWnd::Activate(void)
{
//--- if there are now changes, then succeed
if(IS_ACTIVE)
return(true);
//--- change flag
StateFlagsSet(WND_STATE_FLAG_ACTIVE);
//--- call virtual event handler
return(OnActivate());
}
//+------------------------------------------------------------------+
//| Makes the control inactive |
//+------------------------------------------------------------------+
bool CWnd::Deactivate(void)
{
//--- if there are now changes, then succeed
if(!IS_ACTIVE)
return(true);
//--- change flag
StateFlagsReset(WND_STATE_FLAG_ACTIVE);
//--- call virtual event handler
return(OnDeactivate());
}
//+------------------------------------------------------------------+
//| Set ID of control |
//+------------------------------------------------------------------+
long CWnd::Id(const long id)
{
m_id=id;
//--- always use only one ID
return(1);
}
//+------------------------------------------------------------------+
//| Set parameters of alignment |
//+------------------------------------------------------------------+
void CWnd::Alignment(const int flags,const int left,const int top,const int right,const int bottom)
{
m_align_flags =flags;
m_align_left =left;
m_align_top =top;
m_align_right =right;
m_align_bottom=bottom;
}
//+------------------------------------------------------------------+
//| Align element in specified chart area |
//+------------------------------------------------------------------+
bool CWnd::Align(const CRect &rect)
{
int new_value=0;
//--- check
if(m_align_flags==WND_ALIGN_NONE)
return(true);
//--- we are interested only in alignment by right and bottom borders,
//--- as left and right borders are processed in the OnMove()
if((m_align_flags&WND_ALIGN_RIGHT)!=0)
{
//--- there is alignment by right border,
if((m_align_flags&WND_ALIGN_LEFT)!=0)
{
//--- and by left border (change size)
new_value=rect.Width()-m_align_left-m_align_right;
if(!Size(new_value,Height()))
return(false);
}
else
{
//--- no alignment by left border (move)
new_value=rect.right-Width()-m_align_right;
if(!Move(new_value,Top()))
return(false);
}
}
if((m_align_flags&WND_ALIGN_BOTTOM)!=0)
{
//--- there is alignment by bottom border,
if((m_align_flags&WND_ALIGN_TOP)!=0)
{
//--- and by top border (change size)
new_value=rect.Height()-m_align_top-m_align_bottom;
if(!Size(Width(),new_value))
return(false);
}
else
{
//--- no alignment by top border (move)
new_value=rect.bottom-Height()-m_align_bottom;
if(!Move(Left(),new_value))
return(false);
}
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Remove the mouse focus from control |
//+------------------------------------------------------------------+
bool CWnd::MouseFocusKill(const long id)
{
//--- check
if(id==m_id)
return(false);
//--- reset flag
Deactivate();
//--- clean
m_mouse_x =0;
m_mouse_y =0;
m_mouse_flags=MOUSE_INVALID_FLAGS;
//--- call the handler
return(OnDeactivate());
}
//+------------------------------------------------------------------+
//| Increases the priority of an element |
//+------------------------------------------------------------------+
bool CWnd::BringToTop(void)
{
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_BRING_TO_TOP,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "click" event |
//+------------------------------------------------------------------+
bool CWnd::OnClick(void)
{
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CLICK,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "doubl click" event |
//+------------------------------------------------------------------+
bool CWnd::OnDblClick(void)
{
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DBL_CLICK,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CWnd::OnMouseDown(void)
{
if(IS_CAN_DRAG)
return(OnDragStart());
if(IS_CLICKS_BY_PRESS)
return(OnClick());
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of releasing the left mouse button |
//+------------------------------------------------------------------+
bool CWnd::OnMouseUp(void)
{
if(IS_CAN_DBL_CLICK)
{
uint last_time=GetTickCount();
if(m_last_click==0 || last_time-m_last_click>CONTROLS_DBL_CLICK_TIME)
{
m_last_click=(last_time==0) ? 1 : last_time;
}
else
{
m_last_click=0;
return(OnDblClick());
}
}
if(IS_CAN_DRAG)
return(OnDragEnd());
if(!IS_CLICKS_BY_PRESS)
return(OnClick());
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the control dragging start |
//+------------------------------------------------------------------+
bool CWnd::OnDragStart(void)
{
if(!IS_CAN_DRAG)
return(true);
//--- disable scrolling of chart with mouse
ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,false);
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_START,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of control dragging process |
//+------------------------------------------------------------------+
bool CWnd::OnDragProcess(const int x,const int y)
{
Shift(x-m_mouse_x,y-m_mouse_y);
//--- save
m_mouse_x=x;
m_mouse_y=y;
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the control dragging end |
//+------------------------------------------------------------------+
bool CWnd::OnDragEnd(void)
{
if(!IS_CAN_DRAG)
return(true);
//--- enable scrolling of chart with mouse
ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,true);
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_END,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Destroy the dragged object |
//+------------------------------------------------------------------+
bool CWnd::DragObjectDestroy(void)
{
if(m_drag_object!=NULL)
{
delete m_drag_object;
m_drag_object=NULL;
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Class CDragWnd |
//| Usage: base class for drag |
//+------------------------------------------------------------------+
class CDragWnd : public CWnd
{
protected:
int m_limit_left; // left constraint
int m_limit_top; // top constraint
int m_limit_right; // right constraint
int m_limit_bottom; // bottom constraint
public:
CDragWnd(void);
~CDragWnd(void);
//--- constraints
void Limits(const int l,const int t,const int r,const int b);
protected:
virtual bool OnDragProcess(const int x,const int y);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDragWnd::CDragWnd(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDragWnd::~CDragWnd(void)
{
}
//+------------------------------------------------------------------+
//| Constrain the control dragging |
//+------------------------------------------------------------------+
void CDragWnd::Limits(const int l,const int t,const int r,const int b)
{
//--- save
m_limit_left =l;
m_limit_top =t;
m_limit_right =r;
m_limit_bottom=b;
}
//+------------------------------------------------------------------+
//| Handler of control dragging process |
//+------------------------------------------------------------------+
bool CDragWnd::OnDragProcess(const int x,const int y)
{
int dx=x-m_mouse_x;
int dy=y-m_mouse_y;
//--- check shift
if(Right()+dx>m_limit_right)
dx=m_limit_right-Right();
if(Left()+dx<m_limit_left)
dx=m_limit_left-Left();
if(Bottom()+dy>m_limit_bottom)
dy=m_limit_bottom-Bottom();
if(Top()+dy<m_limit_top)
dy=m_limit_top-Top();
//--- shift
Shift(dx,dy);
//--- save
m_mouse_x=x;
m_mouse_y=y;
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_PROCESS,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
+308
View File
@@ -0,0 +1,308 @@
//+------------------------------------------------------------------+
//| WndClient.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.mqh"
#include "Panel.mqh"
#include "Scrolls.mqh"
//+------------------------------------------------------------------+
//| Class CWndClient |
//| Usage: base class to create areas with |
//| the scrollbars |
//+------------------------------------------------------------------+
class CWndClient : public CWndContainer
{
protected:
//--- flags
bool m_v_scrolled; // "vertical scrolling is possible" flag
bool m_h_scrolled; // "horizontal scrolling is possible" flag
//--- dependent controls
CPanel m_background; // the "scrollbar background" object
CScrollV m_scroll_v; // the vertical scrollbar object
CScrollH m_scroll_h; // the horizontal scrollbar object
public:
CWndClient(void);
~CWndClient(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- parameters
virtual bool ColorBackground(const color value) { return(m_background.ColorBackground(value)); }
virtual bool ColorBorder(const color value) { return(m_background.ColorBorder(value)); }
virtual bool BorderType(const ENUM_BORDER_TYPE flag) { return(m_background.BorderType(flag)); }
//--- settings
virtual bool VScrolled(void) { return(m_v_scrolled); }
virtual bool VScrolled(const bool flag);
virtual bool HScrolled(void) { return(m_h_scrolled); }
virtual bool HScrolled(const bool flag);
//--- ID
virtual long Id(const long id);
virtual long Id(void) const { return(CWnd::Id()); }
//--- state
virtual bool Show(void);
protected:
//--- create dependent controls
virtual bool CreateBack(void);
virtual bool CreateScrollV(void);
virtual bool CreateScrollH(void);
//--- internal event handlers
virtual bool OnResize(void);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void) { return(true); }
virtual bool OnVScrollHide(void) { return(true); }
virtual bool OnHScrollShow(void) { return(true); }
virtual bool OnHScrollHide(void) { return(true); }
virtual bool OnScrollLineDown(void) { return(true); }
virtual bool OnScrollLineUp(void) { return(true); }
virtual bool OnScrollLineLeft(void) { return(true); }
virtual bool OnScrollLineRight(void) { return(true); }
//--- resize
virtual bool Rebound(const CRect &rect);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CWndClient)
ON_NAMED_EVENT(ON_SHOW,m_scroll_v,OnVScrollShow)
ON_NAMED_EVENT(ON_HIDE,m_scroll_v,OnVScrollHide)
ON_EVENT(ON_SCROLL_DEC,m_scroll_v,OnScrollLineUp)
ON_EVENT(ON_SCROLL_INC,m_scroll_v,OnScrollLineDown)
ON_NAMED_EVENT(ON_SHOW,m_scroll_h,OnHScrollShow)
ON_NAMED_EVENT(ON_HIDE,m_scroll_h,OnHScrollHide)
ON_EVENT(ON_SCROLL_DEC,m_scroll_h,OnScrollLineLeft)
ON_EVENT(ON_SCROLL_INC,m_scroll_h,OnScrollLineRight)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWndClient::CWndClient(void) : m_v_scrolled(false),
m_h_scrolled(false)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWndClient::~CWndClient(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CWndClient::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call of the method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateBack())
return(false);
if(m_v_scrolled && !CreateScrollV())
return(false);
if(m_h_scrolled && !CreateScrollH())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scrollbar background |
//+------------------------------------------------------------------+
bool CWndClient::CreateBack(void)
{
//--- create
if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_background.ColorBorder(CONTROLS_CLIENT_COLOR_BORDER))
return(false);
if(!m_background.ColorBackground(CONTROLS_CLIENT_COLOR_BG))
return(false);
if(!Add(m_background))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create vertical scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::CreateScrollV(void)
{
//--- calculate coordinates
int x1=Width()-CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=Height()-CONTROLS_BORDER_WIDTH;
if(m_h_scrolled) y2-=CONTROLS_SCROLL_SIZE;
//--- create
if(!m_scroll_v.Create(m_chart_id,m_name+"VScroll",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_scroll_v))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create horizontal scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::CreateScrollH(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=Height()-CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=Height()-CONTROLS_BORDER_WIDTH;
if(m_v_scrolled) x2-=CONTROLS_SCROLL_SIZE;
//--- create
if(!m_scroll_h.Create(m_chart_id,m_name+"HScroll",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_scroll_h))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set up vertical scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::VScrolled(const bool flag)
{
if(m_v_scrolled==flag)
return(true);
//--- there are changes
int d_size=0;
if(flag)
{
//--- create vertical scrollbar
if(!CreateScrollV())
return(false);
//--- need to shorten horizontal scrollbar (if there is one)
d_size=-CONTROLS_SCROLL_SIZE;
}
else
{
//--- delete vertical scrollbar
m_scroll_v.Destroy();
if(!Delete(m_scroll_v))
return(false);
//--- need to lengthen horizontal scrollbar (if there is one)
d_size=CONTROLS_SCROLL_SIZE;
}
m_v_scrolled=flag;
//--- change width of horizontal scrollbar (if there is one)
if(m_h_scrolled)
{
if(!m_scroll_h.Width(m_scroll_h.Width()+d_size))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set up horizontal scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::HScrolled(const bool flag)
{
if(m_h_scrolled==flag)
return(true);
//--- there are changes
int d_size=0;
if(flag)
{
//--- create horizontal scrollbar
if(!CreateScrollH())
return(false);
//--- need to shorten vertical scrollbar (if there is one)
d_size=-CONTROLS_SCROLL_SIZE;
}
else
{
//--- delete horizontal scrollbar
m_scroll_h.Destroy();
if(!Delete(m_scroll_h))
return(false);
//--- need to lengthen vertical scrollbar (if there is one)
d_size=CONTROLS_SCROLL_SIZE;
}
m_h_scrolled=flag;
//--- change width of vertical scrollbar (if there is one)
if(m_v_scrolled)
{
if(!m_scroll_v.Height(m_scroll_v.Height()+d_size))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set ID of control |
//+------------------------------------------------------------------+
long CWndClient::Id(const long id)
{
//--- reserve ID for container
long id_used=CWndContainer::Id(id);
//---
if(!m_v_scrolled)
id_used+=m_scroll_v.Id(id+id_used);
if(!m_h_scrolled)
id_used+=m_scroll_h.Id(id+id_used);
//--- return number of used IDs
return(id_used);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CWndClient::Show(void)
{
//--- call of the method of the parent class
CWndContainer::Show();
//---
if(!m_v_scrolled)
m_scroll_v.Hide();
if(!m_h_scrolled)
m_scroll_h.Hide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CWndClient::OnResize(void)
{
//--- call of the method of the parent class
if(!CWndContainer::OnResize())
return(false);
//--- resize background
int d_size=0;
m_background.Width(Width());
m_background.Height(Height());
//---
if(m_v_scrolled)
{
//--- move vertical scrollbar
m_scroll_v.Move(Right()-CONTROLS_SCROLL_SIZE,Top());
//--- modify vertical scrollbar
d_size=(m_h_scrolled) ? CONTROLS_SCROLL_SIZE : 0;
m_scroll_v.Height(Height()-d_size);
}
if(m_h_scrolled)
{
//--- move horizontal scrollbar
m_scroll_h.Move(Left(),Bottom()-CONTROLS_SCROLL_SIZE);
//--- modify horizontal scrollbar
d_size=(m_v_scrolled) ? CONTROLS_SCROLL_SIZE : 0;
m_scroll_h.Width(Width()-d_size);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Resize |
//+------------------------------------------------------------------+
bool CWndClient::Rebound(const CRect &rect)
{
m_rect.SetBound(rect);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
+473
View File
@@ -0,0 +1,473 @@
//+------------------------------------------------------------------+
//| WndContainer.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Wnd.mqh"
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Class CWndContainer |
//| Usage: base class of the combined control |
//+------------------------------------------------------------------+
class CWndContainer : public CWnd
{
private:
CArrayObj m_controls; // container of the control
public:
CWndContainer(void);
~CWndContainer(void);
//--- release memory
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
virtual bool OnMouseEvent(const int x,const int y,const int flags);
//--- access the contents of container
int ControlsTotal(void) const { return(m_controls.Total()); }
CWnd* Control(const int ind) const { return(dynamic_cast<CWnd *>(m_controls.At(ind))); }
virtual CWnd* ControlFind(const long id);
//--- for mouse cursor focus
virtual bool MouseFocusKill(const long id=-1);
//--- fill
bool Add(CWnd *control);
bool Add(CWnd &control);
//--- underflowing
bool Delete(CWnd *control);
bool Delete(CWnd &control);
//--- geometry
virtual bool Move(const int x,const int y);
virtual bool Move(const CPoint &point);
virtual bool Shift(const int dx,const int dy);
//--- ID
virtual long Id(const long id);
long Id(void) const { return(CWnd::Id()); }
//--- state
virtual bool Enable(void);
virtual bool Disable(void);
virtual bool Show(void);
virtual bool Hide(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- internal event handlers
virtual bool OnResize(void);
virtual bool OnActivate(void);
virtual bool OnDeactivate(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CWndContainer::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- if an object is being dragged, pass control to the special drag object
if(m_drag_object!=NULL && m_drag_object.OnEvent(id,lparam,dparam,sparam))
return(true);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=total-1;i>=0;i--)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
if(control.OnEvent(id,lparam,dparam,sparam))
return(true);
}
//--- not handled
return(false);
}
//+------------------------------------------------------------------+
//| Common handler of mouse events |
//+------------------------------------------------------------------+
bool CWndContainer::OnMouseEvent(const int x,const int y,const int flags)
{
if(!IS_VISIBLE)
return(false);
//--- if an object is being dragged, pass control to the special drag object
if(m_drag_object!=NULL && m_drag_object.OnMouseEvent(x,y,flags))
return(true);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=total-1;i>=0;i--)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
if(control.OnMouseEvent(x,y,flags))
return(true);
}
//--- call of the method of the parent class
return(CWnd::OnMouseEvent(x,y,flags));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWndContainer::CWndContainer(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWndContainer::~CWndContainer(void)
{
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CWndContainer::Destroy(const int reason)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(0);
//--- check of pointer
if(control==NULL)
continue;
control.Destroy();
m_controls.Delete(0);
}
}
//+------------------------------------------------------------------+
//| Find control by specified ID |
//+------------------------------------------------------------------+
CWnd* CWndContainer::ControlFind(const long id)
{
CWnd *result=CWnd::ControlFind(id);
//---
if(result!=NULL)
return(result);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
result=control.ControlFind(id);
if(result!=NULL)
break;
}
//--- return the result
return(result);
}
//+------------------------------------------------------------------+
//| Remove the mouse focus from control |
//+------------------------------------------------------------------+
bool CWndContainer::MouseFocusKill(const long id=-1)
{
if(!IS_ACTIVE)
return(false);
Deactivate();
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.MouseFocusKill();
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add control to the group (by pointer) |
//+------------------------------------------------------------------+
bool CWndContainer::Add(CWnd *control)
{
//--- check of pointer
if(control==NULL)
return(false);
//--- correct the coordinates of added control
control.Shift(Left(),Top());
//--- "projecting" the group flag "visibility" to the added element
if(IS_VISIBLE && control.IsVisible())
{
//--- element will be "visible" only if the group is "visible" and the element is completely "within" this group
control.Visible(Contains(control));
}
else
control.Hide();
//--- "projecting" the group flag "enabled" to the added element
if(IS_ENABLED)
control.Enable();
else
control.Disable();
//--- adding
return(m_controls.Add(control));
}
//+------------------------------------------------------------------+
//| Add control to the group (by reference) |
//+------------------------------------------------------------------+
bool CWndContainer::Add(CWnd &control)
{
//--- add by pointer
return(Add((CWnd*)GetPointer(control)));
}
//+------------------------------------------------------------------+
//| Delete control from the group (by pointer) |
//+------------------------------------------------------------------+
bool CWndContainer::Delete(CWnd *control)
{
//--- check of pointer
if(control==NULL)
return(false);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *pointer=Control(i);
//--- check of pointer
if(pointer==NULL)
continue;
//--- delete item from group
if(pointer==control)
return(m_controls.Delete(i));
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Delete control from the group (by reference) |
//+------------------------------------------------------------------+
bool CWndContainer::Delete(CWnd &control)
{
//--- delete by pointer
return(Delete((CWnd*)GetPointer(control)));
}
//+------------------------------------------------------------------+
//| Absolute movement of the controls group |
//+------------------------------------------------------------------+
bool CWndContainer::Move(const int x,const int y)
{
//--- relative movement
return(Shift(x-Left(),y-Top()));
}
//+------------------------------------------------------------------+
//| Absolute movement of the controls group |
//+------------------------------------------------------------------+
bool CWndContainer::Move(const CPoint &point)
{
//--- relative movement
return(Shift(point.x-Left(),point.y-Top()));
}
//+------------------------------------------------------------------+
//| Relative movement of the controls group |
//+------------------------------------------------------------------+
bool CWndContainer::Shift(const int dx,const int dy)
{
//--- call of the method of the parent class
if(!CWnd::Shift(dx,dy)) return(false);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
//--- move the group item
control.Shift(dx,dy);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set ID of control |
//+------------------------------------------------------------------+
long CWndContainer::Id(const long id)
{
//--- reserve ID for container
long id_used=1;
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
id_used+=control.Id(id+id_used);
}
m_id=id;
//--- return number of used IDs
return(id_used);
}
//+------------------------------------------------------------------+
//| Enables event handling by the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::Enable(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Enable();
}
//--- call of the method of the parent class
return(CWnd::Enable());
}
//+------------------------------------------------------------------+
//| Disables event handling by the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::Disable(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Disable();
}
//--- call of the method of the parent class
return(CWnd::Disable());
}
//+------------------------------------------------------------------+
//| Makes the group of controls visible |
//+------------------------------------------------------------------+
bool CWndContainer::Show(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Show();
}
//--- call of the method of the parent class
return(CWnd::Show());
}
//+------------------------------------------------------------------+
//| Makes the group of controls hidden |
//+------------------------------------------------------------------+
bool CWndContainer::Hide(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Hide();
}
//--- call of the method of the parent class
return(CWnd::Hide());
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CWndContainer::OnResize()
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
if(!control.Align(Rect()))
return(false);
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of activating the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::OnActivate(void)
{
if(IS_ACTIVE)
return(false);
Activate();
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Activate();
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of deactivating the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::OnDeactivate(void)
{
if(!IS_ACTIVE)
return(false);
Deactivate();
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Deactivate();
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Save |
//+------------------------------------------------------------------+
bool CWndContainer::Save(const int file_handle)
{
bool result=true;
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
result&=control.Save(file_handle);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Load |
//+------------------------------------------------------------------+
bool CWndContainer::Load(const int file_handle)
{
bool result=true;
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
result&=control.Load(file_handle);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
+262
View File
@@ -0,0 +1,262 @@
//+------------------------------------------------------------------+
//| WndObj.mqh |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| www.mql5.com |
//+------------------------------------------------------------------+
#include "Wnd.mqh"
//+------------------------------------------------------------------+
//| Class CWndObj |
//| Usage: base class to work with chart objects |
//+------------------------------------------------------------------+
class CWndObj : public CWnd
{
private:
//--- flags of object
bool m_undeletable; // "object is not deletable" flag
bool m_unchangeable; // "object is not changeable" flag
bool m_unmoveable; // "object is not movable" flag
protected:
//--- parameters of the chart object
string m_text; // object text
color m_color; // object color
color m_color_background; // object background color
color m_color_border; // object border color
string m_font; // object font
int m_font_size; // object font size
long m_zorder; // Z order
public:
CWndObj(void);
~CWndObj(void);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up the object
string Text(void) const { return(m_text); }
bool Text(const string value);
color Color(void) const { return(m_color); }
bool Color(const color value);
color ColorBackground(void) const { return(m_color_background); }
bool ColorBackground(const color value);
color ColorBorder(void) const { return(m_color_border); }
bool ColorBorder(const color value);
string Font(void) const { return(m_font); }
bool Font(const string value);
int FontSize(void) const { return(m_font_size); }
bool FontSize(const int value);
long ZOrder(void) const { return(m_zorder); }
bool ZOrder(const long value);
protected:
//--- handlers of object events
virtual bool OnObjectCreate(void);
virtual bool OnObjectChange(void);
virtual bool OnObjectDelete(void);
virtual bool OnObjectDrag(void);
//--- handlers of object settings
virtual bool OnSetText(void) { return(true); }
virtual bool OnSetColor(void) { return(true); }
virtual bool OnSetColorBackground(void) { return(true); }
virtual bool OnSetColorBorder(void) { return(true); }
virtual bool OnSetFont(void) { return(true); }
virtual bool OnSetFontSize(void) { return(true); }
virtual bool OnSetZOrder(void) { return(true); }
//--- internal event handlers
virtual bool OnDestroy(void) { return(ObjectDelete(m_chart_id,m_name)); }
virtual bool OnChange(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CWndObj::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
if(m_name==sparam)
{
//--- object name and string parameters are equal
//--- this means that event should be handled
switch(id)
{
case CHARTEVENT_OBJECT_CREATE: return(OnObjectCreate());
case CHARTEVENT_OBJECT_CHANGE: return(OnObjectChange());
case CHARTEVENT_OBJECT_DELETE: return(OnObjectDelete());
case CHARTEVENT_OBJECT_DRAG : return(OnObjectDrag());
}
}
//--- event was not handled
return(CWnd::OnEvent(id,lparam,dparam,sparam));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWndObj::CWndObj(void) : m_color(clrNONE),
m_color_background(clrNONE),
m_color_border(clrNONE),
m_font(CONTROLS_FONT_NAME),
m_font_size(CONTROLS_FONT_SIZE),
m_zorder(0),
m_undeletable(true),
m_unchangeable(true),
m_unmoveable(true)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWndObj::~CWndObj(void)
{
}
//+------------------------------------------------------------------+
//| Set the "Text" parameter |
//+------------------------------------------------------------------+
bool CWndObj::Text(const string value)
{
//--- save new value of parameter
m_text=value;
//--- call virtual event handler
return(OnSetText());
}
//+------------------------------------------------------------------+
//| Set the "Color" parameter |
//+------------------------------------------------------------------+
bool CWndObj::Color(const color value)
{
//--- save new value of parameter
m_color=value;
//--- call virtual event handler
return(OnSetColor());
}
//+------------------------------------------------------------------+
//| Setting the "Background color" parameter |
//+------------------------------------------------------------------+
bool CWndObj::ColorBackground(const color value)
{
//--- save new value of parameter
m_color_background=value;
//--- call virtual event handler
return(OnSetColorBackground());
}
//+------------------------------------------------------------------+
//| Set the "Border color" parameter |
//+------------------------------------------------------------------+
bool CWndObj::ColorBorder(const color value)
{
//--- save new value of parameter
m_color_border=value;
//--- call virtual event handler
return(OnSetColorBorder());
}
//+------------------------------------------------------------------+
//| Set the "Font" parameter |
//+------------------------------------------------------------------+
bool CWndObj::Font(const string value)
{
//--- save new value of parameter
m_font=value;
//--- call virtual event handler
return(OnSetFont());
}
//+------------------------------------------------------------------+
//| Set the "Font size" parameter |
//+------------------------------------------------------------------+
bool CWndObj::FontSize(const int value)
{
//--- save new value of parameter
m_font_size=value;
//--- call virtual event handler
return(OnSetFontSize());
}
//+------------------------------------------------------------------+
//| Set the "Z order" parameter |
//+------------------------------------------------------------------+
bool CWndObj::ZOrder(const long value)
{
//--- save new value of parameter
m_zorder=value;
//--- call virtual event handler
return(OnSetZOrder());
}
//+------------------------------------------------------------------+
//| Handler of the "Object creation" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectCreate(void)
{
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Object modification" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectChange(void)
{
//--- if object is not changeable
if(m_unchangeable)
{
//--- restore position
if(!OnMove())
return(false);
//--- restore size
if(!OnResize())
return(false);
//--- restore settings
if(!OnChange())
return(false);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Object deletion" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectDelete(void)
{
//--- if object is not deletable
if(m_undeletable)
{
//--- restore the object
if(!OnCreate())
return(false);
//--- restore settings
if(!OnChange())
return(false);
//--- restore visibility
return(IS_VISIBLE ? OnShow():OnHide());
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Object dragging" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectDrag(void)
{
//--- if object is not movable
if(m_unmoveable)
{
//--- restore position
return(OnMove());
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Set up the object |
//+------------------------------------------------------------------+
bool CWndObj::OnChange(void)
{
//--- set up the chart object according to previously set parameters
if(!OnSetText())
return(false);
if(!OnSetFont())
return(false);
if(!OnSetFontSize())
return(false);
if(!OnSetColor())
return(false);
if(!OnSetColorBackground())
return(false);
if(!OnSetColorBorder())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Some files were not shown because too many files have changed in this diff Show More